1use 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
19pub struct StreamingEncryptingKey {
21 algorithm: &'static Algorithm,
22 mode: OperatingMode,
23 cipher_ctx: LcPtr<EVP_CIPHER_CTX>,
24 context: EncryptionContext,
25 output_generated: usize,
26}
27
28unsafe impl Send for StreamingEncryptingKey {}
29
30pub struct BufferUpdate<'a> {
33 written: &'a [u8],
34 remainder: &'a mut [u8],
35}
36
37impl<'a> BufferUpdate<'a> {
38 fn new(out_buffer: &'a mut [u8], written_len: usize) -> Self {
39 let (written, remainder) = out_buffer.split_at_mut(written_len);
40 Self { written, remainder }
41 }
42}
43
44impl BufferUpdate<'_> {
45 #[must_use]
47 pub fn written(&self) -> &[u8] {
48 self.written
49 }
50
51 #[must_use]
53 pub fn remainder(&self) -> &[u8] {
54 self.remainder
55 }
56
57 #[must_use]
59 pub fn remainder_mut(&mut self) -> &mut [u8] {
60 self.remainder
61 }
62}
63
64fn evp_encrypt_init(
65 cipher_ctx: &mut LcPtr<EVP_CIPHER_CTX>,
66 cipher: &ConstPointer<EVP_CIPHER>,
67 key: &[u8],
68 iv: Option<&[u8]>,
69) -> Result<(), Unspecified> {
70 let iv_ptr: *const u8 = if let Some(iv) = iv {
71 iv.as_ptr()
72 } else {
73 null()
74 };
75
76 if 1 != unsafe {
78 EVP_EncryptInit_ex(
79 cipher_ctx.as_mut_ptr(),
80 cipher.as_const_ptr(),
81 null_mut(),
82 key.as_ptr(),
83 iv_ptr,
84 )
85 } {
86 return Err(Unspecified);
87 }
88
89 Ok(())
90}
91
92fn evp_decrypt_init(
93 cipher_ctx: &mut LcPtr<EVP_CIPHER_CTX>,
94 cipher: &ConstPointer<EVP_CIPHER>,
95 key: &[u8],
96 iv: Option<&[u8]>,
97) -> Result<(), Unspecified> {
98 let iv_ptr: *const u8 = if let Some(iv) = iv {
99 iv.as_ptr()
100 } else {
101 null()
102 };
103
104 if 1 != unsafe {
106 EVP_DecryptInit_ex(
107 cipher_ctx.as_mut_ptr(),
108 cipher.as_const_ptr(),
109 null_mut(),
110 key.as_ptr(),
111 iv_ptr,
112 )
113 } {
114 return Err(Unspecified);
115 }
116
117 Ok(())
118}
119
120impl StreamingEncryptingKey {
121 #[allow(clippy::needless_pass_by_value)]
122 fn new(
123 key: UnboundCipherKey,
124 mode: OperatingMode,
125 context: EncryptionContext,
126 ) -> Result<Self, Unspecified> {
127 let algorithm = key.algorithm();
128 if !algorithm.supports_mode(mode) {
129 return Err(Unspecified);
130 }
131 if !algorithm.is_valid_encryption_context(mode, &context) {
133 return Err(Unspecified);
134 }
135 key.validate_key_material()?;
140 let mut cipher_ctx = LcPtr::new(unsafe { EVP_CIPHER_CTX_new() })?;
141 let cipher = mode.evp_cipher(key.algorithm);
142 let key_bytes = key.key_bytes.as_ref();
143 if key_bytes.len()
144 != <usize>::try_from(unsafe { EVP_CIPHER_key_length(cipher.as_const_ptr()) }).unwrap()
145 {
146 return Err(Unspecified);
147 }
148
149 match &context {
150 ctx @ EncryptionContext::Iv128(..) => {
151 let iv = <&[u8]>::try_from(ctx)?;
152 debug_assert_eq!(
153 iv.len(),
154 <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
155 .unwrap()
156 );
157 evp_encrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
158 }
159 #[cfg(feature = "legacy-des")]
160 ctx @ EncryptionContext::Iv64(..) => {
161 let iv = <&[u8]>::try_from(ctx)?;
162 debug_assert_eq!(
163 iv.len(),
164 <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
165 .unwrap()
166 );
167 evp_encrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
168 }
169 EncryptionContext::None => {
170 evp_encrypt_init(&mut cipher_ctx, &cipher, key_bytes, None)?;
171 }
172 }
173
174 Ok(Self {
175 algorithm,
176 mode,
177 cipher_ctx,
178 context,
179 output_generated: 0,
180 })
181 }
182
183 fn update_internal<'a>(
184 &mut self,
185 input: &[u8],
186 output: &'a mut [u8],
187 min_outsize: usize,
188 ) -> Result<BufferUpdate<'a>, Unspecified> {
189 if output.len() < min_outsize {
190 return Err(Unspecified);
191 }
192 let mut outlen: i32 = 0;
193 let inlen: i32 = input.len().try_into()?;
194
195 if 1 != unsafe {
196 EVP_EncryptUpdate(
197 self.cipher_ctx.as_mut_ptr(),
198 output.as_mut_ptr(),
199 &mut outlen,
200 input.as_ptr(),
201 inlen,
202 )
203 } {
204 return Err(Unspecified);
205 }
206 let outlen: usize = outlen.try_into()?;
207 debug_assert!(outlen <= min_outsize);
208 self.output_generated += outlen;
209 assert!(outlen <= output.len());
210
211 Ok(BufferUpdate::new(output, outlen))
212 }
213
214 pub fn update<'a>(
225 &mut self,
226 input: &[u8],
227 output: &'a mut [u8],
228 ) -> Result<BufferUpdate<'a>, Unspecified> {
229 let min_outsize = input
230 .len()
231 .checked_add(self.algorithm().block_len())
232 .ok_or(Unspecified)?
233 .checked_sub(1)
234 .ok_or(Unspecified)?;
235 self.update_internal(input, output, min_outsize)
236 }
237
238 pub fn less_safe_update<'a>(
260 &mut self,
261 input: &[u8],
262 output: &'a mut [u8],
263 ) -> Result<BufferUpdate<'a>, Unspecified> {
264 let next_total = self
265 .output_generated
266 .checked_add(input.len())
267 .ok_or(Unspecified)?;
268 let extra_buffer_size = (self.algorithm().block_len
269 - next_total.rem_euclid(self.algorithm().block_len))
270 .rem_euclid(self.algorithm().block_len);
271 let min_outsize = input
272 .len()
273 .checked_add(extra_buffer_size)
274 .ok_or(Unspecified)?;
275 self.update_internal(input, output, min_outsize)
276 }
277
278 pub fn finish(
288 mut self,
289 output: &mut [u8],
290 ) -> Result<(DecryptionContext, BufferUpdate<'_>), Unspecified> {
291 if output.len() < self.algorithm().block_len() {
292 return Err(Unspecified);
293 }
294 let mut outlen: i32 = 0;
295
296 if 1 != indicator_check!(unsafe {
297 EVP_EncryptFinal_ex(
298 self.cipher_ctx.as_mut_ptr(),
299 output.as_mut_ptr(),
300 &mut outlen,
301 )
302 }) {
303 return Err(Unspecified);
304 }
305 let outlen: usize = outlen.try_into()?;
306 debug_assert!(outlen <= self.algorithm().block_len());
307 Ok((self.context.into(), BufferUpdate::new(output, outlen)))
308 }
309
310 #[must_use]
312 pub fn mode(&self) -> OperatingMode {
313 self.mode
314 }
315
316 #[must_use]
318 pub fn algorithm(&self) -> &'static Algorithm {
319 self.algorithm
320 }
321
322 pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
331 let context = key.algorithm().new_encryption_context(OperatingMode::CTR)?;
332 Self::less_safe_ctr(key, context)
333 }
334
335 pub fn less_safe_ctr(
347 key: UnboundCipherKey,
348 context: EncryptionContext,
349 ) -> Result<Self, Unspecified> {
350 Self::new(key, OperatingMode::CTR, context)
351 }
352
353 pub fn cbc_pkcs7(key: UnboundCipherKey) -> Result<Self, Unspecified> {
366 let context = key.algorithm().new_encryption_context(OperatingMode::CBC)?;
367 Self::less_safe_cbc_pkcs7(key, context)
368 }
369
370 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
379 let context = key
380 .algorithm()
381 .new_encryption_context(OperatingMode::CFB128)?;
382 Self::less_safe_cfb128(key, context)
383 }
384
385 pub fn ecb_pkcs7(key: UnboundCipherKey) -> Result<Self, Unspecified> {
400 let context = key.algorithm().new_encryption_context(OperatingMode::ECB)?;
401 Self::new(key, OperatingMode::ECB, context)
402 }
403
404 pub fn less_safe_cfb128(
416 key: UnboundCipherKey,
417 context: EncryptionContext,
418 ) -> Result<Self, Unspecified> {
419 Self::new(key, OperatingMode::CFB128, context)
420 }
421
422 pub fn less_safe_cbc_pkcs7(
438 key: UnboundCipherKey,
439 context: EncryptionContext,
440 ) -> Result<Self, Unspecified> {
441 Self::new(key, OperatingMode::CBC, context)
442 }
443}
444
445pub struct StreamingDecryptingKey {
447 algorithm: &'static Algorithm,
448 mode: OperatingMode,
449 cipher_ctx: LcPtr<EVP_CIPHER_CTX>,
450 output_generated: usize,
451}
452
453unsafe impl Send for StreamingDecryptingKey {}
454
455impl StreamingDecryptingKey {
456 #[allow(clippy::needless_pass_by_value)]
457 fn new(
458 key: UnboundCipherKey,
459 mode: OperatingMode,
460 context: DecryptionContext,
461 ) -> Result<Self, Unspecified> {
462 let algorithm = key.algorithm();
463 if !algorithm.supports_mode(mode) {
464 return Err(Unspecified);
465 }
466 if !algorithm.is_valid_decryption_context(mode, &context) {
467 return Err(Unspecified);
468 }
469 key.validate_key_material()?;
471 let mut cipher_ctx = LcPtr::new(unsafe { EVP_CIPHER_CTX_new() })?;
472 let cipher = mode.evp_cipher(key.algorithm);
473 let key_bytes = key.key_bytes.as_ref();
474 if key_bytes.len()
475 != <usize>::try_from(unsafe { EVP_CIPHER_key_length(cipher.as_const_ptr()) }).unwrap()
476 {
477 return Err(Unspecified);
478 }
479
480 match &context {
481 ctx @ DecryptionContext::Iv128(..) => {
482 let iv = <&[u8]>::try_from(ctx)?;
483 debug_assert_eq!(
484 iv.len(),
485 <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
486 .unwrap()
487 );
488 evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
489 }
490 #[cfg(feature = "legacy-des")]
491 ctx @ DecryptionContext::Iv64(..) => {
492 let iv = <&[u8]>::try_from(ctx)?;
493 debug_assert_eq!(
494 iv.len(),
495 <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
496 .unwrap()
497 );
498 evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
499 }
500 DecryptionContext::None => {
501 evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, None)?;
502 }
503 }
504
505 Ok(Self {
506 algorithm,
507 mode,
508 cipher_ctx,
509 output_generated: 0,
510 })
511 }
512
513 fn update_internal<'a>(
514 &mut self,
515 input: &[u8],
516 output: &'a mut [u8],
517 min_outsize: usize,
518 ) -> Result<BufferUpdate<'a>, Unspecified> {
519 if output.len() < min_outsize {
520 return Err(Unspecified);
521 }
522 let mut outlen: i32 = 0;
523 let inlen: i32 = input.len().try_into()?;
524
525 if 1 != unsafe {
526 EVP_DecryptUpdate(
527 self.cipher_ctx.as_mut_ptr(),
528 output.as_mut_ptr(),
529 &mut outlen,
530 input.as_ptr(),
531 inlen,
532 )
533 } {
534 return Err(Unspecified);
535 }
536 let outlen: usize = outlen.try_into()?;
537 debug_assert!(outlen <= min_outsize);
538 self.output_generated += outlen;
539 assert!(outlen <= output.len());
542
543 Ok(BufferUpdate::new(output, outlen))
544 }
545
546 pub fn update<'a>(
557 &mut self,
558 input: &[u8],
559 output: &'a mut [u8],
560 ) -> Result<BufferUpdate<'a>, Unspecified> {
561 let min_outsize = input
562 .len()
563 .checked_add(self.algorithm().block_len())
564 .ok_or(Unspecified)?
565 .checked_sub(1)
566 .ok_or(Unspecified)?;
567 self.update_internal(input, output, min_outsize)
568 }
569
570 pub fn less_safe_update<'a>(
592 &mut self,
593 input: &[u8],
594 output: &'a mut [u8],
595 ) -> Result<BufferUpdate<'a>, Unspecified> {
596 let next_total = self
597 .output_generated
598 .checked_add(input.len())
599 .ok_or(Unspecified)?;
600 let extra_buffer_size = (self.algorithm().block_len
601 - next_total.rem_euclid(self.algorithm().block_len))
602 .rem_euclid(self.algorithm().block_len);
603 let min_outsize = input
604 .len()
605 .checked_add(extra_buffer_size)
606 .ok_or(Unspecified)?;
607 self.update_internal(input, output, min_outsize)
608 }
609
610 pub fn finish(mut self, output: &mut [u8]) -> Result<BufferUpdate<'_>, Unspecified> {
619 if output.len() < self.algorithm().block_len() {
620 return Err(Unspecified);
621 }
622 let mut outlen: i32 = 0;
623
624 if 1 != indicator_check!(unsafe {
625 EVP_DecryptFinal_ex(
626 self.cipher_ctx.as_mut_ptr(),
627 output.as_mut_ptr(),
628 &mut outlen,
629 )
630 }) {
631 return Err(Unspecified);
632 }
633 let outlen: usize = outlen.try_into()?;
634 debug_assert!(outlen <= self.algorithm().block_len());
635 Ok(BufferUpdate::new(output, outlen))
636 }
637
638 #[must_use]
640 pub fn mode(&self) -> OperatingMode {
641 self.mode
642 }
643
644 #[must_use]
646 pub fn algorithm(&self) -> &'static Algorithm {
647 self.algorithm
648 }
649
650 pub fn ctr(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
659 Self::new(key, OperatingMode::CTR, context)
660 }
661
662 pub fn cbc_pkcs7(
673 key: UnboundCipherKey,
674 context: DecryptionContext,
675 ) -> Result<Self, Unspecified> {
676 Self::new(key, OperatingMode::CBC, context)
677 }
678
679 pub fn cfb128(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
688 Self::new(key, OperatingMode::CFB128, context)
689 }
690
691 pub fn ecb_pkcs7(
706 key: UnboundCipherKey,
707 context: DecryptionContext,
708 ) -> Result<Self, Unspecified> {
709 Self::new(key, OperatingMode::ECB, context)
710 }
711}
712
713#[cfg(test)]
714mod tests {
715 #[cfg(feature = "legacy-des")]
716 #[allow(deprecated)]
717 use crate::cipher::DES_FOR_LEGACY_USE_ONLY;
718 use crate::cipher::{
719 DecryptionContext, EncryptionContext, OperatingMode, StreamingDecryptingKey,
720 StreamingEncryptingKey, UnboundCipherKey, AES_128, AES_128_KEY_LEN, AES_256,
721 AES_256_KEY_LEN,
722 };
723 use crate::iv::{FixedLength, IV_LEN_128_BIT};
724 use crate::rand::{SecureRandom, SystemRandom};
725 use crate::test::from_hex;
726 use paste::*;
727
728 const OUTPUT_CANARIES: [u8; 2] = [0xAA, 0x55];
733
734 fn assert_no_write_past(output: &[u8], slice_start: usize, slice_end: usize, canary: u8) {
735 let slice_len = slice_end - slice_start;
736 let tail = &output[slice_end..output.len().min(slice_end + 16)];
737 assert!(
738 output[slice_end..].iter().all(|&b| b == canary),
739 "wrote past the provided {slice_len}-byte output slice at buffer offsets \
740 {slice_start}..{slice_end} \
741 (canary {canary:#04x}, bytes at {slice_end}..: {tail:02x?})"
742 );
743 }
744
745 fn apply_update_with_canary(
746 output: &mut [u8],
747 out_idx: usize,
748 out_end: usize,
749 canary: u8,
750 op: impl FnOnce(&mut [u8]) -> usize,
751 ) -> usize {
752 output[out_end..].fill(canary);
753 let written = op(&mut output[out_idx..out_end]);
754 assert_no_write_past(output, out_idx, out_end, canary);
755 written
756 }
757
758 fn step_encrypt_with_updater<F>(
762 mut encrypting_key: StreamingEncryptingKey,
763 plaintext: &[u8],
764 step: usize,
765 canary: u8,
766 mut updater: F,
767 ) -> (Box<[u8]>, DecryptionContext)
768 where
769 F: FnMut(&mut StreamingEncryptingKey, &[u8], &mut [u8], usize, usize, usize) -> usize,
770 {
771 let alg = encrypting_key.algorithm();
772 let mode = encrypting_key.mode();
773 let block_len = alg.block_len();
774 let n = plaintext.len();
775 let mut ciphertext = vec![canary; n + 2 * block_len];
778
779 let mut in_idx: usize = 0;
780 let mut out_idx: usize = 0;
781 loop {
782 let mut in_end = in_idx + step;
783 if in_end > n {
784 in_end = n;
785 }
786 let written = updater(
787 &mut encrypting_key,
788 &plaintext[in_idx..in_end],
789 &mut ciphertext,
790 out_idx,
791 block_len,
792 step,
793 );
794 in_idx += step;
795 out_idx += written;
796 if in_idx >= n {
797 break;
798 }
799 }
800 let out_end = out_idx + block_len;
801 ciphertext[out_end..].fill(canary);
802 let (decrypt_iv, written_len) = {
803 let (decrypt_iv, output) = encrypting_key
804 .finish(&mut ciphertext[out_idx..out_end])
805 .unwrap();
806 (decrypt_iv, output.written().len())
807 };
808 assert_no_write_past(&ciphertext, out_idx, out_end, canary);
809 ciphertext.truncate(out_idx + written_len);
810 match mode {
811 OperatingMode::CBC | OperatingMode::ECB => {
812 assert!(ciphertext.len() > plaintext.len());
813 assert!(ciphertext.len() <= plaintext.len() + block_len);
814 }
815 _ => {
816 assert_eq!(ciphertext.len(), plaintext.len());
817 }
818 }
819
820 (ciphertext.into_boxed_slice(), decrypt_iv)
821 }
822
823 fn step_decrypt_with_updater<F>(
827 mut decrypting_key: StreamingDecryptingKey,
828 ciphertext: &[u8],
829 step: usize,
830 canary: u8,
831 mut updater: F,
832 ) -> Box<[u8]>
833 where
834 F: FnMut(&mut StreamingDecryptingKey, &[u8], &mut [u8], usize, usize, usize) -> usize,
835 {
836 let alg = decrypting_key.algorithm();
837 let mode = decrypting_key.mode();
838 let block_len = alg.block_len();
839 let n = ciphertext.len();
840 let mut plaintext = vec![canary; n + 2 * block_len];
841
842 let mut in_idx: usize = 0;
843 let mut out_idx: usize = 0;
844 loop {
845 let mut in_end = in_idx + step;
846 if in_end > n {
847 in_end = n;
848 }
849 let written = updater(
850 &mut decrypting_key,
851 &ciphertext[in_idx..in_end],
852 &mut plaintext,
853 out_idx,
854 block_len,
855 step,
856 );
857 in_idx += step;
858 out_idx += written;
859 if in_idx >= n {
860 break;
861 }
862 }
863 let out_end = out_idx + block_len;
864 plaintext[out_end..].fill(canary);
865 let written_len = {
866 let output = decrypting_key
867 .finish(&mut plaintext[out_idx..out_end])
868 .unwrap();
869 output.written().len()
870 };
871 assert_no_write_past(&plaintext, out_idx, out_end, canary);
872 plaintext.truncate(out_idx + written_len);
873 match mode {
874 OperatingMode::CBC | OperatingMode::ECB => {
875 assert!(ciphertext.len() > plaintext.len());
876 assert!(ciphertext.len() <= plaintext.len() + block_len);
877 }
878 _ => {
879 assert_eq!(ciphertext.len(), plaintext.len());
880 }
881 }
882 plaintext.into_boxed_slice()
883 }
884
885 fn step_encrypt(
886 encrypting_key: StreamingEncryptingKey,
887 plaintext: &[u8],
888 step: usize,
889 canary: u8,
890 ) -> (Box<[u8]>, DecryptionContext) {
891 step_encrypt_with_updater(
892 encrypting_key,
893 plaintext,
894 step,
895 canary,
896 |key, input, output, out_idx, block_len, _step| {
897 let out_end = out_idx + input.len() + block_len - 1;
898 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
899 key.update(input, out).unwrap().written().len()
900 })
901 },
902 )
903 }
904
905 fn step_decrypt(
906 decrypting_key: StreamingDecryptingKey,
907 ciphertext: &[u8],
908 step: usize,
909 canary: u8,
910 ) -> Box<[u8]> {
911 step_decrypt_with_updater(
912 decrypting_key,
913 ciphertext,
914 step,
915 canary,
916 |key, input, output, out_idx, block_len, _step| {
917 let out_end = out_idx + input.len() + block_len - 1;
918 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
919 key.update(input, out).unwrap().written().len()
920 })
921 },
922 )
923 }
924
925 fn less_safe_min_out(block_len: usize, out_idx: usize, input_len: usize) -> usize {
926 let next_total = out_idx + input_len;
927 input_len + ((block_len - (next_total % block_len)) % block_len)
928 }
929
930 fn step_encrypt_less_safe(
931 encrypting_key: StreamingEncryptingKey,
932 plaintext: &[u8],
933 step: usize,
934 canary: u8,
935 ) -> (Box<[u8]>, DecryptionContext) {
936 step_encrypt_with_updater(
937 encrypting_key,
938 plaintext,
939 step,
940 canary,
941 |key, input, output, out_idx, block_len, step| {
942 let min_out_len = less_safe_min_out(block_len, out_idx, input.len());
943 if input.len() % block_len == 0 && step % block_len == 0 {
944 assert_eq!(input.len(), min_out_len);
946 }
947 let out_end = out_idx + min_out_len;
948 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
949 key.less_safe_update(input, out).unwrap().written().len()
950 })
951 },
952 )
953 }
954
955 fn step_decrypt_less_safe(
956 decrypting_key: StreamingDecryptingKey,
957 ciphertext: &[u8],
958 step: usize,
959 canary: u8,
960 ) -> Box<[u8]> {
961 step_decrypt_with_updater(
962 decrypting_key,
963 ciphertext,
964 step,
965 canary,
966 |key, input, output, out_idx, block_len, step| {
967 let min_out_len = less_safe_min_out(block_len, out_idx, input.len());
968 if input.len() % block_len == 0 && step % block_len == 0 {
969 assert_eq!(input.len(), min_out_len);
971 }
972 let out_end = out_idx + min_out_len;
973 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
974 key.less_safe_update(input, out).unwrap().written().len()
975 })
976 },
977 )
978 }
979
980 macro_rules! helper_stream_step_encrypt_test {
981 ($mode:ident) => {
982 paste! {
983 fn [<helper_test_ $mode _stream_encrypt_step_n_bytes>](
984 encrypting_key_creator: impl Fn() -> StreamingEncryptingKey,
985 decrypting_key_creator: impl Fn(DecryptionContext) -> StreamingDecryptingKey,
986 n: usize,
987 step: usize,
988 canary: u8,
989 ) {
990 let mut input = vec![0u8; n];
991 let random = SystemRandom::new();
992 random.fill(&mut input).unwrap();
993
994 let encrypting_key = encrypting_key_creator();
995
996 let (ciphertext, decrypt_iv) =
997 step_encrypt(encrypting_key, &input, step, canary);
998
999 let decrypting_key = decrypting_key_creator(decrypt_iv);
1000
1001 let plaintext = step_decrypt(decrypting_key, &ciphertext, step, canary);
1002
1003 assert_eq!(input.as_slice(), &*plaintext);
1004 }
1005 }
1006 };
1007 ($mode:ident, less_safe) => {
1008 paste! {
1009 fn [<helper_test_ $mode _stream_encrypt_step_n_bytes_less_safe>](
1010 encrypting_key_creator: impl Fn() -> StreamingEncryptingKey,
1011 decrypting_key_creator: impl Fn(DecryptionContext) -> StreamingDecryptingKey,
1012 n: usize,
1013 step: usize,
1014 canary: u8,
1015 ) {
1016 let mut input = vec![0u8; n];
1017 let random = SystemRandom::new();
1018 random.fill(&mut input).unwrap();
1019
1020 let encrypting_key = encrypting_key_creator();
1021
1022 let (ciphertext, decrypt_iv) =
1023 step_encrypt_less_safe(encrypting_key, &input, step, canary);
1024
1025 let decrypting_key = decrypting_key_creator(decrypt_iv);
1026
1027 let plaintext =
1028 step_decrypt_less_safe(decrypting_key, &ciphertext, step, canary);
1029
1030 assert_eq!(input.as_slice(), &*plaintext);
1031 }
1032 }
1033 };
1034 }
1035
1036 helper_stream_step_encrypt_test!(cbc_pkcs7);
1037 helper_stream_step_encrypt_test!(ctr);
1038 helper_stream_step_encrypt_test!(cfb128);
1039 helper_stream_step_encrypt_test!(ecb_pkcs7);
1040
1041 helper_stream_step_encrypt_test!(cbc_pkcs7, less_safe);
1042 helper_stream_step_encrypt_test!(ctr, less_safe);
1043 helper_stream_step_encrypt_test!(cfb128, less_safe);
1044 helper_stream_step_encrypt_test!(ecb_pkcs7, less_safe);
1045
1046 fn run_step_matrix(test: impl Fn(usize, usize)) {
1047 for i in 13..=21 {
1048 for j in 124..=131 {
1049 test(j, i);
1050 test(j, j - i);
1051 }
1052 }
1053 for j in 124..=131 {
1054 test(j, j);
1055 test(j, 256);
1056 test(j, 1);
1057 }
1058 }
1059
1060 fn random_aes_key(len: usize) -> Vec<u8> {
1061 let mut key = vec![0u8; len];
1062 SystemRandom::new().fill(&mut key).unwrap();
1063 key
1064 }
1065
1066 macro_rules! step_roundtrip_tests {
1067 ($name:ident, $constructor:ident, $helper:ident) => {
1068 #[test]
1069 fn $name() {
1070 for (alg, key_len) in [(&AES_128, AES_128_KEY_LEN), (&AES_256, AES_256_KEY_LEN)] {
1071 let key = random_aes_key(key_len);
1072 let encrypting_key_creator = || {
1073 let key = UnboundCipherKey::new(alg, &key).unwrap();
1074 StreamingEncryptingKey::$constructor(key).unwrap()
1075 };
1076 let decrypting_key_creator = |decryption_ctx: DecryptionContext| {
1077 let key = UnboundCipherKey::new(alg, &key).unwrap();
1078 StreamingDecryptingKey::$constructor(key, decryption_ctx).unwrap()
1079 };
1080 run_step_matrix(|n, step| {
1084 let canary = OUTPUT_CANARIES[(n + step) % OUTPUT_CANARIES.len()];
1085 $helper(
1086 encrypting_key_creator,
1087 decrypting_key_creator,
1088 n,
1089 step,
1090 canary,
1091 );
1092 });
1093 }
1094 }
1095 };
1096 }
1097
1098 step_roundtrip_tests!(
1099 test_step_cbc,
1100 cbc_pkcs7,
1101 helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes
1102 );
1103 step_roundtrip_tests!(
1104 test_step_ctr,
1105 ctr,
1106 helper_test_ctr_stream_encrypt_step_n_bytes
1107 );
1108 step_roundtrip_tests!(
1109 test_step_cfb128,
1110 cfb128,
1111 helper_test_cfb128_stream_encrypt_step_n_bytes
1112 );
1113 step_roundtrip_tests!(
1114 test_step_ecb_pkcs7,
1115 ecb_pkcs7,
1116 helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes
1117 );
1118 step_roundtrip_tests!(
1119 test_step_cbc_less_safe,
1120 cbc_pkcs7,
1121 helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes_less_safe
1122 );
1123 step_roundtrip_tests!(
1124 test_step_ctr_less_safe,
1125 ctr,
1126 helper_test_ctr_stream_encrypt_step_n_bytes_less_safe
1127 );
1128 step_roundtrip_tests!(
1129 test_step_cfb128_less_safe,
1130 cfb128,
1131 helper_test_cfb128_stream_encrypt_step_n_bytes_less_safe
1132 );
1133 step_roundtrip_tests!(
1134 test_step_ecb_pkcs7_less_safe,
1135 ecb_pkcs7,
1136 helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes_less_safe
1137 );
1138
1139 #[derive(Clone, Copy)]
1140 enum UpdateVariant {
1141 Documented,
1143 LessSafe,
1145 }
1146
1147 fn assert_block_aligned_updates_stay_in_slice(
1152 mut key: StreamingDecryptingKey,
1153 variant: UpdateVariant,
1154 chunks: usize,
1155 canary: u8,
1156 ) {
1157 let block_len = key.algorithm().block_len();
1158 let ciphertext = vec![0x42u8; chunks * block_len];
1159 let mut output = vec![canary; ciphertext.len() + 3 * block_len];
1162 let mut out_idx = 0usize;
1163
1164 for chunk in ciphertext.chunks(block_len) {
1165 let min_outsize = match variant {
1166 UpdateVariant::Documented => chunk.len() + block_len - 1,
1167 UpdateVariant::LessSafe => less_safe_min_out(block_len, out_idx, chunk.len()),
1168 };
1169 let out_end = out_idx + min_outsize;
1170 out_idx += apply_update_with_canary(&mut output, out_idx, out_end, canary, |out| {
1171 match variant {
1172 UpdateVariant::Documented => key.update(chunk, out),
1173 UpdateVariant::LessSafe => key.less_safe_update(chunk, out),
1174 }
1175 .expect("update rejected a documented-minimum output slice")
1176 .written()
1177 .len()
1178 });
1179 }
1180 }
1181
1182 const REGRESSION_CHUNKS: usize = 4;
1185
1186 macro_rules! decrypt_output_bounds_tests {
1187 ($name:ident, $alg:expr, $key_len:expr, $constructor:ident, $context:expr) => {
1188 paste! {
1189 #[test]
1190 fn [<test_ $name _update_stays_in_output_slice>]() {
1191 for canary in OUTPUT_CANARIES {
1192 let unbound =
1193 UnboundCipherKey::new($alg, &random_aes_key($key_len)).unwrap();
1194 let key =
1195 StreamingDecryptingKey::$constructor(unbound, $context).unwrap();
1196 assert_block_aligned_updates_stay_in_slice(
1197 key,
1198 UpdateVariant::Documented,
1199 REGRESSION_CHUNKS,
1200 canary,
1201 );
1202 }
1203 }
1204
1205 #[test]
1206 fn [<test_ $name _less_safe_update_stays_in_output_slice>]() {
1207 for canary in OUTPUT_CANARIES {
1208 let unbound =
1209 UnboundCipherKey::new($alg, &random_aes_key($key_len)).unwrap();
1210 let key =
1211 StreamingDecryptingKey::$constructor(unbound, $context).unwrap();
1212 assert_block_aligned_updates_stay_in_slice(
1213 key,
1214 UpdateVariant::LessSafe,
1215 REGRESSION_CHUNKS,
1216 canary,
1217 );
1218 }
1219 }
1220 }
1221 };
1222 }
1223
1224 decrypt_output_bounds_tests!(
1225 aes_128_cbc_pkcs7,
1226 &AES_128,
1227 AES_128_KEY_LEN,
1228 cbc_pkcs7,
1229 DecryptionContext::Iv128(FixedLength::from([0u8; IV_LEN_128_BIT]))
1230 );
1231 decrypt_output_bounds_tests!(
1232 aes_256_cbc_pkcs7,
1233 &AES_256,
1234 AES_256_KEY_LEN,
1235 cbc_pkcs7,
1236 DecryptionContext::Iv128(FixedLength::from([0u8; IV_LEN_128_BIT]))
1237 );
1238 decrypt_output_bounds_tests!(
1239 aes_128_ecb_pkcs7,
1240 &AES_128,
1241 AES_128_KEY_LEN,
1242 ecb_pkcs7,
1243 DecryptionContext::None
1244 );
1245 decrypt_output_bounds_tests!(
1246 aes_256_ecb_pkcs7,
1247 &AES_256,
1248 AES_256_KEY_LEN,
1249 ecb_pkcs7,
1250 DecryptionContext::None
1251 );
1252
1253 macro_rules! streaming_cipher_kat {
1254 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal, $from_step:literal, $to_step:literal) => {
1255 #[test]
1256 fn $name() {
1257 let key = from_hex($key).unwrap();
1258 let input = from_hex($plaintext).unwrap();
1259 let expected_ciphertext = from_hex($ciphertext).unwrap();
1260 let iv = from_hex($iv).unwrap();
1261
1262 for step in ($from_step..=$to_step) {
1263 let ec = EncryptionContext::Iv128(
1264 FixedLength::<IV_LEN_128_BIT>::try_from(iv.as_slice()).unwrap(),
1265 );
1266
1267 let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
1268
1269 let encrypting_key =
1270 StreamingEncryptingKey::new(unbound_key, $mode, ec).unwrap();
1271
1272 let (ciphertext, decrypt_ctx) =
1273 step_encrypt(encrypting_key, &input, step, OUTPUT_CANARIES[0]);
1274
1275 assert_eq!(expected_ciphertext.as_slice(), ciphertext.as_ref());
1276
1277 let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
1278 let decrypting_key =
1279 StreamingDecryptingKey::new(unbound_key2, $mode, decrypt_ctx).unwrap();
1280
1281 let plaintext =
1282 step_decrypt(decrypting_key, &ciphertext, step, OUTPUT_CANARIES[1]);
1283 assert_eq!(input.as_slice(), plaintext.as_ref());
1284 }
1285 }
1286 };
1287 ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal, $from_step:literal, $to_step:literal) => {
1288 #[test]
1289 fn $name() {
1290 let key = from_hex($key).unwrap();
1291 let input = from_hex($plaintext).unwrap();
1292 let expected_ciphertext = from_hex($ciphertext).unwrap();
1293
1294 for step in ($from_step..=$to_step) {
1295 let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
1296
1297 let encrypting_key =
1298 StreamingEncryptingKey::new(unbound_key, $mode, EncryptionContext::None)
1299 .unwrap();
1300
1301 let (ciphertext, decrypt_ctx) =
1302 step_encrypt(encrypting_key, &input, step, OUTPUT_CANARIES[0]);
1303
1304 assert_eq!(expected_ciphertext.as_slice(), ciphertext.as_ref());
1305
1306 let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
1307 let decrypting_key =
1308 StreamingDecryptingKey::new(unbound_key2, $mode, decrypt_ctx).unwrap();
1309
1310 let plaintext =
1311 step_decrypt(decrypting_key, &ciphertext, step, OUTPUT_CANARIES[1]);
1312 assert_eq!(input.as_slice(), plaintext.as_ref());
1313 }
1314 }
1315 };
1316 }
1317
1318 streaming_cipher_kat!(
1319 test_iv_aes_128_ctr_16_bytes,
1320 &AES_128,
1321 OperatingMode::CTR,
1322 "000102030405060708090a0b0c0d0e0f",
1323 "00000000000000000000000000000000",
1324 "00112233445566778899aabbccddeeff",
1325 "c6b01904c3da3df5e7d62bd96d153686",
1326 2,
1327 9
1328 );
1329 streaming_cipher_kat!(
1330 test_iv_aes_256_ctr_15_bytes,
1331 &AES_256,
1332 OperatingMode::CTR,
1333 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1334 "00000000000000000000000000000000",
1335 "00112233445566778899aabbccddee",
1336 "f28122856e1cf9a7216a30d111f399",
1337 2,
1338 9
1339 );
1340
1341 streaming_cipher_kat!(
1342 test_openssl_aes_128_ctr_15_bytes,
1343 &AES_128,
1344 OperatingMode::CTR,
1345 "244828580821c1652582c76e34d299f5",
1346 "093145d5af233f46072a5eb5adc11aa1",
1347 "3ee38cec171e6cf466bf0df98aa0e1",
1348 "bd7d928f60e3422d96b3f8cd614eb2",
1349 2,
1350 9
1351 );
1352
1353 streaming_cipher_kat!(
1354 test_openssl_aes_256_ctr_15_bytes,
1355 &AES_256,
1356 OperatingMode::CTR,
1357 "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1358 "f028ecb053f801102d11fccc9d303a27",
1359 "eca7285d19f3c20e295378460e8729",
1360 "b5098e5e788de6ac2f2098eb2fc6f8",
1361 2,
1362 9
1363 );
1364
1365 streaming_cipher_kat!(
1366 test_iv_aes_128_cbc_16_bytes,
1367 &AES_128,
1368 OperatingMode::CBC,
1369 "000102030405060708090a0b0c0d0e0f",
1370 "00000000000000000000000000000000",
1371 "00112233445566778899aabbccddeeff",
1372 "69c4e0d86a7b0430d8cdb78070b4c55a9e978e6d16b086570ef794ef97984232",
1373 2,
1374 9
1375 );
1376
1377 streaming_cipher_kat!(
1378 test_iv_aes_256_cbc_15_bytes,
1379 &AES_256,
1380 OperatingMode::CBC,
1381 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1382 "00000000000000000000000000000000",
1383 "00112233445566778899aabbccddee",
1384 "2ddfb635a651a43f582997966840ca0c",
1385 2,
1386 9
1387 );
1388
1389 streaming_cipher_kat!(
1390 test_openssl_aes_128_cbc_15_bytes,
1391 &AES_128,
1392 OperatingMode::CBC,
1393 "053304bb3899e1d99db9d29343ea782d",
1394 "b5313560244a4822c46c2a0c9d0cf7fd",
1395 "a3e4c990356c01f320043c3d8d6f43",
1396 "ad96993f248bd6a29760ec7ccda95ee1",
1397 2,
1398 9
1399 );
1400
1401 streaming_cipher_kat!(
1402 test_openssl_aes_128_cbc_16_bytes,
1403 &AES_128,
1404 OperatingMode::CBC,
1405 "95af71f1c63e4a1d0b0b1a27fb978283",
1406 "89e40797dca70197ff87d3dbb0ef2802",
1407 "aece7b5e3c3df1ffc9802d2dfe296dc7",
1408 "301b5dab49fb11e919d0d39970d06739301919743304f23f3cbc67d28564b25b",
1409 2,
1410 9
1411 );
1412
1413 streaming_cipher_kat!(
1414 test_openssl_aes_256_cbc_15_bytes,
1415 &AES_256,
1416 OperatingMode::CBC,
1417 "d369e03e9752784917cc7bac1db7399598d9555e691861d9dd7b3292a693ef57",
1418 "1399bb66b2f6ad99a7f064140eaaa885",
1419 "7385f5784b85bf0a97768ddd896d6d",
1420 "4351082bac9b4593ae8848cc9dfb5a01",
1421 2,
1422 9
1423 );
1424
1425 streaming_cipher_kat!(
1426 test_openssl_aes_256_cbc_16_bytes,
1427 &AES_256,
1428 OperatingMode::CBC,
1429 "d4a8206dcae01242f9db79a4ecfe277d0f7bb8ccbafd8f9809adb39f35aa9b41",
1430 "24f6076548fb9d93c8f7ed9f6e661ef9",
1431 "a39c1fdf77ea3e1f18178c0ec237c70a",
1432 "f1af484830a149ee0387b854d65fe87ca0e62efc1c8e6909d4b9ab8666470453",
1433 2,
1434 9
1435 );
1436
1437 streaming_cipher_kat!(
1438 test_openssl_aes_128_cfb128_16_bytes,
1439 &AES_128,
1440 OperatingMode::CFB128,
1441 "5c353f739429bbd48b7e3f9a76facf4d",
1442 "7b2c7ce17a9b6a59a9e64253b98c8cd1",
1443 "add1bcebeaabe9423d4e916400e877c5",
1444 "8440ec442e4135a613ddb2ce26107e10",
1445 2,
1446 9
1447 );
1448
1449 streaming_cipher_kat!(
1450 test_openssl_aes_128_cfb128_15_bytes,
1451 &AES_128,
1452 OperatingMode::CFB128,
1453 "e1f39d70ad378efc1ac318aa8ac4489f",
1454 "ec78c3d54fff2fe09678c7883024ddce",
1455 "b8c905004b2a92a323769f1b8dc1b2",
1456 "964c3e9bf8bf2a3cca02d8e2e75608",
1457 2,
1458 9
1459 );
1460
1461 streaming_cipher_kat!(
1462 test_openssl_aes_256_cfb128_16_bytes,
1463 &AES_256,
1464 OperatingMode::CFB128,
1465 "0e8117d0984d6acb957a5d6ca526a12fa612ce5de2daadebd42c14d28a0a192e",
1466 "09147a153b230a40cd7bf4197ad0e825",
1467 "13f4540a4e06394148ade31a6f678787",
1468 "250e590e47b7613b7d0a53f684e970d6",
1469 2,
1470 9
1471 );
1472
1473 streaming_cipher_kat!(
1474 test_openssl_aes_256_cfb128_15_bytes,
1475 &AES_256,
1476 OperatingMode::CFB128,
1477 "5cb17d8d5b9dbd81e4f1e0a2c82ebf36cf61156388fb7abf99d4526622858225",
1478 "13c77415ec24f3e2f784f228478a85be",
1479 "3efa583df4405aab61e18155aa7e0d",
1480 "c1f2ffe8aa5064199e8f4f1b388303",
1481 2,
1482 9
1483 );
1484
1485 streaming_cipher_kat!(
1486 test_openssl_aes_128_ecb_pkcs7_16_bytes,
1487 &AES_128,
1488 OperatingMode::ECB,
1489 "a1b7cd124f9824a1532d8440f8136788",
1490 "388118e6848b0cea97401707a754d7a1",
1491 "19b7c7f5d9c2bda3f957e9e7d20847828d5eb5624bcbf221014063a87b38d133",
1492 2,
1493 9
1494 );
1495
1496 streaming_cipher_kat!(
1497 test_openssl_aes_128_ecb_pkcs7_15_bytes,
1498 &AES_128,
1499 OperatingMode::ECB,
1500 "d10e12accb837aaffbb284448e53138c",
1501 "b21cfd1c9e6e7e6e912c82c7dd1aa8",
1502 "3d1168e61df34b51c6ab6745c20ee881",
1503 2,
1504 9
1505 );
1506
1507 streaming_cipher_kat!(
1508 test_openssl_aes_256_ecb_pkcs7_16_bytes,
1509 &AES_256,
1510 OperatingMode::ECB,
1511 "0600f4ad4eda4bc8e3e99592abdfce7eb08fee0ccc801c5ccee26134bcaafbbd",
1512 "516b45cb1342239a549bd8c1d5998f98",
1513 "854c593555a213e4a862c6f66aa4a79631faca131eba6f163e5cd3940e9c0a57",
1514 2,
1515 9
1516 );
1517
1518 streaming_cipher_kat!(
1519 test_openssl_aes_256_ecb_pkcs7_15_bytes,
1520 &AES_256,
1521 OperatingMode::ECB,
1522 "80f235756c8f70094ae1f99a95a599c27c4452a4b8412fd934e2b253f7098508",
1523 "2235590b90190d7a1dc2464a0205ad",
1524 "8547d8ac8dc6d9cebb2dc77a7034bb67",
1525 2,
1526 9
1527 );
1528
1529 #[test]
1530 fn test_new_rejects_none_context_for_iv_required_modes() {
1531 let key_bytes = [0u8; AES_128_KEY_LEN];
1532 for mode in [
1533 OperatingMode::CBC,
1534 OperatingMode::CTR,
1535 OperatingMode::CFB128,
1536 ] {
1537 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1538 assert!(
1539 StreamingEncryptingKey::new(key, mode, EncryptionContext::None).is_err(),
1540 "AES + {mode:?} + EncryptionContext::None should be rejected"
1541 );
1542
1543 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1544 assert!(
1545 StreamingDecryptingKey::new(key, mode, DecryptionContext::None).is_err(),
1546 "AES + {mode:?} + DecryptionContext::None should be rejected"
1547 );
1548 }
1549 }
1550
1551 #[test]
1552 fn test_new_accepts_none_context_for_ecb() {
1553 let key_bytes = [0u8; AES_128_KEY_LEN];
1554
1555 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1556 assert!(
1557 StreamingEncryptingKey::new(key, OperatingMode::ECB, EncryptionContext::None).is_ok()
1558 );
1559
1560 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1561 assert!(
1562 StreamingDecryptingKey::new(key, OperatingMode::ECB, DecryptionContext::None).is_ok()
1563 );
1564 }
1565
1566 #[cfg(feature = "legacy-des")]
1567 #[test]
1568 fn test_new_rejects_iv64_context_for_aes() {
1569 let key_bytes = [0u8; AES_128_KEY_LEN];
1570 for mode in [
1571 OperatingMode::CBC,
1572 OperatingMode::CTR,
1573 OperatingMode::CFB128,
1574 ] {
1575 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1576 let context = EncryptionContext::Iv64(FixedLength::new().unwrap());
1577 assert!(
1578 StreamingEncryptingKey::new(key, mode, context).is_err(),
1579 "AES + {mode:?} + EncryptionContext::Iv64 should be rejected"
1580 );
1581
1582 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1583 let context = DecryptionContext::Iv64(FixedLength::new().unwrap());
1584 assert!(
1585 StreamingDecryptingKey::new(key, mode, context).is_err(),
1586 "AES + {mode:?} + DecryptionContext::Iv64 should be rejected"
1587 );
1588 }
1589 }
1590
1591 #[cfg(feature = "legacy-des")]
1592 #[test]
1593 #[allow(deprecated)]
1594 fn test_new_rejects_iv128_context_for_des() {
1595 let key_bytes = from_hex("0123456789abcdef").unwrap();
1596
1597 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1598 let context = EncryptionContext::Iv128(FixedLength::new().unwrap());
1599 assert!(
1600 StreamingEncryptingKey::new(key, OperatingMode::CBC, context).is_err(),
1601 "DES + CBC + EncryptionContext::Iv128 should be rejected"
1602 );
1603
1604 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1605 let context = DecryptionContext::Iv128(FixedLength::new().unwrap());
1606 assert!(
1607 StreamingDecryptingKey::new(key, OperatingMode::CBC, context).is_err(),
1608 "DES + CBC + DecryptionContext::Iv128 should be rejected"
1609 );
1610 }
1611
1612 #[cfg(feature = "legacy-des")]
1613 #[test]
1614 #[allow(deprecated)]
1615 fn test_new_accepts_valid_des_contexts() {
1616 let key_bytes = from_hex("0123456789abcdef").unwrap();
1617
1618 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1619 assert!(
1620 StreamingEncryptingKey::new(key, OperatingMode::ECB, EncryptionContext::None).is_ok()
1621 );
1622 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1623 assert!(
1624 StreamingDecryptingKey::new(key, OperatingMode::ECB, DecryptionContext::None).is_ok()
1625 );
1626
1627 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1628 let context = EncryptionContext::Iv64(FixedLength::new().unwrap());
1629 assert!(StreamingEncryptingKey::new(key, OperatingMode::CBC, context).is_ok());
1630
1631 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1632 let context = DecryptionContext::Iv64(FixedLength::new().unwrap());
1633 assert!(StreamingDecryptingKey::new(key, OperatingMode::CBC, context).is_ok());
1634 }
1635}