introduce traits for all the primitives and algorithms. A bit more cleanup.

This commit is contained in:
Jan Winkelmann (keks)
2025-02-26 17:19:58 +01:00
parent 949a3e4d23
commit b84e0beae8
29 changed files with 469 additions and 177 deletions

3
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
@@ -1828,6 +1828,7 @@ dependencies = [
"anyhow", "anyhow",
"rosenpass-oqs", "rosenpass-oqs",
"rosenpass-secret-memory", "rosenpass-secret-memory",
"rosenpass-to",
"thiserror 2.0.11", "thiserror 2.0.11",
] ]

View File

@@ -11,6 +11,7 @@ readme = "readme.md"
[dependencies] [dependencies]
thiserror = "2" thiserror = "2"
rosenpass-to = { workspace = true }
[dev-dependencies] [dev-dependencies]
rosenpass-oqs = { workspace = true } rosenpass-oqs = { workspace = true }

View File

@@ -0,0 +1,81 @@
pub mod keyed_hash_incorrect_hmac_blake2b {
use crate::primitives::keyed_hash::*;
pub const KEY_LEN: usize = 32;
pub const OUT_LEN: usize = 32;
pub trait KeyedHashIncorrectHmacBlake2b: KeyedHash<KEY_LEN, OUT_LEN> {}
}
pub mod keyed_hash_blake2b {
use crate::primitives::keyed_hash::*;
pub const KEY_LEN: usize = 32;
pub const OUT_LEN: usize = 32;
pub trait KeyedHashBlake2b: KeyedHash<KEY_LEN, OUT_LEN> {}
}
pub mod keyed_hash_shake256 {
use crate::primitives::keyed_hash::*;
pub const KEY_LEN: usize = 32;
pub const OUT_LEN: usize = 32;
pub trait KeyedHashShake256: KeyedHash<KEY_LEN, OUT_LEN> {}
}
pub mod aead_chacha20poly1305 {
use crate::primitives::aead::*;
pub const KEY_LEN: usize = 32;
pub const NONCE_LEN: usize = 12;
pub const TAG_LEN: usize = 16;
pub trait AeadChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
}
pub mod aead_xchacha20poly1305 {
use crate::primitives::aead::*;
pub const KEY_LEN: usize = 32;
pub const NONCE_LEN: usize = 24;
pub const TAG_LEN: usize = 16;
pub trait AeadXChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
}
pub mod kem_kyber512 {
use crate::primitives::kem::*;
// page 33 of https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf
// (which is ml-kem instead of kyber, but it's the same)
pub const SK_LEN: usize = 1632;
pub const PK_LEN: usize = 800;
pub const CT_LEN: usize = 768;
pub const SHK_LEN: usize = 32;
pub trait KemKyber512: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
}
pub mod kem_classic_mceliece460896 {
use crate::primitives::kem::*;
// page 6 of https://classic.mceliece.org/mceliece-impl-20221023.pdf
pub const SK_LEN: usize = 13608;
pub const PK_LEN: usize = 524160;
pub const CT_LEN: usize = 156;
pub const SHK_LEN: usize = 32;
pub trait KemClassicMceliece460896: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
}
pub use aead_chacha20poly1305::AeadChaCha20Poly1305;
pub use aead_xchacha20poly1305::AeadXChaCha20Poly1305;
pub use kem_classic_mceliece460896::KemClassicMceliece460896;
pub use kem_kyber512::KemKyber512;
pub use keyed_hash_blake2b::KeyedHashBlake2b;
pub use keyed_hash_incorrect_hmac_blake2b::KeyedHashIncorrectHmacBlake2b;
pub use keyed_hash_shake256::KeyedHashShake256;

View File

@@ -1,2 +1,2 @@
mod primitives; pub mod algorithms;
pub use primitives::*; pub mod primitives;

View File

@@ -1,2 +1,7 @@
pub mod kem; pub(crate) mod aead;
pub mod keyed_hash; pub(crate) mod kem;
pub(crate) mod keyed_hash;
pub use aead::{Aead, AeadWithNonceInCiphertext, Error as AeadError};
pub use kem::{Error as KemError, Kem};
pub use keyed_hash::*;

View File

@@ -0,0 +1,73 @@
use thiserror::Error;
pub trait Aead<const KEY_LEN: usize, const NONCE_LEN: usize, const TAG_LEN: usize> {
const KEY_LEN: usize = KEY_LEN;
const NONCE_LEN: usize = NONCE_LEN;
const TAG_LEN: usize = TAG_LEN;
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), Error>;
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), Error>;
}
/// The API of XChaCha was a bit weird and moved the nonce into the ciphertext. Instead of changing
/// the protocol code, we recreate that API on top of the more normal API, but move it into a
/// separate crate.
pub trait AeadWithNonceInCiphertext<
const KEY_LEN: usize,
const NONCE_LEN: usize,
const TAG_LEN: usize,
>: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>
{
fn decrypt_with_nonce_in_ctxt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), Error> {
if ciphertext.len() < plaintext.len() + TAG_LEN + NONCE_LEN {
return Err(Error::InvalidLengths);
}
let (nonce, rest) = ciphertext.split_at(NONCE_LEN);
// We know this should be the right length (we just split it), and everything else would be
// very unexpected.
let nonce = nonce.try_into().map_err(|_| Error::InternalError)?;
self.decrypt(plaintext, key, nonce, ad, rest)
}
}
impl<
const KEY_LEN: usize,
const NONCE_LEN: usize,
const TAG_LEN: usize,
T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>,
> AeadWithNonceInCiphertext<KEY_LEN, NONCE_LEN, TAG_LEN> for T
{
}
#[derive(Debug, Error)]
pub enum Error {
#[error("internal error")]
InternalError,
#[error("decryption error")]
DecryptError,
#[error("buffers have invalid length")]
InvalidLengths,
}

View File

@@ -109,3 +109,40 @@ where
Static: KeyedHash<KEY_LEN, OUT_LEN>, Static: KeyedHash<KEY_LEN, OUT_LEN>,
{ {
} }
use rosenpass_to::{with_destination, To};
/// Extends the [`KeyedHash`] trait with a [`To`]-flavoured function.
pub trait KeyedHashTo<const KEY_LEN: usize, const HASH_LEN: usize>:
KeyedHash<KEY_LEN, HASH_LEN>
{
fn keyed_hash_to(
key: &[u8; KEY_LEN],
data: &[u8],
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
with_destination(|out| Self::keyed_hash(key, data, out))
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHash<KEY_LEN, HASH_LEN>>
KeyedHashTo<KEY_LEN, HASH_LEN> for T
{
}
/// Extends the [`KeyedHashInstance`] trait with a [`To`]-flavoured function.
pub trait KeyedHashInstanceTo<const KEY_LEN: usize, const HASH_LEN: usize>:
KeyedHashInstance<KEY_LEN, HASH_LEN>
{
fn keyed_hash_to(
&self,
key: &[u8; KEY_LEN],
data: &[u8],
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
with_destination(|out| self.keyed_hash(key, data, out))
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHashInstance<KEY_LEN, HASH_LEN>>
KeyedHashInstanceTo<KEY_LEN, HASH_LEN> for T
{
}

View File

@@ -29,10 +29,11 @@
use anyhow::Result; use anyhow::Result;
use rosenpass_secret_memory::Secret; use rosenpass_secret_memory::Secret;
use rosenpass_to::To as _;
pub use crate::keyed_hash::{KeyedHash, KEY_LEN}; pub use crate::{KeyedHash, KEY_LEN};
use rosenpass_cipher_traits::keyed_hash::KeyedHashInstance; use rosenpass_cipher_traits::primitives::KeyedHashInstanceTo;
// TODO Use a proper Dec interface // TODO Use a proper Dec interface
/// A use-once hash domain for a specified key that can be used directly. /// A use-once hash domain for a specified key that can be used directly.
@@ -78,7 +79,7 @@ impl HashDomain {
/// ///
pub fn mix(self, v: &[u8]) -> Result<Self> { pub fn mix(self, v: &[u8]) -> Result<Self> {
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN]; let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
self.1.keyed_hash(&self.0, v, &mut new_key)?; self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
Ok(Self(new_key, self.1)) Ok(Self(new_key, self.1))
} }
@@ -101,7 +102,7 @@ impl HashDomainNamespace {
/// as the `data` and uses the result as the key for the new [HashDomain]. /// as the `data` and uses the result as the key for the new [HashDomain].
pub fn mix(&self, v: &[u8]) -> Result<HashDomain> { pub fn mix(&self, v: &[u8]) -> Result<HashDomain> {
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN]; let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
self.1.keyed_hash(&self.0, v, &mut new_key)?; self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
Ok(HashDomain(new_key, self.1.clone())) Ok(HashDomain(new_key, self.1.clone()))
} }
@@ -129,9 +130,13 @@ impl SecretHashDomain {
hash_choice: KeyedHash, hash_choice: KeyedHash,
) -> Result<SecretHashDomain> { ) -> Result<SecretHashDomain> {
let mut new_secret_key = Secret::zero(); let mut new_secret_key = Secret::zero();
hash_choice.keyed_hash(k.try_into()?, d, new_secret_key.secret_mut())?; hash_choice
.keyed_hash_to(k.try_into()?, d)
.to(new_secret_key.secret_mut())?;
let mut r = SecretHashDomain(new_secret_key, hash_choice); let mut r = SecretHashDomain(new_secret_key, hash_choice);
KeyedHash::incorrect_hmac_blake2b().keyed_hash(k.try_into()?, d, r.0.secret_mut())?; KeyedHash::incorrect_hmac_blake2b()
.keyed_hash_to(k.try_into()?, d)
.to(r.0.secret_mut())?;
Ok(r) Ok(r)
} }
@@ -186,7 +191,7 @@ impl SecretHashDomain {
* let SecretHashDomain(secret, hash_choice) = &self; * let SecretHashDomain(secret, hash_choice) = &self;
* *
* let mut new_secret = Secret::zero(); * let mut new_secret = Secret::zero();
* hash_choice.keyed_hash(secret.secret(), dst, new_secret.secret_mut())?; * hash_choice.keyed_hash_to(secret.secret(), dst).to(new_secret.secret_mut())?;
* self.0 = new_secret; * self.0 = new_secret;
* *
* Ok(()) * Ok(())

View File

@@ -1,11 +1,12 @@
use rosenpass_cipher_traits::primitives::Aead as _;
use static_assertions::const_assert; use static_assertions::const_assert;
pub mod subtle; pub mod subtle;
/// All keyed primitives in this crate use 32 byte keys /// All keyed primitives in this crate use 32 byte keys
pub const KEY_LEN: usize = 32; pub const KEY_LEN: usize = 32;
const_assert!(KEY_LEN == aead::KEY_LEN); const_assert!(KEY_LEN == Aead::KEY_LEN);
const_assert!(KEY_LEN == xaead::KEY_LEN); const_assert!(KEY_LEN == XAead::KEY_LEN);
const_assert!(KEY_LEN == hash_domain::KEY_LEN); const_assert!(KEY_LEN == hash_domain::KEY_LEN);
/// Keyed hashing /// Keyed hashing
@@ -13,40 +14,30 @@ const_assert!(KEY_LEN == hash_domain::KEY_LEN);
/// This should only be used for implementation details; anything with relevance /// This should only be used for implementation details; anything with relevance
/// to the cryptographic protocol should use the facilities in [hash_domain], (though /// to the cryptographic protocol should use the facilities in [hash_domain], (though
/// hash domain uses this module internally) /// hash domain uses this module internally)
pub use crate::subtle::keyed_hash; pub use crate::subtle::keyed_hash::KeyedHash;
/// Authenticated encryption with associated data /// Authenticated encryption with associated data (AEAD)
/// Chacha20poly1305 is used. /// Chacha20poly1305 is used.
pub mod aead { #[cfg(feature = "experiment_libcrux")]
#[cfg(feature = "experiment_libcrux")] pub use subtle::libcrux::chacha20poly1305_ietf::Chacha20poly1305 as Aead;
pub use crate::subtle::libcrux::chacha20poly1305_ietf::{
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
};
#[cfg(not(feature = "experiment_libcrux"))] /// Authenticated encryption with associated data (AEAD)
pub use crate::subtle::rust_crypto::chacha20poly1305_ietf::{ /// Chacha20poly1305 is used.
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN, #[cfg(not(feature = "experiment_libcrux"))]
}; pub use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
}
/// Authenticated encryption with associated data with a constant nonce /// Authenticated encryption with associated data with a extended-length nonce (XAEAD)
/// XChacha20poly1305 is used. /// XChacha20poly1305 is used.
pub mod xaead { pub use crate::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305 as XAead;
pub use crate::subtle::rust_crypto::xchacha20poly1305_ietf::{
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN, /// Use Classic-McEcliece-460986 as the Static KEM.
}; ///
} /// See [rosenpass_oqs::ClassicMceliece460896] for more details.
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
/// Use Kyber-512 as the Static KEM
///
/// See [rosenpass_oqs::Kyber512] for more details.
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
pub mod hash_domain; pub mod hash_domain;
/// This crate includes two key encapsulation mechanisms.
/// Namely ClassicMceliece460896 (also referred to as `StaticKem` sometimes) and
/// Kyber512 (also referred to as `EphemeralKem` sometimes).
///
/// See [rosenpass_oqs::ClassicMceliece460896]
/// and [rosenpass_oqs::Kyber512] for more details on the specific KEMS.
///
pub mod kem {
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
}

View File

@@ -1,5 +1,8 @@
use anyhow::ensure; use anyhow::ensure;
use rosenpass_cipher_traits::keyed_hash::{InferKeyedHash, KeyedHash}; use rosenpass_cipher_traits::{
algorithms::KeyedHashIncorrectHmacBlake2b,
primitives::{InferKeyedHash, KeyedHash, KeyedHashTo},
};
use rosenpass_constant_time::xor; use rosenpass_constant_time::xor;
use rosenpass_to::{ops::copy_slice, To}; use rosenpass_to::{ops::copy_slice, To};
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -59,14 +62,16 @@ impl KeyedHash<KEY_LEN, HASH_LEN> for IncorrectHmacBlake2bCore {
copy_slice(key).to(tmp_key.as_mut()); copy_slice(key).to(tmp_key.as_mut());
xor(&IPAD).to(tmp_key.as_mut()); xor(&IPAD).to(tmp_key.as_mut());
let mut outer_data = Key::default(); let mut outer_data = Key::default();
blake2b::hash(tmp_key.as_ref(), data).to(outer_data.as_mut())?; blake2b::Blake2b::keyed_hash_to(&tmp_key, data).to(&mut outer_data)?;
copy_slice(key).to(tmp_key.as_mut()); copy_slice(key).to(tmp_key.as_mut());
xor(&OPAD).to(tmp_key.as_mut()); xor(&OPAD).to(tmp_key.as_mut());
blake2b::hash(tmp_key.as_ref(), outer_data.as_ref()).to(out)?; blake2b::Blake2b::keyed_hash_to(&tmp_key, outer_data.as_ref()).to(out)?;
Ok(()) Ok(())
} }
} }
pub type IncorrectHmacBlake2b = InferKeyedHash<IncorrectHmacBlake2bCore, KEY_LEN, HASH_LEN>; pub type IncorrectHmacBlake2b = InferKeyedHash<IncorrectHmacBlake2bCore, KEY_LEN, HASH_LEN>;
impl KeyedHashIncorrectHmacBlake2b for IncorrectHmacBlake2bCore {}

View File

@@ -1,5 +1,5 @@
use anyhow::Result; use anyhow::Result;
use rosenpass_cipher_traits::keyed_hash::KeyedHashInstance; use rosenpass_cipher_traits::primitives::KeyedHashInstance;
pub const KEY_LEN: usize = 32; pub const KEY_LEN: usize = 32;
pub const HASH_LEN: usize = 32; pub const HASH_LEN: usize = 32;

View File

@@ -2,54 +2,33 @@ use zeroize::Zeroizing;
use blake2::digest::crypto_common::generic_array::GenericArray; use blake2::digest::crypto_common::generic_array::GenericArray;
use blake2::digest::crypto_common::typenum::U32; use blake2::digest::crypto_common::typenum::U32;
use blake2::digest::crypto_common::KeySizeUser; use blake2::digest::{FixedOutput, Mac};
use blake2::digest::{FixedOutput, Mac, OutputSizeUser};
use blake2::Blake2bMac; use blake2::Blake2bMac;
use rosenpass_to::{ops::copy_slice, with_destination, To}; use rosenpass_cipher_traits::primitives::KeyedHash;
use rosenpass_util::typenum2const; use rosenpass_to::{ops::copy_slice, To};
/// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b /// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b
/// with output and key length of 32 bytes (see [Blake2bMac]). /// with output and key length of 32 bytes (see [Blake2bMac]).
type Impl = Blake2bMac<U32>; type Impl = Blake2bMac<U32>;
type KeyLen = <Impl as KeySizeUser>::KeySize;
type OutLen = <Impl as OutputSizeUser>::OutputSize;
/// The key length for BLAKE2b supported by this API. Currently 32 Bytes. /// The key length for BLAKE2b supported by this API. Currently 32 Bytes.
const KEY_LEN: usize = typenum2const! { KeyLen }; const KEY_LEN: usize = 32;
/// The output length for BLAKE2b supported by this API. Currently 32 Bytes. /// The output length for BLAKE2b supported by this API. Currently 32 Bytes.
const OUT_LEN: usize = typenum2const! { OutLen }; const OUT_LEN: usize = 32;
/// Minimal key length supported by this API.
pub const KEY_MIN: usize = KEY_LEN;
/// maximal key length supported by this API.
pub const KEY_MAX: usize = KEY_LEN;
/// minimal output length supported by this API.
pub const OUT_MIN: usize = OUT_LEN;
/// maximal output length supported by this API.
pub const OUT_MAX: usize = OUT_LEN;
/// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`. /// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`.
/// The both the length of the output the length of the key 32 bytes (or 256 bits). /// The both the length of the output the length of the key 32 bytes (or 256 bits).
/// pub struct Blake2b;
/// TODO: Adapt example
/// # Examples impl KeyedHash<KEY_LEN, OUT_LEN> for Blake2b {
/// type Error = anyhow::Error;
///```rust
/// # use rosenpass_ciphers::subtle::blake2b::hash; fn keyed_hash(
/// use rosenpass_to::To; key: &[u8; KEY_LEN],
/// let zero_key: [u8; 32] = [0; 32]; data: &[u8],
/// let data: [u8; 32] = [255; 32]; out: &mut [u8; OUT_LEN],
/// // buffer for the hash output ) -> Result<(), Self::Error> {
/// let mut hash_data: [u8; 32] = [0u8; 32];
///
/// assert!(hash(&zero_key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
///```
///
#[inline]
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
with_destination(|out: &mut [u8]| {
let mut h = Impl::new_from_slice(key)?; let mut h = Impl::new_from_slice(key)?;
h.update(data); h.update(data);
@@ -62,5 +41,7 @@ pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<(
h.finalize_into(tmp); h.finalize_into(tmp);
copy_slice(tmp.as_ref()).to(out); copy_slice(tmp.as_ref()).to(out);
Ok(()) Ok(())
}) }
} }
impl rosenpass_cipher_traits::algorithms::KeyedHashBlake2b for Blake2b {}

View File

@@ -1,3 +1,4 @@
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
use rosenpass_to::ops::copy_slice; use rosenpass_to::ops::copy_slice;
use rosenpass_to::To; use rosenpass_to::To;
use rosenpass_util::typenum2const; use rosenpass_util::typenum2const;
@@ -13,6 +14,66 @@ pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
/// The nonce length is 12 bytes or 96 bits. /// The nonce length is 12 bytes or 96 bits.
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize }; pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
pub struct ChaCha20Poly1305;
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), AeadError> {
if ciphertext.len() < plaintext.len() + TAG_LEN {
return Err(AeadError::InvalidLengths);
}
let nonce = GenericArray::from_slice(nonce);
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
copy_slice(plaintext).to(ct);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
let mac_value = encrypter
.encrypt_in_place_detached(nonce, ad, ct)
.map_err(|_| AeadError::InternalError)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
}
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), AeadError> {
if ciphertext.len() < plaintext.len() + TAG_LEN {
return Err(AeadError::InvalidLengths);
}
let nonce = GenericArray::from_slice(nonce);
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
decrypter
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
.map_err(|_| AeadError::DecryptError)?;
Ok(())
}
}
/// Encrypts using ChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305). /// Encrypts using ChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
/// `key` MUST be chosen (pseudo-)randomly and `nonce` MOST NOT be reused. The `key` slice MUST have /// `key` MUST be chosen (pseudo-)randomly and `nonce` MOST NOT be reused. The `key` slice MUST have
/// a length of [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes /// a length of [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
@@ -42,17 +103,14 @@ pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize
#[inline] #[inline]
pub fn encrypt( pub fn encrypt(
ciphertext: &mut [u8], ciphertext: &mut [u8],
key: &[u8], key: &[u8; KEY_LEN],
nonce: &[u8], nonce: &[u8; NONCE_LEN],
ad: &[u8], ad: &[u8],
plaintext: &[u8], plaintext: &[u8],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let nonce = GenericArray::from_slice(nonce); ChaCha20Poly1305
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN); .encrypt(ciphertext, key, nonce, ad, plaintext)
copy_slice(plaintext).to(ct); .map_err(anyhow::Error::from)
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(nonce, ad, ct)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
} }
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data /// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
@@ -85,15 +143,12 @@ pub fn encrypt(
#[inline] #[inline]
pub fn decrypt( pub fn decrypt(
plaintext: &mut [u8], plaintext: &mut [u8],
key: &[u8], key: &[u8; KEY_LEN],
nonce: &[u8], nonce: &[u8; NONCE_LEN],
ad: &[u8], ad: &[u8],
ciphertext: &[u8], ciphertext: &[u8],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let nonce = GenericArray::from_slice(nonce); ChaCha20Poly1305
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN); .decrypt(plaintext, key, nonce, ad, ciphertext)
let tag = GenericArray::from_slice(mac); .map_err(anyhow::Error::from)
copy_slice(ct).to(plaintext);
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(nonce, ad, plaintext, tag)?;
Ok(())
} }

View File

@@ -1,5 +1,5 @@
use anyhow::ensure; use anyhow::ensure;
use rosenpass_cipher_traits::keyed_hash::{InferKeyedHash, KeyedHash}; use rosenpass_cipher_traits::primitives::{InferKeyedHash, KeyedHash};
use sha3::digest::{ExtendableOutput, Update, XofReader}; use sha3::digest::{ExtendableOutput, Update, XofReader};
use sha3::Shake256; use sha3::Shake256;

View File

@@ -1,3 +1,4 @@
use rosenpass_cipher_traits::primitives::{Aead, AeadError, AeadWithNonceInCiphertext};
use rosenpass_to::ops::copy_slice; use rosenpass_to::ops::copy_slice;
use rosenpass_to::To; use rosenpass_to::To;
use rosenpass_util::typenum2const; use rosenpass_util::typenum2const;
@@ -13,6 +14,58 @@ pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
/// The nonce length is 24 bytes or 192 bits. /// The nonce length is 24 bytes or 192 bits.
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize }; pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
pub struct XChaCha20Poly1305;
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for XChaCha20Poly1305 {
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), AeadError> {
let nonce = GenericArray::from_slice(nonce);
let (n, ct_mac) = ciphertext.split_at_mut(NONCE_LEN);
let (ct, mac) = ct_mac.split_at_mut(ct_mac.len() - TAG_LEN);
copy_slice(nonce).to(n);
copy_slice(plaintext).to(ct);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
let mac_value = encrypter
.encrypt_in_place_detached(nonce, ad, ct)
.map_err(|_| AeadError::InternalError)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
}
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), AeadError> {
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
let nonce = GenericArray::from_slice(nonce);
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
decrypter
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
.map_err(|_| AeadError::DecryptError)?;
Ok(())
}
}
/// Encrypts using XChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305). /// Encrypts using XChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
/// `key` and `nonce` MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of /// `key` and `nonce` MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. /// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN].
@@ -44,19 +97,14 @@ pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize
#[inline] #[inline]
pub fn encrypt( pub fn encrypt(
ciphertext: &mut [u8], ciphertext: &mut [u8],
key: &[u8], key: &[u8; KEY_LEN],
nonce: &[u8], nonce: &[u8; NONCE_LEN],
ad: &[u8], ad: &[u8],
plaintext: &[u8], plaintext: &[u8],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let nonce = GenericArray::from_slice(nonce); XChaCha20Poly1305
let (n, ct_mac) = ciphertext.split_at_mut(NONCE_LEN); .encrypt(ciphertext, key, nonce, ad, plaintext)
let (ct, mac) = ct_mac.split_at_mut(ct_mac.len() - TAG_LEN); .map_err(anyhow::Error::from)
copy_slice(nonce).to(n);
copy_slice(plaintext).to(ct);
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(nonce, ad, ct)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
} }
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data /// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
@@ -94,15 +142,11 @@ pub fn encrypt(
#[inline] #[inline]
pub fn decrypt( pub fn decrypt(
plaintext: &mut [u8], plaintext: &mut [u8],
key: &[u8], key: &[u8; KEY_LEN],
ad: &[u8], ad: &[u8],
ciphertext: &[u8], ciphertext: &[u8],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let (n, ct_mac) = ciphertext.split_at(NONCE_LEN); XChaCha20Poly1305
let (ct, mac) = ct_mac.split_at(ct_mac.len() - TAG_LEN); .decrypt_with_nonce_in_ctxt(plaintext, key, ad, ciphertext)
let nonce = GenericArray::from_slice(n); .map_err(anyhow::Error::from)
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(nonce, ad, plaintext, tag)?;
Ok(())
} }

View File

@@ -4,7 +4,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use rosenpass_ciphers::aead; use rosenpass_cipher_traits::primitives::Aead as _;
use rosenpass_ciphers::Aead;
#[derive(arbitrary::Arbitrary, Debug)] #[derive(arbitrary::Arbitrary, Debug)]
pub struct Input { pub struct Input {
@@ -17,7 +18,7 @@ pub struct Input {
fuzz_target!(|input: Input| { fuzz_target!(|input: Input| {
let mut ciphertext = vec![0u8; input.plaintext.len() + 16]; let mut ciphertext = vec![0u8; input.plaintext.len() + 16];
aead::encrypt( Aead.encrypt(
ciphertext.as_mut_slice(), ciphertext.as_mut_slice(),
&input.key, &input.key,
&input.nonce, &input.nonce,

View File

@@ -4,6 +4,7 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::primitives::KeyedHashTo;
use rosenpass_ciphers::subtle::blake2b; use rosenpass_ciphers::subtle::blake2b;
use rosenpass_to::To; use rosenpass_to::To;
@@ -16,5 +17,7 @@ pub struct Blake2b {
fuzz_target!(|input: Blake2b| { fuzz_target!(|input: Blake2b| {
let mut out = [0u8; 32]; let mut out = [0u8; 32];
blake2b::hash(&input.key, &input.data).to(&mut out).unwrap(); blake2b::Blake2b::keyed_hash_to(&input.key, &input.data)
.to(&mut out)
.unwrap();
}); });

View File

@@ -4,8 +4,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use rosenpass::protocol::CryptoServer; use rosenpass::protocol::CryptoServer;
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
use rosenpass_secret_memory::policy::*; use rosenpass_secret_memory::policy::*;
use rosenpass_secret_memory::{PublicBox, Secret}; use rosenpass_secret_memory::{PublicBox, Secret};
use std::sync::Once; use std::sync::Once;

View File

@@ -4,8 +4,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::EphemeralKem; use rosenpass_ciphers::EphemeralKem;
#[derive(arbitrary::Arbitrary, Debug)] #[derive(arbitrary::Arbitrary, Debug)]
pub struct Input { pub struct Input {

View File

@@ -3,8 +3,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
fuzz_target!(|input: [u8; StaticKem::PK_LEN]| { fuzz_target!(|input: [u8; StaticKem::PK_LEN]| {
let mut ciphertext = [0u8; StaticKem::CT_LEN]; let mut ciphertext = [0u8; StaticKem::CT_LEN];

View File

@@ -2,10 +2,10 @@
/// Generate bindings to a liboqs-provided KEM /// Generate bindings to a liboqs-provided KEM
macro_rules! oqs_kem { macro_rules! oqs_kem {
($name:ident) => { ::paste::paste!{ ($name:ident, $algo_trait:path) => { ::paste::paste!{
#[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"] #[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"]
mod [< $name:snake >] { mod [< $name:snake >] {
use rosenpass_cipher_traits::kem; use rosenpass_cipher_traits::primitives::{Kem, KemError};
#[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"] #[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"]
#[doc = ""] #[doc = ""]
@@ -55,8 +55,8 @@ macro_rules! oqs_kem {
/// to only check that the buffers are big enough, allowing them to be even /// to only check that the buffers are big enough, allowing them to be even
/// bigger. However, from a correctness point of view it does not make sense to /// bigger. However, from a correctness point of view it does not make sense to
/// allow bigger buffers. /// allow bigger buffers.
impl kem::Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for [< $name:camel >] { impl Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for [< $name:camel >] {
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), kem::Error> { fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), KemError> {
unsafe { unsafe {
oqs_call!( oqs_call!(
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ keypair >], ::oqs_sys::kem::[< OQS_KEM _ $name:snake _ keypair >],
@@ -68,7 +68,7 @@ macro_rules! oqs_kem {
Ok(()) Ok(())
} }
fn encaps(&self, shk: &mut [u8; SHK_LEN], ct: &mut [u8; CT_LEN], pk: &[u8; PK_LEN]) -> Result<(), kem::Error> { fn encaps(&self, shk: &mut [u8; SHK_LEN], ct: &mut [u8; CT_LEN], pk: &[u8; PK_LEN]) -> Result<(), KemError> {
unsafe { unsafe {
oqs_call!( oqs_call!(
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ encaps >], ::oqs_sys::kem::[< OQS_KEM _ $name:snake _ encaps >],
@@ -81,7 +81,7 @@ macro_rules! oqs_kem {
Ok(()) Ok(())
} }
fn decaps(&self, shk: &mut [u8; SHK_LEN], sk: &[u8; SK_LEN], ct: &[u8; CT_LEN]) -> Result<(), kem::Error> { fn decaps(&self, shk: &mut [u8; SHK_LEN], sk: &[u8; SK_LEN], ct: &[u8; CT_LEN]) -> Result<(), KemError> {
unsafe { unsafe {
oqs_call!( oqs_call!(
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ decaps >], ::oqs_sys::kem::[< OQS_KEM _ $name:snake _ decaps >],
@@ -102,6 +102,8 @@ macro_rules! oqs_kem {
} }
} }
impl $algo_trait for [< $name:camel >] {}
pub use [< $name:snake >] :: [< $name:camel >]; pub use [< $name:snake >] :: [< $name:camel >];
}} }}
} }

View File

@@ -22,5 +22,8 @@ macro_rules! oqs_call {
#[macro_use] #[macro_use]
mod kem_macro; mod kem_macro;
oqs_kem!(kyber_512); oqs_kem!(kyber_512, rosenpass_cipher_traits::algorithms::KemKyber512);
oqs_kem!(classic_mceliece_460896); oqs_kem!(
classic_mceliece_460896,
rosenpass_cipher_traits::algorithms::KemClassicMceliece460896
);

View File

@@ -4,8 +4,8 @@ use rosenpass::protocol::{
}; };
use std::ops::DerefMut; use std::ops::DerefMut;
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets; use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;

View File

@@ -5,8 +5,8 @@
use anyhow::{bail, ensure, Context}; use anyhow::{bail, ensure, Context};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
use rosenpass_secret_memory::file::StoreSecret; use rosenpass_secret_memory::file::StoreSecret;
use rosenpass_util::file::{LoadValue, LoadValueB64, StoreValue}; use rosenpass_util::file::{LoadValue, LoadValueB64, StoreValue};
use rosenpass_wireguard_broker::brokers::native_unix::{ use rosenpass_wireguard_broker::brokers::native_unix::{

View File

@@ -9,13 +9,12 @@
//! To achieve this we utilize the zerocopy library. //! To achieve this we utilize the zerocopy library.
//! //!
use std::mem::size_of; use std::mem::size_of;
use std::u8;
use zerocopy::{AsBytes, FromBytes, FromZeroes}; use zerocopy::{AsBytes, FromBytes, FromZeroes};
use super::RosenpassError; use super::RosenpassError;
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::{Aead as _, Kem};
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem}; use rosenpass_ciphers::{Aead, XAead, KEY_LEN};
use rosenpass_ciphers::{aead, xaead, KEY_LEN}; use rosenpass_ciphers::{EphemeralKem, StaticKem};
/// Length of a session ID such as [InitHello::sidi] /// Length of a session ID such as [InitHello::sidi]
pub const SESSION_ID_LEN: usize = 4; pub const SESSION_ID_LEN: usize = 4;
@@ -32,7 +31,7 @@ pub const MAX_MESSAGE_LEN: usize = 2500; // TODO fix this
pub const BISCUIT_PT_LEN: usize = size_of::<Biscuit>(); pub const BISCUIT_PT_LEN: usize = size_of::<Biscuit>();
/// Length in bytes of an encrypted Biscuit (cipher text) /// Length in bytes of an encrypted Biscuit (cipher text)
pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN; pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + XAead::NONCE_LEN + XAead::TAG_LEN;
/// Size of the field [Envelope::mac] /// Size of the field [Envelope::mac]
pub const MAC_SIZE: usize = 16; pub const MAC_SIZE: usize = 16;
@@ -136,9 +135,9 @@ pub struct InitHello {
/// Classic McEliece Ciphertext /// Classic McEliece Ciphertext
pub sctr: [u8; StaticKem::CT_LEN], pub sctr: [u8; StaticKem::CT_LEN],
/// Encryped: 16 byte hash of McEliece initiator static key /// Encryped: 16 byte hash of McEliece initiator static key
pub pidic: [u8; aead::TAG_LEN + 32], pub pidic: [u8; Aead::TAG_LEN + 32],
/// Encrypted TAI64N Time Stamp (against replay attacks) /// Encrypted TAI64N Time Stamp (against replay attacks)
pub auth: [u8; aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
} }
/// This is the second message sent by the responder to the initiator /// This is the second message sent by the responder to the initiator
@@ -187,7 +186,7 @@ pub struct RespHello {
/// Classic McEliece Ciphertext /// Classic McEliece Ciphertext
pub scti: [u8; StaticKem::CT_LEN], pub scti: [u8; StaticKem::CT_LEN],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
pub auth: [u8; aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
/// Responders handshake state in encrypted form /// Responders handshake state in encrypted form
pub biscuit: [u8; BISCUIT_CT_LEN], pub biscuit: [u8; BISCUIT_CT_LEN],
} }
@@ -236,7 +235,7 @@ pub struct InitConf {
/// Responders handshake state in encrypted form /// Responders handshake state in encrypted form
pub biscuit: [u8; BISCUIT_CT_LEN], pub biscuit: [u8; BISCUIT_CT_LEN],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
pub auth: [u8; aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
} }
/// This is the fourth message sent by the initiator to the responder /// This is the fourth message sent by the initiator to the responder
@@ -292,7 +291,7 @@ pub struct EmptyData {
/// Nonce /// Nonce
pub ctr: [u8; 8], pub ctr: [u8; 8],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
pub auth: [u8; aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
} }
/// Cookie encrypted and sent to the initiator by the responder in [RespHello] /// Cookie encrypted and sent to the initiator by the responder in [RespHello]
@@ -346,7 +345,7 @@ pub struct CookieReplyInner {
/// Session ID of the sender (initiator) /// Session ID of the sender (initiator)
pub sid: [u8; 4], pub sid: [u8; 4],
/// Encrypted cookie with authenticated initiator `mac` /// Encrypted cookie with authenticated initiator `mac`
pub cookie_encrypted: [u8; xaead::NONCE_LEN + COOKIE_SIZE + xaead::TAG_LEN], pub cookie_encrypted: [u8; XAead::NONCE_LEN + COOKIE_SIZE + XAead::TAG_LEN],
} }
/// Specialized message for use in the cookie mechanism. /// Specialized message for use in the cookie mechanism.
@@ -437,7 +436,8 @@ impl From<MsgType> for u8 {
#[cfg(test)] #[cfg(test)]
mod test_constants { mod test_constants {
use crate::msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN}; use crate::msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN};
use rosenpass_ciphers::{xaead, KEY_LEN}; use rosenpass_cipher_traits::primitives::Aead as _;
use rosenpass_ciphers::{XAead, KEY_LEN};
#[test] #[test]
fn sodium_keysize() { fn sodium_keysize() {
@@ -453,7 +453,7 @@ mod test_constants {
fn biscuit_ct_len() { fn biscuit_ct_len() {
assert_eq!( assert_eq!(
BISCUIT_CT_LEN, BISCUIT_CT_LEN,
BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN BISCUIT_PT_LEN + XAead::NONCE_LEN + XAead::TAG_LEN
); );
} }
} }

View File

@@ -20,12 +20,11 @@ use rand::Fill as Randomize;
use crate::{hash_domains, msgs::*, RosenpassError}; use crate::{hash_domains, msgs::*, RosenpassError};
use memoffset::span_of; use memoffset::span_of;
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::{
use rosenpass_cipher_traits::keyed_hash::KeyedHashInstance; Aead as _, AeadWithNonceInCiphertext, Kem, KeyedHashInstance,
};
use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace}; use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace};
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem}; use rosenpass_ciphers::{Aead, EphemeralKem, KeyedHash, StaticKem, XAead, KEY_LEN};
use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
use rosenpass_constant_time as constant_time; use rosenpass_constant_time as constant_time;
use rosenpass_secret_memory::{Public, PublicBox, Secret}; use rosenpass_secret_memory::{Public, PublicBox, Secret};
use rosenpass_to::ops::copy_slice; use rosenpass_to::ops::copy_slice;
@@ -172,7 +171,7 @@ pub type SessionId = Public<SESSION_ID_LEN>;
pub type BiscuitId = Public<BISCUIT_ID_LEN>; pub type BiscuitId = Public<BISCUIT_ID_LEN>;
/// Nonce for use with random-nonce AEAD /// Nonce for use with random-nonce AEAD
pub type XAEADNonce = Public<{ xaead::NONCE_LEN }>; pub type XAEADNonce = Public<{ XAead::NONCE_LEN }>;
/// Buffer capably of holding any Rosenpass protocol message /// Buffer capably of holding any Rosenpass protocol message
pub type MsgBuf = Public<MAX_MESSAGE_LEN>; pub type MsgBuf = Public<MAX_MESSAGE_LEN>;
@@ -2242,7 +2241,7 @@ impl CryptoServer {
msg_out.inner.msg_type = MsgType::CookieReply.into(); msg_out.inner.msg_type = MsgType::CookieReply.into();
msg_out.inner.sid = rx_sid; msg_out.inner.sid = rx_sid;
xaead::encrypt( XAead.encrypt(
&mut msg_out.inner.cookie_encrypted[..], &mut msg_out.inner.cookie_encrypted[..],
&cookie_key, &cookie_key,
&nonce.value, &nonce.value,
@@ -3310,7 +3309,7 @@ impl HandshakeState {
.ck .ck
.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)? .mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?
.into_secret(); .into_secret();
aead::encrypt(ct, k.secret(), &[0u8; aead::NONCE_LEN], &[], pt)?; Aead.encrypt(ct, k.secret(), &[0u8; Aead::NONCE_LEN], &[], pt)?;
self.mix(ct) self.mix(ct)
} }
@@ -3323,7 +3322,7 @@ impl HandshakeState {
.ck .ck
.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)? .mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?
.into_secret(); .into_secret();
aead::decrypt(pt, k.secret(), &[0u8; aead::NONCE_LEN], &[], ct)?; Aead.decrypt(pt, k.secret(), &[0u8; Aead::NONCE_LEN], &[], ct)?;
self.mix(ct) self.mix(ct)
} }
@@ -3449,7 +3448,7 @@ impl HandshakeState {
let k = bk.get(srv).value.secret(); let k = bk.get(srv).value.secret();
let pt = biscuit.as_bytes(); let pt = biscuit.as_bytes();
xaead::encrypt(biscuit_ct, k, &*n, &ad, pt)?; XAead.encrypt(biscuit_ct, k, &*n, &ad, pt)?;
self.mix(biscuit_ct) self.mix(biscuit_ct)
} }
@@ -3476,7 +3475,7 @@ impl HandshakeState {
let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buf let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buf
let mut biscuit: Ref<&mut [u8], Biscuit> = let mut biscuit: Ref<&mut [u8], Biscuit> =
Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap(); Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap();
xaead::decrypt( XAead.decrypt_with_nonce_in_ctxt(
biscuit.as_bytes_mut(), biscuit.as_bytes_mut(),
bk.get(srv).value.secret(), bk.get(srv).value.secret(),
&ad, &ad,
@@ -3790,7 +3789,7 @@ impl CryptoServer {
)?; )?;
// ICR2 // ICR2
core.encrypt_and_mix(&mut [0u8; aead::TAG_LEN], &[])?; core.encrypt_and_mix(&mut [0u8; Aead::TAG_LEN], &[])?;
// ICR3 // ICR3
core.mix(&ic.sidi)?.mix(&ic.sidr)?; core.mix(&ic.sidi)?.mix(&ic.sidr)?;
@@ -3855,9 +3854,9 @@ impl CryptoServer {
rc.ctr.copy_from_slice(&ses.txnm.to_le_bytes()); rc.ctr.copy_from_slice(&ses.txnm.to_le_bytes());
ses.txnm += 1; // Increment nonce before encryption, just in case an error is raised ses.txnm += 1; // Increment nonce before encryption, just in case an error is raised
let n = cat!(aead::NONCE_LEN; &rc.ctr, &[0u8; 4]); let n = cat!(Aead::NONCE_LEN; &rc.ctr, &[0u8; 4]);
let k = ses.txkm.secret(); let k = ses.txkm.secret();
aead::encrypt(&mut rc.auth, k, &n, &[], &[])?; // ct, k, n, ad, pt Aead.encrypt(&mut rc.auth, k, &n, &[], &[])?; // ct, k, n, ad, pt
Ok(peer) Ok(peer)
} }
@@ -3902,11 +3901,11 @@ impl CryptoServer {
let n = u64::from_le_bytes(rc.ctr); let n = u64::from_le_bytes(rc.ctr);
ensure!(n >= s.txnt, "Stale nonce"); ensure!(n >= s.txnt, "Stale nonce");
s.txnt = n; s.txnt = n;
aead::decrypt( Aead.decrypt(
// pt, k, n, ad, ct // pt, k, n, ad, ct
&mut [0u8; 0], &mut [0u8; 0],
s.txkt.secret(), s.txkt.secret(),
&cat!(aead::NONCE_LEN; &rc.ctr, &[0u8; 4]), &cat!(Aead::NONCE_LEN; &rc.ctr, &[0u8; 4]),
&[], &[],
&rc.auth, &rc.auth,
)?; )?;
@@ -3967,7 +3966,12 @@ impl CryptoServer {
.into_value(); .into_value();
let cookie_value = peer.cv().update_mut(self).unwrap(); let cookie_value = peer.cv().update_mut(self).unwrap();
xaead::decrypt(cookie_value, &cookie_key, &mac, &cr.inner.cookie_encrypted)?; XAead.decrypt_with_nonce_in_ctxt(
cookie_value,
&cookie_key,
&mac,
&cr.inner.cookie_encrypted,
)?;
// Immediately retransmit on recieving a cookie reply message // Immediately retransmit on recieving a cookie reply message
peer.hs().register_immediate_retransmission(self)?; peer.hs().register_immediate_retransmission(self)?;

View File

@@ -12,8 +12,8 @@ use rosenpass::{
app_server::{AppServer, AppServerTest, MAX_B64_KEY_SIZE}, app_server::{AppServer, AppServerTest, MAX_B64_KEY_SIZE},
protocol::{SPk, SSk, SymKey}, protocol::{SPk, SSk, SymKey},
}; };
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
use rosenpass_util::{file::LoadValueB64, functional::run, mem::DiscardResultExt, result::OkExt}; use rosenpass_util::{file::LoadValueB64, functional::run, mem::DiscardResultExt, result::OkExt};
#[test] #[test]

View File

@@ -5,8 +5,8 @@ use std::{
ops::DerefMut, ops::DerefMut,
}; };
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
use rosenpass_util::result::OkExt; use rosenpass_util::result::OkExt;
use rosenpass::protocol::{ use rosenpass::protocol::{

View File

@@ -10,8 +10,8 @@ use rosenpass_util::file::{LoadValueB64, StoreValue, StoreValueB64};
use zeroize::Zeroize; use zeroize::Zeroize;
use rosenpass::protocol::{SPk, SSk}; use rosenpass::protocol::{SPk, SSk};
use rosenpass_cipher_traits::kem::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::StaticKem;
use rosenpass_secret_memory::{file::StoreSecret as _, Public, Secret}; use rosenpass_secret_memory::{file::StoreSecret as _, Public, Secret};
/// The length of wireguard keys as a length in base 64 encoding. /// The length of wireguard keys as a length in base 64 encoding.