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 if key_bytes.len() != algorithm.key_len {
491 return Err(Unspecified);
492 }
493 let key_bytes = Buffer::new(key_bytes.to_vec());
494 Ok(UnboundCipherKey {
495 algorithm,
496 key_bytes,
497 })
498 }
499
500 #[inline]
501 #[must_use]
502 pub fn algorithm(&self) -> &'static Algorithm {
504 self.algorithm
505 }
506}
507
508impl TryInto<SymmetricCipherKey> for UnboundCipherKey {
509 type Error = Unspecified;
510
511 fn try_into(self) -> Result<SymmetricCipherKey, Self::Error> {
512 match self.algorithm.id() {
513 AlgorithmId::Aes128 => SymmetricCipherKey::aes128(self.key_bytes.as_ref()),
514 AlgorithmId::Aes192 => SymmetricCipherKey::aes192(self.key_bytes.as_ref()),
515 AlgorithmId::Aes256 => SymmetricCipherKey::aes256(self.key_bytes.as_ref()),
516 }
517 }
518}
519
520pub struct EncryptingKey {
522 algorithm: &'static Algorithm,
523 key: SymmetricCipherKey,
524 mode: OperatingMode,
525}
526
527impl EncryptingKey {
528 pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
538 Self::new(key, OperatingMode::CTR)
539 }
540
541 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
551 Self::new(key, OperatingMode::CFB128)
552 }
553
554 pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
568 Self::new(key, OperatingMode::CBC)
569 }
570
571 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
585 Self::new(key, OperatingMode::ECB)
586 }
587
588 #[allow(clippy::unnecessary_wraps)]
589 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
590 let algorithm = key.algorithm();
591 let key = key.try_into()?;
592 Ok(Self {
593 algorithm,
594 key,
595 mode,
596 })
597 }
598
599 #[must_use]
601 pub fn algorithm(&self) -> &Algorithm {
602 self.algorithm
603 }
604
605 #[must_use]
607 pub fn mode(&self) -> OperatingMode {
608 self.mode
609 }
610
611 pub fn encrypt(&self, in_out: &mut [u8]) -> Result<DecryptionContext, Unspecified> {
622 let context = self.algorithm.new_encryption_context(self.mode)?;
623 self.less_safe_encrypt(in_out, context)
624 }
625
626 pub fn less_safe_encrypt(
638 &self,
639 in_out: &mut [u8],
640 context: EncryptionContext,
641 ) -> Result<DecryptionContext, Unspecified> {
642 if !self
643 .algorithm()
644 .is_valid_encryption_context(self.mode, &context)
645 {
646 return Err(Unspecified);
647 }
648 encrypt(self.algorithm(), &self.key, self.mode, in_out, context)
649 }
650}
651
652impl Debug for EncryptingKey {
653 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
654 f.debug_struct("EncryptingKey")
655 .field("algorithm", self.algorithm)
656 .field("mode", &self.mode)
657 .finish_non_exhaustive()
658 }
659}
660
661pub struct DecryptingKey {
663 algorithm: &'static Algorithm,
664 key: SymmetricCipherKey,
665 mode: OperatingMode,
666}
667
668impl DecryptingKey {
669 pub fn ctr(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
679 Self::new(key, OperatingMode::CTR)
680 }
681
682 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
692 Self::new(key, OperatingMode::CFB128)
693 }
694
695 pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
709 Self::new(key, OperatingMode::CBC)
710 }
711
712 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
726 Self::new(key, OperatingMode::ECB)
727 }
728
729 #[allow(clippy::unnecessary_wraps)]
730 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
731 let algorithm = key.algorithm();
732 let key = key.try_into()?;
733 Ok(Self {
734 algorithm,
735 key,
736 mode,
737 })
738 }
739
740 #[must_use]
742 pub fn algorithm(&self) -> &Algorithm {
743 self.algorithm
744 }
745
746 #[must_use]
748 pub fn mode(&self) -> OperatingMode {
749 self.mode
750 }
751
752 pub fn decrypt<'in_out>(
762 &self,
763 in_out: &'in_out mut [u8],
764 context: DecryptionContext,
765 ) -> Result<&'in_out mut [u8], Unspecified> {
766 decrypt(self.algorithm, &self.key, self.mode, in_out, context)
767 }
768}
769
770impl Debug for DecryptingKey {
771 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
772 f.debug_struct("DecryptingKey")
773 .field("algorithm", &self.algorithm)
774 .field("mode", &self.mode)
775 .finish_non_exhaustive()
776 }
777}
778
779fn encrypt(
780 algorithm: &Algorithm,
781 key: &SymmetricCipherKey,
782 mode: OperatingMode,
783 in_out: &mut [u8],
784 context: EncryptionContext,
785) -> Result<DecryptionContext, Unspecified> {
786 let block_len = algorithm.block_len();
787
788 match mode {
789 OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
790 return Err(Unspecified);
791 }
792 _ => {}
793 }
794
795 match mode {
796 OperatingMode::CBC => match algorithm.id() {
797 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
798 aes::encrypt_cbc_mode(key, context, in_out)
799 }
800 },
801 OperatingMode::CTR => match algorithm.id() {
802 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
803 aes::encrypt_ctr_mode(key, context, in_out)
804 }
805 },
806 OperatingMode::CFB128 => match algorithm.id() {
808 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
809 aes::encrypt_cfb_mode(key, mode, context, in_out)
810 }
811 },
812 OperatingMode::ECB => match algorithm.id() {
813 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
814 aes::encrypt_ecb_mode(key, context, in_out)
815 }
816 },
817 }
818}
819
820fn decrypt<'in_out>(
821 algorithm: &'static Algorithm,
822 key: &SymmetricCipherKey,
823 mode: OperatingMode,
824 in_out: &'in_out mut [u8],
825 context: DecryptionContext,
826) -> Result<&'in_out mut [u8], Unspecified> {
827 let block_len = algorithm.block_len();
828
829 match mode {
830 OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
831 return Err(Unspecified);
832 }
833 _ => {}
834 }
835
836 match mode {
837 OperatingMode::CBC => match algorithm.id() {
838 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
839 aes::decrypt_cbc_mode(key, context, in_out)
840 }
841 },
842 OperatingMode::CTR => match algorithm.id() {
843 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
844 aes::decrypt_ctr_mode(key, context, in_out)
845 }
846 },
847 OperatingMode::CFB128 => match algorithm.id() {
849 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
850 aes::decrypt_cfb_mode(key, mode, context, in_out)
851 }
852 },
853 OperatingMode::ECB => match algorithm.id() {
854 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
855 aes::decrypt_ecb_mode(key, context, in_out)
856 }
857 },
858 }
859}
860
861#[cfg(test)]
862mod tests {
863 use super::*;
864 use crate::test::from_hex;
865
866 #[cfg(feature = "fips")]
867 mod fips;
868
869 #[test]
870 fn test_debug() {
871 {
872 let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
873 let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
874 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
875 }
876
877 {
878 let aes_256_key_bytes =
879 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
880 .unwrap();
881 let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
882 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
883 }
884
885 {
886 let key_bytes = &[0u8; 16];
887 let key = PaddedBlockEncryptingKey::cbc_pkcs7(
888 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
889 )
890 .unwrap();
891 assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
892 let mut data = vec![0u8; 16];
893 let context = key.encrypt(&mut data).unwrap();
894 assert_eq!("Iv128", format!("{context:?}"));
895 let key = PaddedBlockDecryptingKey::cbc_pkcs7(
896 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
897 )
898 .unwrap();
899 assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
900 }
901
902 {
903 let key_bytes = &[0u8; 16];
904 let key =
905 EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
906 assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
907 let mut data = vec![0u8; 16];
908 let context = key.encrypt(&mut data).unwrap();
909 assert_eq!("Iv128", format!("{context:?}"));
910 let key =
911 DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
912 assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
913 }
914 }
915
916 fn helper_test_cipher_n_bytes(
917 key: &[u8],
918 alg: &'static Algorithm,
919 mode: OperatingMode,
920 n: usize,
921 ) {
922 let mut input: Vec<u8> = Vec::with_capacity(n);
923 for i in 0..n {
924 let byte: u8 = i.try_into().unwrap();
925 input.push(byte);
926 }
927
928 let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
929 let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
930
931 let mut in_out = input.clone();
932 let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
933
934 if n > 5 {
935 assert_ne!(input.as_slice(), in_out);
937 }
938
939 let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
940 let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
941
942 let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
943 assert_eq!(input.as_slice(), plaintext);
944 }
945
946 #[test]
947 fn test_aes_128_ctr() {
948 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
949 for i in 0..=50 {
950 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
951 }
952 }
953
954 #[test]
955 fn test_aes_128_cfb128() {
956 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
957 for i in 0..=50 {
958 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
959 }
960 }
961
962 #[test]
963 fn test_aes_256_cfb128() {
964 let key =
965 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
966 for i in 0..=50 {
967 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
968 }
969 }
970
971 #[test]
972 fn test_aes_256_ctr() {
973 let key =
974 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
975 for i in 0..=50 {
976 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
977 }
978 }
979
980 #[test]
981 fn test_aes_128_cbc() {
982 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
983 for i in 0..=3 {
985 let size = i * 16; helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
987 }
988 }
989
990 #[test]
991 fn test_aes_256_cbc() {
992 let key =
993 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
994 for i in 0..=3 {
996 let size = i * 16; helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
998 }
999 }
1000
1001 #[test]
1002 fn test_aes_128_ecb() {
1003 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1004 _ = key;
1005 }
1006
1007 macro_rules! cipher_kat {
1008 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
1009 #[test]
1010 fn $name() {
1011 let key = from_hex($key).unwrap();
1012 let input = from_hex($plaintext).unwrap();
1013 let expected_ciphertext = from_hex($ciphertext).unwrap();
1014 let mut iv = from_hex($iv).unwrap();
1015 let iv = {
1016 let slice = iv.as_mut_slice();
1017 let mut iv = [0u8; $iv.len() / 2];
1018 {
1019 let x = iv.as_mut_slice();
1020 x.copy_from_slice(slice);
1021 }
1022 iv
1023 };
1024
1025 let ec = EncryptionContext::Iv128(FixedLength::from(iv));
1026
1027 let alg = $alg;
1028
1029 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1030
1031 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1032
1033 let mut in_out = input.clone();
1034
1035 let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
1036
1037 assert_eq!(expected_ciphertext, in_out);
1038
1039 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1040 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1041
1042 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1043 assert_eq!(input.as_slice(), plaintext);
1044 }
1045 };
1046 ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
1047 #[test]
1048 fn $name() {
1049 let key = from_hex($key).unwrap();
1050 let input = from_hex($plaintext).unwrap();
1051 let expected_ciphertext = from_hex($ciphertext).unwrap();
1052
1053 let alg = $alg;
1054
1055 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1056
1057 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1058
1059 let mut in_out = input.clone();
1060
1061 let context = encrypting_key
1062 .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1063 .unwrap();
1064
1065 assert_eq!(expected_ciphertext, in_out);
1066
1067 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1068 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1069
1070 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1071 assert_eq!(input.as_slice(), plaintext);
1072 }
1073 };
1074 }
1075
1076 cipher_kat!(
1077 test_iv_aes_128_ctr_16_bytes,
1078 &AES_128,
1079 OperatingMode::CTR,
1080 "000102030405060708090a0b0c0d0e0f",
1081 "00000000000000000000000000000000",
1082 "00112233445566778899aabbccddeeff",
1083 "c6b01904c3da3df5e7d62bd96d153686"
1084 );
1085
1086 cipher_kat!(
1087 test_iv_aes_256_ctr_15_bytes,
1088 &AES_256,
1089 OperatingMode::CTR,
1090 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1091 "00000000000000000000000000000000",
1092 "00112233445566778899aabbccddee",
1093 "f28122856e1cf9a7216a30d111f399"
1094 );
1095
1096 cipher_kat!(
1097 test_openssl_aes_128_ctr_15_bytes,
1098 &AES_128,
1099 OperatingMode::CTR,
1100 "244828580821c1652582c76e34d299f5",
1101 "093145d5af233f46072a5eb5adc11aa1",
1102 "3ee38cec171e6cf466bf0df98aa0e1",
1103 "bd7d928f60e3422d96b3f8cd614eb2"
1104 );
1105
1106 cipher_kat!(
1107 test_openssl_aes_256_ctr_15_bytes,
1108 &AES_256,
1109 OperatingMode::CTR,
1110 "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1111 "f028ecb053f801102d11fccc9d303a27",
1112 "eca7285d19f3c20e295378460e8729",
1113 "b5098e5e788de6ac2f2098eb2fc6f8"
1114 );
1115
1116 cipher_kat!(
1117 test_sp800_38a_cfb128_aes128,
1118 &AES_128,
1119 OperatingMode::CFB128,
1120 "2b7e151628aed2a6abf7158809cf4f3c",
1121 "000102030405060708090a0b0c0d0e0f",
1122 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1123 "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1124 );
1125
1126 cipher_kat!(
1127 test_sp800_38a_cfb128_aes256,
1128 &AES_256,
1129 OperatingMode::CFB128,
1130 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1131 "000102030405060708090a0b0c0d0e0f",
1132 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1133 "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1134 );
1135
1136 cipher_kat!(
1137 test_sp800_38a_ecb_aes128,
1138 &AES_128,
1139 OperatingMode::ECB,
1140 "2b7e151628aed2a6abf7158809cf4f3c",
1141 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1142 "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1143 );
1144
1145 cipher_kat!(
1146 test_sp800_38a_ecb_aes256,
1147 &AES_256,
1148 OperatingMode::ECB,
1149 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1150 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1151 "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1152 );
1153
1154 cipher_kat!(
1155 test_sp800_38a_cbc_aes128,
1156 &AES_128,
1157 OperatingMode::CBC,
1158 "2b7e151628aed2a6abf7158809cf4f3c",
1159 "000102030405060708090a0b0c0d0e0f",
1160 "6bc1bee22e409f96e93d7e117393172a",
1161 "7649abac8119b246cee98e9b12e9197d"
1162 );
1163
1164 cipher_kat!(
1165 test_sp800_38a_cbc_aes256,
1166 &AES_256,
1167 OperatingMode::CBC,
1168 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1169 "000102030405060708090a0b0c0d0e0f",
1170 "6bc1bee22e409f96e93d7e117393172a",
1171 "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1172 );
1173
1174 cipher_kat!(
1175 test_sp800_38a_cbc_aes128_multi_block,
1176 &AES_128,
1177 OperatingMode::CBC,
1178 "2b7e151628aed2a6abf7158809cf4f3c",
1179 "000102030405060708090a0b0c0d0e0f",
1180 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1181 "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1182 );
1183
1184 cipher_kat!(
1185 test_sp800_38a_cbc_aes256_multi_block,
1186 &AES_256,
1187 OperatingMode::CBC,
1188 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1189 "000102030405060708090a0b0c0d0e0f",
1190 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1191 "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1192 );
1193}