use crate::ffi;
use libc::{c_int, c_uint, size_t};
use std::mem::MaybeUninit;
use std::ptr;
#[derive(Debug)]
pub struct KeyError(());
pub struct AesKey(ffi::AES_KEY);
impl AesKey {
#[allow(deprecated)] pub fn new_encrypt(key: &[u8]) -> Result<AesKey, KeyError> {
unsafe {
assert!(key.len() <= c_int::max_value() as usize / 8);
let mut aes_key = MaybeUninit::uninit();
let r = ffi::AES_set_encrypt_key(
key.as_ptr() as *const _,
key.len() as c_uint * 8,
aes_key.as_mut_ptr(),
);
if r == 0 {
Ok(AesKey(aes_key.assume_init()))
} else {
Err(KeyError(()))
}
}
}
#[allow(deprecated)] pub fn new_decrypt(key: &[u8]) -> Result<AesKey, KeyError> {
unsafe {
assert!(key.len() <= c_int::max_value() as usize / 8);
let mut aes_key = MaybeUninit::uninit();
let r = ffi::AES_set_decrypt_key(
key.as_ptr() as *const _,
key.len() as c_uint * 8,
aes_key.as_mut_ptr(),
);
if r == 0 {
Ok(AesKey(aes_key.assume_init()))
} else {
Err(KeyError(()))
}
}
}
}
pub fn wrap_key(
key: &AesKey,
iv: Option<[u8; 8]>,
out: &mut [u8],
in_: &[u8],
) -> Result<usize, KeyError> {
unsafe {
assert!(out.len() >= in_.len() + 8);
let written = ffi::AES_wrap_key(
&key.0 as *const _ as *mut _, 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)
}
}
}
pub fn unwrap_key(
key: &AesKey,
iv: Option<[u8; 8]>,
out: &mut [u8],
in_: &[u8],
) -> Result<usize, KeyError> {
unsafe {
assert!(out.len() + 8 <= in_.len());
let written = ffi::AES_unwrap_key(
&key.0 as *const _ as *mut _, 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::*;
#[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[..]);
}
}