/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rfc6979-0.6.0/src/hmac_drbg.rs
Line | Count | Source |
1 | | use core::fmt::{self, Debug}; |
2 | | use hmac::{ |
3 | | KeyInit, SimpleHmac, |
4 | | digest::{Digest, Mac, OutputSizeUser, array::Array, block_api::BlockSizeUser}, |
5 | | }; |
6 | | |
7 | | /// Implementation of [NIST SP800-90A]'s `HMAC_DRBG` HMAC-based deterministic random bit generator. |
8 | | /// |
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 |
11 | | pub(crate) struct HmacDrbg<D> |
12 | | where |
13 | | D: OutputSizeUser, |
14 | | { |
15 | | /// HMAC key `K` (see RFC 6979 Section 3.2.c) |
16 | | k: Array<u8, D::OutputSize>, |
17 | | |
18 | | /// Chaining value `V` (see RFC 6979 Section 3.2.c) |
19 | | v: Array<u8, D::OutputSize>, |
20 | | } |
21 | | |
22 | | impl<D> HmacDrbg<D> |
23 | | where |
24 | | D: BlockSizeUser + Digest, |
25 | | { |
26 | | /// Initialize `HMAC_DRBG`. |
27 | | #[must_use] |
28 | 2.16k | pub(crate) fn new(entropy_input: &[u8], nonce: &[u8], personalization_string: &[u8]) -> Self { |
29 | 2.16k | let mut drbg = Self { |
30 | 2.16k | k: Array::default(), |
31 | 2.16k | v: Array::default(), |
32 | 2.16k | }; |
33 | 2.16k | drbg.v.fill(0x01); |
34 | 2.16k | drbg.update(&[entropy_input, nonce, personalization_string]); |
35 | 2.16k | drbg |
36 | 2.16k | } |
37 | | |
38 | | /// Write the next `HMAC_DRBG` output to the given byte slice. |
39 | 2.16k | pub(crate) fn fill_bytes(&mut self, out: &mut [u8]) { |
40 | 2.16k | for out_chunk in out.chunks_mut(self.v.len()) { |
41 | 2.16k | self.update_v(); |
42 | 2.16k | out_chunk.copy_from_slice(&self.v[..out_chunk.len()]); |
43 | 2.16k | } |
44 | | |
45 | 2.16k | self.update(&[]); |
46 | 2.16k | } |
47 | | |
48 | | /// Update `K` and `V` using the provided seed material. |
49 | 4.32k | fn update(&mut self, inputs: &[&[u8]]) { |
50 | 4.32k | let mut hmac = self.hmac_k(); |
51 | 4.32k | hmac.update(&self.v); |
52 | 4.32k | hmac.update(&[0x00]); |
53 | 6.48k | inputs.iter().for_each(|&input| hmac.update(input)); |
54 | | |
55 | 4.32k | self.k = hmac.finalize().into_bytes(); |
56 | 4.32k | self.update_v(); |
57 | | |
58 | 4.32k | if !inputs.is_empty() { |
59 | 2.16k | let mut hmac = self.hmac_k(); |
60 | 2.16k | hmac.update(&self.v); |
61 | 2.16k | hmac.update(&[0x01]); |
62 | 6.48k | inputs.iter().for_each(|&input| hmac.update(input)); |
63 | | |
64 | 2.16k | self.k = hmac.finalize().into_bytes(); |
65 | 2.16k | self.update_v(); |
66 | 2.16k | } |
67 | 4.32k | } |
68 | | |
69 | | /// Update `V = HMAC(K, V)`. |
70 | 8.64k | fn update_v(&mut self) { |
71 | 8.64k | let mut hmac = self.hmac_k(); |
72 | 8.64k | hmac.update(&self.v); |
73 | 8.64k | self.v = hmac.finalize().into_bytes(); |
74 | 8.64k | } |
75 | | |
76 | | /// Initialize HMAC using the current value of `K`. |
77 | 15.1k | fn hmac_k(&self) -> SimpleHmac<D> { |
78 | 15.1k | SimpleHmac::<D>::new_from_slice(&self.k).expect("HMAC key should be valid") |
79 | 15.1k | } |
80 | | } |
81 | | |
82 | | impl<D> Debug for HmacDrbg<D> |
83 | | where |
84 | | D: OutputSizeUser, |
85 | | { |
86 | | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
87 | | f.debug_struct("HmacDrbg").finish_non_exhaustive() |
88 | | } |
89 | | } |
90 | | |
91 | | #[cfg(test)] |
92 | | mod tests { |
93 | | use super::HmacDrbg; |
94 | | use hex_literal::hex; |
95 | | use sha2::Sha256; |
96 | | |
97 | | // ECDSA with K-163+SHA-256. |
98 | | #[test] |
99 | | fn rfc6979_appendix_a1_k163() { |
100 | | let x = hex!("009A4D6792295A7F730FC3F2B49CBC0F62E862272F"); |
101 | | |
102 | | // NOTE: this input is `SHA256("sample")` with `bits2octets` applied in advance |
103 | | let h = hex!("01795EDF0D54DB760F156D0DAC04C0322B3A204224"); |
104 | | |
105 | | let mut drbg = HmacDrbg::<Sha256>::new(&x, &h, &[]); |
106 | | let mut out = [0u8; 21]; |
107 | | drbg.fill_bytes(&mut out); |
108 | | assert_eq!(out, hex!("9305A46DE7FF8EB107194DEBD3FD48AA20D5E7656C")); |
109 | | } |
110 | | } |