From 30e158f5941a903846da79adcaf3c00a12706a09 Mon Sep 17 00:00:00 2001 From: David Niehues <7667041+DavidNiehues@users.noreply.github.com> Date: Tue, 11 Feb 2025 21:14:24 +0100 Subject: [PATCH] dev(ciphers): change HashDomain and related structures to use EitherShakeOrBlake. Docu pending --- ciphers/src/hash_domain.rs | 65 +++++++++++-------- ciphers/src/subtle/either_hash.rs | 11 +++- .../subtle/hash_functions/keyed_shake256.rs | 2 +- ciphers/src/subtle/mod.rs | 2 +- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/ciphers/src/hash_domain.rs b/ciphers/src/hash_domain.rs index 2f67460..55443fd 100644 --- a/ciphers/src/hash_domain.rs +++ b/ciphers/src/hash_domain.rs @@ -5,16 +5,20 @@ use rosenpass_to::To; use crate::keyed_hash as hash; pub use hash::KEY_LEN; +use rosenpass_cipher_traits::KeyedHashInstance; +use crate::subtle::either_hash::EitherShakeOrBlake; /// ///```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_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(); +/// let mut hash_domain = HashDomain::zero(EitherShakeOrBlake::Left(SHAKE256Core)); /// hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?; /// // upgrade to reusable hash domain /// let hash_domain_namespace: HashDomainNamespace = hash_domain.dup(); @@ -39,36 +43,36 @@ pub use hash::KEY_LEN; /// The key must consist of [KEY_LEN] many bytes. If the key must remain secret, /// use [SecretHashDomain] instead. #[derive(Clone, Debug)] -pub struct HashDomain([u8; KEY_LEN]); +pub struct HashDomain([u8; KEY_LEN], EitherShakeOrBlake); /// A reusable hash domain for a namespace identified by the key. /// The key must consist of [KEY_LEN] many bytes. If the key must remain secret, /// use [SecretHashDomainNamespace] instead. #[derive(Clone, Debug)] -pub struct HashDomainNamespace([u8; KEY_LEN]); +pub struct HashDomainNamespace([u8; KEY_LEN], EitherShakeOrBlake); /// A use-once hash domain for a specified key that can be used directly /// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes. #[derive(Clone, Debug)] -pub struct SecretHashDomain(Secret); +pub struct SecretHashDomain(Secret, EitherShakeOrBlake); /// A reusable secure hash domain for a namespace identified by the key and that keeps the key secure /// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes. #[derive(Clone, Debug)] -pub struct SecretHashDomainNamespace(Secret); +pub struct SecretHashDomainNamespace(Secret, EitherShakeOrBlake); impl HashDomain { /// Creates a nw [HashDomain] initialized with a all-zeros key. - pub fn zero() -> Self { - Self([0u8; KEY_LEN]) + pub fn zero(choice: EitherShakeOrBlake) -> Self { + Self([0u8; KEY_LEN], choice) } /// Turns this [HashDomain] into a [HashDomainNamespace], keeping the key. pub fn dup(self) -> HashDomainNamespace { - HashDomainNamespace(self.0) + HashDomainNamespace(self.0, self.1) } /// Turns this [HashDomain] into a [SecretHashDomain] by wrapping the key into a [Secret] /// and creating a new [SecretHashDomain] from it. pub fn turn_secret(self) -> SecretHashDomain { - SecretHashDomain(Secret::from_slice(&self.0)) + SecretHashDomain(Secret::from_slice(&self.0), self.1) } // TODO: Protocol! Use domain separation to ensure that @@ -77,14 +81,16 @@ impl HashDomain { /// as the `data` and uses the result as the key for the new [HashDomain]. /// pub fn mix(self, v: &[u8]) -> Result { - Ok(Self(hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?)) + let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN]; + self.1.keyed_hash(&self.0, v, &mut new_key)?; + Ok(Self(new_key, self.1)) } /// Creates a new [SecretHashDomain] by mixing in a new key `v` /// by calling [SecretHashDomain::invoke_primitive] with this /// [HashDomain]'s key as `k` and `v` as `d`. pub fn mix_secret(self, v: Secret) -> Result { - SecretHashDomain::invoke_primitive(&self.0, v.secret()) + SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1) } /// Gets the key of this [HashDomain]. @@ -98,9 +104,9 @@ impl HashDomainNamespace { /// it evaluates [hash::hash] with the key of this HashDomainNamespace key as the key and `v` /// as the `data` and uses the result as the key for the new [HashDomain]. pub fn mix(&self, v: &[u8]) -> Result { - Ok(HashDomain( - hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?, - )) + let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN]; + self.1.keyed_hash(&self.0, v, &mut new_key)?; + Ok(HashDomain(new_key, self.1.clone())) } /// Creates a new [SecretHashDomain] by mixing in a new key `v` @@ -109,7 +115,7 @@ impl HashDomainNamespace { /// /// It requires that `v` consists of exactly [KEY_LEN] many bytes. pub fn mix_secret(&self, v: Secret) -> Result { - SecretHashDomain::invoke_primitive(&self.0, v.secret()) + SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1.clone()) } } @@ -118,27 +124,30 @@ impl SecretHashDomain { /// [hash::hash] with `k` as the `key` and `d` s the `data`, and using the result /// as the content for the new [SecretHashDomain]. /// Both `k` and `d` have to be exactly [KEY_LEN] bytes in length. - pub fn invoke_primitive(k: &[u8], d: &[u8]) -> Result { - let mut r = SecretHashDomain(Secret::zero()); + /// TODO: docu + pub fn invoke_primitive(k: &[u8], d: &[u8], hash_choice: EitherShakeOrBlake) -> Result { + 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())?; Ok(r) } /// Creates a new [SecretHashDomain] that is initialized with an all zeros key. - pub fn zero() -> Self { - Self(Secret::zero()) + pub fn zero(hash_choice: EitherShakeOrBlake) -> Self { + Self(Secret::zero(), hash_choice) } /// Turns this [SecretHashDomain] into a [SecretHashDomainNamespace]. pub fn dup(self) -> SecretHashDomainNamespace { - SecretHashDomainNamespace(self.0) + SecretHashDomainNamespace(self.0, self.1) } /// Creates a new [SecretHashDomain] from a [Secret] `k`. /// /// It requires that `k` consist of exactly [KEY_LEN] bytes. - pub fn danger_from_secret(k: Secret) -> Self { - Self(k) + pub fn danger_from_secret(k: Secret, hash_choice: EitherShakeOrBlake) -> Self { + Self(k, hash_choice) } /// Creates a new [SecretHashDomain] by mixing in a new key `v`. Specifically, @@ -147,7 +156,7 @@ impl SecretHashDomain { /// /// It requires that `v` consists of exactly [KEY_LEN] many bytes. pub fn mix(self, v: &[u8]) -> Result { - Self::invoke_primitive(self.0.secret(), v) + Self::invoke_primitive(self.0.secret(), v, self.1) } /// Creates a new [SecretHashDomain] by mixing in a new key `v` @@ -156,7 +165,7 @@ impl SecretHashDomain { /// /// It requires that `v` consists of exactly [KEY_LEN] many bytes. pub fn mix_secret(self, v: Secret) -> Result { - Self::invoke_primitive(self.0.secret(), v.secret()) + Self::invoke_primitive(self.0.secret(), v.secret(), self.1) } /// Get the secret key data from this [SecretHashDomain]. @@ -180,7 +189,7 @@ impl SecretHashDomainNamespace { /// /// It requires that `v` consists of exactly [KEY_LEN] many bytes. pub fn mix(&self, v: &[u8]) -> Result { - SecretHashDomain::invoke_primitive(self.0.secret(), v) + SecretHashDomain::invoke_primitive(self.0.secret(), v, self.1.clone()) } /// Creates a new [SecretHashDomain] by mixing in a new key `v` @@ -189,7 +198,7 @@ impl SecretHashDomainNamespace { /// /// It requires that `v` consists of exactly [KEY_LEN] many bytes. pub fn mix_secret(&self, v: Secret) -> Result { - SecretHashDomain::invoke_primitive(self.0.secret(), v.secret()) + SecretHashDomain::invoke_primitive(self.0.secret(), v.secret(), self.1.clone()) } // TODO: This entire API is not very nice; we need this for biscuits, but @@ -199,4 +208,8 @@ impl SecretHashDomainNamespace { pub fn danger_into_secret(self) -> Secret { self.0 } + + pub fn shake_or_blake(&self) -> &EitherShakeOrBlake { + &self.1 + } } diff --git a/ciphers/src/subtle/either_hash.rs b/ciphers/src/subtle/either_hash.rs index 02245ff..6539d53 100644 --- a/ciphers/src/subtle/either_hash.rs +++ b/ciphers/src/subtle/either_hash.rs @@ -29,4 +29,13 @@ where } } -pub type EitherShakeOrBlake = HashChoice<32, 32, anyhow::Error, SHAKE256Core<32, 32>, Blake2bCore>; +pub type EitherShakeOrBlake = EitherHash<32, 32, anyhow::Error, SHAKE256Core<32, 32>, Blake2bCore>; + +impl Clone for EitherShakeOrBlake { + fn clone(&self) -> Self { + match self { + Self::Left(l) => Self::Left(l.clone()), + Self::Right(r) => Self::Right(r.clone()), + } + } +} diff --git a/ciphers/src/subtle/hash_functions/keyed_shake256.rs b/ciphers/src/subtle/hash_functions/keyed_shake256.rs index 0dc9f65..7ff188d 100644 --- a/ciphers/src/subtle/hash_functions/keyed_shake256.rs +++ b/ciphers/src/subtle/hash_functions/keyed_shake256.rs @@ -66,7 +66,7 @@ impl SHAKE256Core