From 3c5be3496c1373234c76409aa19e434e208fb8e1 Mon Sep 17 00:00:00 2001 From: "Jan Winkelmann (keks)" Date: Wed, 13 Nov 2024 17:39:40 +0100 Subject: [PATCH] slight api change, more comments --- curve25519/src/impl_hacl.rs | 4 +++ curve25519/src/lib.rs | 4 +++ ed25519/src/impl_hacl.rs | 25 +++++++++++++++--- ed25519/src/lib.rs | 2 ++ hacl-rs/src/lib.rs | 5 ++++ libcrux-ecdh/src/hacl/curve25519.rs | 11 +++----- libcrux-hkdf/src/hacl.rs | 2 ++ libcrux-hkdf/src/hkdf.rs | 12 ++++++--- libcrux-hkdf/src/impl_hacl.rs | 39 ++++++++++++++++++----------- libcrux-hmac/src/impl_hacl.rs | 1 + sha2/src/impl_hacl.rs | 14 +++++++++-- src/hpke/kdf.rs | 9 +++---- src/signature.rs | 5 +++- 13 files changed, 95 insertions(+), 38 deletions(-) diff --git a/curve25519/src/impl_hacl.rs b/curve25519/src/impl_hacl.rs index af8cd90d8..71e9bc491 100644 --- a/curve25519/src/impl_hacl.rs +++ b/curve25519/src/impl_hacl.rs @@ -4,10 +4,14 @@ use super::*; pub struct HaclCurve25519; impl Curve25519 for HaclCurve25519 { + // the hacl::ecdh function requires all parameters to be 32 byte long, which we enforce using + // types. fn secret_to_public(pk: &mut [u8; PK_LEN], sk: &[u8; SK_LEN]) { crate::hacl::secret_to_public(pk, sk) } + // the hacl::ecdh function requires all parameters to be 32 byte long, which we enforce using + // types. fn ecdh(out: &mut [u8; SHK_LEN], pk: &[u8; PK_LEN], sk: &[u8; SK_LEN]) -> Result<(), Error> { if crate::hacl::ecdh(out, sk, pk) { Ok(()) diff --git a/curve25519/src/lib.rs b/curve25519/src/lib.rs index 1568b993c..e1480f697 100644 --- a/curve25519/src/lib.rs +++ b/curve25519/src/lib.rs @@ -22,7 +22,11 @@ pub struct Error; /// This trait is implemented by the backing implementations. /// Only used for implementation agility. trait Curve25519 { + /// Computes a public key from a secret key. fn secret_to_public(pk: &mut [u8; PK_LEN], sk: &[u8; SK_LEN]); + + /// Computes the scalar multiplication between the provided public and secret keys. Returns an + /// error if the result is 0. fn ecdh(out: &mut [u8; SHK_LEN], pk: &[u8; PK_LEN], sk: &[u8; SK_LEN]) -> Result<(), Error>; } diff --git a/ed25519/src/impl_hacl.rs b/ed25519/src/impl_hacl.rs index 0020d12fd..a0e958245 100644 --- a/ed25519/src/impl_hacl.rs +++ b/ed25519/src/impl_hacl.rs @@ -4,6 +4,14 @@ pub enum Error { InvalidSignature, } +/// The hacl implementation requires that +/// - the private key is a 32 byte buffer +/// - the signature is a 64 byte buffer, +/// - the payload buffer is not shorter than payload_len. +/// +/// We enfore the first two using types, and the latter by using `payload.len()` and `payload_len`. +/// This has the caveat that `payload_len` must be <= u32::MAX, so we return an error if that is +/// not the case. pub fn sign(payload: &[u8], private_key: &[u8; 32]) -> Result<[u8; 64], Error> { let mut signature = [0u8; 64]; crate::hacl::ed25519::sign( @@ -16,6 +24,15 @@ pub fn sign(payload: &[u8], private_key: &[u8; 32]) -> Result<[u8; 64], Error> { Ok(signature) } +/// The hacl implementation requires that +/// - the public key is a 32 byte buffer +/// - the signature is a 64 byte buffer, +/// - the payload buffer is not shorter than payload_len. +/// +/// We enfore the first two using types, and the latter by using `payload.len()` and `payload_len`. +/// This has the caveat that `payload_len` must be <= u32::MAX, so we return an error if that is +/// not the case. +/// pub fn verify(payload: &[u8], public_key: &[u8; 32], signature: &[u8; 64]) -> Result<(), Error> { if crate::hacl::ed25519::verify( public_key, @@ -30,8 +47,8 @@ pub fn verify(payload: &[u8], public_key: &[u8; 32], signature: &[u8; 64]) -> Re } /// Compute the public point for the given secret key `sk`. -pub fn secret_to_public(sk: &[u8; 32]) -> [u8; 32] { - let mut out = [0u8; 32]; - crate::hacl::ed25519::secret_to_public(&mut out, sk); - out +/// The hacl implementation requires that these are both 32 byte buffers, which we enforce through +/// types. +pub fn secret_to_public(pk: &mut [u8; 32], sk: &[u8; 32]) { + crate::hacl::ed25519::secret_to_public(pk, sk) } diff --git a/ed25519/src/lib.rs b/ed25519/src/lib.rs index 13c1567d3..e8896ce66 100644 --- a/ed25519/src/lib.rs +++ b/ed25519/src/lib.rs @@ -1,5 +1,7 @@ #[cfg(feature = "hacl")] pub mod hacl { + //! This module contains generated hacl code. + pub mod ed25519; pub mod ed25519_precomptable; } diff --git a/hacl-rs/src/lib.rs b/hacl-rs/src/lib.rs index 96fa25749..3aaaaa6fe 100644 --- a/hacl-rs/src/lib.rs +++ b/hacl-rs/src/lib.rs @@ -1,3 +1,8 @@ +//! This crate contains hacl-generated utility modules for other hacl-generated code. +//! You most likely don't need to import this. +//! +//! hacl-star commit: efbf82f29190e2aecdac8899e4f42c8cb9defc98 + // Utility modules. In the generated hacl-rs, these are individual crates. pub mod bignum; pub mod fstar; diff --git a/libcrux-ecdh/src/hacl/curve25519.rs b/libcrux-ecdh/src/hacl/curve25519.rs index 5fd0b62dd..bd212c05e 100644 --- a/libcrux-ecdh/src/hacl/curve25519.rs +++ b/libcrux-ecdh/src/hacl/curve25519.rs @@ -12,12 +12,9 @@ pub fn ecdh( public_key: impl AsRef<[u8; 32]>, ) -> Result<[u8; 32], Error> { let mut shared = [0u8; 32]; - let ok = libcrux_curve25519::hacl::ecdh(&mut shared, private_key.as_ref(), public_key.as_ref()); - - if !ok { - Err(Error::InvalidInput) - } else { - Ok(shared) + match libcrux_curve25519::ecdh(&mut shared, private_key.as_ref(), public_key.as_ref()) { + Ok(_) => Ok(shared), + Err(_) => Err(Error::InvalidInput), } } @@ -29,7 +26,7 @@ pub fn ecdh( #[inline(always)] pub fn secret_to_public(private_key: impl AsRef<[u8; 32]>) -> [u8; 32] { let mut public = [0u8; 32]; - libcrux_curve25519::hacl::secret_to_public(&mut public, private_key.as_ref()); + libcrux_curve25519::secret_to_public(&mut public, private_key.as_ref()); public } diff --git a/libcrux-hkdf/src/hacl.rs b/libcrux-hkdf/src/hacl.rs index 94700681a..ab8321a0f 100644 --- a/libcrux-hkdf/src/hacl.rs +++ b/libcrux-hkdf/src/hacl.rs @@ -4,6 +4,8 @@ #![allow(unused_assignments)] #![allow(unreachable_patterns)] +//! This module contains generated hacl code. + use libcrux_hacl_rs::lowstar; /** diff --git a/libcrux-hkdf/src/hkdf.rs b/libcrux-hkdf/src/hkdf.rs index 344b3ad9c..83a0ca004 100644 --- a/libcrux-hkdf/src/hkdf.rs +++ b/libcrux-hkdf/src/hkdf.rs @@ -41,7 +41,11 @@ pub enum Error { /// HKDF extract using hash function `mode`, `salt`, and the input key material `ikm`. /// Returns the pre-key material in a vector of tag length. -pub fn extract(alg: Algorithm, salt: impl AsRef<[u8]>, ikm: impl AsRef<[u8]>) -> Vec { +pub fn extract( + alg: Algorithm, + salt: impl AsRef<[u8]>, + ikm: impl AsRef<[u8]>, +) -> Result, Error> { let salt = salt.as_ref(); let ikm = ikm.as_ref(); match alg { @@ -91,8 +95,8 @@ pub fn hkdf( } } -fn allocbuf(f: F) -> Vec { +fn allocbuf Result>(f: F) -> Result, E> { let mut buf = [0u8; N]; - f(&mut buf); - buf.into() + + f(&mut buf).map(|_| buf.into()) } diff --git a/libcrux-hkdf/src/impl_hacl.rs b/libcrux-hkdf/src/impl_hacl.rs index 9accc5b43..a296a72ff 100644 --- a/libcrux-hkdf/src/impl_hacl.rs +++ b/libcrux-hkdf/src/impl_hacl.rs @@ -10,7 +10,7 @@ pub trait HkdfMode { /// 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]); + 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. @@ -47,9 +47,10 @@ pub trait HkdfMode { info: &[u8], ) -> Result<(), Error> { let mut prk = [0u8; HASH_LEN]; - Self::extract(&mut prk, salt, ikm); + 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. @@ -58,7 +59,7 @@ pub trait HkdfMode { /// 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::extract(&mut prk, salt, ikm)?; Self::expand_vec(&prk, info, okm_len) } } @@ -73,7 +74,11 @@ macro_rules! impl_hkdf { impl HkdfMode<$hash_len> for $sname { const MODE: Algorithm = $mode; - fn extract(prk: &mut [u8; $hash_len], salt: &[u8], ikm: &[u8]) { + fn extract( + prk: &mut [u8; $hash_len], + salt: &[u8], + ikm: &[u8], + ) -> Result<(), Error> { extract(prk, salt, ikm) } @@ -93,15 +98,20 @@ macro_rules! impl_hkdf { /// HKDF extract using the `salt`, and the input key material `ikm`. /// Returns the pre-key material in an array of hash length. /// - /// Note that this function panics if `salt` or `ikm` is longer than (2**32 - 1) bytes. - pub fn extract(prk: &mut [u8; $hash_len], salt: &[u8], ikm: &[u8]) { - crate::hacl::$extract( + /// Note that this function returns an [`Error::ArgumentsTooLarge`] + /// if `salt` or `ikm` is larger than 2**32 bytes. + pub fn extract( + prk: &mut [u8; $hash_len], + salt: &[u8], + ikm: &[u8], + ) -> Result<(), Error> { + Ok(crate::hacl::$extract( prk, salt, - checked_u32(salt.len()).unwrap(), + checked_u32(salt.len())?, ikm, - checked_u32(ikm.len()).unwrap(), - ); + checked_u32(ikm.len())?, + )) } /// HKDF expand using the pre-key material `prk` and `info`. The output length @@ -110,7 +120,7 @@ macro_rules! impl_hkdf { /// [`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 larger than 2**32 bytes. + /// if `prk`, `info`, or `OKM_LEN` is larger than 2**32 bytes. pub fn expand( okm: &mut [u8; OKM_LEN], prk: &[u8], @@ -121,15 +131,14 @@ macro_rules! impl_hkdf { return Err(Error::OkmTooLarge); } - crate::hacl::$expand( + Ok(crate::hacl::$expand( okm, prk, checked_u32(prk.len())?, info, checked_u32(info.len())?, checked_u32(OKM_LEN)?, - ); - Ok(()) + )) } /// HKDF using the `salt`, input key material `ikm`, `info`. The output length @@ -145,7 +154,7 @@ macro_rules! impl_hkdf { info: &[u8], ) -> Result<(), Error> { let mut prk = [0u8; $hash_len]; - extract(&mut prk, salt, ikm); + extract(&mut prk, salt, ikm)?; expand(okm, &prk, info) } diff --git a/libcrux-hmac/src/impl_hacl.rs b/libcrux-hmac/src/impl_hacl.rs index 0f3bce549..a5d90d31a 100644 --- a/libcrux-hmac/src/impl_hacl.rs +++ b/libcrux-hmac/src/impl_hacl.rs @@ -3,6 +3,7 @@ macro_rules! impl_hmac { /// Compute HMAC. /// /// Note that this function panics if `key` or `data` is larger than 2**32 bytes. + /// This ensures that all values are in the range valid to be consumed by hacl-rs. pub fn $name(dst: &mut [u8; $tag_len], key: &[u8], data: &[u8]) { $fun( dst, diff --git a/sha2/src/impl_hacl.rs b/sha2/src/impl_hacl.rs index bb62a4be7..134cf544c 100644 --- a/sha2/src/impl_hacl.rs +++ b/sha2/src/impl_hacl.rs @@ -2,6 +2,8 @@ use super::*; use libcrux_traits::Digest; /// SHA2 224 +/// Will panic if `payload` is longer than `u32::MAX` to ensure that hacl-rs can +/// process it. pub fn sha224(payload: &[u8]) -> [u8; SHA224_LENGTH] { let mut digest = [0u8; SHA224_LENGTH]; Sha224::hash(&mut digest, payload); @@ -9,6 +11,8 @@ pub fn sha224(payload: &[u8]) -> [u8; SHA224_LENGTH] { } /// SHA2 256 +/// Will panic if `payload` is longer than `u32::MAX` to ensure that hacl-rs can +/// process it. pub fn sha256(payload: &[u8]) -> [u8; SHA256_LENGTH] { let mut digest = [0u8; SHA256_LENGTH]; Sha256::hash(&mut digest, payload); @@ -16,6 +20,8 @@ pub fn sha256(payload: &[u8]) -> [u8; SHA256_LENGTH] { } /// SHA2 384 +/// Will panic if `payload` is longer than `u32::MAX` to ensure that hacl-rs can +/// process it. pub fn sha384(payload: &[u8]) -> [u8; SHA384_LENGTH] { let mut digest = [0u8; SHA384_LENGTH]; Sha384::hash(&mut digest, payload); @@ -23,6 +29,8 @@ pub fn sha384(payload: &[u8]) -> [u8; SHA384_LENGTH] { } /// SHA2 512 +/// Will panic if `payload` is longer than `u32::MAX` to ensure that hacl-rs can +/// process it. pub fn sha512(payload: &[u8]) -> [u8; SHA512_LENGTH] { let mut digest = [0u8; SHA512_LENGTH]; Sha512::hash(&mut digest, payload); @@ -47,14 +55,16 @@ macro_rules! impl_hash { impl libcrux_traits::Digest<$digest_size> for $name { /// Return the digest for the given input byte slice, in immediate mode. - /// Will panic if `payload` is longer than `u32::MAX`. + /// Will panic if `payload` is longer than `u32::MAX` to ensure that hacl-rs can + /// process it. fn hash(digest: &mut [u8; $digest_size], payload: &[u8]) { let payload_len = payload.len().try_into().unwrap(); $hash(digest, payload, payload_len) } /// Add the `payload` to the digest. - /// Will panic if `payload` is longer than `u32::MAX`. + /// Will panic if `payload` is longer than `u32::MAX` to ensure that hacl-rs can + /// process it. fn update(&mut self, payload: &[u8]) { let payload_len = payload.len().try_into().unwrap(); $update(self.state.as_mut(), payload, payload_len); diff --git a/src/hpke/kdf.rs b/src/hpke/kdf.rs index dee6f875b..fcce60217 100644 --- a/src/hpke/kdf.rs +++ b/src/hpke/kdf.rs @@ -98,11 +98,10 @@ pub fn LabeledExtract( labeled_ikm.extend_from_slice(&label); labeled_ikm.extend_from_slice(ikm); - Ok(crate::hkdf::extract( - hkdf_algorithm(alg), - salt, - &labeled_ikm, - )) + crate::hkdf::extract(hkdf_algorithm(alg), salt, &labeled_ikm).map_err(|err| match err { + libcrux_hkdf::Error::OkmTooLarge => HpkeError::CryptoError, + libcrux_hkdf::Error::ArgumentsTooLarge => HpkeError::InvalidParameters, + }) } /// KDF: Labeled Expand diff --git a/src/signature.rs b/src/signature.rs index 4a140cccc..b8e7dbd9d 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -481,6 +481,8 @@ pub fn key_gen( Algorithm::Ed25519 => { const LIMIT: usize = 100; let mut sk = [0u8; 32]; + let mut pk = [0u8; 32]; + for _ in 0..LIMIT { rng.try_fill_bytes(&mut sk) .map_err(|_| Error::KeyGenError)?; @@ -498,7 +500,8 @@ pub fn key_gen( break; } - let pk = ed25519::secret_to_public(&sk); + + ed25519::secret_to_public(&mut pk, &sk); Ok((sk.to_vec(), pk.to_vec())) }