Skip to content

Commit cea4296

Browse files
ElvrarinYiming Linjustsmth
authored
Adds AES CBC mode no padding (#895)
* Adds AES CBC mode * Fix typo 'compatibility' * Add known-answer tests * More tests; unpadded_cipher_kat! --------- Co-authored-by: Yiming Lin <[email protected]> Co-authored-by: Justin Smith <[email protected]>
1 parent 08c02c9 commit cea4296

File tree

2 files changed

+222
-47
lines changed

2 files changed

+222
-47
lines changed

aws-lc-rs/src/cipher.rs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,10 +548,27 @@ impl EncryptingKey {
548548
Self::new(key, OperatingMode::CFB128)
549549
}
550550

551+
/// Constructs an `EncryptingKey` operating in cipher block chaining (CBC) mode using the provided key.
552+
///
553+
/// # ☠️ ️️️DANGER ☠️
554+
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
555+
/// very likely not what you want to use.
556+
///
557+
// # FIPS
558+
// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
559+
// * `AES_128`
560+
// * `AES_256`
561+
//
562+
/// # Errors
563+
/// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
564+
pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
565+
Self::new(key, OperatingMode::CBC)
566+
}
567+
551568
/// Constructs an `EncryptingKey` operating in electronic code book mode (ECB) using the provided key.
552569
///
553570
/// # ☠️ ️️️DANGER ☠️
554-
/// Offered for computability purposes only. This is an extremely dangerous mode, and
571+
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
555572
/// very likely not what you want to use.
556573
///
557574
// # FIPS
@@ -672,10 +689,27 @@ impl DecryptingKey {
672689
Self::new(key, OperatingMode::CFB128)
673690
}
674691

692+
/// Constructs an `DecryptingKey` operating in cipher block chaining (CBC) mode using the provided key and context.
693+
///
694+
/// # ☠️ ️️️DANGER ☠️
695+
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
696+
/// very likely not what you want to use.
697+
///
698+
// # FIPS
699+
// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
700+
// * `AES_128`
701+
// * `AES_256`
702+
//
703+
/// # Errors
704+
/// * [`Unspecified`]: Returned if there is an error during decryption.
705+
pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
706+
Self::new(key, OperatingMode::CBC)
707+
}
708+
675709
/// Constructs an `DecryptingKey` operating in electronic code book (ECB) mode using the provided key.
676710
///
677711
/// # ☠️ ️️️DANGER ☠️
678-
/// Offered for computability purposes only. This is an extremely dangerous mode, and
712+
/// Offered for compatibility purposes only. This is an extremely dangerous mode, and
679713
/// very likely not what you want to use.
680714
///
681715
// # FIPS
@@ -944,6 +978,27 @@ mod tests {
944978
}
945979
}
946980

981+
#[test]
982+
fn test_aes_128_cbc() {
983+
let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
984+
// CBC mode requires input to be a multiple of block size (16 bytes)
985+
for i in 0..=3 {
986+
let size = i * 16; // Test with 0, 16, 32, 48 bytes
987+
helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
988+
}
989+
}
990+
991+
#[test]
992+
fn test_aes_256_cbc() {
993+
let key =
994+
from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
995+
// CBC mode requires input to be a multiple of block size (16 bytes)
996+
for i in 0..=3 {
997+
let size = i * 16; // Test with 0, 16, 32, 48 bytes
998+
helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
999+
}
1000+
}
1001+
9471002
#[test]
9481003
fn test_aes_128_ecb() {
9491004
let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
@@ -1096,4 +1151,44 @@ mod tests {
10961151
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
10971152
"f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
10981153
);
1154+
1155+
cipher_kat!(
1156+
test_sp800_38a_cbc_aes128,
1157+
&AES_128,
1158+
OperatingMode::CBC,
1159+
"2b7e151628aed2a6abf7158809cf4f3c",
1160+
"000102030405060708090a0b0c0d0e0f",
1161+
"6bc1bee22e409f96e93d7e117393172a",
1162+
"7649abac8119b246cee98e9b12e9197d"
1163+
);
1164+
1165+
cipher_kat!(
1166+
test_sp800_38a_cbc_aes256,
1167+
&AES_256,
1168+
OperatingMode::CBC,
1169+
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1170+
"000102030405060708090a0b0c0d0e0f",
1171+
"6bc1bee22e409f96e93d7e117393172a",
1172+
"f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1173+
);
1174+
1175+
cipher_kat!(
1176+
test_sp800_38a_cbc_aes128_multi_block,
1177+
&AES_128,
1178+
OperatingMode::CBC,
1179+
"2b7e151628aed2a6abf7158809cf4f3c",
1180+
"000102030405060708090a0b0c0d0e0f",
1181+
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1182+
"7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1183+
);
1184+
1185+
cipher_kat!(
1186+
test_sp800_38a_cbc_aes256_multi_block,
1187+
&AES_256,
1188+
OperatingMode::CBC,
1189+
"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1190+
"000102030405060708090a0b0c0d0e0f",
1191+
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1192+
"f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1193+
);
10991194
}

aws-lc-rs/tests/cipher_test.rs

Lines changed: 125 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -303,34 +303,16 @@ macro_rules! padded_ecb_pkcs7_kat {
303303

304304
macro_rules! cipher_kat {
305305
($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
306-
#[test]
307-
fn $name() {
308-
let key = from_hex($key).unwrap();
309-
let input = from_hex($plaintext).unwrap();
310-
let expected_ciphertext = from_hex($ciphertext).unwrap();
311-
312-
let iv = from_hex($iv).unwrap();
313-
let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap();
314-
let context = EncryptionContext::Iv128(fixed_iv);
315-
316-
let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
317-
318-
let encrypting_key = EncryptingKey::$constructor(unbound_key).unwrap();
319-
assert_eq!($mode, encrypting_key.mode());
320-
assert_eq!($alg, encrypting_key.algorithm());
321-
let mut in_out = input.clone();
322-
let context = encrypting_key
323-
.less_safe_encrypt(in_out.as_mut_slice(), context)
324-
.unwrap();
325-
assert_eq!(expected_ciphertext.as_slice(), in_out);
326-
327-
let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
328-
let decrypting_key = DecryptingKey::$constructor(unbound_key2).unwrap();
329-
assert_eq!($mode, decrypting_key.mode());
330-
assert_eq!($alg, decrypting_key.algorithm());
331-
let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
332-
assert_eq!(input.as_slice(), plaintext);
333-
}
306+
unpadded_cipher_kat!(
307+
$name,
308+
$alg,
309+
$mode,
310+
$constructor,
311+
$key,
312+
$iv,
313+
$plaintext,
314+
$ciphertext
315+
);
334316

335317
streaming_cipher_kat!(
336318
$name,
@@ -347,47 +329,64 @@ macro_rules! cipher_kat {
347329
};
348330
}
349331

350-
macro_rules! ecb_kat {
351-
($name:ident, $alg:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
332+
macro_rules! unpadded_cipher_kat {
333+
($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
352334
#[test]
353335
fn $name() {
354336
let key = from_hex($key).unwrap();
355337
let input = from_hex($plaintext).unwrap();
356338
let expected_ciphertext = from_hex($ciphertext).unwrap();
357339

340+
let context = if $iv.len() == 0 {
341+
EncryptionContext::None
342+
} else {
343+
let iv = from_hex($iv).unwrap();
344+
let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap();
345+
EncryptionContext::Iv128(fixed_iv)
346+
};
347+
358348
let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
359349

360-
let encrypting_key = EncryptingKey::ecb(unbound_key).unwrap();
361-
assert_eq!(OperatingMode::ECB, encrypting_key.mode());
350+
let encrypting_key = EncryptingKey::$constructor(unbound_key).unwrap();
351+
assert_eq!($mode, encrypting_key.mode());
362352
assert_eq!($alg, encrypting_key.algorithm());
363353
let mut in_out = input.clone();
364354
let context = encrypting_key
365-
.less_safe_encrypt(in_out.as_mut_slice(), EncryptionContext::None)
355+
.less_safe_encrypt(in_out.as_mut_slice(), context)
366356
.unwrap();
367357
assert_eq!(expected_ciphertext.as_slice(), in_out);
368358

369359
let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap();
370-
let decrypting_key = DecryptingKey::ecb(unbound_key2).unwrap();
371-
assert_eq!(OperatingMode::ECB, decrypting_key.mode());
360+
let decrypting_key = DecryptingKey::$constructor(unbound_key2).unwrap();
361+
assert_eq!($mode, decrypting_key.mode());
372362
assert_eq!($alg, decrypting_key.algorithm());
373363
let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
374364
assert_eq!(input.as_slice(), plaintext);
375365
}
376366
};
377-
($name:ident, $alg:expr, $key:literal, $plaintext:literal) => {
367+
368+
($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal) => {
378369
#[test]
379370
fn $name() {
380371
let key = from_hex($key).unwrap();
381372
let input = from_hex($plaintext).unwrap();
382373

374+
let context = if $iv.len() == 0 {
375+
EncryptionContext::None
376+
} else {
377+
let iv = from_hex($iv).unwrap();
378+
let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap();
379+
EncryptionContext::Iv128(fixed_iv)
380+
};
381+
383382
let unbound_key = UnboundCipherKey::new($alg, &key).unwrap();
384383

385-
let encrypting_key = EncryptingKey::ecb(unbound_key).unwrap();
386-
assert_eq!(OperatingMode::ECB, encrypting_key.mode());
384+
let encrypting_key = EncryptingKey::$constructor(unbound_key).unwrap();
385+
assert_eq!($mode, encrypting_key.mode());
387386
assert_eq!($alg, encrypting_key.algorithm());
388387
let mut in_out = input.clone();
389388
encrypting_key
390-
.less_safe_encrypt(in_out.as_mut_slice(), EncryptionContext::None)
389+
.less_safe_encrypt(in_out.as_mut_slice(), context)
391390
.expect_err("expected encryption failure");
392391
}
393392
};
@@ -856,48 +855,66 @@ padded_ecb_pkcs7_kat!(
856855
"f6dc9e368d2cdf6a2e97a022876eb9f2"
857856
);
858857

859-
ecb_kat!(
858+
unpadded_cipher_kat!(
860859
test_kat_aes_128_ecb_16_bytes,
861860
&AES_128,
861+
OperatingMode::ECB,
862+
ecb,
862863
"f8efb984d9e813c96a79020bdfbb6032",
864+
"", // ECB does not have an IV
863865
"c4a500e39307dbe7727b5b3a36660f70",
864866
"1eea416d959f747da26d48d2df11d205"
865867
);
866868

867-
ecb_kat!(
869+
unpadded_cipher_kat!(
868870
test_kat_aes_192_ecb_16_bytes,
869871
&AES_192,
872+
OperatingMode::ECB,
873+
ecb,
870874
"4c6994ffa9dcdc805b60c2c0095334c42d95a8fc0ca5b080",
875+
"", // ECB does not have an IV
871876
"c4a500e39307dbe7727b5b3a36660f70",
872877
"1f021658980c025396455f7bb7e01d07"
873878
);
874879

875-
ecb_kat!(
880+
unpadded_cipher_kat!(
876881
test_kat_aes_128_ecb_15_bytes,
877882
&AES_128,
883+
OperatingMode::ECB,
884+
ecb,
878885
"f8efb984d9e813c96a79020bdfbb6032",
886+
"", // ECB does not have an IV
879887
"c4a500e39307dbe7727b5b3a36660f"
880888
);
881889

882-
ecb_kat!(
890+
unpadded_cipher_kat!(
883891
test_kat_aes_192_ecb_15_bytes,
884892
&AES_192,
893+
OperatingMode::ECB,
894+
ecb,
885895
"c88f5b00a4ef9a6840e2acaf33f00a3bdc4e25895303fa72",
896+
"", // ECB does not have an IV
886897
"c4a500e39307dbe7727b5b3a36660f"
887898
);
888899

889-
ecb_kat!(
900+
unpadded_cipher_kat!(
890901
test_kat_aes_256_ecb_16_bytes,
891902
&AES_256,
903+
OperatingMode::ECB,
904+
ecb,
892905
"d3c9173cbfc65d0e2b6f43ae57c2a6550b756f487bbb7b6404efec69aa74d411",
906+
"", // ECB does not have an IV
893907
"109082176cf2a9488b0cd887386bb84a",
894908
"c8c9fece9883b26c0ca58e610493a318"
895909
);
896910

897-
ecb_kat!(
911+
unpadded_cipher_kat!(
898912
test_kat_aes_256_ecb_15_bytes,
899913
&AES_256,
914+
OperatingMode::ECB,
915+
ecb,
900916
"d3c9173cbfc65d0e2b6f43ae57c2a6550b756f487bbb7b6404efec69aa74d411",
917+
"", // ECB does not have an IV
901918
"109082176cf2a9488b0cd887386bb8"
902919
);
903920

@@ -1029,3 +1046,66 @@ cipher_kat!(
10291046
"9c1675a95f573b4504e6bc5275d0df",
10301047
"b8e816bd9e74adebdacf9036cbda41"
10311048
);
1049+
1050+
unpadded_cipher_kat!(
1051+
test_kat_aes_128_cbc_16_bytes_raw,
1052+
&AES_128,
1053+
OperatingMode::CBC,
1054+
cbc,
1055+
"000102030405060708090a0b0c0d0e0f",
1056+
"00000000000000000000000000000000",
1057+
"00112233445566778899aabbccddeeff",
1058+
"69c4e0d86a7b0430d8cdb78070b4c55a"
1059+
);
1060+
1061+
unpadded_cipher_kat!(
1062+
test_kat_aes_192_cbc_16_bytes_raw,
1063+
&AES_192,
1064+
OperatingMode::CBC,
1065+
cbc,
1066+
"e08c15411774ec4a908b64eadc6ac4199c7cd453f3aaef53",
1067+
"00000000000000000000000000000000",
1068+
"00112233445566778899aabbccddeeff",
1069+
"fc7f57e545e92c0a0b364c3086d49bf0"
1070+
);
1071+
1072+
unpadded_cipher_kat!(
1073+
test_kat_aes_256_cbc_16_bytes_raw,
1074+
&AES_256,
1075+
OperatingMode::CBC,
1076+
cbc,
1077+
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1078+
"00000000000000000000000000000000",
1079+
"00112233445566778899aabbccddeeff",
1080+
"8ea2b7ca516745bfeafc49904b496089"
1081+
);
1082+
1083+
unpadded_cipher_kat!(
1084+
test_kat_aes_128_cbc_15_bytes_raw,
1085+
&AES_128,
1086+
OperatingMode::CBC,
1087+
cbc,
1088+
"000102030405060708090a0b0c0d0e0f",
1089+
"00000000000000000000000000000000",
1090+
"00112233445566778899aabbccddee"
1091+
);
1092+
1093+
unpadded_cipher_kat!(
1094+
test_kat_aes_192_cbc_15_bytes_raw,
1095+
&AES_192,
1096+
OperatingMode::CBC,
1097+
cbc,
1098+
"e08c15411774ec4a908b64eadc6ac4199c7cd453f3aaef53",
1099+
"00000000000000000000000000000000",
1100+
"00112233445566778899aabbccddee"
1101+
);
1102+
1103+
unpadded_cipher_kat!(
1104+
test_kat_aes_256_cbc_15_bytes_raw,
1105+
&AES_256,
1106+
OperatingMode::CBC,
1107+
cbc,
1108+
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1109+
"00000000000000000000000000000000",
1110+
"00112233445566778899aabbccddee"
1111+
);

0 commit comments

Comments
 (0)