Skip to main content

rama_boring/
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 rama_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 crate::libc_types::c_int;
42use openssl_macros::corresponds;
43use std::mem::MaybeUninit;
44use std::ptr;
45
46/// Provides Error handling for parsing keys.
47#[derive(Debug)]
48pub struct KeyError(());
49
50/// The key used to encrypt or decrypt cipher blocks.
51pub struct AesKey(ffi::AES_KEY);
52
53impl AesKey {
54    /// Prepares a key for encryption.
55    ///
56    /// # Failure
57    ///
58    /// Returns an error if the key is not 128, 192, or 256 bits.
59    #[corresponds(AES_set_encrypt_key)]
60    pub fn new_encrypt(key: &[u8]) -> Result<AesKey, KeyError> {
61        unsafe {
62            assert!(key.len() <= c_int::MAX as usize / 8);
63
64            let mut aes_key = MaybeUninit::uninit();
65            let r = ffi::AES_set_encrypt_key(
66                key.as_ptr(),
67                (key.len() * 8).try_into().map_err(|_| KeyError(()))?,
68                aes_key.as_mut_ptr(),
69            );
70            if r == 0 {
71                Ok(AesKey(aes_key.assume_init()))
72            } else {
73                Err(KeyError(()))
74            }
75        }
76    }
77
78    /// Prepares a key for decryption.
79    ///
80    /// # Failure
81    ///
82    /// Returns an error if the key is not 128, 192, or 256 bits.
83    #[corresponds(AES_set_decrypt_key)]
84    pub fn new_decrypt(key: &[u8]) -> Result<AesKey, KeyError> {
85        unsafe {
86            assert!(key.len() <= c_int::MAX as usize / 8);
87
88            let mut aes_key = MaybeUninit::uninit();
89            let r = ffi::AES_set_decrypt_key(
90                key.as_ptr(),
91                (key.len() * 8).try_into().map_err(|_| KeyError(()))?,
92                aes_key.as_mut_ptr(),
93            );
94
95            if r == 0 {
96                Ok(AesKey(aes_key.assume_init()))
97            } else {
98                Err(KeyError(()))
99            }
100        }
101    }
102}
103
104/// Wrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394)
105///
106/// * `key`: The key-encrypting-key to use. Must be a encrypting key
107/// * `iv`: The IV to use. You must use the same IV for both wrapping and unwrapping
108/// * `out`: The output buffer to store the ciphertext
109/// * `in_`: The input buffer, storing the key to be wrapped
110///
111/// Returns the number of bytes written into `out`
112///
113/// # Panics
114///
115/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or if
116/// `out` is not 8 bytes longer than `in_`
117#[corresponds(AES_wrap_key)]
118pub fn wrap_key(
119    key: &AesKey,
120    iv: Option<[u8; 8]>,
121    out: &mut [u8],
122    in_: &[u8],
123) -> Result<usize, KeyError> {
124    unsafe {
125        assert!(out.len() >= in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1)
126
127        let written = ffi::AES_wrap_key(
128            std::ptr::addr_of!(key.0).cast_mut(), // this is safe, the implementation only uses the key as a const pointer.
129            iv.as_ref().map_or(ptr::null(), |iv| iv.as_ptr()),
130            out.as_mut_ptr(),
131            in_.as_ptr(),
132            in_.len(),
133        );
134        if written <= 0 {
135            Err(KeyError(()))
136        } else {
137            Ok(written as usize)
138        }
139    }
140}
141
142/// Unwrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394)
143///
144/// * `key`: The key-encrypting-key to decrypt the wrapped key. Must be a decrypting key
145/// * `iv`: The same IV used for wrapping the key
146/// * `out`: The buffer to write the unwrapped key to
147/// * `in_`: The input ciphertext
148///
149/// Returns the number of bytes written into `out`
150///
151/// # Panics
152///
153/// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or
154/// if `in_` is not 8 bytes longer than `out`
155#[corresponds(AES_unwrap_key)]
156pub fn unwrap_key(
157    key: &AesKey,
158    iv: Option<[u8; 8]>,
159    out: &mut [u8],
160    in_: &[u8],
161) -> Result<usize, KeyError> {
162    unsafe {
163        assert!(out.len() + 8 <= in_.len());
164
165        let written = ffi::AES_unwrap_key(
166            std::ptr::addr_of!(key.0).cast_mut(), // this is safe, the implementation only uses the key as a const pointer.
167            iv.as_ref().map_or(ptr::null(), |iv| iv.as_ptr().cast()),
168            out.as_ptr().cast_mut(),
169            in_.as_ptr().cast(),
170            in_.len(),
171        );
172
173        if written <= 0 {
174            Err(KeyError(()))
175        } else {
176            Ok(written as usize)
177        }
178    }
179}
180
181#[cfg(test)]
182mod test {
183    use hex::FromHex;
184
185    use super::*;
186
187    // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3
188    #[test]
189    fn test_wrap_unwrap() {
190        let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap();
191        let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap();
192        let expected_ciphertext =
193            Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap();
194
195        let enc_key = AesKey::new_encrypt(&raw_key).unwrap();
196        let mut wrapped = [0; 24];
197        assert_eq!(
198            wrap_key(&enc_key, None, &mut wrapped, &key_data).unwrap(),
199            24
200        );
201        assert_eq!(&wrapped[..], &expected_ciphertext[..]);
202
203        let dec_key = AesKey::new_decrypt(&raw_key).unwrap();
204        let mut unwrapped = [0; 16];
205        assert_eq!(
206            unwrap_key(&dec_key, None, &mut unwrapped, &wrapped).unwrap(),
207            16
208        );
209        assert_eq!(&unwrapped[..], &key_data[..]);
210    }
211}