Coverage Report

Created: 2025-12-31 06:13

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