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 cfb8(key: UnboundCipherKey) -> Result<Self, Unspecified> {
431 let context = key
432 .algorithm()
433 .new_encryption_context(OperatingMode::CFB8)?;
434 Self::less_safe_cfb8(key, context)
435 }
436
437 pub fn less_safe_cfb8(
453 key: UnboundCipherKey,
454 context: EncryptionContext,
455 ) -> Result<Self, Unspecified> {
456 Self::new(key, OperatingMode::CFB8, context)
457 }
458
459 pub fn cfb1(key: UnboundCipherKey) -> Result<Self, Unspecified> {
471 let context = key
472 .algorithm()
473 .new_encryption_context(OperatingMode::CFB1)?;
474 Self::less_safe_cfb1(key, context)
475 }
476
477 pub fn less_safe_cfb1(
496 key: UnboundCipherKey,
497 context: EncryptionContext,
498 ) -> Result<Self, Unspecified> {
499 Self::new(key, OperatingMode::CFB1, context)
500 }
501
502 pub fn ofb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
511 let context = key.algorithm().new_encryption_context(OperatingMode::OFB)?;
512 Self::less_safe_ofb(key, context)
513 }
514
515 pub fn less_safe_ofb(
531 key: UnboundCipherKey,
532 context: EncryptionContext,
533 ) -> Result<Self, Unspecified> {
534 Self::new(key, OperatingMode::OFB, context)
535 }
536
537 pub fn less_safe_cbc_pkcs7(
553 key: UnboundCipherKey,
554 context: EncryptionContext,
555 ) -> Result<Self, Unspecified> {
556 Self::new(key, OperatingMode::CBC, context)
557 }
558}
559
560pub struct StreamingDecryptingKey {
562 algorithm: &'static Algorithm,
563 mode: OperatingMode,
564 cipher_ctx: LcPtr<EVP_CIPHER_CTX>,
565 output_generated: usize,
566}
567
568unsafe impl Send for StreamingDecryptingKey {}
569
570impl StreamingDecryptingKey {
571 #[allow(clippy::needless_pass_by_value)]
572 fn new(
573 key: UnboundCipherKey,
574 mode: OperatingMode,
575 context: DecryptionContext,
576 ) -> Result<Self, Unspecified> {
577 let algorithm = key.algorithm();
578 if !algorithm.supports_mode(mode) {
579 return Err(Unspecified);
580 }
581 if !algorithm.is_valid_decryption_context(mode, &context) {
582 return Err(Unspecified);
583 }
584 key.validate_key_material()?;
586 let mut cipher_ctx = LcPtr::new(unsafe { EVP_CIPHER_CTX_new() })?;
587 let cipher = mode.evp_cipher(key.algorithm);
588 let key_bytes = key.key_bytes.as_ref();
589 if key_bytes.len()
590 != <usize>::try_from(unsafe { EVP_CIPHER_key_length(cipher.as_const_ptr()) }).unwrap()
591 {
592 return Err(Unspecified);
593 }
594
595 match &context {
596 ctx @ DecryptionContext::Iv128(..) => {
597 let iv = <&[u8]>::try_from(ctx)?;
598 debug_assert_eq!(
599 iv.len(),
600 <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
601 .unwrap()
602 );
603 evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
604 }
605 #[cfg(feature = "legacy-des")]
606 ctx @ DecryptionContext::Iv64(..) => {
607 let iv = <&[u8]>::try_from(ctx)?;
608 debug_assert_eq!(
609 iv.len(),
610 <usize>::try_from(unsafe { EVP_CIPHER_iv_length(cipher.as_const_ptr()) })
611 .unwrap()
612 );
613 evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, Some(iv))?;
614 }
615 DecryptionContext::None => {
616 evp_decrypt_init(&mut cipher_ctx, &cipher, key_bytes, None)?;
617 }
618 }
619
620 Ok(Self {
621 algorithm,
622 mode,
623 cipher_ctx,
624 output_generated: 0,
625 })
626 }
627
628 fn update_internal<'a>(
629 &mut self,
630 input: &[u8],
631 output: &'a mut [u8],
632 min_outsize: usize,
633 ) -> Result<BufferUpdate<'a>, Unspecified> {
634 if output.len() < min_outsize {
635 return Err(Unspecified);
636 }
637 let mut outlen: i32 = 0;
638 let inlen: i32 = input.len().try_into()?;
639
640 if 1 != unsafe {
641 EVP_DecryptUpdate(
642 self.cipher_ctx.as_mut_ptr(),
643 output.as_mut_ptr(),
644 &mut outlen,
645 input.as_ptr(),
646 inlen,
647 )
648 } {
649 return Err(Unspecified);
650 }
651 let outlen: usize = outlen.try_into()?;
652 debug_assert!(outlen <= min_outsize);
653 self.output_generated += outlen;
654 assert!(outlen <= output.len());
657
658 Ok(BufferUpdate::new(output, outlen))
659 }
660
661 pub fn update<'a>(
672 &mut self,
673 input: &[u8],
674 output: &'a mut [u8],
675 ) -> Result<BufferUpdate<'a>, Unspecified> {
676 let min_outsize = input
677 .len()
678 .checked_add(self.algorithm().block_len())
679 .ok_or(Unspecified)?
680 .checked_sub(1)
681 .ok_or(Unspecified)?;
682 self.update_internal(input, output, min_outsize)
683 }
684
685 pub fn less_safe_update<'a>(
707 &mut self,
708 input: &[u8],
709 output: &'a mut [u8],
710 ) -> Result<BufferUpdate<'a>, Unspecified> {
711 let next_total = self
712 .output_generated
713 .checked_add(input.len())
714 .ok_or(Unspecified)?;
715 let extra_buffer_size = (self.algorithm().block_len
716 - next_total.rem_euclid(self.algorithm().block_len))
717 .rem_euclid(self.algorithm().block_len);
718 let min_outsize = input
719 .len()
720 .checked_add(extra_buffer_size)
721 .ok_or(Unspecified)?;
722 self.update_internal(input, output, min_outsize)
723 }
724
725 pub fn finish(mut self, output: &mut [u8]) -> Result<BufferUpdate<'_>, Unspecified> {
734 if output.len() < self.algorithm().block_len() {
735 return Err(Unspecified);
736 }
737 let mut outlen: i32 = 0;
738
739 if 1 != indicator_check!(unsafe {
740 EVP_DecryptFinal_ex(
741 self.cipher_ctx.as_mut_ptr(),
742 output.as_mut_ptr(),
743 &mut outlen,
744 )
745 }) {
746 return Err(Unspecified);
747 }
748 let outlen: usize = outlen.try_into()?;
749 debug_assert!(outlen <= self.algorithm().block_len());
750 Ok(BufferUpdate::new(output, outlen))
751 }
752
753 #[must_use]
755 pub fn mode(&self) -> OperatingMode {
756 self.mode
757 }
758
759 #[must_use]
761 pub fn algorithm(&self) -> &'static Algorithm {
762 self.algorithm
763 }
764
765 pub fn ctr(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
774 Self::new(key, OperatingMode::CTR, context)
775 }
776
777 pub fn cbc_pkcs7(
788 key: UnboundCipherKey,
789 context: DecryptionContext,
790 ) -> Result<Self, Unspecified> {
791 Self::new(key, OperatingMode::CBC, context)
792 }
793
794 pub fn cfb128(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
803 Self::new(key, OperatingMode::CFB128, context)
804 }
805
806 pub fn cfb8(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
815 Self::new(key, OperatingMode::CFB8, context)
816 }
817
818 pub fn cfb1(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
830 Self::new(key, OperatingMode::CFB1, context)
831 }
832
833 pub fn ofb(key: UnboundCipherKey, context: DecryptionContext) -> Result<Self, Unspecified> {
842 Self::new(key, OperatingMode::OFB, context)
843 }
844
845 pub fn ecb_pkcs7(
860 key: UnboundCipherKey,
861 context: DecryptionContext,
862 ) -> Result<Self, Unspecified> {
863 Self::new(key, OperatingMode::ECB, context)
864 }
865}
866
867#[cfg(test)]
868mod tests {
869 #[cfg(feature = "legacy-des")]
870 #[allow(deprecated)]
871 use crate::cipher::DES_FOR_LEGACY_USE_ONLY;
872 use crate::cipher::{
873 DecryptionContext, EncryptionContext, OperatingMode, StreamingDecryptingKey,
874 StreamingEncryptingKey, UnboundCipherKey, AES_128, AES_128_KEY_LEN, AES_256,
875 AES_256_KEY_LEN,
876 };
877 use crate::iv::{FixedLength, IV_LEN_128_BIT};
878 use crate::rand::{SecureRandom, SystemRandom};
879 use crate::test::from_hex;
880 use paste::*;
881
882 const OUTPUT_CANARIES: [u8; 2] = [0xAA, 0x55];
887
888 fn assert_no_write_past(output: &[u8], slice_start: usize, slice_end: usize, canary: u8) {
889 let slice_len = slice_end - slice_start;
890 let tail = &output[slice_end..output.len().min(slice_end + 16)];
891 assert!(
892 output[slice_end..].iter().all(|&b| b == canary),
893 "wrote past the provided {slice_len}-byte output slice at buffer offsets \
894 {slice_start}..{slice_end} \
895 (canary {canary:#04x}, bytes at {slice_end}..: {tail:02x?})"
896 );
897 }
898
899 fn apply_update_with_canary(
900 output: &mut [u8],
901 out_idx: usize,
902 out_end: usize,
903 canary: u8,
904 op: impl FnOnce(&mut [u8]) -> usize,
905 ) -> usize {
906 output[out_end..].fill(canary);
907 let written = op(&mut output[out_idx..out_end]);
908 assert_no_write_past(output, out_idx, out_end, canary);
909 written
910 }
911
912 fn step_encrypt_with_updater<F>(
916 mut encrypting_key: StreamingEncryptingKey,
917 plaintext: &[u8],
918 step: usize,
919 canary: u8,
920 mut updater: F,
921 ) -> (Box<[u8]>, DecryptionContext)
922 where
923 F: FnMut(&mut StreamingEncryptingKey, &[u8], &mut [u8], usize, usize, usize) -> usize,
924 {
925 let alg = encrypting_key.algorithm();
926 let mode = encrypting_key.mode();
927 let block_len = alg.block_len();
928 let n = plaintext.len();
929 let mut ciphertext = vec![canary; n + 2 * block_len];
932
933 let mut in_idx: usize = 0;
934 let mut out_idx: usize = 0;
935 loop {
936 let mut in_end = in_idx + step;
937 if in_end > n {
938 in_end = n;
939 }
940 let written = updater(
941 &mut encrypting_key,
942 &plaintext[in_idx..in_end],
943 &mut ciphertext,
944 out_idx,
945 block_len,
946 step,
947 );
948 in_idx += step;
949 out_idx += written;
950 if in_idx >= n {
951 break;
952 }
953 }
954 let out_end = out_idx + block_len;
955 ciphertext[out_end..].fill(canary);
956 let (decrypt_iv, written_len) = {
957 let (decrypt_iv, output) = encrypting_key
958 .finish(&mut ciphertext[out_idx..out_end])
959 .unwrap();
960 (decrypt_iv, output.written().len())
961 };
962 assert_no_write_past(&ciphertext, out_idx, out_end, canary);
963 ciphertext.truncate(out_idx + written_len);
964 match mode {
965 OperatingMode::CBC | OperatingMode::ECB => {
966 assert!(ciphertext.len() > plaintext.len());
967 assert!(ciphertext.len() <= plaintext.len() + block_len);
968 }
969 _ => {
970 assert_eq!(ciphertext.len(), plaintext.len());
971 }
972 }
973
974 (ciphertext.into_boxed_slice(), decrypt_iv)
975 }
976
977 fn step_decrypt_with_updater<F>(
981 mut decrypting_key: StreamingDecryptingKey,
982 ciphertext: &[u8],
983 step: usize,
984 canary: u8,
985 mut updater: F,
986 ) -> Box<[u8]>
987 where
988 F: FnMut(&mut StreamingDecryptingKey, &[u8], &mut [u8], usize, usize, usize) -> usize,
989 {
990 let alg = decrypting_key.algorithm();
991 let mode = decrypting_key.mode();
992 let block_len = alg.block_len();
993 let n = ciphertext.len();
994 let mut plaintext = vec![canary; n + 2 * block_len];
995
996 let mut in_idx: usize = 0;
997 let mut out_idx: usize = 0;
998 loop {
999 let mut in_end = in_idx + step;
1000 if in_end > n {
1001 in_end = n;
1002 }
1003 let written = updater(
1004 &mut decrypting_key,
1005 &ciphertext[in_idx..in_end],
1006 &mut plaintext,
1007 out_idx,
1008 block_len,
1009 step,
1010 );
1011 in_idx += step;
1012 out_idx += written;
1013 if in_idx >= n {
1014 break;
1015 }
1016 }
1017 let out_end = out_idx + block_len;
1018 plaintext[out_end..].fill(canary);
1019 let written_len = {
1020 let output = decrypting_key
1021 .finish(&mut plaintext[out_idx..out_end])
1022 .unwrap();
1023 output.written().len()
1024 };
1025 assert_no_write_past(&plaintext, out_idx, out_end, canary);
1026 plaintext.truncate(out_idx + written_len);
1027 match mode {
1028 OperatingMode::CBC | OperatingMode::ECB => {
1029 assert!(ciphertext.len() > plaintext.len());
1030 assert!(ciphertext.len() <= plaintext.len() + block_len);
1031 }
1032 _ => {
1033 assert_eq!(ciphertext.len(), plaintext.len());
1034 }
1035 }
1036 plaintext.into_boxed_slice()
1037 }
1038
1039 fn step_encrypt(
1040 encrypting_key: StreamingEncryptingKey,
1041 plaintext: &[u8],
1042 step: usize,
1043 canary: u8,
1044 ) -> (Box<[u8]>, DecryptionContext) {
1045 step_encrypt_with_updater(
1046 encrypting_key,
1047 plaintext,
1048 step,
1049 canary,
1050 |key, input, output, out_idx, block_len, _step| {
1051 let out_end = out_idx + input.len() + block_len - 1;
1052 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
1053 key.update(input, out).unwrap().written().len()
1054 })
1055 },
1056 )
1057 }
1058
1059 fn step_decrypt(
1060 decrypting_key: StreamingDecryptingKey,
1061 ciphertext: &[u8],
1062 step: usize,
1063 canary: u8,
1064 ) -> Box<[u8]> {
1065 step_decrypt_with_updater(
1066 decrypting_key,
1067 ciphertext,
1068 step,
1069 canary,
1070 |key, input, output, out_idx, block_len, _step| {
1071 let out_end = out_idx + input.len() + block_len - 1;
1072 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
1073 key.update(input, out).unwrap().written().len()
1074 })
1075 },
1076 )
1077 }
1078
1079 fn less_safe_min_out(block_len: usize, out_idx: usize, input_len: usize) -> usize {
1080 let next_total = out_idx + input_len;
1081 input_len + ((block_len - (next_total % block_len)) % block_len)
1082 }
1083
1084 fn step_encrypt_less_safe(
1085 encrypting_key: StreamingEncryptingKey,
1086 plaintext: &[u8],
1087 step: usize,
1088 canary: u8,
1089 ) -> (Box<[u8]>, DecryptionContext) {
1090 step_encrypt_with_updater(
1091 encrypting_key,
1092 plaintext,
1093 step,
1094 canary,
1095 |key, input, output, out_idx, block_len, step| {
1096 let min_out_len = less_safe_min_out(block_len, out_idx, input.len());
1097 if input.len() % block_len == 0 && step % block_len == 0 {
1098 assert_eq!(input.len(), min_out_len);
1100 }
1101 let out_end = out_idx + min_out_len;
1102 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
1103 key.less_safe_update(input, out).unwrap().written().len()
1104 })
1105 },
1106 )
1107 }
1108
1109 fn step_decrypt_less_safe(
1110 decrypting_key: StreamingDecryptingKey,
1111 ciphertext: &[u8],
1112 step: usize,
1113 canary: u8,
1114 ) -> Box<[u8]> {
1115 step_decrypt_with_updater(
1116 decrypting_key,
1117 ciphertext,
1118 step,
1119 canary,
1120 |key, input, output, out_idx, block_len, step| {
1121 let min_out_len = less_safe_min_out(block_len, out_idx, input.len());
1122 if input.len() % block_len == 0 && step % block_len == 0 {
1123 assert_eq!(input.len(), min_out_len);
1125 }
1126 let out_end = out_idx + min_out_len;
1127 apply_update_with_canary(output, out_idx, out_end, canary, |out| {
1128 key.less_safe_update(input, out).unwrap().written().len()
1129 })
1130 },
1131 )
1132 }
1133
1134 macro_rules! helper_stream_step_encrypt_test {
1135 ($mode:ident) => {
1136 paste! {
1137 fn [<helper_test_ $mode _stream_encrypt_step_n_bytes>](
1138 encrypting_key_creator: impl Fn() -> StreamingEncryptingKey,
1139 decrypting_key_creator: impl Fn(DecryptionContext) -> StreamingDecryptingKey,
1140 n: usize,
1141 step: usize,
1142 canary: u8,
1143 ) {
1144 let mut input = vec![0u8; n];
1145 let random = SystemRandom::new();
1146 random.fill(&mut input).unwrap();
1147
1148 let encrypting_key = encrypting_key_creator();
1149
1150 let (ciphertext, decrypt_iv) =
1151 step_encrypt(encrypting_key, &input, step, canary);
1152
1153 let decrypting_key = decrypting_key_creator(decrypt_iv);
1154
1155 let plaintext = step_decrypt(decrypting_key, &ciphertext, step, canary);
1156
1157 assert_eq!(input.as_slice(), &*plaintext);
1158 }
1159 }
1160 };
1161 ($mode:ident, less_safe) => {
1162 paste! {
1163 fn [<helper_test_ $mode _stream_encrypt_step_n_bytes_less_safe>](
1164 encrypting_key_creator: impl Fn() -> StreamingEncryptingKey,
1165 decrypting_key_creator: impl Fn(DecryptionContext) -> StreamingDecryptingKey,
1166 n: usize,
1167 step: usize,
1168 canary: u8,
1169 ) {
1170 let mut input = vec![0u8; n];
1171 let random = SystemRandom::new();
1172 random.fill(&mut input).unwrap();
1173
1174 let encrypting_key = encrypting_key_creator();
1175
1176 let (ciphertext, decrypt_iv) =
1177 step_encrypt_less_safe(encrypting_key, &input, step, canary);
1178
1179 let decrypting_key = decrypting_key_creator(decrypt_iv);
1180
1181 let plaintext =
1182 step_decrypt_less_safe(decrypting_key, &ciphertext, step, canary);
1183
1184 assert_eq!(input.as_slice(), &*plaintext);
1185 }
1186 }
1187 };
1188 }
1189
1190 helper_stream_step_encrypt_test!(cbc_pkcs7);
1191 helper_stream_step_encrypt_test!(ctr);
1192 helper_stream_step_encrypt_test!(cfb128);
1193 helper_stream_step_encrypt_test!(ecb_pkcs7);
1194 helper_stream_step_encrypt_test!(cfb1);
1195
1196 helper_stream_step_encrypt_test!(cbc_pkcs7, less_safe);
1197 helper_stream_step_encrypt_test!(ctr, less_safe);
1198 helper_stream_step_encrypt_test!(cfb128, less_safe);
1199 helper_stream_step_encrypt_test!(ecb_pkcs7, less_safe);
1200 helper_stream_step_encrypt_test!(cfb1, less_safe);
1201
1202 fn run_step_matrix(test: impl Fn(usize, usize)) {
1203 for i in 13..=21 {
1204 for j in 124..=131 {
1205 test(j, i);
1206 test(j, j - i);
1207 }
1208 }
1209 for j in 124..=131 {
1210 test(j, j);
1211 test(j, 256);
1212 test(j, 1);
1213 }
1214 }
1215
1216 fn random_aes_key(len: usize) -> Vec<u8> {
1217 let mut key = vec![0u8; len];
1218 SystemRandom::new().fill(&mut key).unwrap();
1219 key
1220 }
1221
1222 macro_rules! step_roundtrip_tests {
1223 ($name:ident, $constructor:ident, $helper:ident) => {
1224 #[test]
1225 fn $name() {
1226 for (alg, key_len) in [(&AES_128, AES_128_KEY_LEN), (&AES_256, AES_256_KEY_LEN)] {
1227 let key = random_aes_key(key_len);
1228 let encrypting_key_creator = || {
1229 let key = UnboundCipherKey::new(alg, &key).unwrap();
1230 StreamingEncryptingKey::$constructor(key).unwrap()
1231 };
1232 let decrypting_key_creator = |decryption_ctx: DecryptionContext| {
1233 let key = UnboundCipherKey::new(alg, &key).unwrap();
1234 StreamingDecryptingKey::$constructor(key, decryption_ctx).unwrap()
1235 };
1236 run_step_matrix(|n, step| {
1240 let canary = OUTPUT_CANARIES[(n + step) % OUTPUT_CANARIES.len()];
1241 $helper(
1242 encrypting_key_creator,
1243 decrypting_key_creator,
1244 n,
1245 step,
1246 canary,
1247 );
1248 });
1249 }
1250 }
1251 };
1252 }
1253
1254 step_roundtrip_tests!(
1255 test_step_cbc,
1256 cbc_pkcs7,
1257 helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes
1258 );
1259 step_roundtrip_tests!(
1260 test_step_ctr,
1261 ctr,
1262 helper_test_ctr_stream_encrypt_step_n_bytes
1263 );
1264 step_roundtrip_tests!(
1265 test_step_cfb128,
1266 cfb128,
1267 helper_test_cfb128_stream_encrypt_step_n_bytes
1268 );
1269 step_roundtrip_tests!(
1270 test_step_ecb_pkcs7,
1271 ecb_pkcs7,
1272 helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes
1273 );
1274 step_roundtrip_tests!(
1275 test_step_cfb1,
1276 cfb1,
1277 helper_test_cfb1_stream_encrypt_step_n_bytes
1278 );
1279 step_roundtrip_tests!(
1280 test_step_cbc_less_safe,
1281 cbc_pkcs7,
1282 helper_test_cbc_pkcs7_stream_encrypt_step_n_bytes_less_safe
1283 );
1284 step_roundtrip_tests!(
1285 test_step_ctr_less_safe,
1286 ctr,
1287 helper_test_ctr_stream_encrypt_step_n_bytes_less_safe
1288 );
1289 step_roundtrip_tests!(
1290 test_step_cfb128_less_safe,
1291 cfb128,
1292 helper_test_cfb128_stream_encrypt_step_n_bytes_less_safe
1293 );
1294 step_roundtrip_tests!(
1295 test_step_ecb_pkcs7_less_safe,
1296 ecb_pkcs7,
1297 helper_test_ecb_pkcs7_stream_encrypt_step_n_bytes_less_safe
1298 );
1299 step_roundtrip_tests!(
1300 test_step_cfb1_less_safe,
1301 cfb1,
1302 helper_test_cfb1_stream_encrypt_step_n_bytes_less_safe
1303 );
1304
1305 #[derive(Clone, Copy)]
1306 enum UpdateVariant {
1307 Documented,
1309 LessSafe,
1311 }
1312
1313 fn assert_block_aligned_updates_stay_in_slice(
1318 mut key: StreamingDecryptingKey,
1319 variant: UpdateVariant,
1320 chunks: usize,
1321 canary: u8,
1322 ) {
1323 let block_len = key.algorithm().block_len();
1324 let ciphertext = vec![0x42u8; chunks * block_len];
1325 let mut output = vec![canary; ciphertext.len() + 3 * block_len];
1328 let mut out_idx = 0usize;
1329
1330 for chunk in ciphertext.chunks(block_len) {
1331 let min_outsize = match variant {
1332 UpdateVariant::Documented => chunk.len() + block_len - 1,
1333 UpdateVariant::LessSafe => less_safe_min_out(block_len, out_idx, chunk.len()),
1334 };
1335 let out_end = out_idx + min_outsize;
1336 out_idx += apply_update_with_canary(&mut output, out_idx, out_end, canary, |out| {
1337 match variant {
1338 UpdateVariant::Documented => key.update(chunk, out),
1339 UpdateVariant::LessSafe => key.less_safe_update(chunk, out),
1340 }
1341 .expect("update rejected a documented-minimum output slice")
1342 .written()
1343 .len()
1344 });
1345 }
1346 }
1347
1348 const REGRESSION_CHUNKS: usize = 4;
1351
1352 macro_rules! decrypt_output_bounds_tests {
1353 ($name:ident, $alg:expr, $key_len:expr, $constructor:ident, $context:expr) => {
1354 paste! {
1355 #[test]
1356 fn [<test_ $name _update_stays_in_output_slice>]() {
1357 for canary in OUTPUT_CANARIES {
1358 let unbound =
1359 UnboundCipherKey::new($alg, &random_aes_key($key_len)).unwrap();
1360 let key =
1361 StreamingDecryptingKey::$constructor(unbound, $context).unwrap();
1362 assert_block_aligned_updates_stay_in_slice(
1363 key,
1364 UpdateVariant::Documented,
1365 REGRESSION_CHUNKS,
1366 canary,
1367 );
1368 }
1369 }
1370
1371 #[test]
1372 fn [<test_ $name _less_safe_update_stays_in_output_slice>]() {
1373 for canary in OUTPUT_CANARIES {
1374 let unbound =
1375 UnboundCipherKey::new($alg, &random_aes_key($key_len)).unwrap();
1376 let key =
1377 StreamingDecryptingKey::$constructor(unbound, $context).unwrap();
1378 assert_block_aligned_updates_stay_in_slice(
1379 key,
1380 UpdateVariant::LessSafe,
1381 REGRESSION_CHUNKS,
1382 canary,
1383 );
1384 }
1385 }
1386 }
1387 };
1388 }
1389
1390 decrypt_output_bounds_tests!(
1391 aes_128_cbc_pkcs7,
1392 &AES_128,
1393 AES_128_KEY_LEN,
1394 cbc_pkcs7,
1395 DecryptionContext::Iv128(FixedLength::from([0u8; IV_LEN_128_BIT]))
1396 );
1397 decrypt_output_bounds_tests!(
1398 aes_256_cbc_pkcs7,
1399 &AES_256,
1400 AES_256_KEY_LEN,
1401 cbc_pkcs7,
1402 DecryptionContext::Iv128(FixedLength::from([0u8; IV_LEN_128_BIT]))
1403 );
1404 decrypt_output_bounds_tests!(
1405 aes_128_ecb_pkcs7,
1406 &AES_128,
1407 AES_128_KEY_LEN,
1408 ecb_pkcs7,
1409 DecryptionContext::None
1410 );
1411 decrypt_output_bounds_tests!(
1412 aes_256_ecb_pkcs7,
1413 &AES_256,
1414 AES_256_KEY_LEN,
1415 ecb_pkcs7,
1416 DecryptionContext::None
1417 );
1418
1419 macro_rules! streaming_cipher_kat {
1420 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal, $from_step:literal, $to_step:literal) => {
1421 #[test]
1422 fn $name() {
1423 let key = from_hex($key).unwrap();
1424 let input = from_hex($plaintext).unwrap();
1425 let expected_ciphertext = from_hex($ciphertext).unwrap();
1426 let iv = from_hex($iv).unwrap();
1427
1428 for step in ($from_step..=$to_step) {
1429 let ec = EncryptionContext::Iv128(
1430 FixedLength::<IV_LEN_128_BIT>::try_from(iv.as_slice()).unwrap(),
1431 );
1432
1433 let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
1434
1435 let encrypting_key =
1436 StreamingEncryptingKey::new(unbound_key, $mode, ec).unwrap();
1437
1438 let (ciphertext, decrypt_ctx) =
1439 step_encrypt(encrypting_key, &input, step, OUTPUT_CANARIES[0]);
1440
1441 assert_eq!(expected_ciphertext.as_slice(), ciphertext.as_ref());
1442
1443 let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
1444 let decrypting_key =
1445 StreamingDecryptingKey::new(unbound_key2, $mode, decrypt_ctx).unwrap();
1446
1447 let plaintext =
1448 step_decrypt(decrypting_key, &ciphertext, step, OUTPUT_CANARIES[1]);
1449 assert_eq!(input.as_slice(), plaintext.as_ref());
1450 }
1451 }
1452 };
1453 ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal, $from_step:literal, $to_step:literal) => {
1454 #[test]
1455 fn $name() {
1456 let key = from_hex($key).unwrap();
1457 let input = from_hex($plaintext).unwrap();
1458 let expected_ciphertext = from_hex($ciphertext).unwrap();
1459
1460 for step in ($from_step..=$to_step) {
1461 let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
1462
1463 let encrypting_key =
1464 StreamingEncryptingKey::new(unbound_key, $mode, EncryptionContext::None)
1465 .unwrap();
1466
1467 let (ciphertext, decrypt_ctx) =
1468 step_encrypt(encrypting_key, &input, step, OUTPUT_CANARIES[0]);
1469
1470 assert_eq!(expected_ciphertext.as_slice(), ciphertext.as_ref());
1471
1472 let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
1473 let decrypting_key =
1474 StreamingDecryptingKey::new(unbound_key2, $mode, decrypt_ctx).unwrap();
1475
1476 let plaintext =
1477 step_decrypt(decrypting_key, &ciphertext, step, OUTPUT_CANARIES[1]);
1478 assert_eq!(input.as_slice(), plaintext.as_ref());
1479 }
1480 }
1481 };
1482 }
1483
1484 streaming_cipher_kat!(
1485 test_iv_aes_128_ctr_16_bytes,
1486 &AES_128,
1487 OperatingMode::CTR,
1488 "000102030405060708090a0b0c0d0e0f",
1489 "00000000000000000000000000000000",
1490 "00112233445566778899aabbccddeeff",
1491 "c6b01904c3da3df5e7d62bd96d153686",
1492 2,
1493 9
1494 );
1495 streaming_cipher_kat!(
1496 test_iv_aes_256_ctr_15_bytes,
1497 &AES_256,
1498 OperatingMode::CTR,
1499 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1500 "00000000000000000000000000000000",
1501 "00112233445566778899aabbccddee",
1502 "f28122856e1cf9a7216a30d111f399",
1503 2,
1504 9
1505 );
1506
1507 streaming_cipher_kat!(
1508 test_openssl_aes_128_ctr_15_bytes,
1509 &AES_128,
1510 OperatingMode::CTR,
1511 "244828580821c1652582c76e34d299f5",
1512 "093145d5af233f46072a5eb5adc11aa1",
1513 "3ee38cec171e6cf466bf0df98aa0e1",
1514 "bd7d928f60e3422d96b3f8cd614eb2",
1515 2,
1516 9
1517 );
1518
1519 streaming_cipher_kat!(
1520 test_openssl_aes_256_ctr_15_bytes,
1521 &AES_256,
1522 OperatingMode::CTR,
1523 "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1524 "f028ecb053f801102d11fccc9d303a27",
1525 "eca7285d19f3c20e295378460e8729",
1526 "b5098e5e788de6ac2f2098eb2fc6f8",
1527 2,
1528 9
1529 );
1530
1531 streaming_cipher_kat!(
1532 test_iv_aes_128_cbc_16_bytes,
1533 &AES_128,
1534 OperatingMode::CBC,
1535 "000102030405060708090a0b0c0d0e0f",
1536 "00000000000000000000000000000000",
1537 "00112233445566778899aabbccddeeff",
1538 "69c4e0d86a7b0430d8cdb78070b4c55a9e978e6d16b086570ef794ef97984232",
1539 2,
1540 9
1541 );
1542
1543 streaming_cipher_kat!(
1544 test_iv_aes_256_cbc_15_bytes,
1545 &AES_256,
1546 OperatingMode::CBC,
1547 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1548 "00000000000000000000000000000000",
1549 "00112233445566778899aabbccddee",
1550 "2ddfb635a651a43f582997966840ca0c",
1551 2,
1552 9
1553 );
1554
1555 streaming_cipher_kat!(
1556 test_openssl_aes_128_cbc_15_bytes,
1557 &AES_128,
1558 OperatingMode::CBC,
1559 "053304bb3899e1d99db9d29343ea782d",
1560 "b5313560244a4822c46c2a0c9d0cf7fd",
1561 "a3e4c990356c01f320043c3d8d6f43",
1562 "ad96993f248bd6a29760ec7ccda95ee1",
1563 2,
1564 9
1565 );
1566
1567 streaming_cipher_kat!(
1568 test_openssl_aes_128_cbc_16_bytes,
1569 &AES_128,
1570 OperatingMode::CBC,
1571 "95af71f1c63e4a1d0b0b1a27fb978283",
1572 "89e40797dca70197ff87d3dbb0ef2802",
1573 "aece7b5e3c3df1ffc9802d2dfe296dc7",
1574 "301b5dab49fb11e919d0d39970d06739301919743304f23f3cbc67d28564b25b",
1575 2,
1576 9
1577 );
1578
1579 streaming_cipher_kat!(
1580 test_openssl_aes_256_cbc_15_bytes,
1581 &AES_256,
1582 OperatingMode::CBC,
1583 "d369e03e9752784917cc7bac1db7399598d9555e691861d9dd7b3292a693ef57",
1584 "1399bb66b2f6ad99a7f064140eaaa885",
1585 "7385f5784b85bf0a97768ddd896d6d",
1586 "4351082bac9b4593ae8848cc9dfb5a01",
1587 2,
1588 9
1589 );
1590
1591 streaming_cipher_kat!(
1592 test_openssl_aes_256_cbc_16_bytes,
1593 &AES_256,
1594 OperatingMode::CBC,
1595 "d4a8206dcae01242f9db79a4ecfe277d0f7bb8ccbafd8f9809adb39f35aa9b41",
1596 "24f6076548fb9d93c8f7ed9f6e661ef9",
1597 "a39c1fdf77ea3e1f18178c0ec237c70a",
1598 "f1af484830a149ee0387b854d65fe87ca0e62efc1c8e6909d4b9ab8666470453",
1599 2,
1600 9
1601 );
1602
1603 streaming_cipher_kat!(
1604 test_openssl_aes_128_cfb128_16_bytes,
1605 &AES_128,
1606 OperatingMode::CFB128,
1607 "5c353f739429bbd48b7e3f9a76facf4d",
1608 "7b2c7ce17a9b6a59a9e64253b98c8cd1",
1609 "add1bcebeaabe9423d4e916400e877c5",
1610 "8440ec442e4135a613ddb2ce26107e10",
1611 2,
1612 9
1613 );
1614
1615 streaming_cipher_kat!(
1616 test_openssl_aes_128_cfb128_15_bytes,
1617 &AES_128,
1618 OperatingMode::CFB128,
1619 "e1f39d70ad378efc1ac318aa8ac4489f",
1620 "ec78c3d54fff2fe09678c7883024ddce",
1621 "b8c905004b2a92a323769f1b8dc1b2",
1622 "964c3e9bf8bf2a3cca02d8e2e75608",
1623 2,
1624 9
1625 );
1626
1627 streaming_cipher_kat!(
1628 test_openssl_aes_256_cfb128_16_bytes,
1629 &AES_256,
1630 OperatingMode::CFB128,
1631 "0e8117d0984d6acb957a5d6ca526a12fa612ce5de2daadebd42c14d28a0a192e",
1632 "09147a153b230a40cd7bf4197ad0e825",
1633 "13f4540a4e06394148ade31a6f678787",
1634 "250e590e47b7613b7d0a53f684e970d6",
1635 2,
1636 9
1637 );
1638
1639 streaming_cipher_kat!(
1640 test_openssl_aes_256_cfb128_15_bytes,
1641 &AES_256,
1642 OperatingMode::CFB128,
1643 "5cb17d8d5b9dbd81e4f1e0a2c82ebf36cf61156388fb7abf99d4526622858225",
1644 "13c77415ec24f3e2f784f228478a85be",
1645 "3efa583df4405aab61e18155aa7e0d",
1646 "c1f2ffe8aa5064199e8f4f1b388303",
1647 2,
1648 9
1649 );
1650
1651 streaming_cipher_kat!(
1652 test_openssl_aes_128_ecb_pkcs7_16_bytes,
1653 &AES_128,
1654 OperatingMode::ECB,
1655 "a1b7cd124f9824a1532d8440f8136788",
1656 "388118e6848b0cea97401707a754d7a1",
1657 "19b7c7f5d9c2bda3f957e9e7d20847828d5eb5624bcbf221014063a87b38d133",
1658 2,
1659 9
1660 );
1661
1662 streaming_cipher_kat!(
1663 test_openssl_aes_128_ecb_pkcs7_15_bytes,
1664 &AES_128,
1665 OperatingMode::ECB,
1666 "d10e12accb837aaffbb284448e53138c",
1667 "b21cfd1c9e6e7e6e912c82c7dd1aa8",
1668 "3d1168e61df34b51c6ab6745c20ee881",
1669 2,
1670 9
1671 );
1672
1673 streaming_cipher_kat!(
1674 test_openssl_aes_256_ecb_pkcs7_16_bytes,
1675 &AES_256,
1676 OperatingMode::ECB,
1677 "0600f4ad4eda4bc8e3e99592abdfce7eb08fee0ccc801c5ccee26134bcaafbbd",
1678 "516b45cb1342239a549bd8c1d5998f98",
1679 "854c593555a213e4a862c6f66aa4a79631faca131eba6f163e5cd3940e9c0a57",
1680 2,
1681 9
1682 );
1683
1684 streaming_cipher_kat!(
1685 test_openssl_aes_256_ecb_pkcs7_15_bytes,
1686 &AES_256,
1687 OperatingMode::ECB,
1688 "80f235756c8f70094ae1f99a95a599c27c4452a4b8412fd934e2b253f7098508",
1689 "2235590b90190d7a1dc2464a0205ad",
1690 "8547d8ac8dc6d9cebb2dc77a7034bb67",
1691 2,
1692 9
1693 );
1694
1695 #[test]
1696 fn test_new_rejects_none_context_for_iv_required_modes() {
1697 let key_bytes = [0u8; AES_128_KEY_LEN];
1698 for mode in [
1699 OperatingMode::CBC,
1700 OperatingMode::CTR,
1701 OperatingMode::CFB128,
1702 OperatingMode::CFB8,
1703 OperatingMode::CFB1,
1704 OperatingMode::OFB,
1705 ] {
1706 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1707 assert!(
1708 StreamingEncryptingKey::new(key, mode, EncryptionContext::None).is_err(),
1709 "AES + {mode:?} + EncryptionContext::None should be rejected"
1710 );
1711
1712 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1713 assert!(
1714 StreamingDecryptingKey::new(key, mode, DecryptionContext::None).is_err(),
1715 "AES + {mode:?} + DecryptionContext::None should be rejected"
1716 );
1717 }
1718 }
1719
1720 #[test]
1721 fn test_new_accepts_none_context_for_ecb() {
1722 let key_bytes = [0u8; AES_128_KEY_LEN];
1723
1724 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1725 assert!(
1726 StreamingEncryptingKey::new(key, OperatingMode::ECB, EncryptionContext::None).is_ok()
1727 );
1728
1729 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1730 assert!(
1731 StreamingDecryptingKey::new(key, OperatingMode::ECB, DecryptionContext::None).is_ok()
1732 );
1733 }
1734
1735 #[cfg(feature = "legacy-des")]
1736 #[test]
1737 fn test_new_rejects_iv64_context_for_aes() {
1738 let key_bytes = [0u8; AES_128_KEY_LEN];
1739 for mode in [
1740 OperatingMode::CBC,
1741 OperatingMode::CTR,
1742 OperatingMode::CFB128,
1743 OperatingMode::CFB8,
1744 OperatingMode::CFB1,
1745 OperatingMode::OFB,
1746 ] {
1747 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1748 let context = EncryptionContext::Iv64(FixedLength::new().unwrap());
1749 assert!(
1750 StreamingEncryptingKey::new(key, mode, context).is_err(),
1751 "AES + {mode:?} + EncryptionContext::Iv64 should be rejected"
1752 );
1753
1754 let key = UnboundCipherKey::new(&AES_128, &key_bytes).unwrap();
1755 let context = DecryptionContext::Iv64(FixedLength::new().unwrap());
1756 assert!(
1757 StreamingDecryptingKey::new(key, mode, context).is_err(),
1758 "AES + {mode:?} + DecryptionContext::Iv64 should be rejected"
1759 );
1760 }
1761 }
1762
1763 #[cfg(feature = "legacy-des")]
1764 #[test]
1765 #[allow(deprecated)]
1766 fn test_new_rejects_iv128_context_for_des() {
1767 let key_bytes = from_hex("0123456789abcdef").unwrap();
1768
1769 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1770 let context = EncryptionContext::Iv128(FixedLength::new().unwrap());
1771 assert!(
1772 StreamingEncryptingKey::new(key, OperatingMode::CBC, context).is_err(),
1773 "DES + CBC + EncryptionContext::Iv128 should be rejected"
1774 );
1775
1776 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1777 let context = DecryptionContext::Iv128(FixedLength::new().unwrap());
1778 assert!(
1779 StreamingDecryptingKey::new(key, OperatingMode::CBC, context).is_err(),
1780 "DES + CBC + DecryptionContext::Iv128 should be rejected"
1781 );
1782 }
1783
1784 #[cfg(feature = "legacy-des")]
1785 #[test]
1786 #[allow(deprecated)]
1787 fn test_new_accepts_valid_des_contexts() {
1788 let key_bytes = from_hex("0123456789abcdef").unwrap();
1789
1790 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1791 assert!(
1792 StreamingEncryptingKey::new(key, OperatingMode::ECB, EncryptionContext::None).is_ok()
1793 );
1794 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1795 assert!(
1796 StreamingDecryptingKey::new(key, OperatingMode::ECB, DecryptionContext::None).is_ok()
1797 );
1798
1799 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1800 let context = EncryptionContext::Iv64(FixedLength::new().unwrap());
1801 assert!(StreamingEncryptingKey::new(key, OperatingMode::CBC, context).is_ok());
1802
1803 let key = UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key_bytes).unwrap();
1804 let context = DecryptionContext::Iv64(FixedLength::new().unwrap());
1805 assert!(StreamingDecryptingKey::new(key, OperatingMode::CBC, context).is_ok());
1806 }
1807}