#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use crate::CryptoBaseError;
use aes::{
cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt},
Aes128, Aes192, Aes256,
};
use crypto_common::KeyInit;
const DEFAULT_IV: u64 = 0xa6a6_a6a6_a6a6_a6a6;
const DEFAULT_RFC5649_CONST: u32 = 0xA659_59A6_u32;
fn build_iv(data_size: usize) -> u64 {
let l = u64::from(DEFAULT_RFC5649_CONST);
let r = u32::to_le(data_size as u32);
l << 32 | u64::from(r)
}
fn check_iv(iv: u64, data: &[u8]) -> bool {
let data_size: usize = data.len();
if (iv >> 32) as u32 != DEFAULT_RFC5649_CONST {
return false;
}
let real_data_size = u32::to_le(iv as u32) as usize;
if real_data_size > data_size || real_data_size <= (data_size - 8) {
return false;
}
data[real_data_size..].iter().all(|&x| x == 0)
}
pub fn wrap(plain: &[u8], kek: &[u8]) -> Result<Vec<u8>, CryptoBaseError> {
let n = plain.len();
let m = n % 8;
let padded_plain = if m != 0 {
let missing_bytes = 8 - m;
[plain.to_vec(), vec![0u8; missing_bytes]].concat()
} else {
plain.to_vec()
};
if n <= 8 {
let mut x = [&build_iv(n).to_be_bytes(), &padded_plain[0..8]].concat();
let C = GenericArray::from_mut_slice(&mut x);
match kek.len() {
16 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes128::new(key);
cipher.encrypt_block(C);
}
24 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes192::new(key);
cipher.encrypt_block(C);
}
32 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes256::new(key);
cipher.encrypt_block(C);
}
_ => {
return Err(CryptoBaseError::InvalidSize(
"The kek size should be 16, 24 or 32".to_string(),
))
}
};
Ok(C[0..16].to_vec())
} else {
_wrap_64(&padded_plain, kek, Some(build_iv(n)))
}
}
pub fn unwrap(ciphertext: &[u8], kek: &[u8]) -> Result<Vec<u8>, CryptoBaseError> {
let n = ciphertext.len();
if n % 8 != 0 || n < 16 {
return Err(CryptoBaseError::InvalidSize(
"The ciphertext size should be >= 16 and a multiple of 8".to_string(),
));
}
if n > 16 {
let (iv, padded_plain) = _unwrap_64(ciphertext, kek)?;
if !check_iv(iv, &padded_plain) {
return Err(CryptoBaseError::InvalidSize(
"The ciphertext is invalid. Decrypted IV is not appropriate".to_string(),
));
}
let unpadded_size = u32::from_le(iv as u32) as usize;
Ok(padded_plain[0..unpadded_size].to_vec())
} else {
let mut C = ciphertext.to_owned();
let padded_plain = GenericArray::from_mut_slice(&mut C);
match kek.len() {
16 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes128::new(key);
cipher.decrypt_block(padded_plain);
}
24 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes192::new(key);
cipher.decrypt_block(padded_plain);
}
32 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes256::new(key);
cipher.decrypt_block(padded_plain);
}
_ => {
return Err(CryptoBaseError::InvalidSize(
"The kek size should be 16, 24 or 32".to_string(),
))
}
};
if !check_iv(
u64::from_be_bytes(padded_plain[0..8].try_into()?),
&padded_plain[8..16],
) {
return Err(CryptoBaseError::InvalidSize(
"The ciphertext is invalid. Decrypted IV is not appropriate".to_string(),
));
}
let unpadded_size = u32::from_be_bytes(padded_plain[4..8].try_into()?) as usize;
Ok(padded_plain[8..(8 + unpadded_size)].to_vec())
}
}
pub fn wrap_64(plain: &[u8], kek: &[u8]) -> Result<Vec<u8>, CryptoBaseError> {
_wrap_64(plain, kek, None)
}
fn _wrap_64(plain: &[u8], kek: &[u8], iv: Option<u64>) -> Result<Vec<u8>, CryptoBaseError> {
let n = plain.len();
if n % 8 != 0 {
return Err(CryptoBaseError::InvalidSize(
"The plaintext size should be a multiple of 8".to_string(),
));
}
let n = n / 8;
let mut A = iv.unwrap_or(DEFAULT_IV);
let mut R = Vec::with_capacity(n);
for chunk in plain.chunks(8) {
R.push(u64::from_be_bytes(chunk.try_into()?));
}
for j in 0..6 {
for (i, r) in R.iter_mut().enumerate().take(n) {
let I: u128 = u128::from(A) << 64 | u128::from(*r);
let mut B = GenericArray::from(I.to_be_bytes());
match kek.len() {
16 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes128::new(key);
cipher.encrypt_block(&mut B);
}
24 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes192::new(key);
cipher.encrypt_block(&mut B);
}
32 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes256::new(key);
cipher.encrypt_block(&mut B);
}
_ => {
return Err(CryptoBaseError::InvalidSize(
"The kek size should be 16, 24 or 32".to_string(),
))
}
};
let t = ((n * j) + (i + 1)) as u64;
A = u64::from_be_bytes(B[0..8].try_into()?) ^ t;
*r = u64::from_be_bytes(B[8..16].try_into()?);
}
}
let mut C = A.to_be_bytes().to_vec();
for r in R {
C.append(&mut r.to_be_bytes().to_vec());
}
Ok(C)
}
pub fn unwrap_64(cipher: &[u8], kek: &[u8]) -> Result<Vec<u8>, CryptoBaseError> {
let (iv, plain) = _unwrap_64(cipher, kek)?;
if iv != DEFAULT_IV {
return Err(CryptoBaseError::InvalidSize(
"The ciphertext is invalid. Decrypted IV is not appropriate".to_string(),
));
}
Ok(plain)
}
fn _unwrap_64(ciphertext: &[u8], kek: &[u8]) -> Result<(u64, Vec<u8>), CryptoBaseError> {
let n = ciphertext.len();
if n % 8 != 0 || n < 16 {
return Err(CryptoBaseError::InvalidSize(
"The ciphertext size should be >= 16 and a multiple of 8".to_string(),
));
}
let n = n / 8 - 1;
let mut R: Vec<u64> = Vec::with_capacity(n + 1);
for chunk in ciphertext.chunks(8) {
R.push(u64::from_be_bytes(chunk.try_into()?));
}
let mut A = R[0];
for j in (0..6).rev() {
for (i, r) in R[1..].iter_mut().rev().enumerate().take(n) {
let t = ((n * j) + (n - i)) as u64;
let I: u128 = u128::from(A ^ t) << 64 | u128::from(*r);
let mut B = GenericArray::from(I.to_be_bytes());
match kek.len() {
16 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes128::new(key);
cipher.decrypt_block(&mut B);
}
24 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes192::new(key);
cipher.decrypt_block(&mut B);
}
32 => {
let key = GenericArray::from_slice(kek);
let cipher = Aes256::new(key);
cipher.decrypt_block(&mut B);
}
_ => {
return Err(CryptoBaseError::InvalidSize(
"The kek size should be 16, 24 or 32".to_string(),
))
}
};
A = u64::from_be_bytes(B[0..8].try_into()?);
*r = u64::from_be_bytes(B[8..16].try_into()?);
}
}
let mut P = vec![];
for r in &R[1..] {
P.append(&mut r.to_be_bytes().to_vec());
}
Ok((A, P))
}
#[cfg(test)]
mod tests {
use crate::key_wrapping::{unwrap, unwrap_64, wrap, wrap_64};
#[test]
pub fn test_wrap64() {
let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
let wrapped_key = [
0x64, 0xe8, 0xc3, 0xf9, 0xce, 0x0f, 0x5b, 0xa2, 0x63, 0xe9, 0x77, 0x79, 0x5, 0x81,
0x8a, 0x2a, 0x93, 0xc8, 0x19, 0x1e, 0x7d, 0x6e, 0x8a, 0xe7,
];
assert_eq!(
wrap_64(key_to_wrap, kek).expect("Fail to wrap"),
wrapped_key
);
assert_eq!(
unwrap_64(&wrapped_key, kek).expect("Fail to unwrap"),
key_to_wrap
);
}
#[test]
pub fn test_wrap64_bad_key_size() {
let kek = b"\x00";
let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
let wrapped_key = [
0x64, 0xe8, 0xc3, 0xf9, 0xce, 0x0f, 0x5b, 0xa2, 0x63, 0xe9, 0x77, 0x79, 0x5, 0x81,
0x8a, 0x2a, 0x93, 0xc8, 0x19, 0x1e, 0x7d, 0x6e, 0x8a, 0xe7,
];
assert!(wrap_64(key_to_wrap, kek).is_err());
assert!(unwrap_64(&wrapped_key, kek).is_err());
}
#[test]
pub fn test_wrap64_bad_input_size() {
let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE";
let wrapped_key = [
0x64, 0xe8, 0xc3, 0xf9, 0xce, 0x0f, 0x5b, 0xa2, 0x63, 0xe9, 0x77, 0x79, 0x5, 0x81,
0x8a, 0x2a, 0x93, 0xc8, 0x19, 0x1e, 0x7d, 0x6e, 0x8a,
];
assert!(wrap_64(key_to_wrap, kek).is_err());
assert!(unwrap_64(&wrapped_key, kek).is_err());
}
#[test]
pub fn test_wrap64_bad_input_content() {
let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
let wrapped_key = [
0x64, 0xe8, 0xc3, 0xf9, 0xce, 0x0f, 0x5b, 0xa2, 0x63, 0xe9, 0x77, 0x79, 0x5, 0x81,
0x8a, 0x2a, 0x93, 0xc8, 0x19, 0x1e, 0x7d, 0x6e, 0x8a, 0xe8,
];
assert!(unwrap_64(&wrapped_key, kek).is_err());
}
#[test]
pub fn test_wrap_large_length() {
let kek = b"\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8";
let key_to_wrap =
b"\xc3\x7b\x7e\x64\x92\x58\x43\x40\xbe\xd1\x22\x07\x80\x89\x41\x15\x50\x68\xf7\x38";
let wrapped_key = [
0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc, 0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22,
0x48, 0xee, 0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a, 0x5f, 0x54, 0xf3, 0x73,
0xfa, 0x54, 0x3b, 0x6a,
];
assert_eq!(wrap(key_to_wrap, kek).expect("Fail to wrap"), wrapped_key);
assert_eq!(
unwrap(&wrapped_key, kek).expect("Fail to unwrap"),
key_to_wrap
);
}
#[test]
pub fn test_wrap_small_length() {
let kek = b"\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8";
let key_to_wrap = b"\x46\x6f\x72\x50\x61\x73\x69";
let wrapped_key = [
0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41, 0x92, 0x0, 0xf2, 0xcc, 0xb5, 0xb, 0xb2,
0x4f,
];
assert_eq!(wrap(key_to_wrap, kek).expect("Fail to wrap"), wrapped_key);
assert_eq!(
unwrap(&wrapped_key, kek).expect("Fail to unwrap"),
key_to_wrap
);
}
#[test]
pub fn test_wrap_bad_key_size() {
let kek = b"\x00";
let key_to_wrap = b"\x46\x6f\x72\x50\x61\x73\x69";
let wrapped_key = [
0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41, 0x92, 0x0, 0xf2, 0xcc, 0xb5, 0xb, 0xb2,
0x4f,
];
assert!(wrap(key_to_wrap, kek).is_err());
assert!(unwrap(&wrapped_key, kek).is_err());
let kek = b"\x00";
let key_to_wrap =
b"\xc3\x7b\x7e\x64\x92\x58\x43\x40\xbe\xd1\x22\x07\x80\x89\x41\x15\x50\x68\xf7\x38";
let wrapped_key = [
0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc, 0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22,
0x48, 0xee, 0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a, 0x5f, 0x54, 0xf3, 0x73,
0xfa, 0x54, 0x3b, 0x6a,
];
assert!(wrap(key_to_wrap, kek).is_err());
assert!(unwrap(&wrapped_key, kek).is_err());
}
#[test]
pub fn test_wrap_bad_input_size() {
let kek = b"\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8";
let wrapped_key = [
0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41, 0x92, 0x0, 0xf2, 0xcc, 0xb5, 0xb, 0xb2,
];
assert!(unwrap(&wrapped_key, kek).is_err());
}
#[test]
pub fn test_wrap_bad_input_content() {
let kek = b"\x58\x40\xdf\x6e\x29\xb0\x2a\xf1\xab\x49\x3b\x70\x5b\xf1\x6e\xa1\xae\x83\x38\xf4\xdc\xc1\x76\xa8";
let wrapped_key = [
0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41, 0x92, 0x0, 0xf2, 0xcc, 0xb5, 0xb, 0xb2,
0x4a,
];
assert!(unwrap(&wrapped_key, kek).is_err());
let wrapped_key = [
0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc, 0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22,
0x48, 0xee, 0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a, 0x5f, 0x54, 0xf3, 0x73,
0xfa, 0x54, 0x3b, 0x6b,
];
assert!(unwrap(&wrapped_key, kek).is_err());
}
}