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 ConstPointer::new(match (self, algorithm.id) {
289 (OperatingMode::CBC, AlgorithmId::Aes128) => unsafe { EVP_aes_128_cbc() },
290 (OperatingMode::CTR, AlgorithmId::Aes128) => unsafe { EVP_aes_128_ctr() },
291 (OperatingMode::CFB128, AlgorithmId::Aes128) => unsafe { EVP_aes_128_cfb128() },
292 (OperatingMode::ECB, AlgorithmId::Aes128) => unsafe { EVP_aes_128_ecb() },
293 (OperatingMode::CBC, AlgorithmId::Aes192) => unsafe { EVP_aes_192_cbc() },
294 (OperatingMode::CTR, AlgorithmId::Aes192) => unsafe { EVP_aes_192_ctr() },
295 (OperatingMode::CFB128, AlgorithmId::Aes192) => unsafe { EVP_aes_192_cfb128() },
296 (OperatingMode::ECB, AlgorithmId::Aes192) => unsafe { EVP_aes_192_ecb() },
297 (OperatingMode::CBC, AlgorithmId::Aes256) => unsafe { EVP_aes_256_cbc() },
298 (OperatingMode::CTR, AlgorithmId::Aes256) => unsafe { EVP_aes_256_ctr() },
299 (OperatingMode::CFB128, AlgorithmId::Aes256) => unsafe { EVP_aes_256_cfb128() },
300 (OperatingMode::ECB, AlgorithmId::Aes256) => unsafe { EVP_aes_256_ecb() },
301 })
302 .unwrap()
303 }
304}
305
306macro_rules! define_cipher_context {
307 ($name:ident, $other:ident) => {
308 #[non_exhaustive]
310 pub enum $name {
311 Iv128(FixedLength<IV_LEN_128_BIT>),
313
314 None,
316 }
317
318 impl<'a> TryFrom<&'a $name> for &'a [u8] {
319 type Error = Unspecified;
320
321 fn try_from(value: &'a $name) -> Result<Self, Unspecified> {
322 match value {
323 $name::Iv128(iv) => Ok(iv.as_ref()),
324 _ => Err(Unspecified),
325 }
326 }
327 }
328
329 impl Debug for $name {
330 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
331 match self {
332 Self::Iv128(_) => write!(f, "Iv128"),
333 Self::None => write!(f, "None"),
334 }
335 }
336 }
337
338 impl From<$other> for $name {
339 fn from(value: $other) -> Self {
340 match value {
341 $other::Iv128(iv) => $name::Iv128(iv),
342 $other::None => $name::None,
343 }
344 }
345 }
346 };
347}
348
349define_cipher_context!(EncryptionContext, DecryptionContext);
350define_cipher_context!(DecryptionContext, EncryptionContext);
351
352#[non_exhaustive]
353#[derive(Debug, PartialEq, Eq, Clone, Copy)]
354pub enum AlgorithmId {
356 Aes128,
358
359 Aes256,
361
362 Aes192,
364}
365
366#[derive(Debug, PartialEq, Eq)]
368pub struct Algorithm {
369 id: AlgorithmId,
370 key_len: usize,
371 block_len: usize,
372}
373
374pub static AES_128: Algorithm = Algorithm {
376 id: AlgorithmId::Aes128,
377 key_len: AES_128_KEY_LEN,
378 block_len: AES_BLOCK_LEN,
379};
380
381pub static AES_192: Algorithm = Algorithm {
383 id: AlgorithmId::Aes192,
384 key_len: AES_192_KEY_LEN,
385 block_len: AES_BLOCK_LEN,
386};
387
388pub static AES_256: Algorithm = Algorithm {
390 id: AlgorithmId::Aes256,
391 key_len: AES_256_KEY_LEN,
392 block_len: AES_BLOCK_LEN,
393};
394
395impl Algorithm {
396 fn id(&self) -> &AlgorithmId {
397 &self.id
398 }
399
400 #[must_use]
402 pub const fn block_len(&self) -> usize {
403 self.block_len
404 }
405
406 fn new_encryption_context(
407 &self,
408 mode: OperatingMode,
409 ) -> Result<EncryptionContext, Unspecified> {
410 match self.id {
411 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
413 OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
414 Ok(EncryptionContext::Iv128(FixedLength::new()?))
415 }
416 OperatingMode::ECB => Ok(EncryptionContext::None),
417 },
418 }
419 }
420
421 fn is_valid_encryption_context(&self, mode: OperatingMode, input: &EncryptionContext) -> bool {
422 match self.id {
423 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
425 OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
426 matches!(input, EncryptionContext::Iv128(_))
427 }
428 OperatingMode::ECB => {
429 matches!(input, EncryptionContext::None)
430 }
431 },
432 }
433 }
434
435 fn is_valid_decryption_context(&self, mode: OperatingMode, input: &DecryptionContext) -> bool {
436 match self.id {
438 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
439 OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
440 matches!(input, DecryptionContext::Iv128(_))
441 }
442 OperatingMode::ECB => {
443 matches!(input, DecryptionContext::None)
444 }
445 },
446 }
447 }
448}
449
450#[allow(clippy::missing_fields_in_debug)]
451impl Debug for UnboundCipherKey {
452 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
453 f.debug_struct("UnboundCipherKey")
454 .field("algorithm", &self.algorithm)
455 .finish()
456 }
457}
458
459impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundCipherKey {
460 fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
461 let mut key_bytes = [0; MAX_CIPHER_KEY_LEN];
462 let key_bytes = &mut key_bytes[..okm.len().key_len];
463 let algorithm = *okm.len();
464 okm.fill(key_bytes).unwrap();
465 Self::new(algorithm, key_bytes).unwrap()
466 }
467}
468
469impl KeyType for &'static Algorithm {
470 fn len(&self) -> usize {
471 self.key_len
472 }
473}
474
475pub struct UnboundCipherKey {
477 algorithm: &'static Algorithm,
478 key_bytes: Buffer<'static, &'static [u8]>,
479}
480
481impl UnboundCipherKey {
482 pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self, Unspecified> {
488 let key_bytes = Buffer::new(key_bytes.to_vec());
489 Ok(UnboundCipherKey {
490 algorithm,
491 key_bytes,
492 })
493 }
494
495 #[inline]
496 #[must_use]
497 pub fn algorithm(&self) -> &'static Algorithm {
499 self.algorithm
500 }
501}
502
503impl TryInto<SymmetricCipherKey> for UnboundCipherKey {
504 type Error = Unspecified;
505
506 fn try_into(self) -> Result<SymmetricCipherKey, Self::Error> {
507 match self.algorithm.id() {
508 AlgorithmId::Aes128 => SymmetricCipherKey::aes128(self.key_bytes.as_ref()),
509 AlgorithmId::Aes192 => SymmetricCipherKey::aes192(self.key_bytes.as_ref()),
510 AlgorithmId::Aes256 => SymmetricCipherKey::aes256(self.key_bytes.as_ref()),
511 }
512 }
513}
514
515pub struct EncryptingKey {
517 algorithm: &'static Algorithm,
518 key: SymmetricCipherKey,
519 mode: OperatingMode,
520}
521
522impl EncryptingKey {
523 pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
533 Self::new(key, OperatingMode::CTR)
534 }
535
536 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
546 Self::new(key, OperatingMode::CFB128)
547 }
548
549 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
563 Self::new(key, OperatingMode::ECB)
564 }
565
566 #[allow(clippy::unnecessary_wraps)]
567 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
568 let algorithm = key.algorithm();
569 let key = key.try_into()?;
570 Ok(Self {
571 algorithm,
572 key,
573 mode,
574 })
575 }
576
577 #[must_use]
579 pub fn algorithm(&self) -> &Algorithm {
580 self.algorithm
581 }
582
583 #[must_use]
585 pub fn mode(&self) -> OperatingMode {
586 self.mode
587 }
588
589 pub fn encrypt(&self, in_out: &mut [u8]) -> Result<DecryptionContext, Unspecified> {
600 let context = self.algorithm.new_encryption_context(self.mode)?;
601 self.less_safe_encrypt(in_out, context)
602 }
603
604 pub fn less_safe_encrypt(
616 &self,
617 in_out: &mut [u8],
618 context: EncryptionContext,
619 ) -> Result<DecryptionContext, Unspecified> {
620 if !self
621 .algorithm()
622 .is_valid_encryption_context(self.mode, &context)
623 {
624 return Err(Unspecified);
625 }
626 encrypt(self.algorithm(), &self.key, self.mode, in_out, context)
627 }
628}
629
630impl Debug for EncryptingKey {
631 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
632 f.debug_struct("EncryptingKey")
633 .field("algorithm", self.algorithm)
634 .field("mode", &self.mode)
635 .finish_non_exhaustive()
636 }
637}
638
639pub struct DecryptingKey {
641 algorithm: &'static Algorithm,
642 key: SymmetricCipherKey,
643 mode: OperatingMode,
644}
645
646impl DecryptingKey {
647 pub fn ctr(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
657 Self::new(key, OperatingMode::CTR)
658 }
659
660 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
670 Self::new(key, OperatingMode::CFB128)
671 }
672
673 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
687 Self::new(key, OperatingMode::ECB)
688 }
689
690 #[allow(clippy::unnecessary_wraps)]
691 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
692 let algorithm = key.algorithm();
693 let key = key.try_into()?;
694 Ok(Self {
695 algorithm,
696 key,
697 mode,
698 })
699 }
700
701 #[must_use]
703 pub fn algorithm(&self) -> &Algorithm {
704 self.algorithm
705 }
706
707 #[must_use]
709 pub fn mode(&self) -> OperatingMode {
710 self.mode
711 }
712
713 pub fn decrypt<'in_out>(
723 &self,
724 in_out: &'in_out mut [u8],
725 context: DecryptionContext,
726 ) -> Result<&'in_out mut [u8], Unspecified> {
727 decrypt(self.algorithm, &self.key, self.mode, in_out, context)
728 }
729}
730
731impl Debug for DecryptingKey {
732 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
733 f.debug_struct("DecryptingKey")
734 .field("algorithm", &self.algorithm)
735 .field("mode", &self.mode)
736 .finish_non_exhaustive()
737 }
738}
739
740fn encrypt(
741 algorithm: &Algorithm,
742 key: &SymmetricCipherKey,
743 mode: OperatingMode,
744 in_out: &mut [u8],
745 context: EncryptionContext,
746) -> Result<DecryptionContext, Unspecified> {
747 let block_len = algorithm.block_len();
748
749 match mode {
750 OperatingMode::CBC | OperatingMode::ECB => {
751 if in_out.len() % block_len != 0 {
752 return Err(Unspecified);
753 }
754 }
755 _ => {}
756 }
757
758 match mode {
759 OperatingMode::CBC => match algorithm.id() {
760 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
761 aes::encrypt_cbc_mode(key, context, in_out)
762 }
763 },
764 OperatingMode::CTR => match algorithm.id() {
765 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
766 aes::encrypt_ctr_mode(key, context, in_out)
767 }
768 },
769 OperatingMode::CFB128 => match algorithm.id() {
771 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
772 aes::encrypt_cfb_mode(key, mode, context, in_out)
773 }
774 },
775 OperatingMode::ECB => match algorithm.id() {
776 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
777 aes::encrypt_ecb_mode(key, context, in_out)
778 }
779 },
780 }
781}
782
783fn decrypt<'in_out>(
784 algorithm: &'static Algorithm,
785 key: &SymmetricCipherKey,
786 mode: OperatingMode,
787 in_out: &'in_out mut [u8],
788 context: DecryptionContext,
789) -> Result<&'in_out mut [u8], Unspecified> {
790 let block_len = algorithm.block_len();
791
792 match mode {
793 OperatingMode::CBC | OperatingMode::ECB => {
794 if in_out.len() % block_len != 0 {
795 return Err(Unspecified);
796 }
797 }
798 _ => {}
799 }
800
801 match mode {
802 OperatingMode::CBC => match algorithm.id() {
803 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
804 aes::decrypt_cbc_mode(key, context, in_out)
805 }
806 },
807 OperatingMode::CTR => match algorithm.id() {
808 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
809 aes::decrypt_ctr_mode(key, context, in_out)
810 }
811 },
812 OperatingMode::CFB128 => match algorithm.id() {
814 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
815 aes::decrypt_cfb_mode(key, mode, context, in_out)
816 }
817 },
818 OperatingMode::ECB => match algorithm.id() {
819 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
820 aes::decrypt_ecb_mode(key, context, in_out)
821 }
822 },
823 }
824}
825
826#[cfg(test)]
827mod tests {
828 use super::*;
829 use crate::test::from_hex;
830
831 #[cfg(feature = "fips")]
832 mod fips;
833
834 #[test]
835 fn test_debug() {
836 {
837 let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
838 let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
839 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
840 }
841
842 {
843 let aes_256_key_bytes =
844 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
845 .unwrap();
846 let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
847 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
848 }
849
850 {
851 let key_bytes = &[0u8; 16];
852 let key = PaddedBlockEncryptingKey::cbc_pkcs7(
853 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
854 )
855 .unwrap();
856 assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
857 let mut data = vec![0u8; 16];
858 let context = key.encrypt(&mut data).unwrap();
859 assert_eq!("Iv128", format!("{context:?}"));
860 let key = PaddedBlockDecryptingKey::cbc_pkcs7(
861 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
862 )
863 .unwrap();
864 assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
865 }
866
867 {
868 let key_bytes = &[0u8; 16];
869 let key =
870 EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
871 assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
872 let mut data = vec![0u8; 16];
873 let context = key.encrypt(&mut data).unwrap();
874 assert_eq!("Iv128", format!("{context:?}"));
875 let key =
876 DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
877 assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
878 }
879 }
880
881 fn helper_test_cipher_n_bytes(
882 key: &[u8],
883 alg: &'static Algorithm,
884 mode: OperatingMode,
885 n: usize,
886 ) {
887 let mut input: Vec<u8> = Vec::with_capacity(n);
888 for i in 0..n {
889 let byte: u8 = i.try_into().unwrap();
890 input.push(byte);
891 }
892
893 let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
894 let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
895
896 let mut in_out = input.clone();
897 let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
898
899 if n > 5 {
900 assert_ne!(input.as_slice(), in_out);
902 }
903
904 let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
905 let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
906
907 let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
908 assert_eq!(input.as_slice(), plaintext);
909 }
910
911 #[test]
912 fn test_aes_128_ctr() {
913 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
914 for i in 0..=50 {
915 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
916 }
917 }
918
919 #[test]
920 fn test_aes_128_cfb128() {
921 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
922 for i in 0..=50 {
923 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
924 }
925 }
926
927 #[test]
928 fn test_aes_256_cfb128() {
929 let key =
930 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
931 for i in 0..=50 {
932 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
933 }
934 }
935
936 #[test]
937 fn test_aes_256_ctr() {
938 let key =
939 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
940 for i in 0..=50 {
941 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
942 }
943 }
944
945 #[test]
946 fn test_aes_128_ecb() {
947 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
948 _ = key;
949 }
950
951 macro_rules! cipher_kat {
952 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
953 #[test]
954 fn $name() {
955 let key = from_hex($key).unwrap();
956 let input = from_hex($plaintext).unwrap();
957 let expected_ciphertext = from_hex($ciphertext).unwrap();
958 let mut iv = from_hex($iv).unwrap();
959 let iv = {
960 let slice = iv.as_mut_slice();
961 let mut iv = [0u8; $iv.len() / 2];
962 {
963 let x = iv.as_mut_slice();
964 x.copy_from_slice(slice);
965 }
966 iv
967 };
968
969 let ec = EncryptionContext::Iv128(FixedLength::from(iv));
970
971 let alg = $alg;
972
973 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
974
975 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
976
977 let mut in_out = input.clone();
978
979 let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
980
981 assert_eq!(expected_ciphertext, in_out);
982
983 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
984 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
985
986 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
987 assert_eq!(input.as_slice(), plaintext);
988 }
989 };
990 ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
991 #[test]
992 fn $name() {
993 let key = from_hex($key).unwrap();
994 let input = from_hex($plaintext).unwrap();
995 let expected_ciphertext = from_hex($ciphertext).unwrap();
996
997 let alg = $alg;
998
999 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1000
1001 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1002
1003 let mut in_out = input.clone();
1004
1005 let context = encrypting_key
1006 .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1007 .unwrap();
1008
1009 assert_eq!(expected_ciphertext, in_out);
1010
1011 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1012 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1013
1014 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1015 assert_eq!(input.as_slice(), plaintext);
1016 }
1017 };
1018 }
1019
1020 cipher_kat!(
1021 test_iv_aes_128_ctr_16_bytes,
1022 &AES_128,
1023 OperatingMode::CTR,
1024 "000102030405060708090a0b0c0d0e0f",
1025 "00000000000000000000000000000000",
1026 "00112233445566778899aabbccddeeff",
1027 "c6b01904c3da3df5e7d62bd96d153686"
1028 );
1029
1030 cipher_kat!(
1031 test_iv_aes_256_ctr_15_bytes,
1032 &AES_256,
1033 OperatingMode::CTR,
1034 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1035 "00000000000000000000000000000000",
1036 "00112233445566778899aabbccddee",
1037 "f28122856e1cf9a7216a30d111f399"
1038 );
1039
1040 cipher_kat!(
1041 test_openssl_aes_128_ctr_15_bytes,
1042 &AES_128,
1043 OperatingMode::CTR,
1044 "244828580821c1652582c76e34d299f5",
1045 "093145d5af233f46072a5eb5adc11aa1",
1046 "3ee38cec171e6cf466bf0df98aa0e1",
1047 "bd7d928f60e3422d96b3f8cd614eb2"
1048 );
1049
1050 cipher_kat!(
1051 test_openssl_aes_256_ctr_15_bytes,
1052 &AES_256,
1053 OperatingMode::CTR,
1054 "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1055 "f028ecb053f801102d11fccc9d303a27",
1056 "eca7285d19f3c20e295378460e8729",
1057 "b5098e5e788de6ac2f2098eb2fc6f8"
1058 );
1059
1060 cipher_kat!(
1061 test_sp800_38a_cfb128_aes128,
1062 &AES_128,
1063 OperatingMode::CFB128,
1064 "2b7e151628aed2a6abf7158809cf4f3c",
1065 "000102030405060708090a0b0c0d0e0f",
1066 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1067 "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1068 );
1069
1070 cipher_kat!(
1071 test_sp800_38a_cfb128_aes256,
1072 &AES_256,
1073 OperatingMode::CFB128,
1074 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1075 "000102030405060708090a0b0c0d0e0f",
1076 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1077 "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1078 );
1079
1080 cipher_kat!(
1081 test_sp800_38a_ecb_aes128,
1082 &AES_128,
1083 OperatingMode::ECB,
1084 "2b7e151628aed2a6abf7158809cf4f3c",
1085 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1086 "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1087 );
1088
1089 cipher_kat!(
1090 test_sp800_38a_ecb_aes256,
1091 &AES_256,
1092 OperatingMode::ECB,
1093 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1094 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1095 "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1096 );
1097}