Allow creation of HKDF using PRK bytes. Change-Id: I34a326fb8c0e83c81380bc6608b7f0b52c63e7c0 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/67987 Reviewed-by: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com>
diff --git a/rust/bssl-crypto/src/hkdf.rs b/rust/bssl-crypto/src/hkdf.rs index 973ed88..532468f 100644 --- a/rust/bssl-crypto/src/hkdf.rs +++ b/rust/bssl-crypto/src/hkdf.rs
@@ -63,6 +63,20 @@ //! //! assert_eq!(out, HkdfSha256::derive(b"secret", hkdf::Salt::None, b"info")); //! ``` +//! +//! To expand output from the explicit bytes of a PRK, use `Prk::new`: +//! +//! ``` +//! use bssl_crypto::{digest::Sha256, digest::Algorithm, hkdf}; +//! +//! let prk: [u8; Sha256::OUTPUT_LEN] = bssl_crypto::rand_array(); +//! // unwrap: only fails if the input is not equal to the digest length, which +//! // cannot happen here. +//! let prk = hkdf::Prk::new::<Sha256>(&prk).unwrap(); +//! let mut out = vec![0u8; 42]; +//! prk.expand_into(b"info", &mut out)?; +//! # Ok::<(), hkdf::TooLong>(()) +//! ``` use crate::{digest, sealed, with_output_array, FfiMutSlice, FfiSlice, ForeignTypeRef}; use core::marker::PhantomData; @@ -173,6 +187,33 @@ #[allow(clippy::let_unit_value)] impl Prk { + /// Creates a Prk from bytes. + pub fn new<MD: digest::Algorithm>(prk_bytes: &[u8]) -> Option<Self> { + if prk_bytes.len() != MD::OUTPUT_LEN { + return None; + } + + let mut prk = [0u8; bssl_sys::EVP_MAX_MD_SIZE as usize]; + prk.get_mut(..MD::OUTPUT_LEN) + // unwrap: `EVP_MAX_MD_SIZE` must be greater than the length of any + // digest function thus this is always successful. + .unwrap() + .copy_from_slice(prk_bytes); + + Some(Prk { + prk, + len: MD::OUTPUT_LEN, + evp_md: MD::get_md(sealed::Sealed).as_ptr(), + }) + } + + /// Returns the bytes of the pseudorandom key. + pub fn as_bytes(&self) -> &[u8] { + // `self.len` must be less than the length of `self.prk` thus + // this is always in bounds. + &self.prk[..self.len] + } + /// Derive key material for the given info parameter. Attempting /// to derive more than 255 bytes is a compile-time error, see `expand_into` /// for longer outputs. @@ -243,7 +284,8 @@ )] mod tests { use crate::{ - hkdf::{HkdfSha256, HkdfSha512, Salt}, + digest::Sha256, + hkdf::{HkdfSha256, HkdfSha512, Prk, Salt}, test_helpers::{decode_hex, decode_hex_into_vec}, }; @@ -280,6 +322,7 @@ ikm: Vec<u8>, salt: Vec<u8>, info: Vec<u8>, + prk: Vec<u8>, okm: Vec<u8>, } let tests = [ @@ -288,6 +331,10 @@ ikm: decode_hex_into_vec("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), salt: decode_hex_into_vec("000102030405060708090a0b0c"), info: decode_hex_into_vec("f0f1f2f3f4f5f6f7f8f9"), + prk: decode_hex_into_vec( + "077709362c2e32df0ddc3f0dc47bba63\ + 90b6c73bb50f9c3122ec844ad7c2b3e5", + ), okm: decode_hex_into_vec("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") }, Test { @@ -313,6 +360,10 @@ e0e1e2e3e4e5e6e7e8e9eaebecedeeef\ f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", ), + prk: decode_hex_into_vec( + "06a6b88c5853361a06104c9ceb35b45c\ + ef760014904671014a193f40c15fc244", + ), okm: decode_hex_into_vec( "b11e398dc80327a1c8e7f78c596a4934\ 4f012eda2d4efad8a050cc4c19afa97c\ @@ -327,6 +378,10 @@ ikm: decode_hex_into_vec("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), salt: Vec::new(), info: Vec::new(), + prk: decode_hex_into_vec( + "19ef24a32c717b167f33a91d6f648bdf\ + 96596776afdb6377ac434c1c293ccb04", + ), okm: decode_hex_into_vec( "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"), }, @@ -336,6 +391,7 @@ ikm, salt, info, + prk, okm, } in tests.iter() { @@ -349,6 +405,12 @@ HkdfSha256::derive_into(ikm.as_slice(), salt, info.as_slice(), &mut okm2).is_ok() ); assert_eq!(okm2.as_slice(), okm.as_slice()); + + let prk2 = Prk::new::<Sha256>(prk.as_slice()).unwrap(); + assert_eq!(prk2.as_bytes(), prk.as_slice()); + let mut okm3 = vec![0u8; okm.len()]; + let _ = prk2.expand_into(info.as_slice(), &mut okm3); + assert_eq!(okm3.as_slice(), okm.as_slice()); } } @@ -361,4 +423,16 @@ let mut too_long = vec![0u8; HkdfSha256::MAX_OUTPUT_LEN + 1]; assert!(hkdf.expand_into(b"", &mut too_long).is_err()); } + + #[test] + fn wrong_prk_len() { + assert!(Prk::new::<Sha256>( + decode_hex_into_vec("077709362c2e32df0ddc3f0dc47bba63").as_slice() + ) + .is_none()); + assert!(Prk::new::<Sha256>( + decode_hex_into_vec("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e590b6c73bb50f9c3122ec844ad7c2b3e5").as_slice()) + .is_none() + ); + } }