1#![forbid(unsafe_code)]
2
3extern crate alloc;
6
7pub mod rand_adapter;
9
10use alloc::vec::Vec;
11use core::{cmp::min, fmt};
12use getrandom::getrandom;
13use hmac::{Hmac, Mac};
14use sha2::Sha512;
15use subtle::{Choice, ConstantTimeEq};
16use zeroize::{Zeroize, ZeroizeOnDrop};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum Error {
21 RequestTooLarge,
23 ReseedRequired,
25 EntropyUnavailable,
27 EntropyHealthFailed,
29}
30
31impl fmt::Display for Error {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 write!(f, "{:?}", self)
34 }
35}
36
37impl std::error::Error for Error {}
38
39const DEFAULT_RESEED_INTERVAL: u64 = 1u64 << 48;
41const BLOCK_LEN: usize = 64;
42const MAX_REQUEST: usize = 65536; const DEFAULT_MAX_BYTES_BETWEEN_RESEED: u128 = 1u128 << 20;
44
45#[derive(Zeroize, ZeroizeOnDrop)]
47pub struct HmacDrbg {
48 k: [u8; BLOCK_LEN],
49 v: [u8; BLOCK_LEN],
50 reseed_counter: u64,
51 reseed_interval: u64,
52 generated_bytes: u128,
53 max_bytes_between_reseed: u128,
54 last_entropy: Vec<u8>,
55}
56
57impl HmacDrbg {
58 pub fn new(
60 entropy: &[u8],
61 nonce: &[u8],
62 personalization: Option<&[u8]>,
63 ) -> Result<Self, Error> {
64 Self::validate_entropy(entropy)?;
65
66 let mut seed = Vec::with_capacity(
67 entropy.len() + nonce.len() + personalization.map_or(0, |p| p.len()),
68 );
69 seed.extend_from_slice(entropy);
70 seed.extend_from_slice(nonce);
71 if let Some(pers) = personalization {
72 seed.extend_from_slice(pers);
73 }
74
75 let mut drbg = Self {
76 k: [0u8; BLOCK_LEN],
77 v: [0x01u8; BLOCK_LEN],
78 reseed_counter: 1,
79 reseed_interval: DEFAULT_RESEED_INTERVAL,
80 generated_bytes: 0,
81 max_bytes_between_reseed: DEFAULT_MAX_BYTES_BETWEEN_RESEED,
82 last_entropy: entropy.to_vec(),
83 };
84 drbg.update(Some(&seed));
85 seed.zeroize();
86 Ok(drbg)
87 }
88
89 pub fn from_os(personalization: Option<&[u8]>) -> Result<Self, Error> {
91 let mut entropy = [0u8; 48];
92 let mut nonce = [0u8; 16];
93 getrandom(&mut entropy).map_err(|_| Error::EntropyUnavailable)?;
94 getrandom(&mut nonce).map_err(|_| Error::EntropyUnavailable)?;
95 Self::validate_entropy(&nonce)?;
96 let drbg = Self::new(&entropy, &nonce, personalization)?;
97 entropy.zeroize();
98 nonce.zeroize();
99 Ok(drbg)
100 }
101
102 pub fn set_reseed_interval(&mut self, interval: u64) {
104 self.reseed_interval = interval.max(1);
105 }
106
107 pub fn set_max_bytes_between_reseed(&mut self, max_bytes: u128) {
109 self.max_bytes_between_reseed = max_bytes.max(1);
110 }
111
112 pub fn reseed(&mut self, entropy: &[u8], additional_input: Option<&[u8]>) -> Result<(), Error> {
114 self.check_new_entropy(entropy)?;
115 let mut seed = Vec::with_capacity(entropy.len() + additional_input.map_or(0, |a| a.len()));
116 seed.extend_from_slice(entropy);
117 if let Some(ai) = additional_input {
118 seed.extend_from_slice(ai);
119 }
120 self.update(Some(&seed));
121 seed.zeroize();
122 self.last_entropy.clear();
123 self.last_entropy.extend_from_slice(entropy);
124 self.reseed_counter = 1;
125 self.generated_bytes = 0;
126 Ok(())
127 }
128
129 pub fn generate(
131 &mut self,
132 out: &mut [u8],
133 additional_input: Option<&[u8]>,
134 ) -> Result<(), Error> {
135 if out.len() > MAX_REQUEST {
136 return Err(Error::RequestTooLarge);
137 }
138 if self.reseed_counter > self.reseed_interval
139 || (self.generated_bytes + (out.len() as u128)) >= self.max_bytes_between_reseed
140 {
141 return Err(Error::ReseedRequired);
142 }
143 if let Some(ai) = additional_input {
144 self.update(Some(ai));
145 }
146 let mut generated = 0usize;
147 while generated < out.len() {
148 let mut mac = Hmac::<Sha512>::new_from_slice(&self.k).expect("hmac key len");
149 mac.update(&self.v);
150 self.v = mac.finalize().into_bytes().into();
151 let take = min(out.len() - generated, BLOCK_LEN);
152 out[generated..generated + take].copy_from_slice(&self.v[..take]);
153 generated += take;
154 }
155 self.update(additional_input);
156 self.reseed_counter = self.reseed_counter.saturating_add(1);
157 self.generated_bytes = self.generated_bytes.saturating_add(out.len() as u128);
158 Ok(())
159 }
160
161 fn update(&mut self, provided_data: Option<&[u8]>) {
162 let zero = [0x00u8];
163 let one = [0x01u8];
164
165 let mut mac = Hmac::<Sha512>::new_from_slice(&self.k).expect("hmac key len");
166 mac.update(&self.v);
167 mac.update(&zero);
168 if let Some(data) = provided_data {
169 mac.update(data);
170 }
171 self.k = mac.finalize().into_bytes().into();
172 let mut mac = Hmac::<Sha512>::new_from_slice(&self.k).expect("hmac key len");
173 mac.update(&self.v);
174 self.v = mac.finalize().into_bytes().into();
175
176 if provided_data.is_some() {
177 let mut mac = Hmac::<Sha512>::new_from_slice(&self.k).expect("hmac key len");
178 mac.update(&self.v);
179 mac.update(&one);
180 if let Some(data) = provided_data {
181 mac.update(data);
182 }
183 self.k = mac.finalize().into_bytes().into();
184 let mut mac = Hmac::<Sha512>::new_from_slice(&self.k).expect("hmac key len");
185 mac.update(&self.v);
186 self.v = mac.finalize().into_bytes().into();
187 }
188 }
189
190 fn validate_entropy(entropy: &[u8]) -> Result<(), Error> {
191 if entropy.len() < 16 {
192 return Err(Error::EntropyHealthFailed);
193 }
194 Ok(())
195 }
196
197 fn check_new_entropy(&self, new_entropy: &[u8]) -> Result<(), Error> {
198 if new_entropy.len() < 16 {
199 return Err(Error::EntropyHealthFailed);
200 }
201 let prefix = &self.last_entropy[..min(16, self.last_entropy.len())];
202 let new_prefix = &new_entropy[..min(16, new_entropy.len())];
203 if bool::from(prefix.ct_eq(new_prefix)) {
204 return Err(Error::EntropyHealthFailed);
205 }
206 Ok(())
207 }
208}
209
210impl ConstantTimeEq for HmacDrbg {
211 fn ct_eq(&self, other: &Self) -> Choice {
212 let mut c = self.k.ct_eq(&other.k) & self.v.ct_eq(&other.v);
213 c &= Choice::from((self.reseed_counter == other.reseed_counter) as u8);
214 c &= Choice::from((self.reseed_interval == other.reseed_interval) as u8);
215 c &= Choice::from((self.generated_bytes == other.generated_bytes) as u8);
216 c &= Choice::from((self.max_bytes_between_reseed == other.max_bytes_between_reseed) as u8);
217 if self.last_entropy.len() != other.last_entropy.len() {
218 return Choice::from(0);
219 }
220 let mut v = Choice::from(1);
221 for (a, b) in self.last_entropy.iter().zip(other.last_entropy.iter()) {
222 v &= Choice::from((*a == *b) as u8);
223 }
224 c & v
225 }
226}
227
228#[cfg(test)]
231mod tests {
232 use super::*;
233
234 fn entropy(seed: u8) -> [u8; 48] {
235 let mut out = [0u8; 48];
236 for (i, byte) in out.iter_mut().enumerate() {
237 *byte = seed.wrapping_add(i as u8);
238 }
239 out
240 }
241
242 fn nonce(seed: u8) -> [u8; 16] {
243 let mut out = [0u8; 16];
244 for (i, byte) in out.iter_mut().enumerate() {
245 *byte = seed.wrapping_add((i * 3) as u8);
246 }
247 out
248 }
249
250 #[test]
251 fn identical_seed_produces_identical_stream() {
252 let mut a = HmacDrbg::new(&entropy(1), &nonce(2), Some(b"p")).unwrap();
253 let mut b = HmacDrbg::new(&entropy(1), &nonce(2), Some(b"p")).unwrap();
254 let mut out_a = [0u8; 96];
255 let mut out_b = [0u8; 96];
256 a.generate(&mut out_a, None).unwrap();
257 b.generate(&mut out_b, None).unwrap();
258 assert_eq!(out_a, out_b);
259 assert!(bool::from(a.ct_eq(&b)));
260 }
261
262 #[test]
263 fn reseed_changes_output() {
264 let mut drbg = HmacDrbg::new(&entropy(3), &nonce(4), None).unwrap();
265 let mut first = [0u8; 64];
266 drbg.generate(&mut first, None).unwrap();
267 drbg.reseed(&entropy(9), None).unwrap();
268 let mut second = [0u8; 64];
269 drbg.generate(&mut second, None).unwrap();
270 assert_ne!(first, second);
271 }
272
273 #[test]
274 fn additional_input_affects_stream() {
275 let mut drbg = HmacDrbg::new(&entropy(5), &nonce(6), None).unwrap();
276 let mut buf1 = [0u8; 64];
277 let mut buf2 = [0u8; 64];
278 drbg.generate(&mut buf1, Some(b"ai1")).unwrap();
279 drbg.generate(&mut buf2, Some(b"ai2")).unwrap();
280 assert_ne!(buf1, buf2);
281 }
282
283 #[test]
284 fn request_too_large_fails() {
285 let mut drbg = HmacDrbg::new(&entropy(7), &nonce(8), None).unwrap();
286 let mut buf = vec![0u8; MAX_REQUEST + 1];
287 assert_eq!(drbg.generate(&mut buf, None), Err(Error::RequestTooLarge));
288 }
289
290 #[test]
291 fn reseed_interval_enforced() {
292 let mut drbg = HmacDrbg::new(&entropy(9), &nonce(10), None).unwrap();
293 drbg.set_reseed_interval(1);
294 let mut buf = [0u8; 32];
295 drbg.generate(&mut buf, None).unwrap();
296 assert_eq!(drbg.generate(&mut buf, None), Err(Error::ReseedRequired));
297 }
298 #[test]
299 fn repeated_entropy_fails_health() {
300 let mut drbg = HmacDrbg::new(&entropy(1), &nonce(2), None).unwrap();
301 assert!(matches!(
302 drbg.reseed(&entropy(1), None),
303 Err(Error::EntropyHealthFailed)
304 ));
305 }
306
307 #[test]
308 fn byte_budget_enforced() {
309 let mut drbg = HmacDrbg::new(&entropy(11), &nonce(12), None).unwrap();
310 drbg.set_max_bytes_between_reseed(64);
311 let mut buf = [0u8; 32];
312 drbg.generate(&mut buf, None).unwrap();
313 assert!(matches!(
314 drbg.generate(&mut buf, None),
315 Err(Error::ReseedRequired)
316 ));
317 }
318}