1use crate::drbg::Error;
32use tessera::{Digest, hmac_multi};
33
34const RESEED_INTERVAL: u64 = 1 << 48;
36const MAX_REQUEST_OCTETS: usize = 1 << 16;
38const MAX_OPT_OCTETS: usize = u32::MAX as usize;
40
41const MAX_OUTPUT: usize = 64;
43
44pub struct HmacDrbg<H: Digest> {
47 k: [u8; MAX_OUTPUT],
48 v: [u8; MAX_OUTPUT],
49 reseed_counter: u64,
50 _marker: core::marker::PhantomData<H>,
51}
52
53impl<H: Digest> HmacDrbg<H> {
54 fn update(&mut self, provided_parts: &[&[u8]]) {
66 let outlen = H::OUTPUT_LEN;
67 let has_data = provided_parts.iter().any(|p| !p.is_empty());
68
69 let mut newk = [0u8; MAX_OUTPUT];
71 {
72 let mut parts: [&[u8]; 8] = [&[]; 8];
73 let n = assemble(&mut parts, &self.v[..outlen], 0x00, provided_parts);
74 hmac_multi::<H>(&self.k[..outlen], &parts[..n], &mut newk[..outlen]);
75 }
76 self.k[..outlen].copy_from_slice(&newk[..outlen]);
77 let mut newv = [0u8; MAX_OUTPUT];
79 hmac_multi::<H>(&self.k[..outlen], &[&self.v[..outlen]], &mut newv[..outlen]);
80 self.v[..outlen].copy_from_slice(&newv[..outlen]);
81
82 if !has_data {
83 return;
84 }
85
86 {
88 let mut parts: [&[u8]; 8] = [&[]; 8];
89 let n = assemble(&mut parts, &self.v[..outlen], 0x01, provided_parts);
90 hmac_multi::<H>(&self.k[..outlen], &parts[..n], &mut newk[..outlen]);
91 }
92 self.k[..outlen].copy_from_slice(&newk[..outlen]);
93 hmac_multi::<H>(&self.k[..outlen], &[&self.v[..outlen]], &mut newv[..outlen]);
95 self.v[..outlen].copy_from_slice(&newv[..outlen]);
96 }
97
98 pub fn instantiate(entropy_input: &[u8], nonce: &[u8], personalization: &[u8]) -> Result<Self, Error> {
108 if entropy_input.len() * 8 < security_strength::<H>() {
109 return Err(Error::InsufficientEntropy);
110 }
111 if personalization.len() > MAX_OPT_OCTETS {
112 return Err(Error::PersonalizationTooLong);
113 }
114 let outlen = H::OUTPUT_LEN;
115 let mut s = HmacDrbg::<H> {
116 k: [0x00u8; MAX_OUTPUT],
117 v: [0x01u8; MAX_OUTPUT],
118 reseed_counter: 1,
119 _marker: core::marker::PhantomData,
120 };
121 for i in 0..outlen {
123 s.k[i] = 0x00;
124 s.v[i] = 0x01;
125 }
126 s.update(&[entropy_input, nonce, personalization]);
127 s.reseed_counter = 1;
128 Ok(s)
129 }
130
131 pub fn reseed(&mut self, entropy_input: &[u8], additional_input: &[u8]) -> Result<(), Error> {
139 if entropy_input.len() * 8 < security_strength::<H>() {
140 return Err(Error::InsufficientEntropy);
141 }
142 if additional_input.len() > MAX_OPT_OCTETS {
143 return Err(Error::AdditionalInputTooLong);
144 }
145 self.update(&[entropy_input, additional_input]);
146 self.reseed_counter = 1;
147 Ok(())
148 }
149
150 pub fn generate(&mut self, out: &mut [u8], additional_input: &[u8]) -> Result<(), Error> {
163 if out.len() > MAX_REQUEST_OCTETS {
164 return Err(Error::RequestTooLarge);
165 }
166 if additional_input.len() > MAX_OPT_OCTETS {
167 return Err(Error::AdditionalInputTooLong);
168 }
169 if self.reseed_counter > RESEED_INTERVAL {
170 return Err(Error::ReseedRequired);
171 }
172 let outlen = H::OUTPUT_LEN;
173
174 if !additional_input.is_empty() {
176 self.update(&[additional_input]);
177 }
178
179 let mut off = 0;
181 let mut newv = [0u8; MAX_OUTPUT];
182 while off < out.len() {
183 hmac_multi::<H>(&self.k[..outlen], &[&self.v[..outlen]], &mut newv[..outlen]);
184 self.v[..outlen].copy_from_slice(&newv[..outlen]);
185 let take = core::cmp::min(outlen, out.len() - off);
186 out[off..off + take].copy_from_slice(&self.v[..take]);
187 off += take;
188 }
189
190 self.update(&[additional_input]);
192 self.reseed_counter += 1;
194 Ok(())
195 }
196}
197
198fn assemble<'a>(parts: &mut [&'a [u8]; 8], v: &'a [u8], tag: u8, provided: &[&'a [u8]]) -> usize {
203 parts[0] = v;
204 parts[1] = TAG_BYTES[tag as usize];
205 let mut n = 2;
206 for p in provided {
207 if !p.is_empty() {
208 parts[n] = p;
209 n += 1;
210 }
211 }
212 n
213}
214
215static TAG_BYTES: [&[u8]; 2] = [&[0x00u8], &[0x01u8]];
217
218const fn security_strength<H: Digest>() -> usize {
220 match H::OUTPUT_LEN {
221 20 => 128, 28 => 192, _ => 256, }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use crate::drbg::test_util::hx;
231 use tessera::{Sha256, Sha384, Sha512};
232
233 #[test]
238 fn hmac_sha256_no_reseed_pers0_add0() {
239 let entropy = hx("ca851911349384bffe89de1cbdc46e6831e44d34a4fb935ee285dd14b71a7488");
240 let nonce = hx("659ba96c601dc69fc902940805ec0ca8");
241 let mut drbg = HmacDrbg::<Sha256>::instantiate(&entropy, &nonce, &[]).unwrap();
242 let mut out = [0u8; 128];
243 drbg.generate(&mut out, &[]).unwrap();
244 drbg.generate(&mut out, &[]).unwrap();
245 assert_eq!(
246 out[..],
247 hx(
248 "e528e9abf2dece54d47c7e75e5fe302149f817ea9fb4bee6f4199697d04d5b89d54fbb978a15b5c443c9ec21036d2460\
249 b6f73ebad0dc2aba6e624abf07745bc107694bb7547bb0995f70de25d6b29e2d3011bb19d27676c07162c8b5ccde06689\
250 61df86803482cb37ed6d5c0bb8d50cf1f50d476aa0458bdaba806f48be9dcb8"
251 )[..]
252 );
253 }
254
255 #[test]
259 fn hmac_sha256_pr_true_pers0_add0() {
260 let entropy = hx("9969e54b4703ff31785b879a7e5c0eae0d3e309559e9fe96b0676d49d591ea4d");
261 let nonce = hx("07d20d46d064757d3023cac2376127ab");
262 let pr0 = hx("c60f2999100f738c10f74792676a3fc4a262d13721798046e29a295181569f54");
263 let pr1 = hx("c11d4524c9071bd3096015fcf7bc24a607f22fa065c937658a2a77a8699089f4");
264 let mut drbg = HmacDrbg::<Sha256>::instantiate(&entropy, &nonce, &[]).unwrap();
265 let mut out = [0u8; 128];
266 drbg.reseed(&pr0, &[]).unwrap();
268 drbg.generate(&mut out, &[]).unwrap();
269 drbg.reseed(&pr1, &[]).unwrap();
271 drbg.generate(&mut out, &[]).unwrap();
272 assert_eq!(
273 out[..],
274 hx(
275 "abc015856094803a938dffd20da94843870ef935b82cfec17706b8f551b8385044235dd44b599f94b39be78dd476e0cf\
276 11309c995a7334e0a78b37bc9586235086fa3b637ba91cf8fb65efa22a589c137531aa7b2d4e2607aac27292b01c698e6\
277 e01ae679eb87c01a89c7422d4372d6d754ababb4bf896fcb1cd09d692d0283f"
278 )[..]
279 );
280 }
281
282 #[test]
285 fn hmac_sha256_pr_true_pers_add() {
286 let entropy = hx("4294671d493dc085b5184607d7de2ff2b6aceb734a1b026f6cfee7c5a90f03da");
287 let nonce = hx("d071544e599235d5eb38b64b551d2a6e");
288 let pers = hx("63bc769ae1d95a98bde870e4db7776297041d37c8a5c688d4e024b78d83f4d78");
289 let add0 = hx("28848becd3f47696f124f4b14853a456156f69be583a7d4682cff8d44b39e1d3");
290 let add1 = hx("8bfce0b7132661c3cd78175d83926f643e36f7608eec2c5dac3ddcbacc8c2182");
291 let pr0 = hx("db9b4790b62336fbb9a684b82947065393eeef8f57bd2477141ad17e776dac34");
292 let pr1 = hx("4a9abe80f6f522f29878bedf8245b27940a76471006fb4a4110beb4decb6c341");
293 let mut drbg = HmacDrbg::<Sha256>::instantiate(&entropy, &nonce, &pers).unwrap();
294 let mut out = [0u8; 128];
295 drbg.reseed(&pr0, &add0).unwrap();
299 drbg.generate(&mut out, &[]).unwrap();
300 drbg.reseed(&pr1, &add1).unwrap();
301 drbg.generate(&mut out, &[]).unwrap();
302 assert_eq!(
303 out[..],
304 hx(
305 "e580dc969194b2b18a97478aef9d1a72390aff14562747bf080d741527a6655ce7fc135325b457483a9f9c70f91165a8\
306 11cf4524b50d51199a0df3bd60d12abac27d0bf6618e6b114e05420352e23f3603dfe8a225dc19b3d1fff1dc245dc6b1d\
307 f24c741744bec3f9437dbbf222df84881a457a589e7815ef132f686b760f012"
308 )[..]
309 );
310 }
311
312 #[test]
317 fn hmac_sha384_no_reseed_pers0_add0() {
318 let entropy = hx("a1dc2dfeda4f3a1124e0e75ebfbe5f98cac11018221dda3fdcf8f9125d68447a");
319 let nonce = hx("bae5ea27166540515268a493a96b5187");
320 let mut drbg = HmacDrbg::<Sha384>::instantiate(&entropy, &nonce, &[]).unwrap();
321 let mut out = [0u8; 192];
322 drbg.generate(&mut out, &[]).unwrap();
323 drbg.generate(&mut out, &[]).unwrap();
324 assert_eq!(
325 out[..],
326 hx(
327 "228293e59b1e4545a4ff9f232616fc5108a1128debd0f7c20ace837ca105cbf24c0dac1f9847dafd0d0500721ffad3c6\
328 84a992d110a549a264d14a8911c50be8cd6a7e8fac783ad95b24f64fd8cc4c8b649eac2b15b363e30df79541a6b8a1ca\
329 ac238949b46643694c85e1d5fcbcd9aaae6260acee660b8a79bea48e079ceb6a5eaf4993a82c3f1b758d7c53e3094eea\
330 c63dc255be6dcdcc2b51e5ca45d2b20684a5a8fa5806b96f8461ebf51bc515a7dd8c5475c0e70f2fd0faf7869a99ab6c"
331 )[..]
332 );
333 }
334
335 #[test]
337 fn hmac_sha384_no_reseed_pers_add() {
338 let entropy = hx("c2feb900032f2cca98d3f60536f563d8ac9af5fb2e90dba36c371c0a1c58cf5e");
339 let nonce = hx("4a60f2be0fa13b8266b715be8aad128c");
340 let pers = hx("8e6f9be0c692648072d19c750804b10e2ec313c8013abd363de7a467787859f2");
341 let add0 = hx("72f54ba3f8e71ad69a040bb8493283acfc8815f17dbcea220ecd68372a2dffae");
342 let add1 = hx("adce8157ef60482841dd2ac5ac512bf7649120c1dba81ea75f2a70b7512bb6f3");
343 let mut drbg = HmacDrbg::<Sha384>::instantiate(&entropy, &nonce, &pers).unwrap();
344 let mut out = [0u8; 192];
345 drbg.generate(&mut out, &add0).unwrap();
346 drbg.generate(&mut out, &add1).unwrap();
347 assert_eq!(
348 out[..],
349 hx(
350 "e76e4326ac69ddbc6b2408c529b05a96425c65cc65671601191238e9434d2a0147f3a25ce9b6818774f5263c92459bca\
351 421d2b492f9a9c2971359baaa1426d6e2c36d8924f39d02ee2fb5502c4e0b206dbe9aeeacd508abe6c055d547b5f9f35\
352 de4fdc9c05a2c63ad699a3a7e265598b8f40a8a295d7376b88c49af9edc790b8a5ee221e19877616678e2a5135d7b375\
353 6109200439d9ec8bfe0cc5f3c334ca9c022ab9192d5d554dc7ae76af1dc06d814427f46a7cfa2dcc62f4777d07ebde7d"
354 )[..]
355 );
356 }
357
358 #[test]
360 fn hmac_sha512_no_reseed_pers0_add0() {
361 let entropy = hx("35049f389a33c0ecb1293238fd951f8ffd517dfde06041d32945b3e26914ba15");
362 let nonce = hx("f7328760be6168e6aa9fb54784989a11");
363 let mut drbg = HmacDrbg::<Sha512>::instantiate(&entropy, &nonce, &[]).unwrap();
364 let mut out = [0u8; 256];
365 drbg.generate(&mut out, &[]).unwrap();
366 drbg.generate(&mut out, &[]).unwrap();
367 assert_eq!(
368 out[..],
369 hx(
370 "e76491b0260aacfded01ad39fbf1a66a88284caa5123368a2ad9330ee48335e3c9c9ba90e6cbc9429962d60c1a6661ed\
371 cfaa31d972b8264b9d4562cf18494128a092c17a8da6f3113e8a7edfcd4427082bd390675e9662408144971717303d8d\
372 c352c9e8b95e7f35fa2ac9f549b292bc7c4bc7f01ee0a577859ef6e82d79ef23892d167c140d22aac32b64ccdfeee273\
373 0528a38763b24227f91ac3ffe47fb11538e435307e77481802b0f613f370ffb0dbeab774fe1efbb1a80d01154a9459e7\
374 3ad361108bbc86b0914f095136cbe634555ce0bb263618dc5c367291ce0825518987154fe9ecb052b3f0a256fcc30cc1\
375 4572531c9628973639beda456f2bddf6"
376 )[..]
377 );
378 }
379
380 #[test]
382 fn hmac_sha512_no_reseed_pers_add() {
383 let entropy = hx("e97a4631d0a08d549cde8af9a1aae058e3e9585575a726c76a27bc62bed18a4b");
384 let nonce = hx("227221d5fe5a5db9810f9afe56a3ee78");
385 let pers = hx("94084b11d55e0f9c2ef577741753af66ad7a25b28524b50ea970105c3545e97d");
386 let add0 = hx("24c81d4773938371b906cf4801957ac22f87432b9c8a84bc5ac04ad5b1cc3f57");
387 let add1 = hx("c8c878451e2b76577c36393ca253888c1038885bbfdacd8539615a611e2ac00b");
388 let mut drbg = HmacDrbg::<Sha512>::instantiate(&entropy, &nonce, &pers).unwrap();
389 let mut out = [0u8; 256];
390 drbg.generate(&mut out, &add0).unwrap();
391 drbg.generate(&mut out, &add1).unwrap();
392 assert_eq!(
393 out[..],
394 hx(
395 "761422dea283262998c0ffffefc77de2d395c818b9cf1ac2bcd1153235e0d8b63199c51e195135a75f1f87b454484ecc\
396 560c532c7ba5923c9490a423c177453459d81efc38ce2939226043cb733062eae303a009b48ee0cf3c7e40abe2b57a70\
397 a6062c669a9fbff20b4c94b4ecbc5f744a80d7be8134359581d441da921737b1329470b214f3e679fb7ad48baf046bac\
398 59a36b5770806cdef28cc4a8fd0e049b924c3c9216e00ba63c2ff771d66b7520dd33a85382a84b622717e594e447c919\
399 926a5b2e94d490ee626da9df587fed674067917963fd51d383e55730c17a124555e2e46e1395c9920d07dae4d67ffee5\
400 c759b6a326eec6d7b3ba6dee012e4807"
401 )[..]
402 );
403 }
404
405 #[test]
406 fn hmac_sha256_rejects_short_entropy() {
407 let short = [0u8; 16];
408 assert_eq!(
409 HmacDrbg::<Sha256>::instantiate(&short, &[0u8; 16], &[]).err(),
410 Some(Error::InsufficientEntropy)
411 );
412 }
413}