Skip to content

Commit 4b88ca4

Browse files
committed
rfc6979: cleanups for HMAC_DRBG implementation
These are inspired by part from feedback on RustCrypto/CSRNGs#7
1 parent a53bd2e commit 4b88ca4

2 files changed

Lines changed: 54 additions & 55 deletions

File tree

rfc6979/src/hmac_drbg.rs

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,87 @@
11
use core::fmt::{self, Debug};
22
use hmac::{
3-
KeyInit, SimpleHmacReset,
4-
digest::{Digest, FixedOutputReset, Mac, array::Array, block_api::BlockSizeUser},
3+
KeyInit, SimpleHmac,
4+
digest::{Digest, Mac, OutputSizeUser, array::Array, block_api::BlockSizeUser},
55
};
66

7-
/// Implementation of `HMAC_DRBG` as described in NIST SP800-90A.
7+
/// Implementation of [NIST SP800-90A]'s `HMAC_DRBG` HMAC-based deterministic random bit generator.
88
///
9-
/// <https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final>
10-
///
11-
/// This is a HMAC-based deterministic random bit generator.
12-
// TODO(tarcieri): extract this into its own crate
9+
/// [NIST SP800-90A]: https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final
10+
// TODO(tarcieri): extract this into the `hmacdrbg` crate: RustCrypto/CSRNGs#7
1311
pub(crate) struct HmacDrbg<D>
1412
where
15-
D: Digest + BlockSizeUser + FixedOutputReset,
13+
D: OutputSizeUser,
1614
{
1715
/// HMAC key `K` (see RFC 6979 Section 3.2.c)
18-
k: SimpleHmacReset<D>,
16+
k: Array<u8, D::OutputSize>,
1917

2018
/// Chaining value `V` (see RFC 6979 Section 3.2.c)
2119
v: Array<u8, D::OutputSize>,
2220
}
2321

2422
impl<D> HmacDrbg<D>
2523
where
26-
D: Digest + BlockSizeUser + FixedOutputReset,
24+
D: Digest + BlockSizeUser,
2725
{
2826
/// Initialize `HMAC_DRBG`.
2927
#[must_use]
30-
#[allow(clippy::missing_panics_doc, reason = "should not panic")]
3128
pub(crate) fn new(entropy_input: &[u8], nonce: &[u8], personalization_string: &[u8]) -> Self {
32-
let mut k = SimpleHmacReset::new(&Default::default());
33-
let mut v = Array::default();
34-
35-
v.fill(0x01);
36-
37-
for i in 0..=1 {
38-
k.update(&v);
39-
k.update(&[i]);
40-
k.update(entropy_input);
41-
k.update(nonce);
42-
k.update(personalization_string);
43-
k = SimpleHmacReset::new_from_slice(&k.finalize().into_bytes()).expect("should work");
44-
45-
// Steps 3.2.e,g: v = HMAC_k(v)
46-
k.update(&v);
47-
v = k.finalize_reset().into_bytes();
48-
}
49-
50-
Self { k, v }
29+
let mut drbg = Self {
30+
k: Array::default(),
31+
v: Array::default(),
32+
};
33+
drbg.v.fill(0x01);
34+
drbg.update(&[entropy_input, nonce, personalization_string]);
35+
drbg
5136
}
5237

5338
/// Write the next `HMAC_DRBG` output to the given byte slice.
54-
#[allow(clippy::missing_panics_doc, reason = "should not panic")]
5539
pub(crate) fn fill_bytes(&mut self, out: &mut [u8]) {
56-
let mut out_chunks = out.chunks_exact_mut(self.v.len());
57-
58-
for out_chunk in &mut out_chunks {
59-
self.k.update(&self.v);
60-
self.v = self.k.finalize_reset().into_bytes();
40+
for out_chunk in out.chunks_mut(self.v.len()) {
41+
self.update_v();
6142
out_chunk.copy_from_slice(&self.v[..out_chunk.len()]);
6243
}
6344

64-
let out_remainder = out_chunks.into_remainder();
65-
if !out_remainder.is_empty() {
66-
self.k.update(&self.v);
67-
self.v = self.k.finalize_reset().into_bytes();
68-
out_remainder.copy_from_slice(&self.v[..out_remainder.len()]);
45+
self.update(&[]);
46+
}
47+
48+
/// Update `K` and `V` using the provided seed material.
49+
fn update(&mut self, inputs: &[&[u8]]) {
50+
let mut hmac = self.hmac_k();
51+
hmac.update(&self.v);
52+
hmac.update(&[0x00]);
53+
inputs.iter().for_each(|&input| hmac.update(input));
54+
55+
self.k = hmac.finalize().into_bytes();
56+
self.update_v();
57+
58+
if !inputs.is_empty() {
59+
let mut hmac = self.hmac_k();
60+
hmac.update(&self.v);
61+
hmac.update(&[0x01]);
62+
inputs.iter().for_each(|&input| hmac.update(input));
63+
64+
self.k = hmac.finalize().into_bytes();
65+
self.update_v();
6966
}
67+
}
68+
69+
/// Update `V = HMAC(K, V)`.
70+
fn update_v(&mut self) {
71+
let mut hmac = self.hmac_k();
72+
hmac.update(&self.v);
73+
self.v = hmac.finalize().into_bytes();
74+
}
7075

71-
self.k.update(&self.v);
72-
self.k.update(&[0x00]);
73-
self.k = SimpleHmacReset::new_from_slice(&self.k.finalize_reset().into_bytes())
74-
.expect("should work");
75-
self.k.update(&self.v);
76-
self.v = self.k.finalize_reset().into_bytes();
76+
/// Initialize HMAC using the current value of `K`.
77+
fn hmac_k(&self) -> SimpleHmac<D> {
78+
SimpleHmac::<D>::new_from_slice(&self.k).expect("HMAC key should be valid")
7779
}
7880
}
7981

8082
impl<D> Debug for HmacDrbg<D>
8183
where
82-
D: Digest + BlockSizeUser + FixedOutputReset,
84+
D: OutputSizeUser,
8385
{
8486
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8587
f.debug_struct("HmacDrbg").finish_non_exhaustive()

rfc6979/src/lib.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,17 @@ pub use hmac::digest::array::typenum::consts;
5555
use crate::hmac_drbg::HmacDrbg;
5656
use bigint::{Encoding, Limb, Unsigned};
5757
use core::fmt;
58-
use hmac::digest::{Digest, FixedOutput, FixedOutputReset, block_api::BlockSizeUser};
58+
use hmac::digest::{Digest, OutputSizeUser, block_api::BlockSizeUser};
5959

6060
/// Deterministic generator for the ephemeral scalar `k` as used by (EC)DSA.
61-
pub struct KGenerator<'a, D, U>
62-
where
63-
D: Digest + BlockSizeUser + FixedOutput + FixedOutputReset,
64-
{
61+
pub struct KGenerator<'a, D: OutputSizeUser, U> {
6562
drbg: HmacDrbg<D>,
6663
q: &'a U,
6764
}
6865

6966
impl<'a, D, U> KGenerator<'a, D, U>
7067
where
71-
D: Digest + BlockSizeUser + FixedOutput + FixedOutputReset,
68+
D: Digest + BlockSizeUser,
7269
U: Unsigned + Encoding,
7370
{
7471
/// Initialize `k` generator.
@@ -109,7 +106,7 @@ where
109106

110107
impl<'a, D, U> fmt::Debug for KGenerator<'a, D, U>
111108
where
112-
D: Digest + BlockSizeUser + FixedOutput + FixedOutputReset,
109+
D: Digest + BlockSizeUser,
113110
U: Unsigned + Encoding,
114111
{
115112
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

0 commit comments

Comments
 (0)