diff --git a/Cargo.lock b/Cargo.lock index 202e3a50..dcfd10db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "cipher", "cpufeatures", "hex-literal", + "subtle", "zeroize", ] @@ -103,8 +104,7 @@ dependencies = [ [[package]] name = "crypto-common" version = "0.2.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b8ce8218c97789f16356e7896b3714f26c2ee1079b79c0b7ae7064bb9089fa" +source = "git+https://github.com/baloo/traits.git?branch=baloo/weak-key#10715bf9d0bb24a239666cc2fa4a50b1e508c3a3" dependencies = [ "hybrid-array", ] @@ -114,6 +114,7 @@ name = "des" version = "0.9.0-pre.2" dependencies = [ "cipher", + "subtle", ] [[package]] @@ -216,6 +217,12 @@ dependencies = [ "hex-literal", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "threefish" version = "0.6.0-pre" diff --git a/Cargo.toml b/Cargo.toml index cbf5fa31..4966fde6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,6 @@ members = [ [profile.dev] opt-level = 2 + +[patch.crates-io] +crypto-common = { git = "https://github.com/baloo/traits.git", branch = "baloo/weak-key" } diff --git a/aes/Cargo.toml b/aes/Cargo.toml index cbe2c1ce..c4e82b81 100644 --- a/aes/Cargo.toml +++ b/aes/Cargo.toml @@ -15,6 +15,7 @@ categories = ["cryptography", "no-std"] [dependencies] cfg-if = "1" cipher = "=0.5.0-pre.7" +subtle = { version = "2.6", default-features = false } zeroize = { version = "1.5.6", optional = true, default-features = false, features = [ "aarch64", ] } diff --git a/aes/src/armv8.rs b/aes/src/armv8.rs index f0de41fa..114f637f 100644 --- a/aes/src/armv8.rs +++ b/aes/src/armv8.rs @@ -19,6 +19,7 @@ mod test_expand; use cipher::{ consts::{self, U16, U24, U32}, + crypto_common::WeakKeyError, AlgorithmName, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, Key, KeyInit, KeySizeUser, }; @@ -108,6 +109,10 @@ macro_rules! define_aes_impl { let decrypt = $name_back_dec::from(encrypt.clone()); Self { encrypt, decrypt } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl From<$name_enc> for $name { @@ -193,6 +198,10 @@ macro_rules! define_aes_impl { let backend = $name_back_enc::new(key); Self { backend } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl BlockSizeUser for $name_enc { @@ -255,6 +264,10 @@ macro_rules! define_aes_impl { let backend = encrypt.clone().into(); Self { backend } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl From<$name_enc> for $name_dec { diff --git a/aes/src/autodetect.rs b/aes/src/autodetect.rs index 8c0e6898..8cfd47c4 100644 --- a/aes/src/autodetect.rs +++ b/aes/src/autodetect.rs @@ -4,6 +4,7 @@ use crate::soft; use cipher::{ consts::{U16, U24, U32}, + crypto_common::WeakKeyError, AlgorithmName, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, Key, KeyInit, KeySizeUser, }; @@ -103,6 +104,10 @@ macro_rules! define_aes_impl { Self { inner, token } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl Clone for $name { @@ -220,6 +225,10 @@ macro_rules! define_aes_impl { Self { inner, token } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl Clone for $name_enc { @@ -347,6 +356,10 @@ macro_rules! define_aes_impl { Self { inner, token } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl Clone for $name_dec { diff --git a/aes/src/macros.rs b/aes/src/macros.rs index e688c00d..28583e99 100644 --- a/aes/src/macros.rs +++ b/aes/src/macros.rs @@ -103,3 +103,29 @@ macro_rules! impl_backends { } }; } + +macro_rules! weak_key_test { + ($key: expr, $k: ty) => {{ + // Check if any bit of the upper half of the key is set + // + // This follows the interpretation laid out in section `11.4.10.4 Reject of weak keys` + // from the TPM specification: + // ``` + // In the case of AES, at least one bit in the upper half of the key must be set + // ``` + // See: https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82 + let mut weak = subtle::Choice::from(0); + + for v in &$key + [..(<<$k as cipher::KeySizeUser>::KeySize as cipher::typenum::Unsigned>::USIZE / 2)] + { + weak |= <_ as subtle::ConstantTimeGreater>::ct_gt(v, &0); + } + + if weak.unwrap_u8() == 0 { + Err(cipher::crypto_common::WeakKeyError) + } else { + Ok(()) + } + }}; +} diff --git a/aes/src/ni.rs b/aes/src/ni.rs index a39a7c0c..5833b821 100644 --- a/aes/src/ni.rs +++ b/aes/src/ni.rs @@ -30,6 +30,7 @@ use core::arch::x86_64 as arch; use cipher::{ consts::{self, U16, U24, U32}, + crypto_common::WeakKeyError, AlgorithmName, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, Key, KeyInit, KeySizeUser, }; @@ -118,6 +119,10 @@ macro_rules! define_aes_impl { let decrypt = $name_dec::from(&encrypt); Self { encrypt, decrypt } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl From<$name_enc> for $name { @@ -193,6 +198,10 @@ macro_rules! define_aes_impl { backend: $name_back_enc::new(key), } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl BlockSizeUser for $name_enc { @@ -253,6 +262,10 @@ macro_rules! define_aes_impl { fn new(key: &Key) -> Self { $name_enc::new(key).into() } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl From<$name_enc> for $name_dec { diff --git a/aes/src/soft.rs b/aes/src/soft.rs index 9e5f9bef..19c2576d 100644 --- a/aes/src/soft.rs +++ b/aes/src/soft.rs @@ -15,6 +15,7 @@ pub(crate) mod fixslice; use crate::Block; use cipher::{ consts::{U16, U24, U32}, + crypto_common::WeakKeyError, inout::InOut, AlgorithmName, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, Key, KeyInit, @@ -67,6 +68,10 @@ macro_rules! define_aes_impl { keys: $fixslice_key_schedule(key.into()), } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl BlockSizeUser for $name { @@ -146,6 +151,10 @@ macro_rules! define_aes_impl { let inner = $name::new(key); Self { inner } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl BlockSizeUser for $name_enc { @@ -197,6 +206,10 @@ macro_rules! define_aes_impl { let inner = $name::new(key); Self { inner } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test!(key, Self) + } } impl From<$name_enc> for $name_dec { diff --git a/aes/tests/weak.rs b/aes/tests/weak.rs new file mode 100644 index 00000000..f95c1bcf --- /dev/null +++ b/aes/tests/weak.rs @@ -0,0 +1,24 @@ +use aes::Aes128; +use cipher::{Key, KeyInit}; +use hex_literal::hex; + +#[test] +fn test_weak_key() { + for k in &[ + hex!("00000000000000000000000000000000"), + hex!("00000000000000000101010101010101"), + hex!("00000000000000000100000000000000"), + ] { + let k = Key::::from(*k); + assert!(Aes128::weak_key_test(&k).is_err()); + } + + for k in &[ + hex!("00000000010000000000000000000000"), + hex!("00000000010000000101010101010101"), + hex!("00000000010000000100000000000000"), + ] { + let k = Key::::from(*k); + assert!(Aes128::weak_key_test(&k).is_ok()); + } +} diff --git a/des/Cargo.toml b/des/Cargo.toml index f839232f..be4cf9c5 100644 --- a/des/Cargo.toml +++ b/des/Cargo.toml @@ -14,6 +14,7 @@ categories = ["cryptography", "no-std"] [dependencies] cipher = "=0.5.0-pre.7" +subtle = { version = "2.6", default-features = false } [dev-dependencies] cipher = { version = "=0.5.0-pre.7", features = ["dev"] } diff --git a/des/src/des.rs b/des/src/des.rs index 128e4c3c..b45cae55 100644 --- a/des/src/des.rs +++ b/des/src/des.rs @@ -4,11 +4,13 @@ use cipher::{ consts::{U1, U8}, + crypto_common::WeakKeyError, AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InOut, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, }; use core::fmt; +use subtle::{Choice, ConstantTimeEq}; #[cfg(feature = "zeroize")] use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; @@ -43,12 +45,93 @@ impl KeySizeUser for Des { type KeySize = U8; } +static WEAK_KEYS: [[u8; 8]; 64] = [ + [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], + [0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], + [0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1], + [0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E], + [0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E], + [0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01], + [0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1], + [0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01], + [0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE], + [0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01], + [0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1], + [0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E], + [0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE], + [0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E], + [0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE], + [0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1], + [0x01, 0x01, 0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E], + [0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E, 0x01, 0x01], + [0xE0, 0xE0, 0x1F, 0x1F, 0xF1, 0xF1, 0x0E, 0x0E], + [0x01, 0x01, 0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1], + [0x1F, 0x1F, 0xE0, 0xE0, 0x0E, 0x0E, 0xF1, 0xF1], + [0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1, 0xFE, 0xFE], + [0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE], + [0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E, 0xFE, 0xFE], + [0xE0, 0xFE, 0x01, 0x1F, 0xF1, 0xFE, 0x01, 0x0E], + [0x01, 0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E, 0x01], + [0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1, 0x01, 0xFE], + [0xE0, 0xFE, 0x1F, 0x01, 0xF1, 0xFE, 0x0E, 0x01], + [0x01, 0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1, 0xFE], + [0x1F, 0xE0, 0xE0, 0x1F, 0x0E, 0xF1, 0xF1, 0x0E], + [0xE0, 0xFE, 0xFE, 0xE0, 0xF1, 0xFE, 0xFE, 0xF1], + [0x01, 0x1F, 0xFE, 0xE0, 0x01, 0x0E, 0xFE, 0xF1], + [0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1, 0xFE, 0x01], + [0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE], + [0x01, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E, 0xFE], + [0x1F, 0xFE, 0x01, 0xE0, 0x0E, 0xFE, 0x01, 0xF1], + [0xFE, 0x01, 0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1], + [0xFE, 0x01, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E], + [0x1F, 0xFE, 0xE0, 0x01, 0x0E, 0xFE, 0xF1, 0x01], + [0xFE, 0x1F, 0x01, 0xE0, 0xFE, 0x0E, 0x01, 0xF1], + [0x01, 0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1, 0x01], + [0x1F, 0xFE, 0xFE, 0x1F, 0x0E, 0xFE, 0xFE, 0x0E], + [0xFE, 0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1, 0x01], + [0x01, 0xE0, 0xFE, 0x1F, 0x01, 0xF1, 0xFE, 0x0E], + [0xE0, 0x01, 0x01, 0xE0, 0xF1, 0x01, 0x01, 0xF1], + [0xFE, 0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E, 0xFE], + [0x01, 0xFE, 0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1], + [0xE0, 0x01, 0x1F, 0xFE, 0xF1, 0x01, 0x0E, 0xFE], + [0xFE, 0xE0, 0x01, 0x1F, 0xFE, 0xF1, 0x01, 0x0E], + [0x01, 0xFE, 0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E], + [0xE0, 0x01, 0xFE, 0x1F, 0xF1, 0x01, 0xFE, 0x0E], + [0xFE, 0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E, 0x01], + [0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01], + [0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E, 0x01, 0xFE], + [0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1, 0xFE], + [0x1F, 0x01, 0x01, 0x1F, 0x0E, 0x01, 0x01, 0x0E], + [0xE0, 0x1F, 0x1F, 0xE0, 0xF1, 0x0E, 0x0E, 0xF1], + [0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01], + [0x1F, 0x01, 0xE0, 0xFE, 0x0E, 0x01, 0xF1, 0xFE], + [0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E, 0xFE, 0x01], + [0xFE, 0xFE, 0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E], + [0x1F, 0x01, 0xFE, 0xE0, 0x0E, 0x01, 0xFE, 0xF1], + [0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1, 0x01, 0x01], + [0xFE, 0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1], +]; + impl KeyInit for Des { #[inline] fn new(key: &Key) -> Self { let keys = gen_keys(u64::from_be_bytes(key.0)); Self { keys } } + + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + let mut weak = Choice::from(0); + + for weak_key in &WEAK_KEYS { + weak |= key.ct_eq(weak_key); + } + + if weak.unwrap_u8() == 0 { + Ok(()) + } else { + Err(WeakKeyError) + } + } } impl BlockSizeUser for Des {