xref: /aosp_15_r20/system/security/mls/mls-rs-crypto-boringssl/src/hash.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker 
15*e1997b9aSAndroid Build Coastguard Worker //! Hash functions and hash-based message authentication codes.
16*e1997b9aSAndroid Build Coastguard Worker 
17*e1997b9aSAndroid Build Coastguard Worker use bssl_crypto::digest;
18*e1997b9aSAndroid Build Coastguard Worker use bssl_crypto::hmac::{HmacSha256, HmacSha512};
19*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::crypto::CipherSuite;
20*e1997b9aSAndroid Build Coastguard Worker use thiserror::Error;
21*e1997b9aSAndroid Build Coastguard Worker 
22*e1997b9aSAndroid Build Coastguard Worker /// Errors returned from hash functions and HMACs.
23*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Error)]
24*e1997b9aSAndroid Build Coastguard Worker pub enum HashError {
25*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when unsupported cipher suite is requested.
26*e1997b9aSAndroid Build Coastguard Worker     #[error("unsupported cipher suite")]
27*e1997b9aSAndroid Build Coastguard Worker     UnsupportedCipherSuite,
28*e1997b9aSAndroid Build Coastguard Worker }
29*e1997b9aSAndroid Build Coastguard Worker 
30*e1997b9aSAndroid Build Coastguard Worker /// Hash function and HMAC implementations backed by BoringSSL.
31*e1997b9aSAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, Eq, PartialEq)]
32*e1997b9aSAndroid Build Coastguard Worker #[repr(u16)]
33*e1997b9aSAndroid Build Coastguard Worker pub enum Hash {
34*e1997b9aSAndroid Build Coastguard Worker     /// SHA-256.
35*e1997b9aSAndroid Build Coastguard Worker     Sha256,
36*e1997b9aSAndroid Build Coastguard Worker     /// SHA-384.
37*e1997b9aSAndroid Build Coastguard Worker     Sha384,
38*e1997b9aSAndroid Build Coastguard Worker     /// SHA-512.
39*e1997b9aSAndroid Build Coastguard Worker     Sha512,
40*e1997b9aSAndroid Build Coastguard Worker }
41*e1997b9aSAndroid Build Coastguard Worker 
42*e1997b9aSAndroid Build Coastguard Worker impl Hash {
43*e1997b9aSAndroid Build Coastguard Worker     /// Creates a new Hash.
new(cipher_suite: CipherSuite) -> Result<Self, HashError>44*e1997b9aSAndroid Build Coastguard Worker     pub fn new(cipher_suite: CipherSuite) -> Result<Self, HashError> {
45*e1997b9aSAndroid Build Coastguard Worker         match cipher_suite {
46*e1997b9aSAndroid Build Coastguard Worker             CipherSuite::CURVE25519_AES128
47*e1997b9aSAndroid Build Coastguard Worker             | CipherSuite::P256_AES128
48*e1997b9aSAndroid Build Coastguard Worker             | CipherSuite::CURVE25519_CHACHA => Ok(Hash::Sha256),
49*e1997b9aSAndroid Build Coastguard Worker             CipherSuite::P384_AES256 => Ok(Hash::Sha384),
50*e1997b9aSAndroid Build Coastguard Worker             CipherSuite::CURVE448_AES256
51*e1997b9aSAndroid Build Coastguard Worker             | CipherSuite::CURVE448_CHACHA
52*e1997b9aSAndroid Build Coastguard Worker             | CipherSuite::P521_AES256 => Ok(Hash::Sha512),
53*e1997b9aSAndroid Build Coastguard Worker             _ => Err(HashError::UnsupportedCipherSuite),
54*e1997b9aSAndroid Build Coastguard Worker         }
55*e1997b9aSAndroid Build Coastguard Worker     }
56*e1997b9aSAndroid Build Coastguard Worker 
57*e1997b9aSAndroid Build Coastguard Worker     /// Hashes `data`.
hash(&self, data: &[u8]) -> Vec<u8>58*e1997b9aSAndroid Build Coastguard Worker     pub fn hash(&self, data: &[u8]) -> Vec<u8> {
59*e1997b9aSAndroid Build Coastguard Worker         match self {
60*e1997b9aSAndroid Build Coastguard Worker             Hash::Sha256 => digest::Sha256::hash(data).to_vec(),
61*e1997b9aSAndroid Build Coastguard Worker             Hash::Sha384 => digest::Sha384::hash(data).to_vec(),
62*e1997b9aSAndroid Build Coastguard Worker             Hash::Sha512 => digest::Sha512::hash(data).to_vec(),
63*e1997b9aSAndroid Build Coastguard Worker         }
64*e1997b9aSAndroid Build Coastguard Worker     }
65*e1997b9aSAndroid Build Coastguard Worker 
66*e1997b9aSAndroid Build Coastguard Worker     /// Computes the HMAC of `data` using `key`.
mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, HashError>67*e1997b9aSAndroid Build Coastguard Worker     pub fn mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, HashError> {
68*e1997b9aSAndroid Build Coastguard Worker         match self {
69*e1997b9aSAndroid Build Coastguard Worker             Hash::Sha256 => Ok(HmacSha256::mac(key, data).to_vec()),
70*e1997b9aSAndroid Build Coastguard Worker             Hash::Sha384 => Err(HashError::UnsupportedCipherSuite),
71*e1997b9aSAndroid Build Coastguard Worker             Hash::Sha512 => Ok(HmacSha512::mac(key, data).to_vec()),
72*e1997b9aSAndroid Build Coastguard Worker         }
73*e1997b9aSAndroid Build Coastguard Worker     }
74*e1997b9aSAndroid Build Coastguard Worker }
75*e1997b9aSAndroid Build Coastguard Worker 
76*e1997b9aSAndroid Build Coastguard Worker #[cfg(all(not(mls_build_async), test))]
77*e1997b9aSAndroid Build Coastguard Worker mod test {
78*e1997b9aSAndroid Build Coastguard Worker     use super::{Hash, HashError};
79*e1997b9aSAndroid Build Coastguard Worker     use crate::test_helpers::decode_hex;
80*e1997b9aSAndroid Build Coastguard Worker     use assert_matches::assert_matches;
81*e1997b9aSAndroid Build Coastguard Worker     use mls_rs_core::crypto::CipherSuite;
82*e1997b9aSAndroid Build Coastguard Worker 
83*e1997b9aSAndroid Build Coastguard Worker     // bssl_crypto::hmac test vectors.
84*e1997b9aSAndroid Build Coastguard Worker 
85*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha256()86*e1997b9aSAndroid Build Coastguard Worker     fn sha256() {
87*e1997b9aSAndroid Build Coastguard Worker         let hash = Hash::new(CipherSuite::P256_AES128).unwrap();
88*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(
89*e1997b9aSAndroid Build Coastguard Worker             hash.hash(&decode_hex::<4>("74ba2521")),
90*e1997b9aSAndroid Build Coastguard Worker             decode_hex::<32>("b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e")
91*e1997b9aSAndroid Build Coastguard Worker         );
92*e1997b9aSAndroid Build Coastguard Worker     }
93*e1997b9aSAndroid Build Coastguard Worker 
94*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha384()95*e1997b9aSAndroid Build Coastguard Worker     fn sha384() {
96*e1997b9aSAndroid Build Coastguard Worker         let hash = Hash::new(CipherSuite::P384_AES256).unwrap();
97*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(
98*e1997b9aSAndroid Build Coastguard Worker             hash.hash(b"abc"),
99*e1997b9aSAndroid Build Coastguard Worker             decode_hex::<48>("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7")
100*e1997b9aSAndroid Build Coastguard Worker         );
101*e1997b9aSAndroid Build Coastguard Worker     }
102*e1997b9aSAndroid Build Coastguard Worker 
103*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha512()104*e1997b9aSAndroid Build Coastguard Worker     fn sha512() {
105*e1997b9aSAndroid Build Coastguard Worker         let hash = Hash::new(CipherSuite::CURVE448_CHACHA).unwrap();
106*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(
107*e1997b9aSAndroid Build Coastguard Worker             hash.hash(&decode_hex::<4>("23be86d5")),
108*e1997b9aSAndroid Build Coastguard Worker             decode_hex::<64>(concat!(
109*e1997b9aSAndroid Build Coastguard Worker                 "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2",
110*e1997b9aSAndroid Build Coastguard Worker                 "ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb"
111*e1997b9aSAndroid Build Coastguard Worker             ))
112*e1997b9aSAndroid Build Coastguard Worker         );
113*e1997b9aSAndroid Build Coastguard Worker     }
114*e1997b9aSAndroid Build Coastguard Worker 
115*e1997b9aSAndroid Build Coastguard Worker     #[test]
hmac_sha256()116*e1997b9aSAndroid Build Coastguard Worker     fn hmac_sha256() {
117*e1997b9aSAndroid Build Coastguard Worker         let expected = vec![
118*e1997b9aSAndroid Build Coastguard Worker             0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
119*e1997b9aSAndroid Build Coastguard Worker             0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
120*e1997b9aSAndroid Build Coastguard Worker             0x2e, 0x32, 0xcf, 0xf7,
121*e1997b9aSAndroid Build Coastguard Worker         ];
122*e1997b9aSAndroid Build Coastguard Worker         let key: [u8; 20] = [0x0b; 20];
123*e1997b9aSAndroid Build Coastguard Worker         let data = b"Hi There";
124*e1997b9aSAndroid Build Coastguard Worker 
125*e1997b9aSAndroid Build Coastguard Worker         let hmac = Hash::new(CipherSuite::CURVE25519_AES128).unwrap();
126*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(expected, hmac.mac(&key, data).unwrap());
127*e1997b9aSAndroid Build Coastguard Worker     }
128*e1997b9aSAndroid Build Coastguard Worker 
129*e1997b9aSAndroid Build Coastguard Worker     #[test]
hmac_sha384()130*e1997b9aSAndroid Build Coastguard Worker     fn hmac_sha384() {
131*e1997b9aSAndroid Build Coastguard Worker         let key: [u8; 20] = [0x0b; 20];
132*e1997b9aSAndroid Build Coastguard Worker         let data = b"Hi There";
133*e1997b9aSAndroid Build Coastguard Worker 
134*e1997b9aSAndroid Build Coastguard Worker         let hmac = Hash::new(CipherSuite::P384_AES256).unwrap();
135*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(hmac.mac(&key, data), Err(HashError::UnsupportedCipherSuite));
136*e1997b9aSAndroid Build Coastguard Worker     }
137*e1997b9aSAndroid Build Coastguard Worker 
138*e1997b9aSAndroid Build Coastguard Worker     #[test]
hmac_sha512()139*e1997b9aSAndroid Build Coastguard Worker     fn hmac_sha512() {
140*e1997b9aSAndroid Build Coastguard Worker         let expected = vec![
141*e1997b9aSAndroid Build Coastguard Worker             135, 170, 124, 222, 165, 239, 97, 157, 79, 240, 180, 36, 26, 29, 108, 176, 35, 121,
142*e1997b9aSAndroid Build Coastguard Worker             244, 226, 206, 78, 194, 120, 122, 208, 179, 5, 69, 225, 124, 222, 218, 168, 51, 183,
143*e1997b9aSAndroid Build Coastguard Worker             214, 184, 167, 2, 3, 139, 39, 78, 174, 163, 244, 228, 190, 157, 145, 78, 235, 97, 241,
144*e1997b9aSAndroid Build Coastguard Worker             112, 46, 105, 108, 32, 58, 18, 104, 84,
145*e1997b9aSAndroid Build Coastguard Worker         ];
146*e1997b9aSAndroid Build Coastguard Worker         let key: [u8; 20] = [0x0b; 20];
147*e1997b9aSAndroid Build Coastguard Worker         let data = b"Hi There";
148*e1997b9aSAndroid Build Coastguard Worker 
149*e1997b9aSAndroid Build Coastguard Worker         let hmac = Hash::new(CipherSuite::CURVE448_CHACHA).unwrap();
150*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(expected, hmac.mac(&key, data).unwrap());
151*e1997b9aSAndroid Build Coastguard Worker     }
152*e1997b9aSAndroid Build Coastguard Worker }
153