boring_imp/aes.rs
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`].
10//!
11//! [`new_encrypt`]: struct.AesKey.html#method.new_encrypt
12//!
13//! The [`symm`] module should be used in preference to this module in most cases.
14//! The IGE block cypher is a non-traditional cipher mode. More traditional AES
15//! encryption methods are found in the [`Crypter`] and [`Cipher`] structs.
16//!
17//! [`symm`]: ../symm/index.html
18//! [`Crypter`]: ../symm/struct.Crypter.html
19//! [`Cipher`]: ../symm/struct.Cipher.html
20//!
21//! # Examples
22//!
23//! ## Key wrapping
24//! ```rust
25//! use boring::aes::{AesKey, unwrap_key, wrap_key};
26//!
27//! let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
28//! let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
29//!
30//! let enc_key = AesKey::new_encrypt(kek).unwrap();
31//! let mut ciphertext = [0u8; 24];
32//! wrap_key(&enc_key, None, &mut ciphertext, &key_to_wrap[..]).unwrap();
33//! let dec_key = AesKey::new_decrypt(kek).unwrap();
34//! let mut orig_key = [0u8; 16];
35//! unwrap_key(&dec_key, None, &mut orig_key, &ciphertext[..]).unwrap();
36//!
37//! assert_eq!(&orig_key[..], &key_to_wrap[..]);
38//! ```
39//!
40use crate::ffi;
41use libc::{c_int, c_uint, size_t};
42use std::mem::MaybeUninit;
43use std::ptr;
44
45/// Provides Error handling for parsing keys.
46#[derive(Debug)]
47pub struct KeyError(());
48
49/// The key used to encrypt or decrypt cipher blocks.
50pub struct AesKey(ffi::AES_KEY);
51
52impl AesKey {
53 /// Prepares a key for encryption.
54 ///
55 /// # Failure
56 ///
57 /// Returns an error if the key is not 128, 192, or 256 bits.
58 #[allow(deprecated)] // https://github.com/rust-lang/rust/issues/63566
59 pub fn new_encrypt(key: &[u8]) -> Result<AesKey, KeyError> {
60 unsafe {
61 assert!(key.len() <= c_int::MAX as usize / 8);
62
63 let mut aes_key = MaybeUninit::uninit();
64 let r = ffi::AES_set_encrypt_key(
65 key.as_ptr() as *const _,
66 key.len() as c_uint * 8,
67 aes_key.as_mut_ptr(),
68 );
69 if r == 0 {
70 Ok(AesKey(aes_key.assume_init()))
71 } else {
72 Err(KeyError(()))
73 }
74 }
75 }
76
77 /// Prepares a key for decryption.
78 ///
79 /// # Failure
80 ///
81 /// Returns an error if the key is not 128, 192, or 256 bits.
82 #[allow(deprecated)] // https://github.com/rust-lang/rust/issues/63566
83 pub fn new_decrypt(key: &[u8]) -> Result<AesKey, KeyError> {
84 unsafe {
85 assert!(key.len() <= c_int::MAX as usize / 8);
86
87 let mut aes_key = MaybeUninit::uninit();
88 let r = ffi::AES_set_decrypt_key(
89 key.as_ptr() as *const _,
90 key.len() as c_uint * 8,
91 aes_key.as_mut_ptr(),
92 );
93
94 if r == 0 {
95 Ok(AesKey(aes_key.assume_init()))
96 } else {
97 Err(KeyError(()))
98 }
99 }
100 }
101}
102
103/// Wrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394)
104///
105/// * `key`: The key-encrypting-key to use. Must be a encrypting key
106/// * `iv`: The IV to use. You must use the same IV for both wrapping and unwrapping
107/// * `out`: The output buffer to store the ciphertext
108/// * `in_`: The input buffer, storing the key to be wrapped
109///
110/// Returns the number of bytes written into `out`
111///
112/// # Panics
113///
114/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or if
115/// `out` is not 8 bytes longer than `in_`
116pub fn wrap_key(
117 key: &AesKey,
118 iv: Option<[u8; 8]>,
119 out: &mut [u8],
120 in_: &[u8],
121) -> Result<usize, KeyError> {
122 unsafe {
123 assert!(out.len() >= in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1)
124
125 let written = ffi::AES_wrap_key(
126 &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer.
127 iv.as_ref()
128 .map_or(ptr::null(), |iv| iv.as_ptr() as *const _),
129 out.as_ptr() as *mut _,
130 in_.as_ptr() as *const _,
131 in_.len() as size_t,
132 );
133 if written <= 0 {
134 Err(KeyError(()))
135 } else {
136 Ok(written as usize)
137 }
138 }
139}
140
141/// Unwrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394)
142///
143/// * `key`: The key-encrypting-key to decrypt the wrapped key. Must be a decrypting key
144/// * `iv`: The same IV used for wrapping the key
145/// * `out`: The buffer to write the unwrapped key to
146/// * `in_`: The input ciphertext
147///
148/// Returns the number of bytes written into `out`
149///
150/// # Panics
151///
152/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or
153/// if `in_` is not 8 bytes longer than `out`
154pub fn unwrap_key(
155 key: &AesKey,
156 iv: Option<[u8; 8]>,
157 out: &mut [u8],
158 in_: &[u8],
159) -> Result<usize, KeyError> {
160 unsafe {
161 assert!(out.len() + 8 <= in_.len());
162
163 let written = ffi::AES_unwrap_key(
164 &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer.
165 iv.as_ref()
166 .map_or(ptr::null(), |iv| iv.as_ptr() as *const _),
167 out.as_ptr() as *mut _,
168 in_.as_ptr() as *const _,
169 in_.len() as size_t,
170 );
171
172 if written <= 0 {
173 Err(KeyError(()))
174 } else {
175 Ok(written as usize)
176 }
177 }
178}
179
180#[cfg(test)]
181mod test {
182 use hex::FromHex;
183
184 use super::*;
185
186 // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3
187 #[test]
188 fn test_wrap_unwrap() {
189 let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
190 let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
191 let expected_ciphertext =
192 Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
193
194 let enc_key = AesKey::new_encrypt(&raw_key).unwrap();
195 let mut wrapped = [0; 24];
196 assert_eq!(
197 wrap_key(&enc_key, None, &mut wrapped, &key_data).unwrap(),
198 24
199 );
200 assert_eq!(&wrapped[..], &expected_ciphertext[..]);
201
202 let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
203 let mut unwrapped = [0; 16];
204 assert_eq!(
205 unwrap_key(&dec_key, None, &mut unwrapped, &wrapped).unwrap(),
206 16
207 );
208 assert_eq!(&unwrapped[..], &key_data[..]);
209 }
210}