Coverage Report

Created: 2026-11-12 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/openssl-0.10.62/src/aes.rs
Line
Count
Source
1
//! Low level AES IGE and key wrapping functionality
2
//!
3
//! AES ECB, CBC, XTS, CTR, CFB, GCM and other conventional symmetric encryption
4
//! modes are found in [`symm`].  This is the implementation of AES IGE and key wrapping
5
//!
6
//! Advanced Encryption Standard (AES) provides symmetric key cipher that
7
//! the same key is used to encrypt and decrypt data.  This implementation
8
//! uses 128, 192, or 256 bit keys.  This module provides functions to
9
//! create a new key with [`new_encrypt`] and perform an encryption/decryption
10
//! using that key with [`aes_ige`].
11
//!
12
//! [`new_encrypt`]: struct.AesKey.html#method.new_encrypt
13
//! [`aes_ige`]: fn.aes_ige.html
14
//!
15
//! The [`symm`] module should be used in preference to this module in most cases.
16
//! The IGE block cipher is a non-traditional cipher mode.  More traditional AES
17
//! encryption methods are found in the [`Crypter`] and [`Cipher`] structs.
18
//!
19
//! [`symm`]: ../symm/index.html
20
//! [`Crypter`]: ../symm/struct.Crypter.html
21
//! [`Cipher`]: ../symm/struct.Cipher.html
22
//!
23
//! # Examples
24
25
#![cfg_attr(
26
    all(not(boringssl), not(osslconf = "OPENSSL_NO_DEPRECATED_3_0")),
27
    doc = r#"\
28
## AES IGE
29
```rust
30
use openssl::aes::{AesKey, aes_ige};
31
use openssl::symm::Mode;
32
33
let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
34
let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56";
35
let mut iv = *b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\
36
                \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
37
38
 let key = AesKey::new_encrypt(key).unwrap();
39
 let mut output = [0u8; 16];
40
 aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt);
41
 assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32");
42
```"#
43
)]
44
45
//!
46
//! ## Key wrapping
47
//! ```rust
48
//! use openssl::aes::{AesKey, unwrap_key, wrap_key};
49
//!
50
//! let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
51
//! let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
52
//!
53
//! let enc_key = AesKey::new_encrypt(kek).unwrap();
54
//! let mut ciphertext = [0u8; 24];
55
//! wrap_key(&enc_key, None, &mut ciphertext, &key_to_wrap[..]).unwrap();
56
//! let dec_key = AesKey::new_decrypt(kek).unwrap();
57
//! let mut orig_key = [0u8; 16];
58
//! unwrap_key(&dec_key, None, &mut orig_key, &ciphertext[..]).unwrap();
59
//!
60
//! assert_eq!(&orig_key[..], &key_to_wrap[..]);
61
//! ```
62
//!
63
use cfg_if::cfg_if;
64
use libc::{c_int, c_uint};
65
use std::mem::MaybeUninit;
66
use std::ptr;
67
68
#[cfg(not(boringssl))]
69
use crate::symm::Mode;
70
use openssl_macros::corresponds;
71
72
/// Provides Error handling for parsing keys.
73
#[derive(Debug)]
74
pub struct KeyError(());
75
76
/// The key used to encrypt or decrypt cipher blocks.
77
pub struct AesKey(ffi::AES_KEY);
78
79
cfg_if! {
80
    if #[cfg(boringssl)] {
81
        type AesBitType = c_uint;
82
        type AesSizeType = usize;
83
    } else {
84
        type AesBitType = c_int;
85
        type AesSizeType = c_uint;
86
    }
87
}
88
89
impl AesKey {
90
    /// Prepares a key for encryption.
91
    ///
92
    /// # Failure
93
    ///
94
    /// Returns an error if the key is not 128, 192, or 256 bits.
95
    #[corresponds(AES_set_encrypt_key)]
96
0
    pub fn new_encrypt(key: &[u8]) -> Result<AesKey, KeyError> {
97
        unsafe {
98
0
            assert!(key.len() <= c_int::max_value() as usize / 8);
99
100
0
            let mut aes_key = MaybeUninit::uninit();
101
0
            let r = ffi::AES_set_encrypt_key(
102
0
                key.as_ptr() as *const _,
103
0
                key.len() as AesBitType * 8,
104
0
                aes_key.as_mut_ptr(),
105
            );
106
0
            if r == 0 {
107
0
                Ok(AesKey(aes_key.assume_init()))
108
            } else {
109
0
                Err(KeyError(()))
110
            }
111
        }
112
0
    }
113
114
    /// Prepares a key for decryption.
115
    ///
116
    /// # Failure
117
    ///
118
    /// Returns an error if the key is not 128, 192, or 256 bits.
119
    #[corresponds(AES_set_decrypt_key)]
120
0
    pub fn new_decrypt(key: &[u8]) -> Result<AesKey, KeyError> {
121
        unsafe {
122
0
            assert!(key.len() <= c_int::max_value() as usize / 8);
123
124
0
            let mut aes_key = MaybeUninit::uninit();
125
0
            let r = ffi::AES_set_decrypt_key(
126
0
                key.as_ptr() as *const _,
127
0
                key.len() as AesBitType * 8,
128
0
                aes_key.as_mut_ptr(),
129
            );
130
131
0
            if r == 0 {
132
0
                Ok(AesKey(aes_key.assume_init()))
133
            } else {
134
0
                Err(KeyError(()))
135
            }
136
        }
137
0
    }
138
}
139
140
/// Performs AES IGE encryption or decryption
141
///
142
/// AES IGE (Infinite Garble Extension) is a form of AES block cipher utilized in
143
/// OpenSSL.  Infinite Garble refers to propagating forward errors.  IGE, like other
144
/// block ciphers implemented for AES requires an initialization vector.  The IGE mode
145
/// allows a stream of blocks to be encrypted or decrypted without having the entire
146
/// plaintext available.  For more information, visit [AES IGE Encryption].
147
///
148
/// This block cipher uses 16 byte blocks.  The rust implementation will panic
149
/// if the input or output does not meet this 16-byte boundary.  Attention must
150
/// be made in this low level implementation to pad the value to the 128-bit boundary.
151
///
152
/// [AES IGE Encryption]: http://www.links.org/files/openssl-ige.pdf
153
///
154
/// # Panics
155
///
156
/// Panics if `in_` is not the same length as `out`, if that length is not a multiple of 16, or if
157
/// `iv` is not at least 32 bytes.
158
#[cfg(not(boringssl))]
159
#[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))]
160
#[corresponds(AES_ige_encrypt)]
161
0
pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mode) {
162
    unsafe {
163
0
        assert!(in_.len() == out.len());
164
0
        assert!(in_.len() % ffi::AES_BLOCK_SIZE as usize == 0);
165
0
        assert!(iv.len() >= ffi::AES_BLOCK_SIZE as usize * 2);
166
167
0
        let mode = match mode {
168
0
            Mode::Encrypt => ffi::AES_ENCRYPT,
169
0
            Mode::Decrypt => ffi::AES_DECRYPT,
170
        };
171
0
        ffi::AES_ige_encrypt(
172
0
            in_.as_ptr() as *const _,
173
0
            out.as_mut_ptr() as *mut _,
174
0
            in_.len(),
175
0
            &key.0,
176
0
            iv.as_mut_ptr() as *mut _,
177
0
            mode,
178
        );
179
    }
180
0
}
181
182
/// Wrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394)
183
///
184
/// * `key`: The key-encrypting-key to use. Must be a encrypting key
185
/// * `iv`: The IV to use. You must use the same IV for both wrapping and unwrapping
186
/// * `out`: The output buffer to store the ciphertext
187
/// * `in_`: The input buffer, storing the key to be wrapped
188
///
189
/// Returns the number of bytes written into `out`
190
///
191
/// # Panics
192
///
193
/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or if
194
/// `out` is not 8 bytes longer than `in_`
195
#[corresponds(AES_wrap_key)]
196
0
pub fn wrap_key(
197
0
    key: &AesKey,
198
0
    iv: Option<[u8; 8]>,
199
0
    out: &mut [u8],
200
0
    in_: &[u8],
201
0
) -> Result<usize, KeyError> {
202
    unsafe {
203
0
        assert!(out.len() >= in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1)
204
205
0
        let written = ffi::AES_wrap_key(
206
0
            &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer.
207
0
            iv.as_ref()
208
0
                .map_or(ptr::null(), |iv| iv.as_ptr() as *const _),
209
0
            out.as_ptr() as *mut _,
210
0
            in_.as_ptr() as *const _,
211
0
            in_.len() as AesSizeType,
212
        );
213
0
        if written <= 0 {
214
0
            Err(KeyError(()))
215
        } else {
216
0
            Ok(written as usize)
217
        }
218
    }
219
0
}
220
221
/// Unwrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394)
222
///
223
/// * `key`: The key-encrypting-key to decrypt the wrapped key. Must be a decrypting key
224
/// * `iv`: The same IV used for wrapping the key
225
/// * `out`: The buffer to write the unwrapped key to
226
/// * `in_`: The input ciphertext
227
///
228
/// Returns the number of bytes written into `out`
229
///
230
/// # Panics
231
///
232
/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or
233
/// if `in_` is not 8 bytes longer than `out`
234
#[corresponds(AES_unwrap_key)]
235
0
pub fn unwrap_key(
236
0
    key: &AesKey,
237
0
    iv: Option<[u8; 8]>,
238
0
    out: &mut [u8],
239
0
    in_: &[u8],
240
0
) -> Result<usize, KeyError> {
241
    unsafe {
242
0
        assert!(out.len() + 8 <= in_.len());
243
244
0
        let written = ffi::AES_unwrap_key(
245
0
            &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer.
246
0
            iv.as_ref()
247
0
                .map_or(ptr::null(), |iv| iv.as_ptr() as *const _),
248
0
            out.as_ptr() as *mut _,
249
0
            in_.as_ptr() as *const _,
250
0
            in_.len() as AesSizeType,
251
        );
252
253
0
        if written <= 0 {
254
0
            Err(KeyError(()))
255
        } else {
256
0
            Ok(written as usize)
257
        }
258
    }
259
0
}
260
261
#[cfg(test)]
262
mod test {
263
    use hex::FromHex;
264
265
    use super::*;
266
    #[cfg(not(boringssl))]
267
    use crate::symm::Mode;
268
269
    // From https://www.mgp25.com/AESIGE/
270
    #[test]
271
    #[cfg(not(boringssl))]
272
    #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))]
273
    fn ige_vector_1() {
274
        let raw_key = "000102030405060708090A0B0C0D0E0F";
275
        let raw_iv = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
276
        let raw_pt = "0000000000000000000000000000000000000000000000000000000000000000";
277
        let raw_ct = "1A8519A6557BE652E9DA8E43DA4EF4453CF456B4CA488AA383C79C98B34797CB";
278
279
        let key = AesKey::new_encrypt(&Vec::from_hex(raw_key).unwrap()).unwrap();
280
        let mut iv = Vec::from_hex(raw_iv).unwrap();
281
        let pt = Vec::from_hex(raw_pt).unwrap();
282
        let ct = Vec::from_hex(raw_ct).unwrap();
283
284
        let mut ct_actual = vec![0; ct.len()];
285
        aes_ige(&pt, &mut ct_actual, &key, &mut iv, Mode::Encrypt);
286
        assert_eq!(ct_actual, ct);
287
288
        let key = AesKey::new_decrypt(&Vec::from_hex(raw_key).unwrap()).unwrap();
289
        let mut iv = Vec::from_hex(raw_iv).unwrap();
290
        let mut pt_actual = vec![0; pt.len()];
291
        aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt);
292
        assert_eq!(pt_actual, pt);
293
    }
294
295
    // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3
296
    #[test]
297
    fn test_wrap_unwrap() {
298
        let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
299
        let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
300
        let expected_ciphertext =
301
            Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
302
303
        let enc_key = AesKey::new_encrypt(&raw_key).unwrap();
304
        let mut wrapped = [0; 24];
305
        assert_eq!(
306
            wrap_key(&enc_key, None, &mut wrapped, &key_data).unwrap(),
307
            24
308
        );
309
        assert_eq!(&wrapped[..], &expected_ciphertext[..]);
310
311
        let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
312
        let mut unwrapped = [0; 16];
313
        assert_eq!(
314
            unwrap_key(&dec_key, None, &mut unwrapped, &wrapped).unwrap(),
315
            16
316
        );
317
        assert_eq!(&unwrapped[..], &key_data[..]);
318
    }
319
}