From 3cd80765eeb4e7f77054e5b1337d6a2fb0d90ede Mon Sep 17 00:00:00 2001 From: Theo von Arx Date: Wed, 7 Aug 2024 08:09:55 +0200 Subject: [PATCH] blake2: add unkeyed hashing --- blake2/src/macros.rs | 55 +++++++++++++++++++++++++---------------- blake2/tests/mac.rs | 8 ++++-- blake2/tests/persona.rs | 4 +-- blake2/tests/unkeyed.rs | 28 +++++++++++++++++++++ 4 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 blake2/tests/unkeyed.rs diff --git a/blake2/src/macros.rs b/blake2/src/macros.rs index b17adb98..38067aaf 100644 --- a/blake2/src/macros.rs +++ b/blake2/src/macros.rs @@ -275,7 +275,7 @@ macro_rules! blake2_mac_impl { core: $hash, buffer: LazyBuffer<<$hash as BlockSizeUser>::BlockSize>, #[cfg(feature = "reset")] - key_block: Key, + key_block: Option>, _out: PhantomData, } @@ -286,35 +286,42 @@ macro_rules! blake2_mac_impl { { /// Create new instance using provided key, salt, and persona. /// + /// Setting key to `None` indicates unkeyed usage. + /// /// # Errors /// - /// Key length should not be empty or bigger than the block size and - /// the salt and persona length should not be bigger than quarter of - /// block size. If any of those conditions is false the method will - /// return an error. + /// If key is `Some`, then its length should not be zero or bigger + /// than the block size. The salt and persona length should not be + /// bigger than quarter of block size. If any of those conditions is + /// false the method will return an error. #[inline] pub fn new_with_salt_and_personal( - key: &[u8], + key: Option<&[u8]>, salt: &[u8], persona: &[u8], ) -> Result { - let kl = key.len(); + let kl = key.map_or(0, |k| k.len()); let bs = <$hash as BlockSizeUser>::BlockSize::USIZE; let qbs = bs / 4; - if kl == 0 || kl > bs || salt.len() > qbs || persona.len() > qbs { + if key.is_some() && kl == 0 || kl > bs || salt.len() > qbs || persona.len() > qbs { return Err(InvalidLength); } - let mut padded_key = Block::<$hash>::default(); - padded_key[..kl].copy_from_slice(key); + let buffer = if let Some(k) = key { + let mut padded_key = Block::<$hash>::default(); + padded_key[..kl].copy_from_slice(k); + LazyBuffer::new(&padded_key) + } else { + LazyBuffer::default() + }; Ok(Self { - core: <$hash>::new_with_params(salt, persona, key.len(), OutSize::USIZE), - buffer: LazyBuffer::new(&padded_key), + core: <$hash>::new_with_params(salt, persona, kl, OutSize::USIZE), + buffer, #[cfg(feature = "reset")] - key_block: { + key_block: key.map(|k| { let mut t = Key::::default(); - t[..kl].copy_from_slice(key); + t[..kl].copy_from_slice(k); t - }, + }), _out: PhantomData, }) } @@ -353,7 +360,7 @@ macro_rules! blake2_mac_impl { key_block: { let mut t = Key::::default(); t[..kl].copy_from_slice(key); - t + Some(t) }, _out: PhantomData, }) @@ -402,10 +409,14 @@ macro_rules! blake2_mac_impl { { fn reset(&mut self) { self.core.reset(); - let kl = self.key_block.len(); - let mut padded_key = Block::<$hash>::default(); - padded_key[..kl].copy_from_slice(&self.key_block); - self.buffer = LazyBuffer::new(&padded_key); + self.buffer = if let Some(k) = self.key_block { + let kl = k.len(); + let mut padded_key = Block::<$hash>::default(); + padded_key[..kl].copy_from_slice(&k); + LazyBuffer::new(&padded_key) + } else { + LazyBuffer::default() + } } } @@ -453,7 +464,9 @@ macro_rules! blake2_mac_impl { // `self.core` zeroized by its `Drop` impl self.buffer.zeroize(); #[cfg(feature = "reset")] - self.key_block.zeroize(); + if let Some(mut key_block) = self.key_block { + key_block.zeroize(); + } } } } diff --git a/blake2/tests/mac.rs b/blake2/tests/mac.rs index 7a166a04..6534f98c 100644 --- a/blake2/tests/mac.rs +++ b/blake2/tests/mac.rs @@ -30,6 +30,10 @@ fn blake2b_new_test() { #[test] fn mac_refuses_empty_keys() { - assert!(blake2::Blake2bMac512::new_with_salt_and_personal(&[], b"salt", b"persona").is_err()); - assert!(blake2::Blake2sMac256::new_with_salt_and_personal(&[], b"salt", b"persona").is_err()); + assert!( + blake2::Blake2bMac512::new_with_salt_and_personal(Some(&[]), b"salt", b"persona").is_err() + ); + assert!( + blake2::Blake2sMac256::new_with_salt_and_personal(Some(&[]), b"salt", b"persona").is_err() + ); } diff --git a/blake2/tests/persona.rs b/blake2/tests/persona.rs index 53ba8ef0..b2c552df 100644 --- a/blake2/tests/persona.rs +++ b/blake2/tests/persona.rs @@ -8,7 +8,7 @@ fn blake2s_persona() { "101112131415161718191a1b1c1d1e1f" ); let persona = b"personal"; - let ctx = Blake2sMac256::new_with_salt_and_personal(&key, &[], persona).unwrap(); + let ctx = Blake2sMac256::new_with_salt_and_personal(Some(&key), &[], persona).unwrap(); assert_eq!( ctx.finalize_fixed(), hex!( @@ -25,7 +25,7 @@ fn blake2b_persona() { "101112131415161718191a1b1c1d1e1f" ); let persona = b"personal"; - let ctx = Blake2bMac512::new_with_salt_and_personal(&key, &[], persona).unwrap(); + let ctx = Blake2bMac512::new_with_salt_and_personal(Some(&key), &[], persona).unwrap(); assert_eq!( ctx.finalize_fixed(), hex!( diff --git a/blake2/tests/unkeyed.rs b/blake2/tests/unkeyed.rs new file mode 100644 index 00000000..37bcb14e --- /dev/null +++ b/blake2/tests/unkeyed.rs @@ -0,0 +1,28 @@ +use blake2::{digest::FixedOutput, Blake2bMac512, Blake2sMac256}; +use hex_literal::hex; + +#[test] +fn blake2s_unkeyed() { + let ctx = Blake2sMac256::new_with_salt_and_personal(None, b"salt", b"persona").unwrap(); + assert_eq!( + ctx.finalize_fixed(), + hex!( + "d7de83e2b1fedd9755db747235b7ba4b" + "f9773a16b91c6b241e4b1d926160d9eb" + ), + ); +} + +#[test] +fn blake2b_unkeyed() { + let ctx = Blake2bMac512::new_with_salt_and_personal(None, b"salt", b"persona").unwrap(); + assert_eq!( + ctx.finalize_fixed(), + hex!( + "fa3cd38902ae0602d8f0066f18c579fa" + "e8068074fbe91f9f5774f841f5ab51fe" + "39140ad78d6576f8a0b9f8f4c2642211" + "11c9911d8ba1dbefcd034acdbedb8cde" + ), + ); +}