1#![no_std]
2#![doc = include_str!("../README.md")]
3#![forbid(unsafe_code, clippy::unwrap_used)]
4#![warn(missing_docs, rust_2018_idioms)]
5#![doc(
6 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
7 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
8)]
9
10mod ct_cmp;
41
42pub use hmac::digest::generic_array::typenum::consts;
43
44use hmac::{
45 digest::{
46 core_api::BlockSizeUser,
47 generic_array::{ArrayLength, GenericArray},
48 Digest, FixedOutput, FixedOutputReset, Mac,
49 },
50 SimpleHmac,
51};
52
53pub type ByteArray<Size> = GenericArray<u8, Size>;
55
56#[inline]
65pub fn generate_k<D, N>(
66 x: &ByteArray<N>,
67 n: &ByteArray<N>,
68 h: &ByteArray<N>,
69 data: &[u8],
70) -> ByteArray<N>
71where
72 D: Digest + BlockSizeUser + FixedOutput<OutputSize = N> + FixedOutputReset,
73 N: ArrayLength<u8>,
74{
75 let mut hmac_drbg = HmacDrbg::<D>::new(x, h, data);
76
77 loop {
78 let mut k = ByteArray::<N>::default();
79 hmac_drbg.fill_bytes(&mut k);
80
81 let k_is_zero = ct_cmp::ct_eq(&k, &ByteArray::default());
82 if (!k_is_zero & ct_cmp::ct_lt(&k, n)).into() {
83 return k;
84 }
85 }
86}
87
88pub struct HmacDrbg<D>
95where
96 D: Digest + BlockSizeUser + FixedOutputReset,
97{
98 k: SimpleHmac<D>,
100
101 v: GenericArray<u8, D::OutputSize>,
103}
104
105impl<D> HmacDrbg<D>
106where
107 D: Digest + BlockSizeUser + FixedOutputReset,
108{
109 pub fn new(entropy_input: &[u8], nonce: &[u8], additional_data: &[u8]) -> Self {
111 let mut k = SimpleHmac::new(&Default::default());
112 let mut v = GenericArray::default();
113
114 for b in &mut v {
115 *b = 0x01;
116 }
117
118 for i in 0..=1 {
119 k.update(&v);
120 k.update(&[i]);
121 k.update(entropy_input);
122 k.update(nonce);
123 k.update(additional_data);
124 k = SimpleHmac::new_from_slice(&k.finalize().into_bytes()).expect("HMAC error");
125
126 k.update(&v);
128 v = k.finalize_reset().into_bytes();
129 }
130
131 Self { k, v }
132 }
133
134 pub fn fill_bytes(&mut self, out: &mut [u8]) {
136 for out_chunk in out.chunks_mut(self.v.len()) {
137 self.k.update(&self.v);
138 self.v = self.k.finalize_reset().into_bytes();
139 out_chunk.copy_from_slice(&self.v[..out_chunk.len()]);
140 }
141
142 self.k.update(&self.v);
143 self.k.update(&[0x00]);
144 self.k =
145 SimpleHmac::new_from_slice(&self.k.finalize_reset().into_bytes()).expect("HMAC error");
146 self.k.update(&self.v);
147 self.v = self.k.finalize_reset().into_bytes();
148 }
149}