1#![allow(unsafe_op_in_unsafe_fn)]
2
3use super::aes::{encrypt_block, expand_key};
4use crate::{StreamCipher, aes::RoundKeys};
5
6#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
13pub struct Aes128Ctr(pub(crate) AesCtr<11>);
14
15impl Aes128Ctr {
16 #[inline]
20 pub fn new(key: &[u8; 16]) -> Self {
21 Self(AesCtr::<11>::new(key))
22 }
23
24 #[inline]
28 pub fn set_counter(&mut self, counter: &[u8; 16]) {
29 self.0.set_counter(counter)
30 }
31}
32
33impl StreamCipher for Aes128Ctr {
34 #[inline]
35 fn xor_keystream(&mut self, in_out: &mut [u8]) {
36 self.0.xor_keystream(in_out)
37 }
38}
39
40#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
47pub struct Aes256Ctr(pub(crate) AesCtr<15>);
48
49impl Aes256Ctr {
50 #[inline]
54 pub fn new(key: &[u8; 32]) -> Self {
55 Self(AesCtr::<15>::new(key))
56 }
57
58 #[inline]
62 pub fn set_counter(&mut self, counter: &[u8; 16]) {
63 self.0.set_counter(counter)
64 }
65}
66
67impl StreamCipher for Aes256Ctr {
68 #[inline]
69 fn xor_keystream(&mut self, in_out: &mut [u8]) {
70 self.0.xor_keystream(in_out)
71 }
72}
73
74#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
80pub(crate) struct AesCtr<const N: usize> {
81 round_keys: RoundKeys<N>,
82 counter: [u8; 16],
83}
84
85impl AesCtr<11> {
86 pub fn new(key: &[u8; 16]) -> Self {
87 Self::new_inner(key)
88 }
89}
90
91impl AesCtr<15> {
92 pub fn new(key: &[u8; 32]) -> Self {
93 Self::new_inner(key)
94 }
95}
96
97impl<const N: usize> AesCtr<N> {
98 fn new_inner(key: &[u8]) -> Self {
102 const { assert!(N == 11 || N == 15) };
103
104 let round_keys_software = expand_key(key);
105
106 #[cfg(target_arch = "aarch64")]
107 {
108 #[cfg(any(feature = "std", target_feature = "aes"))]
109 use crate::aes::aes_arm64::expand_key_armv8;
110
111 #[cfg(feature = "std")]
112 if std::arch::is_aarch64_feature_detected!("aes") {
113 return AesCtr {
114 round_keys: RoundKeys::Armv8(expand_key_armv8(round_keys_software)),
115 counter: [0u8; 16],
116 };
117 }
118
119 #[cfg(all(not(feature = "std"), target_feature = "aes"))]
120 return AesCtr {
121 round_keys: RoundKeys::Armv8(expand_key_armv8(round_keys_software)),
122 counter: [0u8; 16],
123 };
124 }
125
126 #[cfg(target_arch = "x86_64")]
127 {
128 use crate::aes::aes_amd64::expand_key_x86_64;
129
130 #[cfg(feature = "std")]
131 if std::arch::is_x86_feature_detected!("aes") {
132 return AesCtr {
133 round_keys: RoundKeys::X86_64(expand_key_x86_64(round_keys_software)),
134 counter: [0u8; 16],
135 };
136 }
137
138 #[cfg(all(not(feature = "std"), target_feature = "aes"))]
139 return AesCtr {
140 round_keys: RoundKeys::X86_64(expand_key_x86_64(round_keys_software)),
141 counter: [0u8; 16],
142 };
143 }
144
145 AesCtr {
146 round_keys: RoundKeys::Software(round_keys_software),
147 counter: [0u8; 16],
148 }
149 }
150
151 #[inline]
154 pub(crate) fn from_round_keys(round_keys: RoundKeys<N>) -> Self {
155 const { assert!(N == 11 || N == 15) };
156
157 Self {
158 round_keys,
159 counter: [0u8; 16],
160 }
161 }
162
163 pub(crate) fn xor_keystream(&mut self, in_out: &mut [u8]) {
164 match &self.round_keys {
165 #[cfg(target_arch = "aarch64")]
166 RoundKeys::Armv8(round_keys) => unsafe {
167 use super::aes_ctr_arm64::xor_keystream_armv8;
168 xor_keystream_armv8(round_keys, &mut self.counter, in_out);
169 },
170 #[cfg(target_arch = "x86_64")]
171 RoundKeys::X86_64(round_keys) => unsafe {
172 use super::aes_ctr_amd64::xor_keystream_aesni;
173 xor_keystream_aesni(round_keys, &mut self.counter, in_out);
174 },
175 RoundKeys::Software(round_keys) => xor_keystream_soft(round_keys, &mut self.counter, in_out),
176 }
177 }
178
179 #[inline]
183 pub fn set_counter(&mut self, counter: &[u8; 16]) {
184 self.counter = *counter;
185 }
186}
187
188fn xor_keystream_soft<const N: usize>(round_keys: &[[u8; 16]; N], counter: &mut [u8; 16], in_out: &mut [u8]) {
189 let n = in_out.len();
190 let mut i = 0;
191
192 while i + 16 <= n {
193 let ks = encrypt_block(&round_keys, counter);
194 for k in 0..16 {
195 in_out[i + k] ^= ks[k];
196 }
197 increment_counter(counter);
198 i += 16;
199 }
200
201 if i < n {
202 let ks = encrypt_block(&round_keys, counter);
203 for k in 0..n - i {
204 in_out[i + k] ^= ks[k];
205 }
206 }
207}
208
209#[inline]
210fn increment_counter(counter: &mut [u8; 16]) {
211 let counter_value = u32::from_be_bytes(counter[12..16].try_into().unwrap());
212 counter[12..16].copy_from_slice(&counter_value.wrapping_add(1).to_be_bytes());
213}
214
215#[cfg(test)]
216mod tests {
217 use hex;
218
219 use super::*;
220
221 struct CtrVector {
222 key: &'static str,
223 counter: &'static str,
224 plaintext: &'static str,
225 ciphertext: &'static str,
226 }
227
228 const NIST_CTR_128_VECTORS: &[CtrVector] = &[
232 CtrVector {
233 key: "2b7e151628aed2a6abf7158809cf4f3c",
234 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
235 plaintext: "6bc1bee22e409f96e93d7e117393172a",
236 ciphertext: "874d6191b620e3261bef6864990db6ce",
237 },
238 CtrVector {
239 key: "2b7e151628aed2a6abf7158809cf4f3c",
240 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
241 plaintext: "ae2d8a571e03ac9c9eb76fac45af8e51",
242 ciphertext: "9806f66b7970fdff8617187bb9fffdff",
243 },
244 CtrVector {
245 key: "2b7e151628aed2a6abf7158809cf4f3c",
246 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
247 plaintext: "30c81c46a35ce411e5fbc1191a0a52ef",
248 ciphertext: "5ae4df3edbd5d35e5b4f09020db03eab",
249 },
250 CtrVector {
251 key: "2b7e151628aed2a6abf7158809cf4f3c",
252 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
253 plaintext: "f69f2445df4f9b17ad2b417be66c3710",
254 ciphertext: "1e031dda2fbe03d1792170a0f3009cee",
255 },
256 ];
257
258 const NIST_CTR_256_VECTORS: &[CtrVector] = &[
260 CtrVector {
261 key: "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
262 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
263 plaintext: "6bc1bee22e409f96e93d7e117393172a",
264 ciphertext: "601ec313775789a5b7a7f504bbf3d228",
265 },
266 CtrVector {
267 key: "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
268 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
269 plaintext: "ae2d8a571e03ac9c9eb76fac45af8e51",
270 ciphertext: "f443e3ca4d62b59aca84e990cacaf5c5",
271 },
272 CtrVector {
273 key: "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
274 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
275 plaintext: "30c81c46a35ce411e5fbc1191a0a52ef",
276 ciphertext: "2b0930daa23de94ce87017ba2d84988d",
277 },
278 CtrVector {
279 key: "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
280 counter: "f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
281 plaintext: "f69f2445df4f9b17ad2b417be66c3710",
282 ciphertext: "dfc9c58db67aada613c2dd08457941a6",
283 },
284 ];
285
286 use super::super::aes::expand_key;
287
288 fn run_ctr_vector_128(v: &CtrVector) {
289 let key: [u8; 16] = hex::decode_array::<16>(v.key.as_bytes()).unwrap();
290 let counter: [u8; 16] = hex::decode_array::<16>(v.counter.as_bytes()).unwrap();
291 let pt = hex::decode(v.plaintext).unwrap();
292 let expected_ct = hex::decode(v.ciphertext).unwrap();
293
294 let mut buf = pt.clone();
295 let mut cipher = Aes128Ctr::new(&key);
296 cipher.set_counter(&counter);
297 cipher.xor_keystream(&mut buf);
298 assert_eq!(buf, expected_ct, "AES-128-CTR mismatch for key={}", v.key);
299
300 let mut buf_soft = pt.clone();
301 let mut ctr_soft = counter;
302 let rk: [[u8; 16]; 11] = expand_key::<11>(&key);
303 xor_keystream_soft(&rk, &mut ctr_soft, &mut buf_soft);
304 assert_eq!(buf_soft, expected_ct, "AES-128-CTR soft mismatch for key={}", v.key);
305
306 assert_eq!(buf, buf_soft, "dispatch and soft xor_keystream differ for key={}", v.key);
307 }
308
309 fn run_ctr_vector_256(v: &CtrVector) {
310 let key: [u8; 32] = hex::decode_array::<32>(v.key.as_bytes()).unwrap();
311 let counter: [u8; 16] = hex::decode_array::<16>(v.counter.as_bytes()).unwrap();
312 let pt = hex::decode(v.plaintext).unwrap();
313 let expected_ct = hex::decode(v.ciphertext).unwrap();
314
315 let mut buf = pt.clone();
316 let mut cipher = Aes256Ctr::new(&key);
317 cipher.set_counter(&counter);
318 cipher.xor_keystream(&mut buf);
319 assert_eq!(buf, expected_ct, "AES-256-CTR mismatch for key={}", v.key);
320
321 let mut buf_soft = pt.clone();
322 let mut ctr_soft = counter;
323 let rk: [[u8; 16]; 15] = expand_key::<15>(&key);
324 xor_keystream_soft(&rk, &mut ctr_soft, &mut buf_soft);
325 assert_eq!(buf_soft, expected_ct, "AES-256-CTR soft mismatch for key={}", v.key);
326
327 assert_eq!(buf, buf_soft, "dispatch and soft xor_keystream differ for key={}", v.key);
328 }
329
330 #[test]
331 fn nist_aes128_ctr_vectors() {
332 for v in NIST_CTR_128_VECTORS {
333 run_ctr_vector_128(v);
334 }
335 }
336
337 #[test]
338 fn nist_aes128_ctr_combined_blocks() {
339 let key: [u8; 16] = hex::decode_array::<16>(b"2b7e151628aed2a6abf7158809cf4f3c").unwrap();
341 let counter: [u8; 16] = hex::decode_array::<16>(b"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff").unwrap();
342 let pt = hex::decode(b"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710").unwrap();
343 let expected_ct = hex::decode(b"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee").unwrap();
344
345 let mut buf = pt.clone();
346 let mut cipher = Aes128Ctr::new(&key);
347 cipher.set_counter(&counter);
348 cipher.xor_keystream(&mut buf);
349 assert_eq!(buf, expected_ct);
350
351 let mut buf_soft = pt.clone();
352 let mut ctr_soft = counter;
353 let rk: [[u8; 16]; 11] = expand_key::<11>(&key);
354 xor_keystream_soft(&rk, &mut ctr_soft, &mut buf_soft);
355 assert_eq!(buf_soft, expected_ct, "AES-128-CTR soft multi-block mismatch");
356 assert_eq!(buf, buf_soft, "dispatch and soft xor_keystream differ on multi-block");
357 }
358
359 #[test]
360 fn nist_aes256_ctr_vectors() {
361 for v in NIST_CTR_256_VECTORS {
362 run_ctr_vector_256(v);
363 }
364 }
365
366 #[test]
367 fn nist_aes256_ctr_combined_blocks() {
368 let key: [u8; 32] =
369 hex::decode_array::<32>(b"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4").unwrap();
370 let counter: [u8; 16] = hex::decode_array::<16>(b"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff").unwrap();
371 let pt = hex::decode(b"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710").unwrap();
372 let expected_ct = hex::decode(b"601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6").unwrap();
373
374 let mut buf = pt.clone();
375 let mut cipher = Aes256Ctr::new(&key);
376 cipher.set_counter(&counter);
377 cipher.xor_keystream(&mut buf);
378 assert_eq!(buf, expected_ct);
379
380 let mut buf_soft = pt.clone();
381 let mut ctr_soft = counter;
382 let rk: [[u8; 16]; 15] = expand_key::<15>(&key);
383 xor_keystream_soft(&rk, &mut ctr_soft, &mut buf_soft);
384 assert_eq!(buf_soft, expected_ct, "AES-256-CTR soft multi-block mismatch");
385 assert_eq!(buf, buf_soft, "dispatch and soft xor_keystream differ on multi-block");
386 }
387
388 #[test]
389 fn aes128_ctr_empty_plaintext() {
390 let key = [0xabu8; 16];
391 let counter = [0x01u8; 16];
392 let mut buf: Vec<u8> = vec![];
393 let mut cipher = Aes128Ctr::new(&key);
394 cipher.set_counter(&counter);
395 cipher.xor_keystream(&mut buf);
396 assert!(buf.is_empty());
397 }
398
399 #[test]
400 fn aes128_ctr_partial_block() {
401 let key: [u8; 16] = hex::decode_array::<16>(b"2b7e151628aed2a6abf7158809cf4f3c").unwrap();
402 let counter: [u8; 16] = hex::decode_array::<16>(b"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff").unwrap();
403 let pt = hex::decode(b"6bc1bee22e").unwrap();
405 let expected_ct = hex::decode(b"874d6191b6").unwrap();
406
407 let mut buf = pt.clone();
408 let mut cipher = Aes128Ctr::new(&key);
409 cipher.set_counter(&counter);
410 cipher.xor_keystream(&mut buf);
411 assert_eq!(buf, expected_ct);
412 }
413
414 #[test]
415 fn aes128_ctr_cross_block_boundary() {
416 let key: [u8; 16] = hex::decode_array::<16>(b"2b7e151628aed2a6abf7158809cf4f3c").unwrap();
418 let counter: [u8; 16] = hex::decode_array::<16>(b"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff").unwrap();
419 let pt = hex::decode(b"6bc1bee22e409f96e93d7e117393172aae").unwrap();
421 let expected_ct = hex::decode(b"874d6191b620e3261bef6864990db6ce98").unwrap();
422
423 let mut buf = pt.clone();
424 let mut cipher = Aes128Ctr::new(&key);
425 cipher.set_counter(&counter);
426 cipher.xor_keystream(&mut buf);
427 assert_eq!(buf, expected_ct);
428 }
429
430 #[test]
431 fn aes128_ctr_roundtrip() {
432 let key = [0x42u8; 16];
433 let counter = [0x07u8; 16];
434 let pt: Vec<u8> = (0u8..=255u8).cycle().take(1024).collect();
435
436 let mut buf = pt.clone();
437 let mut cipher = Aes128Ctr::new(&key);
438 cipher.set_counter(&counter);
439 cipher.xor_keystream(&mut buf);
440 let mut cipher2 = Aes128Ctr::new(&key);
442 cipher2.set_counter(&counter);
443 cipher2.xor_keystream(&mut buf);
444 assert_eq!(buf, pt);
445 }
446
447 #[test]
448 fn aes256_ctr_roundtrip() {
449 let key = [0x42u8; 32];
450 let counter = [0x07u8; 16];
451 let pt: Vec<u8> = (0u8..=255u8).cycle().take(1024).collect();
452
453 let mut buf = pt.clone();
454 let mut cipher = Aes256Ctr::new(&key);
455 cipher.set_counter(&counter);
456 cipher.xor_keystream(&mut buf);
457 let mut cipher2 = Aes256Ctr::new(&key);
458 cipher2.set_counter(&counter);
459 cipher2.xor_keystream(&mut buf);
460 assert_eq!(buf, pt);
461 }
462
463 #[test]
464 fn aes128_ctr_zero_key_zero_counter() {
465 let key = [0u8; 16];
466 let counter = [0u8; 16];
467 let pt = [0u8; 16];
468 let expected_keystream: [u8; 16] = hex::decode_array::<16>(b"66e94bd4ef8a2c3b884cfa59ca342b2e").unwrap();
469
470 let mut buf = pt.to_vec();
471 let mut cipher = Aes128Ctr::new(&key);
472 cipher.set_counter(&counter);
473 cipher.xor_keystream(&mut buf);
474 assert_eq!(buf, expected_keystream.to_vec());
475
476 let mut cipher2 = Aes128Ctr::new(&key);
478 cipher2.set_counter(&counter);
479 cipher2.xor_keystream(&mut buf);
480 assert_eq!(buf, pt.to_vec());
481 }
482
483 #[test]
484 fn aes128_ctr_increment_counter() {
485 let mut ctr = [0u8; 16];
486 increment_counter(&mut ctr);
487 assert_eq!(ctr, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
488
489 let mut ctr2 = [0xffu8; 16];
490 increment_counter(&mut ctr2);
491 let expected: [u8; 16] = hex::decode_array::<16>(b"ffffffffffffffffffffffff00000000").unwrap();
492 assert_eq!(ctr2, expected);
493 }
494}