use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use crate::dma::ChannelAndRequest;
use crate::interrupt::typelevel::Interrupt;
use crate::mode::{Async, Blocking, Mode};
use crate::{interrupt, pac, peripherals, rcc};
const AES_BLOCK_SIZE: usize = 16;
static AES_WAKER: AtomicWaker = AtomicWaker::new();
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let sr = T::regs().sr().read();
if sr.ccf() {
T::regs().icr().write(|w| w.0 = 0xFFFF_FFFF);
AES_WAKER.wake();
}
if sr.rderr() || sr.wrerr() {
T::regs().icr().write(|w| w.0 = 0xFFFF_FFFF);
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
KeyError,
ReadError,
WriteError,
ConfigError,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Direction {
Encrypt = 0,
Decrypt = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeySize {
Bits128 = 0,
Bits256 = 1,
}
pub trait Cipher<'c> {
const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
const REQUIRES_PADDING: bool = false;
fn key(&self) -> &[u8];
fn iv(&self) -> &[u8];
fn key_size(&self) -> KeySize {
match self.key().len() {
16 => KeySize::Bits128,
32 => KeySize::Bits256,
_ => panic!("Invalid key size"),
}
}
fn set_mode(&self, p: pac::aes::Aes);
fn datatype(&self) -> u8 {
0 }
fn chmod_bits(&self) -> u8 {
0 }
fn prepare_key(&self, _p: pac::aes::Aes, _dir: Direction) {}
fn init_phase_blocking<T: Instance, M: Mode>(&self, _p: pac::aes::Aes, _aes: &Aes<T, M>) {}
async fn init_phase<T: Instance>(&self, _p: pac::aes::Aes, _aes: &mut Aes<'_, T, Async>) {}
fn pre_final(&self, _p: pac::aes::Aes, _dir: Direction, _padding_len: usize) -> [u32; 4] {
[0; 4]
}
fn post_final_blocking<T: Instance, M: Mode>(
&self,
_p: pac::aes::Aes,
_aes: &Aes<T, M>,
_dir: Direction,
_int_data: &mut [u8; AES_BLOCK_SIZE],
_temp1: [u32; 4],
_padding_mask: [u8; 16],
) {
}
async fn post_final<T: Instance>(
&self,
_p: pac::aes::Aes,
_aes: &mut Aes<'_, T, Async>,
_dir: Direction,
_int_data: &mut [u8; AES_BLOCK_SIZE],
_temp1: [u32; 4],
_padding_mask: [u8; 16],
) {
}
fn get_header_block(&self) -> &[u8] {
[0; 0].as_slice()
}
fn uses_gcm_phases(&self) -> bool {
false
}
fn is_ccm_mode(&self) -> bool {
false
}
fn ccm_b0(&self) -> Option<&[u8; 16]> {
None
}
fn ccm_format_aad_header(&self, aad_len: usize) -> ([u8; 10], usize) {
let mut header = [0u8; 10];
let len = if aad_len == 0 {
0
} else if aad_len < (1 << 16) - (1 << 8) {
header[0] = (aad_len >> 8) as u8;
header[1] = aad_len as u8;
2
} else if aad_len < (1u64 << 32) as usize {
header[0] = 0xFF;
header[1] = 0xFE;
header[2..6].copy_from_slice(&(aad_len as u32).to_be_bytes());
6
} else {
header[0] = 0xFF;
header[1] = 0xFF;
header[2..10].copy_from_slice(&(aad_len as u64).to_be_bytes());
10
};
(header, len)
}
}
pub trait CipherSized {}
pub trait IVSized {}
pub trait CipherAuthenticated<const TAG_SIZE: usize> {
const TAG_SIZE: usize = TAG_SIZE;
}
pub struct AesEcb<'c, const KEY_SIZE: usize> {
iv: &'c [u8; 0],
key: &'c [u8; KEY_SIZE],
}
impl<'c, const KEY_SIZE: usize> AesEcb<'c, KEY_SIZE> {
pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
Self { key, iv: &[0; 0] }
}
}
impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
const REQUIRES_PADDING: bool = true;
fn key(&self) -> &[u8] {
self.key
}
fn iv(&self) -> &[u8] {
self.iv
}
fn set_mode(&self, p: pac::aes::Aes) {
p.cr().modify(|w| {
w.set_chmod(pac::aes::vals::Chmod::from_bits(0));
});
}
fn chmod_bits(&self) -> u8 {
0
}
fn prepare_key(&self, p: pac::aes::Aes, dir: Direction) {
if dir == Direction::Decrypt {
p.cr().modify(|w| w.set_mode(pac::aes::vals::Mode::from_bits(1)));
p.cr().modify(|w| w.set_en(true));
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
}
}
}
impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {}
impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {}
impl<'c, const KEY_SIZE: usize> IVSized for AesEcb<'c, KEY_SIZE> {}
pub struct AesCbc<'c, const KEY_SIZE: usize> {
iv: &'c [u8; 16],
key: &'c [u8; KEY_SIZE],
}
impl<'c, const KEY_SIZE: usize> AesCbc<'c, KEY_SIZE> {
pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
Self { key, iv }
}
}
impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
const REQUIRES_PADDING: bool = true;
fn key(&self) -> &[u8] {
self.key
}
fn iv(&self) -> &[u8] {
self.iv
}
fn set_mode(&self, p: pac::aes::Aes) {
p.cr().modify(|w| {
w.set_chmod(pac::aes::vals::Chmod::from_bits(1));
});
}
fn chmod_bits(&self) -> u8 {
1
}
fn prepare_key(&self, p: pac::aes::Aes, dir: Direction) {
if dir == Direction::Decrypt {
p.cr().modify(|w| w.set_mode(pac::aes::vals::Mode::from_bits(1)));
p.cr().modify(|w| w.set_en(true));
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
}
}
}
impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {}
impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {}
impl<'c, const KEY_SIZE: usize> IVSized for AesCbc<'c, KEY_SIZE> {}
pub struct AesCtr<'c, const KEY_SIZE: usize> {
iv: &'c [u8; 16],
key: &'c [u8; KEY_SIZE],
}
impl<'c, const KEY_SIZE: usize> AesCtr<'c, KEY_SIZE> {
pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
Self { key, iv }
}
}
impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
const REQUIRES_PADDING: bool = false;
fn key(&self) -> &[u8] {
self.key
}
fn iv(&self) -> &[u8] {
self.iv
}
fn set_mode(&self, p: pac::aes::Aes) {
p.cr().modify(|w| {
w.set_chmod(pac::aes::vals::Chmod::from_bits(2));
});
}
fn chmod_bits(&self) -> u8 {
2
}
}
impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {}
impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {}
pub struct AesGcm<'c, const KEY_SIZE: usize> {
key: &'c [u8; KEY_SIZE],
iv: [u8; 16],
}
impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
let mut iv_full = [0u8; 16];
iv_full[..12].copy_from_slice(iv);
iv_full[15] = 2; Self { key, iv: iv_full }
}
}
impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
const REQUIRES_PADDING: bool = false;
fn key(&self) -> &[u8] {
self.key
}
fn iv(&self) -> &[u8] {
&self.iv
}
fn set_mode(&self, p: pac::aes::Aes) {
p.cr().modify(|w| {
w.set_chmod(pac::aes::vals::Chmod::from_bits(3));
});
}
fn chmod_bits(&self) -> u8 {
3
}
fn init_phase_blocking<T: Instance, M: Mode>(&self, p: pac::aes::Aes, _aes: &Aes<T, M>) {
p.cr().modify(|w| w.set_en(true));
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
}
async fn init_phase<T: Instance>(&self, p: pac::aes::Aes, _aes: &mut Aes<'_, T, Async>) {
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(0)));
p.cr().modify(|w| w.set_en(true));
poll_fn(|cx| {
if p.sr().read().ccf() {
Poll::Ready(())
} else {
AES_WAKER.register(cx.waker());
if p.sr().read().ccf() {
Poll::Ready(())
} else {
Poll::Pending
}
}
})
.await;
}
fn pre_final(&self, p: pac::aes::Aes, _dir: Direction, padding_len: usize) -> [u32; 4] {
if padding_len > 0 {
p.cr().modify(|w| w.set_npblb(padding_len as u8));
}
[0; 4]
}
fn uses_gcm_phases(&self) -> bool {
true
}
}
impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {}
impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {}
pub struct AesGmac<'c, const KEY_SIZE: usize> {
key: &'c [u8; KEY_SIZE],
iv: [u8; 16],
}
impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
let mut iv_full = [0u8; 16];
iv_full[..12].copy_from_slice(iv);
iv_full[15] = 2; Self { key, iv: iv_full }
}
}
impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
const REQUIRES_PADDING: bool = false;
fn key(&self) -> &[u8] {
self.key
}
fn iv(&self) -> &[u8] {
&self.iv
}
fn set_mode(&self, p: pac::aes::Aes) {
p.cr().modify(|w| {
w.set_chmod(pac::aes::vals::Chmod::from_bits(3));
});
}
fn chmod_bits(&self) -> u8 {
3
}
fn init_phase_blocking<T: Instance, M: Mode>(&self, p: pac::aes::Aes, _aes: &Aes<T, M>) {
p.cr().modify(|w| w.set_en(true));
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
}
async fn init_phase<T: Instance>(&self, p: pac::aes::Aes, _aes: &mut Aes<'_, T, Async>) {
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(0)));
p.cr().modify(|w| w.set_en(true));
poll_fn(|cx| {
if p.sr().read().ccf() {
Poll::Ready(())
} else {
AES_WAKER.register(cx.waker());
if p.sr().read().ccf() {
Poll::Ready(())
} else {
Poll::Pending
}
}
})
.await;
}
fn uses_gcm_phases(&self) -> bool {
true
}
}
impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {}
impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {}
pub struct AesCcm<'c, const KEY_SIZE: usize, const IV_SIZE: usize, const TAG_SIZE: usize> {
key: &'c [u8; KEY_SIZE],
iv: [u8; 16],
#[allow(dead_code)] aad_len: usize,
#[allow(dead_code)] payload_len: usize,
}
impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize, const TAG_SIZE: usize> AesCcm<'c, KEY_SIZE, IV_SIZE, TAG_SIZE> {
pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self {
assert!(IV_SIZE >= 7 && IV_SIZE <= 13, "CCM IV must be 7-13 bytes");
assert!(
TAG_SIZE >= 4 && TAG_SIZE <= 16 && TAG_SIZE % 2 == 0,
"CCM tag must be 4-16 bytes and even"
);
let mut iv_full = [0u8; 16];
let l = 15 - IV_SIZE; iv_full[0] = ((l - 1) as u8) | ((((TAG_SIZE - 2) / 2) as u8) << 3);
if aad_len > 0 {
iv_full[0] |= 0x40; }
iv_full[1..1 + IV_SIZE].copy_from_slice(iv);
let payload_bytes = (payload_len as u64).to_be_bytes();
let offset = 16 - l;
iv_full[offset..].copy_from_slice(&payload_bytes[8 - l..]);
Self {
key,
iv: iv_full,
aad_len,
payload_len,
}
}
}
impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize, const TAG_SIZE: usize> Cipher<'c>
for AesCcm<'c, KEY_SIZE, IV_SIZE, TAG_SIZE>
{
const REQUIRES_PADDING: bool = false;
fn key(&self) -> &[u8] {
self.key
}
fn iv(&self) -> &[u8] {
&self.iv
}
fn set_mode(&self, p: pac::aes::Aes) {
p.cr().modify(|w| {
w.set_chmod(pac::aes::vals::Chmod::from_bits(4));
});
}
fn chmod_bits(&self) -> u8 {
4
}
fn init_phase_blocking<T: Instance, M: Mode>(&self, p: pac::aes::Aes, _aes: &Aes<T, M>) {
p.cr().modify(|w| w.set_en(true));
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
}
async fn init_phase<T: Instance>(&self, p: pac::aes::Aes, _aes: &mut Aes<'_, T, Async>) {
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(0)));
p.cr().modify(|w| w.set_en(true));
poll_fn(|cx| {
if p.sr().read().ccf() {
Poll::Ready(())
} else {
AES_WAKER.register(cx.waker());
if p.sr().read().ccf() {
Poll::Ready(())
} else {
Poll::Pending
}
}
})
.await;
}
fn pre_final(&self, p: pac::aes::Aes, _dir: Direction, padding_len: usize) -> [u32; 4] {
if padding_len > 0 {
p.cr().modify(|w| w.set_npblb(padding_len as u8));
}
[0; 4]
}
fn uses_gcm_phases(&self) -> bool {
true
}
fn is_ccm_mode(&self) -> bool {
true
}
fn ccm_b0(&self) -> Option<&[u8; 16]> {
Some(&self.iv)
}
}
impl<'c, const IV_SIZE: usize, const TAG_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, IV_SIZE, TAG_SIZE> {}
impl<'c, const IV_SIZE: usize, const TAG_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, IV_SIZE, TAG_SIZE> {}
impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize, const TAG_SIZE: usize> IVSized
for AesCcm<'c, KEY_SIZE, IV_SIZE, TAG_SIZE>
{
}
impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize, const TAG_SIZE: usize> CipherAuthenticated<TAG_SIZE>
for AesCcm<'c, KEY_SIZE, IV_SIZE, TAG_SIZE>
{
}
#[derive(Clone)]
pub struct Context<'c, C: Cipher<'c>> {
pub cipher: &'c C,
pub dir: Direction,
pub last_block_processed: bool,
pub is_gcm_ccm: bool,
pub header_processed: bool,
pub header_len: u64,
pub payload_len: u64,
pub aad_buffer: [u8; 16],
pub aad_buffer_len: usize,
pub cr: u32,
pub iv: [u32; 4],
pub suspr: [u32; 8],
}
pub struct Aes<'d, T: Instance, M: Mode> {
_peripheral: Peri<'d, T>,
_phantom: PhantomData<M>,
#[allow(dead_code)] dma_in: Option<ChannelAndRequest<'d>>,
#[allow(dead_code)] dma_out: Option<ChannelAndRequest<'d>>,
}
impl<'d, T: Instance> Aes<'d, T, Blocking> {
pub fn new_blocking(
peripheral: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
rcc::enable_and_reset::<T>();
let instance = Self {
_peripheral: peripheral,
_phantom: PhantomData,
dma_in: None,
dma_out: None,
};
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
instance
}
}
impl<'d, T: Instance> Aes<'d, T, Async> {
pub fn new<D1: DmaIn<T>, D2: DmaOut<T>>(
peripheral: Peri<'d, T>,
dma_in: Peri<'d, D1>,
dma_out: Peri<'d, D2>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>>
+ interrupt::typelevel::Binding<D1::Interrupt, crate::dma::InterruptHandler<D1>>
+ interrupt::typelevel::Binding<D2::Interrupt, crate::dma::InterruptHandler<D2>>
+ 'd,
) -> Self {
rcc::enable_and_reset::<T>();
let instance = Self {
_peripheral: peripheral,
_phantom: PhantomData,
dma_in: new_dma!(dma_in, _irq),
dma_out: new_dma!(dma_out, _irq),
};
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
instance
}
}
impl<'d, T: Instance, M: Mode> Aes<'d, T, M> {
pub fn start<'c, C>(&mut self, cipher: &'c C, dir: Direction) -> Context<'c, C>
where
C: Cipher<'c> + CipherSized + IVSized,
{
let p = T::regs();
p.cr().modify(|w| w.set_en(false));
p.cr()
.modify(|w| w.set_datatype(pac::aes::vals::Datatype::from_bits(cipher.datatype())));
let keysize = cipher.key_size();
p.cr().modify(|w| w.set_keysize(keysize == KeySize::Bits256));
p.cr()
.modify(|w| w.set_mode(pac::aes::vals::Mode::from_bits(dir as u8)));
cipher.set_mode(p);
let is_gcm_ccm = cipher.uses_gcm_phases();
if is_gcm_ccm {
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(0)));
}
let needs_key_prep = dir == Direction::Decrypt && !is_gcm_ccm && cipher.key().len() > 0;
if is_gcm_ccm {
self.load_key(cipher.key());
if !cipher.iv().is_empty() {
self.load_iv(cipher.iv());
}
} else if needs_key_prep {
self.load_key(cipher.key());
cipher.prepare_key(p, dir);
p.cr()
.modify(|w| w.set_mode(pac::aes::vals::Mode::from_bits(dir as u8)));
cipher.set_mode(p);
if !cipher.iv().is_empty() {
self.load_iv(cipher.iv());
}
} else {
if !cipher.iv().is_empty() {
self.load_iv(cipher.iv());
}
self.load_key(cipher.key());
}
if is_gcm_ccm {
cipher.init_phase_blocking(p, self);
} else {
p.cr().modify(|w| w.set_en(true));
}
Context {
cipher,
dir,
last_block_processed: false,
is_gcm_ccm,
header_processed: false,
header_len: 0,
payload_len: 0,
aad_buffer: [0; 16],
aad_buffer_len: 0,
cr: p.cr().read().0,
iv: [p.ivr(0).read(), p.ivr(1).read(), p.ivr(2).read(), p.ivr(3).read()],
suspr: [0; 8],
}
}
pub fn aad_blocking<'c, C>(&mut self, ctx: &mut Context<'c, C>, aad: &[u8], last: bool) -> Result<(), Error>
where
C: Cipher<'c> + CipherAuthenticated<16>,
{
let p = T::regs();
if ctx.header_processed && last {
return Ok(());
}
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(1)));
p.cr().modify(|w| w.set_en(true));
let mut aad_remaining = aad.len();
let mut aad_index = 0;
if ctx.aad_buffer_len > 0 {
let space_available = 16 - ctx.aad_buffer_len;
let to_copy = core::cmp::min(space_available, aad_remaining);
ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + to_copy].copy_from_slice(&aad[..to_copy]);
ctx.aad_buffer_len += to_copy;
aad_index += to_copy;
aad_remaining -= to_copy;
if ctx.aad_buffer_len == 16 {
self.write_block_blocking(&ctx.aad_buffer)?;
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
ctx.header_len += 16;
ctx.aad_buffer_len = 0;
}
}
while aad_remaining >= 16 {
self.write_block_blocking(&aad[aad_index..aad_index + 16])?;
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
ctx.header_len += 16;
aad_index += 16;
aad_remaining -= 16;
}
if aad_remaining > 0 {
ctx.aad_buffer[..aad_remaining].copy_from_slice(&aad[aad_index..aad_index + aad_remaining]);
ctx.aad_buffer_len = aad_remaining;
}
if last {
if ctx.aad_buffer_len > 0 {
for i in ctx.aad_buffer_len..16 {
ctx.aad_buffer[i] = 0;
}
self.write_block_blocking(&ctx.aad_buffer)?;
while !p.sr().read().ccf() {}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
ctx.header_len += ctx.aad_buffer_len as u64;
ctx.aad_buffer_len = 0;
}
ctx.header_processed = true;
}
Ok(())
}
pub fn payload_blocking<'c, C>(
&mut self,
ctx: &mut Context<'c, C>,
input: &[u8],
output: &mut [u8],
last: bool,
) -> Result<(), Error>
where
C: Cipher<'c>,
{
let p = T::regs();
if output.len() < input.len() {
return Err(Error::ConfigError);
}
if ctx.is_gcm_ccm {
let header_was_skipped = !ctx.header_processed;
if header_was_skipped {
ctx.header_processed = true;
}
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(2)));
p.cr().modify(|w| w.set_npblb(0));
if header_was_skipped {
p.cr().modify(|w| w.set_en(true));
}
}
let block_size = C::BLOCK_SIZE;
let mut processed = 0;
if !last && input.len() % block_size != 0 {
return Err(Error::ConfigError);
}
let complete_blocks = if last {
input.len() / block_size
} else {
input.len() / block_size
};
for _ in 0..complete_blocks {
let block = &input[processed..processed + block_size];
let out_block = &mut output[processed..processed + block_size];
self.write_block_blocking(block)?;
self.read_block_blocking(out_block)?;
processed += block_size;
ctx.payload_len += block_size as u64;
}
if last && processed < input.len() {
if C::REQUIRES_PADDING {
return Err(Error::ConfigError); }
let remaining = input.len() - processed;
let mut partial_block = [0u8; 16];
partial_block[..remaining].copy_from_slice(&input[processed..]);
let is_ccm = ctx.cipher.is_ccm_mode();
let should_set_npblb = if is_ccm {
ctx.dir == Direction::Decrypt } else {
true };
if should_set_npblb {
let npblb = (16 - remaining) as u8;
p.cr().modify(|w| w.set_npblb(npblb));
}
self.write_block_blocking(&partial_block)?;
self.read_block_blocking(&mut partial_block)?;
output[processed..processed + remaining].copy_from_slice(&partial_block[..remaining]);
ctx.payload_len += remaining as u64;
}
if last {
ctx.last_block_processed = true;
}
Ok(())
}
pub fn finish_blocking<'c, C>(&mut self, ctx: Context<'c, C>) -> Result<Option<[u8; 16]>, Error>
where
C: Cipher<'c>,
{
let p = T::regs();
if ctx.is_gcm_ccm {
while p.sr().read().busy() {}
p.cr().modify(|w| w.set_gcmph(pac::aes::vals::Gcmph::from_bits(3)));
if ctx.cipher.is_ccm_mode() {
p.cr().modify(|w| w.set_en(true));
} else {
let header_bits = (ctx.header_len * 8) as u32;
let payload_bits = (ctx.payload_len * 8) as u32;
p.dinr().write_value(0);
p.dinr().write_value(header_bits);
p.dinr().write_value(0);
p.dinr().write_value(payload_bits);
}
while !p.sr().read().ccf() {}
let mut tag = [0u8; 16];
for i in 0..4 {
let word = p.doutr().read();
tag[i * 4..i * 4 + 4].copy_from_slice(&word.to_be_bytes());
}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
p.cr().modify(|w| w.set_en(false));
Ok(Some(tag))
} else {
p.cr().modify(|w| w.set_en(false));
Ok(None)
}
}
fn load_key(&mut self, key: &[u8]) {
let p = T::regs();
let key_words = key.len() / 4;
for i in 0..key_words {
let word = u32::from_be_bytes([key[i * 4], key[i * 4 + 1], key[i * 4 + 2], key[i * 4 + 3]]);
p.keyr(key_words - 1 - i).write_value(word); }
}
fn load_iv(&mut self, iv: &[u8]) {
if iv.is_empty() {
return;
}
let p = T::regs();
let iv_words = core::cmp::min(iv.len(), 16) / 4;
for i in 0..iv_words {
let word = u32::from_be_bytes([iv[i * 4], iv[i * 4 + 1], iv[i * 4 + 2], iv[i * 4 + 3]]);
p.ivr(iv_words - 1 - i).write_value(word); }
}
fn write_block_blocking(&mut self, block: &[u8]) -> Result<(), Error> {
let p = T::regs();
for i in 0..4 {
if p.sr().read().wrerr() {
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
return Err(Error::WriteError);
}
let word = u32::from_be_bytes([block[i * 4], block[i * 4 + 1], block[i * 4 + 2], block[i * 4 + 3]]);
p.dinr().write_value(word);
}
Ok(())
}
fn read_block_blocking(&mut self, block: &mut [u8]) -> Result<(), Error> {
let p = T::regs();
while !p.sr().read().ccf() {}
let sr = p.sr().read();
if sr.rderr() {
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
return Err(Error::ReadError);
}
for i in 0..4 {
let word = p.doutr().read();
let bytes = word.to_be_bytes();
block[i * 4..i * 4 + 4].copy_from_slice(&bytes);
}
p.icr().write(|w| w.0 = 0xFFFF_FFFF);
Ok(())
}
}
trait SealedInstance {
fn regs() -> pac::aes::Aes;
}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send {
type Interrupt: interrupt::typelevel::Interrupt;
}
foreach_interrupt!(
($inst:ident, aes, AES, GLOBAL, $irq:ident) => {
impl Instance for peripherals::$inst {
type Interrupt = crate::interrupt::typelevel::$irq;
}
impl SealedInstance for peripherals::$inst {
fn regs() -> crate::pac::aes::Aes {
crate::pac::$inst
}
}
};
);
dma_trait!(DmaIn, Instance);
dma_trait!(DmaOut, Instance);