aws_lc_rs/cipher/
aes.rs

1// Copyright 2018 Brian Smith.
2// SPDX-License-Identifier: ISC
3// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6use crate::aws_lc::{
7    AES_cbc_encrypt, AES_cfb128_encrypt, AES_ctr128_encrypt, AES_ecb_encrypt, AES_DECRYPT,
8    AES_ENCRYPT, AES_KEY,
9};
10use crate::cipher::block::Block;
11use crate::error::Unspecified;
12use crate::fips::indicator_check;
13use zeroize::Zeroize;
14
15use super::{DecryptionContext, EncryptionContext, OperatingMode, SymmetricCipherKey};
16
17/// Length of an AES-128 key in bytes.
18pub const AES_128_KEY_LEN: usize = 16;
19
20/// Length of an AES-192 key in bytes.
21pub const AES_192_KEY_LEN: usize = 24;
22
23/// Length of an AES-256 key in bytes.
24pub const AES_256_KEY_LEN: usize = 32;
25
26/// The number of bytes for an AES-CBC initialization vector (IV)
27pub const AES_CBC_IV_LEN: usize = 16;
28
29/// The number of bytes for an AES-CTR initialization vector (IV)
30pub const AES_CTR_IV_LEN: usize = 16;
31
32/// The number of bytes for an AES-CFB initialization vector (IV)
33pub const AES_CFB_IV_LEN: usize = 16;
34
35pub const AES_BLOCK_LEN: usize = 16;
36
37#[inline]
38pub(crate) fn encrypt_block(aes_key: &AES_KEY, mut block: Block) -> Block {
39    {
40        let block_ref = block.as_mut();
41        debug_assert_eq!(block_ref.len(), AES_BLOCK_LEN);
42        aes_ecb_encrypt(aes_key, block_ref);
43    }
44    block
45}
46
47pub(super) fn encrypt_ctr_mode(
48    key: &SymmetricCipherKey,
49    context: EncryptionContext,
50    in_out: &mut [u8],
51) -> Result<DecryptionContext, Unspecified> {
52    let (SymmetricCipherKey::Aes128 { enc_key, .. }
53    | SymmetricCipherKey::Aes192 { enc_key, .. }
54    | SymmetricCipherKey::Aes256 { enc_key, .. }) = &key
55    else {
56        unreachable!()
57    };
58
59    let mut iv = {
60        let mut iv = [0u8; AES_CTR_IV_LEN];
61        iv.copy_from_slice((&context).try_into()?);
62        iv
63    };
64
65    let mut buffer = [0u8; AES_BLOCK_LEN];
66
67    aes_ctr128_encrypt(enc_key, &mut iv, &mut buffer, in_out);
68    iv.zeroize();
69
70    Ok(context.into())
71}
72
73pub(super) fn decrypt_ctr_mode<'in_out>(
74    key: &SymmetricCipherKey,
75    context: DecryptionContext,
76    in_out: &'in_out mut [u8],
77) -> Result<&'in_out mut [u8], Unspecified> {
78    // it's the same in CTR, just providing a nice named wrapper to match
79    encrypt_ctr_mode(key, context.into(), in_out).map(|_| in_out)
80}
81
82pub(super) fn encrypt_cbc_mode(
83    key: &SymmetricCipherKey,
84    context: EncryptionContext,
85    in_out: &mut [u8],
86) -> Result<DecryptionContext, Unspecified> {
87    let (SymmetricCipherKey::Aes128 { enc_key, .. }
88    | SymmetricCipherKey::Aes192 { enc_key, .. }
89    | SymmetricCipherKey::Aes256 { enc_key, .. }) = &key
90    else {
91        unreachable!()
92    };
93
94    let mut iv = {
95        let mut iv = [0u8; AES_CBC_IV_LEN];
96        iv.copy_from_slice((&context).try_into()?);
97        iv
98    };
99
100    aes_cbc_encrypt(enc_key, &mut iv, in_out);
101    iv.zeroize();
102
103    Ok(context.into())
104}
105
106#[allow(clippy::needless_pass_by_value)]
107pub(super) fn decrypt_cbc_mode<'in_out>(
108    key: &SymmetricCipherKey,
109    context: DecryptionContext,
110    in_out: &'in_out mut [u8],
111) -> Result<&'in_out mut [u8], Unspecified> {
112    let (SymmetricCipherKey::Aes128 { dec_key, .. }
113    | SymmetricCipherKey::Aes192 { dec_key, .. }
114    | SymmetricCipherKey::Aes256 { dec_key, .. }) = &key
115    else {
116        unreachable!()
117    };
118
119    let mut iv = {
120        let mut iv = [0u8; AES_CBC_IV_LEN];
121        iv.copy_from_slice((&context).try_into()?);
122        iv
123    };
124
125    aes_cbc_decrypt(dec_key, &mut iv, in_out);
126    iv.zeroize();
127
128    Ok(in_out)
129}
130
131#[allow(clippy::needless_pass_by_value)]
132pub(super) fn encrypt_cfb_mode(
133    key: &SymmetricCipherKey,
134    mode: OperatingMode,
135    context: EncryptionContext,
136    in_out: &mut [u8],
137) -> Result<DecryptionContext, Unspecified> {
138    let (SymmetricCipherKey::Aes128 { enc_key, .. }
139    | SymmetricCipherKey::Aes192 { enc_key, .. }
140    | SymmetricCipherKey::Aes256 { enc_key, .. }) = &key
141    else {
142        unreachable!()
143    };
144
145    let mut iv = {
146        let mut iv = [0u8; AES_CFB_IV_LEN];
147        iv.copy_from_slice((&context).try_into()?);
148        iv
149    };
150
151    let cfb_encrypt: fn(&AES_KEY, &mut [u8], &mut [u8]) = match mode {
152        // TODO: Hopefully support CFB1, and CFB8
153        OperatingMode::CFB128 => aes_cfb128_encrypt,
154        _ => unreachable!(),
155    };
156
157    cfb_encrypt(enc_key, &mut iv, in_out);
158    iv.zeroize();
159
160    Ok(context.into())
161}
162
163#[allow(clippy::needless_pass_by_value)]
164pub(super) fn decrypt_cfb_mode<'in_out>(
165    key: &SymmetricCipherKey,
166    mode: OperatingMode,
167    context: DecryptionContext,
168    in_out: &'in_out mut [u8],
169) -> Result<&'in_out mut [u8], Unspecified> {
170    let (SymmetricCipherKey::Aes128 { enc_key, .. }
171    | SymmetricCipherKey::Aes192 { enc_key, .. }
172    | SymmetricCipherKey::Aes256 { enc_key, .. }) = &key
173    else {
174        unreachable!()
175    };
176
177    let mut iv = {
178        let mut iv = [0u8; AES_CFB_IV_LEN];
179        iv.copy_from_slice((&context).try_into()?);
180        iv
181    };
182
183    let cfb_decrypt: fn(&AES_KEY, &mut [u8], &mut [u8]) = match mode {
184        // TODO: Hopefully support CFB1, and CFB8
185        OperatingMode::CFB128 => aes_cfb128_decrypt,
186        _ => unreachable!(),
187    };
188
189    cfb_decrypt(enc_key, &mut iv, in_out);
190
191    iv.zeroize();
192
193    Ok(in_out)
194}
195
196#[allow(clippy::needless_pass_by_value, clippy::unnecessary_wraps)]
197pub(super) fn encrypt_ecb_mode(
198    key: &SymmetricCipherKey,
199    context: EncryptionContext,
200    in_out: &mut [u8],
201) -> Result<DecryptionContext, Unspecified> {
202    if !matches!(context, EncryptionContext::None) {
203        unreachable!();
204    }
205
206    let (SymmetricCipherKey::Aes128 { enc_key, .. }
207    | SymmetricCipherKey::Aes192 { enc_key, .. }
208    | SymmetricCipherKey::Aes256 { enc_key, .. }) = &key
209    else {
210        unreachable!()
211    };
212
213    let mut in_out_iter = in_out.chunks_exact_mut(AES_BLOCK_LEN);
214
215    for block in in_out_iter.by_ref() {
216        aes_ecb_encrypt(enc_key, block);
217    }
218
219    // This is a sanity check that should not happen. We validate in `encrypt` that in_out.len() % block_len == 0
220    // for this mode.
221    debug_assert!(in_out_iter.into_remainder().is_empty());
222
223    Ok(context.into())
224}
225
226#[allow(clippy::needless_pass_by_value, clippy::unnecessary_wraps)]
227pub(super) fn decrypt_ecb_mode<'in_out>(
228    key: &SymmetricCipherKey,
229    context: DecryptionContext,
230    in_out: &'in_out mut [u8],
231) -> Result<&'in_out mut [u8], Unspecified> {
232    if !matches!(context, DecryptionContext::None) {
233        unreachable!();
234    }
235
236    let (SymmetricCipherKey::Aes128 { dec_key, .. }
237    | SymmetricCipherKey::Aes192 { dec_key, .. }
238    | SymmetricCipherKey::Aes256 { dec_key, .. }) = &key
239    else {
240        unreachable!()
241    };
242
243    {
244        let mut in_out_iter = in_out.chunks_exact_mut(AES_BLOCK_LEN);
245
246        for block in in_out_iter.by_ref() {
247            aes_ecb_decrypt(dec_key, block);
248        }
249
250        // This is a sanity check hat should not fail. We validate in `decrypt` that in_out.len() % block_len == 0 for
251        // this mode.
252        debug_assert!(in_out_iter.into_remainder().is_empty());
253    }
254
255    Ok(in_out)
256}
257
258fn aes_ecb_encrypt(key: &AES_KEY, in_out: &mut [u8]) {
259    indicator_check!(unsafe {
260        AES_ecb_encrypt(in_out.as_ptr(), in_out.as_mut_ptr(), key, AES_ENCRYPT);
261    });
262}
263
264fn aes_ecb_decrypt(key: &AES_KEY, in_out: &mut [u8]) {
265    indicator_check!(unsafe {
266        AES_ecb_encrypt(in_out.as_ptr(), in_out.as_mut_ptr(), key, AES_DECRYPT);
267    });
268}
269
270fn aes_ctr128_encrypt(key: &AES_KEY, iv: &mut [u8], block_buffer: &mut [u8], in_out: &mut [u8]) {
271    let mut num: u32 = 0;
272
273    indicator_check!(unsafe {
274        AES_ctr128_encrypt(
275            in_out.as_ptr(),
276            in_out.as_mut_ptr(),
277            in_out.len(),
278            key,
279            iv.as_mut_ptr(),
280            block_buffer.as_mut_ptr(),
281            &mut num,
282        );
283    });
284
285    Zeroize::zeroize(block_buffer);
286}
287
288fn aes_cbc_encrypt(key: &AES_KEY, iv: &mut [u8], in_out: &mut [u8]) {
289    indicator_check!(unsafe {
290        AES_cbc_encrypt(
291            in_out.as_ptr(),
292            in_out.as_mut_ptr(),
293            in_out.len(),
294            key,
295            iv.as_mut_ptr(),
296            AES_ENCRYPT,
297        );
298    });
299}
300
301fn aes_cbc_decrypt(key: &AES_KEY, iv: &mut [u8], in_out: &mut [u8]) {
302    indicator_check!(unsafe {
303        AES_cbc_encrypt(
304            in_out.as_ptr(),
305            in_out.as_mut_ptr(),
306            in_out.len(),
307            key,
308            iv.as_mut_ptr(),
309            AES_DECRYPT,
310        );
311    });
312}
313
314fn aes_cfb128_encrypt(key: &AES_KEY, iv: &mut [u8], in_out: &mut [u8]) {
315    let mut num: i32 = 0;
316    indicator_check!(unsafe {
317        AES_cfb128_encrypt(
318            in_out.as_ptr(),
319            in_out.as_mut_ptr(),
320            in_out.len(),
321            key,
322            iv.as_mut_ptr(),
323            &mut num,
324            AES_ENCRYPT,
325        );
326    });
327}
328
329fn aes_cfb128_decrypt(key: &AES_KEY, iv: &mut [u8], in_out: &mut [u8]) {
330    let mut num: i32 = 0;
331    indicator_check!(unsafe {
332        AES_cfb128_encrypt(
333            in_out.as_ptr(),
334            in_out.as_mut_ptr(),
335            in_out.len(),
336            key,
337            iv.as_mut_ptr(),
338            &mut num,
339            AES_DECRYPT,
340        );
341    });
342}