Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 97 additions & 2 deletions aws-lc-rs/src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,10 +548,27 @@ impl EncryptingKey {
Self::new(key, OperatingMode::CFB128)
}

/// Constructs an `EncryptingKey` operating in cipher block chaining (CBC) mode using the provided key.
///
/// # ☠️ ️️️DANGER ☠️
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
/// very likely not what you want to use.
///
// # FIPS
// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
// * `AES_128`
// * `AES_256`
//
/// # Errors
/// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
Self::new(key, OperatingMode::CBC)
}

/// Constructs an `EncryptingKey` operating in electronic code book mode (ECB) using the provided key.
///
/// # ☠️ ️️️DANGER ☠️
/// Offered for computability purposes only. This is an extremely dangerous mode, and
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
/// very likely not what you want to use.
///
// # FIPS
Expand Down Expand Up @@ -672,10 +689,27 @@ impl DecryptingKey {
Self::new(key, OperatingMode::CFB128)
}

/// Constructs an `DecryptingKey` operating in cipher block chaining (CBC) mode using the provided key and context.
///
/// # ☠️ ️️️DANGER ☠️
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
/// very likely not what you want to use.
///
// # FIPS
// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
// * `AES_128`
// * `AES_256`
//
/// # Errors
/// * [`Unspecified`]: Returned if there is an error during decryption.
pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
Self::new(key, OperatingMode::CBC)
}

/// Constructs an `DecryptingKey` operating in electronic code book (ECB) mode using the provided key.
///
/// # ☠️ ️️️DANGER ☠️
/// Offered for computability purposes only. This is an extremely dangerous mode, and
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
/// very likely not what you want to use.
///
// # FIPS
Expand Down Expand Up @@ -944,6 +978,27 @@ mod tests {
}
}

#[test]
fn test_aes_128_cbc() {
let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
// CBC mode requires input to be a multiple of block size (16 bytes)
for i in 0..=3 {
let size = i * 16; // Test with 0, 16, 32, 48 bytes
helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
}
}

#[test]
fn test_aes_256_cbc() {
let key =
from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
// CBC mode requires input to be a multiple of block size (16 bytes)
for i in 0..=3 {
let size = i * 16; // Test with 0, 16, 32, 48 bytes
helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
}
}

#[test]
fn test_aes_128_ecb() {
let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
Expand Down Expand Up @@ -1096,4 +1151,44 @@ mod tests {
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
);

cipher_kat!(
test_sp800_38a_cbc_aes128,
&AES_128,
OperatingMode::CBC,
"2b7e151628aed2a6abf7158809cf4f3c",
"000102030405060708090a0b0c0d0e0f",
"6bc1bee22e409f96e93d7e117393172a",
"7649abac8119b246cee98e9b12e9197d"
);

cipher_kat!(
test_sp800_38a_cbc_aes256,
&AES_256,
OperatingMode::CBC,
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"000102030405060708090a0b0c0d0e0f",
"6bc1bee22e409f96e93d7e117393172a",
"f58c4c04d6e5f1ba779eabfb5f7bfbd6"
);

cipher_kat!(
test_sp800_38a_cbc_aes128_multi_block,
&AES_128,
OperatingMode::CBC,
"2b7e151628aed2a6abf7158809cf4f3c",
"000102030405060708090a0b0c0d0e0f",
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
);

cipher_kat!(
test_sp800_38a_cbc_aes256_multi_block,
&AES_256,
OperatingMode::CBC,
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
"000102030405060708090a0b0c0d0e0f",
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
"f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
);
}
170 changes: 125 additions & 45 deletions aws-lc-rs/tests/cipher_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,34 +303,16 @@ macro_rules! padded_ecb_pkcs7_kat {

macro_rules! cipher_kat {
($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
#[test]
fn $name() {
let key = from_hex($key).unwrap();
let input = from_hex($plaintext).unwrap();
let expected_ciphertext = from_hex($ciphertext).unwrap();

let iv = from_hex($iv).unwrap();
let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap();
let context = EncryptionContext::Iv128(fixed_iv);

let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();

let encrypting_key = EncryptingKey::$constructor(unbound_key).unwrap();
assert_eq!($mode, encrypting_key.mode());
assert_eq!($alg, encrypting_key.algorithm());
let mut in_out = input.clone();
let context = encrypting_key
.less_safe_encrypt(in_out.as_mut_slice(), context)
.unwrap();
assert_eq!(expected_ciphertext.as_slice(), in_out);

let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
let decrypting_key = DecryptingKey::$constructor(unbound_key2).unwrap();
assert_eq!($mode, decrypting_key.mode());
assert_eq!($alg, decrypting_key.algorithm());
let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
assert_eq!(input.as_slice(), plaintext);
}
unpadded_cipher_kat!(
$name,
$alg,
$mode,
$constructor,
$key,
$iv,
$plaintext,
$ciphertext
);

streaming_cipher_kat!(
$name,
Expand All @@ -347,47 +329,64 @@ macro_rules! cipher_kat {
};
}

macro_rules! ecb_kat {
($name:ident, $alg:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
macro_rules! unpadded_cipher_kat {
($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
#[test]
fn $name() {
let key = from_hex($key).unwrap();
let input = from_hex($plaintext).unwrap();
let expected_ciphertext = from_hex($ciphertext).unwrap();

let context = if $iv.len() == 0 {
EncryptionContext::None
} else {
let iv = from_hex($iv).unwrap();
let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap();
EncryptionContext::Iv128(fixed_iv)
};

let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();

let encrypting_key = EncryptingKey::ecb(unbound_key).unwrap();
assert_eq!(OperatingMode::ECB, encrypting_key.mode());
let encrypting_key = EncryptingKey::$constructor(unbound_key).unwrap();
assert_eq!($mode, encrypting_key.mode());
assert_eq!($alg, encrypting_key.algorithm());
let mut in_out = input.clone();
let context = encrypting_key
.less_safe_encrypt(in_out.as_mut_slice(), EncryptionContext::None)
.less_safe_encrypt(in_out.as_mut_slice(), context)
.unwrap();
assert_eq!(expected_ciphertext.as_slice(), in_out);

let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
let decrypting_key = DecryptingKey::ecb(unbound_key2).unwrap();
assert_eq!(OperatingMode::ECB, decrypting_key.mode());
let decrypting_key = DecryptingKey::$constructor(unbound_key2).unwrap();
assert_eq!($mode, decrypting_key.mode());
assert_eq!($alg, decrypting_key.algorithm());
let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
assert_eq!(input.as_slice(), plaintext);
}
};
($name:ident, $alg:expr, $key:literal, $plaintext:literal) => {

($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal) => {
#[test]
fn $name() {
let key = from_hex($key).unwrap();
let input = from_hex($plaintext).unwrap();

let context = if $iv.len() == 0 {
EncryptionContext::None
} else {
let iv = from_hex($iv).unwrap();
let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap();
EncryptionContext::Iv128(fixed_iv)
};

let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();

let encrypting_key = EncryptingKey::ecb(unbound_key).unwrap();
assert_eq!(OperatingMode::ECB, encrypting_key.mode());
let encrypting_key = EncryptingKey::$constructor(unbound_key).unwrap();
assert_eq!($mode, encrypting_key.mode());
assert_eq!($alg, encrypting_key.algorithm());
let mut in_out = input.clone();
encrypting_key
.less_safe_encrypt(in_out.as_mut_slice(), EncryptionContext::None)
.less_safe_encrypt(in_out.as_mut_slice(), context)
.expect_err("expected encryption failure");
}
};
Expand Down Expand Up @@ -856,48 +855,66 @@ padded_ecb_pkcs7_kat!(
"f6dc9e368d2cdf6a2e97a022876eb9f2"
);

ecb_kat!(
unpadded_cipher_kat!(
test_kat_aes_128_ecb_16_bytes,
&AES_128,
OperatingMode::ECB,
ecb,
"f8efb984d9e813c96a79020bdfbb6032",
"", // ECB does not have an IV
"c4a500e39307dbe7727b5b3a36660f70",
"1eea416d959f747da26d48d2df11d205"
);

ecb_kat!(
unpadded_cipher_kat!(
test_kat_aes_192_ecb_16_bytes,
&AES_192,
OperatingMode::ECB,
ecb,
"4c6994ffa9dcdc805b60c2c0095334c42d95a8fc0ca5b080",
"", // ECB does not have an IV
"c4a500e39307dbe7727b5b3a36660f70",
"1f021658980c025396455f7bb7e01d07"
);

ecb_kat!(
unpadded_cipher_kat!(
test_kat_aes_128_ecb_15_bytes,
&AES_128,
OperatingMode::ECB,
ecb,
"f8efb984d9e813c96a79020bdfbb6032",
"", // ECB does not have an IV
"c4a500e39307dbe7727b5b3a36660f"
);

ecb_kat!(
unpadded_cipher_kat!(
test_kat_aes_192_ecb_15_bytes,
&AES_192,
OperatingMode::ECB,
ecb,
"c88f5b00a4ef9a6840e2acaf33f00a3bdc4e25895303fa72",
"", // ECB does not have an IV
"c4a500e39307dbe7727b5b3a36660f"
);

ecb_kat!(
unpadded_cipher_kat!(
test_kat_aes_256_ecb_16_bytes,
&AES_256,
OperatingMode::ECB,
ecb,
"d3c9173cbfc65d0e2b6f43ae57c2a6550b756f487bbb7b6404efec69aa74d411",
"", // ECB does not have an IV
"109082176cf2a9488b0cd887386bb84a",
"c8c9fece9883b26c0ca58e610493a318"
);

ecb_kat!(
unpadded_cipher_kat!(
test_kat_aes_256_ecb_15_bytes,
&AES_256,
OperatingMode::ECB,
ecb,
"d3c9173cbfc65d0e2b6f43ae57c2a6550b756f487bbb7b6404efec69aa74d411",
"", // ECB does not have an IV
"109082176cf2a9488b0cd887386bb8"
);

Expand Down Expand Up @@ -1029,3 +1046,66 @@ cipher_kat!(
"9c1675a95f573b4504e6bc5275d0df",
"b8e816bd9e74adebdacf9036cbda41"
);

unpadded_cipher_kat!(
test_kat_aes_128_cbc_16_bytes_raw,
&AES_128,
OperatingMode::CBC,
cbc,
"000102030405060708090a0b0c0d0e0f",
"00000000000000000000000000000000",
"00112233445566778899aabbccddeeff",
"69c4e0d86a7b0430d8cdb78070b4c55a"
);

unpadded_cipher_kat!(
test_kat_aes_192_cbc_16_bytes_raw,
&AES_192,
OperatingMode::CBC,
cbc,
"e08c15411774ec4a908b64eadc6ac4199c7cd453f3aaef53",
"00000000000000000000000000000000",
"00112233445566778899aabbccddeeff",
"fc7f57e545e92c0a0b364c3086d49bf0"
);

unpadded_cipher_kat!(
test_kat_aes_256_cbc_16_bytes_raw,
&AES_256,
OperatingMode::CBC,
cbc,
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"00000000000000000000000000000000",
"00112233445566778899aabbccddeeff",
"8ea2b7ca516745bfeafc49904b496089"
);

unpadded_cipher_kat!(
test_kat_aes_128_cbc_15_bytes_raw,
&AES_128,
OperatingMode::CBC,
cbc,
"000102030405060708090a0b0c0d0e0f",
"00000000000000000000000000000000",
"00112233445566778899aabbccddee"
);

unpadded_cipher_kat!(
test_kat_aes_192_cbc_15_bytes_raw,
&AES_192,
OperatingMode::CBC,
cbc,
"e08c15411774ec4a908b64eadc6ac4199c7cd453f3aaef53",
"00000000000000000000000000000000",
"00112233445566778899aabbccddee"
);

unpadded_cipher_kat!(
test_kat_aes_256_cbc_15_bytes_raw,
&AES_256,
OperatingMode::CBC,
cbc,
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
"00000000000000000000000000000000",
"00112233445566778899aabbccddee"
);
Loading