use crate::builder::{Error, Result};
use const_oid::AssociatedOid;
use spki::AlgorithmIdentifierOwned;
use alloc::{string::String, vec::Vec};
use core::ops::Add;
use aes::cipher::{
BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, Key, KeyInit, KeySizeUser,
array::{Array, ArraySize},
typenum::{Sum, U8, U16, Unsigned},
};
use aes_kw::AesKw;
pub trait KeyWrapAlgorithm: AssociatedOid + KeySizeUser {
fn key_size_in_bits() -> u32;
fn algorithm_identifier() -> AlgorithmIdentifierOwned;
fn init_kek() -> Key<Self>;
fn init_wrapped<T>() -> WrappedKey<T>
where
T: KeySizeUser,
Sum<T::KeySize, U8>: ArraySize,
<T as KeySizeUser>::KeySize: Add<U8>;
fn try_wrap(key: &Key<Self>, data: &[u8], out: &mut [u8]) -> Result<()>;
}
pub struct WrappedKey<T>
where
T: KeySizeUser,
Sum<T::KeySize, U8>: ArraySize,
<T as KeySizeUser>::KeySize: Add<U8>,
{
inner: Array<u8, Sum<T::KeySize, U8>>,
}
impl<T> AsMut<[u8]> for WrappedKey<T>
where
T: KeySizeUser,
Sum<T::KeySize, U8>: ArraySize,
<T as KeySizeUser>::KeySize: Add<U8>,
{
fn as_mut(&mut self) -> &mut [u8] {
self.inner.as_mut()
}
}
impl<T> From<WrappedKey<T>> for Vec<u8>
where
T: KeySizeUser,
Sum<T::KeySize, U8>: ArraySize,
<T as KeySizeUser>::KeySize: Add<U8>,
{
fn from(wrapped_key: WrappedKey<T>) -> Self {
wrapped_key.inner.to_vec()
}
}
impl<AesWrap> KeyWrapAlgorithm for AesKw<AesWrap>
where
AesWrap: KeyInit + BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + BlockCipherDecrypt,
AesKw<AesWrap>: AssociatedOid + KeyInit,
{
fn key_size_in_bits() -> u32 {
AesWrap::KeySize::U32 * 8u32
}
fn algorithm_identifier() -> AlgorithmIdentifierOwned {
AlgorithmIdentifierOwned {
oid: Self::OID,
parameters: None,
}
}
fn init_kek() -> Key<Self> {
Key::<Self>::default()
}
fn init_wrapped<AesEnc>() -> WrappedKey<AesEnc>
where
AesEnc: KeySizeUser,
Sum<AesEnc::KeySize, aes_kw::IvLen>: ArraySize,
<AesEnc as KeySizeUser>::KeySize: Add<aes_kw::IvLen>,
{
WrappedKey::<AesEnc> {
inner: Array::<u8, Sum<AesEnc::KeySize, aes_kw::IvLen>>::default(),
}
}
fn try_wrap(key: &Key<Self>, data: &[u8], out: &mut [u8]) -> Result<()> {
let kek = AesKw::new(key);
let res = kek
.wrap_key(data, out)
.map_err(|_| Error::Builder(String::from("could not wrap key")))?;
if res.len() != out.len() {
return Err(Error::Builder(String::from("output buffer invalid size")));
}
Ok(())
}
}