1#![allow(clippy::module_name_repetitions)]
220
221pub(crate) mod aes;
222pub(crate) mod block;
223pub(crate) mod chacha;
224pub(crate) mod key;
225mod padded;
226mod streaming;
227
228pub use padded::{PaddedBlockDecryptingKey, PaddedBlockEncryptingKey};
229pub use streaming::{BufferUpdate, StreamingDecryptingKey, StreamingEncryptingKey};
230
231use crate::aws_lc::{
232 EVP_aes_128_cbc, EVP_aes_128_cfb128, EVP_aes_128_ctr, EVP_aes_128_ecb, EVP_aes_192_cbc,
233 EVP_aes_192_cfb128, EVP_aes_192_ctr, EVP_aes_192_ecb, EVP_aes_256_cbc, EVP_aes_256_cfb128,
234 EVP_aes_256_ctr, EVP_aes_256_ecb, EVP_CIPHER,
235};
236use crate::buffer::Buffer;
237use crate::error::Unspecified;
238use crate::hkdf;
239use crate::hkdf::KeyType;
240use crate::iv::{FixedLength, IV_LEN_128_BIT};
241use crate::ptr::ConstPointer;
242use core::fmt::Debug;
243use key::SymmetricCipherKey;
244
245pub use crate::cipher::aes::AES_128_KEY_LEN;
247
248pub use crate::cipher::aes::AES_192_KEY_LEN;
250
251pub use crate::cipher::aes::AES_256_KEY_LEN;
253
254const MAX_CIPHER_KEY_LEN: usize = AES_256_KEY_LEN;
255
256pub use crate::cipher::aes::AES_CBC_IV_LEN;
258
259pub use crate::cipher::aes::AES_CTR_IV_LEN;
261
262pub use crate::cipher::aes::AES_CFB_IV_LEN;
264
265use crate::cipher::aes::AES_BLOCK_LEN;
266
267const MAX_CIPHER_BLOCK_LEN: usize = AES_BLOCK_LEN;
268
269#[non_exhaustive]
271#[derive(Debug, PartialEq, Eq, Clone, Copy)]
272pub enum OperatingMode {
273 CBC,
275
276 CTR,
278
279 CFB128,
281
282 ECB,
284}
285
286impl OperatingMode {
287 fn evp_cipher(&self, algorithm: &Algorithm) -> ConstPointer<'_, EVP_CIPHER> {
288 unsafe {
289 ConstPointer::new_static(match (self, algorithm.id) {
290 (OperatingMode::CBC, AlgorithmId::Aes128) => EVP_aes_128_cbc(),
291 (OperatingMode::CTR, AlgorithmId::Aes128) => EVP_aes_128_ctr(),
292 (OperatingMode::CFB128, AlgorithmId::Aes128) => EVP_aes_128_cfb128(),
293 (OperatingMode::ECB, AlgorithmId::Aes128) => EVP_aes_128_ecb(),
294 (OperatingMode::CBC, AlgorithmId::Aes192) => EVP_aes_192_cbc(),
295 (OperatingMode::CTR, AlgorithmId::Aes192) => EVP_aes_192_ctr(),
296 (OperatingMode::CFB128, AlgorithmId::Aes192) => EVP_aes_192_cfb128(),
297 (OperatingMode::ECB, AlgorithmId::Aes192) => EVP_aes_192_ecb(),
298 (OperatingMode::CBC, AlgorithmId::Aes256) => EVP_aes_256_cbc(),
299 (OperatingMode::CTR, AlgorithmId::Aes256) => EVP_aes_256_ctr(),
300 (OperatingMode::CFB128, AlgorithmId::Aes256) => EVP_aes_256_cfb128(),
301 (OperatingMode::ECB, AlgorithmId::Aes256) => EVP_aes_256_ecb(),
302 })
303 .unwrap()
304 }
305 }
306}
307
308macro_rules! define_cipher_context {
309 ($name:ident, $other:ident) => {
310 #[non_exhaustive]
312 pub enum $name {
313 Iv128(FixedLength<IV_LEN_128_BIT>),
315
316 None,
318 }
319
320 impl<'a> TryFrom<&'a $name> for &'a [u8] {
321 type Error = Unspecified;
322
323 fn try_from(value: &'a $name) -> Result<Self, Unspecified> {
324 match value {
325 $name::Iv128(iv) => Ok(iv.as_ref()),
326 _ => Err(Unspecified),
327 }
328 }
329 }
330
331 impl Debug for $name {
332 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
333 match self {
334 Self::Iv128(_) => write!(f, "Iv128"),
335 Self::None => write!(f, "None"),
336 }
337 }
338 }
339
340 impl From<$other> for $name {
341 fn from(value: $other) -> Self {
342 match value {
343 $other::Iv128(iv) => $name::Iv128(iv),
344 $other::None => $name::None,
345 }
346 }
347 }
348 };
349}
350
351define_cipher_context!(EncryptionContext, DecryptionContext);
352define_cipher_context!(DecryptionContext, EncryptionContext);
353
354#[non_exhaustive]
355#[derive(Debug, PartialEq, Eq, Clone, Copy)]
356pub enum AlgorithmId {
358 Aes128,
360
361 Aes256,
363
364 Aes192,
366}
367
368#[derive(Debug, PartialEq, Eq)]
370pub struct Algorithm {
371 id: AlgorithmId,
372 key_len: usize,
373 block_len: usize,
374}
375
376pub const AES_128: Algorithm = Algorithm {
378 id: AlgorithmId::Aes128,
379 key_len: AES_128_KEY_LEN,
380 block_len: AES_BLOCK_LEN,
381};
382
383pub const AES_192: Algorithm = Algorithm {
385 id: AlgorithmId::Aes192,
386 key_len: AES_192_KEY_LEN,
387 block_len: AES_BLOCK_LEN,
388};
389
390pub const AES_256: Algorithm = Algorithm {
392 id: AlgorithmId::Aes256,
393 key_len: AES_256_KEY_LEN,
394 block_len: AES_BLOCK_LEN,
395};
396
397impl Algorithm {
398 fn id(&self) -> &AlgorithmId {
399 &self.id
400 }
401
402 #[must_use]
404 pub const fn block_len(&self) -> usize {
405 self.block_len
406 }
407
408 fn new_encryption_context(
409 &self,
410 mode: OperatingMode,
411 ) -> Result<EncryptionContext, Unspecified> {
412 match self.id {
413 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
415 OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
416 Ok(EncryptionContext::Iv128(FixedLength::new()?))
417 }
418 OperatingMode::ECB => Ok(EncryptionContext::None),
419 },
420 }
421 }
422
423 fn is_valid_encryption_context(&self, mode: OperatingMode, input: &EncryptionContext) -> bool {
424 match self.id {
425 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
427 OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
428 matches!(input, EncryptionContext::Iv128(_))
429 }
430 OperatingMode::ECB => {
431 matches!(input, EncryptionContext::None)
432 }
433 },
434 }
435 }
436
437 fn is_valid_decryption_context(&self, mode: OperatingMode, input: &DecryptionContext) -> bool {
438 match self.id {
440 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
441 OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
442 matches!(input, DecryptionContext::Iv128(_))
443 }
444 OperatingMode::ECB => {
445 matches!(input, DecryptionContext::None)
446 }
447 },
448 }
449 }
450}
451
452#[allow(clippy::missing_fields_in_debug)]
453impl Debug for UnboundCipherKey {
454 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
455 f.debug_struct("UnboundCipherKey")
456 .field("algorithm", &self.algorithm)
457 .finish()
458 }
459}
460
461impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundCipherKey {
462 fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
463 let mut key_bytes = [0; MAX_CIPHER_KEY_LEN];
464 let key_bytes = &mut key_bytes[..okm.len().key_len];
465 let algorithm = *okm.len();
466 okm.fill(key_bytes).unwrap();
467 Self::new(algorithm, key_bytes).unwrap()
468 }
469}
470
471impl KeyType for &'static Algorithm {
472 fn len(&self) -> usize {
473 self.key_len
474 }
475}
476
477pub struct UnboundCipherKey {
479 algorithm: &'static Algorithm,
480 key_bytes: Buffer<'static, &'static [u8]>,
481}
482
483impl UnboundCipherKey {
484 pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self, Unspecified> {
490 let key_bytes = Buffer::new(key_bytes.to_vec());
491 Ok(UnboundCipherKey {
492 algorithm,
493 key_bytes,
494 })
495 }
496
497 #[inline]
498 #[must_use]
499 pub fn algorithm(&self) -> &'static Algorithm {
501 self.algorithm
502 }
503}
504
505impl TryInto<SymmetricCipherKey> for UnboundCipherKey {
506 type Error = Unspecified;
507
508 fn try_into(self) -> Result<SymmetricCipherKey, Self::Error> {
509 match self.algorithm.id() {
510 AlgorithmId::Aes128 => SymmetricCipherKey::aes128(self.key_bytes.as_ref()),
511 AlgorithmId::Aes192 => SymmetricCipherKey::aes192(self.key_bytes.as_ref()),
512 AlgorithmId::Aes256 => SymmetricCipherKey::aes256(self.key_bytes.as_ref()),
513 }
514 }
515}
516
517pub struct EncryptingKey {
519 algorithm: &'static Algorithm,
520 key: SymmetricCipherKey,
521 mode: OperatingMode,
522}
523
524impl EncryptingKey {
525 pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
535 Self::new(key, OperatingMode::CTR)
536 }
537
538 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
548 Self::new(key, OperatingMode::CFB128)
549 }
550
551 pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
565 Self::new(key, OperatingMode::CBC)
566 }
567
568 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
582 Self::new(key, OperatingMode::ECB)
583 }
584
585 #[allow(clippy::unnecessary_wraps)]
586 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
587 let algorithm = key.algorithm();
588 let key = key.try_into()?;
589 Ok(Self {
590 algorithm,
591 key,
592 mode,
593 })
594 }
595
596 #[must_use]
598 pub fn algorithm(&self) -> &Algorithm {
599 self.algorithm
600 }
601
602 #[must_use]
604 pub fn mode(&self) -> OperatingMode {
605 self.mode
606 }
607
608 pub fn encrypt(&self, in_out: &mut [u8]) -> Result<DecryptionContext, Unspecified> {
619 let context = self.algorithm.new_encryption_context(self.mode)?;
620 self.less_safe_encrypt(in_out, context)
621 }
622
623 pub fn less_safe_encrypt(
635 &self,
636 in_out: &mut [u8],
637 context: EncryptionContext,
638 ) -> Result<DecryptionContext, Unspecified> {
639 if !self
640 .algorithm()
641 .is_valid_encryption_context(self.mode, &context)
642 {
643 return Err(Unspecified);
644 }
645 encrypt(self.algorithm(), &self.key, self.mode, in_out, context)
646 }
647}
648
649impl Debug for EncryptingKey {
650 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
651 f.debug_struct("EncryptingKey")
652 .field("algorithm", self.algorithm)
653 .field("mode", &self.mode)
654 .finish_non_exhaustive()
655 }
656}
657
658pub struct DecryptingKey {
660 algorithm: &'static Algorithm,
661 key: SymmetricCipherKey,
662 mode: OperatingMode,
663}
664
665impl DecryptingKey {
666 pub fn ctr(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
676 Self::new(key, OperatingMode::CTR)
677 }
678
679 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
689 Self::new(key, OperatingMode::CFB128)
690 }
691
692 pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
706 Self::new(key, OperatingMode::CBC)
707 }
708
709 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
723 Self::new(key, OperatingMode::ECB)
724 }
725
726 #[allow(clippy::unnecessary_wraps)]
727 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
728 let algorithm = key.algorithm();
729 let key = key.try_into()?;
730 Ok(Self {
731 algorithm,
732 key,
733 mode,
734 })
735 }
736
737 #[must_use]
739 pub fn algorithm(&self) -> &Algorithm {
740 self.algorithm
741 }
742
743 #[must_use]
745 pub fn mode(&self) -> OperatingMode {
746 self.mode
747 }
748
749 pub fn decrypt<'in_out>(
759 &self,
760 in_out: &'in_out mut [u8],
761 context: DecryptionContext,
762 ) -> Result<&'in_out mut [u8], Unspecified> {
763 decrypt(self.algorithm, &self.key, self.mode, in_out, context)
764 }
765}
766
767impl Debug for DecryptingKey {
768 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
769 f.debug_struct("DecryptingKey")
770 .field("algorithm", &self.algorithm)
771 .field("mode", &self.mode)
772 .finish_non_exhaustive()
773 }
774}
775
776fn encrypt(
777 algorithm: &Algorithm,
778 key: &SymmetricCipherKey,
779 mode: OperatingMode,
780 in_out: &mut [u8],
781 context: EncryptionContext,
782) -> Result<DecryptionContext, Unspecified> {
783 let block_len = algorithm.block_len();
784
785 match mode {
786 OperatingMode::CBC | OperatingMode::ECB => {
787 if in_out.len() % block_len != 0 {
788 return Err(Unspecified);
789 }
790 }
791 _ => {}
792 }
793
794 match mode {
795 OperatingMode::CBC => match algorithm.id() {
796 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
797 aes::encrypt_cbc_mode(key, context, in_out)
798 }
799 },
800 OperatingMode::CTR => match algorithm.id() {
801 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
802 aes::encrypt_ctr_mode(key, context, in_out)
803 }
804 },
805 OperatingMode::CFB128 => match algorithm.id() {
807 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
808 aes::encrypt_cfb_mode(key, mode, context, in_out)
809 }
810 },
811 OperatingMode::ECB => match algorithm.id() {
812 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
813 aes::encrypt_ecb_mode(key, context, in_out)
814 }
815 },
816 }
817}
818
819fn decrypt<'in_out>(
820 algorithm: &'static Algorithm,
821 key: &SymmetricCipherKey,
822 mode: OperatingMode,
823 in_out: &'in_out mut [u8],
824 context: DecryptionContext,
825) -> Result<&'in_out mut [u8], Unspecified> {
826 let block_len = algorithm.block_len();
827
828 match mode {
829 OperatingMode::CBC | OperatingMode::ECB => {
830 if in_out.len() % block_len != 0 {
831 return Err(Unspecified);
832 }
833 }
834 _ => {}
835 }
836
837 match mode {
838 OperatingMode::CBC => match algorithm.id() {
839 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
840 aes::decrypt_cbc_mode(key, context, in_out)
841 }
842 },
843 OperatingMode::CTR => match algorithm.id() {
844 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
845 aes::decrypt_ctr_mode(key, context, in_out)
846 }
847 },
848 OperatingMode::CFB128 => match algorithm.id() {
850 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
851 aes::decrypt_cfb_mode(key, mode, context, in_out)
852 }
853 },
854 OperatingMode::ECB => match algorithm.id() {
855 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
856 aes::decrypt_ecb_mode(key, context, in_out)
857 }
858 },
859 }
860}
861
862#[cfg(test)]
863mod tests {
864 use super::*;
865 use crate::test::from_hex;
866
867 #[cfg(feature = "fips")]
868 mod fips;
869
870 #[test]
871 fn test_debug() {
872 {
873 let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
874 let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
875 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
876 }
877
878 {
879 let aes_256_key_bytes =
880 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
881 .unwrap();
882 let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
883 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
884 }
885
886 {
887 let key_bytes = &[0u8; 16];
888 let key = PaddedBlockEncryptingKey::cbc_pkcs7(
889 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
890 )
891 .unwrap();
892 assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
893 let mut data = vec![0u8; 16];
894 let context = key.encrypt(&mut data).unwrap();
895 assert_eq!("Iv128", format!("{context:?}"));
896 let key = PaddedBlockDecryptingKey::cbc_pkcs7(
897 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
898 )
899 .unwrap();
900 assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
901 }
902
903 {
904 let key_bytes = &[0u8; 16];
905 let key =
906 EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
907 assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
908 let mut data = vec![0u8; 16];
909 let context = key.encrypt(&mut data).unwrap();
910 assert_eq!("Iv128", format!("{context:?}"));
911 let key =
912 DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
913 assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
914 }
915 }
916
917 fn helper_test_cipher_n_bytes(
918 key: &[u8],
919 alg: &'static Algorithm,
920 mode: OperatingMode,
921 n: usize,
922 ) {
923 let mut input: Vec<u8> = Vec::with_capacity(n);
924 for i in 0..n {
925 let byte: u8 = i.try_into().unwrap();
926 input.push(byte);
927 }
928
929 let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
930 let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
931
932 let mut in_out = input.clone();
933 let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
934
935 if n > 5 {
936 assert_ne!(input.as_slice(), in_out);
938 }
939
940 let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
941 let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
942
943 let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
944 assert_eq!(input.as_slice(), plaintext);
945 }
946
947 #[test]
948 fn test_aes_128_ctr() {
949 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
950 for i in 0..=50 {
951 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
952 }
953 }
954
955 #[test]
956 fn test_aes_128_cfb128() {
957 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
958 for i in 0..=50 {
959 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
960 }
961 }
962
963 #[test]
964 fn test_aes_256_cfb128() {
965 let key =
966 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
967 for i in 0..=50 {
968 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
969 }
970 }
971
972 #[test]
973 fn test_aes_256_ctr() {
974 let key =
975 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
976 for i in 0..=50 {
977 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
978 }
979 }
980
981 #[test]
982 fn test_aes_128_cbc() {
983 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
984 for i in 0..=3 {
986 let size = i * 16; helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
988 }
989 }
990
991 #[test]
992 fn test_aes_256_cbc() {
993 let key =
994 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
995 for i in 0..=3 {
997 let size = i * 16; helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
999 }
1000 }
1001
1002 #[test]
1003 fn test_aes_128_ecb() {
1004 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1005 _ = key;
1006 }
1007
1008 macro_rules! cipher_kat {
1009 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
1010 #[test]
1011 fn $name() {
1012 let key = from_hex($key).unwrap();
1013 let input = from_hex($plaintext).unwrap();
1014 let expected_ciphertext = from_hex($ciphertext).unwrap();
1015 let mut iv = from_hex($iv).unwrap();
1016 let iv = {
1017 let slice = iv.as_mut_slice();
1018 let mut iv = [0u8; $iv.len() / 2];
1019 {
1020 let x = iv.as_mut_slice();
1021 x.copy_from_slice(slice);
1022 }
1023 iv
1024 };
1025
1026 let ec = EncryptionContext::Iv128(FixedLength::from(iv));
1027
1028 let alg = $alg;
1029
1030 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1031
1032 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1033
1034 let mut in_out = input.clone();
1035
1036 let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
1037
1038 assert_eq!(expected_ciphertext, in_out);
1039
1040 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1041 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1042
1043 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1044 assert_eq!(input.as_slice(), plaintext);
1045 }
1046 };
1047 ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
1048 #[test]
1049 fn $name() {
1050 let key = from_hex($key).unwrap();
1051 let input = from_hex($plaintext).unwrap();
1052 let expected_ciphertext = from_hex($ciphertext).unwrap();
1053
1054 let alg = $alg;
1055
1056 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1057
1058 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1059
1060 let mut in_out = input.clone();
1061
1062 let context = encrypting_key
1063 .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1064 .unwrap();
1065
1066 assert_eq!(expected_ciphertext, in_out);
1067
1068 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1069 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1070
1071 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1072 assert_eq!(input.as_slice(), plaintext);
1073 }
1074 };
1075 }
1076
1077 cipher_kat!(
1078 test_iv_aes_128_ctr_16_bytes,
1079 &AES_128,
1080 OperatingMode::CTR,
1081 "000102030405060708090a0b0c0d0e0f",
1082 "00000000000000000000000000000000",
1083 "00112233445566778899aabbccddeeff",
1084 "c6b01904c3da3df5e7d62bd96d153686"
1085 );
1086
1087 cipher_kat!(
1088 test_iv_aes_256_ctr_15_bytes,
1089 &AES_256,
1090 OperatingMode::CTR,
1091 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1092 "00000000000000000000000000000000",
1093 "00112233445566778899aabbccddee",
1094 "f28122856e1cf9a7216a30d111f399"
1095 );
1096
1097 cipher_kat!(
1098 test_openssl_aes_128_ctr_15_bytes,
1099 &AES_128,
1100 OperatingMode::CTR,
1101 "244828580821c1652582c76e34d299f5",
1102 "093145d5af233f46072a5eb5adc11aa1",
1103 "3ee38cec171e6cf466bf0df98aa0e1",
1104 "bd7d928f60e3422d96b3f8cd614eb2"
1105 );
1106
1107 cipher_kat!(
1108 test_openssl_aes_256_ctr_15_bytes,
1109 &AES_256,
1110 OperatingMode::CTR,
1111 "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1112 "f028ecb053f801102d11fccc9d303a27",
1113 "eca7285d19f3c20e295378460e8729",
1114 "b5098e5e788de6ac2f2098eb2fc6f8"
1115 );
1116
1117 cipher_kat!(
1118 test_sp800_38a_cfb128_aes128,
1119 &AES_128,
1120 OperatingMode::CFB128,
1121 "2b7e151628aed2a6abf7158809cf4f3c",
1122 "000102030405060708090a0b0c0d0e0f",
1123 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1124 "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1125 );
1126
1127 cipher_kat!(
1128 test_sp800_38a_cfb128_aes256,
1129 &AES_256,
1130 OperatingMode::CFB128,
1131 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1132 "000102030405060708090a0b0c0d0e0f",
1133 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1134 "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1135 );
1136
1137 cipher_kat!(
1138 test_sp800_38a_ecb_aes128,
1139 &AES_128,
1140 OperatingMode::ECB,
1141 "2b7e151628aed2a6abf7158809cf4f3c",
1142 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1143 "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1144 );
1145
1146 cipher_kat!(
1147 test_sp800_38a_ecb_aes256,
1148 &AES_256,
1149 OperatingMode::ECB,
1150 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1151 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1152 "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1153 );
1154
1155 cipher_kat!(
1156 test_sp800_38a_cbc_aes128,
1157 &AES_128,
1158 OperatingMode::CBC,
1159 "2b7e151628aed2a6abf7158809cf4f3c",
1160 "000102030405060708090a0b0c0d0e0f",
1161 "6bc1bee22e409f96e93d7e117393172a",
1162 "7649abac8119b246cee98e9b12e9197d"
1163 );
1164
1165 cipher_kat!(
1166 test_sp800_38a_cbc_aes256,
1167 &AES_256,
1168 OperatingMode::CBC,
1169 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1170 "000102030405060708090a0b0c0d0e0f",
1171 "6bc1bee22e409f96e93d7e117393172a",
1172 "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1173 );
1174
1175 cipher_kat!(
1176 test_sp800_38a_cbc_aes128_multi_block,
1177 &AES_128,
1178 OperatingMode::CBC,
1179 "2b7e151628aed2a6abf7158809cf4f3c",
1180 "000102030405060708090a0b0c0d0e0f",
1181 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1182 "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1183 );
1184
1185 cipher_kat!(
1186 test_sp800_38a_cbc_aes256_multi_block,
1187 &AES_256,
1188 OperatingMode::CBC,
1189 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1190 "000102030405060708090a0b0c0d0e0f",
1191 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1192 "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1193 );
1194}