mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-12 15:49:22 -08:00
Reorganize the ciphers crate
This commit is contained in:
@@ -18,3 +18,94 @@ pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> {
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// This is a helper to allow for type parameter inference when calling functions
|
||||
/// that need a [KeyedHash].
|
||||
///
|
||||
/// Really just binds the [KeyedHash] trait to a dummy variable, so the type of this dummy variable
|
||||
/// can be used for type inference. Less typing work.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InferKeyedHash<Static, const KEY_LEN: usize, const HASH_LEN: usize>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub _phantom_keyed_hasher: PhantomData<*const Static>,
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub const KEY_LEN: usize = KEY_LEN;
|
||||
pub const HASH_LEN: usize = HASH_LEN;
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
_phantom_keyed_hasher: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static`
|
||||
fn keyed_hash_internal<'a>(
|
||||
&self,
|
||||
key: &'a [u8; KEY_LEN],
|
||||
data: &'a [u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Static::Error> {
|
||||
Static::keyed_hash(key, data, out)
|
||||
}
|
||||
|
||||
pub const fn key_len(self) -> usize {
|
||||
Self::KEY_LEN
|
||||
}
|
||||
|
||||
pub const fn hash_len(self) -> usize {
|
||||
Self::HASH_LEN
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, Static: KeyedHash<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
{
|
||||
type Error = Static::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Static::Error> {
|
||||
self.keyed_hash_internal(key, data, out)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper traits /////////////////////////////////////////////
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
//!
|
||||
//!```rust
|
||||
//! # use rosenpass_ciphers::hash_domain::{HashDomain, HashDomainNamespace, SecretHashDomain, SecretHashDomainNamespace};
|
||||
//! use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||
//! use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||
//! use rosenpass_ciphers::keyed_hash::KeyedHash;
|
||||
//! use rosenpass_secret_memory::Secret;
|
||||
//! # rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
|
||||
//!
|
||||
//! const PROTOCOL_IDENTIFIER: &str = "MY_PROTOCOL:IDENTIFIER";
|
||||
//! // create use once hash domain for the protocol identifier
|
||||
//! let mut hash_domain = HashDomain::zero(EitherShakeOrBlake::Left(SHAKE256Core));
|
||||
//! let mut hash_domain = HashDomain::zero(KeyedHash::keyed_shake256());
|
||||
//! hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?;
|
||||
//! // upgrade to reusable hash domain
|
||||
//! let hash_domain_namespace: HashDomainNamespace = hash_domain.dup();
|
||||
@@ -30,12 +29,9 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_to::To;
|
||||
|
||||
use crate::keyed_hash as hash;
|
||||
pub use crate::keyed_hash::{KeyedHash, KEY_LEN};
|
||||
|
||||
use crate::subtle::either_hash::KeyedHash;
|
||||
pub use hash::KEY_LEN;
|
||||
use rosenpass_cipher_traits::keyed_hash::KeyedHashInstance;
|
||||
|
||||
// TODO Use a proper Dec interface
|
||||
@@ -120,6 +116,8 @@ impl HashDomainNamespace {
|
||||
}
|
||||
|
||||
impl SecretHashDomain {
|
||||
// XXX: Why is the old hash still used unconditionally?
|
||||
//
|
||||
/// Create a new [SecretHashDomain] with the given key `k` and data `d` by calling
|
||||
/// [hash::hash] with `k` as the `key` and `d` s the `data`, and using the result
|
||||
/// as the content for the new [SecretHashDomain].
|
||||
@@ -133,7 +131,7 @@ impl SecretHashDomain {
|
||||
let mut new_secret_key = Secret::zero();
|
||||
hash_choice.keyed_hash(k.try_into()?, d, new_secret_key.secret_mut())?;
|
||||
let mut r = SecretHashDomain(new_secret_key, hash_choice);
|
||||
hash::hash(k, d).to(r.0.secret_mut())?;
|
||||
KeyedHash::incorrect_hmac_blake2b().keyed_hash(k.try_into()?, d, r.0.secret_mut())?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
@@ -177,13 +175,23 @@ impl SecretHashDomain {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Evaluate [hash::hash] with this [SecretHashDomain]'s data as the `key` and
|
||||
/// `dst` as the `data` and stores the result as the new data for this [SecretHashDomain].
|
||||
///
|
||||
/// It requires that both `v` and `d` consist of exactly [KEY_LEN] many bytes.
|
||||
pub fn into_secret_slice(mut self, v: &[u8], dst: &[u8]) -> Result<()> {
|
||||
hash::hash(v, dst).to(self.0.secret_mut())
|
||||
}
|
||||
/* XXX: This code was calling the specific hmac-blake2b code as well as the new KeyedHash enum
|
||||
* (f.k.a. EitherHash). I was confused by the way the code used the local variables, because it
|
||||
* didn't match the code. I made the code match the documentation, but I'm not sure that is
|
||||
* correct. Either way, it doesn't look like this is used anywhere. Maybe just remove it?
|
||||
*
|
||||
* /// Evaluate [hash::hash] with this [SecretHashDomain]'s data as the `key` and
|
||||
* /// `dst` as the `data` and stores the result as the new data for this [SecretHashDomain].
|
||||
* pub fn into_secret_slice(mut self, v: &[u8; KEY_LEN], dst: &[u8; KEY_LEN]) -> Result<()> {
|
||||
* let SecretHashDomain(secret, hash_choice) = &self;
|
||||
*
|
||||
* let mut new_secret = Secret::zero();
|
||||
* hash_choice.keyed_hash(secret.secret(), dst, new_secret.secret_mut())?;
|
||||
* self.0 = new_secret;
|
||||
*
|
||||
* Ok(())
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
impl SecretHashDomainNamespace {
|
||||
|
||||
@@ -13,19 +13,18 @@ const_assert!(KEY_LEN == hash_domain::KEY_LEN);
|
||||
/// This should only be used for implementation details; anything with relevance
|
||||
/// to the cryptographic protocol should use the facilities in [hash_domain], (though
|
||||
/// hash domain uses this module internally)
|
||||
pub mod keyed_hash {
|
||||
pub use crate::subtle::incorrect_hmac_blake2b::{
|
||||
hash, KEY_LEN, KEY_MAX, KEY_MIN, OUT_MAX, OUT_MIN,
|
||||
};
|
||||
}
|
||||
pub use crate::subtle::keyed_hash;
|
||||
|
||||
/// Authenticated encryption with associated data
|
||||
/// Chacha20poly1305 is used.
|
||||
pub mod aead {
|
||||
#[cfg(not(feature = "experiment_libcrux"))]
|
||||
pub use crate::subtle::chacha20poly1305_ietf::{decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
#[cfg(feature = "experiment_libcrux")]
|
||||
pub use crate::subtle::chacha20poly1305_ietf_libcrux::{
|
||||
pub use crate::subtle::libcrux::chacha20poly1305_ietf::{
|
||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "experiment_libcrux"))]
|
||||
pub use crate::subtle::rust_crypto::chacha20poly1305_ietf::{
|
||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
}
|
||||
@@ -33,7 +32,7 @@ pub mod aead {
|
||||
/// Authenticated encryption with associated data with a constant nonce
|
||||
/// XChacha20poly1305 is used.
|
||||
pub mod xaead {
|
||||
pub use crate::subtle::xchacha20poly1305_ietf::{
|
||||
pub use crate::subtle::rust_crypto::xchacha20poly1305_ietf::{
|
||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
use anyhow::ensure;
|
||||
use rosenpass_cipher_traits::keyed_hash::KeyedHash;
|
||||
use rosenpass_cipher_traits::keyed_hash::{InferKeyedHash, KeyedHash};
|
||||
use rosenpass_constant_time::xor;
|
||||
use rosenpass_to::{ops::copy_slice, with_destination, To};
|
||||
use rosenpass_to::{ops::copy_slice, To};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use crate::subtle::hash_functions::blake2b;
|
||||
use crate::subtle::hash_functions::infer_keyed_hash::InferKeyedHash;
|
||||
use crate::subtle::rust_crypto::blake2b;
|
||||
|
||||
/// The key length, 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The minimal key length, identical to [KEY_LEN]
|
||||
pub const KEY_MIN: usize = KEY_LEN;
|
||||
/// The maximal key length, identical to [KEY_LEN]
|
||||
pub const KEY_MAX: usize = KEY_LEN;
|
||||
/// The minimal output length, see [blake2b::OUT_MIN]
|
||||
pub const OUT_MIN: usize = blake2b::OUT_MIN;
|
||||
/// The maximal output length, see [blake2b::OUT_MAX]
|
||||
pub const OUT_MAX: usize = blake2b::OUT_MAX;
|
||||
|
||||
/// The hash length, 32 bytes or 256 bits.
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// This is a woefully incorrect implementation of hmac_blake2b.
|
||||
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
|
||||
@@ -41,12 +35,20 @@ pub const OUT_MAX: usize = blake2b::OUT_MAX;
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
///```
|
||||
///
|
||||
#[inline]
|
||||
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct IncorrectHmacBlake2bCore;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for IncorrectHmacBlake2bCore {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||
|
||||
with_destination(|out: &mut [u8]| {
|
||||
// Not bothering with padding; the implementation
|
||||
// uses appropriately sized keys.
|
||||
ensure!(key.len() == KEY_LEN);
|
||||
@@ -64,18 +66,7 @@ pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<(
|
||||
blake2b::hash(tmp_key.as_ref(), outer_data.as_ref()).to(out)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Blake2bCore;
|
||||
|
||||
impl KeyedHash<32, 32> for Blake2bCore {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(key: &[u8; 32], data: &[u8], out: &mut [u8; 32]) -> Result<(), Self::Error> {
|
||||
hash(key, data).to(out)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Blake2b = InferKeyedHash<Blake2bCore, 32, 32>;
|
||||
pub type IncorrectHmacBlake2b = InferKeyedHash<IncorrectHmacBlake2bCore, KEY_LEN, HASH_LEN>;
|
||||
3
ciphers/src/subtle/custom/mod.rs
Normal file
3
ciphers/src/subtle/custom/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Own implementations of custom algorithms
|
||||
|
||||
pub mod incorrect_hmac_blake2b;
|
||||
@@ -1,90 +0,0 @@
|
||||
use anyhow::Result;
|
||||
use rosenpass_cipher_traits::keyed_hash::{KeyedHash, KeyedHashInstance};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// This is a helper to allow for type parameter inference when calling functions
|
||||
/// that need a [KeyedHash].
|
||||
///
|
||||
/// Really just binds the [KeyedHash] trait to a dummy variable, so the type of this dummy variable
|
||||
/// can be used for type inference. Less typing work.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InferKeyedHash<Static, const KEY_LEN: usize, const HASH_LEN: usize>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub _phantom_keyed_hasher: PhantomData<*const Static>,
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN, Error = anyhow::Error>,
|
||||
{
|
||||
pub const KEY_LEN: usize = KEY_LEN;
|
||||
pub const HASH_LEN: usize = HASH_LEN;
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
_phantom_keyed_hasher: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static`
|
||||
fn keyed_hash_internal<'a>(
|
||||
&self,
|
||||
key: &'a [u8; KEY_LEN],
|
||||
data: &'a [u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<()> {
|
||||
Static::keyed_hash(key, data, out)
|
||||
}
|
||||
|
||||
pub const fn key_len(self) -> usize {
|
||||
Self::KEY_LEN
|
||||
}
|
||||
|
||||
pub const fn hash_len(self) -> usize {
|
||||
Self::HASH_LEN
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
const KEY_LEN: usize,
|
||||
const HASH_LEN: usize,
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN, Error = anyhow::Error>,
|
||||
> KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
{
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(&self, key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN]) -> Result<()> {
|
||||
self.keyed_hash_internal(key, data, out)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper traits /////////////////////////////////////////////
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>,
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
pub mod blake2b;
|
||||
pub mod incorrect_hmac_blake2b;
|
||||
mod infer_keyed_hash;
|
||||
pub mod keyed_shake256;
|
||||
@@ -6,8 +6,8 @@ pub const HASH_LEN: usize = 32;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum KeyedHash {
|
||||
KeyedShake256(super::hash_functions::keyed_shake256::SHAKE256<KEY_LEN, HASH_LEN>),
|
||||
IncorrectHmacBlake2b(super::hash_functions::incorrect_hmac_blake2b::Blake2b),
|
||||
KeyedShake256(super::rust_crypto::keyed_shake256::SHAKE256<KEY_LEN, HASH_LEN>),
|
||||
IncorrectHmacBlake2b(super::custom::incorrect_hmac_blake2b::IncorrectHmacBlake2b),
|
||||
}
|
||||
|
||||
impl KeyedHash {
|
||||
3
ciphers/src/subtle/libcrux/mod.rs
Normal file
3
ciphers/src/subtle/libcrux/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Implementations backed by libcrux, a verified crypto library
|
||||
|
||||
pub mod chacha20poly1305_ietf;
|
||||
@@ -1,15 +1,10 @@
|
||||
/// This module provides the following cryptographic schemes:
|
||||
/// - [blake2b]: The blake2b hash function
|
||||
/// - [chacha20poly1305_ietf]: The Chacha20Poly1305 AEAD as implemented in [RustCrypto](https://crates.io/crates/chacha20poly1305) (only used when the feature `experiment_libcrux` is disabled).
|
||||
/// - [chacha20poly1305_ietf_libcrux]: The Chacha20Poly1305 AEAD as implemented in [libcrux](https://github.com/cryspen/libcrux) (only used when the feature `experiment_libcrux` is enabled).
|
||||
/// - [incorrect_hmac_blake2b]: An (incorrect) hmac based on [blake2b].
|
||||
/// - [xchacha20poly1305_ietf] The Chacha20Poly1305 AEAD as implemented in [RustCrypto](https://crates.io/crates/chacha20poly1305)
|
||||
#[cfg(not(feature = "experiment_libcrux"))]
|
||||
pub mod chacha20poly1305_ietf;
|
||||
#[cfg(feature = "experiment_libcrux")]
|
||||
pub mod chacha20poly1305_ietf_libcrux;
|
||||
pub mod either_hash;
|
||||
mod hash_functions;
|
||||
pub mod xchacha20poly1305_ietf;
|
||||
pub mod keyed_hash;
|
||||
|
||||
pub use hash_functions::{blake2b, incorrect_hmac_blake2b, keyed_shake256};
|
||||
pub use custom::incorrect_hmac_blake2b;
|
||||
pub use rust_crypto::{blake2b, keyed_shake256};
|
||||
|
||||
pub mod custom;
|
||||
pub mod rust_crypto;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux")]
|
||||
pub mod libcrux;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::subtle::hash_functions::infer_keyed_hash::InferKeyedHash;
|
||||
use anyhow::ensure;
|
||||
use rosenpass_cipher_traits::keyed_hash::KeyedHash;
|
||||
use rosenpass_cipher_traits::keyed_hash::{InferKeyedHash, KeyedHash};
|
||||
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||
use sha3::Shake256;
|
||||
|
||||
7
ciphers/src/subtle/rust_crypto/mod.rs
Normal file
7
ciphers/src/subtle/rust_crypto/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//! Implementations backed by RustCrypto
|
||||
|
||||
pub mod blake2b;
|
||||
pub mod keyed_shake256;
|
||||
|
||||
pub mod chacha20poly1305_ietf;
|
||||
pub mod xchacha20poly1305_ietf;
|
||||
@@ -1,8 +1,7 @@
|
||||
use anyhow::{Context, Result};
|
||||
use heck::ToShoutySnakeCase;
|
||||
|
||||
use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
|
||||
use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||
use rosenpass_ciphers::{hash_domain::HashDomain, KEY_LEN};
|
||||
|
||||
@@ -15,7 +14,7 @@ fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]
|
||||
}
|
||||
|
||||
/// Print a hash literal for pasting into the Rosenpass source code
|
||||
fn print_literal(path: &[&str], shake_or_blake: EitherShakeOrBlake) -> Result<()> {
|
||||
fn print_literal(path: &[&str], shake_or_blake: KeyedHash) -> Result<()> {
|
||||
let val = calculate_hash_value(HashDomain::zero(shake_or_blake), path)?;
|
||||
let (last, prefix) = path.split_last().context("developer error!")?;
|
||||
let var_name = last.to_shouty_snake_case();
|
||||
@@ -54,7 +53,7 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_code_inner(&self, prefix: &[&str], shake_or_blake: EitherShakeOrBlake) -> Result<()> {
|
||||
fn gen_code_inner(&self, prefix: &[&str], shake_or_blake: KeyedHash) -> Result<()> {
|
||||
let mut path = prefix.to_owned();
|
||||
path.push(self.name());
|
||||
|
||||
@@ -70,7 +69,7 @@ impl Tree {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gen_code(&self, shake_or_blake: EitherShakeOrBlake) -> Result<()> {
|
||||
fn gen_code(&self, shake_or_blake: KeyedHash) -> Result<()> {
|
||||
self.gen_code_inner(&[], shake_or_blake)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//! use rosenpass::{hash_domain, hash_domain_ns};
|
||||
//! use rosenpass::hash_domains::protocol;
|
||||
//!
|
||||
//! use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||
//! use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
//!
|
||||
//! // Declaring a custom hash domain
|
||||
//! hash_domain_ns!(protocol, custom_domain, "my custom hash domain label");
|
||||
@@ -29,7 +29,7 @@
|
||||
//! hash_domain!(domain_separators, sep2, "2");
|
||||
//!
|
||||
//! // We use the SHAKE256 hash function for this example
|
||||
//! let hash_choice = EitherShakeOrBlake::Left(rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core);
|
||||
//! let hash_choice = KeyedHash::keyed_shake256();
|
||||
//!
|
||||
//! // Generating values under hasher1 with both domain separators
|
||||
//! let h1 = hasher1(hash_choice.clone())?.mix(b"some data")?.dup();
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_ciphers::hash_domain::HashDomain;
|
||||
use rosenpass_ciphers::subtle::either_hash::KeyedHash;
|
||||
use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
|
||||
/// Declare a hash function
|
||||
///
|
||||
|
||||
@@ -21,11 +21,11 @@ use rand::Fill as Randomize;
|
||||
|
||||
use crate::{hash_domains, msgs::*, RosenpassError};
|
||||
use memoffset::span_of;
|
||||
use rosenpass_cipher_traits::keyed_hash::KeyedHashInstance;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace};
|
||||
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
|
||||
use rosenpass_ciphers::keyed_hash;
|
||||
use rosenpass_ciphers::subtle::either_hash::KeyedHash;
|
||||
use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
||||
use rosenpass_constant_time as constant_time;
|
||||
use rosenpass_secret_memory::{Public, PublicBox, Secret};
|
||||
@@ -371,7 +371,7 @@ pub enum ProtocolVersion {
|
||||
}
|
||||
|
||||
impl ProtocolVersion {
|
||||
pub fn shake_or_blake(&self) -> KeyedHash {
|
||||
pub fn keyed_hash(&self) -> KeyedHash {
|
||||
match self {
|
||||
ProtocolVersion::V02 => KeyedHash::incorrect_hmac_blake2b(),
|
||||
ProtocolVersion::V03 => KeyedHash::keyed_shake256(),
|
||||
@@ -720,8 +720,13 @@ impl KnownResponseHasher {
|
||||
/// Panics in case of a problem with this underlying hash function
|
||||
pub fn hash<Msg: AsBytes + FromBytes>(&self, msg: &Envelope<Msg>) -> KnownResponseHash {
|
||||
let data = &msg.as_bytes()[span_of!(Envelope<Msg>, msg_type..cookie)];
|
||||
let hash = keyed_hash::hash(self.key.secret(), data)
|
||||
.to_this(Public::<32>::zero)
|
||||
// TODO: the hash choice hasn't been propagated here so far
|
||||
let hash_choice =
|
||||
rosenpass_ciphers::subtle::keyed_hash::KeyedHash::incorrect_hmac_blake2b();
|
||||
|
||||
let mut hash = [0; 32];
|
||||
hash_choice
|
||||
.keyed_hash(self.key.secret(), data, &mut hash)
|
||||
.unwrap();
|
||||
Public::from_slice(&hash[0..16]) // truncate to 16 bytes
|
||||
}
|
||||
@@ -1682,7 +1687,7 @@ impl Peer {
|
||||
#[rustfmt::skip]
|
||||
pub fn pidt(&self) -> Result<PeerId> {
|
||||
Ok(Public::new(
|
||||
hash_domains::peerid(self.protocol_version.shake_or_blake())?
|
||||
hash_domains::peerid(self.protocol_version.keyed_hash())?
|
||||
.mix(self.spkt.deref())?
|
||||
.into_value()))
|
||||
}
|
||||
@@ -1695,12 +1700,11 @@ impl Session {
|
||||
///
|
||||
/// ```
|
||||
/// use rosenpass::protocol::{Session, HandshakeRole};
|
||||
/// use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
|
||||
/// use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||
/// use rosenpass_ciphers::keyed_hash::KeyedHash;
|
||||
///
|
||||
/// rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
///
|
||||
/// let s = Session::zero(EitherShakeOrBlake::keyed_shake256());
|
||||
/// let s = Session::zero(KeyedHash::keyed_shake256());
|
||||
/// assert_eq!(s.created_at, 0.0);
|
||||
/// assert_eq!(s.handshake_role, HandshakeRole::Initiator);
|
||||
/// ```
|
||||
@@ -2352,7 +2356,7 @@ impl CryptoServer {
|
||||
let mut msg_out = truncating_cast_into::<Envelope<InitConf>>(tx_buf)?;
|
||||
let peer = self.handle_resp_hello(&msg_in.payload, &mut msg_out.payload)?;
|
||||
ensure!(
|
||||
msg_in.check_seal(self, peer.get(self).protocol_version.shake_or_blake())?,
|
||||
msg_in.check_seal(self, peer.get(self).protocol_version.keyed_hash())?,
|
||||
seal_broken
|
||||
);
|
||||
|
||||
@@ -2374,10 +2378,8 @@ impl CryptoServer {
|
||||
Some(cached) => {
|
||||
let peer = cached.peer();
|
||||
ensure!(
|
||||
msg_in.check_seal(
|
||||
self,
|
||||
peer.get(self).protocol_version.shake_or_blake()
|
||||
)?,
|
||||
msg_in
|
||||
.check_seal(self, peer.get(self).protocol_version.keyed_hash())?,
|
||||
seal_broken
|
||||
);
|
||||
let cached = cached
|
||||
@@ -2458,7 +2460,7 @@ impl CryptoServer {
|
||||
|
||||
/// TODO documentation
|
||||
fn verify_hash_choice_match(&self, peer: PeerPtr, peer_hash_choice: KeyedHash) -> Result<()> {
|
||||
match peer.get(self).protocol_version.shake_or_blake() {
|
||||
match peer.get(self).protocol_version.keyed_hash() {
|
||||
KeyedHash::KeyedShake256(_) => match peer_hash_choice {
|
||||
KeyedHash::KeyedShake256(_) => Ok(()),
|
||||
KeyedHash::IncorrectHmacBlake2b(_) => bail!("Hash function mismatch"),
|
||||
@@ -3208,7 +3210,7 @@ where
|
||||
{
|
||||
/// Internal business logic: Calculate the message authentication code (`mac`) and also append cookie value
|
||||
pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
|
||||
let mac = hash_domains::mac(peer.get(srv).protocol_version.shake_or_blake())?
|
||||
let mac = hash_domains::mac(peer.get(srv).protocol_version.keyed_hash())?
|
||||
.mix(peer.get(srv).spkt.deref())?
|
||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
||||
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
|
||||
@@ -3221,7 +3223,7 @@ where
|
||||
/// This is called inside [Self::seal] and does not need to be called again separately.
|
||||
pub fn seal_cookie(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
|
||||
if let Some(cookie_key) = &peer.cv().get(srv) {
|
||||
let cookie = hash_domains::cookie(peer.get(srv).protocol_version.shake_or_blake())?
|
||||
let cookie = hash_domains::cookie(peer.get(srv).protocol_version.keyed_hash())?
|
||||
.mix(cookie_key.value.secret())?
|
||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..cookie)])?;
|
||||
self.cookie
|
||||
@@ -3384,7 +3386,7 @@ impl HandshakeState {
|
||||
.copy_from_slice(self.ck.clone().danger_into_secret().secret());
|
||||
|
||||
// calculate ad contents
|
||||
let ad = hash_domains::biscuit_ad(peer.get(srv).protocol_version.shake_or_blake())?
|
||||
let ad = hash_domains::biscuit_ad(peer.get(srv).protocol_version.keyed_hash())?
|
||||
.mix(srv.spkm.deref())?
|
||||
.mix(self.sidi.as_slice())?
|
||||
.mix(self.sidr.as_slice())?
|
||||
@@ -3446,7 +3448,7 @@ impl HandshakeState {
|
||||
|
||||
let ck = SecretHashDomain::danger_from_secret(
|
||||
Secret::from_slice(&biscuit.ck),
|
||||
peer.get(srv).protocol_version.shake_or_blake(),
|
||||
peer.get(srv).protocol_version.keyed_hash(),
|
||||
)
|
||||
.dup();
|
||||
// Reconstruct the handshake state
|
||||
@@ -3514,7 +3516,7 @@ impl CryptoServer {
|
||||
Ok(session
|
||||
.ck
|
||||
.mix(&hash_domains::osk(
|
||||
peer.get(self).protocol_version.shake_or_blake(),
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?)?
|
||||
.into_secret())
|
||||
}
|
||||
@@ -3526,7 +3528,7 @@ impl CryptoServer {
|
||||
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
|
||||
let mut hs = InitiatorHandshake::zero_with_timestamp(
|
||||
self,
|
||||
peer.get(self).protocol_version.shake_or_blake(),
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
);
|
||||
|
||||
// IHI1
|
||||
@@ -3553,7 +3555,7 @@ impl CryptoServer {
|
||||
// IHI6
|
||||
hs.core.encrypt_and_mix(
|
||||
ih.pidic.as_mut_slice(),
|
||||
self.pidm(peer.get(self).protocol_version.shake_or_blake())?
|
||||
self.pidm(peer.get(self).protocol_version.keyed_hash())?
|
||||
.as_ref(),
|
||||
)?;
|
||||
|
||||
@@ -3729,7 +3731,7 @@ impl CryptoServer {
|
||||
core.enter_live(
|
||||
self,
|
||||
HandshakeRole::Initiator,
|
||||
peer.get(self).protocol_version.shake_or_blake(),
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?,
|
||||
)?;
|
||||
hs_mut!().core.erase();
|
||||
@@ -3787,7 +3789,7 @@ impl CryptoServer {
|
||||
core.enter_live(
|
||||
self,
|
||||
HandshakeRole::Responder,
|
||||
peer.get(self).protocol_version.shake_or_blake(),
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?,
|
||||
)?;
|
||||
// TODO: This should be part of the protocol specification.
|
||||
@@ -3848,7 +3850,7 @@ impl CryptoServer {
|
||||
.lookup_handshake(sid)
|
||||
.with_context(|| format!("Got RespConf packet for non-existent session {sid:?}"))?;
|
||||
ensure!(
|
||||
msg_in.check_seal(self, hs.peer().get(self).protocol_version.shake_or_blake())?,
|
||||
msg_in.check_seal(self, hs.peer().get(self).protocol_version.keyed_hash())?,
|
||||
seal_broken
|
||||
);
|
||||
let ses = hs.peer().session();
|
||||
@@ -4362,21 +4364,20 @@ mod test {
|
||||
|
||||
assert_eq!(PeerPtr(0).cv().lifecycle(&a), Lifecycle::Young);
|
||||
|
||||
let expected_cookie_value =
|
||||
hash_domains::cookie_value(protocol_version.shake_or_blake())
|
||||
.unwrap()
|
||||
.mix(
|
||||
b.active_or_retired_cookie_secrets()[0]
|
||||
.unwrap()
|
||||
.get(&b)
|
||||
.value
|
||||
.secret(),
|
||||
)
|
||||
.unwrap()
|
||||
.mix(ip_addr_port_a.encode())
|
||||
.unwrap()
|
||||
.into_value()[..16]
|
||||
.to_vec();
|
||||
let expected_cookie_value = hash_domains::cookie_value(protocol_version.keyed_hash())
|
||||
.unwrap()
|
||||
.mix(
|
||||
b.active_or_retired_cookie_secrets()[0]
|
||||
.unwrap()
|
||||
.get(&b)
|
||||
.value
|
||||
.secret(),
|
||||
)
|
||||
.unwrap()
|
||||
.mix(ip_addr_port_a.encode())
|
||||
.unwrap()
|
||||
.into_value()[..16]
|
||||
.to_vec();
|
||||
|
||||
assert_eq!(
|
||||
PeerPtr(0).cv().get(&a).map(|x| &x.value.secret()[..]),
|
||||
@@ -4593,7 +4594,7 @@ mod test {
|
||||
let res = srv.handle_init_conf(
|
||||
&ic.payload,
|
||||
&mut discard_resp_conf,
|
||||
protocol_version.clone().shake_or_blake(),
|
||||
protocol_version.clone().keyed_hash(),
|
||||
);
|
||||
assert!(res.is_err());
|
||||
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
ops::DerefMut,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::mpsc,
|
||||
thread::{self, sleep},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::ensure;
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use rosenpass::{
|
||||
app_server::{ipv4_any_binding, ipv6_any_binding, AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
||||
app_server::{AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
||||
protocol::{SPk, SSk, SymKey},
|
||||
};
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_util::{file::LoadValueB64, functional::run, mem::DiscardResultExt, result::OkExt};
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user