Loading openssl-sys/src/aes.rs +16 −0 Original line number Diff line number Diff line Loading @@ -25,4 +25,20 @@ extern "C" { ivec: *mut c_uchar, enc: c_int, ); pub fn AES_wrap_key( key: *mut AES_KEY, iv: *const c_uchar, out: *mut c_uchar, in_: *const c_uchar, inlen: c_uint, ) -> c_int; pub fn AES_unwrap_key( key: *mut AES_KEY, iv: *const c_uchar, out: *mut c_uchar, in_: *const c_uchar, inlen: c_uint, ) -> c_int; } openssl/src/aes.rs +115 −3 Original line number Diff line number Diff line //! Low level AES IGE functionality //! 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. //! 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 Loading @@ -22,6 +22,7 @@ //! //! # Examples //! //! ## AES IGE //! ```rust //! use openssl::aes::{AesKey, aes_ige}; //! use openssl::symm::Mode; Loading @@ -35,10 +36,31 @@ //! let mut output = [0u8; 16]; //! aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt); //! assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32"); //! ``` //! //! ## 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; use libc::{c_int, c_uint}; use std::mem; use cvt; use error::ErrorStack; use symm::Mode; /// Provides Error handling for parsing keys. Loading Loading @@ -136,6 +158,70 @@ pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mo } } /// 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 /// /// # 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<usize, ErrorStack> { unsafe { assert!(out.len() == in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1) assert!(in_.len() % 8 == 0); // Input (and hence output, given above) are integer multiples of 64 bit values cvt(ffi::AES_wrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.map_or(std::ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as c_uint, )) .map(|written| written as usize) // convert is safe, cvt only return ok with positive numbers } } /// 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 /// /// # 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 `in_`. pub fn unwrap_key( key: &AesKey, iv: Option<[u8; 8]>, out: &mut [u8], in_: &[u8], ) -> Result<usize, ErrorStack> { unsafe { assert!(in_.len() == out.len() + 8); assert!(in_.len() % 8 == 0); cvt(ffi::AES_unwrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.map_or(std::ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as c_uint, )) .map(|written| written as usize) } } #[cfg(test)] mod test { use hex::FromHex; Loading Loading @@ -166,4 +252,30 @@ mod test { aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt); assert_eq!(pt_actual, pt); } // 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[..]); } } Loading
openssl-sys/src/aes.rs +16 −0 Original line number Diff line number Diff line Loading @@ -25,4 +25,20 @@ extern "C" { ivec: *mut c_uchar, enc: c_int, ); pub fn AES_wrap_key( key: *mut AES_KEY, iv: *const c_uchar, out: *mut c_uchar, in_: *const c_uchar, inlen: c_uint, ) -> c_int; pub fn AES_unwrap_key( key: *mut AES_KEY, iv: *const c_uchar, out: *mut c_uchar, in_: *const c_uchar, inlen: c_uint, ) -> c_int; }
openssl/src/aes.rs +115 −3 Original line number Diff line number Diff line //! Low level AES IGE functionality //! 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. //! 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 Loading @@ -22,6 +22,7 @@ //! //! # Examples //! //! ## AES IGE //! ```rust //! use openssl::aes::{AesKey, aes_ige}; //! use openssl::symm::Mode; Loading @@ -35,10 +36,31 @@ //! let mut output = [0u8; 16]; //! aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt); //! assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32"); //! ``` //! //! ## 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; use libc::{c_int, c_uint}; use std::mem; use cvt; use error::ErrorStack; use symm::Mode; /// Provides Error handling for parsing keys. Loading Loading @@ -136,6 +158,70 @@ pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mo } } /// 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 /// /// # 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<usize, ErrorStack> { unsafe { assert!(out.len() == in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1) assert!(in_.len() % 8 == 0); // Input (and hence output, given above) are integer multiples of 64 bit values cvt(ffi::AES_wrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.map_or(std::ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as c_uint, )) .map(|written| written as usize) // convert is safe, cvt only return ok with positive numbers } } /// 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 /// /// # 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 `in_`. pub fn unwrap_key( key: &AesKey, iv: Option<[u8; 8]>, out: &mut [u8], in_: &[u8], ) -> Result<usize, ErrorStack> { unsafe { assert!(in_.len() == out.len() + 8); assert!(in_.len() % 8 == 0); cvt(ffi::AES_unwrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.map_or(std::ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as c_uint, )) .map(|written| written as usize) } } #[cfg(test)] mod test { use hex::FromHex; Loading Loading @@ -166,4 +252,30 @@ mod test { aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt); assert_eq!(pt_actual, pt); } // 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[..]); } }