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