Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export fixed-size versions of HPKE #690

Merged
merged 5 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion libcrux-hkdf/src/hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<const HASH_LEN: usize> {
/// 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<const OKM_LEN: usize>(
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<u8>`] 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<Vec<u8>, 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<const OKM_LEN: usize>(
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<u8>`] 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<Vec<u8>, 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)]
Expand Down
180 changes: 69 additions & 111 deletions libcrux-hkdf/src/impl_hacl.rs
Original file line number Diff line number Diff line change
@@ -1,77 +1,17 @@
#![allow(dead_code)]

use crate::{Algorithm, Error};

pub trait HkdfMode<const HASH_LEN: usize> {
/// 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<const OKM_LEN: usize>(
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<Vec<u8>, 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<const OKM_LEN: usize>(
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<Vec<u8>, 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(
Expand All @@ -91,15 +31,16 @@ macro_rules! impl_hkdf {
}

fn expand_vec(prk: &[u8], info: &[u8], okm_len: usize) -> Result<Vec<u8>, 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],
Expand All @@ -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<const OKM_LEN: usize>(
okm: &mut [u8; OKM_LEN],
prk: &[u8],
Expand All @@ -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<u8>`] 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<Vec<u8>, 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<const OKM_LEN: usize>(
okm: &mut [u8; OKM_LEN],
salt: &[u8],
Expand All @@ -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<Vec<u8>, 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<u8>`] 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<Vec<u8>, Error> {
let mut prk = [0u8; $hash_len];
extract(&mut prk, salt, ikm)?;
expand_vec(&prk, info, okm_len)
}
}
};
Expand All @@ -195,6 +150,7 @@ macro_rules! impl_hkdf {
impl_hkdf!(
HkdfSha2_256,
sha2_256,
"SHA2-256",
Algorithm::Sha256,
extract_sha2_256,
expand_sha2_256,
Expand All @@ -204,6 +160,7 @@ impl_hkdf!(
impl_hkdf!(
HkdfSha2_384,
sha2_384,
"SHA2-384",
Algorithm::Sha384,
extract_sha2_384,
expand_sha2_384,
Expand All @@ -213,6 +170,7 @@ impl_hkdf!(
impl_hkdf!(
HkdfSha2_512,
sha2_512,
"SHA2-512",
Algorithm::Sha512,
extract_sha2_512,
expand_sha2_512,
Expand Down
Loading