blob: cd97524a662aaea93cd446eb70c7721d476f08e6 [file] [log] [blame]
use crate::{errors::InvalidLength, BlockCipher, NewBlockCipher};
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
/// Key for an algorithm that implements [`NewCipher`].
pub type CipherKey<C> = GenericArray<u8, <C as NewCipher>::KeySize>;
/// Nonce for an algorithm that implements [`NewCipher`].
pub type Nonce<C> = GenericArray<u8, <C as NewCipher>::NonceSize>;
/// Cipher creation trait.
///
/// It can be used for creation of block modes, synchronous and asynchronous stream ciphers.
pub trait NewCipher: Sized {
/// Key size in bytes
type KeySize: ArrayLength<u8>;
/// Nonce size in bytes
type NonceSize: ArrayLength<u8>;
/// Create new stream cipher instance from key and nonce arrays.
fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> Self;
/// Create new stream cipher instance from variable length key and nonce
/// given as byte slices.
#[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))
}
}
}
/// Trait for types which can be initialized from a block cipher and nonce.
pub trait FromBlockCipher {
/// Block cipher
type BlockCipher: BlockCipher;
/// Nonce size in bytes
type NonceSize: ArrayLength<u8>;
/// Instantiate a stream cipher from a block cipher
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)
})
}
}
}