1#![allow(clippy::module_name_repetitions)]
230
231pub(crate) mod aes;
232pub(crate) mod block;
233pub(crate) mod chacha;
234#[cfg(feature = "legacy-des")]
235pub(crate) mod des;
236pub(crate) mod key;
237mod padded;
238mod streaming;
239
240pub use padded::{PaddedBlockDecryptingKey, PaddedBlockEncryptingKey};
241pub use streaming::{BufferUpdate, StreamingDecryptingKey, StreamingEncryptingKey};
242
243use crate::aws_lc::{
244 EVP_aes_128_cbc, EVP_aes_128_cfb1, EVP_aes_128_cfb128, EVP_aes_128_cfb8, EVP_aes_128_ctr,
245 EVP_aes_128_ecb, EVP_aes_128_ofb, EVP_aes_192_cbc, EVP_aes_192_cfb1, EVP_aes_192_cfb128,
246 EVP_aes_192_cfb8, EVP_aes_192_ctr, EVP_aes_192_ecb, EVP_aes_192_ofb, EVP_aes_256_cbc,
247 EVP_aes_256_cfb1, EVP_aes_256_cfb128, EVP_aes_256_cfb8, EVP_aes_256_ctr, EVP_aes_256_ecb,
248 EVP_aes_256_ofb, EVP_CIPHER,
249};
250#[cfg(feature = "legacy-des")]
251use crate::aws_lc::{
252 EVP_des_cbc, EVP_des_ecb, EVP_des_ede, EVP_des_ede3_cbc, EVP_des_ede3_ecb, EVP_des_ede_cbc,
253};
254use crate::buffer::Buffer;
255use crate::error::{KeyRejected, Unspecified};
256use crate::hkdf;
257use crate::hkdf::KeyType;
258#[cfg(feature = "legacy-des")]
259use crate::iv::IV_LEN_64_BIT;
260use crate::iv::{FixedLength, IV_LEN_128_BIT};
261use crate::ptr::ConstPointer;
262use core::fmt::Debug;
263use key::SymmetricCipherKey;
264
265pub use crate::cipher::aes::AES_128_KEY_LEN;
267
268pub use crate::cipher::aes::AES_192_KEY_LEN;
270
271pub use crate::cipher::aes::AES_256_KEY_LEN;
273
274#[cfg(feature = "legacy-des")]
279#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
280#[deprecated(
281 since = "1.17.0",
282 note = "Single DES is a legacy algorithm retained for interoperability only. Prefer an AES-based algorithm."
283)]
284pub use crate::cipher::des::DES_KEY_LEN;
285
286#[cfg(feature = "legacy-des")]
291#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
292#[deprecated(
293 since = "1.17.0",
294 note = "2-key Triple DES is a legacy algorithm retained for interoperability only; NIST SP 800-131A Rev. 2 disallows its use for encryption. Prefer an AES-based algorithm."
295)]
296pub use crate::cipher::des::DES_EDE_KEY_LEN;
297
298#[cfg(feature = "legacy-des")]
303#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
304#[deprecated(
305 since = "1.17.0",
306 note = "3DES is a legacy algorithm retained for interoperability only; NIST SP 800-131A Rev. 2 disallows its use for encryption. Prefer an AES-based algorithm."
307)]
308pub use crate::cipher::des::DES_EDE3_KEY_LEN;
309
310const MAX_CIPHER_KEY_LEN: usize = AES_256_KEY_LEN;
311
312pub use crate::cipher::aes::AES_CBC_IV_LEN;
314
315pub use crate::cipher::aes::AES_CTR_IV_LEN;
317
318pub use crate::cipher::aes::AES_CFB_IV_LEN;
320
321pub use crate::cipher::aes::AES_OFB_IV_LEN;
323
324#[cfg(feature = "legacy-des")]
329#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
330#[deprecated(
331 since = "1.17.0",
332 note = "DES/3DES are legacy algorithms retained for interoperability only; NIST SP 800-131A Rev. 2 disallows their use for encryption. Prefer an AES-based algorithm."
333)]
334pub use crate::cipher::des::DES_CBC_IV_LEN;
335
336use crate::cipher::aes::AES_BLOCK_LEN;
337#[cfg(feature = "legacy-des")]
338use crate::cipher::des::DES_BLOCK_LEN;
339
340const MAX_CIPHER_BLOCK_LEN: usize = AES_BLOCK_LEN;
341
342#[non_exhaustive]
344#[derive(Debug, PartialEq, Eq, Clone, Copy)]
345pub enum OperatingMode {
346 CBC,
348
349 CTR,
351
352 CFB128,
354
355 ECB,
357
358 CFB8,
360
361 CFB1,
366
367 OFB,
369}
370
371impl OperatingMode {
372 fn evp_cipher(&self, algorithm: &Algorithm) -> ConstPointer<'_, EVP_CIPHER> {
373 let alg = match (self, algorithm.id) {
374 (OperatingMode::CBC, AlgorithmId::Aes128) => unsafe { EVP_aes_128_cbc() },
375 (OperatingMode::CTR, AlgorithmId::Aes128) => unsafe { EVP_aes_128_ctr() },
376 (OperatingMode::CFB128, AlgorithmId::Aes128) => unsafe { EVP_aes_128_cfb128() },
377 (OperatingMode::CFB8, AlgorithmId::Aes128) => unsafe { EVP_aes_128_cfb8() },
378 (OperatingMode::CFB1, AlgorithmId::Aes128) => unsafe { EVP_aes_128_cfb1() },
379 (OperatingMode::OFB, AlgorithmId::Aes128) => unsafe { EVP_aes_128_ofb() },
380 (OperatingMode::ECB, AlgorithmId::Aes128) => unsafe { EVP_aes_128_ecb() },
381 (OperatingMode::CBC, AlgorithmId::Aes192) => unsafe { EVP_aes_192_cbc() },
382 (OperatingMode::CTR, AlgorithmId::Aes192) => unsafe { EVP_aes_192_ctr() },
383 (OperatingMode::CFB128, AlgorithmId::Aes192) => unsafe { EVP_aes_192_cfb128() },
384 (OperatingMode::CFB8, AlgorithmId::Aes192) => unsafe { EVP_aes_192_cfb8() },
385 (OperatingMode::CFB1, AlgorithmId::Aes192) => unsafe { EVP_aes_192_cfb1() },
386 (OperatingMode::OFB, AlgorithmId::Aes192) => unsafe { EVP_aes_192_ofb() },
387 (OperatingMode::ECB, AlgorithmId::Aes192) => unsafe { EVP_aes_192_ecb() },
388 (OperatingMode::CBC, AlgorithmId::Aes256) => unsafe { EVP_aes_256_cbc() },
389 (OperatingMode::CTR, AlgorithmId::Aes256) => unsafe { EVP_aes_256_ctr() },
390 (OperatingMode::CFB128, AlgorithmId::Aes256) => unsafe { EVP_aes_256_cfb128() },
391 (OperatingMode::CFB8, AlgorithmId::Aes256) => unsafe { EVP_aes_256_cfb8() },
392 (OperatingMode::CFB1, AlgorithmId::Aes256) => unsafe { EVP_aes_256_cfb1() },
393 (OperatingMode::OFB, AlgorithmId::Aes256) => unsafe { EVP_aes_256_ofb() },
394 (OperatingMode::ECB, AlgorithmId::Aes256) => unsafe { EVP_aes_256_ecb() },
395 #[cfg(feature = "legacy-des")]
396 #[allow(deprecated)]
397 (OperatingMode::CBC, AlgorithmId::DesForLegacyUseOnly) => unsafe { EVP_des_cbc() },
398 #[cfg(feature = "legacy-des")]
399 #[allow(deprecated)]
400 (OperatingMode::ECB, AlgorithmId::DesForLegacyUseOnly) => unsafe { EVP_des_ecb() },
401 #[cfg(feature = "legacy-des")]
402 #[allow(deprecated)]
403 (OperatingMode::CBC, AlgorithmId::DesEdeForLegacyUseOnly) => unsafe {
404 EVP_des_ede_cbc()
405 },
406 #[cfg(feature = "legacy-des")]
407 #[allow(deprecated)]
408 (OperatingMode::ECB, AlgorithmId::DesEdeForLegacyUseOnly) => unsafe { EVP_des_ede() },
409 #[cfg(feature = "legacy-des")]
410 #[allow(deprecated)]
411 (OperatingMode::CBC, AlgorithmId::DesEde3ForLegacyUseOnly) => unsafe {
412 EVP_des_ede3_cbc()
413 },
414 #[cfg(feature = "legacy-des")]
415 #[allow(deprecated)]
416 (OperatingMode::ECB, AlgorithmId::DesEde3ForLegacyUseOnly) => unsafe {
417 EVP_des_ede3_ecb()
418 },
419 #[cfg(feature = "legacy-des")]
420 #[allow(deprecated)]
421 (
422 OperatingMode::CTR
423 | OperatingMode::CFB128
424 | OperatingMode::CFB8
425 | OperatingMode::CFB1
426 | OperatingMode::OFB,
427 AlgorithmId::DesForLegacyUseOnly
428 | AlgorithmId::DesEdeForLegacyUseOnly
429 | AlgorithmId::DesEde3ForLegacyUseOnly,
430 ) => {
431 unreachable!("DES does not support CTR, CFB or OFB modes")
434 }
435 };
436 unsafe { ConstPointer::new_static(alg).unwrap() }
437 }
438}
439
440macro_rules! define_cipher_context {
441 ($name:ident, $other:ident) => {
442 #[non_exhaustive]
444 pub enum $name {
445 Iv128(FixedLength<IV_LEN_128_BIT>),
447
448 #[cfg(feature = "legacy-des")]
454 #[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
455 Iv64(FixedLength<IV_LEN_64_BIT>),
456
457 None,
459 }
460
461 impl<'a> TryFrom<&'a $name> for &'a [u8] {
462 type Error = Unspecified;
463
464 fn try_from(value: &'a $name) -> Result<Self, Unspecified> {
465 match value {
466 $name::Iv128(iv) => Ok(iv.as_ref()),
467 #[cfg(feature = "legacy-des")]
468 $name::Iv64(iv) => Ok(iv.as_ref()),
469 _ => Err(Unspecified),
470 }
471 }
472 }
473
474 impl Debug for $name {
475 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
476 match self {
477 Self::Iv128(_) => write!(f, "Iv128"),
478 #[cfg(feature = "legacy-des")]
479 Self::Iv64(_) => write!(f, "Iv64"),
480 Self::None => write!(f, "None"),
481 }
482 }
483 }
484
485 impl From<$other> for $name {
486 fn from(value: $other) -> Self {
487 match value {
488 $other::Iv128(iv) => $name::Iv128(iv),
489 #[cfg(feature = "legacy-des")]
490 $other::Iv64(iv) => $name::Iv64(iv),
491 $other::None => $name::None,
492 }
493 }
494 }
495 };
496}
497
498define_cipher_context!(EncryptionContext, DecryptionContext);
499define_cipher_context!(DecryptionContext, EncryptionContext);
500
501#[non_exhaustive]
502#[derive(Debug, PartialEq, Eq, Clone, Copy)]
503pub enum AlgorithmId {
505 Aes128,
507
508 Aes256,
510
511 Aes192,
513
514 #[cfg(feature = "legacy-des")]
519 #[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
520 #[deprecated(
521 since = "1.17.0",
522 note = "Single DES is a legacy algorithm retained for interoperability only. Prefer an AES-based algorithm."
523 )]
524 DesForLegacyUseOnly,
525
526 #[cfg(feature = "legacy-des")]
531 #[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
532 #[deprecated(
533 since = "1.17.0",
534 note = "2-key Triple DES is a legacy algorithm retained for interoperability only; NIST SP 800-131A Rev. 2 disallows its use for encryption. Prefer an AES-based algorithm."
535 )]
536 DesEdeForLegacyUseOnly,
537
538 #[cfg(feature = "legacy-des")]
543 #[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
544 #[deprecated(
545 since = "1.17.0",
546 note = "3DES is a legacy algorithm retained for interoperability only; NIST SP 800-131A Rev. 2 disallows its use for encryption. Prefer an AES-based algorithm."
547 )]
548 DesEde3ForLegacyUseOnly,
549}
550
551#[derive(Debug, PartialEq, Eq)]
553pub struct Algorithm {
554 id: AlgorithmId,
555 key_len: usize,
556 block_len: usize,
557}
558
559pub const AES_128: Algorithm = Algorithm {
561 id: AlgorithmId::Aes128,
562 key_len: AES_128_KEY_LEN,
563 block_len: AES_BLOCK_LEN,
564};
565
566pub const AES_192: Algorithm = Algorithm {
568 id: AlgorithmId::Aes192,
569 key_len: AES_192_KEY_LEN,
570 block_len: AES_BLOCK_LEN,
571};
572
573pub const AES_256: Algorithm = Algorithm {
575 id: AlgorithmId::Aes256,
576 key_len: AES_256_KEY_LEN,
577 block_len: AES_BLOCK_LEN,
578};
579
580#[cfg(feature = "legacy-des")]
590#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
591#[allow(deprecated)]
592#[deprecated(
593 since = "1.17.0",
594 note = "Single DES is a legacy algorithm retained for interoperability only. Prefer an AES-based algorithm."
595)]
596pub const DES_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
597 id: AlgorithmId::DesForLegacyUseOnly,
598 key_len: DES_KEY_LEN,
599 block_len: DES_BLOCK_LEN,
600};
601
602#[cfg(feature = "legacy-des")]
618#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
619#[allow(deprecated)]
620#[deprecated(
621 since = "1.17.0",
622 note = "2-key Triple DES is a legacy algorithm retained for interoperability only; NIST SP 800-131A Rev. 2 disallows its use for encryption. Prefer an AES-based algorithm."
623)]
624pub const DES_EDE_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
625 id: AlgorithmId::DesEdeForLegacyUseOnly,
626 key_len: DES_EDE_KEY_LEN,
627 block_len: DES_BLOCK_LEN,
628};
629
630#[cfg(feature = "legacy-des")]
681#[cfg_attr(aws_lc_rs_docsrs, doc(cfg(feature = "legacy-des")))]
682#[allow(deprecated)]
683#[deprecated(
684 since = "1.17.0",
685 note = "3DES is a legacy algorithm retained for interoperability only; NIST SP 800-131A Rev. 2 disallows its use for encryption. Prefer an AES-based algorithm."
686)]
687pub const DES_EDE3_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
688 id: AlgorithmId::DesEde3ForLegacyUseOnly,
689 key_len: DES_EDE3_KEY_LEN,
690 block_len: DES_BLOCK_LEN,
691};
692
693impl Algorithm {
694 fn id(&self) -> &AlgorithmId {
695 &self.id
696 }
697
698 #[must_use]
700 pub const fn block_len(&self) -> usize {
701 self.block_len
702 }
703
704 fn new_encryption_context(
705 &self,
706 mode: OperatingMode,
707 ) -> Result<EncryptionContext, Unspecified> {
708 match self.id {
709 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
710 OperatingMode::CBC
711 | OperatingMode::CTR
712 | OperatingMode::CFB128
713 | OperatingMode::CFB8
714 | OperatingMode::CFB1
715 | OperatingMode::OFB => Ok(EncryptionContext::Iv128(FixedLength::new()?)),
716 OperatingMode::ECB => Ok(EncryptionContext::None),
717 },
718 #[cfg(feature = "legacy-des")]
719 #[allow(deprecated)]
720 AlgorithmId::DesForLegacyUseOnly
721 | AlgorithmId::DesEdeForLegacyUseOnly
722 | AlgorithmId::DesEde3ForLegacyUseOnly => match mode {
723 OperatingMode::CBC => Ok(EncryptionContext::Iv64(FixedLength::new()?)),
724 OperatingMode::ECB => Ok(EncryptionContext::None),
725 _ => Err(Unspecified),
726 },
727 }
728 }
729
730 fn is_valid_encryption_context(&self, mode: OperatingMode, input: &EncryptionContext) -> bool {
731 match self.id {
732 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
733 OperatingMode::CBC
734 | OperatingMode::CTR
735 | OperatingMode::CFB128
736 | OperatingMode::CFB8
737 | OperatingMode::CFB1
738 | OperatingMode::OFB => matches!(input, EncryptionContext::Iv128(_)),
739 OperatingMode::ECB => {
740 matches!(input, EncryptionContext::None)
741 }
742 },
743 #[cfg(feature = "legacy-des")]
744 #[allow(deprecated)]
745 AlgorithmId::DesForLegacyUseOnly
746 | AlgorithmId::DesEdeForLegacyUseOnly
747 | AlgorithmId::DesEde3ForLegacyUseOnly => match mode {
748 OperatingMode::CBC => matches!(input, EncryptionContext::Iv64(_)),
749 OperatingMode::ECB => matches!(input, EncryptionContext::None),
750 _ => false,
751 },
752 }
753 }
754
755 fn is_valid_decryption_context(&self, mode: OperatingMode, input: &DecryptionContext) -> bool {
756 match self.id {
757 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
758 OperatingMode::CBC
759 | OperatingMode::CTR
760 | OperatingMode::CFB128
761 | OperatingMode::CFB8
762 | OperatingMode::CFB1
763 | OperatingMode::OFB => matches!(input, DecryptionContext::Iv128(_)),
764 OperatingMode::ECB => {
765 matches!(input, DecryptionContext::None)
766 }
767 },
768 #[cfg(feature = "legacy-des")]
769 #[allow(deprecated)]
770 AlgorithmId::DesForLegacyUseOnly
771 | AlgorithmId::DesEdeForLegacyUseOnly
772 | AlgorithmId::DesEde3ForLegacyUseOnly => match mode {
773 OperatingMode::CBC => matches!(input, DecryptionContext::Iv64(_)),
774 OperatingMode::ECB => matches!(input, DecryptionContext::None),
775 _ => false,
776 },
777 }
778 }
779
780 fn supports_mode(&self, mode: OperatingMode) -> bool {
786 match self.id {
787 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => matches!(
788 mode,
789 OperatingMode::CBC
790 | OperatingMode::CTR
791 | OperatingMode::CFB128
792 | OperatingMode::CFB8
793 | OperatingMode::CFB1
794 | OperatingMode::OFB
795 | OperatingMode::ECB
796 ),
797 #[cfg(feature = "legacy-des")]
798 #[allow(deprecated)]
799 AlgorithmId::DesForLegacyUseOnly
800 | AlgorithmId::DesEdeForLegacyUseOnly
801 | AlgorithmId::DesEde3ForLegacyUseOnly => {
802 matches!(mode, OperatingMode::CBC | OperatingMode::ECB)
803 }
804 }
805 }
806}
807
808#[allow(clippy::missing_fields_in_debug)]
809impl Debug for UnboundCipherKey {
810 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
811 f.debug_struct("UnboundCipherKey")
812 .field("algorithm", &self.algorithm)
813 .finish()
814 }
815}
816
817impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundCipherKey {
818 fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
819 let mut key_bytes = [0; MAX_CIPHER_KEY_LEN];
820 let key_bytes = &mut key_bytes[..okm.len().key_len];
821 let algorithm = *okm.len();
822 okm.fill(key_bytes).unwrap();
823 Self::new(algorithm, key_bytes).unwrap()
824 }
825}
826
827impl KeyType for &'static Algorithm {
828 fn len(&self) -> usize {
829 self.key_len
830 }
831}
832
833pub struct UnboundCipherKey {
835 algorithm: &'static Algorithm,
836 key_bytes: Buffer<'static, &'static [u8]>,
837}
838
839impl UnboundCipherKey {
840 pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self, Unspecified> {
846 if key_bytes.len() != algorithm.key_len {
847 return Err(Unspecified);
848 }
849 let key_bytes = Buffer::new(key_bytes.to_vec());
850 Ok(UnboundCipherKey {
851 algorithm,
852 key_bytes,
853 })
854 }
855
856 #[inline]
857 #[must_use]
858 pub fn algorithm(&self) -> &'static Algorithm {
860 self.algorithm
861 }
862
863 #[allow(clippy::unused_self)]
876 #[allow(clippy::unnecessary_wraps)]
877 fn validate_key_material(&self) -> Result<(), KeyRejected> {
878 #[cfg(feature = "legacy-des")]
879 #[allow(deprecated)]
880 match self.algorithm.id() {
881 AlgorithmId::DesForLegacyUseOnly => {
882 let _ = SymmetricCipherKey::prepare_des(self.key_bytes.as_ref())?;
883 }
884 AlgorithmId::DesEdeForLegacyUseOnly => {
885 let _ = SymmetricCipherKey::prepare_des_ede(self.key_bytes.as_ref())?;
886 }
887 AlgorithmId::DesEde3ForLegacyUseOnly => {
888 let _ = SymmetricCipherKey::prepare_des_ede3(self.key_bytes.as_ref())?;
889 }
890 _ => {}
891 }
892 Ok(())
893 }
894}
895
896impl TryInto<SymmetricCipherKey> for UnboundCipherKey {
897 type Error = KeyRejected;
898
899 fn try_into(self) -> Result<SymmetricCipherKey, Self::Error> {
900 match self.algorithm.id() {
901 AlgorithmId::Aes128 => SymmetricCipherKey::aes128(self.key_bytes.as_ref()),
902 AlgorithmId::Aes192 => SymmetricCipherKey::aes192(self.key_bytes.as_ref()),
903 AlgorithmId::Aes256 => SymmetricCipherKey::aes256(self.key_bytes.as_ref()),
904 #[cfg(feature = "legacy-des")]
905 #[allow(deprecated)]
906 AlgorithmId::DesForLegacyUseOnly => SymmetricCipherKey::des(self.key_bytes.as_ref()),
907 #[cfg(feature = "legacy-des")]
908 #[allow(deprecated)]
909 AlgorithmId::DesEdeForLegacyUseOnly => {
910 SymmetricCipherKey::des_ede(self.key_bytes.as_ref())
911 }
912 #[cfg(feature = "legacy-des")]
913 #[allow(deprecated)]
914 AlgorithmId::DesEde3ForLegacyUseOnly => {
915 SymmetricCipherKey::des_ede3(self.key_bytes.as_ref())
916 }
917 }
918 }
919}
920
921pub struct EncryptingKey {
923 algorithm: &'static Algorithm,
924 key: SymmetricCipherKey,
925 mode: OperatingMode,
926}
927
928impl EncryptingKey {
929 pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
942 Self::new(key, OperatingMode::CTR)
943 }
944
945 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
958 Self::new(key, OperatingMode::CFB128)
959 }
960
961 pub fn cfb8(key: UnboundCipherKey) -> Result<Self, Unspecified> {
972 Self::new(key, OperatingMode::CFB8)
973 }
974
975 pub fn cfb1(key: UnboundCipherKey) -> Result<Self, Unspecified> {
989 Self::new(key, OperatingMode::CFB1)
990 }
991
992 pub fn ofb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1003 Self::new(key, OperatingMode::OFB)
1004 }
1005
1006 pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1029 Self::new(key, OperatingMode::CBC)
1030 }
1031
1032 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1055 Self::new(key, OperatingMode::ECB)
1056 }
1057
1058 #[allow(clippy::unnecessary_wraps)]
1059 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
1060 let algorithm = key.algorithm();
1061 if !algorithm.supports_mode(mode) {
1062 return Err(Unspecified);
1063 }
1064 let key = key.try_into()?;
1065 Ok(Self {
1066 algorithm,
1067 key,
1068 mode,
1069 })
1070 }
1071
1072 #[must_use]
1074 pub fn algorithm(&self) -> &Algorithm {
1075 self.algorithm
1076 }
1077
1078 #[must_use]
1080 pub fn mode(&self) -> OperatingMode {
1081 self.mode
1082 }
1083
1084 pub fn encrypt(&self, in_out: &mut [u8]) -> Result<DecryptionContext, Unspecified> {
1095 let context = self.algorithm.new_encryption_context(self.mode)?;
1096 self.less_safe_encrypt(in_out, context)
1097 }
1098
1099 pub fn less_safe_encrypt(
1115 &self,
1116 in_out: &mut [u8],
1117 context: EncryptionContext,
1118 ) -> Result<DecryptionContext, Unspecified> {
1119 if !self
1120 .algorithm()
1121 .is_valid_encryption_context(self.mode, &context)
1122 {
1123 return Err(Unspecified);
1124 }
1125 encrypt(self.algorithm(), &self.key, self.mode, in_out, context)
1126 }
1127}
1128
1129impl Debug for EncryptingKey {
1130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1131 f.debug_struct("EncryptingKey")
1132 .field("algorithm", self.algorithm)
1133 .field("mode", &self.mode)
1134 .finish_non_exhaustive()
1135 }
1136}
1137
1138pub struct DecryptingKey {
1140 algorithm: &'static Algorithm,
1141 key: SymmetricCipherKey,
1142 mode: OperatingMode,
1143}
1144
1145impl DecryptingKey {
1146 pub fn ctr(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
1159 Self::new(key, OperatingMode::CTR)
1160 }
1161
1162 pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1175 Self::new(key, OperatingMode::CFB128)
1176 }
1177
1178 pub fn cfb8(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1189 Self::new(key, OperatingMode::CFB8)
1190 }
1191
1192 pub fn cfb1(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1206 Self::new(key, OperatingMode::CFB1)
1207 }
1208
1209 pub fn ofb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1220 Self::new(key, OperatingMode::OFB)
1221 }
1222
1223 pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
1246 Self::new(key, OperatingMode::CBC)
1247 }
1248
1249 pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
1272 Self::new(key, OperatingMode::ECB)
1273 }
1274
1275 #[allow(clippy::unnecessary_wraps)]
1276 fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
1277 let algorithm = key.algorithm();
1278 if !algorithm.supports_mode(mode) {
1279 return Err(Unspecified);
1280 }
1281 let key = key.try_into()?;
1282 Ok(Self {
1283 algorithm,
1284 key,
1285 mode,
1286 })
1287 }
1288
1289 #[must_use]
1291 pub fn algorithm(&self) -> &Algorithm {
1292 self.algorithm
1293 }
1294
1295 #[must_use]
1297 pub fn mode(&self) -> OperatingMode {
1298 self.mode
1299 }
1300
1301 pub fn decrypt<'in_out>(
1312 &self,
1313 in_out: &'in_out mut [u8],
1314 context: DecryptionContext,
1315 ) -> Result<&'in_out mut [u8], Unspecified> {
1316 if !self
1317 .algorithm()
1318 .is_valid_decryption_context(self.mode, &context)
1319 {
1320 return Err(Unspecified);
1321 }
1322 decrypt(self.algorithm, &self.key, self.mode, in_out, context)
1323 }
1324}
1325
1326impl Debug for DecryptingKey {
1327 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1328 f.debug_struct("DecryptingKey")
1329 .field("algorithm", &self.algorithm)
1330 .field("mode", &self.mode)
1331 .finish_non_exhaustive()
1332 }
1333}
1334
1335fn encrypt(
1336 algorithm: &Algorithm,
1337 key: &SymmetricCipherKey,
1338 mode: OperatingMode,
1339 in_out: &mut [u8],
1340 context: EncryptionContext,
1341) -> Result<DecryptionContext, Unspecified> {
1342 let block_len = algorithm.block_len();
1343
1344 match mode {
1345 OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
1346 return Err(Unspecified);
1347 }
1348 _ => {}
1349 }
1350
1351 match mode {
1352 OperatingMode::CBC => match algorithm.id() {
1353 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1354 aes::encrypt_cbc_mode(key, context, in_out)
1355 }
1356 #[cfg(feature = "legacy-des")]
1357 #[allow(deprecated)]
1358 AlgorithmId::DesForLegacyUseOnly
1359 | AlgorithmId::DesEdeForLegacyUseOnly
1360 | AlgorithmId::DesEde3ForLegacyUseOnly => des::encrypt_cbc_mode(key, context, in_out),
1361 },
1362 OperatingMode::CTR => match algorithm.id() {
1363 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1364 aes::encrypt_ctr_mode(key, context, in_out)
1365 }
1366 #[cfg(feature = "legacy-des")]
1367 #[allow(deprecated)]
1368 AlgorithmId::DesForLegacyUseOnly
1369 | AlgorithmId::DesEdeForLegacyUseOnly
1370 | AlgorithmId::DesEde3ForLegacyUseOnly => {
1371 unreachable!("DES does not support CTR mode.")
1372 }
1373 },
1374 OperatingMode::CFB128 | OperatingMode::CFB8 | OperatingMode::CFB1 => match algorithm.id() {
1375 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1376 aes::encrypt_cfb_mode(key, mode, context, in_out)
1377 }
1378 #[cfg(feature = "legacy-des")]
1379 #[allow(deprecated)]
1380 AlgorithmId::DesForLegacyUseOnly
1381 | AlgorithmId::DesEdeForLegacyUseOnly
1382 | AlgorithmId::DesEde3ForLegacyUseOnly => {
1383 unreachable!("DES does not support CFB modes.")
1384 }
1385 },
1386 OperatingMode::OFB => match algorithm.id() {
1387 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1388 aes::encrypt_ofb_mode(key, context, in_out)
1389 }
1390 #[cfg(feature = "legacy-des")]
1391 #[allow(deprecated)]
1392 AlgorithmId::DesForLegacyUseOnly
1393 | AlgorithmId::DesEdeForLegacyUseOnly
1394 | AlgorithmId::DesEde3ForLegacyUseOnly => {
1395 unreachable!("DES does not support OFB mode.")
1396 }
1397 },
1398 OperatingMode::ECB => match algorithm.id() {
1399 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1400 aes::encrypt_ecb_mode(key, context, in_out)
1401 }
1402 #[cfg(feature = "legacy-des")]
1403 #[allow(deprecated)]
1404 AlgorithmId::DesForLegacyUseOnly
1405 | AlgorithmId::DesEdeForLegacyUseOnly
1406 | AlgorithmId::DesEde3ForLegacyUseOnly => des::encrypt_ecb_mode(key, context, in_out),
1407 },
1408 }
1409}
1410
1411fn decrypt<'in_out>(
1412 algorithm: &'static Algorithm,
1413 key: &SymmetricCipherKey,
1414 mode: OperatingMode,
1415 in_out: &'in_out mut [u8],
1416 context: DecryptionContext,
1417) -> Result<&'in_out mut [u8], Unspecified> {
1418 let block_len = algorithm.block_len();
1419
1420 match mode {
1421 OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
1422 return Err(Unspecified);
1423 }
1424 _ => {}
1425 }
1426
1427 match mode {
1428 OperatingMode::CBC => match algorithm.id() {
1429 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1430 aes::decrypt_cbc_mode(key, context, in_out)
1431 }
1432 #[cfg(feature = "legacy-des")]
1433 #[allow(deprecated)]
1434 AlgorithmId::DesForLegacyUseOnly
1435 | AlgorithmId::DesEdeForLegacyUseOnly
1436 | AlgorithmId::DesEde3ForLegacyUseOnly => des::decrypt_cbc_mode(key, context, in_out),
1437 },
1438 OperatingMode::CTR => match algorithm.id() {
1439 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1440 aes::decrypt_ctr_mode(key, context, in_out)
1441 }
1442 #[cfg(feature = "legacy-des")]
1443 #[allow(deprecated)]
1444 AlgorithmId::DesForLegacyUseOnly
1445 | AlgorithmId::DesEdeForLegacyUseOnly
1446 | AlgorithmId::DesEde3ForLegacyUseOnly => {
1447 unreachable!("DES does not support CTR mode.")
1448 }
1449 },
1450 OperatingMode::CFB128 | OperatingMode::CFB8 | OperatingMode::CFB1 => match algorithm.id() {
1451 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1452 aes::decrypt_cfb_mode(key, mode, context, in_out)
1453 }
1454 #[cfg(feature = "legacy-des")]
1455 #[allow(deprecated)]
1456 AlgorithmId::DesForLegacyUseOnly
1457 | AlgorithmId::DesEdeForLegacyUseOnly
1458 | AlgorithmId::DesEde3ForLegacyUseOnly => {
1459 unreachable!("DES does not support CFB modes.")
1460 }
1461 },
1462 OperatingMode::OFB => match algorithm.id() {
1463 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1464 aes::decrypt_ofb_mode(key, context, in_out)
1465 }
1466 #[cfg(feature = "legacy-des")]
1467 #[allow(deprecated)]
1468 AlgorithmId::DesForLegacyUseOnly
1469 | AlgorithmId::DesEdeForLegacyUseOnly
1470 | AlgorithmId::DesEde3ForLegacyUseOnly => {
1471 unreachable!("DES does not support OFB mode.")
1472 }
1473 },
1474 OperatingMode::ECB => match algorithm.id() {
1475 AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
1476 aes::decrypt_ecb_mode(key, context, in_out)
1477 }
1478 #[cfg(feature = "legacy-des")]
1479 #[allow(deprecated)]
1480 AlgorithmId::DesForLegacyUseOnly
1481 | AlgorithmId::DesEdeForLegacyUseOnly
1482 | AlgorithmId::DesEde3ForLegacyUseOnly => des::decrypt_ecb_mode(key, context, in_out),
1483 },
1484 }
1485}
1486
1487#[cfg(test)]
1488mod tests {
1489 use super::*;
1490 use crate::test::from_hex;
1491
1492 #[cfg(feature = "fips")]
1493 mod fips;
1494
1495 #[test]
1496 fn test_debug() {
1497 {
1498 let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1499 let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
1500 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
1501 }
1502
1503 {
1504 let aes_256_key_bytes =
1505 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
1506 .unwrap();
1507 let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
1508 assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
1509 }
1510
1511 {
1512 let key_bytes = &[0u8; 16];
1513 let key = PaddedBlockEncryptingKey::cbc_pkcs7(
1514 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
1515 )
1516 .unwrap();
1517 assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
1518 let mut data = vec![0u8; 16];
1519 let context = key.encrypt(&mut data).unwrap();
1520 assert_eq!("Iv128", format!("{context:?}"));
1521 let key = PaddedBlockDecryptingKey::cbc_pkcs7(
1522 UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
1523 )
1524 .unwrap();
1525 assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
1526 }
1527
1528 {
1529 let key_bytes = &[0u8; 16];
1530 let key =
1531 EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
1532 assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
1533 let mut data = vec![0u8; 16];
1534 let context = key.encrypt(&mut data).unwrap();
1535 assert_eq!("Iv128", format!("{context:?}"));
1536 let key =
1537 DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
1538 assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
1539 }
1540 }
1541
1542 fn helper_test_cipher_n_bytes(
1543 key: &[u8],
1544 alg: &'static Algorithm,
1545 mode: OperatingMode,
1546 n: usize,
1547 ) {
1548 let mut input: Vec<u8> = Vec::with_capacity(n);
1549 for i in 0..n {
1550 let byte: u8 = i.try_into().unwrap();
1551 input.push(byte);
1552 }
1553
1554 let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
1555 let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
1556
1557 let mut in_out = input.clone();
1558 let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
1559
1560 if n > 5 {
1561 assert_ne!(input.as_slice(), in_out);
1563 }
1564
1565 let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
1566 let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
1567
1568 let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
1569 assert_eq!(input.as_slice(), plaintext);
1570 }
1571
1572 #[test]
1573 fn test_aes_128_ctr() {
1574 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1575 for i in 0..=50 {
1576 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
1577 }
1578 }
1579
1580 #[test]
1581 fn test_aes_128_cfb128() {
1582 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1583 for i in 0..=50 {
1584 helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
1585 }
1586 }
1587
1588 #[test]
1589 fn test_aes_256_cfb128() {
1590 let key =
1591 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
1592 for i in 0..=50 {
1593 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
1594 }
1595 }
1596
1597 #[test]
1598 fn test_aes_256_ctr() {
1599 let key =
1600 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
1601 for i in 0..=50 {
1602 helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
1603 }
1604 }
1605
1606 #[test]
1607 fn test_aes_128_cbc() {
1608 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1609 for i in 0..=3 {
1611 let size = i * 16; helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
1613 }
1614 }
1615
1616 #[test]
1617 fn test_aes_256_cbc() {
1618 let key =
1619 from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
1620 for i in 0..=3 {
1622 let size = i * 16; helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
1624 }
1625 }
1626
1627 #[test]
1628 fn test_aes_128_ecb() {
1629 let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1630 _ = key;
1631 }
1632
1633 macro_rules! cipher_kat {
1634 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
1635 #[test]
1636 fn $name() {
1637 let key = from_hex($key).unwrap();
1638 let input = from_hex($plaintext).unwrap();
1639 let expected_ciphertext = from_hex($ciphertext).unwrap();
1640 let mut iv = from_hex($iv).unwrap();
1641 let iv = {
1642 let slice = iv.as_mut_slice();
1643 let mut iv = [0u8; $iv.len() / 2];
1644 {
1645 let x = iv.as_mut_slice();
1646 x.copy_from_slice(slice);
1647 }
1648 iv
1649 };
1650
1651 let ec = EncryptionContext::Iv128(FixedLength::from(iv));
1652
1653 let alg = $alg;
1654
1655 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1656
1657 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1658
1659 let mut in_out = input.clone();
1660
1661 let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
1662
1663 assert_eq!(expected_ciphertext, in_out);
1664
1665 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1666 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1667
1668 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1669 assert_eq!(input.as_slice(), plaintext);
1670 }
1671 };
1672 ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
1673 #[test]
1674 fn $name() {
1675 let key = from_hex($key).unwrap();
1676 let input = from_hex($plaintext).unwrap();
1677 let expected_ciphertext = from_hex($ciphertext).unwrap();
1678
1679 let alg = $alg;
1680
1681 let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1682
1683 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1684
1685 let mut in_out = input.clone();
1686
1687 let context = encrypting_key
1688 .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1689 .unwrap();
1690
1691 assert_eq!(expected_ciphertext, in_out);
1692
1693 let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1694 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1695
1696 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1697 assert_eq!(input.as_slice(), plaintext);
1698 }
1699 };
1700 }
1701
1702 cipher_kat!(
1703 test_iv_aes_128_ctr_16_bytes,
1704 &AES_128,
1705 OperatingMode::CTR,
1706 "000102030405060708090a0b0c0d0e0f",
1707 "00000000000000000000000000000000",
1708 "00112233445566778899aabbccddeeff",
1709 "c6b01904c3da3df5e7d62bd96d153686"
1710 );
1711
1712 cipher_kat!(
1713 test_iv_aes_256_ctr_15_bytes,
1714 &AES_256,
1715 OperatingMode::CTR,
1716 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1717 "00000000000000000000000000000000",
1718 "00112233445566778899aabbccddee",
1719 "f28122856e1cf9a7216a30d111f399"
1720 );
1721
1722 cipher_kat!(
1723 test_openssl_aes_128_ctr_15_bytes,
1724 &AES_128,
1725 OperatingMode::CTR,
1726 "244828580821c1652582c76e34d299f5",
1727 "093145d5af233f46072a5eb5adc11aa1",
1728 "3ee38cec171e6cf466bf0df98aa0e1",
1729 "bd7d928f60e3422d96b3f8cd614eb2"
1730 );
1731
1732 cipher_kat!(
1733 test_openssl_aes_256_ctr_15_bytes,
1734 &AES_256,
1735 OperatingMode::CTR,
1736 "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1737 "f028ecb053f801102d11fccc9d303a27",
1738 "eca7285d19f3c20e295378460e8729",
1739 "b5098e5e788de6ac2f2098eb2fc6f8"
1740 );
1741
1742 cipher_kat!(
1743 test_sp800_38a_cfb128_aes128,
1744 &AES_128,
1745 OperatingMode::CFB128,
1746 "2b7e151628aed2a6abf7158809cf4f3c",
1747 "000102030405060708090a0b0c0d0e0f",
1748 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1749 "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1750 );
1751
1752 cipher_kat!(
1753 test_sp800_38a_cfb128_aes256,
1754 &AES_256,
1755 OperatingMode::CFB128,
1756 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1757 "000102030405060708090a0b0c0d0e0f",
1758 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1759 "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1760 );
1761
1762 cipher_kat!(
1763 test_sp800_38a_ecb_aes128,
1764 &AES_128,
1765 OperatingMode::ECB,
1766 "2b7e151628aed2a6abf7158809cf4f3c",
1767 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1768 "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1769 );
1770
1771 cipher_kat!(
1772 test_sp800_38a_ecb_aes256,
1773 &AES_256,
1774 OperatingMode::ECB,
1775 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1776 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1777 "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1778 );
1779
1780 cipher_kat!(
1781 test_sp800_38a_cbc_aes128,
1782 &AES_128,
1783 OperatingMode::CBC,
1784 "2b7e151628aed2a6abf7158809cf4f3c",
1785 "000102030405060708090a0b0c0d0e0f",
1786 "6bc1bee22e409f96e93d7e117393172a",
1787 "7649abac8119b246cee98e9b12e9197d"
1788 );
1789
1790 cipher_kat!(
1791 test_sp800_38a_cbc_aes256,
1792 &AES_256,
1793 OperatingMode::CBC,
1794 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1795 "000102030405060708090a0b0c0d0e0f",
1796 "6bc1bee22e409f96e93d7e117393172a",
1797 "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1798 );
1799
1800 cipher_kat!(
1801 test_sp800_38a_cbc_aes128_multi_block,
1802 &AES_128,
1803 OperatingMode::CBC,
1804 "2b7e151628aed2a6abf7158809cf4f3c",
1805 "000102030405060708090a0b0c0d0e0f",
1806 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1807 "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1808 );
1809
1810 cipher_kat!(
1811 test_sp800_38a_cbc_aes256_multi_block,
1812 &AES_256,
1813 OperatingMode::CBC,
1814 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1815 "000102030405060708090a0b0c0d0e0f",
1816 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1817 "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1818 );
1819
1820 cipher_kat!(
1825 test_sp800_38a_ofb_aes128,
1826 &AES_128,
1827 OperatingMode::OFB,
1828 "2b7e151628aed2a6abf7158809cf4f3c",
1829 "000102030405060708090a0b0c0d0e0f",
1830 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1831 "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e"
1832 );
1833
1834 cipher_kat!(
1836 test_sp800_38a_ofb_aes192,
1837 &AES_192,
1838 OperatingMode::OFB,
1839 "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
1840 "000102030405060708090a0b0c0d0e0f",
1841 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1842 "cdc80d6fddf18cab34c25909c99a4174fcc28b8d4c63837c09e81700c11004018d9a9aeac0f6596f559c6d4daf59a5f26d9f200857ca6c3e9cac524bd9acc92a"
1843 );
1844
1845 cipher_kat!(
1847 test_sp800_38a_ofb_aes256,
1848 &AES_256,
1849 OperatingMode::OFB,
1850 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1851 "000102030405060708090a0b0c0d0e0f",
1852 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1853 "dc7e84bfda79164b7ecd8486985d38604febdc6740d20b3ac88f6ad82a4fb08d71ab47a086e86eedf39d1c5bba97c4080126141d67f37be8538f5a8be740e484"
1854 );
1855
1856 cipher_kat!(
1858 test_sp800_38a_cfb8_aes128,
1859 &AES_128,
1860 OperatingMode::CFB8,
1861 "2b7e151628aed2a6abf7158809cf4f3c",
1862 "000102030405060708090a0b0c0d0e0f",
1863 "6bc1bee22e409f96e93d7e117393172aae2d",
1864 "3b79424c9c0dd436bace9e0ed4586a4f32b9"
1865 );
1866
1867 cipher_kat!(
1869 test_sp800_38a_cfb8_aes192,
1870 &AES_192,
1871 OperatingMode::CFB8,
1872 "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
1873 "000102030405060708090a0b0c0d0e0f",
1874 "6bc1bee22e409f96e93d7e117393172aae2d",
1875 "cda2521ef0a905ca44cd057cbf0d47a0678a"
1876 );
1877
1878 cipher_kat!(
1880 test_sp800_38a_cfb8_aes256,
1881 &AES_256,
1882 OperatingMode::CFB8,
1883 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1884 "000102030405060708090a0b0c0d0e0f",
1885 "6bc1bee22e409f96e93d7e117393172aae2d",
1886 "dc1f1a8520a64db55fcc8ac554844e889700"
1887 );
1888
1889 cipher_kat!(
1891 test_sp800_38a_cfb1_aes128,
1892 &AES_128,
1893 OperatingMode::CFB1,
1894 "2b7e151628aed2a6abf7158809cf4f3c",
1895 "000102030405060708090a0b0c0d0e0f",
1896 "6bc1",
1897 "68b3"
1898 );
1899
1900 cipher_kat!(
1902 test_sp800_38a_cfb1_aes192,
1903 &AES_192,
1904 OperatingMode::CFB1,
1905 "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
1906 "000102030405060708090a0b0c0d0e0f",
1907 "6bc1",
1908 "9359"
1909 );
1910
1911 cipher_kat!(
1913 test_sp800_38a_cfb1_aes256,
1914 &AES_256,
1915 OperatingMode::CFB1,
1916 "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1917 "000102030405060708090a0b0c0d0e0f",
1918 "6bc1",
1919 "9029"
1920 );
1921
1922 #[cfg(feature = "legacy-des")]
1923 #[test]
1924 #[allow(deprecated)]
1925 fn test_des_rejects_weak_key() {
1926 let weak_keys: [&str; 4] = [
1927 "0101010101010101",
1928 "fefefefefefefefe",
1929 "e0e0e0e0f1f1f1f1",
1930 "1f1f1f1f0e0e0e0e",
1931 ];
1932 for weak in &weak_keys {
1933 let key = from_hex(weak).unwrap();
1934 assert!(
1935 UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key)
1936 .and_then(EncryptingKey::cbc)
1937 .is_err(),
1938 "expected weak DES key {weak} to be rejected"
1939 );
1940 }
1941 }
1942
1943 #[cfg(feature = "legacy-des")]
1944 #[test]
1945 #[allow(deprecated)]
1946 fn test_des_rejects_semi_weak_key() {
1947 let semi_weak_keys: [&str; 12] = [
1948 "01fe01fe01fe01fe",
1949 "fe01fe01fe01fe01",
1950 "1fe01fe00ef10ef1",
1951 "e01fe01ff10ef10e",
1952 "01e001e001f101f1",
1953 "e001e001f101f101",
1954 "1ffe1ffe0efe0efe",
1955 "fe1ffe1ffe0efe0e",
1956 "011f011f010e010e",
1957 "1f011f010e010e01",
1958 "e0fee0fef1fef1fe",
1959 "fee0fee0fef1fef1",
1960 ];
1961 for semi_weak in &semi_weak_keys {
1962 let key = from_hex(semi_weak).unwrap();
1963 assert!(
1964 UnboundCipherKey::new(&DES_FOR_LEGACY_USE_ONLY, &key)
1965 .and_then(EncryptingKey::cbc)
1966 .is_err(),
1967 "expected semi-weak DES key {semi_weak} to be rejected"
1968 );
1969 }
1970 }
1971
1972 #[cfg(feature = "legacy-des")]
1973 #[test]
1974 #[allow(deprecated)]
1975 fn test_des_ede_rejects_k1_equal_k2() {
1976 let weak_key = from_hex("0123456789abcdef0123456789abcdef").unwrap();
1979 let result = UnboundCipherKey::new(&DES_EDE_FOR_LEGACY_USE_ONLY, &weak_key)
1980 .and_then(EncryptingKey::cbc);
1981 assert!(result.is_err(), "expected K1 == K2 to be rejected");
1982
1983 let good_key = from_hex("0123456789abcdef23456789abcdef01").unwrap();
1985 UnboundCipherKey::new(&DES_EDE_FOR_LEGACY_USE_ONLY, &good_key)
1986 .and_then(EncryptingKey::cbc)
1987 .expect("valid 2TDEA key should be accepted");
1988 }
1989
1990 #[cfg(feature = "legacy-des")]
1991 #[test]
1992 #[allow(deprecated)]
1993 fn test_des_ede_rejects_weak_subkey() {
1994 let weak_keys: [&str; 4] = [
1999 "0101010101010101",
2000 "fefefefefefefefe",
2001 "e0e0e0e0f1f1f1f1",
2002 "1f1f1f1f0e0e0e0e",
2003 ];
2004 let distinct = "23456789abcdef01";
2005 for weak in &weak_keys {
2006 let key = from_hex(&format!("{weak}{distinct}")).unwrap();
2008 assert!(
2009 UnboundCipherKey::new(&DES_EDE_FOR_LEGACY_USE_ONLY, &key)
2010 .and_then(EncryptingKey::cbc)
2011 .is_err(),
2012 "expected weak DES K1 = {weak} to be rejected in 2TDEA"
2013 );
2014 let key = from_hex(&format!("{distinct}{weak}")).unwrap();
2016 assert!(
2017 UnboundCipherKey::new(&DES_EDE_FOR_LEGACY_USE_ONLY, &key)
2018 .and_then(EncryptingKey::cbc)
2019 .is_err(),
2020 "expected weak DES K2 = {weak} to be rejected in 2TDEA"
2021 );
2022 }
2023 }
2024
2025 #[cfg(feature = "legacy-des")]
2026 #[test]
2027 #[allow(deprecated)]
2028 fn test_des_ede3_rejects_degenerate_keys() {
2029 let k1_eq_k2 = from_hex("0123456789abcdef0123456789abcdef456789abcdef0123").unwrap();
2034 assert!(
2035 UnboundCipherKey::new(&DES_EDE3_FOR_LEGACY_USE_ONLY, &k1_eq_k2)
2036 .and_then(EncryptingKey::cbc)
2037 .is_err(),
2038 "expected K1 == K2 to be rejected for 3TDEA"
2039 );
2040
2041 let k2_eq_k3 = from_hex("0123456789abcdef23456789abcdef0123456789abcdef01").unwrap();
2042 assert!(
2043 UnboundCipherKey::new(&DES_EDE3_FOR_LEGACY_USE_ONLY, &k2_eq_k3)
2044 .and_then(EncryptingKey::cbc)
2045 .is_err(),
2046 "expected K2 == K3 to be rejected for 3TDEA"
2047 );
2048
2049 let k1_eq_k3 = from_hex("0123456789abcdef23456789abcdef010123456789abcdef").unwrap();
2050 assert!(
2051 UnboundCipherKey::new(&DES_EDE3_FOR_LEGACY_USE_ONLY, &k1_eq_k3)
2052 .and_then(EncryptingKey::cbc)
2053 .is_err(),
2054 "expected K1 == K3 (2TDEA-in-3TDEA form) to be rejected for 3TDEA"
2055 );
2056
2057 let good_key = from_hex("0123456789abcdef23456789abcdef01456789abcdef0123").unwrap();
2059 UnboundCipherKey::new(&DES_EDE3_FOR_LEGACY_USE_ONLY, &good_key)
2060 .and_then(EncryptingKey::cbc)
2061 .expect("valid 3TDEA key should be accepted");
2062 }
2063
2064 #[cfg(feature = "legacy-des")]
2065 #[test]
2066 #[allow(deprecated)]
2067 fn test_des_ede3_rejects_weak_subkey() {
2068 let weak_keys: [&str; 4] = [
2073 "0101010101010101",
2074 "fefefefefefefefe",
2075 "e0e0e0e0f1f1f1f1",
2076 "1f1f1f1f0e0e0e0e",
2077 ];
2078 let fillers = ["23456789abcdef01", "456789abcdef0123"];
2079
2080 for weak in &weak_keys {
2081 for position in 0..3 {
2082 let mut parts = [""; 3];
2087 parts[position] = *weak;
2088 parts[(position + 1) % 3] = fillers[0];
2089 parts[(position + 2) % 3] = fillers[1];
2090 let key = from_hex(&format!("{}{}{}", parts[0], parts[1], parts[2])).unwrap();
2091 assert!(
2092 UnboundCipherKey::new(&DES_EDE3_FOR_LEGACY_USE_ONLY, &key)
2093 .and_then(EncryptingKey::cbc)
2094 .is_err(),
2095 "expected weak DES subkey {weak} at position {position} to be rejected"
2096 );
2097 }
2098 }
2099 }
2100
2101 #[cfg(feature = "legacy-des")]
2102 #[test]
2103 #[allow(deprecated)]
2104 fn test_des_ede_rejects_semi_weak_subkey() {
2105 let semi_weak_keys: [&str; 12] = [
2116 "01fe01fe01fe01fe",
2117 "fe01fe01fe01fe01",
2118 "1fe01fe00ef10ef1",
2119 "e01fe01ff10ef10e",
2120 "01e001e001f101f1",
2121 "e001e001f101f101",
2122 "1ffe1ffe0efe0efe",
2123 "fe1ffe1ffe0efe0e",
2124 "011f011f010e010e",
2125 "1f011f010e010e01",
2126 "e0fee0fef1fef1fe",
2127 "fee0fee0fef1fef1",
2128 ];
2129 let distinct = "0123456789abcdef";
2130 for semi_weak in &semi_weak_keys {
2131 let key = from_hex(&format!("{semi_weak}{distinct}")).unwrap();
2132 assert!(
2133 UnboundCipherKey::new(&DES_EDE_FOR_LEGACY_USE_ONLY, &key)
2134 .and_then(EncryptingKey::cbc)
2135 .is_err(),
2136 "expected semi-weak DES K1 = {semi_weak} to be rejected in 2TDEA"
2137 );
2138 let key = from_hex(&format!("{distinct}{semi_weak}")).unwrap();
2139 assert!(
2140 UnboundCipherKey::new(&DES_EDE_FOR_LEGACY_USE_ONLY, &key)
2141 .and_then(EncryptingKey::cbc)
2142 .is_err(),
2143 "expected semi-weak DES K2 = {semi_weak} to be rejected in 2TDEA"
2144 );
2145 }
2146 }
2147
2148 #[cfg(feature = "legacy-des")]
2149 #[test]
2150 #[allow(deprecated)]
2151 fn test_des_ede3_rejects_semi_weak_subkey() {
2152 let semi_weak_keys: [&str; 12] = [
2155 "01fe01fe01fe01fe",
2156 "fe01fe01fe01fe01",
2157 "1fe01fe00ef10ef1",
2158 "e01fe01ff10ef10e",
2159 "01e001e001f101f1",
2160 "e001e001f101f101",
2161 "1ffe1ffe0efe0efe",
2162 "fe1ffe1ffe0efe0e",
2163 "011f011f010e010e",
2164 "1f011f010e010e01",
2165 "e0fee0fef1fef1fe",
2166 "fee0fee0fef1fef1",
2167 ];
2168 let fillers = ["0123456789abcdef", "23456789abcdef01"];
2169
2170 for semi_weak in &semi_weak_keys {
2171 for position in 0..3 {
2172 let mut parts = [""; 3];
2173 parts[position] = *semi_weak;
2174 parts[(position + 1) % 3] = fillers[0];
2175 parts[(position + 2) % 3] = fillers[1];
2176 let key = from_hex(&format!("{}{}{}", parts[0], parts[1], parts[2])).unwrap();
2177 assert!(
2178 UnboundCipherKey::new(&DES_EDE3_FOR_LEGACY_USE_ONLY, &key)
2179 .and_then(EncryptingKey::cbc)
2180 .is_err(),
2181 "expected semi-weak DES subkey {semi_weak} at position {position} to be rejected in 3TDEA"
2182 );
2183 }
2184 }
2185 }
2186
2187 #[test]
2188 fn test_decrypting_key_rejects_invalid_context() {
2189 type Constructor = fn(UnboundCipherKey) -> Result<DecryptingKey, Unspecified>;
2190 let key = || UnboundCipherKey::new(&AES_128, &[0u8; 16]).unwrap();
2191 let iv_modes: [(&str, Constructor); 6] = [
2192 ("CBC", DecryptingKey::cbc),
2193 ("CTR", DecryptingKey::ctr),
2194 ("CFB128", DecryptingKey::cfb128),
2195 ("CFB8", DecryptingKey::cfb8),
2196 ("CFB1", DecryptingKey::cfb1),
2197 ("OFB", DecryptingKey::ofb),
2198 ];
2199 for (name, constructor) in iv_modes {
2200 let decrypting_key = constructor(key()).unwrap();
2201 let mut in_out = [0u8; 16];
2202 assert!(
2203 decrypting_key
2204 .decrypt(&mut in_out, DecryptionContext::None)
2205 .is_err(),
2206 "AES + {name} + DecryptionContext::None should be rejected"
2207 );
2208 #[cfg(feature = "legacy-des")]
2209 assert!(
2210 decrypting_key
2211 .decrypt(
2212 &mut in_out,
2213 DecryptionContext::Iv64(FixedLength::from([0u8; 8]))
2214 )
2215 .is_err(),
2216 "AES + {name} + DecryptionContext::Iv64 should be rejected"
2217 );
2218 }
2219
2220 let decrypting_key = DecryptingKey::ecb(key()).unwrap();
2221 assert!(
2222 decrypting_key
2223 .decrypt(
2224 &mut [0u8; 16],
2225 DecryptionContext::Iv128(FixedLength::from([0u8; 16]))
2226 )
2227 .is_err(),
2228 "AES + ECB + DecryptionContext::Iv128 should be rejected"
2229 );
2230 }
2231
2232 #[cfg(feature = "legacy-des")]
2233 #[test]
2234 #[allow(deprecated)]
2235 fn test_des_rejects_unsupported_modes() {
2236 type Constructor = fn(UnboundCipherKey) -> bool;
2241
2242 let algorithms: [(&str, &'static Algorithm, &str); 3] = [
2243 ("DES", &DES_FOR_LEGACY_USE_ONLY, "0123456789abcdef"),
2244 (
2245 "2TDEA",
2246 &DES_EDE_FOR_LEGACY_USE_ONLY,
2247 "0123456789abcdef23456789abcdef01",
2248 ),
2249 (
2250 "3TDEA",
2251 &DES_EDE3_FOR_LEGACY_USE_ONLY,
2252 "0123456789abcdef23456789abcdef01456789abcdef0123",
2253 ),
2254 ];
2255 let constructors: [(&str, Constructor); 23] = [
2256 ("CTR (encrypt)", |k| EncryptingKey::ctr(k).is_ok()),
2257 ("CFB128 (encrypt)", |k| EncryptingKey::cfb128(k).is_ok()),
2258 ("CTR (decrypt)", |k| DecryptingKey::ctr(k).is_ok()),
2259 ("CFB128 (decrypt)", |k| DecryptingKey::cfb128(k).is_ok()),
2260 ("CTR (streaming encrypt)", |k| {
2261 StreamingEncryptingKey::ctr(k).is_ok()
2262 }),
2263 ("CFB128 (streaming encrypt)", |k| {
2264 StreamingEncryptingKey::cfb128(k).is_ok()
2265 }),
2266 ("CTR (streaming decrypt)", |k| {
2267 StreamingDecryptingKey::ctr(k, DecryptionContext::None).is_ok()
2268 }),
2269 ("CFB128 (streaming decrypt)", |k| {
2270 StreamingDecryptingKey::cfb128(k, DecryptionContext::None).is_ok()
2271 }),
2272 ("CFB8 (encrypt)", |k| EncryptingKey::cfb8(k).is_ok()),
2273 ("CFB8 (decrypt)", |k| DecryptingKey::cfb8(k).is_ok()),
2274 ("CFB8 (streaming encrypt)", |k| {
2275 StreamingEncryptingKey::cfb8(k).is_ok()
2276 }),
2277 ("CFB8 (streaming encrypt, context)", |k| {
2278 StreamingEncryptingKey::less_safe_cfb8(k, EncryptionContext::None).is_ok()
2279 }),
2280 ("CFB8 (streaming decrypt)", |k| {
2281 StreamingDecryptingKey::cfb8(k, DecryptionContext::None).is_ok()
2282 }),
2283 ("CFB1 (encrypt)", |k| EncryptingKey::cfb1(k).is_ok()),
2284 ("CFB1 (decrypt)", |k| DecryptingKey::cfb1(k).is_ok()),
2285 ("CFB1 (streaming encrypt)", |k| {
2286 StreamingEncryptingKey::cfb1(k).is_ok()
2287 }),
2288 ("CFB1 (streaming encrypt, context)", |k| {
2289 StreamingEncryptingKey::less_safe_cfb1(k, EncryptionContext::None).is_ok()
2290 }),
2291 ("CFB1 (streaming decrypt)", |k| {
2292 StreamingDecryptingKey::cfb1(k, DecryptionContext::None).is_ok()
2293 }),
2294 ("OFB (encrypt)", |k| EncryptingKey::ofb(k).is_ok()),
2295 ("OFB (decrypt)", |k| DecryptingKey::ofb(k).is_ok()),
2296 ("OFB (streaming encrypt)", |k| {
2297 StreamingEncryptingKey::ofb(k).is_ok()
2298 }),
2299 ("OFB (streaming encrypt, context)", |k| {
2300 StreamingEncryptingKey::less_safe_ofb(k, EncryptionContext::None).is_ok()
2301 }),
2302 ("OFB (streaming decrypt)", |k| {
2303 StreamingDecryptingKey::ofb(k, DecryptionContext::None).is_ok()
2304 }),
2305 ];
2306
2307 for (alg_name, algorithm, key_hex) in algorithms {
2308 let key_bytes = from_hex(key_hex).unwrap();
2309 for (mode_name, construct) in constructors {
2310 let key = UnboundCipherKey::new(algorithm, &key_bytes).unwrap();
2313 assert!(
2314 !construct(key),
2315 "{alg_name} + {mode_name} should be rejected"
2316 );
2317 }
2318 }
2319 }
2320
2321 #[cfg(feature = "legacy-des")]
2322 #[test]
2323 #[allow(deprecated)]
2324 fn test_des_cbc() {
2325 let key = from_hex("0123456789abcdef").unwrap();
2326 for i in 0..=3 {
2327 let size = i * 8;
2328 helper_test_cipher_n_bytes(
2329 key.as_slice(),
2330 &DES_FOR_LEGACY_USE_ONLY,
2331 OperatingMode::CBC,
2332 size,
2333 );
2334 }
2335 }
2336
2337 #[cfg(feature = "legacy-des")]
2338 #[test]
2339 #[allow(deprecated)]
2340 fn test_des_ecb() {
2341 let key = from_hex("0123456789abcdef").unwrap();
2342 for i in 0..=3 {
2343 let size = i * 8;
2344 helper_test_cipher_n_bytes(
2345 key.as_slice(),
2346 &DES_FOR_LEGACY_USE_ONLY,
2347 OperatingMode::ECB,
2348 size,
2349 );
2350 }
2351 }
2352
2353 #[cfg(feature = "legacy-des")]
2354 #[test]
2355 #[allow(deprecated)]
2356 fn test_des_ede_cbc() {
2357 let key = from_hex("0123456789abcdef23456789abcdef01").unwrap();
2358 for i in 0..=3 {
2359 let size = i * 8;
2360 helper_test_cipher_n_bytes(
2361 key.as_slice(),
2362 &DES_EDE_FOR_LEGACY_USE_ONLY,
2363 OperatingMode::CBC,
2364 size,
2365 );
2366 }
2367 }
2368
2369 #[cfg(feature = "legacy-des")]
2370 #[test]
2371 #[allow(deprecated)]
2372 fn test_des_ede_ecb() {
2373 let key = from_hex("0123456789abcdef23456789abcdef01").unwrap();
2374 for i in 0..=3 {
2375 let size = i * 8;
2376 helper_test_cipher_n_bytes(
2377 key.as_slice(),
2378 &DES_EDE_FOR_LEGACY_USE_ONLY,
2379 OperatingMode::ECB,
2380 size,
2381 );
2382 }
2383 }
2384
2385 #[cfg(feature = "legacy-des")]
2386 #[test]
2387 #[allow(deprecated)]
2388 fn test_des_ede3_cbc() {
2389 let key = from_hex("0123456789abcdef23456789abcdef01456789abcdef0123").unwrap();
2390 for i in 0..=3 {
2391 let size = i * 8;
2392 helper_test_cipher_n_bytes(
2393 key.as_slice(),
2394 &DES_EDE3_FOR_LEGACY_USE_ONLY,
2395 OperatingMode::CBC,
2396 size,
2397 );
2398 }
2399 }
2400
2401 #[cfg(feature = "legacy-des")]
2402 #[test]
2403 #[allow(deprecated)]
2404 fn test_des_ede3_ecb() {
2405 let key = from_hex("0123456789abcdef23456789abcdef01456789abcdef0123").unwrap();
2406 for i in 0..=3 {
2407 let size = i * 8;
2408 helper_test_cipher_n_bytes(
2409 key.as_slice(),
2410 &DES_EDE3_FOR_LEGACY_USE_ONLY,
2411 OperatingMode::ECB,
2412 size,
2413 );
2414 }
2415 }
2416
2417 #[cfg(feature = "legacy-des")]
2418 macro_rules! des_cipher_kat {
2419 ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv:literal, $plaintext:literal, $ciphertext:literal) => {
2420 #[test]
2421 #[allow(deprecated)]
2422 fn $name() {
2423 let key = from_hex($key).unwrap();
2424 let input = from_hex($plaintext).unwrap();
2425 let expected_ciphertext = from_hex($ciphertext).unwrap();
2426
2427 let ec = if $iv.len() == 0 {
2428 EncryptionContext::None
2429 } else {
2430 let iv_arr: [u8; 8] = from_hex($iv).unwrap().try_into().unwrap();
2431 EncryptionContext::Iv64(FixedLength::from(iv_arr))
2432 };
2433
2434 let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
2435 let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
2436 let mut in_out = input.clone();
2437 let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
2438 assert_eq!(expected_ciphertext, in_out);
2439
2440 let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
2441 let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
2442 let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
2443 assert_eq!(input.as_slice(), plaintext);
2444 }
2445 };
2446 }
2447
2448 #[cfg(feature = "legacy-des")]
2449 des_cipher_kat!(
2450 test_des_cbc_kat,
2451 &DES_FOR_LEGACY_USE_ONLY,
2452 OperatingMode::CBC,
2453 "0123456789abcdef",
2454 "f69f2445df4f9b17",
2455 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
2456 "2d121f90fcf68631ed788fcfe31a62dffa784891fa512ef928ea856d934257c6"
2457 );
2458
2459 #[cfg(feature = "legacy-des")]
2460 des_cipher_kat!(
2461 test_des_ecb_kat,
2462 &DES_FOR_LEGACY_USE_ONLY,
2463 OperatingMode::ECB,
2464 "0123456789abcdef",
2465 "",
2466 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
2467 "7277a00dc1c1c36b2256338b7a9f36ef6e511022cfebec489a4a53a1c7d22e5b"
2468 );
2469
2470 #[cfg(feature = "legacy-des")]
2471 des_cipher_kat!(
2472 test_sp800_67_des_ede_cbc,
2473 &DES_EDE_FOR_LEGACY_USE_ONLY,
2474 OperatingMode::CBC,
2475 "0123456789abcdef23456789abcdef01",
2476 "f69f2445df4f9b17",
2477 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
2478 "7401CE1EAB6D003CAFF84BF47B36CC2154F0238F9FFECD8F6ACF118392B45581"
2479 );
2480
2481 #[cfg(feature = "legacy-des")]
2482 des_cipher_kat!(
2483 test_sp800_67_des_ede_ecb,
2484 &DES_EDE_FOR_LEGACY_USE_ONLY,
2485 OperatingMode::ECB,
2486 "0123456789abcdef23456789abcdef01",
2487 "",
2488 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
2489 "06EDE3D82884090AFF322C19F0518486730576972A666E58B6C88CF107340D3D"
2490 );
2491
2492 #[cfg(feature = "legacy-des")]
2493 des_cipher_kat!(
2494 test_sp800_67_des_ede3_cbc,
2495 &DES_EDE3_FOR_LEGACY_USE_ONLY,
2496 OperatingMode::CBC,
2497 "0123456789abcdef23456789abcdef01456789abcdef0123",
2498 "f69f2445df4f9b17",
2499 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
2500 "2079c3d53aa763e193b79e2569ab5262516570481f25b50f73c0bda85c8e0da7"
2501 );
2502
2503 #[cfg(feature = "legacy-des")]
2504 des_cipher_kat!(
2505 test_sp800_67_des_ede3_ecb,
2506 &DES_EDE3_FOR_LEGACY_USE_ONLY,
2507 OperatingMode::ECB,
2508 "0123456789abcdef23456789abcdef01456789abcdef0123",
2509 "",
2510 "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51",
2511 "714772f339841d34267fcc4bd2949cc3ee11c22a576a303876183f99c0b6de87"
2512 );
2513
2514 #[test]
2515 #[allow(deprecated)]
2516 fn test_ecb_rejects_iv_context_after_dispatch() {
2517 let cases: &[(&'static Algorithm, &str)] = &[
2521 (&AES_128, "000102030405060708090a0b0c0d0e0f"),
2522 #[cfg(feature = "legacy-des")]
2523 (
2524 &DES_EDE3_FOR_LEGACY_USE_ONLY,
2525 "0123456789abcdef23456789abcdef01456789abcdef0123",
2526 ),
2527 ];
2528 for &(algorithm, key_hex) in cases {
2529 let key_bytes = from_hex(key_hex).unwrap();
2530 let encrypting_key =
2531 EncryptingKey::ecb(UnboundCipherKey::new(algorithm, &key_bytes).unwrap()).unwrap();
2532 let decrypting_key =
2533 DecryptingKey::ecb(UnboundCipherKey::new(algorithm, &key_bytes).unwrap()).unwrap();
2534 let mut in_out = vec![0u8; algorithm.block_len()];
2535 let iv = [0u8; IV_LEN_128_BIT];
2536
2537 assert!(encrypt(
2538 algorithm,
2539 &encrypting_key.key,
2540 OperatingMode::ECB,
2541 &mut in_out,
2542 EncryptionContext::Iv128(FixedLength::from(iv)),
2543 )
2544 .is_err());
2545 assert!(decrypt(
2546 algorithm,
2547 &decrypting_key.key,
2548 OperatingMode::ECB,
2549 &mut in_out,
2550 DecryptionContext::Iv128(FixedLength::from(iv)),
2551 )
2552 .is_err());
2553 }
2554 }
2555}