//! Low level AES IGE and key wrapping functionality //! //! AES ECB, CBC, XTS, CTR, CFB, GCM and other conventional symmetric encryption //! modes are found in [`symm`]. This is the implementation of AES IGE and key wrapping //! //! Advanced Encryption Standard (AES) provides symmetric key cipher that //! the same key is used to encrypt and decrypt data. This implementation //! uses 128, 192, or 256 bit keys. This module provides functions to //! create a new key with [`new_encrypt`]. //! //! [`new_encrypt`]: struct.AesKey.html#method.new_encrypt //! //! The [`symm`] module should be used in preference to this module in most cases. //! The IGE block cypher is a non-traditional cipher mode. More traditional AES //! encryption methods are found in the [`Crypter`] and [`Cipher`] structs. //! //! [`symm`]: ../symm/index.html //! [`Crypter`]: ../symm/struct.Crypter.html //! [`Cipher`]: ../symm/struct.Cipher.html //! //! # Examples //! //! ## Key wrapping //! ```rust //! use openssl::aes::{AesKey, unwrap_key, wrap_key}; //! //! let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; //! let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"; //! //! let enc_key = AesKey::new_encrypt(kek).unwrap(); //! let mut ciphertext = [0u8; 24]; //! wrap_key(&enc_key, None, &mut ciphertext, &key_to_wrap[..]).unwrap(); //! let dec_key = AesKey::new_decrypt(kek).unwrap(); //! let mut orig_key = [0u8; 16]; //! unwrap_key(&dec_key, None, &mut orig_key, &ciphertext[..]).unwrap(); //! //! assert_eq!(&orig_key[..], &key_to_wrap[..]); //! ``` //! use ffi; use libc::{c_int, c_uint, size_t}; use std::{mem, ptr}; /// Provides Error handling for parsing keys. #[derive(Debug)] pub struct KeyError(()); /// The key used to encrypt or decrypt cipher blocks. pub struct AesKey(ffi::AES_KEY); impl AesKey { /// Prepares a key for encryption. /// /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. #[allow(deprecated)] // https://github.com/rust-lang/rust/issues/63566 pub fn new_encrypt(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize / 8); let mut aes_key = mem::uninitialized(); let r = ffi::AES_set_encrypt_key( key.as_ptr() as *const _, key.len() as c_uint * 8, &mut aes_key, ); if r == 0 { Ok(AesKey(aes_key)) } else { Err(KeyError(())) } } } /// Prepares a key for decryption. /// /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. #[allow(deprecated)] // https://github.com/rust-lang/rust/issues/63566 pub fn new_decrypt(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize / 8); let mut aes_key = mem::uninitialized(); let r = ffi::AES_set_decrypt_key( key.as_ptr() as *const _, key.len() as c_uint * 8, &mut aes_key, ); if r == 0 { Ok(AesKey(aes_key)) } else { Err(KeyError(())) } } } } /// Wrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394) /// /// * `key`: The key-encrypting-key to use. Must be a encrypting key /// * `iv`: The IV to use. You must use the same IV for both wrapping and unwrapping /// * `out`: The output buffer to store the ciphertext /// * `in_`: The input buffer, storing the key to be wrapped /// /// Returns the number of bytes written into `out` /// /// # Panics /// /// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or if /// `out` is not 8 bytes longer than `in_` pub fn wrap_key( key: &AesKey, iv: Option<[u8; 8]>, out: &mut [u8], in_: &[u8], ) -> Result { unsafe { assert!(out.len() >= in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1) let written = ffi::AES_wrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.as_ref() .map_or(ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as size_t, ); if written <= 0 { Err(KeyError(())) } else { Ok(written as usize) } } } /// Unwrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394) /// /// * `key`: The key-encrypting-key to decrypt the wrapped key. Must be a decrypting key /// * `iv`: The same IV used for wrapping the key /// * `out`: The buffer to write the unwrapped key to /// * `in_`: The input ciphertext /// /// Returns the number of bytes written into `out` /// /// # Panics /// /// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or /// if `in_` is not 8 bytes longer than `out` pub fn unwrap_key( key: &AesKey, iv: Option<[u8; 8]>, out: &mut [u8], in_: &[u8], ) -> Result { unsafe { assert!(out.len() + 8 <= in_.len()); let written = ffi::AES_unwrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.as_ref() .map_or(ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as size_t, ); if written <= 0 { Err(KeyError(())) } else { Ok(written as usize) } } } #[cfg(test)] mod test { use hex::FromHex; use super::*; // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3 #[test] fn test_wrap_unwrap() { let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap(); let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap(); let expected_ciphertext = Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap(); let enc_key = AesKey::new_encrypt(&raw_key).unwrap(); let mut wrapped = [0; 24]; assert_eq!( wrap_key(&enc_key, None, &mut wrapped, &key_data).unwrap(), 24 ); assert_eq!(&wrapped[..], &expected_ciphertext[..]); let dec_key = AesKey::new_decrypt(&raw_key).unwrap(); let mut unwrapped = [0; 16]; assert_eq!( unwrap_key(&dec_key, None, &mut unwrapped, &wrapped).unwrap(), 16 ); assert_eq!(&unwrapped[..], &key_data[..]); } }