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}