1use crate::ct::zeroize_slice;
18use crate::{Aes256, BlockCipher, Csprng};
19
20const KEY_LEN: usize = 32;
21const BLOCK_LEN: usize = 16;
22const SEED_LEN: usize = KEY_LEN + BLOCK_LEN;
23const MAX_REQUEST_BYTES: usize = 1 << 16; const RESEED_INTERVAL: u64 = 1 << 48;
25
26#[inline]
27fn increment_be(counter: &mut [u8; BLOCK_LEN]) {
28 for b in counter.iter_mut().rev() {
29 let (next, carry) = b.overflowing_add(1);
30 *b = next;
31 if !carry {
32 break;
33 }
34 }
35}
36
37pub struct CtrDrbgAes256 {
39 key: [u8; KEY_LEN],
40 v: [u8; BLOCK_LEN],
41 reseed_counter: u64,
42}
43
44impl CtrDrbgAes256 {
45 #[must_use]
50 pub fn new(seed_material: &[u8; SEED_LEN]) -> Self {
51 let mut out = Self {
52 key: [0u8; KEY_LEN],
53 v: [0u8; BLOCK_LEN],
54 reseed_counter: 1,
55 };
56 out.update(Some(seed_material));
57 out
58 }
59
60 pub fn new_wiping(seed_material: &mut [u8; SEED_LEN]) -> Self {
66 let out = Self::new(seed_material);
67 zeroize_slice(seed_material.as_mut_slice());
68 out
69 }
70
71 pub fn reseed(&mut self, seed_material: &[u8; SEED_LEN]) {
76 self.update(Some(seed_material));
77 self.reseed_counter = 1;
78 }
79
80 pub fn reseed_wiping(&mut self, seed_material: &mut [u8; SEED_LEN]) {
82 self.reseed(seed_material);
83 zeroize_slice(seed_material.as_mut_slice());
84 }
85
86 pub fn generate(&mut self, out: &mut [u8], additional_input: Option<&[u8; SEED_LEN]>) {
97 assert!(
98 self.reseed_counter <= RESEED_INTERVAL,
99 "CTR_DRBG reseed required"
100 );
101 assert!(out.len() <= MAX_REQUEST_BYTES, "CTR_DRBG request too large");
102
103 if let Some(additional_input) = additional_input {
104 self.update(Some(additional_input));
105 }
106
107 let cipher = Aes256::new(&self.key);
108 let mut offset = 0usize;
109 while offset < out.len() {
110 increment_be(&mut self.v);
111 let mut block = self.v;
112 cipher.encrypt(&mut block);
113 let take = (out.len() - offset).min(BLOCK_LEN);
114 out[offset..offset + take].copy_from_slice(&block[..take]);
115 offset += take;
116 }
117
118 self.update(additional_input);
119 self.reseed_counter += 1;
120 }
121
122 #[must_use]
127 pub fn reseed_counter(&self) -> u64 {
128 self.reseed_counter
129 }
130
131 fn update(&mut self, provided_data: Option<&[u8; SEED_LEN]>) {
132 let cipher = Aes256::new(&self.key);
137 let mut temp = [0u8; SEED_LEN];
138 let mut offset = 0usize;
139
140 while offset < SEED_LEN {
141 increment_be(&mut self.v);
142 let mut block = self.v;
143 cipher.encrypt(&mut block);
144 temp[offset..offset + BLOCK_LEN].copy_from_slice(&block);
145 offset += BLOCK_LEN;
146 }
147
148 if let Some(data) = provided_data {
149 for (t, d) in temp.iter_mut().zip(data.iter()) {
150 *t ^= *d;
151 }
152 }
153
154 self.key.copy_from_slice(&temp[..KEY_LEN]);
155 self.v.copy_from_slice(&temp[KEY_LEN..]);
156 zeroize_slice(temp.as_mut_slice());
157 }
158}
159
160impl Csprng for CtrDrbgAes256 {
161 fn fill_bytes(&mut self, out: &mut [u8]) {
162 self.generate(out, None);
163 }
164}
165
166impl Drop for CtrDrbgAes256 {
167 fn drop(&mut self) {
168 zeroize_slice(self.key.as_mut_slice());
169 zeroize_slice(self.v.as_mut_slice());
170 self.reseed_counter = 0;
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn same_seed_same_stream() {
180 let seed = core::array::from_fn::<u8, SEED_LEN, _>(|i| {
181 u8::try_from(i).expect("seed byte index fits in u8")
182 });
183 let mut a = CtrDrbgAes256::new(&seed);
184 let mut b = CtrDrbgAes256::new(&seed);
185
186 let mut out_a = [0u8; 64];
187 let mut out_b = [0u8; 64];
188 a.fill_bytes(&mut out_a);
189 b.fill_bytes(&mut out_b);
190
191 assert_eq!(out_a, out_b);
192 }
193
194 #[test]
195 fn additional_input_changes_stream() {
196 let seed = core::array::from_fn::<u8, SEED_LEN, _>(|i| {
197 u8::try_from(i).expect("seed byte index fits in u8")
198 });
199 let add = core::array::from_fn::<u8, SEED_LEN, _>(|i| {
200 u8::try_from(255usize - i).expect("masked additional-input byte fits in u8")
201 });
202
203 let mut plain = CtrDrbgAes256::new(&seed);
204 let mut mixed = CtrDrbgAes256::new(&seed);
205
206 let mut out_plain = [0u8; 32];
207 let mut out_mixed = [0u8; 32];
208 plain.generate(&mut out_plain, None);
209 mixed.generate(&mut out_mixed, Some(&add));
210
211 assert_ne!(out_plain, out_mixed);
212 }
213
214 #[test]
215 fn nist_cavs_count0_no_df_kat() {
216 let seed = [
217 0xdf, 0x5d, 0x73, 0xfa, 0xa4, 0x68, 0x64, 0x9e, 0xdd, 0xa3, 0x3b, 0x5c, 0xca, 0x79,
218 0xb0, 0xb0, 0x56, 0x00, 0x41, 0x9c, 0xcb, 0x7a, 0x87, 0x9d, 0xdf, 0xec, 0x9d, 0xb3,
219 0x2e, 0xe4, 0x94, 0xe5, 0x53, 0x1b, 0x51, 0xde, 0x16, 0xa3, 0x0f, 0x76, 0x92, 0x62,
220 0x47, 0x4c, 0x73, 0xbe, 0xc0, 0x10,
221 ];
222 let mut drbg = CtrDrbgAes256::new(&seed);
223 let mut discard = [0u8; 64];
224 drbg.fill_bytes(&mut discard);
225 let mut out = [0u8; 64];
226 drbg.fill_bytes(&mut out);
227
228 assert_eq!(
229 out,
230 [
231 0xd1, 0xc0, 0x7c, 0xd9, 0x5a, 0xf8, 0xa7, 0xf1, 0x10, 0x12, 0xc8, 0x4c, 0xe4, 0x8b,
232 0xb8, 0xcb, 0x87, 0x18, 0x9e, 0x99, 0xd4, 0x0f, 0xcc, 0xb1, 0x77, 0x1c, 0x61, 0x9b,
233 0xdf, 0x82, 0xab, 0x22, 0x80, 0xb1, 0xdc, 0x2f, 0x25, 0x81, 0xf3, 0x91, 0x64, 0xf7,
234 0xac, 0x0c, 0x51, 0x04, 0x94, 0xb3, 0xa4, 0x3c, 0x41, 0xb7, 0xdb, 0x17, 0x51, 0x4c,
235 0x87, 0xb1, 0x07, 0xae, 0x79, 0x3e, 0x01, 0xc5,
236 ]
237 );
238 }
239}