Skip to main content

bssl_crypto/cipher/
aes_cbc.rs

1/* Copyright 2023 The BoringSSL Authors
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16extern crate alloc;
17
18use crate::cipher::{
19    BlockCipher, Cipher, CipherError, CipherInitPurpose, EvpAes128Cbc, EvpAes256Cbc,
20};
21use alloc::vec::Vec;
22
23/// AES-CBC-128 Cipher implementation.
24pub struct Aes128Cbc(Cipher<EvpAes128Cbc>);
25
26impl BlockCipher for Aes128Cbc {
27    type Key = [u8; 16];
28    type Nonce = [u8; 16];
29
30    fn new_encrypt(key: &Self::Key, nonce: &Self::Nonce) -> Self {
31        Self(Cipher::new(key, nonce, CipherInitPurpose::Encrypt))
32    }
33
34    fn new_decrypt(key: &Self::Key, nonce: &Self::Nonce) -> Self {
35        Self(Cipher::new(key, nonce, CipherInitPurpose::Decrypt))
36    }
37
38    fn encrypt_padded(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError> {
39        // Note: Padding is enabled because we did not disable it with `EVP_CIPHER_CTX_set_padding`
40        self.0.encrypt(buffer)
41    }
42
43    fn decrypt_padded(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError> {
44        // Note: Padding is enabled because we did not disable it with `EVP_CIPHER_CTX_set_padding`
45        self.0.decrypt(buffer)
46    }
47}
48
49/// AES-CBC-256 Cipher implementation.
50pub struct Aes256Cbc(Cipher<EvpAes256Cbc>);
51
52impl BlockCipher for Aes256Cbc {
53    type Key = [u8; 32];
54    type Nonce = [u8; 16];
55
56    fn new_encrypt(key: &Self::Key, nonce: &Self::Nonce) -> Self {
57        Self(Cipher::new(key, nonce, CipherInitPurpose::Encrypt))
58    }
59
60    fn new_decrypt(key: &Self::Key, nonce: &Self::Nonce) -> Self {
61        Self(Cipher::new(key, nonce, CipherInitPurpose::Decrypt))
62    }
63
64    fn encrypt_padded(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError> {
65        // Note: Padding is enabled because we did not disable it with `EVP_CIPHER_CTX_set_padding`
66        self.0.encrypt(buffer)
67    }
68
69    fn decrypt_padded(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError> {
70        // Note: Padding is enabled because we did not disable it with `EVP_CIPHER_CTX_set_padding`
71        self.0.decrypt(buffer)
72    }
73}
74
75#[allow(clippy::expect_used)]
76#[cfg(test)]
77mod test {
78    use super::*;
79    use crate::test_helpers::decode_hex;
80
81    #[test]
82    fn aes_128_cbc_test_encrypt() {
83        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L30
84        // tcId: 2
85        let iv = decode_hex("c9ee3cd746bf208c65ca9e72a266d54f");
86        let key = decode_hex("e09eaa5a3f5e56d279d5e7a03373f6ea");
87
88        let cipher = Aes128Cbc::new_encrypt(&key, &iv);
89        let msg: [u8; 16] = decode_hex("ef4eab37181f98423e53e947e7050fd0");
90
91        let output = cipher.encrypt_padded(&msg).expect("Failed to encrypt");
92
93        let expected_ciphertext: [u8; 32] =
94            decode_hex("d1fa697f3e2e04d64f1a0da203813ca5bc226a0b1d42287b2a5b994a66eaf14a");
95        assert_eq!(expected_ciphertext, &output[..]);
96    }
97
98    #[test]
99    fn aes_128_cbc_test_encrypt_more_than_one_block() {
100        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L210
101        // tcId: 20
102        let iv = decode_hex("54f2459e40e002763144f4752cde2fb5");
103        let key = decode_hex("831e664c9e3f0c3094c0b27b9d908eb2");
104
105        let cipher = Aes128Cbc::new_encrypt(&key, &iv);
106        let msg: [u8; 17] = decode_hex("26603bb76dd0a0180791c4ed4d3b058807");
107
108        let output = cipher.encrypt_padded(&msg).expect("Failed to encrypt");
109
110        let expected_ciphertext: [u8; 32] =
111            decode_hex("8d55dc10584e243f55d2bdbb5758b7fabcd58c8d3785f01c7e3640b2a1dadcd9");
112        assert_eq!(expected_ciphertext, &output[..]);
113    }
114
115    #[test]
116    fn aes_128_cbc_test_decrypt() {
117        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L30
118        // tcId: 2
119        let key = decode_hex("e09eaa5a3f5e56d279d5e7a03373f6ea");
120        let iv = decode_hex("c9ee3cd746bf208c65ca9e72a266d54f");
121        let cipher = Aes128Cbc::new_decrypt(&key, &iv);
122        let ciphertext: [u8; 32] =
123            decode_hex("d1fa697f3e2e04d64f1a0da203813ca5bc226a0b1d42287b2a5b994a66eaf14a");
124        let decrypted = cipher
125            .decrypt_padded(&ciphertext)
126            .expect("Failed to decrypt");
127        let expected_plaintext: [u8; 16] = decode_hex("ef4eab37181f98423e53e947e7050fd0");
128        assert_eq!(expected_plaintext, &decrypted[..]);
129    }
130
131    #[test]
132    fn aes_128_cbc_test_decrypt_empty_message() {
133        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L20
134        // tcId: 1
135        let key = decode_hex("e34f15c7bd819930fe9d66e0c166e61c");
136        let iv = decode_hex("da9520f7d3520277035173299388bee2");
137        let cipher = Aes128Cbc::new_decrypt(&key, &iv);
138        let ciphertext: [u8; 16] = decode_hex("b10ab60153276941361000414aed0a9d");
139        let decrypted = cipher
140            .decrypt_padded(&ciphertext)
141            .expect("Failed to decrypt");
142        let expected_plaintext: [u8; 0] = decode_hex("");
143        assert_eq!(expected_plaintext, &decrypted[..]);
144    }
145
146    #[test]
147    pub fn aes_256_cbc_test_encrypt() {
148        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L1412
149        // tcId: 124
150        let iv = decode_hex("9ec7b863ac845cad5e4673da21f5b6a9");
151        let key = decode_hex("612e837843ceae7f61d49625faa7e7494f9253e20cb3adcea686512b043936cd");
152
153        let cipher = Aes256Cbc::new_encrypt(&key, &iv);
154        let msg: [u8; 16] = decode_hex("cc37fae15f745a2f40e2c8b192f2b38d");
155
156        let output = cipher.encrypt_padded(&msg).expect("Failed to encrypt");
157
158        let expected_ciphertext: [u8; 32] =
159            decode_hex("299295be47e9f5441fe83a7a811c4aeb2650333e681e69fa6b767d28a6ccf282");
160        assert_eq!(expected_ciphertext, &output[..]);
161    }
162
163    #[test]
164    pub fn aes_256_cbc_test_encrypt_more_than_one_block() {
165        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L1582C24-L1582C24
166        // tcId: 141
167        let iv = decode_hex("4b74bd981ea9d074757c3e2ef515e5fb");
168        let key = decode_hex("73216fafd0022d0d6ee27198b2272578fa8f04dd9f44467fbb6437aa45641bf7");
169
170        let cipher = Aes256Cbc::new_encrypt(&key, &iv);
171        let msg: [u8; 17] = decode_hex("d5247b8f6c3edcbfb1d591d13ece23d2f5");
172
173        let output = cipher.encrypt_padded(&msg).expect("Failed to encrypt");
174
175        let expected_ciphertext: [u8; 32] =
176            decode_hex("fbea776fb1653635f88e2937ed2450ba4e9063e96d7cdba04928f01cb85492fe");
177        assert_eq!(expected_ciphertext, &output[..]);
178    }
179
180    #[test]
181    fn aes_256_cbc_test_decrypt() {
182        // https://github.com/google/wycheproof/blob/master/testvectors/aes_cbc_pkcs5_test.json#L1452
183        // tcId: 128
184        let key = decode_hex("ea3b016bdd387dd64d837c71683808f335dbdc53598a4ea8c5f952473fafaf5f");
185        let iv = decode_hex("fae3e2054113f6b3b904aadbfe59655c");
186        let cipher = Aes256Cbc::new_decrypt(&key, &iv);
187        let ciphertext: [u8; 16] = decode_hex("b90c326b72eb222ddb4dae47f2bc223c");
188        let decrypted = cipher
189            .decrypt_padded(&ciphertext)
190            .expect("Failed to decrypt");
191        let expected_plaintext: [u8; 2] = decode_hex("6601");
192        assert_eq!(expected_plaintext, &decrypted[..]);
193    }
194}