1use crate::{errors::InvalidLength, BlockCipher, NewBlockCipher};
2use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
3
4pub type CipherKey<C> = GenericArray<u8, <C as NewCipher>::KeySize>;
6
7pub type Nonce<C> = GenericArray<u8, <C as NewCipher>::NonceSize>;
9
10pub trait NewCipher: Sized {
14    type KeySize: ArrayLength<u8>;
16
17    type NonceSize: ArrayLength<u8>;
19
20    fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> Self;
22
23    #[inline]
26    fn new_from_slices(key: &[u8], nonce: &[u8]) -> Result<Self, InvalidLength> {
27        let kl = Self::KeySize::to_usize();
28        let nl = Self::NonceSize::to_usize();
29        if key.len() != kl || nonce.len() != nl {
30            Err(InvalidLength)
31        } else {
32            let key = GenericArray::from_slice(key);
33            let nonce = GenericArray::from_slice(nonce);
34            Ok(Self::new(key, nonce))
35        }
36    }
37}
38
39pub trait FromBlockCipher {
41    type BlockCipher: BlockCipher;
43    type NonceSize: ArrayLength<u8>;
45
46    fn from_block_cipher(
48        cipher: Self::BlockCipher,
49        nonce: &GenericArray<u8, Self::NonceSize>,
50    ) -> Self;
51}
52
53impl<C> NewCipher for C
54where
55    C: FromBlockCipher,
56    C::BlockCipher: NewBlockCipher,
57{
58    type KeySize = <<Self as FromBlockCipher>::BlockCipher as NewBlockCipher>::KeySize;
59    type NonceSize = <Self as FromBlockCipher>::NonceSize;
60
61    fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> C {
62        C::from_block_cipher(
63            <<Self as FromBlockCipher>::BlockCipher as NewBlockCipher>::new(key),
64            nonce,
65        )
66    }
67
68    fn new_from_slices(key: &[u8], nonce: &[u8]) -> Result<Self, InvalidLength> {
69        if nonce.len() != Self::NonceSize::USIZE {
70            Err(InvalidLength)
71        } else {
72            C::BlockCipher::new_from_slice(key)
73                .map_err(|_| InvalidLength)
74                .map(|cipher| {
75                    let nonce = GenericArray::from_slice(nonce);
76                    Self::from_block_cipher(cipher, nonce)
77                })
78        }
79    }
80}