@@ -212,10 +212,16 @@ use bouncycastle_core::traits::XOF;
212212// end doc-only imports
213213
214214/*** Constants ***/
215- // Slightly hacky, but set this to accommodate the underlying hash primitive with the largest output size.
216- // Would be better to somehow pull that at compile time from H, but I'm not sure how to do that.
217- // todo can I delete this?
218- const HMAC_BLOCK_LEN : usize = 64 ;
215+ /// The size of the output key material from the HKDF-Extract phase `prk`, in bytes.
216+ /// This has been sized so that the output KeyMaterial has enough capacity to accommodate the
217+ /// underlying hash primitive with the largest output size.
218+ /// If the given hash function has a smaller output size, then the output KeyMaterial will be
219+ /// under-full (ie have a key_len that does not use its full capacity).
220+ /// TODO: This is a dirty dirty hack because correctly sizing the output key
221+ /// really requires the generic_const_exprs feature, which is currently only available on
222+ /// nightly Rust, and not on stable. Once they merge that feature, we will be able to get rid of this
223+ /// and declare `okm: &mut KeyMaterial<H::OUTPUT_LEN>` instead of this hack.
224+ pub const MAX_HMAC_OUTPUT_LEN : usize = 64 ;
219225
220226/*** String constants ***/
221227
@@ -382,7 +388,7 @@ impl<H: Hash + HashAlgParams + Default> HKDF<H> {
382388 salt : & impl KeyMaterialTrait ,
383389 ikm : & impl KeyMaterialTrait ,
384390 ) -> Result < impl KeyMaterialTrait , MACError > {
385- let mut prk = KeyMaterial :: < HMAC_BLOCK_LEN > :: new ( ) ;
391+ let mut prk = KeyMaterial :: < MAX_HMAC_OUTPUT_LEN > :: new ( ) ;
386392 Self :: extract_out ( salt, ikm, & mut prk) ?;
387393 Ok ( prk)
388394 }
@@ -392,7 +398,7 @@ impl<H: Hash + HashAlgParams + Default> HKDF<H> {
392398 pub fn extract_out (
393399 salt : & impl KeyMaterialTrait ,
394400 ikm : & impl KeyMaterialTrait ,
395- prk : & mut KeyMaterial < H :: OUTPUT_LEN > ,
401+ prk : & mut KeyMaterial < MAX_HMAC_OUTPUT_LEN > ,
396402 ) -> Result < usize , MACError > {
397403 // PRK = HMAC-Hash(salt, IKM)
398404
@@ -474,12 +480,15 @@ impl<H: Hash + HashAlgParams + Default> HKDF<H> {
474480
475481 // Could potentially speed this up by unrolling T(0) and T(1)
476482
477- // We're gonna have to kludge the prk key type to MACKey to make HMAC happy, but we'll set it back to the original value afterwards.
478- let prk_as_mac_key =
479- KeyMaterial :: < HMAC_BLOCK_LEN > :: from_bytes_as_type ( prk. ref_to_bytes ( ) , KeyType :: MACKey ) ?;
483+ // We're gonna have to kludge the prk key type to MACKey to make HMAC happy,
484+ // but we'll set it back to the original value afterwards.
485+ let prk_as_mac_key = KeyMaterial :: < MAX_HMAC_OUTPUT_LEN > :: from_bytes_as_type (
486+ prk. ref_to_bytes ( ) ,
487+ KeyType :: MACKey ,
488+ ) ?;
480489
481490 #[ allow( non_snake_case) ]
482- let mut T = [ 0u8 ; HMAC_BLOCK_LEN ] ;
491+ let mut T = [ 0u8 ; MAX_HMAC_OUTPUT_LEN ] ;
483492 let mut t_len: usize = 0 ;
484493 let mut i = 1u8 ;
485494
@@ -637,18 +646,18 @@ impl<H: Hash + HashAlgParams + Default> HKDF<H> {
637646
638647 /// Finish the HKDF-Extract phase and produce the output `prk`.
639648 #[ allow( non_snake_case) ]
640- pub fn do_extract_final ( self ) -> Result < KeyMaterial < HMAC_BLOCK_LEN > , MACError > {
641- let mut okm = KeyMaterial :: < HMAC_BLOCK_LEN > :: new ( ) ;
642- self . do_extract_final_out ( & mut okm ) ?;
643- Ok ( okm )
649+ pub fn do_extract_final ( self ) -> Result < KeyMaterial < MAX_HMAC_OUTPUT_LEN > , MACError > {
650+ let mut prk = KeyMaterial :: < MAX_HMAC_OUTPUT_LEN > :: new ( ) ;
651+ self . do_extract_final_out ( & mut prk ) ?;
652+ Ok ( prk )
644653 }
645654
646655 /// Finish the HKDF-Extract phase and fill the provided `prk`.
647656 /// Note that the provided KeyMaterial must be correctly sized to the HMAC block length.
648657 #[ allow( non_snake_case) ]
649658 pub fn do_extract_final_out (
650659 self ,
651- okm : & mut KeyMaterial < HMAC_BLOCK_LEN > ,
660+ prk : & mut KeyMaterial < MAX_HMAC_OUTPUT_LEN > ,
652661 ) -> Result < usize , MACError > {
653662 if self . state == HkdfStates :: Uninitialized {
654663 return Err ( MACError :: InvalidState (
@@ -660,7 +669,7 @@ impl<H: Hash + HashAlgParams + Default> HKDF<H> {
660669 let output_key_type = self . entropy . get_output_key_type ( ) ; // need to do this above self.hmac.do_final_out, which will consume self.
661670
662671 let mut bytes_written = 0 ;
663- key_material:: do_hazardous_operations ( okm , |okm| {
672+ key_material:: do_hazardous_operations ( prk , |okm| {
664673 bytes_written = self
665674 . hmac
666675 . unwrap ( )
@@ -680,6 +689,9 @@ impl<H: Hash + HashAlgParams + Default> HKDF<H> {
680689 )
681690 }
682691 } ) ?;
692+ // By RFC5869, the output size of prk is HashLen denotes the length of the
693+ // hash function output in octets
694+ debug_assert_eq ! ( prk. key_len( ) , H :: OUTPUT_LEN ) ;
683695 Ok ( bytes_written)
684696 }
685697}
@@ -769,7 +781,7 @@ impl<H: Hash + HashAlgParams + Default> KDF for HKDF<H> {
769781 entropy. credit_entropy ( * key) ;
770782 }
771783 }
772- let mut prk = KeyMaterial :: < HMAC_BLOCK_LEN > :: new ( ) ;
784+ let mut prk = KeyMaterial :: < MAX_HMAC_OUTPUT_LEN > :: new ( ) ;
773785 _ = hkdf. do_extract_final_out ( & mut prk) ?;
774786 let bytes_written =
775787 HKDF :: < H > :: expand_out ( & prk, additional_input, output_key. capacity ( ) , output_key) ?;
0 commit comments