1use crate::drbg::Error;
33use crate::drbg::util::{ct_add_into, ct_add_u64};
34use tessera::Digest;
35
36const RESEED_INTERVAL: u64 = 1 << 48;
38const MAX_REQUEST_OCTETS: usize = 1 << 16;
40const MAX_OPT_OCTETS: usize = u32::MAX as usize;
44
45const MAX_SEEDLEN: usize = 111;
47const MAX_OUTPUT: usize = 64;
49
50const fn seedlen_octets<H: Digest>() -> usize {
53 if H::OUTPUT_LEN <= 32 { 55 } else { 111 }
54}
55
56fn hash_df<H: Digest>(input_parts: &[&[u8]], out: &mut [u8]) {
71 let outlen = H::OUTPUT_LEN;
72 let no_of_bits = (out.len() as u32) * 8;
73 let no_of_bits_be = no_of_bits.to_be_bytes();
74 let mut counter: u8 = 1;
75 let mut off = 0;
76 let mut block = [0u8; MAX_OUTPUT];
77 while off < out.len() {
78 let mut h = H::new();
79 h.update(&[counter]);
80 h.update(&no_of_bits_be);
81 for p in input_parts {
82 h.update(p);
83 }
84 h.finalize(&mut block[..outlen]);
85 let take = core::cmp::min(outlen, out.len() - off);
86 out[off..off + take].copy_from_slice(&block[..take]);
87 off += take;
88 counter = counter.wrapping_add(1);
89 }
90}
91
92pub struct HashDrbg<H: Digest> {
97 v: [u8; MAX_SEEDLEN],
98 c: [u8; MAX_SEEDLEN],
99 reseed_counter: u64,
100 seedlen: usize,
101 _marker: core::marker::PhantomData<H>,
102}
103
104impl<H: Digest> HashDrbg<H> {
105 pub fn instantiate(entropy_input: &[u8], nonce: &[u8], personalization: &[u8]) -> Result<Self, Error> {
120 let sec_strength_bits = security_strength::<H>();
121 if entropy_input.len() * 8 < sec_strength_bits {
122 return Err(Error::InsufficientEntropy);
123 }
124 if personalization.len() > MAX_OPT_OCTETS {
125 return Err(Error::PersonalizationTooLong);
126 }
127 let seedlen = seedlen_octets::<H>();
128 let mut s = HashDrbg::<H> {
129 v: [0u8; MAX_SEEDLEN],
130 c: [0u8; MAX_SEEDLEN],
131 reseed_counter: 1,
132 seedlen,
133 _marker: core::marker::PhantomData,
134 };
135 hash_df::<H>(&[entropy_input, nonce, personalization], &mut s.v[..seedlen]);
137 let mut newc = [0u8; MAX_SEEDLEN];
139 hash_df::<H>(&[&[0x00u8], &s.v[..seedlen]], &mut newc[..seedlen]);
140 s.c[..seedlen].copy_from_slice(&newc[..seedlen]);
141 s.reseed_counter = 1;
142 Ok(s)
143 }
144
145 pub fn reseed(&mut self, entropy_input: &[u8], additional_input: &[u8]) -> Result<(), Error> {
154 let sec_strength_bits = security_strength::<H>();
155 if entropy_input.len() * 8 < sec_strength_bits {
156 return Err(Error::InsufficientEntropy);
157 }
158 if additional_input.len() > MAX_OPT_OCTETS {
159 return Err(Error::AdditionalInputTooLong);
160 }
161 let seedlen = self.seedlen;
162 let old_v = self.v; hash_df::<H>(
165 &[&[0x01u8], &old_v[..seedlen], entropy_input, additional_input],
166 &mut self.v[..seedlen],
167 );
168 let mut newc = [0u8; MAX_SEEDLEN];
170 hash_df::<H>(&[&[0x00u8], &self.v[..seedlen]], &mut newc[..seedlen]);
171 self.c[..seedlen].copy_from_slice(&newc[..seedlen]);
172 self.reseed_counter = 1;
173 Ok(())
174 }
175
176 pub fn generate(&mut self, out: &mut [u8], additional_input: &[u8]) -> Result<(), Error> {
191 if out.len() > MAX_REQUEST_OCTETS {
192 return Err(Error::RequestTooLarge);
193 }
194 if additional_input.len() > MAX_OPT_OCTETS {
195 return Err(Error::AdditionalInputTooLong);
196 }
197 if self.reseed_counter > RESEED_INTERVAL {
199 return Err(Error::ReseedRequired);
200 }
201 let seedlen = self.seedlen;
202 let outlen = H::OUTPUT_LEN;
203
204 if !additional_input.is_empty() {
206 let mut w = [0u8; MAX_OUTPUT];
207 let mut h = H::new();
208 h.update(&[0x02u8]);
209 h.update(&self.v[..seedlen]);
210 h.update(additional_input);
211 h.finalize(&mut w[..outlen]);
212 ct_add_into(&mut self.v[..seedlen], &w[..outlen]);
213 }
214
215 self.hashgen(out);
217
218 let mut hbuf = [0u8; MAX_OUTPUT];
220 let mut h = H::new();
221 h.update(&[0x03u8]);
222 h.update(&self.v[..seedlen]);
223 h.finalize(&mut hbuf[..outlen]);
224 ct_add_into(&mut self.v[..seedlen], &hbuf[..outlen]);
225 let c_copy = self.c;
226 ct_add_into(&mut self.v[..seedlen], &c_copy[..seedlen]);
227 ct_add_u64(&mut self.v[..seedlen], self.reseed_counter);
228
229 self.reseed_counter += 1;
231 Ok(())
232 }
233
234 fn hashgen(&self, out: &mut [u8]) {
245 let seedlen = self.seedlen;
246 let outlen = H::OUTPUT_LEN;
247 let mut data = [0u8; MAX_SEEDLEN];
248 data[..seedlen].copy_from_slice(&self.v[..seedlen]);
249 let mut off = 0;
250 let mut w = [0u8; MAX_OUTPUT];
251 while off < out.len() {
252 let mut h = H::new();
253 h.update(&data[..seedlen]);
254 h.finalize(&mut w[..outlen]);
255 let take = core::cmp::min(outlen, out.len() - off);
256 out[off..off + take].copy_from_slice(&w[..take]);
257 off += take;
258 crate::drbg::util::ct_increment(&mut data[..seedlen]);
260 }
261 }
262}
263
264const fn security_strength<H: Digest>() -> usize {
269 match H::OUTPUT_LEN {
270 20 => 128, 28 => 192, _ => 256, }
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279 use crate::drbg::test_util::hx;
280 use tessera::{Sha256, Sha384, Sha512};
281
282 #[test]
293 fn hash_sha256_no_reseed_pers0_add0() {
294 let entropy = hx("a65ad0f345db4e0effe875c3a2e71f42c7129d620ff5c119a9ef55f05185e0fb");
295 let nonce = hx("8581f9317517276e06e9607ddbcbcc2e");
296 let mut drbg = HashDrbg::<Sha256>::instantiate(&entropy, &nonce, &[]).unwrap();
297 let mut out = [0u8; 128];
298 drbg.generate(&mut out, &[]).unwrap(); drbg.generate(&mut out, &[]).unwrap(); assert_eq!(
301 out[..],
302 hx(
303 "d3e160c35b99f340b2628264d1751060e0045da383ff57a57d73a673d2b8d80daaf6a6c35a91bb4579d73fd0c8fed111b\
304 0391306828adfed528f018121b3febdc343e797b87dbb63db1333ded9d1ece177cfa6b71fe8ab1da46624ed6415e51ccd\
305 e2c7ca86e283990eeaeb91120415528b2295910281b02dd431f4c9f70427df"
306 )[..]
307 );
308 }
309
310 #[test]
312 fn hash_sha256_no_reseed_pers_add() {
313 let entropy = hx("68c43a008fe46a823d260a9d7fa388fb9e401f0197e7e758a744b4babb3f4651");
314 let nonce = hx("eb6825777856331884aaf3751b3e4006");
315 let pers = hx("23ce0d32cbf2d26467f0d62acff1a3acbaa6d2746dc3ee7aa9d32c880788afc8");
316 let add0 = hx("a31b9f13b58d4fa2f8d8ac42b62a207ff647339a146bd8b268b33d4aff57adbd");
317 let add1 = hx("d34fc6504eca4b568193c75357b0d3821a48c77ff80d6dbd21c6cf045ff489cf");
318 let mut drbg = HashDrbg::<Sha256>::instantiate(&entropy, &nonce, &pers).unwrap();
319 let mut out = [0u8; 128];
320 drbg.generate(&mut out, &add0).unwrap();
321 drbg.generate(&mut out, &add1).unwrap();
322 assert_eq!(
323 out[..],
324 hx(
325 "abb4ecbacd4e8fa943c7221aed433861c3b203232657ec4c417d021f905d911db1058ff1e11e272232482ec96bae7cb4\
326 efc135502dbe41724077077f6de79b713670c385d04644e1281c3e582e0016255abbe5f8c06d0de57160559f0c08f7fb5\
327 be3563c649966190f8d3261364447537de2c7371c6e8c308933d27145bf90ab"
328 )[..]
329 );
330 }
331
332 #[test]
335 fn hash_sha256_pr_false_reseed_pers0_add0() {
336 let entropy = hx("63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569");
337 let nonce = hx("808aa38f2a72a62359915a9f8a04ca68");
338 let reseed_entropy = hx("e62b8a8ee8f141b6980566e3bfe3c04903dad4ac2cdf9f2280010a6739bc83d3");
339 let mut drbg = HashDrbg::<Sha256>::instantiate(&entropy, &nonce, &[]).unwrap();
340 drbg.reseed(&reseed_entropy, &[]).unwrap();
341 let mut out = [0u8; 128];
342 drbg.generate(&mut out, &[]).unwrap();
343 drbg.generate(&mut out, &[]).unwrap();
344 assert_eq!(
345 out[..],
346 hx(
347 "04eec63bb231df2c630a1afbe724949d005a587851e1aa795e477347c8b056621c18bddcdd8d99fc5fc2b92053d8cfacf\
348 b0bb8831205fad1ddd6c071318a6018f03b73f5ede4d4d071f9de03fd7aea105d9299b8af99aa075bdb4db9aa28c18d17\
349 4b56ee2a014d098896ff2282c955a81969e069fa8ce007a180183a07dfae17"
350 )[..]
351 );
352 }
353
354 #[test]
356 fn hash_sha256_pr_false_reseed_pers_add() {
357 let entropy = hx("6c623aea73bc8a59e28c6cd9c7c7ec8ca2e75190bd5dcae5978cf0c199c23f4f");
358 let nonce = hx("e55db067a0ed537e66886b7cda02f772");
359 let pers = hx("1e59d798810083d1ff848e90b25c9927e3dfb55a0888b0339566a9f9ca7542dc");
360 let reseed_entropy = hx("9ab40164744c7d00c78b4196f6f917ec33d70030a0812cd4606c5a25387568a9");
361 let reseed_add = hx("4e8bead7cbba7a7bc9ae1e1617222c4139661347599950e7225d1e2faa5d57f5");
362 let add0 = hx("dcb22a5d9f149858636f3ede2253e419816fb7b1103194451ed6a573a8fe6271");
363 let add1 = hx("8f9d5c78cdabc32e71ac3b3c49239caddf96053250f4fd92056efbd0be487d36");
364 let mut drbg = HashDrbg::<Sha256>::instantiate(&entropy, &nonce, &pers).unwrap();
365 drbg.reseed(&reseed_entropy, &reseed_add).unwrap();
366 let mut out = [0u8; 128];
367 drbg.generate(&mut out, &add0).unwrap();
368 drbg.generate(&mut out, &add1).unwrap();
369 assert_eq!(
370 out[..],
371 hx(
372 "6e98a3b1f686f6ffa79355c9d8a5ab7f93312159d52659a2298315f10007c71adabc0b5ccb4164c0949fbdb221b43acd\
373 b62bed3099596f2d7bd5d0048173dd2360a543b234ab61a441ddb9299af84ca45c6e618fd521366dbf509d4ec06174da9\
374 24361d642b107e5564ac1b32340dd2f3158bf4c00bcb4dcf12c6d67af4b74ee"
375 )[..]
376 );
377 }
378
379 #[test]
384 fn hash_sha384_no_reseed_pers0_add0() {
385 let entropy = hx("9ef0b00381d6c8c54d08fcadc6f5ef331134bb986373f65c6a14f553bcb6c55d");
386 let nonce = hx("9fce26ada7b1de39590312bd9d81c4f5");
387 let mut drbg = HashDrbg::<Sha384>::instantiate(&entropy, &nonce, &[]).unwrap();
388 let mut out = [0u8; 192];
389 drbg.generate(&mut out, &[]).unwrap();
390 drbg.generate(&mut out, &[]).unwrap();
391 assert_eq!(
392 out[..],
393 hx(
394 "663ffb625e62c4eb67d7177a6abb808a9f68c2d5840f19992c11ea3a635d05b537fae1f1746c1314e1a75e141c2e0941\
395 87d17b9daae1442e41d3a0d1fea94d8ef9d840111379a52e6c7ffafa7ee83b244ced129613d5b8bb089e7ea25de1c298\
396 97735cf95695043a648a2ef6fd4aa74ce8328a5550da8ddb51f98adcdc108e455603f6f18f5a50016f3e8ebcb244a16b\
397 c6b6e554a7546153c12f522c75ca5f1017e01da36650e6203f30ed5c3da3b6078736465eecb400eeaaa2c876e37564d8"
398 )[..]
399 );
400 }
401
402 #[test]
404 fn hash_sha384_no_reseed_pers_add() {
405 let entropy = hx("2e154070573312bc5ea0fa00e589b85dd559797a47c7e5ac731fea50531771a1");
406 let nonce = hx("8443504d05af55a2c5091f077b1edf22");
407 let pers = hx("35679c78e75c78bd6eff67b7d62a9fef1fad39a049debd1efb09be9acc62260d");
408 let add0 = hx("f4bf0561b3e91f0eab5a801388b04b43eee57887d43516a1f332c7c503ab53d6");
409 let add1 = hx("77371fdee3485a12e55d5029d70b9536aabbb28ac1ef9ca761633bec9058bc04");
410 let mut drbg = HashDrbg::<Sha384>::instantiate(&entropy, &nonce, &pers).unwrap();
411 let mut out = [0u8; 192];
412 drbg.generate(&mut out, &add0).unwrap();
413 drbg.generate(&mut out, &add1).unwrap();
414 assert_eq!(
415 out[..],
416 hx(
417 "c6a7ee27596c28ed32d6d0a3dc5b7255448c873b2246d2bd5dbecb1a3d32de95ecd780e3e61974a84b374a1c0b32258e\
418 f8dd41371c5af762aaec6555fd1359efa5051f24bfdbadf9be8c101198fbf6fa97ef58c1ab2865a913f1b1e08019bb25\
419 f0e17ff5f7543cc1fd35e7baa042916d12d29ac6a52202082f4224a45932772dec149a34da4b3912c30903b7681e89e1\
420 530c7d8569eef281d165ea99da653df0728c74c809dc4a0ec8b754193ccfef2ab725db8890f84b1aa19bed96ed1c6927"
421 )[..]
422 );
423 }
424
425 #[test]
427 fn hash_sha512_no_reseed_pers0_add0() {
428 let entropy = hx("6b50a7d8f8a55d7a3df8bb40bcc3b722d8708de67fda010b03c4c84d72096f8c");
429 let nonce = hx("3ec649cc6256d9fa31db7a2904aaf025");
430 let mut drbg = HashDrbg::<Sha512>::instantiate(&entropy, &nonce, &[]).unwrap();
431 let mut out = [0u8; 256];
432 drbg.generate(&mut out, &[]).unwrap();
433 drbg.generate(&mut out, &[]).unwrap();
434 assert_eq!(
435 out[..],
436 hx(
437 "95b7f17e9802d3577392c6a9c08083b67dd1292265b5f42d237f1c55bb9b10bfcfd82c77a378b8266a0099143b3c2d64\
438 611eeeb69acdc055957c139e8b190c7a06955f2c797c2778de940396a501f40e91396acf8d7e45ebdbb53bbf8c975230\
439 d2f0ff9106c76119ae498e7fbc03d90f8e4c51627aed5c8d4263d5d2b978873a0de596ee6dc7f7c29e37eee8b34c90dd\
440 1cf6a9ddb22b4cbd086b14b35de93da2d5cb1806698cbd7bbb67bfe3d31fd2d1dbd2a1e058a3eb99d7e51f1a938eed5e\
441 1c1de23a6b4345d3191409f92f39b3670d8dbfb635d8e6a36932d81033d1448d63b403ddf88e121b6e819ac381226c13\
442 21e4b08644f6727c368c5a9f7a4b3ee2"
443 )[..]
444 );
445 }
446
447 #[test]
449 fn hash_sha512_no_reseed_pers_add() {
450 let entropy = hx("31e8d6fbdc9026b0708405c20b558fcc0a107f3fdc836fe056f020df30d9dc57");
451 let nonce = hx("2b8bbab9b486abb659c4ae8ff5978e22");
452 let pers = hx("949eb753762869aa5ea0ce725523595f9bc9b219735113e71feab228d0872c38");
453 let add0 = hx("88f1180d4ef564315280a9692f107ed9c0639d79bb7040dfc3b7d58bf24ef8f5");
454 let add1 = hx("f4fc8a26e0ad181838f1399fe5b8a4b86670e92ab92b2c4daf3913470724d3f2");
455 let mut drbg = HashDrbg::<Sha512>::instantiate(&entropy, &nonce, &pers).unwrap();
456 let mut out = [0u8; 256];
457 drbg.generate(&mut out, &add0).unwrap();
458 drbg.generate(&mut out, &add1).unwrap();
459 assert_eq!(
460 out[..],
461 hx(
462 "10509641332a4d72a3c5936512c37cb9ab9874693902ee4c76e963675627ef86aa2e7d7029a152b800072fc53eeb6b41\
463 d12f481cde99b467dac3486836f6e146e9a79d3fb90d9b26f213ddbfac590ca083ed83fde4924395d25b645b96a6983e\
464 65fd662cae66112ebfa990f09b86b01270b7f0ef35f183eb01ffcbd7d5ec6adc4839cf3814dac858e013c6d79528ef27\
465 3dd83724ccdc82b73dc63698fcf8ef0924f27b6a49d6d38f0ce261aa5a0a88779e47a413c29e1d7d20e4ab914bbabd5e\
466 6e0241cf53263a8efa321b4a632eb062b255c0ce5a0833114161dd073dd037967a1f03daf2dd7e927b801b40e62f26c08\
467 72ea100132807650232126aa8f29d70"
468 )[..]
469 );
470 }
471
472 #[test]
474 fn hash_sha256_rejects_short_entropy() {
475 let short = [0u8; 16]; assert_eq!(
477 HashDrbg::<Sha256>::instantiate(&short, &[0u8; 16], &[]).err(),
478 Some(Error::InsufficientEntropy)
479 );
480 }
481}