use crate::pac;
pub const BLOCK_SIZE: usize = 16;
#[derive(Clone)]
pub enum Key {
Aes128([u8; 16]),
Aes192([u8; 24]),
Aes256([u8; 32]),
}
impl Key {
fn bytes(&self) -> &[u8] {
match self {
Key::Aes128(k) => k,
Key::Aes192(k) => k,
Key::Aes256(k) => k,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
NotBlockAligned,
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Op {
Encrypt, Decrypt, }
pub struct Aes {
aes: pac::AesAccelerator,
key: Key,
loaded: Option<Op>,
}
impl Aes {
pub fn new(aes: pac::AesAccelerator, key: Key) -> Self {
let mut this = Aes {
aes,
key,
loaded: None,
};
this.reset();
this
}
pub fn set_key(&mut self, key: Key) {
self.key = key;
self.loaded = None;
}
pub fn free(mut self) -> pac::AesAccelerator {
self.reset();
self.aes
}
pub fn encrypt_blocks(&mut self, data: &mut [u8]) -> Result<(), Error> {
for block in blocks_mut(data)? {
self.process_block(Op::Encrypt, block);
}
Ok(())
}
pub fn decrypt_blocks(&mut self, data: &mut [u8]) -> Result<(), Error> {
for block in blocks_mut(data)? {
self.process_block(Op::Decrypt, block);
}
Ok(())
}
pub fn encrypt_cbc(&mut self, iv: &[u8; BLOCK_SIZE], data: &mut [u8]) -> Result<(), Error> {
let mut chain = *iv;
for block in blocks_mut(data)? {
for (b, c) in block.iter_mut().zip(chain.iter()) {
*b ^= c;
}
self.process_block(Op::Encrypt, block);
chain = *block;
}
Ok(())
}
pub fn decrypt_cbc(&mut self, iv: &[u8; BLOCK_SIZE], data: &mut [u8]) -> Result<(), Error> {
let mut chain = *iv;
for block in blocks_mut(data)? {
let ct = *block; self.process_block(Op::Decrypt, block);
for (b, c) in block.iter_mut().zip(chain.iter()) {
*b ^= c;
}
chain = ct;
}
Ok(())
}
fn process_block(&mut self, op: Op, block: &mut [u8; BLOCK_SIZE]) {
if self.loaded != Some(op) {
self.load_key(op);
}
for chunk in block.chunks_exact(2) {
self.aes
.aesadin()
.write(|w| unsafe { w.bits(u16::from_le_bytes([chunk[0], chunk[1]])) });
}
while self.aes.aesastat().read().aesbusy().bit_is_set() {}
for chunk in block.chunks_exact_mut(2) {
let word = self.aes.aesadout().read().bits();
chunk.copy_from_slice(&word.to_le_bytes());
}
}
fn load_key(&mut self, op: Op) {
while self.aes.aesastat().read().aesbusy().bit_is_set() {}
self.aes.aesactl0().write(|w| {
let w = match op {
Op::Encrypt => w.aesop().aesop_0(),
Op::Decrypt => w.aesop().aesop_1(),
};
match self.key {
Key::Aes128(_) => w.aeskl().aeskl_0(),
Key::Aes192(_) => w.aeskl().aeskl_1(),
Key::Aes256(_) => w.aeskl().aeskl_2(),
}
});
for chunk in self.key.bytes().chunks_exact(2) {
self.aes
.aesakey()
.write(|w| unsafe { w.bits(u16::from_le_bytes([chunk[0], chunk[1]])) });
}
while self.aes.aesastat().read().aeskeywr().bit_is_clear() {}
self.loaded = Some(op);
}
fn reset(&mut self) {
self.aes.aesactl0().write(|w| w.aesswrst().set_bit());
self.loaded = None;
}
}
fn blocks_mut(data: &mut [u8]) -> Result<&mut [[u8; BLOCK_SIZE]], Error> {
let (blocks, rest) = data.as_chunks_mut::<BLOCK_SIZE>();
if rest.is_empty() {
Ok(blocks)
} else {
Err(Error::NotBlockAligned)
}
}