aws_lc_rs/cipher/
streaming.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4use crate::aws_lc::{
5    EVP_CIPHER_CTX_new, EVP_CIPHER_iv_length, EVP_CIPHER_key_length, EVP_DecryptFinal_ex,
6    EVP_DecryptInit_ex, EVP_DecryptUpdate, EVP_EncryptFinal_ex, EVP_EncryptInit_ex,
7    EVP_EncryptUpdate, EVP_CIPHER, EVP_CIPHER_CTX,
8};
9use crate::cipher::{
10    Algorithm, DecryptionContext, EncryptionContext, OperatingMode, UnboundCipherKey,
11};
12use crate::error::Unspecified;
13use crate::fips::indicator_check;
14use crate::ptr::LcPtr;
15use std::ptr::{null, null_mut};
16
17use super::ConstPointer;
18
19/// A key for streaming encryption operations.
20pub struct StreamingEncryptingKey {
21    algorithm: &'static Algorithm,
22    mode: OperatingMode,
23    cipher_ctx: LcPtr<EVP_CIPHER_CTX>,
24    context: EncryptionContext,
25}
26
27/// A struct indicating the portion of a buffer written to, and/or not written to, during an
28/// encryption/decryption operation.
29pub struct BufferUpdate<'a> {
30    written: &'a [u8],
31    remainder: &'a mut [u8],
32}
33
34impl<'a> BufferUpdate<'a> {
35    fn new(out_buffer: &'a mut [u8], written_len: usize) -> Self {
36        let (written, remainder) = out_buffer.split_at_mut(written_len);
37        Self { written, remainder }
38    }
39}
40
41impl BufferUpdate<'_> {
42    /// Returns the slice from the buffer that was modified by the operation.
43    #[must_use]
44    pub fn written(&self) -> &[u8] {
45        self.written
46    }
47
48    /// Returns the slice of the buffer that was not modified by the operation.
49    #[must_use]
50    pub fn remainder(&self) -> &[u8] {
51        self.remainder
52    }
53
54    /// Returns a mutable slice of the buffer that was not modified by the operation.
55    #[must_use]
56    pub fn remainder_mut(&mut self) -> &mut [u8] {
57        self.remainder
58    }
59}
60
61fn evp_encrypt_init(
62    cipher_ctx: &mut LcPtr<EVP_CIPHER_CTX>,
63    cipher: &ConstPointer<EVP_CIPHER>,
64    key: &[u8],
65    iv: Option<&[u8]>,
66) -> Result<(), Unspecified> {
67    let iv_ptr: *const u8 = if let Some(iv) = iv {
68        iv.as_ptr()
69    } else {
70        null()
71    };
72
73    // AWS-LC copies the key and iv values into the EVP_CIPHER_CTX, and thus can be dropped after this.
74    if 1 != unsafe {
75        EVP_EncryptInit_ex(
76            cipher_ctx.as_mut_ptr(),
77            cipher.as_const_ptr(),
78            null_mut(),
79            key.as_ptr(),
80            iv_ptr,
81        )
82    } {
83        return Err(Unspecified);
84    }
85
86    Ok(())
87}
88
89fn evp_decrypt_init(
90    cipher_ctx: &mut LcPtr<EVP_CIPHER_CTX>,
91    cipher: &ConstPointer<EVP_CIPHER>,
92    key: &[u8],
93    iv: Option<&[u8]>,
94) -> Result<(), Unspecified> {
95    let iv_ptr: *const u8 = if let Some(iv) = iv {
96        iv.as_ptr()
97    } else {
98        null()
99    };
100
101    // AWS-LC copies the key and iv values into the EVP_CIPHER_CTX, and thus can be dropped after this.
102    if 1 != unsafe {
103        EVP_DecryptInit_ex(
104            cipher_ctx.as_mut_ptr(),
105            cipher.as_const_ptr(),
106            null_mut(),
107            key.as_ptr(),
108            iv_ptr,
109        )
110    } {
111        return Err(Unspecified);
112    }
113
114    Ok(())
115}
116
117impl StreamingEncryptingKey {
118    #[allow(clippy::needless_pass_by_value)]
119    fn new(
120        key: UnboundCipherKey,
121        mode: OperatingMode,
122        context: EncryptionContext,
123    ) -> Result<Self, Unspecified> {
124        let algorithm = key.algorithm();
125        let mut cipher_ctx = LcPtr::new(unsafe { EVP_CIPHER_CTX_new() })?;
126        let cipher = mode.evp_cipher(key.algorithm);
127        let key_bytes = key.key_bytes.as_ref();
128        debug_assert_eq!(
129            key_bytes.len(),
130            <usize>::try_from(unsafe { EVP_CIPHER_key_length(cipher.as_const_ptr()) }).unwrap()
131        );
132
133        match &context {
134            ctx @ EncryptionContext::Iv128(..) => {
135                let iv = <&[u8]>::try_from(ctx)?;
136                debug_assert_eq!(
137                    iv.len(),
138                    <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
139                        .unwrap()
140                );
141                evp_encrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
142            }
143            EncryptionContext::None => {
144                evp_encrypt_init(&mut cipher_ctx, &cipher, key_bytes, None)?;
145            }
146        }
147
148        Ok(Self {
149            algorithm,
150            mode,
151            cipher_ctx,
152            context,
153        })
154    }
155
156    /// Updates the internal state of the key with the provided ciphertext `input`,
157    /// potentially writing bytes of ciphertext to `output`.
158    ///
159    /// The number of bytes written to `output` can be up to `input.len()`
160    /// plus the block length of the algorithm (e.g., [`Algorithm::block_len`]).
161    ///
162    /// # Errors
163    /// * Returns an error if the `output` buffer is smaller than the length of
164    ///   the `input` plus the algorithm's block length (e.g. [`Algorithm::block_len`]) minus one.
165    /// * May return an error if the length of `input` plus the algorithm's block length is larger than `i32::MAX`.
166    pub fn update<'a>(
167        &mut self,
168        input: &[u8],
169        output: &'a mut [u8],
170    ) -> Result<BufferUpdate<'a>, Unspecified> {
171        let min_outsize = input
172            .len()
173            .checked_add(self.algorithm().block_len())
174            .ok_or(Unspecified)?
175            - 1;
176        if output.len() < min_outsize {
177            return Err(Unspecified);
178        }
179        let mut outlen: i32 = 0;
180        let inlen: i32 = input.len().try_into()?;
181
182        if 1 != unsafe {
183            EVP_EncryptUpdate(
184                self.cipher_ctx.as_mut_ptr(),
185                output.as_mut_ptr(),
186                &mut outlen,
187                input.as_ptr(),
188                inlen,
189            )
190        } {
191            return Err(Unspecified);
192        }
193        let outlen: usize = outlen.try_into()?;
194        debug_assert!(outlen <= min_outsize);
195        Ok(BufferUpdate::new(output, outlen))
196    }
197
198    /// Finishes the encryption operation, writing any remaining ciphertext to
199    /// `output`.
200    ///
201    /// The number of bytes written to `output` can be up to the block length of
202    /// [`Algorithm::block_len`].
203    ///
204    /// # Errors
205    /// * Returns an error if the `output` buffer is smaller than the algorithm's
206    ///   block length.
207    pub fn finish(
208        mut self,
209        output: &mut [u8],
210    ) -> Result<(DecryptionContext, BufferUpdate<'_>), Unspecified> {
211        if output.len() < self.algorithm().block_len() {
212            return Err(Unspecified);
213        }
214        let mut outlen: i32 = 0;
215
216        if 1 != indicator_check!(unsafe {
217            EVP_EncryptFinal_ex(
218                self.cipher_ctx.as_mut_ptr(),
219                output.as_mut_ptr(),
220                &mut outlen,
221            )
222        }) {
223            return Err(Unspecified);
224        }
225        let outlen: usize = outlen.try_into()?;
226        debug_assert!(outlen <= self.algorithm().block_len());
227        Ok((self.context.into(), BufferUpdate::new(output, outlen)))
228    }
229
230    /// Returns the cipher operating mode.
231    #[must_use]
232    pub fn mode(&self) -> OperatingMode {
233        self.mode
234    }
235
236    /// Returns the cipher algorithm.
237    #[must_use]
238    pub fn algorithm(&self) -> &'static Algorithm {
239        self.algorithm
240    }
241
242    /// Constructs a `StreamingEncryptingKey` for encrypting data using the CTR cipher mode.
243    /// The resulting ciphertext will be the same length as the plaintext.
244    ///
245    /// # Errors
246    /// Returns and error on an internal failure.
247    pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
248        let context = key.algorithm().new_encryption_context(OperatingMode::CTR)?;
249        Self::less_safe_ctr(key, context)
250    }
251
252    /// Constructs a `StreamingEncryptingKey` for encrypting data using the CTR cipher mode.
253    /// The resulting ciphertext will be the same length as the plaintext.
254    ///
255    /// This is considered less safe because the caller could potentially construct
256    /// an `EncryptionContext` from a previously used initialization vector (IV).
257    ///
258    /// # Errors
259    /// Returns an error on an internal failure.
260    pub fn less_safe_ctr(
261        key: UnboundCipherKey,
262        context: EncryptionContext,
263    ) -> Result<Self, Unspecified> {
264        Self::new(key, OperatingMode::CTR, context)
265    }
266
267    /// Constructs a `StreamingEncryptingKey` for encrypting data using the CBC cipher mode
268    /// with pkcs7 padding.
269    /// The resulting ciphertext will be longer than the plaintext; padding is added
270    /// to fill the next block of ciphertext.
271    ///
272    /// # Errors
273    /// Returns an error on an internal failure.
274    pub fn cbc_pkcs7(key: UnboundCipherKey) -> Result<Self, Unspecified> {
275        let context = key.algorithm().new_encryption_context(OperatingMode::CBC)?;
276        Self::less_safe_cbc_pkcs7(key, context)
277    }
278
279    /// Constructs a `StreamingEncryptingKey` for encrypting data using the CFB128 cipher mode.
280    /// The resulting ciphertext will be the same length as the plaintext.
281    ///
282    /// # Errors
283    /// Returns and error on an internal failure.
284    pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
285        let context = key
286            .algorithm()
287            .new_encryption_context(OperatingMode::CFB128)?;
288        Self::less_safe_cfb128(key, context)
289    }
290
291    /// Constructs a `StreamingEncryptingKey` for encrypting using ECB cipher mode with PKCS7 padding.
292    /// The resulting plaintext will be the same length as the ciphertext.
293    ///
294    /// # ☠️ ️️️DANGER ☠️
295    /// Offered for computability purposes only. This is an extremely dangerous mode, and
296    /// very likely not what you want to use.
297    ///
298    /// # Errors
299    /// Returns an error on an internal failure.
300    pub fn ecb_pkcs7(key: UnboundCipherKey) -> Result<Self, Unspecified> {
301        let context = key.algorithm().new_encryption_context(OperatingMode::ECB)?;
302        Self::new(key, OperatingMode::ECB, context)
303    }
304
305    /// Constructs a `StreamingEncryptingKey` for encrypting data using the CFB128 cipher mode.
306    /// The resulting ciphertext will be the same length as the plaintext.
307    ///
308    /// This is considered less safe because the caller could potentially construct
309    /// an `EncryptionContext` from a previously used initialization vector (IV).
310    ///
311    /// # Errors
312    /// Returns an error on an internal failure.
313    pub fn less_safe_cfb128(
314        key: UnboundCipherKey,
315        context: EncryptionContext,
316    ) -> Result<Self, Unspecified> {
317        Self::new(key, OperatingMode::CFB128, context)
318    }
319
320    /// Constructs a `StreamingEncryptingKey` for encrypting data using the CBC cipher mode
321    /// with pkcs7 padding.
322    /// The resulting ciphertext will be longer than the plaintext; padding is added
323    /// to fill the next block of ciphertext.
324    ///
325    /// This is considered less safe because the caller could potentially construct
326    /// an `EncryptionContext` from a previously used initialization vector (IV).
327    ///
328    /// # Errors
329    /// Returns an error on an internal failure.
330    pub fn less_safe_cbc_pkcs7(
331        key: UnboundCipherKey,
332        context: EncryptionContext,
333    ) -> Result<Self, Unspecified> {
334        Self::new(key, OperatingMode::CBC, context)
335    }
336}
337
338/// A key for streaming decryption operations.
339pub struct StreamingDecryptingKey {
340    algorithm: &'static Algorithm,
341    mode: OperatingMode,
342    cipher_ctx: LcPtr<EVP_CIPHER_CTX>,
343}
344impl StreamingDecryptingKey {
345    #[allow(clippy::needless_pass_by_value)]
346    fn new(
347        key: UnboundCipherKey,
348        mode: OperatingMode,
349        context: DecryptionContext,
350    ) -> Result<Self, Unspecified> {
351        let mut cipher_ctx = LcPtr::new(unsafe { EVP_CIPHER_CTX_new() })?;
352        let algorithm = key.algorithm();
353        let cipher = mode.evp_cipher(key.algorithm);
354        let key_bytes = key.key_bytes.as_ref();
355        debug_assert_eq!(
356            key_bytes.len(),
357            <usize>::try_from(unsafe { EVP_CIPHER_key_length(cipher.as_const_ptr()) }).unwrap()
358        );
359
360        match &context {
361            ctx @ DecryptionContext::Iv128(..) => {
362                let iv = <&[u8]>::try_from(ctx)?;
363                debug_assert_eq!(
364                    iv.len(),
365                    <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
366                        .unwrap()
367                );
368                evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
369            }
370            DecryptionContext::None => {
371                evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, None)?;
372            }
373        }
374
375        Ok(Self {
376            algorithm,
377            mode,
378            cipher_ctx,
379        })
380    }
381
382    /// Updates the internal state of the key with the provided ciphertext `input`,
383    /// potentially also writing bytes of plaintext to `output`.
384    /// The number of bytes written to `output` can be up to `input.len()`
385    /// plus the block length of the cipher algorithm (e.g., [`Algorithm::block_len`]).
386    ///
387    /// # Errors
388    /// * Returns an error if the `output` buffer is smaller than the length of
389    ///   the `input` plus the algorithm's block length.
390    /// * May return an error if the length of `input` plus the algorithm's block length is larger
391    ///   than `i32::MAX`.
392    pub fn update<'a>(
393        &mut self,
394        input: &[u8],
395        output: &'a mut [u8],
396    ) -> Result<BufferUpdate<'a>, Unspecified> {
397        let mut outlen: i32 = 0;
398        let inlen: i32 = input.len().try_into()?;
399
400        let min_outsize = input
401            .len()
402            .checked_add(self.algorithm().block_len())
403            .ok_or(Unspecified)?;
404        if output.len() < min_outsize {
405            return Err(Unspecified);
406        }
407
408        if 1 != unsafe {
409            EVP_DecryptUpdate(
410                self.cipher_ctx.as_mut_ptr(),
411                output.as_mut_ptr(),
412                &mut outlen,
413                input.as_ptr(),
414                inlen,
415            )
416        } {
417            return Err(Unspecified);
418        }
419        let outlen: usize = outlen.try_into()?;
420        debug_assert!(outlen <= min_outsize);
421        Ok(BufferUpdate::new(output, outlen))
422    }
423
424    /// Finishes the decryption operation, writing the remaining plaintext to
425    /// `output`.
426    /// The number of bytes written to `output` can be up to the block length of
427    /// the cipher algorithm (e.g., [`Algorithm::block_len`]).
428    ///
429    /// # Errors
430    /// * Returns an error if the `output` buffer is smaller than the algorithm's
431    ///   block length.
432    pub fn finish(mut self, output: &mut [u8]) -> Result<BufferUpdate<'_>, Unspecified> {
433        if output.len() < self.algorithm().block_len() {
434            return Err(Unspecified);
435        }
436        let mut outlen: i32 = 0;
437
438        if 1 != indicator_check!(unsafe {
439            EVP_DecryptFinal_ex(
440                self.cipher_ctx.as_mut_ptr(),
441                output.as_mut_ptr(),
442                &mut outlen,
443            )
444        }) {
445            return Err(Unspecified);
446        }
447        let outlen: usize = outlen.try_into()?;
448        debug_assert!(outlen <= self.algorithm().block_len());
449        Ok(BufferUpdate::new(output, outlen))
450    }
451
452    /// Returns the cipher operating mode.
453    #[must_use]
454    pub fn mode(&self) -> OperatingMode {
455        self.mode
456    }
457
458    /// Returns the cipher algorithm
459    #[must_use]
460    pub fn algorithm(&self) -> &'static Algorithm {
461        self.algorithm
462    }
463
464    /// Constructs a `StreamingDecryptingKey` for decrypting using the CTR cipher mode.
465    /// The resulting plaintext will be the same length as the ciphertext.
466    ///
467    /// # Errors
468    /// Returns an error on an internal failure.
469    pub fn ctr(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
470        Self::new(key, OperatingMode::CTR, context)
471    }
472
473    /// Constructs a `StreamingDecryptingKey` for decrypting using the CBC cipher mode.
474    /// The resulting plaintext will be shorter than the ciphertext.
475    ///
476    /// # Errors
477    /// Returns an error on an internal failure.
478    pub fn cbc_pkcs7(
479        key: UnboundCipherKey,
480        context: DecryptionContext,
481    ) -> Result<Self, Unspecified> {
482        Self::new(key, OperatingMode::CBC, context)
483    }
484
485    // Constructs a `StreamingDecryptingKey` for decrypting using the CFB128 cipher mode.
486    /// The resulting plaintext will be the same length as the ciphertext.
487    ///
488    /// # Errors
489    /// Returns an error on an internal failure.
490    pub fn cfb128(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
491        Self::new(key, OperatingMode::CFB128, context)
492    }
493
494    /// Constructs a `StreamingDecryptingKey` for decrypting using the ECB cipher mode.
495    /// The resulting plaintext will be the same length as the ciphertext.
496    ///
497    /// # ☠️ ️️️DANGER ☠️
498    /// Offered for computability purposes only. This is an extremely dangerous mode, and
499    /// very likely not what you want to use.
500    ///
501    /// # Errors
502    /// Returns an error on an internal failure.
503    pub fn ecb_pkcs7(
504        key: UnboundCipherKey,
505        context: DecryptionContext,
506    ) -> Result<Self, Unspecified> {
507        Self::new(key, OperatingMode::ECB, context)
508    }
509}
510
511#[cfg(test)]
512mod tests {
513    use crate::cipher::{
514        DecryptionContext, EncryptionContext, OperatingMode, StreamingDecryptingKey,
515        StreamingEncryptingKey, UnboundCipherKey, AES_128, AES_256, AES_256_KEY_LEN,
516    };
517    use crate::iv::{FixedLength, IV_LEN_128_BIT};
518    use crate::rand::{SecureRandom, SystemRandom};
519    use crate::test::from_hex;
520    use paste::*;
521
522    fn step_encrypt(
523        mut encrypting_key: StreamingEncryptingKey,
524        plaintext: &[u8],
525        step: usize,
526    ) -> (Box<[u8]>, DecryptionContext) {
527        let alg = encrypting_key.algorithm();
528        let mode = encrypting_key.mode();
529        let n = plaintext.len();
530        let mut ciphertext = vec![0u8; n + alg.block_len()];
531
532        let mut in_idx: usize = 0;
533        let mut out_idx: usize = 0;
534        loop {
535            let mut in_end = in_idx + step;
536            if in_end > n {
537                in_end = n;
538            }
539            let out_end = out_idx + (in_end - in_idx) + alg.block_len();
540            let output = encrypting_key
541                .update(
542                    &plaintext[in_idx..in_end],
543                    &mut ciphertext[out_idx..out_end],
544                )
545                .unwrap();
546            in_idx += step;
547            out_idx += output.written().len();
548            if in_idx >= n {
549                break;
550            }
551        }
552        let out_end = out_idx + alg.block_len();
553        let (decrypt_iv, output) = encrypting_key
554            .finish(&mut ciphertext[out_idx..out_end])
555            .unwrap();
556        let outlen = output.written().len();
557        ciphertext.truncate(out_idx + outlen);
558        match mode {
559            OperatingMode::CBC | OperatingMode::ECB => {
560                assert!(ciphertext.len() > plaintext.len());
561                assert!(ciphertext.len() <= plaintext.len() + alg.block_len());
562            }
563            _ => {
564                assert_eq!(ciphertext.len(), plaintext.len());
565            }
566        }
567
568        (ciphertext.into_boxed_slice(), decrypt_iv)
569    }
570
571    fn step_decrypt(
572        mut decrypting_key: StreamingDecryptingKey,
573        ciphertext: &[u8],
574        step: usize,
575    ) -> Box<[u8]> {
576        let alg = decrypting_key.algorithm();
577        let mode = decrypting_key.mode();
578        let n = ciphertext.len();
579        let mut plaintext = vec![0u8; n + alg.block_len()];
580
581        let mut in_idx: usize = 0;
582        let mut out_idx: usize = 0;
583        loop {
584            let mut in_end = in_idx + step;
585            if in_end > n {
586                in_end = n;
587            }
588            let out_end = out_idx + (in_end - in_idx) + alg.block_len();
589            let output = decrypting_key
590                .update(
591                    &ciphertext[in_idx..in_end],
592                    &mut plaintext[out_idx..out_end],
593                )
594                .unwrap();
595            in_idx += step;
596            out_idx += output.written().len();
597            if in_idx >= n {
598                break;
599            }
600        }
601        let out_end = out_idx + alg.block_len();
602        let output = decrypting_key
603            .finish(&mut plaintext[out_idx..out_end])
604            .unwrap();
605        let outlen = output.written().len();
606        plaintext.truncate(out_idx + outlen);
607        match mode {
608            OperatingMode::CBC | OperatingMode::ECB => {
609                assert!(ciphertext.len() > plaintext.len());
610                assert!(ciphertext.len() <= plaintext.len() + alg.block_len());
611            }
612            _ => {
613                assert_eq!(ciphertext.len(), plaintext.len());
614            }
615        }
616        plaintext.into_boxed_slice()
617    }
618
619    macro_rules! helper_stream_step_encrypt_test {
620        ($mode:ident) => {
621            paste! {
622                fn [<helper_test_ $mode _stream_encrypt_step_n_bytes>](
623                    encrypting_key_creator: impl Fn() -> StreamingEncryptingKey,
624                    decrypting_key_creator: impl Fn(DecryptionContext) -> StreamingDecryptingKey,
625                    n: usize,
626                    step: usize,
627                ) {
628                    let mut input = vec![0u8; n];
629                    let random = SystemRandom::new();
630                    random.fill(&mut input).unwrap();
631
632                    let encrypting_key = encrypting_key_creator();
633
634                    let (ciphertext, decrypt_iv) = step_encrypt(encrypting_key, &input, step);
635
636                    let decrypting_key = decrypting_key_creator(decrypt_iv);
637
638                    let plaintext = step_decrypt(decrypting_key, &ciphertext, step);
639
640                    assert_eq!(input.as_slice(), &*plaintext);
641                }
642            }
643        };
644    }
645
646    helper_stream_step_encrypt_test!(cbc_pkcs7);
647    helper_stream_step_encrypt_test!(ctr);
648    helper_stream_step_encrypt_test!(cfb128);
649    helper_stream_step_encrypt_test!(ecb_pkcs7);
650
651    #[test]
652    fn test_step_cbc() {
653        let random = SystemRandom::new();
654        let mut key = [0u8; AES_256_KEY_LEN];
655        random.fill(&mut key).unwrap();
656        let key = key;
657
658        let encrypting_key_creator = || {
659            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
660            StreamingEncryptingKey::cbc_pkcs7(key).unwrap()
661        };
662        let decrypting_key_creator = |decryption_ctx: DecryptionContext| {
663            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
664            StreamingDecryptingKey::cbc_pkcs7(key, decryption_ctx).unwrap()
665        };
666
667        for i in 13..=21 {
668            for j in 124..=131 {
669                helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes(
670                    encrypting_key_creator,
671                    decrypting_key_creator,
672                    j,
673                    i,
674                );
675            }
676            for j in 124..=131 {
677                helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes(
678                    encrypting_key_creator,
679                    decrypting_key_creator,
680                    j,
681                    j - i,
682                );
683            }
684        }
685        for j in 124..=131 {
686            helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes(
687                encrypting_key_creator,
688                decrypting_key_creator,
689                j,
690                j,
691            );
692            helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes(
693                encrypting_key_creator,
694                decrypting_key_creator,
695                j,
696                256,
697            );
698            helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes(
699                encrypting_key_creator,
700                decrypting_key_creator,
701                j,
702                1,
703            );
704        }
705    }
706
707    #[test]
708    fn test_step_ctr() {
709        let random = SystemRandom::new();
710        let mut key = [0u8; AES_256_KEY_LEN];
711        random.fill(&mut key).unwrap();
712
713        let encrypting_key_creator = || {
714            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
715            StreamingEncryptingKey::ctr(key).unwrap()
716        };
717        let decrypting_key_creator = |decryption_ctx: DecryptionContext| {
718            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
719            StreamingDecryptingKey::ctr(key, decryption_ctx).unwrap()
720        };
721
722        for i in 13..=21 {
723            for j in 124..=131 {
724                helper_test_ctr_stream_encrypt_step_n_bytes(
725                    encrypting_key_creator,
726                    decrypting_key_creator,
727                    j,
728                    i,
729                );
730            }
731            for j in 124..=131 {
732                helper_test_ctr_stream_encrypt_step_n_bytes(
733                    encrypting_key_creator,
734                    decrypting_key_creator,
735                    j,
736                    j - i,
737                );
738            }
739        }
740        for j in 124..=131 {
741            helper_test_ctr_stream_encrypt_step_n_bytes(
742                encrypting_key_creator,
743                decrypting_key_creator,
744                j,
745                j,
746            );
747            helper_test_ctr_stream_encrypt_step_n_bytes(
748                encrypting_key_creator,
749                decrypting_key_creator,
750                j,
751                256,
752            );
753            helper_test_ctr_stream_encrypt_step_n_bytes(
754                encrypting_key_creator,
755                decrypting_key_creator,
756                j,
757                1,
758            );
759        }
760    }
761
762    #[test]
763    fn test_step_cfb128() {
764        let random = SystemRandom::new();
765        let mut key = [0u8; AES_256_KEY_LEN];
766        random.fill(&mut key).unwrap();
767
768        let encrypting_key_creator = || {
769            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
770            StreamingEncryptingKey::cfb128(key).unwrap()
771        };
772        let decrypting_key_creator = |decryption_ctx: DecryptionContext| {
773            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
774            StreamingDecryptingKey::cfb128(key, decryption_ctx).unwrap()
775        };
776
777        for i in 13..=21 {
778            for j in 124..=131 {
779                helper_test_cfb128_stream_encrypt_step_n_bytes(
780                    encrypting_key_creator,
781                    decrypting_key_creator,
782                    j,
783                    i,
784                );
785            }
786            for j in 124..=131 {
787                helper_test_cfb128_stream_encrypt_step_n_bytes(
788                    encrypting_key_creator,
789                    decrypting_key_creator,
790                    j,
791                    j - i,
792                );
793            }
794        }
795        for j in 124..=131 {
796            helper_test_cfb128_stream_encrypt_step_n_bytes(
797                encrypting_key_creator,
798                decrypting_key_creator,
799                j,
800                j,
801            );
802            helper_test_cfb128_stream_encrypt_step_n_bytes(
803                encrypting_key_creator,
804                decrypting_key_creator,
805                j,
806                256,
807            );
808            helper_test_cfb128_stream_encrypt_step_n_bytes(
809                encrypting_key_creator,
810                decrypting_key_creator,
811                j,
812                1,
813            );
814        }
815    }
816
817    #[test]
818    fn test_step_ecb_pkcs7() {
819        let random = SystemRandom::new();
820        let mut key = [0u8; AES_256_KEY_LEN];
821        random.fill(&mut key).unwrap();
822
823        let encrypting_key_creator = || {
824            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
825            StreamingEncryptingKey::ecb_pkcs7(key).unwrap()
826        };
827        let decrypting_key_creator = |decryption_ctx: DecryptionContext| {
828            let key = UnboundCipherKey::new(&AES_256, &key.clone()).unwrap();
829            StreamingDecryptingKey::ecb_pkcs7(key, decryption_ctx).unwrap()
830        };
831
832        for i in 13..=21 {
833            for j in 124..=131 {
834                helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes(
835                    encrypting_key_creator,
836                    decrypting_key_creator,
837                    j,
838                    i,
839                );
840            }
841            for j in 124..=131 {
842                helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes(
843                    encrypting_key_creator,
844                    decrypting_key_creator,
845                    j,
846                    j - i,
847                );
848            }
849        }
850        for j in 124..=131 {
851            helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes(
852                encrypting_key_creator,
853                decrypting_key_creator,
854                j,
855                j,
856            );
857            helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes(
858                encrypting_key_creator,
859                decrypting_key_creator,
860                j,
861                256,
862            );
863            helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes(
864                encrypting_key_creator,
865                decrypting_key_creator,
866                j,
867                1,
868            );
869        }
870    }
871
872    macro_rules! streaming_cipher_kat {
873        ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal, $from_step:literal, $to_step:literal) => {
874            #[test]
875            fn $name() {
876                let key = from_hex($key).unwrap();
877                let input = from_hex($plaintext).unwrap();
878                let expected_ciphertext = from_hex($ciphertext).unwrap();
879                let iv = from_hex($iv).unwrap();
880
881                for step in ($from_step..=$to_step) {
882                    let ec = EncryptionContext::Iv128(
883                        FixedLength::<IV_LEN_128_BIT>::try_from(iv.as_slice()).unwrap(),
884                    );
885
886                    let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
887
888                    let encrypting_key =
889                        StreamingEncryptingKey::new(unbound_key, $mode, ec).unwrap();
890
891                    let (ciphertext, decrypt_ctx) = step_encrypt(encrypting_key, &input, step);
892
893                    assert_eq!(expected_ciphertext.as_slice(), ciphertext.as_ref());
894
895                    let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
896                    let decrypting_key =
897                        StreamingDecryptingKey::new(unbound_key2, $mode, decrypt_ctx).unwrap();
898
899                    let plaintext = step_decrypt(decrypting_key, &ciphertext, step);
900                    assert_eq!(input.as_slice(), plaintext.as_ref());
901                }
902            }
903        };
904        ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal, $from_step:literal, $to_step:literal) => {
905            #[test]
906            fn $name() {
907                let key = from_hex($key).unwrap();
908                let input = from_hex($plaintext).unwrap();
909                let expected_ciphertext = from_hex($ciphertext).unwrap();
910
911                for step in ($from_step..=$to_step) {
912                    let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
913
914                    let encrypting_key =
915                        StreamingEncryptingKey::new(unbound_key, $mode, EncryptionContext::None)
916                            .unwrap();
917
918                    let (ciphertext, decrypt_ctx) = step_encrypt(encrypting_key, &input, step);
919
920                    assert_eq!(expected_ciphertext.as_slice(), ciphertext.as_ref());
921
922                    let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
923                    let decrypting_key =
924                        StreamingDecryptingKey::new(unbound_key2, $mode, decrypt_ctx).unwrap();
925
926                    let plaintext = step_decrypt(decrypting_key, &ciphertext, step);
927                    assert_eq!(input.as_slice(), plaintext.as_ref());
928                }
929            }
930        };
931    }
932
933    streaming_cipher_kat!(
934        test_iv_aes_128_ctr_16_bytes,
935        &AES_128,
936        OperatingMode::CTR,
937        "000102030405060708090a0b0c0d0e0f",
938        "00000000000000000000000000000000",
939        "00112233445566778899aabbccddeeff",
940        "c6b01904c3da3df5e7d62bd96d153686",
941        2,
942        9
943    );
944    streaming_cipher_kat!(
945        test_iv_aes_256_ctr_15_bytes,
946        &AES_256,
947        OperatingMode::CTR,
948        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
949        "00000000000000000000000000000000",
950        "00112233445566778899aabbccddee",
951        "f28122856e1cf9a7216a30d111f399",
952        2,
953        9
954    );
955
956    streaming_cipher_kat!(
957        test_openssl_aes_128_ctr_15_bytes,
958        &AES_128,
959        OperatingMode::CTR,
960        "244828580821c1652582c76e34d299f5",
961        "093145d5af233f46072a5eb5adc11aa1",
962        "3ee38cec171e6cf466bf0df98aa0e1",
963        "bd7d928f60e3422d96b3f8cd614eb2",
964        2,
965        9
966    );
967
968    streaming_cipher_kat!(
969        test_openssl_aes_256_ctr_15_bytes,
970        &AES_256,
971        OperatingMode::CTR,
972        "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
973        "f028ecb053f801102d11fccc9d303a27",
974        "eca7285d19f3c20e295378460e8729",
975        "b5098e5e788de6ac2f2098eb2fc6f8",
976        2,
977        9
978    );
979
980    streaming_cipher_kat!(
981        test_iv_aes_128_cbc_16_bytes,
982        &AES_128,
983        OperatingMode::CBC,
984        "000102030405060708090a0b0c0d0e0f",
985        "00000000000000000000000000000000",
986        "00112233445566778899aabbccddeeff",
987        "69c4e0d86a7b0430d8cdb78070b4c55a9e978e6d16b086570ef794ef97984232",
988        2,
989        9
990    );
991
992    streaming_cipher_kat!(
993        test_iv_aes_256_cbc_15_bytes,
994        &AES_256,
995        OperatingMode::CBC,
996        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
997        "00000000000000000000000000000000",
998        "00112233445566778899aabbccddee",
999        "2ddfb635a651a43f582997966840ca0c",
1000        2,
1001        9
1002    );
1003
1004    streaming_cipher_kat!(
1005        test_openssl_aes_128_cbc_15_bytes,
1006        &AES_128,
1007        OperatingMode::CBC,
1008        "053304bb3899e1d99db9d29343ea782d",
1009        "b5313560244a4822c46c2a0c9d0cf7fd",
1010        "a3e4c990356c01f320043c3d8d6f43",
1011        "ad96993f248bd6a29760ec7ccda95ee1",
1012        2,
1013        9
1014    );
1015
1016    streaming_cipher_kat!(
1017        test_openssl_aes_128_cbc_16_bytes,
1018        &AES_128,
1019        OperatingMode::CBC,
1020        "95af71f1c63e4a1d0b0b1a27fb978283",
1021        "89e40797dca70197ff87d3dbb0ef2802",
1022        "aece7b5e3c3df1ffc9802d2dfe296dc7",
1023        "301b5dab49fb11e919d0d39970d06739301919743304f23f3cbc67d28564b25b",
1024        2,
1025        9
1026    );
1027
1028    streaming_cipher_kat!(
1029        test_openssl_aes_256_cbc_15_bytes,
1030        &AES_256,
1031        OperatingMode::CBC,
1032        "d369e03e9752784917cc7bac1db7399598d9555e691861d9dd7b3292a693ef57",
1033        "1399bb66b2f6ad99a7f064140eaaa885",
1034        "7385f5784b85bf0a97768ddd896d6d",
1035        "4351082bac9b4593ae8848cc9dfb5a01",
1036        2,
1037        9
1038    );
1039
1040    streaming_cipher_kat!(
1041        test_openssl_aes_256_cbc_16_bytes,
1042        &AES_256,
1043        OperatingMode::CBC,
1044        "d4a8206dcae01242f9db79a4ecfe277d0f7bb8ccbafd8f9809adb39f35aa9b41",
1045        "24f6076548fb9d93c8f7ed9f6e661ef9",
1046        "a39c1fdf77ea3e1f18178c0ec237c70a",
1047        "f1af484830a149ee0387b854d65fe87ca0e62efc1c8e6909d4b9ab8666470453",
1048        2,
1049        9
1050    );
1051
1052    streaming_cipher_kat!(
1053        test_openssl_aes_128_cfb128_16_bytes,
1054        &AES_128,
1055        OperatingMode::CFB128,
1056        "5c353f739429bbd48b7e3f9a76facf4d",
1057        "7b2c7ce17a9b6a59a9e64253b98c8cd1",
1058        "add1bcebeaabe9423d4e916400e877c5",
1059        "8440ec442e4135a613ddb2ce26107e10",
1060        2,
1061        9
1062    );
1063
1064    streaming_cipher_kat!(
1065        test_openssl_aes_128_cfb128_15_bytes,
1066        &AES_128,
1067        OperatingMode::CFB128,
1068        "e1f39d70ad378efc1ac318aa8ac4489f",
1069        "ec78c3d54fff2fe09678c7883024ddce",
1070        "b8c905004b2a92a323769f1b8dc1b2",
1071        "964c3e9bf8bf2a3cca02d8e2e75608",
1072        2,
1073        9
1074    );
1075
1076    streaming_cipher_kat!(
1077        test_openssl_aes_256_cfb128_16_bytes,
1078        &AES_256,
1079        OperatingMode::CFB128,
1080        "0e8117d0984d6acb957a5d6ca526a12fa612ce5de2daadebd42c14d28a0a192e",
1081        "09147a153b230a40cd7bf4197ad0e825",
1082        "13f4540a4e06394148ade31a6f678787",
1083        "250e590e47b7613b7d0a53f684e970d6",
1084        2,
1085        9
1086    );
1087
1088    streaming_cipher_kat!(
1089        test_openssl_aes_256_cfb128_15_bytes,
1090        &AES_256,
1091        OperatingMode::CFB128,
1092        "5cb17d8d5b9dbd81e4f1e0a2c82ebf36cf61156388fb7abf99d4526622858225",
1093        "13c77415ec24f3e2f784f228478a85be",
1094        "3efa583df4405aab61e18155aa7e0d",
1095        "c1f2ffe8aa5064199e8f4f1b388303",
1096        2,
1097        9
1098    );
1099
1100    streaming_cipher_kat!(
1101        test_openssl_aes_128_ecb_pkcs7_16_bytes,
1102        &AES_128,
1103        OperatingMode::ECB,
1104        "a1b7cd124f9824a1532d8440f8136788",
1105        "388118e6848b0cea97401707a754d7a1",
1106        "19b7c7f5d9c2bda3f957e9e7d20847828d5eb5624bcbf221014063a87b38d133",
1107        2,
1108        9
1109    );
1110
1111    streaming_cipher_kat!(
1112        test_openssl_aes_128_ecb_pkcs7_15_bytes,
1113        &AES_128,
1114        OperatingMode::ECB,
1115        "d10e12accb837aaffbb284448e53138c",
1116        "b21cfd1c9e6e7e6e912c82c7dd1aa8",
1117        "3d1168e61df34b51c6ab6745c20ee881",
1118        2,
1119        9
1120    );
1121
1122    streaming_cipher_kat!(
1123        test_openssl_aes_256_ecb_pkcs7_16_bytes,
1124        &AES_256,
1125        OperatingMode::ECB,
1126        "0600f4ad4eda4bc8e3e99592abdfce7eb08fee0ccc801c5ccee26134bcaafbbd",
1127        "516b45cb1342239a549bd8c1d5998f98",
1128        "854c593555a213e4a862c6f66aa4a79631faca131eba6f163e5cd3940e9c0a57",
1129        2,
1130        9
1131    );
1132
1133    streaming_cipher_kat!(
1134        test_openssl_aes_256_ecb_pkcs7_15_bytes,
1135        &AES_256,
1136        OperatingMode::ECB,
1137        "80f235756c8f70094ae1f99a95a599c27c4452a4b8412fd934e2b253f7098508",
1138        "2235590b90190d7a1dc2464a0205ad",
1139        "8547d8ac8dc6d9cebb2dc77a7034bb67",
1140        2,
1141        9
1142    );
1143}