xref: /aosp_15_r20/system/security/mls/mls-rs-crypto-boringssl/src/kdf.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 //! Key derivation function.
16*e1997b9aSAndroid Build Coastguard Worker 
17*e1997b9aSAndroid Build Coastguard Worker use bssl_crypto::digest;
18*e1997b9aSAndroid Build Coastguard Worker use bssl_crypto::hkdf::{HkdfSha256, HkdfSha512, Prk, Salt};
19*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::crypto::CipherSuite;
20*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::error::IntoAnyError;
21*e1997b9aSAndroid Build Coastguard Worker use mls_rs_crypto_traits::{KdfId, KdfType};
22*e1997b9aSAndroid Build Coastguard Worker use thiserror::Error;
23*e1997b9aSAndroid Build Coastguard Worker 
24*e1997b9aSAndroid Build Coastguard Worker /// Errors returned from KDF.
25*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Error)]
26*e1997b9aSAndroid Build Coastguard Worker pub enum KdfError {
27*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the input key material (IKM) is too short.
28*e1997b9aSAndroid Build Coastguard Worker     #[error("KDF IKM of length {len}, expected length at least {min_len}")]
29*e1997b9aSAndroid Build Coastguard Worker     TooShortIkm {
30*e1997b9aSAndroid Build Coastguard Worker         /// Invalid IKM length.
31*e1997b9aSAndroid Build Coastguard Worker         len: usize,
32*e1997b9aSAndroid Build Coastguard Worker         /// Minimum IKM length.
33*e1997b9aSAndroid Build Coastguard Worker         min_len: usize,
34*e1997b9aSAndroid Build Coastguard Worker     },
35*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the pseudorandom key (PRK) is too short.
36*e1997b9aSAndroid Build Coastguard Worker     #[error("KDF PRK of length {len}, expected length at least {min_len}")]
37*e1997b9aSAndroid Build Coastguard Worker     TooShortPrk {
38*e1997b9aSAndroid Build Coastguard Worker         /// Invalid PRK length.
39*e1997b9aSAndroid Build Coastguard Worker         len: usize,
40*e1997b9aSAndroid Build Coastguard Worker         /// Minimum PRK length.
41*e1997b9aSAndroid Build Coastguard Worker         min_len: usize,
42*e1997b9aSAndroid Build Coastguard Worker     },
43*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the output key material (OKM) requested it too long.
44*e1997b9aSAndroid Build Coastguard Worker     #[error("KDF OKM of length {len} requested, expected length at most {max_len}")]
45*e1997b9aSAndroid Build Coastguard Worker     TooLongOkm {
46*e1997b9aSAndroid Build Coastguard Worker         /// Invalid OKM length.
47*e1997b9aSAndroid Build Coastguard Worker         len: usize,
48*e1997b9aSAndroid Build Coastguard Worker         /// Maximum OKM length.
49*e1997b9aSAndroid Build Coastguard Worker         max_len: usize,
50*e1997b9aSAndroid Build Coastguard Worker     },
51*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when unsupported cipher suite is requested.
52*e1997b9aSAndroid Build Coastguard Worker     #[error("unsupported cipher suite")]
53*e1997b9aSAndroid Build Coastguard Worker     UnsupportedCipherSuite,
54*e1997b9aSAndroid Build Coastguard Worker }
55*e1997b9aSAndroid Build Coastguard Worker 
56*e1997b9aSAndroid Build Coastguard Worker impl IntoAnyError for KdfError {
into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self>57*e1997b9aSAndroid Build Coastguard Worker     fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> {
58*e1997b9aSAndroid Build Coastguard Worker         Ok(self.into())
59*e1997b9aSAndroid Build Coastguard Worker     }
60*e1997b9aSAndroid Build Coastguard Worker }
61*e1997b9aSAndroid Build Coastguard Worker 
62*e1997b9aSAndroid Build Coastguard Worker /// KdfType implementation backed by BoringSSL.
63*e1997b9aSAndroid Build Coastguard Worker #[derive(Clone)]
64*e1997b9aSAndroid Build Coastguard Worker pub struct Kdf(KdfId);
65*e1997b9aSAndroid Build Coastguard Worker 
66*e1997b9aSAndroid Build Coastguard Worker impl Kdf {
67*e1997b9aSAndroid Build Coastguard Worker     /// Creates a new Kdf.
new(cipher_suite: CipherSuite) -> Option<Self>68*e1997b9aSAndroid Build Coastguard Worker     pub fn new(cipher_suite: CipherSuite) -> Option<Self> {
69*e1997b9aSAndroid Build Coastguard Worker         KdfId::new(cipher_suite).map(Self)
70*e1997b9aSAndroid Build Coastguard Worker     }
71*e1997b9aSAndroid Build Coastguard Worker }
72*e1997b9aSAndroid Build Coastguard Worker 
73*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
74*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))]
75*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(all(not(target_arch = "wasm32"), mls_build_async), maybe_async::must_be_async)]
76*e1997b9aSAndroid Build Coastguard Worker impl KdfType for Kdf {
77*e1997b9aSAndroid Build Coastguard Worker     type Error = KdfError;
78*e1997b9aSAndroid Build Coastguard Worker 
extract(&self, salt: &[u8], ikm: &[u8]) -> Result<Vec<u8>, KdfError>79*e1997b9aSAndroid Build Coastguard Worker     async fn extract(&self, salt: &[u8], ikm: &[u8]) -> Result<Vec<u8>, KdfError> {
80*e1997b9aSAndroid Build Coastguard Worker         if ikm.is_empty() {
81*e1997b9aSAndroid Build Coastguard Worker             return Err(KdfError::TooShortIkm { len: 0, min_len: 1 });
82*e1997b9aSAndroid Build Coastguard Worker         }
83*e1997b9aSAndroid Build Coastguard Worker 
84*e1997b9aSAndroid Build Coastguard Worker         let salt = if salt.is_empty() { Salt::None } else { Salt::NonEmpty(salt) };
85*e1997b9aSAndroid Build Coastguard Worker 
86*e1997b9aSAndroid Build Coastguard Worker         match self.0 {
87*e1997b9aSAndroid Build Coastguard Worker             KdfId::HkdfSha256 => {
88*e1997b9aSAndroid Build Coastguard Worker                 Ok(HkdfSha256::extract(ikm, salt).as_bytes()[..self.extract_size()].to_vec())
89*e1997b9aSAndroid Build Coastguard Worker             }
90*e1997b9aSAndroid Build Coastguard Worker             KdfId::HkdfSha512 => {
91*e1997b9aSAndroid Build Coastguard Worker                 Ok(HkdfSha512::extract(ikm, salt).as_bytes()[..self.extract_size()].to_vec())
92*e1997b9aSAndroid Build Coastguard Worker             }
93*e1997b9aSAndroid Build Coastguard Worker             _ => Err(KdfError::UnsupportedCipherSuite),
94*e1997b9aSAndroid Build Coastguard Worker         }
95*e1997b9aSAndroid Build Coastguard Worker     }
96*e1997b9aSAndroid Build Coastguard Worker 
expand(&self, prk: &[u8], info: &[u8], len: usize) -> Result<Vec<u8>, KdfError>97*e1997b9aSAndroid Build Coastguard Worker     async fn expand(&self, prk: &[u8], info: &[u8], len: usize) -> Result<Vec<u8>, KdfError> {
98*e1997b9aSAndroid Build Coastguard Worker         if prk.len() < self.extract_size() {
99*e1997b9aSAndroid Build Coastguard Worker             return Err(KdfError::TooShortPrk { len: prk.len(), min_len: self.extract_size() });
100*e1997b9aSAndroid Build Coastguard Worker         }
101*e1997b9aSAndroid Build Coastguard Worker 
102*e1997b9aSAndroid Build Coastguard Worker         match self.0 {
103*e1997b9aSAndroid Build Coastguard Worker             KdfId::HkdfSha256 => match Prk::new::<digest::Sha256>(prk) {
104*e1997b9aSAndroid Build Coastguard Worker                 Some(hkdf) => {
105*e1997b9aSAndroid Build Coastguard Worker                     let mut out = vec![0; len];
106*e1997b9aSAndroid Build Coastguard Worker                     match hkdf.expand_into(info, &mut out) {
107*e1997b9aSAndroid Build Coastguard Worker                         Ok(_) => Ok(out),
108*e1997b9aSAndroid Build Coastguard Worker                         Err(_) => {
109*e1997b9aSAndroid Build Coastguard Worker                             Err(KdfError::TooLongOkm { len, max_len: HkdfSha256::MAX_OUTPUT_LEN })
110*e1997b9aSAndroid Build Coastguard Worker                         }
111*e1997b9aSAndroid Build Coastguard Worker                     }
112*e1997b9aSAndroid Build Coastguard Worker                 }
113*e1997b9aSAndroid Build Coastguard Worker                 None => Err(KdfError::TooShortPrk { len: prk.len(), min_len: self.extract_size() }),
114*e1997b9aSAndroid Build Coastguard Worker             },
115*e1997b9aSAndroid Build Coastguard Worker             KdfId::HkdfSha512 => match Prk::new::<digest::Sha512>(prk) {
116*e1997b9aSAndroid Build Coastguard Worker                 Some(hkdf) => {
117*e1997b9aSAndroid Build Coastguard Worker                     let mut out = vec![0; len];
118*e1997b9aSAndroid Build Coastguard Worker                     match hkdf.expand_into(info, &mut out) {
119*e1997b9aSAndroid Build Coastguard Worker                         Ok(_) => Ok(out),
120*e1997b9aSAndroid Build Coastguard Worker                         Err(_) => {
121*e1997b9aSAndroid Build Coastguard Worker                             Err(KdfError::TooLongOkm { len, max_len: HkdfSha512::MAX_OUTPUT_LEN })
122*e1997b9aSAndroid Build Coastguard Worker                         }
123*e1997b9aSAndroid Build Coastguard Worker                     }
124*e1997b9aSAndroid Build Coastguard Worker                 }
125*e1997b9aSAndroid Build Coastguard Worker                 None => Err(KdfError::TooShortPrk { len: prk.len(), min_len: self.extract_size() }),
126*e1997b9aSAndroid Build Coastguard Worker             },
127*e1997b9aSAndroid Build Coastguard Worker             _ => Err(KdfError::UnsupportedCipherSuite),
128*e1997b9aSAndroid Build Coastguard Worker         }
129*e1997b9aSAndroid Build Coastguard Worker     }
130*e1997b9aSAndroid Build Coastguard Worker 
extract_size(&self) -> usize131*e1997b9aSAndroid Build Coastguard Worker     fn extract_size(&self) -> usize {
132*e1997b9aSAndroid Build Coastguard Worker         self.0.extract_size()
133*e1997b9aSAndroid Build Coastguard Worker     }
134*e1997b9aSAndroid Build Coastguard Worker 
kdf_id(&self) -> u16135*e1997b9aSAndroid Build Coastguard Worker     fn kdf_id(&self) -> u16 {
136*e1997b9aSAndroid Build Coastguard Worker         self.0 as u16
137*e1997b9aSAndroid Build Coastguard Worker     }
138*e1997b9aSAndroid Build Coastguard Worker }
139*e1997b9aSAndroid Build Coastguard Worker 
140*e1997b9aSAndroid Build Coastguard Worker #[cfg(all(not(mls_build_async), test))]
141*e1997b9aSAndroid Build Coastguard Worker mod test {
142*e1997b9aSAndroid Build Coastguard Worker     use super::{Kdf, KdfError, KdfType};
143*e1997b9aSAndroid Build Coastguard Worker     use crate::test_helpers::decode_hex;
144*e1997b9aSAndroid Build Coastguard Worker     use assert_matches::assert_matches;
145*e1997b9aSAndroid Build Coastguard Worker     use bssl_crypto::hkdf::{HkdfSha256, HkdfSha512};
146*e1997b9aSAndroid Build Coastguard Worker     use mls_rs_core::crypto::CipherSuite;
147*e1997b9aSAndroid Build Coastguard Worker 
148*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha256()149*e1997b9aSAndroid Build Coastguard Worker     fn sha256() {
150*e1997b9aSAndroid Build Coastguard Worker         // https://www.rfc-editor.org/rfc/rfc5869.html#appendix-A.1
151*e1997b9aSAndroid Build Coastguard Worker         let salt: [u8; 13] = decode_hex("000102030405060708090a0b0c");
152*e1997b9aSAndroid Build Coastguard Worker         let ikm: [u8; 22] = decode_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
153*e1997b9aSAndroid Build Coastguard Worker         let info: [u8; 10] = decode_hex("f0f1f2f3f4f5f6f7f8f9");
154*e1997b9aSAndroid Build Coastguard Worker         let expected_prk: [u8; 32] =
155*e1997b9aSAndroid Build Coastguard Worker             decode_hex("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5");
156*e1997b9aSAndroid Build Coastguard Worker         let expected_okm: [u8; 42] = decode_hex(
157*e1997b9aSAndroid Build Coastguard Worker             "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
158*e1997b9aSAndroid Build Coastguard Worker         );
159*e1997b9aSAndroid Build Coastguard Worker 
160*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE25519_AES128).unwrap();
161*e1997b9aSAndroid Build Coastguard Worker         let prk = kdf.extract(&salt, &ikm).unwrap();
162*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(prk, expected_prk);
163*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(kdf.expand(&prk, &info, 42).unwrap(), expected_okm);
164*e1997b9aSAndroid Build Coastguard Worker     }
165*e1997b9aSAndroid Build Coastguard Worker 
166*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha512()167*e1997b9aSAndroid Build Coastguard Worker     fn sha512() {
168*e1997b9aSAndroid Build Coastguard Worker         // https://github.com/C2SP/wycheproof/blob/cd27d6419bedd83cbd24611ec54b6d4bfdb0cdca/testvectors/hkdf_sha512_test.json#L141
169*e1997b9aSAndroid Build Coastguard Worker         let salt: [u8; 16] = decode_hex("1d6f3b38a1e607b5e6bcd4af1800a9d3");
170*e1997b9aSAndroid Build Coastguard Worker         let ikm: [u8; 16] = decode_hex("5d3db20e8238a90b62a600fa57fdb318");
171*e1997b9aSAndroid Build Coastguard Worker         let info: [u8; 20] = decode_hex("2bc5f39032b6fc87da69ba8711ce735b169646fd");
172*e1997b9aSAndroid Build Coastguard Worker         let expected_okm: [u8; 42] = decode_hex(
173*e1997b9aSAndroid Build Coastguard Worker             "8c3cf7122dcb5eb7efaf02718f1faf70bca20dcb75070e9d0871a413a6c05fc195a75aa9ffc349d70aae",
174*e1997b9aSAndroid Build Coastguard Worker         );
175*e1997b9aSAndroid Build Coastguard Worker 
176*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE448_CHACHA).unwrap();
177*e1997b9aSAndroid Build Coastguard Worker         let prk = kdf.extract(&salt, &ikm).unwrap();
178*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(kdf.expand(&prk, &info, 42).unwrap(), expected_okm);
179*e1997b9aSAndroid Build Coastguard Worker     }
180*e1997b9aSAndroid Build Coastguard Worker 
181*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha256_extract_short_ikm()182*e1997b9aSAndroid Build Coastguard Worker     fn sha256_extract_short_ikm() {
183*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE25519_AES128).unwrap();
184*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(kdf.extract(b"salty", b""), Err(KdfError::TooShortIkm { .. }));
185*e1997b9aSAndroid Build Coastguard Worker     }
186*e1997b9aSAndroid Build Coastguard Worker 
187*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha256_expand_short_prk()188*e1997b9aSAndroid Build Coastguard Worker     fn sha256_expand_short_prk() {
189*e1997b9aSAndroid Build Coastguard Worker         let prk_short: [u8; 16] = decode_hex("077709362c2e32df0ddc3f0dc47bba63");
190*e1997b9aSAndroid Build Coastguard Worker         let info: [u8; 10] = decode_hex("f0f1f2f3f4f5f6f7f8f9");
191*e1997b9aSAndroid Build Coastguard Worker 
192*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE25519_AES128).unwrap();
193*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(kdf.expand(&prk_short, &info, 42), Err(KdfError::TooShortPrk { .. }));
194*e1997b9aSAndroid Build Coastguard Worker     }
195*e1997b9aSAndroid Build Coastguard Worker 
196*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha256_expand_long_okm()197*e1997b9aSAndroid Build Coastguard Worker     fn sha256_expand_long_okm() {
198*e1997b9aSAndroid Build Coastguard Worker         // https://www.rfc-editor.org/rfc/rfc5869.html#appendix-A.1
199*e1997b9aSAndroid Build Coastguard Worker         let prk: [u8; 32] =
200*e1997b9aSAndroid Build Coastguard Worker             decode_hex("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5");
201*e1997b9aSAndroid Build Coastguard Worker         let info: [u8; 10] = decode_hex("f0f1f2f3f4f5f6f7f8f9");
202*e1997b9aSAndroid Build Coastguard Worker 
203*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE25519_AES128).unwrap();
204*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(
205*e1997b9aSAndroid Build Coastguard Worker             kdf.expand(&prk, &info, HkdfSha256::MAX_OUTPUT_LEN + 1),
206*e1997b9aSAndroid Build Coastguard Worker             Err(KdfError::TooLongOkm { .. })
207*e1997b9aSAndroid Build Coastguard Worker         );
208*e1997b9aSAndroid Build Coastguard Worker     }
209*e1997b9aSAndroid Build Coastguard Worker 
210*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha512_extract_short_ikm()211*e1997b9aSAndroid Build Coastguard Worker     fn sha512_extract_short_ikm() {
212*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE448_CHACHA).unwrap();
213*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(kdf.extract(b"salty", b""), Err(KdfError::TooShortIkm { .. }));
214*e1997b9aSAndroid Build Coastguard Worker     }
215*e1997b9aSAndroid Build Coastguard Worker 
216*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha512_expand_short_prk()217*e1997b9aSAndroid Build Coastguard Worker     fn sha512_expand_short_prk() {
218*e1997b9aSAndroid Build Coastguard Worker         let prk_short: [u8; 16] = decode_hex("077709362c2e32df0ddc3f0dc47bba63");
219*e1997b9aSAndroid Build Coastguard Worker         let info: [u8; 10] = decode_hex("f0f1f2f3f4f5f6f7f8f9");
220*e1997b9aSAndroid Build Coastguard Worker 
221*e1997b9aSAndroid Build Coastguard Worker         let kdf = Kdf::new(CipherSuite::CURVE448_CHACHA).unwrap();
222*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(kdf.expand(&prk_short, &info, 42), Err(KdfError::TooShortPrk { .. }));
223*e1997b9aSAndroid Build Coastguard Worker     }
224*e1997b9aSAndroid Build Coastguard Worker 
225*e1997b9aSAndroid Build Coastguard Worker     #[test]
sha512_expand_long_okm()226*e1997b9aSAndroid Build Coastguard Worker     fn sha512_expand_long_okm() {
227*e1997b9aSAndroid Build Coastguard Worker         // https://github.com/C2SP/wycheproof/blob/cd27d6419bedd83cbd24611ec54b6d4bfdb0cdca/testvectors/hkdf_sha512_test.json#L141
228*e1997b9aSAndroid Build Coastguard Worker         let salt: [u8; 16] = decode_hex("1d6f3b38a1e607b5e6bcd4af1800a9d3");
229*e1997b9aSAndroid Build Coastguard Worker         let ikm: [u8; 16] = decode_hex("5d3db20e8238a90b62a600fa57fdb318");
230*e1997b9aSAndroid Build Coastguard Worker         let info: [u8; 20] = decode_hex("2bc5f39032b6fc87da69ba8711ce735b169646fd");
231*e1997b9aSAndroid Build Coastguard Worker 
232*e1997b9aSAndroid Build Coastguard Worker         let kdf_sha512 = Kdf::new(CipherSuite::CURVE448_CHACHA).unwrap();
233*e1997b9aSAndroid Build Coastguard Worker         let prk = kdf_sha512.extract(&salt, &ikm).unwrap();
234*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(
235*e1997b9aSAndroid Build Coastguard Worker             kdf_sha512.expand(&prk, &info, HkdfSha512::MAX_OUTPUT_LEN + 1),
236*e1997b9aSAndroid Build Coastguard Worker             Err(KdfError::TooLongOkm { .. })
237*e1997b9aSAndroid Build Coastguard Worker         );
238*e1997b9aSAndroid Build Coastguard Worker     }
239*e1997b9aSAndroid Build Coastguard Worker 
240*e1997b9aSAndroid Build Coastguard Worker     #[test]
unsupported_cipher_suites()241*e1997b9aSAndroid Build Coastguard Worker     fn unsupported_cipher_suites() {
242*e1997b9aSAndroid Build Coastguard Worker         let ikm: [u8; 22] = decode_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
243*e1997b9aSAndroid Build Coastguard Worker         let salt: [u8; 13] = decode_hex("000102030405060708090a0b0c");
244*e1997b9aSAndroid Build Coastguard Worker 
245*e1997b9aSAndroid Build Coastguard Worker         assert_matches!(
246*e1997b9aSAndroid Build Coastguard Worker             Kdf::new(CipherSuite::P384_AES256).unwrap().extract(&salt, &ikm),
247*e1997b9aSAndroid Build Coastguard Worker             Err(KdfError::UnsupportedCipherSuite)
248*e1997b9aSAndroid Build Coastguard Worker         );
249*e1997b9aSAndroid Build Coastguard Worker     }
250*e1997b9aSAndroid Build Coastguard Worker }
251