use aes::Aes128;
use aes::cipher::{BlockEncrypt, KeyInit, generic_array::GenericArray};
const BLOCK_SIZE: usize = 16;
pub struct AesCtr {
cipher: Aes128,
counter: [u8; BLOCK_SIZE],
state: [u8; BLOCK_SIZE],
available: usize,
}
impl AesCtr {
pub fn new(key: &[u8; 16], nonce: &[u8; 16]) -> Self {
let cipher = Aes128::new(GenericArray::from_slice(key));
let mut counter = [0u8; BLOCK_SIZE];
counter.copy_from_slice(nonce);
Self {
cipher,
counter,
state: [0u8; BLOCK_SIZE],
available: 0,
}
}
fn inc_counter(&mut self) {
let mut carry: u16 = 1;
for i in (0..BLOCK_SIZE).rev() {
carry += self.counter[i] as u16;
self.counter[i] = carry as u8;
carry >>= 8;
}
}
pub fn encrypt(&mut self, data: &mut [u8]) {
let mut idx = 0;
while idx < data.len() {
if self.available == 0 {
let mut block = GenericArray::clone_from_slice(&self.counter);
self.cipher.encrypt_block(&mut block);
self.state.copy_from_slice(&block);
self.available = BLOCK_SIZE;
self.inc_counter();
}
let offset = BLOCK_SIZE - self.available;
let n = self.available.min(data.len() - idx);
for i in 0..n {
data[idx] ^= self.state[offset + i];
idx += 1;
}
self.available -= n;
}
}
pub fn encrypt_to(&mut self, src: &[u8], dst: &mut [u8]) {
dst[..src.len()].copy_from_slice(src);
self.encrypt(&mut dst[..src.len()]);
}
}