diff --git a/libcrux-hkdf/src/hkdf.rs b/libcrux-hkdf/src/hkdf.rs index 83a0ca004..9bd3e282e 100644 --- a/libcrux-hkdf/src/hkdf.rs +++ b/libcrux-hkdf/src/hkdf.rs @@ -8,7 +8,73 @@ pub mod hacl; #[cfg(feature = "hacl")] mod impl_hacl; -use impl_hacl::{HkdfMode, HkdfSha2_256, HkdfSha2_384, HkdfSha2_512}; +pub use impl_hacl::{HkdfSha2_256, HkdfSha2_384, HkdfSha2_512}; + +pub trait HkdfMode { + /// The hash algorithm used in this HKDF mode. + const MODE: Algorithm; + + /// HKDF extract using the `salt` and the input key material `ikm`. + /// The result is written to `prk`. + /// + /// Returns nothing on success. + /// Returns [`Error::ArgumentsTooLarge`] if one of `ikm` or `salt` is longer than [`u32::MAX`] + /// bytes. + fn extract(prk: &mut [u8; HASH_LEN], salt: &[u8], ikm: &[u8]) -> Result<(), Error>; + + /// HKDF expand using the pre-key material `prk` and `info`. The output length + /// is defined through the type of the `okm` parameter, that the output is written to. + /// + /// Returns nothing on success. + /// Returns [`Error::OkmTooLarge`] if the requested `OKM_LEN` is large. + /// Returns [`Error::ArgumentsTooLarge`] if `prk` or `info` is longer than [`u32::MAX`] bytes. + fn expand( + okm: &mut [u8; OKM_LEN], + prk: &[u8], + info: &[u8], + ) -> Result<(), Error>; + + /// HKDF expand using the pre-key material `prk` and `info`. The output length + /// is defined by the parameter `okm_len`. + /// + /// Returns the key material in a [`Vec`] of length `okm_len` on success. + /// Returns [`Error::OkmTooLarge`] if the requested `okm_len` is too large. + /// Returns [`Error::ArgumentsTooLarge`] if `prk` or `info` is longer than [`u32::MAX`] bytes. + fn expand_vec(prk: &[u8], info: &[u8], okm_len: usize) -> Result, Error>; + + /// HKDF using the `salt`, input key material `ikm`, `info`. + /// The result is written to `okm`. + /// The output length is defined through the length of `okm`. + /// Calls `extract` and `expand` with the given inputs. + /// + /// Returns nothing on success. + /// Returns [`Error::OkmTooLarge`] if the requested `OKM_LEN` is too large. + /// Returns [`Error::ArgumentsTooLarge`] if one of `ikm`, `salt` or `info` is longer than + /// [`u32::MAX`] bytes. + fn hkdf( + okm: &mut [u8; OKM_LEN], + salt: &[u8], + ikm: &[u8], + info: &[u8], + ) -> Result<(), Error> { + let mut prk = [0u8; HASH_LEN]; + Self::extract(&mut prk, salt, ikm)?; + Self::expand(okm, &prk, info) + } + + /// HKDF using the `salt`, input key material `ikm`, `info`. + /// The output length is defined by the parameter `okm_len`. + /// Calls `extract` and `expand_vec` with the given input. + /// + /// Returns the key material in a [`Vec`] of length `okm_len` on success. + /// Returns [`Error::OkmTooLarge`] if the requested `okm_len` is too large. + /// Returns [`Error::ArgumentsTooLarge`] if `salt`, `ikm` or `info` is longer than [`u32::MAX`] bytes. + fn hkdf_vec(salt: &[u8], ikm: &[u8], info: &[u8], okm_len: usize) -> Result, Error> { + let mut prk = [0u8; HASH_LEN]; + Self::extract(&mut prk, salt, ikm)?; + Self::expand_vec(&prk, info, okm_len) + } +} /// The HKDF algorithm defining the used hash function. #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/libcrux-hkdf/src/impl_hacl.rs b/libcrux-hkdf/src/impl_hacl.rs index a296a72ff..1797b1bba 100644 --- a/libcrux-hkdf/src/impl_hacl.rs +++ b/libcrux-hkdf/src/impl_hacl.rs @@ -1,77 +1,17 @@ #![allow(dead_code)] -use crate::{Algorithm, Error}; - -pub trait HkdfMode { - /// The hash algorithm used in this HKDF mode. - const MODE: Algorithm; - - /// HKDF extract using the `salt` and the input key material `ikm`. - /// The result is written to `prk`. - /// - /// Note that this function panics if `salt` or `ikm` is longer than (2**32 - 1) bytes. - fn extract(prk: &mut [u8; HASH_LEN], salt: &[u8], ikm: &[u8]) -> Result<(), Error>; - - /// HKDF expand using the pre-key material `prk` and `info`. The output length - /// is defined through the type of the `okm` parameter, that the output is written to. - /// - /// Returns nothing on success. - /// Returns [`Error::OkmTooLarge`] if the requested `okm_len` is too large. - /// Returns [`Error::ArgumentsTooLarge`] if one of `salt` or `ikm` are longer than, or - /// `OKM_LEN` is larger than (2**32 - 1) bytes. - fn expand( - okm: &mut [u8; OKM_LEN], - prk: &[u8], - info: &[u8], - ) -> Result<(), Error>; - - /// HKDF expand using the pre-key material `prk` and `info`. The output length - /// is defined by the parameter `okm_len`. - /// - /// Returns the key material in an array of length `okm_len` on success. - /// Returns [`Error::OkmTooLarge`] if the requested `okm_len` is too large. - /// Returns [`Error::ArgumentsTooLarge`] if `salt` or `ikm` is longer than - /// (2**32 - 1) bytes. - fn expand_vec(prk: &[u8], info: &[u8], okm_len: usize) -> Result, Error>; - - /// HKDF using the `salt`, input key material `ikm`, `info`. The output length - /// is defined through the result type. - /// Calls `extract` and `expand` with the given input. - /// - /// Returns the key material in an array of length `okm_len`. - /// Note that this function panics if `salt` or `ikm` is longer than (2**32 - 1) bytes. - fn hkdf( - okm: &mut [u8; OKM_LEN], - salt: &[u8], - ikm: &[u8], - info: &[u8], - ) -> Result<(), Error> { - let mut prk = [0u8; HASH_LEN]; - Self::extract(&mut prk, salt, ikm)?; - Self::expand(okm, &prk, info) - } - - /// HKDF using the `salt`, input key material `ikm`, `info`. The output length - /// is defined by the parameter `okm_len`. - /// Calls `extract` and `expand` with the given input. - /// - /// Returns the key material in an array of length `okm_len`. - /// Note that this function panics if `salt` or `ikm` is longer than (2**32 - 1) bytes. - fn hkdf_vec(salt: &[u8], ikm: &[u8], info: &[u8], okm_len: usize) -> Result, Error> { - let mut prk = [0u8; HASH_LEN]; - Self::extract(&mut prk, salt, ikm)?; - Self::expand_vec(&prk, info, okm_len) - } -} +use crate::{Algorithm, Error, HkdfMode}; macro_rules! impl_hkdf { - ($sname:ident,$name:ident, $mode:path, $extract:ident, $expand:ident,$hash_len:literal) => { - pub struct $sname; + ($struct_name:ident,$name:ident, $string_name:literal, $mode:path, $extract:ident, $expand:ident,$hash_len:literal) => { + #[doc = "Implementation of HKDF backed by"] + #[doc = $string_name] + pub struct $struct_name; pub mod $name { - use super::{checked_u32, $sname, Algorithm, Error, HkdfMode}; + use super::{checked_u32, $struct_name, Algorithm, Error, HkdfMode}; - impl HkdfMode<$hash_len> for $sname { + impl HkdfMode<$hash_len> for $struct_name { const MODE: Algorithm = $mode; fn extract( @@ -91,15 +31,16 @@ macro_rules! impl_hkdf { } fn expand_vec(prk: &[u8], info: &[u8], okm_len: usize) -> Result, Error> { - vec::expand(prk, info, okm_len) + expand_vec(prk, info, okm_len) } } - /// HKDF extract using the `salt`, and the input key material `ikm`. - /// Returns the pre-key material in an array of hash length. + /// HKDF extract using the `salt` and the input key material `ikm`. + /// The result is written to `prk`. /// - /// Note that this function returns an [`Error::ArgumentsTooLarge`] - /// if `salt` or `ikm` is larger than 2**32 bytes. + /// Returns nothing on success. + /// Returns [`Error::ArgumentsTooLarge`] if one of `ikm` or `salt` is longer than + /// [`u32::MAX`] bytes. pub fn extract( prk: &mut [u8; $hash_len], salt: &[u8], @@ -114,13 +55,13 @@ macro_rules! impl_hkdf { )) } - /// HKDF expand using the pre-key material `prk` and `info`. The output length - /// is defined through the result type. - /// Returns the key material in an array of length `okm_len` or - /// [`Error::OkmTooLarge`] if the requested `okm_len` is too large. + /// HKDF expand using the pre-key material `prk` and `info`. + /// The output is written to `okm`. /// - /// Note that this function returns an [`Error::ArgumentsTooLarge`] - /// if `prk`, `info`, or `OKM_LEN` is larger than 2**32 bytes. + /// Returns nothing on success. + /// Returns [`Error::OkmTooLarge`] if the requested `OKM_LEN` is large. + /// Returns [`Error::ArgumentsTooLarge`] if one of `prk` or `info` is longer than + /// [`u32::MAX`] bytes. pub fn expand( okm: &mut [u8; OKM_LEN], prk: &[u8], @@ -141,12 +82,39 @@ macro_rules! impl_hkdf { )) } - /// HKDF using the `salt`, input key material `ikm`, `info`. The output length - /// is defined through the result type. + /// HKDF expand using the pre-key material `prk` and `info`. The output length + /// is defined by the parameter `okm_len`. + /// + /// Returns the key material in a [`Vec`] of length `okm_len` on success. + /// Returns [`Error::OkmTooLarge`] if the requested `okm_len` is too large. + /// Returns [`Error::ArgumentsTooLarge`] if `prk` or `info` is longer than [`u32::MAX`] bytes. + pub fn expand_vec(prk: &[u8], info: &[u8], okm_len: usize) -> Result, Error> { + if okm_len > 255 * $hash_len { + // Output size is too large. HACL doesn't catch this. + return Err(Error::OkmTooLarge); + } + + let mut okm = vec![0u8; okm_len]; + crate::hacl::$expand( + &mut okm, + prk, + checked_u32(prk.len())?, + info, + checked_u32(info.len())?, + checked_u32(okm_len)?, + ); + Ok(okm) + } + + /// HKDF using the `salt`, input key material `ikm`, `info`. + /// The result is written to `okm`. + /// The output length is defined through the length of `okm`. /// Calls `extract` and `expand` with the given input. /// - /// Returns the key material in an array of length `okm_len`. - /// Note that this function panics if `salt` or `ikm` is longer than (2**32 - 1) bytes. + /// Returns nothing on success. + /// Returns [`Error::OkmTooLarge`] if the requested `OKM_LEN` is too large. + /// Returns [`Error::ArgumentsTooLarge`] if one of `ikm`, `salt` or `info` is longer + /// than [`u32::MAX`] bytes. pub fn hkdf( okm: &mut [u8; OKM_LEN], salt: &[u8], @@ -158,35 +126,22 @@ macro_rules! impl_hkdf { expand(okm, &prk, info) } - /// This module uses heap allocated vectors for cases where the output - /// length is not const. - pub mod vec { - use super::{checked_u32, Error}; - - /// HKDF expand using the pre-key material `prk` and `info`. The output length - /// is defined by the parameter `okm_len`. - /// Returns the key material in an array of length `okm_len` or - /// [`Error::OkmTooLarge`] if the requested `okm_len` is too large. - /// - /// Note that this function returns an [`Error::ArgumentsTooLarge`] - /// if `salt`, `ikm`, or `OKM_LEN` is longer than (2**32 - 1) bytes. - pub fn expand(prk: &[u8], info: &[u8], okm_len: usize) -> Result, Error> { - if okm_len > 255 * $hash_len { - // Output size is too large. HACL doesn't catch this. - return Err(Error::OkmTooLarge); - } - - let mut okm = vec![0u8; okm_len]; - crate::hacl::$expand( - &mut okm, - prk, - checked_u32(prk.len())?, - info, - checked_u32(info.len())?, - checked_u32(okm_len)?, - ); - Ok(okm) - } + /// HKDF using the `salt`, input key material `ikm`, `info`. + /// The output length is defined by the parameter `okm_len`. + /// Calls `extract` and `expand_vec` with the given input. + /// + /// Returns the key material in a [`Vec`] of length `okm_len` on success. + /// Returns [`Error::OkmTooLarge`] if the requested `okm_len` is too large. + /// Returns [`Error::ArgumentsTooLarge`] if `salt`, `ikm` or `info` is longer than [`u32::MAX`] bytes. + pub fn hkdf_vec( + salt: &[u8], + ikm: &[u8], + info: &[u8], + okm_len: usize, + ) -> Result, Error> { + let mut prk = [0u8; $hash_len]; + extract(&mut prk, salt, ikm)?; + expand_vec(&prk, info, okm_len) } } }; @@ -195,6 +150,7 @@ macro_rules! impl_hkdf { impl_hkdf!( HkdfSha2_256, sha2_256, + "SHA2-256", Algorithm::Sha256, extract_sha2_256, expand_sha2_256, @@ -204,6 +160,7 @@ impl_hkdf!( impl_hkdf!( HkdfSha2_384, sha2_384, + "SHA2-384", Algorithm::Sha384, extract_sha2_384, expand_sha2_384, @@ -213,6 +170,7 @@ impl_hkdf!( impl_hkdf!( HkdfSha2_512, sha2_512, + "SHA2-512", Algorithm::Sha512, extract_sha2_512, expand_sha2_512,