wolf_crypto/aes/ctr.rs
1use core::ptr::{addr_of_mut};
2use wolf_crypto_sys::{Aes as AesLL, wc_AesCtrEncrypt, wc_AesSetKey, wc_AesFree};
3use crate::aes::{Key, init_aes, AesM};
4use crate::ptr::{ConstPtr};
5use core::ffi::c_int;
6use crate::buf::Iv;
7use crate::opaque_res::Res;
8use core::mem::MaybeUninit;
9
10#[must_use]
11#[cfg_attr(not(debug_assertions), inline(always))]
12pub(crate) unsafe fn init_aes_ctr(
13 aes: *mut AesLL, key: ConstPtr<Key>, iv: ConstPtr<Iv>, mode: AesM
14) -> c_int {
15 wc_AesSetKey(
16 aes,
17 key.as_slice().as_ptr(),
18 key.capacity() as u32,
19 iv.slice().as_ptr(),
20 mode.mode() as c_int
21 )
22}
23
24#[inline]
25pub(crate) unsafe fn create_aes_ctr(
26 key: ConstPtr<Key>, iv: ConstPtr<Iv>, mode: AesM
27) -> (MaybeUninit<AesLL>, Res) {
28 let (mut aes, mut res) = init_aes(MaybeUninit::<AesLL>::uninit());
29
30 // NOTE: It looks as though the `wc_AesSetKey` can handle `wc_AesInit` failing from this
31 // example:
32 // https://www.wolfssl.com/documentation/manuals/wolfssl/group__AES.html#function-wc_aessetkey
33 // This requires testing to back up this assumption.
34
35 res.ensure_0(init_aes_ctr(aes.as_mut_ptr(), key, iv, mode));
36
37 (aes, res)
38}
39
40#[inline]
41#[must_use]
42const fn size_predicate(len: usize) -> bool {
43 len <= (u32::MAX as usize)
44}
45
46#[inline]
47#[must_use]
48const fn larger(left: usize, right: usize) -> usize {
49 if left < right {
50 right
51 } else {
52 left
53 }
54}
55
56#[inline]
57#[must_use]
58const fn predicate(input_len: usize, output_len: usize) -> bool {
59 let larger = larger(input_len, output_len);
60 input_len <= output_len && size_predicate(larger)
61}
62
63macro_rules! impl_aes_api {
64 (
65 $(#[$ll_meta:meta])*
66 unsafe => $ll_ident:ident,
67 $(#[$sized_meta:meta])*
68 sized => $sized_ident:ident,
69 $(#[$try_meta:meta])*
70 try => $try_ident:ident,
71 $(#[$panics_meta:meta])*
72 panics => $panics_ident:ident $(,)?
73 ) => {
74 $(#[$sized_meta])*
75 #[inline]
76 pub fn $sized_ident<const S: usize>(
77 &mut self, input: &[u8; S], output: &mut [u8; S]
78 ) -> Res {
79 if !size_predicate(S) {
80 return Res::ERR
81 }
82 unsafe {
83 // SAFETY: Output size is guaranteed from type system to be at least the size
84 // (or in this case equivalent) of the input.
85 self.$ll_ident(input.as_slice(), output.as_mut_slice())
86 }
87 }
88
89 $(#[$try_meta])*
90 #[inline]
91 pub fn $try_ident(&mut self, input: &[u8], output: &mut [u8]) -> Res {
92 if !predicate(input.len(), output.len()) {
93 return Res::ERR
94 }
95
96 unsafe {
97 // SAFETY: `Self::predicate` ensures output is at least the size of input and
98 // that the size does not overflow on u32 cast.
99 self.$ll_ident(input, output)
100 }
101 }
102
103 panic_api! {
104 $(#[$panics_meta])*
105 pub fn $panics_ident(&mut self, input: &[u8], output: &mut [u8]) {
106 if self.$try_ident(input, output).is_err() {
107 panic!("Failed to apply keystream");
108 }
109 }
110 }
111
112 $(#[$ll_meta])*
113 pub unsafe fn $ll_ident(&mut self, input: &[u8], output: &mut [u8]) -> Res {
114 let mut res = Res::new();
115
116 res.ensure_0(wc_AesCtrEncrypt(
117 addr_of_mut!(self.inner),
118 output.as_mut_ptr(),
119 input.as_ptr(),
120 input.len() as u32
121 ));
122
123 res
124 }
125 };
126}
127
128macro_rules! impl_aes_type {
129 (
130 $(#[$struct_meta:meta])*
131 struct $s_ident:ident,
132 direction $dir:ident,
133 api {
134 $(#[$new_meta:meta])*
135 $new_vis:vis new,
136 $(#[$ll_meta:meta])*
137 unsafe => $ll_ident:ident,
138 $(#[$sized_meta:meta])*
139 sized => $sized_ident:ident,
140 $(#[$try_meta:meta])*
141 try => $try_ident:ident,
142 $(#[$panics_meta:meta])*
143 panics => $panics_ident:ident $(,)?
144 }
145 ) => {
146 $(#[$struct_meta])*
147 #[repr(transparent)]
148 pub struct $s_ident {
149 inner: AesLL,
150 }
151
152 impl $s_ident {
153 $(#[$new_meta])*
154 $new_vis fn new(key: &Key, iv: &Iv) -> Result<Self, $crate::error::Unspecified> {
155 let key_ptr = ConstPtr::new(::core::ptr::from_ref(key));
156 let nonce_ptr = ConstPtr::new(::core::ptr::from_ref(iv));
157
158 unsafe {
159 let (aes_ll, res) = create_aes_ctr(key_ptr, nonce_ptr, AesM::$dir);
160 res.unit_err_with(|| Self { inner: aes_ll.assume_init() })
161 }
162 }
163
164 impl_aes_api! {
165 $(#[$ll_meta])*
166 unsafe => $ll_ident,
167 $(#[$sized_meta])*
168 sized => $sized_ident,
169 $(#[$try_meta])*
170 try => $try_ident,
171 $(#[$panics_meta])*
172 panics => $panics_ident
173 }
174 }
175
176 impl Drop for $s_ident {
177 #[inline]
178 fn drop(&mut self) {
179 unsafe {
180 // SAFETY:
181 //
182 // We are in the drop implementation, so we are never going to be using the
183 // `Aes` type again. Since we are configured to not malloc, this simply zeroes
184 // the secrets that were copied on `wc_AesSetKey` invocation. I wish there
185 // was a way to avoid the copying as I do not like secrets living in memory
186 // more than once, but I understand the decision to do this for ensuring safety.
187 wc_AesFree(addr_of_mut!(self.inner));
188 }
189 }
190 }
191 };
192}
193
194impl_aes_type! {
195 /// Represents an AES-CTR (Counter Mode) instance.
196 struct AesCtr,
197 direction ENCRYPT,
198 api {
199 /// Create a new AES CTR instance.
200 ///
201 /// # Arguments
202 ///
203 /// * `key` - The key material to use (which determines the number of rounds).
204 /// * `iv` - The initialization vector (nonce).
205 ///
206 /// # Returns
207 ///
208 /// A new AES instance in CTR mode.
209 ///
210 /// # Note
211 ///
212 /// This copies the key and nonce in the underlying C code and is out of scope of this Rust
213 /// API. At the end of the `AesCtr`'s lifetime these will be zeroed. It may be desirable
214 /// to immediately zero the key and nonce passed to this function by reference post
215 /// invocation.
216 pub new,
217
218 /// Apply the underlying keystream to the output buffer.
219 ///
220 /// This method performs no runtime safety checks.
221 ///
222 /// # Safety
223 ///
224 /// - The `output` buffer must be at least the size of the `input`.
225 /// - The size of both buffers must be representable by an `unsigned int` (u32).
226 ///
227 /// # Arguments
228 ///
229 /// * `input` - The input to apply the keystream to.
230 /// * `output` - The output buffer to store the result of applying the keystream.
231 ///
232 /// # Errors
233 ///
234 /// If the application of the keystream failed.
235 ///
236 /// # Example
237 ///
238 /// ```
239 /// use wolf_crypto::{buf::Iv, aes::{Key, AesCtr}};
240 ///
241 /// // securely generate a random key and initialization vector ...
242 /// # let mut key = Key::Aes256([1u8; 32]);
243 /// # let iv = Iv::new([2u8; 16]);
244 ///
245 /// let mut input = [1u8; 32];
246 /// let mut output = [0u8; 32];
247 ///
248 /// # unsafe {
249 /// assert!(AesCtr::new(&key, &iv)
250 /// .unwrap()
251 /// .apply_keystream_unchecked(input.as_slice(), output.as_mut_slice())
252 /// .is_ok());
253 /// # }
254 ///
255 /// assert_ne!(&output, &input);
256 ///
257 /// // and decrypt
258 ///
259 /// let mut original = [0u8; 32];
260 /// # unsafe {
261 /// assert!(AesCtr::new(&key, &iv)
262 /// .unwrap()
263 /// .apply_keystream_unchecked(output.as_slice(), original.as_mut_slice())
264 /// .is_ok());
265 /// # }
266 ///
267 /// assert_eq!(&original, &input);
268 ///
269 /// key.zero();
270 /// ```
271 unsafe => apply_keystream_unchecked,
272
273 /// Apply the underlying keystream to the output buffer, with the size of both the input and
274 /// output buffers described at compile time to avoid most runtime checks.
275 ///
276 /// # Arguments
277 ///
278 /// * `input` - The input to apply the keystream to.
279 /// * `output` - The output buffer to store the result of applying the keystream.
280 ///
281 /// # Errors
282 ///
283 /// - If the application of the keystream failed.
284 /// - (Unlikely) If the size of the input and output buffer is greater than what can be
285 /// represented by an `unsigned int` (u32).
286 ///
287 /// # Example
288 ///
289 /// ```
290 /// use wolf_crypto::{buf::Iv, aes::{Key, AesCtr}};
291 /// // securely generate a random key and initialization vector ...
292 /// # let mut key = Key::Aes256([1u8; 32]);
293 /// # let iv = Iv::new([2u8; 16]);
294 ///
295 /// let mut input = [1u8; 32];
296 /// let mut output = [0u8; 32];
297 ///
298 /// assert!(AesCtr::new(&key, &iv)
299 /// .unwrap()
300 /// .apply_keystream_sized(&input, &mut output)
301 /// .is_ok());
302 ///
303 /// assert_ne!(&input, &output);
304 /// assert_ne!(output, [0u8; 32]);
305 ///
306 /// // and decrypt
307 ///
308 /// let mut plain = [0u8; 32];
309 /// assert!(AesCtr::new(&key, &iv)
310 /// .unwrap()
311 /// .apply_keystream_sized(&output, &mut plain)
312 /// .is_ok());
313 ///
314 /// assert_eq!(&plain, &input);
315 /// key.zero();
316 /// ```
317 sized => apply_keystream_sized,
318
319 /// Try to apply the underlying keystream to the output buffer.
320 ///
321 /// # Arguments
322 ///
323 /// * `input` - The input to apply the keystream to.
324 /// * `output` - The output buffer to store the result of applying the keystream.
325 ///
326 /// # Errors
327 ///
328 /// - If the application of the keystream failed.
329 /// - If the `input` buffer is larger than the `output` buffer.
330 /// - (Unlikely) If the size of the `input` or `output` buffer is greater than what can be
331 /// represented by an `unsigned int` (u32).
332 ///
333 /// # Example
334 ///
335 /// ```
336 /// use wolf_crypto::{buf::Iv, aes::{Key, AesCtr}};
337 /// // securely generate a random key and initialization vector ...
338 /// # let mut key = Key::Aes256([1u8; 32]);
339 /// # let iv = Iv::new([2u8; 16]);
340 ///
341 /// let mut input = [1u8; 32];
342 /// let mut output = [0u8; 32];
343 ///
344 /// assert!(AesCtr::new(&key, &iv)
345 /// .unwrap()
346 /// .try_apply_keystream(input.as_slice(), output.as_mut_slice())
347 /// .is_ok());
348 ///
349 /// assert_ne!(&input, &output);
350 /// assert_ne!(output, [0u8; 32]);
351 ///
352 /// // and decrypt
353 ///
354 /// let mut plain = [0u8; 32];
355 /// assert!(AesCtr::new(&key, &iv)
356 /// .unwrap()
357 /// .try_apply_keystream(output.as_slice(), plain.as_mut_slice())
358 /// .is_ok());
359 ///
360 /// assert_eq!(&plain, &input);
361 /// key.zero();
362 /// ```
363 try => try_apply_keystream,
364
365 /// Apply the underlying keystream to the output buffer using the encryption key.
366 ///
367 /// # Arguments
368 ///
369 /// * `input` - The input to apply the keystream to.
370 /// * `output` - The output buffer to store the result of applying the keystream.
371 ///
372 /// # Panics
373 ///
374 /// - If the application of the keystream failed.
375 /// - If the `input` buffer is larger than the `output` buffer.
376 /// - (Unlikely) If the size of the `input` or `output` buffer is greater than what can be
377 /// represented by an `unsigned int` (u32).
378 ///
379 /// # Example
380 ///
381 /// ```
382 /// use wolf_crypto::{buf::Iv, aes::{Key, AesCtr}};
383 /// // securely generate a random key and initialization vector ...
384 /// # let mut key = Key::Aes256([1u8; 32]);
385 /// # let iv = Iv::new([2u8; 16]);
386 ///
387 /// let mut input = [1u8; 32];
388 /// let mut output = [0u8; 32];
389 ///
390 /// AesCtr::new(&key, &iv)
391 /// .unwrap()
392 /// .apply_keystream(input.as_slice(), output.as_mut_slice());
393 ///
394 /// assert_ne!(&input, &output);
395 /// assert_ne!(output, [0u8; 32]);
396 ///
397 /// // and decrypt
398 ///
399 /// let mut plain = [0u8; 32];
400 /// AesCtr::new(&key, &iv)
401 /// .unwrap()
402 /// .apply_keystream(output.as_slice(), plain.as_mut_slice());
403 ///
404 /// assert_eq!(&plain, &input);
405 /// key.zero();
406 /// ```
407 panics => apply_keystream
408 }
409}
410
411// SAFETY:
412// All methods which mutate the underlying AES instance require a mutable reference,
413// the only way to obtain a mutable reference across thread boundaries is via synchronization or
414// unsafe in Rust (which then would be the user's responsibility).
415unsafe impl Send for AesCtr {}
416
417// SAFETY:
418// There is no providing of interior mutability in the `AesCtr`, all methods which mutate the
419// underlying AES instance require a mutable reference, thus making this safe to mark `Sync`.
420unsafe impl Sync for AesCtr {}
421
422mark_fips! { AesCtr, Sealed }
423
424#[cfg(all(test, feature = "can-panic"))]
425mod tests {
426 use ctr::Ctr128BE;
427 use aes::Aes256;
428 use ctr::cipher::{KeyIvInit, StreamCipher};
429 use super::*;
430
431 #[test]
432 fn apply_smoke() {
433 let key = Key::Aes256([7; 32]);
434 let nonce = [0u8; 16].into();
435
436 let mut ctr = AesCtr::new(&key, &nonce).unwrap();
437
438 let input = [0u8; 12];
439 let mut output = [0u8; 12];
440
441 assert!(ctr.apply_keystream_sized(&input, &mut output).is_ok());
442
443 let mut output2 = [0u8; 12];
444 assert!(ctr.apply_keystream_sized(&input, &mut output2).is_ok());
445
446 assert_ne!(output, output2);
447 }
448
449 #[test]
450 fn against_ctr_rust_crypto_smoke() {
451 let key = Key::Aes256([7; 32]);
452 let nonce = [3; 16].into();
453 let mut ctr = AesCtr::new(&key, &nonce).unwrap();
454
455 let mut rc_ctr = Ctr128BE::<Aes256>::new_from_slices(
456 key.as_slice(), nonce.slice()
457 ).unwrap();
458
459 let input = [0u8; 12];
460 let mut out = [0u8; 12];
461 let mut out_rc = [0u8; 12];
462
463 rc_ctr.apply_keystream_b2b(input.as_slice(), out_rc.as_mut_slice()).unwrap();
464 ctr.apply_keystream(input.as_slice(), out.as_mut_slice());
465
466 assert_eq!(out, out_rc);
467 }
468
469 #[test]
470 fn self_bijective_smoke() {
471 let key = Key::Aes256([7; 32]);
472 let nonce = [1u8; 16].into();
473
474 let mut ctr = AesCtr::new(&key, &nonce).unwrap();
475
476 let input = [1u8; 12];
477 let mut output = [0u8; 12];
478
479 assert!(ctr.apply_keystream_sized(&input, &mut output).is_ok());
480 assert_ne!(output, input);
481
482 let mut decrypt_ctr = AesCtr::new(&key, &nonce).unwrap();
483
484 let mut plain = [0u8; 12];
485 assert!(decrypt_ctr.apply_keystream_sized(&output, &mut plain).is_ok());
486
487 assert_eq!(plain, input);
488 }
489
490 #[test]
491 fn precondition_ensured() {
492 let input = [0u8; 12];
493 let mut output = [0u8; 11];
494
495 let key = Key::Aes256([7; 32]);
496 let nonce = [1u8; 16].into();
497
498 let res = AesCtr::new(&key, &nonce).unwrap()
499 .try_apply_keystream(input.as_slice(), output.as_mut_slice());
500
501 assert!(res.is_err());
502 }
503}
504
505#[cfg(all(test, not(miri), feature = "can-panic"))]
506mod property_tests {
507 use aes::{Aes256, Aes192, Aes128};
508 use ctr::cipher::{KeyIvInit, StreamCipher};
509 use ctr::Ctr128BE;
510 use proptest::prelude::*;
511 use crate::aes::test_utils::*;
512 use super::*;
513
514 macro_rules! with_rust_crypto_ctr {
515 ($key:expr, $nonce:expr, |$ctr:ident| $do:expr) => {
516 match $key {
517 Key::Aes256(buf) => {
518 let mut $ctr = Ctr128BE::<Aes256>::new_from_slices(
519 buf.as_slice(), $nonce.slice()
520 ).unwrap();
521
522 $do
523 },
524 Key::Aes128(buf) => {
525 let mut $ctr = Ctr128BE::<Aes128>::new_from_slices(
526 buf.as_slice(), $nonce.slice()
527 ).unwrap();
528
529 $do
530 },
531 Key::Aes192(buf) => {
532 let mut $ctr = Ctr128BE::<Aes192>::new_from_slices(
533 buf.as_slice(), $nonce.slice()
534 ).unwrap();
535
536 $do
537 }
538 }
539 };
540 }
541
542 proptest! {
543 #![proptest_config(ProptestConfig::with_cases(10000))]
544
545 #[test]
546 fn self_bijective(
547 input in any::<BoundList<1024>>(),
548 key in any::<Key>(),
549 nonce in any::<Iv>()
550 ) {
551 let mut output = input.create_self();
552
553 let res = AesCtr::new(&key, &nonce)
554 .unwrap()
555 .try_apply_keystream(input.as_slice(), output.as_mut_slice());
556
557 prop_assert!(res.is_ok());
558
559 if input.len() >= 2 {
560 prop_assert_ne!(&output, &input);
561 }
562
563 let mut plain = input.create_self();
564 let res = AesCtr::new(&key, &nonce)
565 .unwrap()
566 .try_apply_keystream(output.as_slice(), plain.as_mut_slice());
567
568 prop_assert!(res.is_ok());
569
570 prop_assert_eq!(plain.as_slice(), input.as_slice());
571 }
572
573 #[test]
574 fn from_ctr_crate_to_wolf(
575 input in any::<BoundList<1024>>(),
576 key in any::<Key>(),
577 nonce in any::<Iv>()
578 ) {
579 let mut ctr = AesCtr::new(&key, &nonce).unwrap();
580 let mut c_in = input;
581
582 with_rust_crypto_ctr!(key, nonce, |o_ctr| {
583 o_ctr.apply_keystream(c_in.as_mut_slice());
584 });
585
586 let mut plain = input.create_self();
587 ctr.apply_keystream(c_in.as_slice(), plain.as_mut_slice());
588
589 prop_assert_eq!(plain.as_slice(), input.as_slice());
590 }
591
592 #[test]
593 fn from_wolf_to_ctr_crate(
594 input in any::<BoundList<1024>>(),
595 key in any::<Key>(),
596 nonce in any::<Iv>()
597 ) {
598 let mut ctr = AesCtr::new(&key, &nonce).unwrap();
599 let mut cipher = input.create_self();
600
601 ctr.apply_keystream(input.as_slice(), cipher.as_mut_slice());
602
603 if input.len() >= 2 {
604 prop_assert_ne!(&input, &cipher);
605 }
606
607 with_rust_crypto_ctr!(key, nonce, |o_ctr| {
608 o_ctr.apply_keystream(cipher.as_mut_slice());
609 });
610
611 prop_assert_eq!(cipher.as_slice(), input.as_slice());
612 }
613 }
614
615 proptest! {
616 #![proptest_config(ProptestConfig::with_cases(1000))]
617
618 #[test]
619 fn wolf_and_ctr_crate_eq_many_invocations(
620 mut input in any::<BoundList<512>>(),
621 key in any::<Key>(),
622 nonce in any::<Iv>(),
623 ) {
624 let mut ctr = AesCtr::new(&key, &nonce).unwrap();
625
626 with_rust_crypto_ctr!(key, nonce, |o_ctr| {
627 for _ in 0..256 {
628 let mut wolf_out = input.create_self();
629 ctr.apply_keystream(input.as_slice(), wolf_out.as_mut_slice());
630
631 o_ctr.apply_keystream(input.as_mut_slice());
632
633 prop_assert_eq!(wolf_out.as_slice(), input.as_slice());
634 }
635 });
636 }
637 }
638}