use crate::{errors::InvalidLength, BlockCipher, NewBlockCipher};
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
pub type CipherKey<C> = GenericArray<u8, <C as NewCipher>::KeySize>;
pub type Nonce<C> = GenericArray<u8, <C as NewCipher>::NonceSize>;
pub trait NewCipher: Sized {
type KeySize: ArrayLength<u8>;
type NonceSize: ArrayLength<u8>;
fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> Self;
#[inline]
fn new_from_slices(key: &[u8], nonce: &[u8]) -> Result<Self, InvalidLength> {
let kl = Self::KeySize::to_usize();
let nl = Self::NonceSize::to_usize();
if key.len() != kl || nonce.len() != nl {
Err(InvalidLength)
} else {
let key = GenericArray::from_slice(key);
let nonce = GenericArray::from_slice(nonce);
Ok(Self::new(key, nonce))
}
}
}
pub trait FromBlockCipher {
type BlockCipher: BlockCipher;
type NonceSize: ArrayLength<u8>;
fn from_block_cipher(
cipher: Self::BlockCipher,
nonce: &GenericArray<u8, Self::NonceSize>,
) -> Self;
}
impl<C> NewCipher for C
where
C: FromBlockCipher,
C::BlockCipher: NewBlockCipher,
{
type KeySize = <<Self as FromBlockCipher>::BlockCipher as NewBlockCipher>::KeySize;
type NonceSize = <Self as FromBlockCipher>::NonceSize;
fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> C {
C::from_block_cipher(
<<Self as FromBlockCipher>::BlockCipher as NewBlockCipher>::new(key),
nonce,
)
}
fn new_from_slices(key: &[u8], nonce: &[u8]) -> Result<Self, InvalidLength> {
if nonce.len() != Self::NonceSize::USIZE {
Err(InvalidLength)
} else {
C::BlockCipher::new_from_slice(key)
.map_err(|_| InvalidLength)
.map(|cipher| {
let nonce = GenericArray::from_slice(nonce);
Self::from_block_cipher(cipher, nonce)
})
}
}
}