Skip to content

Commit 01e79f7

Browse files
authored
blake2: add unkeyed hashing (#612)
This introduces unkeyed hashing for blake2 as specified in [Section 2.5 of RFC 7693](https://www.rfc-editor.org/rfc/rfc7693.html#section-2.5) states the following: The second (little-endian) byte of the parameter block, "kk", specifies the key size in bytes. Set kk = 00 for unkeyed hashing. I propose to make the key an `Option<&[u8]>`: ```rust pub fn new_with_salt_and_personal( key: Option<&[u8]>, salt: &[u8], persona: &[u8], ) -> Result<Self, InvalidLength> ``` By making the key an `Option<&[u8]>` - rather than opting for the unkeyed usage in case of an empty `key` - we make the unkeyed usage explicit and avoid inadvertent usages. This closes #482. See also #509.
1 parent 2795b4f commit 01e79f7

File tree

4 files changed

+70
-25
lines changed

4 files changed

+70
-25
lines changed

blake2/src/macros.rs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ macro_rules! blake2_mac_impl {
275275
core: $hash,
276276
buffer: LazyBuffer<<$hash as BlockSizeUser>::BlockSize>,
277277
#[cfg(feature = "reset")]
278-
key_block: Key<Self>,
278+
key_block: Option<Key<Self>>,
279279
_out: PhantomData<OutSize>,
280280
}
281281

@@ -286,35 +286,42 @@ macro_rules! blake2_mac_impl {
286286
{
287287
/// Create new instance using provided key, salt, and persona.
288288
///
289+
/// Setting key to `None` indicates unkeyed usage.
290+
///
289291
/// # Errors
290292
///
291-
/// Key length should not be empty or bigger than the block size and
292-
/// the salt and persona length should not be bigger than quarter of
293-
/// block size. If any of those conditions is false the method will
294-
/// return an error.
293+
/// If key is `Some`, then its length should not be zero or bigger
294+
/// than the block size. The salt and persona length should not be
295+
/// bigger than quarter of block size. If any of those conditions is
296+
/// false the method will return an error.
295297
#[inline]
296298
pub fn new_with_salt_and_personal(
297-
key: &[u8],
299+
key: Option<&[u8]>,
298300
salt: &[u8],
299301
persona: &[u8],
300302
) -> Result<Self, InvalidLength> {
301-
let kl = key.len();
303+
let kl = key.map_or(0, |k| k.len());
302304
let bs = <$hash as BlockSizeUser>::BlockSize::USIZE;
303305
let qbs = bs / 4;
304-
if kl == 0 || kl > bs || salt.len() > qbs || persona.len() > qbs {
306+
if key.is_some() && kl == 0 || kl > bs || salt.len() > qbs || persona.len() > qbs {
305307
return Err(InvalidLength);
306308
}
307-
let mut padded_key = Block::<$hash>::default();
308-
padded_key[..kl].copy_from_slice(key);
309+
let buffer = if let Some(k) = key {
310+
let mut padded_key = Block::<$hash>::default();
311+
padded_key[..kl].copy_from_slice(k);
312+
LazyBuffer::new(&padded_key)
313+
} else {
314+
LazyBuffer::default()
315+
};
309316
Ok(Self {
310-
core: <$hash>::new_with_params(salt, persona, key.len(), OutSize::USIZE),
311-
buffer: LazyBuffer::new(&padded_key),
317+
core: <$hash>::new_with_params(salt, persona, kl, OutSize::USIZE),
318+
buffer,
312319
#[cfg(feature = "reset")]
313-
key_block: {
320+
key_block: key.map(|k| {
314321
let mut t = Key::<Self>::default();
315-
t[..kl].copy_from_slice(key);
322+
t[..kl].copy_from_slice(k);
316323
t
317-
},
324+
}),
318325
_out: PhantomData,
319326
})
320327
}
@@ -353,7 +360,7 @@ macro_rules! blake2_mac_impl {
353360
key_block: {
354361
let mut t = Key::<Self>::default();
355362
t[..kl].copy_from_slice(key);
356-
t
363+
Some(t)
357364
},
358365
_out: PhantomData,
359366
})
@@ -402,10 +409,14 @@ macro_rules! blake2_mac_impl {
402409
{
403410
fn reset(&mut self) {
404411
self.core.reset();
405-
let kl = self.key_block.len();
406-
let mut padded_key = Block::<$hash>::default();
407-
padded_key[..kl].copy_from_slice(&self.key_block);
408-
self.buffer = LazyBuffer::new(&padded_key);
412+
self.buffer = if let Some(k) = self.key_block {
413+
let kl = k.len();
414+
let mut padded_key = Block::<$hash>::default();
415+
padded_key[..kl].copy_from_slice(&k);
416+
LazyBuffer::new(&padded_key)
417+
} else {
418+
LazyBuffer::default()
419+
}
409420
}
410421
}
411422

@@ -453,7 +464,9 @@ macro_rules! blake2_mac_impl {
453464
// `self.core` zeroized by its `Drop` impl
454465
self.buffer.zeroize();
455466
#[cfg(feature = "reset")]
456-
self.key_block.zeroize();
467+
if let Some(mut key_block) = self.key_block {
468+
key_block.zeroize();
469+
}
457470
}
458471
}
459472
}

blake2/tests/mac.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ fn blake2b_new_test() {
3030

3131
#[test]
3232
fn mac_refuses_empty_keys() {
33-
assert!(blake2::Blake2bMac512::new_with_salt_and_personal(&[], b"salt", b"persona").is_err());
34-
assert!(blake2::Blake2sMac256::new_with_salt_and_personal(&[], b"salt", b"persona").is_err());
33+
assert!(
34+
blake2::Blake2bMac512::new_with_salt_and_personal(Some(&[]), b"salt", b"persona").is_err()
35+
);
36+
assert!(
37+
blake2::Blake2sMac256::new_with_salt_and_personal(Some(&[]), b"salt", b"persona").is_err()
38+
);
3539
}

blake2/tests/persona.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn blake2s_persona() {
88
"101112131415161718191a1b1c1d1e1f"
99
);
1010
let persona = b"personal";
11-
let ctx = Blake2sMac256::new_with_salt_and_personal(&key, &[], persona).unwrap();
11+
let ctx = Blake2sMac256::new_with_salt_and_personal(Some(&key), &[], persona).unwrap();
1212
assert_eq!(
1313
ctx.finalize_fixed(),
1414
hex!(
@@ -25,7 +25,7 @@ fn blake2b_persona() {
2525
"101112131415161718191a1b1c1d1e1f"
2626
);
2727
let persona = b"personal";
28-
let ctx = Blake2bMac512::new_with_salt_and_personal(&key, &[], persona).unwrap();
28+
let ctx = Blake2bMac512::new_with_salt_and_personal(Some(&key), &[], persona).unwrap();
2929
assert_eq!(
3030
ctx.finalize_fixed(),
3131
hex!(

blake2/tests/unkeyed.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use blake2::{digest::FixedOutput, Blake2bMac512, Blake2sMac256};
2+
use hex_literal::hex;
3+
4+
#[test]
5+
fn blake2s_unkeyed() {
6+
let ctx = Blake2sMac256::new_with_salt_and_personal(None, b"salt", b"persona").unwrap();
7+
assert_eq!(
8+
ctx.finalize_fixed(),
9+
hex!(
10+
"d7de83e2b1fedd9755db747235b7ba4b"
11+
"f9773a16b91c6b241e4b1d926160d9eb"
12+
),
13+
);
14+
}
15+
16+
#[test]
17+
fn blake2b_unkeyed() {
18+
let ctx = Blake2bMac512::new_with_salt_and_personal(None, b"salt", b"persona").unwrap();
19+
assert_eq!(
20+
ctx.finalize_fixed(),
21+
hex!(
22+
"fa3cd38902ae0602d8f0066f18c579fa"
23+
"e8068074fbe91f9f5774f841f5ab51fe"
24+
"39140ad78d6576f8a0b9f8f4c2642211"
25+
"11c9911d8ba1dbefcd034acdbedb8cde"
26+
),
27+
);
28+
}

0 commit comments

Comments
 (0)