Skip to content

Commit e727d23

Browse files
authored
rfc6979: cleanups for HMAC_DRBG implementation (#1403)
These are inspired by part from feedback on RustCrypto/CSRNGs#7
1 parent a53bd2e commit e727d23

8 files changed

Lines changed: 73 additions & 74 deletions

File tree

dsa/src/generate/secret_number.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{Components, signing_key::SigningKey};
66
use alloc::vec;
77
use core::cmp::min;
88
use crypto_bigint::{BoxedUint, NonZero, RandomBits, Resize};
9-
use digest::{Digest, FixedOutputReset, common::BlockSizeUser};
9+
use digest::{Digest, common::BlockSizeUser};
1010
use signature::rand_core::TryCryptoRng;
1111
use zeroize::Zeroizing;
1212

@@ -25,7 +25,7 @@ pub(crate) fn secret_number_rfc6979<D>(
2525
hash: &[u8],
2626
) -> Result<(BoxedUint, BoxedUint), signature::Error>
2727
where
28-
D: Digest + BlockSizeUser + FixedOutputReset,
28+
D: BlockSizeUser + Digest,
2929
{
3030
let q = signing_key.verifying_key().components().q();
3131
let size = (q.bits() / 8) as usize;

dsa/src/signing_key.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crypto_bigint::{
1414
modular::{BoxedMontyForm, BoxedMontyParams},
1515
};
1616
use crypto_common::Generate;
17-
use digest::{Digest, FixedOutputReset, common::BlockSizeUser};
17+
use digest::{Digest, Update, common::BlockSizeUser};
1818
use signature::{
1919
DigestSigner, MultipartSigner, RandomizedDigestSigner, Signer,
2020
hazmat::{PrehashSigner, RandomizedPrehashSigner},
@@ -96,7 +96,7 @@ impl SigningKey {
9696
#[cfg(feature = "hazmat")]
9797
pub fn sign_prehashed_rfc6979<D>(&self, prehash: &[u8]) -> Result<Signature, signature::Error>
9898
where
99-
D: Digest + BlockSizeUser + FixedOutputReset,
99+
D: BlockSizeUser + Digest,
100100
{
101101
let k_kinv = crate::generate::secret_number_rfc6979::<D>(self, prehash)?;
102102
self.sign_prehashed(k_kinv, prehash)
@@ -170,7 +170,7 @@ impl Signer<Signature> for SigningKey {
170170
impl MultipartSigner<Signature> for SigningKey {
171171
fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<Signature, signature::Error> {
172172
self.try_sign_digest(|digest: &mut sha2::Sha256| {
173-
msg.iter().for_each(|slice| digest.update(slice));
173+
msg.iter().for_each(|slice| Update::update(digest, slice));
174174
Ok(())
175175
})
176176
}
@@ -202,7 +202,7 @@ impl RandomizedPrehashSigner<Signature> for SigningKey {
202202

203203
impl<D> DigestSigner<D, Signature> for SigningKey
204204
where
205-
D: Digest + FixedOutputReset + BlockSizeUser,
205+
D: BlockSizeUser + Digest + Update,
206206
{
207207
fn try_sign_digest<F: Fn(&mut D) -> Result<(), signature::Error>>(
208208
&self,
@@ -219,7 +219,7 @@ where
219219

220220
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey
221221
where
222-
D: Digest + FixedOutputReset + BlockSizeUser,
222+
D: BlockSizeUser + Digest + Update,
223223
{
224224
fn try_sign_digest_with_rng<
225225
R: TryCryptoRng + ?Sized,

dsa/tests/deterministic.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![cfg(feature = "hazmat")]
22
use crypto_bigint::BoxedUint;
3-
use digest::{Digest, FixedOutputReset, common::BlockSizeUser};
3+
use digest::{Digest, Update, common::BlockSizeUser};
44
use dsa::{Components, Signature, SigningKey, VerifyingKey};
55
use sha1::Sha1;
66
use sha2::{Sha224, Sha256, Sha384, Sha512};
@@ -100,23 +100,23 @@ fn dsa_2048_signing_key() -> SigningKey {
100100
/// Generate a signature given the unhashed message and a private key
101101
fn generate_signature<D>(signing_key: SigningKey, data: &[u8]) -> Signature
102102
where
103-
D: Digest + FixedOutputReset + BlockSizeUser,
103+
D: BlockSizeUser + Digest + Update,
104104
{
105-
signing_key.sign_digest(|digest: &mut D| Digest::update(digest, data))
105+
signing_key.sign_digest(|digest: &mut D| Update::update(digest, data))
106106
}
107107

108108
/// Generate a signature using the 1024-bit DSA key
109109
fn generate_1024_signature<D>(data: &[u8]) -> Signature
110110
where
111-
D: Digest + FixedOutputReset + BlockSizeUser,
111+
D: BlockSizeUser + Digest + Update,
112112
{
113113
generate_signature::<D>(dsa_1024_signing_key(), data)
114114
}
115115

116116
/// Generate a signature using the 2048-bit DSA key
117117
fn generate_2048_signature<D>(data: &[u8]) -> Signature
118118
where
119-
D: Digest + FixedOutputReset + BlockSizeUser,
119+
D: BlockSizeUser + Digest + Update,
120120
{
121121
generate_signature::<D>(dsa_2048_signing_key(), data)
122122
}

ecdsa/src/hazmat.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use elliptic_curve::{
2525
};
2626

2727
#[cfg(feature = "digest")]
28-
use digest::{Digest, FixedOutputReset, block_api::BlockSizeUser};
28+
use digest::{Digest, block_api::BlockSizeUser};
2929

3030
/// Sign a prehashed message digest using the provided secret scalar and
3131
/// ephemeral scalar, returning an ECDSA signature.
@@ -108,7 +108,7 @@ pub fn sign_prehashed_rfc6979<C, D>(
108108
) -> (Signature<C>, RecoveryId)
109109
where
110110
C: EcdsaCurve + CurveArithmetic,
111-
D: Digest + BlockSizeUser + FixedOutputReset,
111+
D: Digest + BlockSizeUser,
112112
SignatureSize<C>: ArraySize,
113113
{
114114
let order = C::ORDER;

ecdsa/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ use elliptic_curve::{
9595
use alloc::vec::Vec;
9696
#[cfg(feature = "digest")]
9797
use digest::{
98-
Digest, FixedOutputReset,
98+
Digest, FixedOutput,
9999
common::BlockSizeUser,
100100
const_oid::{AssociatedOid, ObjectIdentifier},
101101
};
@@ -672,7 +672,7 @@ where
672672
pub trait DigestAlgorithm: EcdsaCurve {
673673
/// Preferred digest to use when computing ECDSA signatures for this
674674
/// elliptic curve. This is typically a member of the SHA-2 family.
675-
type Digest: BlockSizeUser + Digest + FixedOutputReset;
675+
type Digest: BlockSizeUser + Digest + FixedOutput;
676676
}
677677

678678
#[cfg(feature = "digest")]

ecdsa/src/recovery.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use {
88
DigestAlgorithm, EcdsaCurve, Signature, SignatureSize, SigningKey, VerifyingKey,
99
hazmat::{bytes2scalar, sign_prehashed_rfc6979, verify_prehashed},
1010
},
11-
digest::{Digest, FixedOutputReset, Update},
11+
digest::{Digest, Update},
1212
elliptic_curve::{
1313
AffinePoint, CurveArithmetic, FieldBytes, FieldBytesSize, Group, PrimeField,
1414
ProjectivePoint, Scalar,
@@ -252,7 +252,7 @@ where
252252
impl<C, D> RandomizedDigestSigner<D, (Signature<C>, RecoveryId)> for SigningKey<C>
253253
where
254254
C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
255-
D: Digest + Update + FixedOutputReset,
255+
D: Digest + Update,
256256
Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
257257
SignatureSize<C>: ArraySize,
258258
{
@@ -263,7 +263,7 @@ where
263263
) -> Result<(Signature<C>, RecoveryId)> {
264264
let mut digest = D::new();
265265
f(&mut digest)?;
266-
self.sign_prehash_with_rng(rng, &digest.finalize_reset())
266+
self.sign_prehash_with_rng(rng, &digest.finalize())
267267
}
268268
}
269269

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: BlockSizeUser + Digest,
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: BlockSizeUser + Digest,
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: BlockSizeUser + Digest,
113110
U: Unsigned + Encoding,
114111
{
115112
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

0 commit comments

Comments
 (0)