use {
crate::{BlockEncrypt, BlockMode, Cipher, CipherDecrypt, CipherEncrypt, OneTimePad},
docext::docext,
std::{convert::Infallible, fmt, iter, mem},
};
#[docext]
#[derive(Debug, Clone)]
pub struct Ctr<Enc> {
enc: Enc,
nonce: u64,
}
impl<Enc> Cipher for Ctr<Enc>
where
Enc: BlockEncrypt,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + Clone,
{
type Key = Enc::EncryptionKey;
}
impl<Enc> BlockMode for Ctr<Enc>
where
Enc: BlockEncrypt,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + Clone,
{
}
impl<Enc, const BLOCK_SIZE: usize> Ctr<Enc>
where
Enc: BlockEncrypt<EncryptionBlock = [u8; BLOCK_SIZE]>,
{
pub fn new(enc: Enc, nonce: u64) -> Result<Self, BlockSizeTooSmall> {
if BLOCK_SIZE < mem::size_of_val(&nonce) {
Err(BlockSizeTooSmall)
} else {
Ok(Self { enc, nonce })
}
}
}
impl<Enc> CipherEncrypt for Ctr<Enc>
where
Enc: BlockEncrypt,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + Clone,
{
type EncryptionErr = Infallible;
type EncryptionKey = Enc::EncryptionKey;
fn encrypt(
&self,
data: Vec<u8>,
key: Self::EncryptionKey,
) -> Result<Vec<u8>, Self::EncryptionErr> {
Ok(OneTimePad::default()
.encrypt(data, keystream(&self.enc, key, self.nonce))
.expect("infinite keystream"))
}
}
impl<Enc> CipherDecrypt for Ctr<Enc>
where
Enc: BlockEncrypt,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + Clone,
{
type DecryptionErr = Infallible;
type DecryptionKey = Enc::EncryptionKey;
fn decrypt(
&self,
data: Vec<u8>,
key: Self::DecryptionKey,
) -> Result<Vec<u8>, Self::DecryptionErr> {
Ok(OneTimePad::default()
.decrypt(data, keystream(&self.enc, key, self.nonce))
.expect("infinite keystream"))
}
}
fn keystream<Enc>(enc: &Enc, key: Enc::EncryptionKey, nonce: u64) -> impl Iterator<Item = u8> + '_
where
Enc: BlockEncrypt,
Enc::EncryptionBlock: IntoIterator<Item = u8> + AsMut<[u8]> + Default,
Enc::EncryptionKey: 'static + Clone,
{
iter::successors(Some(nonce), |ctr| Some(ctr.wrapping_add(1))).flat_map(move |ctr| {
let mut ctr_block = Enc::EncryptionBlock::default();
ctr_block
.as_mut()
.iter_mut()
.zip(ctr.to_le_bytes())
.for_each(|(b, n)| *b = n);
enc.encrypt(ctr_block, key.clone()).into_iter()
})
}
#[derive(Debug)]
pub struct BlockSizeTooSmall;
impl fmt::Display for BlockSizeTooSmall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("block size too small to fit counter")
}
}