Midterm AES rework (#3882)

* Midterm AES rework

* Update esp-hal/src/aes/mod.rs

Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>

* Update esp-hal/MIGRATING-1.0.0-rc.0.md

Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>

* Panic on wrong size

---------

Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>
This commit is contained in:
Dániel Buga 2025-07-30 17:02:12 +02:00 committed by GitHub
parent e1917abf9f
commit 406056ab9c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 392 additions and 633 deletions

View File

@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `rng` module has been rewritten (#3829)
- Update `embassy-usb` to v0.5.0 (#3848)
- `aes::Key` variants have been renamed from bytes to bits (e.g. `Key16 -> Key128`) (#3845)
- `aes::Mode` has been replaced by `Operation`. The key length is now solely determined by the key. (#3882)
- `Aes::process` has been split into `Aes::encrypt` and `Aes::decrypt` (#3882)
### Fixed
@ -27,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Removed
- `Trng::new` (replaced by `Trng::try_new`) (#3829)
- `AesDma::write_block` has been removed. (#3882)
## [v1.0.0-rc.0] - 2025-07-16

View File

@ -24,3 +24,19 @@ The previous way to obtain RNG object has changed like so:
+// As long as `trng_source` is alive:
+let trng = Tnrg::try_new().unrwap();
```
## AES changes
The `esp_hal::aes::Aes` driver has been slightly reworked:
- `Mode` has been replaced by `Operation`. Operation has `Encrypt` and `Decrypt` variants, but the key length is no longer part of the enum. The key length is specified by the key. AesDma now takes this `Operation`.
- `Aes::process` has been split into `encrypt` and `decrypt`. These functions no longer take a mode parameter.
- `AesDma::write_block` has been removed.
```diff
-aes.process(block, Mode::Encrypt128, key);
+aes.encrypt(block, key_16_bytes);
-aes.process(block, Mode::Decrypt256, key);
+aes.decrypt(block, key_32_bytes);
```

View File

@ -1,68 +0,0 @@
use crate::aes::{ALIGN_SIZE, Aes, Endianness, Mode};
impl Aes<'_> {
pub(super) fn init(&mut self) {
self.write_endianness(
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
);
}
pub(super) fn write_key(&mut self, key: &[u8]) {
let key_len = self.regs().key_iter().count();
debug_assert!(key.len() <= key_len * ALIGN_SIZE);
debug_assert_eq!(key.len() % ALIGN_SIZE, 0);
self.alignment_helper
.volatile_write_regset(self.regs().key(0).as_ptr(), key, key_len);
}
pub(super) fn write_block(&mut self, block: &[u8]) {
let text_len = self.regs().text_iter().count();
debug_assert_eq!(block.len(), text_len * ALIGN_SIZE);
self.alignment_helper
.volatile_write_regset(self.regs().text(0).as_ptr(), block, text_len);
}
pub(super) fn write_mode(&self, mode: Mode) {
self.regs().mode().write(|w| unsafe { w.bits(mode as _) });
}
/// Configures how the state matrix would be laid out
pub fn write_endianness(
&mut self,
input_text_word_endianess: Endianness,
input_text_byte_endianess: Endianness,
output_text_word_endianess: Endianness,
output_text_byte_endianess: Endianness,
key_word_endianess: Endianness,
key_byte_endianess: Endianness,
) {
let mut to_write = 0_u32;
to_write |= key_byte_endianess as u32;
to_write |= (key_word_endianess as u32) << 1;
to_write |= (input_text_byte_endianess as u32) << 2;
to_write |= (input_text_word_endianess as u32) << 3;
to_write |= (output_text_byte_endianess as u32) << 4;
to_write |= (output_text_word_endianess as u32) << 5;
self.regs().endian().write(|w| unsafe { w.bits(to_write) });
}
pub(super) fn write_start(&self) {
self.regs().start().write(|w| w.start().set_bit());
}
pub(super) fn read_idle(&mut self) -> bool {
self.regs().idle().read().idle().bit_is_set()
}
pub(super) fn read_block(&self, block: &mut [u8]) {
let text_len = self.regs().text_iter().count();
debug_assert_eq!(block.len(), text_len * ALIGN_SIZE);
self.alignment_helper
.volatile_read_regset(self.regs().text(0).as_ptr(), block, text_len);
}
}

View File

@ -1,44 +0,0 @@
use crate::aes::{ALIGN_SIZE, Aes, Mode};
impl Aes<'_> {
pub(super) fn init(&mut self) {
self.write_dma(false);
}
fn write_dma(&mut self, enable_dma: bool) {
self.regs()
.dma_enable()
.write(|w| w.dma_enable().bit(enable_dma));
}
pub(super) fn write_key(&mut self, key: &[u8]) {
debug_assert!(key.len() <= 8 * ALIGN_SIZE);
debug_assert_eq!(key.len() % ALIGN_SIZE, 0);
self.alignment_helper
.volatile_write_regset(self.regs().key(0).as_ptr(), key, 8);
}
pub(super) fn write_block(&mut self, block: &[u8]) {
debug_assert_eq!(block.len(), 4 * ALIGN_SIZE);
self.alignment_helper
.volatile_write_regset(self.regs().text_in(0).as_ptr(), block, 4);
}
pub(super) fn write_mode(&self, mode: Mode) {
self.regs().mode().write(|w| unsafe { w.bits(mode as _) });
}
pub(super) fn write_start(&self) {
self.regs().trigger().write(|w| w.trigger().set_bit());
}
pub(super) fn read_idle(&mut self) -> bool {
self.regs().state().read().state().bits() == 0
}
pub(super) fn read_block(&self, block: &mut [u8]) {
debug_assert_eq!(block.len(), 4 * ALIGN_SIZE);
self.alignment_helper
.volatile_read_regset(self.regs().text_out(0).as_ptr(), block, 4);
}
}

View File

@ -1,81 +0,0 @@
use crate::aes::{ALIGN_SIZE, Aes, Endianness, Mode};
impl Aes<'_> {
pub(super) fn init(&mut self) {
self.write_dma(false);
self.write_endianness(
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
Endianness::BigEndian,
);
}
fn write_dma(&mut self, enable_dma: bool) {
self.regs()
.dma_enable()
.write(|w| w.dma_enable().bit(enable_dma));
}
pub(super) fn write_key(&mut self, key: &[u8]) {
let key_len = self.regs().key_iter().count();
debug_assert!(key.len() <= key_len * ALIGN_SIZE);
debug_assert_eq!(key.len() % ALIGN_SIZE, 0);
self.alignment_helper
.volatile_write_regset(self.regs().key(0).as_ptr(), key, key_len);
}
pub(super) fn write_block(&mut self, block: &[u8]) {
let text_in_len = self.regs().text_in_iter().count();
debug_assert_eq!(block.len(), text_in_len * ALIGN_SIZE);
self.alignment_helper.volatile_write_regset(
self.regs().text_in(0).as_ptr(),
block,
text_in_len,
);
}
pub(super) fn write_mode(&self, mode: Mode) {
self.regs().mode().write(|w| unsafe { w.bits(mode as _) });
}
/// Configures how the state matrix would be laid out.
pub fn write_endianness(
&mut self,
input_text_word_endianess: Endianness,
input_text_byte_endianess: Endianness,
output_text_word_endianess: Endianness,
output_text_byte_endianess: Endianness,
key_word_endianess: Endianness,
key_byte_endianess: Endianness,
) {
let mut to_write = 0_u32;
to_write |= key_byte_endianess as u32;
to_write |= (key_word_endianess as u32) << 1;
to_write |= (input_text_byte_endianess as u32) << 2;
to_write |= (input_text_word_endianess as u32) << 3;
to_write |= (output_text_byte_endianess as u32) << 4;
to_write |= (output_text_word_endianess as u32) << 5;
self.regs().endian().write(|w| unsafe { w.bits(to_write) });
}
pub(super) fn write_start(&self) {
self.regs().trigger().write(|w| w.trigger().set_bit());
}
pub(super) fn read_idle(&mut self) -> bool {
self.regs().state().read().state().bits() == 0
}
pub(super) fn read_block(&self, block: &mut [u8]) {
let text_out_len = self.regs().text_out_iter().count();
debug_assert_eq!(block.len(), text_out_len * ALIGN_SIZE);
self.alignment_helper.volatile_read_regset(
self.regs().text_out(0).as_ptr(),
block,
text_out_len,
);
}
}

View File

@ -1,53 +0,0 @@
use crate::aes::{ALIGN_SIZE, Aes, Mode};
impl Aes<'_> {
pub(super) fn init(&mut self) {
self.write_dma(false);
}
fn write_dma(&mut self, enable_dma: bool) {
self.regs()
.dma_enable()
.write(|w| w.dma_enable().bit(enable_dma));
}
pub(super) fn write_key(&mut self, key: &[u8]) {
let key_len = self.regs().key_iter().count();
debug_assert!(key.len() <= key_len * ALIGN_SIZE);
debug_assert_eq!(key.len() % ALIGN_SIZE, 0);
self.alignment_helper
.volatile_write_regset(self.regs().key(0).as_ptr(), key, key_len);
}
pub(super) fn write_block(&mut self, block: &[u8]) {
let text_in_len = self.regs().text_in_iter().count();
debug_assert_eq!(block.len(), text_in_len * ALIGN_SIZE);
self.alignment_helper.volatile_write_regset(
self.regs().text_in(0).as_ptr(),
block,
text_in_len,
);
}
pub(super) fn write_mode(&self, mode: Mode) {
self.regs().mode().write(|w| unsafe { w.bits(mode as _) });
}
pub(super) fn write_start(&self) {
self.regs().trigger().write(|w| w.trigger().set_bit());
}
pub(super) fn read_idle(&mut self) -> bool {
self.regs().state().read().state().bits() == 0
}
pub(super) fn read_block(&self, block: &mut [u8]) {
let text_out_len = self.regs().text_out_iter().count();
debug_assert_eq!(block.len(), text_out_len * ALIGN_SIZE);
self.alignment_helper.volatile_read_regset(
self.regs().text_out(0).as_ptr(),
block,
text_out_len,
);
}
}

View File

@ -24,7 +24,7 @@
//!
//! ```rust, no_run
//! # {before_snippet}
//! # use esp_hal::aes::{Aes, Mode};
//! # use esp_hal::aes::{Aes, Operation};
//! # let keytext = b"SUp4SeCp@sSw0rd";
//! # let plaintext = b"message";
//! # let mut keybuf = [0_u8; 16];
@ -34,11 +34,11 @@
//! block[..plaintext.len()].copy_from_slice(plaintext);
//!
//! let mut aes = Aes::new(peripherals.AES);
//! aes.process(&mut block, Mode::Encryption128, keybuf);
//! aes.encrypt(&mut block, keybuf);
//!
//! // The encryption happens in-place, so the ciphertext is in `block`
//!
//! aes.process(&mut block, Mode::Decryption128, keybuf);
//! aes.decrypt(&mut block, keybuf);
//!
//! // The decryption happens in-place, so the plaintext is in `block`
//! # {after_snippet}
@ -50,28 +50,8 @@
//! mode.
//!
//! [AES-DMA]: https://github.com/esp-rs/esp-hal/blob/main/hil-test/tests/aes_dma.rs
//!
//! ## Implementation State
//!
//! * AES-DMA mode is currently not supported on ESP32
//! * AES-DMA Initialization Vector (IV) is currently not supported
use crate::{
pac,
peripherals::AES,
reg_access::{AlignmentHelper, NativeEndianess},
system::GenericPeripheralGuard,
};
#[cfg_attr(esp32, path = "esp32.rs")]
#[cfg_attr(esp32s3, path = "esp32s3.rs")]
#[cfg_attr(esp32s2, path = "esp32s2.rs")]
#[cfg_attr(esp32c3, path = "esp32cX.rs")]
#[cfg_attr(esp32c6, path = "esp32cX.rs")]
#[cfg_attr(esp32h2, path = "esp32cX.rs")]
mod aes_spec_impl;
const ALIGN_SIZE: usize = core::mem::size_of::<u32>();
use crate::{pac, peripherals::AES, system::GenericPeripheralGuard};
for_each_aes_key_length! {
($len:literal) => {
@ -122,23 +102,45 @@ for_each_aes_key_length! {
paste::paste! {
/// Defines the operating modes for AES encryption and decryption.
#[repr(C)]
pub enum Mode {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Mode {
$(
#[doc= concat!("Encryption mode with ", stringify!($len), "-bit key")]
[<Encryption $bits>] = $encrypt,
#[doc= concat!("Decryption mode with ", stringify!($len), "-bit key")]
[<Decryption $bits>] = $decrypt,
)*
}
impl Key {
fn encrypt_mode(&self) -> Mode {
match self {
$(Self::[<Key $bits>](_) => Mode::[<Encryption $bits>],)*
}
}
fn decrypt_mode(&self) -> Mode {
match self {
$(Self::[<Key $bits>](_) => Mode::[<Decryption $bits>],)*
}
}
}
}
};
}
/// Defines the operating modes for AES encryption and decryption.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Operation {
/// Produce ciphertext from plaintext
Encrypt,
/// Produce plaintext from ciphertext
Decrypt,
}
/// AES peripheral container
pub struct Aes<'d> {
aes: AES<'d>,
alignment_helper: AlignmentHelper<NativeEndianess>,
_guard: GenericPeripheralGuard<{ crate::system::Peripheral::Aes as u8 }>,
}
@ -147,48 +149,120 @@ impl<'d> Aes<'d> {
pub fn new(aes: AES<'d>) -> Self {
let guard = GenericPeripheralGuard::new();
let mut ret = Self {
aes,
alignment_helper: AlignmentHelper::native_endianess(),
_guard: guard,
};
ret.init();
#[cfg_attr(not(aes_dma), expect(unused_mut))]
let mut this = Self { aes, _guard: guard };
ret
#[cfg(aes_dma)]
this.write_dma(false);
this
}
fn regs(&self) -> &pac::aes::RegisterBlock {
self.aes.register_block()
}
/// Encrypts/Decrypts the given buffer based on `mode` parameter
pub fn process<K>(&mut self, block: &mut [u8; 16], mode: Mode, key: K)
where
K: Into<Key>,
{
// Convert from into Key enum
self.write_key(key.into().as_slice());
self.write_mode(mode);
self.set_block(block);
self.start();
while !(self.is_idle()) {}
self.block(block);
/// Configures how the state matrix would be laid out
#[cfg(aes_endianness_configurable)]
pub fn write_endianness(
&mut self,
input_text_word_endianess: Endianness,
input_text_byte_endianess: Endianness,
output_text_word_endianess: Endianness,
output_text_byte_endianess: Endianness,
key_word_endianess: Endianness,
key_byte_endianess: Endianness,
) {
let mut to_write = 0_u32;
to_write |= key_byte_endianess as u32;
to_write |= (key_word_endianess as u32) << 1;
to_write |= (input_text_byte_endianess as u32) << 2;
to_write |= (input_text_word_endianess as u32) << 3;
to_write |= (output_text_byte_endianess as u32) << 4;
to_write |= (output_text_word_endianess as u32) << 5;
self.regs().endian().write(|w| unsafe { w.bits(to_write) });
}
fn start(&self) {
cfg_if::cfg_if! {
if #[cfg(esp32)] {
self.regs().start().write(|w| w.start().set_bit());
} else {
self.regs().trigger().write(|w| w.trigger().set_bit());
}
}
}
fn is_idle(&mut self) -> bool {
self.read_idle()
cfg_if::cfg_if! {
if #[cfg(esp32)] {
self.regs().idle().read().idle().bit_is_set()
} else {
self.regs().state().read().state().bits() == 0
}
}
}
fn set_block(&mut self, block: &[u8; 16]) {
fn write_key(&mut self, input: &[u8]) {
for (i, word) in read_words(input).enumerate() {
self.regs().key(i).write(|w| unsafe { w.bits(word) });
}
}
fn write_block(&mut self, block: &[u8]) {
for (i, word) in read_words(block).enumerate() {
cfg_if::cfg_if! {
if #[cfg(aes_has_split_text_registers)] {
self.regs().text_in(i).write(|w| unsafe { w.bits(word) });
} else {
self.regs().text(i).write(|w| unsafe { w.bits(word) });
}
}
}
}
fn read_block(&self, block: &mut [u8]) {
cfg_if::cfg_if! {
if #[cfg(aes_has_split_text_registers)] {
write_words(block, |i| self.regs().text_out(i).read().bits());
} else {
write_words(block, |i| self.regs().text(i).read().bits());
}
}
}
fn write_mode(&self, mode: Mode) {
self.regs().mode().write(|w| unsafe { w.bits(mode as _) });
}
#[cfg(aes_dma)]
fn write_dma(&mut self, enable_dma: bool) {
self.regs()
.dma_enable()
.write(|w| w.dma_enable().bit(enable_dma));
}
fn process(&mut self, block: &mut [u8; 16], mode: Mode, key: Key) {
self.write_key(key.as_slice());
self.write_mode(mode);
self.write_block(block);
}
fn block(&self, block: &mut [u8; 16]) {
self.start();
while !(self.is_idle()) {}
self.read_block(block);
}
fn start(&mut self) {
self.write_start();
/// Encrypts the given buffer with the given key.
pub fn encrypt(&mut self, block: &mut [u8; 16], key: impl Into<Key>) {
let key = key.into();
let mode = key.encrypt_mode();
self.process(block, mode, key)
}
/// Decrypts the given buffer with the given key.
pub fn decrypt(&mut self, block: &mut [u8; 16], key: impl Into<Key>) {
let key = key.into();
let mode = key.decrypt_mode();
self.process(block, mode, key)
}
}
@ -222,7 +296,7 @@ pub mod dma {
use crate::{
Blocking,
aes::{Key, Mode},
aes::{Key, Operation},
dma::{
Channel,
DmaChannelFor,
@ -287,21 +361,12 @@ pub mod dma {
impl<'d> AesDma<'d> {
/// Writes the encryption key to the AES hardware, checking that its
/// length matches expected constraints.
pub fn write_key<K>(&mut self, key: K)
where
K: Into<Key>,
{
pub fn write_key(&mut self, key: impl Into<Key>) {
let key = key.into(); // Convert into Key enum
debug_assert!(key.as_slice().len() <= 8 * ALIGN_SIZE);
debug_assert_eq!(key.as_slice().len() % ALIGN_SIZE, 0);
self.aes.write_key(key.as_slice());
}
/// Writes a block of data to the AES hardware, ensuring the block's
/// length is properly aligned.
pub fn write_block(&mut self, block: &[u8]) {
debug_assert_eq!(block.len(), 4 * ALIGN_SIZE);
self.aes.write_key(block);
let key = key.as_slice();
debug_assert!(key.len() <= 8 * ALIGN_SIZE);
debug_assert_eq!(key.len() % ALIGN_SIZE, 0);
self.aes.write_key(key);
}
/// Perform a DMA transfer.
@ -313,7 +378,7 @@ pub mod dma {
number_of_blocks: usize,
mut output: RXBUF,
mut input: TXBUF,
mode: Mode,
mode: Operation,
cipher_mode: CipherMode,
key: K,
) -> Result<AesTransfer<'d, RXBUF, TXBUF>, (crate::dma::DmaError, Self, RXBUF, TXBUF)>
@ -347,11 +412,16 @@ pub mod dma {
return Err((err, self, output, input));
}
let key = key.into();
self.enable_dma(true);
self.enable_interrupt();
self.aes.write_mode(mode);
self.aes.write_mode(if mode == Operation::Encrypt {
key.encrypt_mode()
} else {
key.decrypt_mode()
});
self.set_cipher_mode(cipher_mode);
self.write_key(key.into());
self.write_key(key);
self.set_num_block(number_of_blocks as u32);
@ -398,7 +468,7 @@ pub mod dma {
}
fn start_transform(&self) {
self.aes.write_start();
self.aes.start();
}
fn finish_transform(&self) {
@ -479,7 +549,7 @@ pub mod dma {
self.aes_dma.channel.rx.stop_transfer();
self.aes_dma.channel.tx.stop_transfer();
// SAFETY: This is Drop, we know that self.i8080 and self.buf_view
// SAFETY: This is Drop, we know that self.aes_dma and self.buf_view
// won't be touched again.
unsafe {
ManuallyDrop::drop(&mut self.aes_dma);
@ -491,3 +561,24 @@ pub mod dma {
}
}
}
// Utilities
fn read_words(slice: &[u8]) -> impl Iterator<Item = u32> {
fn bytes<const N: usize>(slice: &[u8]) -> impl Iterator<Item = [u8; N]> {
slice.chunks(N).map(|c| {
let mut bytes = [0; N];
bytes[0..c.len()].copy_from_slice(c);
bytes
})
}
bytes::<4>(slice).map(u32::from_le_bytes)
}
fn write_words(slice: &mut [u8], next: impl Fn(usize) -> u32) {
for (i, chunk) in slice.chunks_mut(4).enumerate() {
let bytes = next(i).to_le_bytes();
chunk.copy_from_slice(&bytes[0..chunk.len()]);
}
}

View File

@ -79,18 +79,6 @@ impl AlignmentHelper<SocDependentEndianess> {
}
}
// only used by AES
#[cfg(aes)]
impl AlignmentHelper<NativeEndianess> {
pub fn native_endianess() -> AlignmentHelper<NativeEndianess> {
AlignmentHelper {
buf: [0u8; U32_ALIGN_SIZE],
buf_fill: 0,
phantom: PhantomData,
}
}
}
impl<E: EndianessConverter> AlignmentHelper<E> {
pub fn reset(&mut self) {
self.buf_fill = 0;

View File

@ -266,6 +266,7 @@ impl Chip {
"soc_ref_tick_hz_is_set",
"soc_rc_fast_clk_default=\"8000000\"",
"soc_rc_fast_clk_default_is_set",
"aes_endianness_configurable",
"gpio_has_bank_1",
"gpio_gpio_function=\"2\"",
"gpio_constant_0_input=\"48\"",
@ -419,6 +420,7 @@ impl Chip {
"cargo:rustc-cfg=soc_ref_tick_hz_is_set",
"cargo:rustc-cfg=soc_rc_fast_clk_default=\"8000000\"",
"cargo:rustc-cfg=soc_rc_fast_clk_default_is_set",
"cargo:rustc-cfg=aes_endianness_configurable",
"cargo:rustc-cfg=gpio_has_bank_1",
"cargo:rustc-cfg=gpio_gpio_function=\"2\"",
"cargo:rustc-cfg=gpio_constant_0_input=\"48\"",
@ -792,6 +794,7 @@ impl Chip {
"aes_dma_mode_ctr",
"aes_dma_mode_cfb8",
"aes_dma_mode_cfb128",
"aes_has_split_text_registers",
"assist_debug_has_sp_monitor",
"assist_debug_has_region_monitor",
"gpio_gpio_function=\"1\"",
@ -934,6 +937,7 @@ impl Chip {
"cargo:rustc-cfg=aes_dma_mode_ctr",
"cargo:rustc-cfg=aes_dma_mode_cfb8",
"cargo:rustc-cfg=aes_dma_mode_cfb128",
"cargo:rustc-cfg=aes_has_split_text_registers",
"cargo:rustc-cfg=assist_debug_has_sp_monitor",
"cargo:rustc-cfg=assist_debug_has_region_monitor",
"cargo:rustc-cfg=gpio_gpio_function=\"1\"",
@ -1131,6 +1135,7 @@ impl Chip {
"aes_dma_mode_ctr",
"aes_dma_mode_cfb8",
"aes_dma_mode_cfb128",
"aes_has_split_text_registers",
"assist_debug_has_sp_monitor",
"assist_debug_has_region_monitor",
"gpio_gpio_function=\"1\"",
@ -1329,6 +1334,7 @@ impl Chip {
"cargo:rustc-cfg=aes_dma_mode_ctr",
"cargo:rustc-cfg=aes_dma_mode_cfb8",
"cargo:rustc-cfg=aes_dma_mode_cfb128",
"cargo:rustc-cfg=aes_has_split_text_registers",
"cargo:rustc-cfg=assist_debug_has_sp_monitor",
"cargo:rustc-cfg=assist_debug_has_region_monitor",
"cargo:rustc-cfg=gpio_gpio_function=\"1\"",
@ -1508,6 +1514,7 @@ impl Chip {
"aes_dma_mode_ctr",
"aes_dma_mode_cfb8",
"aes_dma_mode_cfb128",
"aes_has_split_text_registers",
"assist_debug_has_sp_monitor",
"assist_debug_has_region_monitor",
"gpio_gpio_function=\"1\"",
@ -1680,6 +1687,7 @@ impl Chip {
"cargo:rustc-cfg=aes_dma_mode_ctr",
"cargo:rustc-cfg=aes_dma_mode_cfb8",
"cargo:rustc-cfg=aes_dma_mode_cfb128",
"cargo:rustc-cfg=aes_has_split_text_registers",
"cargo:rustc-cfg=assist_debug_has_sp_monitor",
"cargo:rustc-cfg=assist_debug_has_region_monitor",
"cargo:rustc-cfg=gpio_gpio_function=\"1\"",
@ -1853,6 +1861,8 @@ impl Chip {
"aes_dma_mode_cfb8",
"aes_dma_mode_cfb128",
"aes_dma_mode_gcm",
"aes_has_split_text_registers",
"aes_endianness_configurable",
"gpio_has_bank_1",
"gpio_gpio_function=\"1\"",
"gpio_constant_0_input=\"60\"",
@ -2021,6 +2031,8 @@ impl Chip {
"cargo:rustc-cfg=aes_dma_mode_cfb8",
"cargo:rustc-cfg=aes_dma_mode_cfb128",
"cargo:rustc-cfg=aes_dma_mode_gcm",
"cargo:rustc-cfg=aes_has_split_text_registers",
"cargo:rustc-cfg=aes_endianness_configurable",
"cargo:rustc-cfg=gpio_has_bank_1",
"cargo:rustc-cfg=gpio_gpio_function=\"1\"",
"cargo:rustc-cfg=gpio_constant_0_input=\"60\"",
@ -2205,6 +2217,7 @@ impl Chip {
"aes_dma_mode_ctr",
"aes_dma_mode_cfb8",
"aes_dma_mode_cfb128",
"aes_has_split_text_registers",
"assist_debug_has_region_monitor",
"gpio_has_bank_1",
"gpio_gpio_function=\"1\"",
@ -2389,6 +2402,7 @@ impl Chip {
"cargo:rustc-cfg=aes_dma_mode_ctr",
"cargo:rustc-cfg=aes_dma_mode_cfb8",
"cargo:rustc-cfg=aes_dma_mode_cfb128",
"cargo:rustc-cfg=aes_has_split_text_registers",
"cargo:rustc-cfg=assist_debug_has_region_monitor",
"cargo:rustc-cfg=gpio_has_bank_1",
"cargo:rustc-cfg=gpio_gpio_function=\"1\"",
@ -2563,6 +2577,7 @@ impl Config {
println!("cargo:rustc-check-cfg=cfg(uart_uart2)");
println!("cargo:rustc-check-cfg=cfg(soc_ref_tick_hz_is_set)");
println!("cargo:rustc-check-cfg=cfg(soc_rc_fast_clk_default_is_set)");
println!("cargo:rustc-check-cfg=cfg(aes_endianness_configurable)");
println!("cargo:rustc-check-cfg=cfg(gpio_has_bank_1)");
println!("cargo:rustc-check-cfg=cfg(gpio_remap_iomux_pin_registers)");
println!("cargo:rustc-check-cfg=cfg(i2c_master_separate_filter_config_registers)");
@ -2635,6 +2650,7 @@ impl Config {
println!("cargo:rustc-check-cfg=cfg(aes_dma_mode_ctr)");
println!("cargo:rustc-check-cfg=cfg(aes_dma_mode_cfb8)");
println!("cargo:rustc-check-cfg=cfg(aes_dma_mode_cfb128)");
println!("cargo:rustc-check-cfg=cfg(aes_has_split_text_registers)");
println!("cargo:rustc-check-cfg=cfg(assist_debug_has_region_monitor)");
println!("cargo:rustc-check-cfg=cfg(esp32c6)");
println!("cargo:rustc-check-cfg=cfg(soc_has_atomic)");

View File

@ -57,6 +57,12 @@ macro_rules! property {
("aes.dma") => {
false
};
("aes.has_split_text_registers") => {
false
};
("aes.endianness_configurable") => {
true
};
("gpio.has_bank_1") => {
true
};

View File

@ -51,6 +51,12 @@ macro_rules! property {
("aes.dma") => {
true
};
("aes.has_split_text_registers") => {
true
};
("aes.endianness_configurable") => {
false
};
("assist_debug.has_sp_monitor") => {
true
};

View File

@ -51,6 +51,12 @@ macro_rules! property {
("aes.dma") => {
true
};
("aes.has_split_text_registers") => {
true
};
("aes.endianness_configurable") => {
false
};
("assist_debug.has_sp_monitor") => {
true
};

View File

@ -51,6 +51,12 @@ macro_rules! property {
("aes.dma") => {
true
};
("aes.has_split_text_registers") => {
true
};
("aes.endianness_configurable") => {
false
};
("assist_debug.has_sp_monitor") => {
true
};

View File

@ -57,6 +57,12 @@ macro_rules! property {
("aes.dma") => {
true
};
("aes.has_split_text_registers") => {
true
};
("aes.endianness_configurable") => {
true
};
("gpio.has_bank_1") => {
true
};

View File

@ -51,6 +51,12 @@ macro_rules! property {
("aes.dma") => {
true
};
("aes.has_split_text_registers") => {
true
};
("aes.endianness_configurable") => {
false
};
("assist_debug.has_sp_monitor") => {
false
};

View File

@ -112,6 +112,8 @@ instances = [
[device.aes]
support_status = "partial"
has_split_text_registers = false
endianness_configurable = true
key_length = { options = [
{ bits = 128, encrypt_mode = 0, decrypt_mode = 4 },
{ bits = 192, encrypt_mode = 1, decrypt_mode = 5 },

View File

@ -99,6 +99,8 @@ instances = [
[device.aes]
support_status = "partial"
has_split_text_registers = true
endianness_configurable = false
dma = true
dma_mode = ["ECB", "CBC", "OFB", "CTR", "CFB8", "CFB128"]
key_length = { options = [

View File

@ -140,6 +140,8 @@ instances = [
[device.aes]
support_status = "partial"
has_split_text_registers = true
endianness_configurable = false
dma = true
dma_mode = ["ECB", "CBC", "OFB", "CTR", "CFB8", "CFB128"]
key_length = { options = [

View File

@ -119,6 +119,8 @@ instances = [
[device.aes]
support_status = "partial"
has_split_text_registers = true
endianness_configurable = false
dma = true
dma_mode = ["ECB", "CBC", "OFB", "CTR", "CFB8", "CFB128"]
key_length = { options = [

View File

@ -114,6 +114,8 @@ instances = [
[device.aes]
support_status = "partial"
has_split_text_registers = true
endianness_configurable = true
dma = true
dma_mode = ["ECB", "CBC", "OFB", "CTR", "CFB8", "CFB128", "GCM"]
key_length = { options = [

View File

@ -123,6 +123,8 @@ instances = [
[device.aes]
support_status = "partial"
has_split_text_registers = true
endianness_configurable = false
dma = true
dma_mode = ["ECB", "CBC", "OFB", "CTR", "CFB8", "CFB128"]
key_length = { options = [

View File

@ -293,6 +293,8 @@ driver_configs![
dma: bool,
#[serde(default)]
dma_mode: Vec<String>,
has_split_text_registers: bool,
endianness_configurable: bool,
}
},
AssistDebugProperties {

View File

@ -6,142 +6,80 @@
#![no_std]
#![no_main]
use esp_hal::{
aes::{Aes, Mode},
clock::CpuClock,
};
use hil_test as _;
esp_bootloader_esp_idf::esp_app_desc!();
struct Context<'a> {
aes: Aes<'a>,
const fn pad_to<const K: usize>(input: &[u8]) -> [u8; K] {
let mut out = [0; K];
let in_bytes = input.len();
assert!(in_bytes <= K);
let mut i = 0;
while i < in_bytes {
out[i] = input[i];
i += 1;
}
out
}
#[cfg(test)]
#[embedded_test::tests(default_timeout = 3)]
mod tests {
use esp_hal::{
Config,
aes::{Aes, Key},
clock::CpuClock,
};
use hil_test as _;
use super::*;
#[init]
fn init() -> Context<'static> {
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
let aes = Aes::new(peripherals.AES);
const KEY: &[u8] = b"SUp4SeCp@sSw0rd";
Context { aes }
}
const PLAINTEXT: &[u8] = b"message";
const PLAINTEXT_BUF: [u8; 16] = pad_to::<16>(PLAINTEXT);
const CIPHERTEXT_ECB_128: [u8; 16] = [
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a, 0x31,
0x96,
];
#[cfg(any(esp32, esp32s2))]
const CIPHERTEXT_ECB_192: [u8; 16] = [
0x79, 0x88, 0x3f, 0x9d, 0x67, 0x27, 0xf4, 0x18, 0x3, 0xe3, 0xc6, 0x6a, 0x2e, 0x76, 0xb6,
0xf7,
];
const CIPHERTEXT_ECB_256: [u8; 16] = [
0x0, 0x63, 0x3f, 0x02, 0xa4, 0x53, 0x09, 0x72, 0x20, 0x6d, 0xc9, 0x08, 0x7c, 0xe5, 0xfd,
0xc,
];
#[test]
fn test_aes_128_encryption(mut ctx: Context<'static>) {
let keytext = b"SUp4SeCp@sSw0rd";
let plaintext = b"message";
let encrypted_message = [
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
0x31, 0x96,
];
fn test_aes_block_operation() {
fn test_aes_block<const K: usize>(
aes: &mut Aes<'_>,
plaintext: [u8; 16],
ciphertext: [u8; 16],
) where
Key: From<[u8; K]>,
{
let mut block_buf = plaintext;
aes.encrypt(&mut block_buf, pad_to::<K>(KEY));
assert_eq!(&block_buf[..ciphertext.len()], ciphertext);
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let mut block_buf = ciphertext;
aes.decrypt(&mut block_buf, pad_to::<K>(KEY));
assert_eq!(&block_buf[..plaintext.len()], plaintext);
}
let mut block_buf = [0_u8; 16];
block_buf[..plaintext.len()].copy_from_slice(plaintext);
let p = esp_hal::init(Config::default().with_cpu_clock(CpuClock::max()));
let mut aes = Aes::new(p.AES);
let mut block = block_buf.clone();
ctx.aes.process(&mut block, Mode::Encryption128, keybuf);
assert_eq!(block, encrypted_message);
}
test_aes_block::<16>(&mut aes, PLAINTEXT_BUF, CIPHERTEXT_ECB_128);
#[test]
fn test_aes_128_decryption(mut ctx: Context<'static>) {
let keytext = b"SUp4SeCp@sSw0rd";
let plaintext = b"message";
let mut encrypted_message = [
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
0x31, 0x96,
];
#[cfg(any(esp32, esp32s2))]
test_aes_block::<24>(&mut aes, PLAINTEXT_BUF, CIPHERTEXT_ECB_192);
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
ctx.aes
.process(&mut encrypted_message, Mode::Decryption128, keybuf);
assert_eq!(&encrypted_message[..plaintext.len()], plaintext);
}
#[test]
#[cfg(any(feature = "esp32", feature = "esp32s2"))]
fn test_aes_192_encryption(mut ctx: Context<'static>) {
let keytext = b"SUp4SeCp@sSw0rd";
let plaintext = b"message";
let encrypted_message = [
0x79, 0x88, 0x3f, 0x9d, 0x67, 0x27, 0xf4, 0x18, 0x3, 0xe3, 0xc6, 0x6a, 0x2e, 0x76,
0xb6, 0xf7,
];
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let mut block_buf = [0_u8; 16];
block_buf[..plaintext.len()].copy_from_slice(plaintext);
let mut block = block_buf.clone();
ctx.aes.process(&mut block, Mode::Encryption192, keybuf);
assert_eq!(block, encrypted_message);
}
#[test]
#[cfg(any(feature = "esp32", feature = "esp32s2"))]
fn test_aes_192_decryption(mut ctx: Context<'static>) {
let keytext = b"SUp4SeCp@sSw0rd";
let plaintext = b"message";
let mut encrypted_message = [
0x79, 0x88, 0x3f, 0x9d, 0x67, 0x27, 0xf4, 0x18, 0x3, 0xe3, 0xc6, 0x6a, 0x2e, 0x76,
0xb6, 0xf7,
];
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
ctx.aes
.process(&mut encrypted_message, Mode::Decryption192, keybuf);
assert_eq!(&encrypted_message[..plaintext.len()], plaintext);
}
#[test]
fn test_aes_256_encryption(mut ctx: Context<'static>) {
let keytext = b"SUp4SeCp@sSw0rd";
let plaintext = b"message";
let encrypted_message = [
0x0, 0x63, 0x3f, 0x2, 0xa4, 0x53, 0x9, 0x72, 0x20, 0x6d, 0xc9, 0x8, 0x7c, 0xe5, 0xfd,
0xc,
];
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let mut block_buf = [0_u8; 16];
block_buf[..plaintext.len()].copy_from_slice(plaintext);
let mut block = block_buf.clone();
ctx.aes.process(&mut block, Mode::Encryption256, keybuf);
assert_eq!(block, encrypted_message);
}
#[test]
fn test_aes_256_decryption(mut ctx: Context<'static>) {
let keytext = b"SUp4SeCp@sSw0rd";
let plaintext = b"message";
let mut encrypted_message = [
0x0, 0x63, 0x3f, 0x2, 0xa4, 0x53, 0x9, 0x72, 0x20, 0x6d, 0xc9, 0x8, 0x7c, 0xe5, 0xfd,
0xc,
];
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
ctx.aes
.process(&mut encrypted_message, Mode::Decryption256, keybuf);
assert_eq!(&encrypted_message[..plaintext.len()], plaintext);
test_aes_block::<32>(&mut aes, PLAINTEXT_BUF, CIPHERTEXT_ECB_256);
}
}

View File

@ -7,30 +7,103 @@
#![no_main]
use esp_hal::{
aes::{Aes, Mode, dma::CipherMode},
aes::{Aes, Key, Operation, dma::CipherMode},
clock::CpuClock,
dma::{DmaRxBuf, DmaTxBuf},
dma_buffers,
peripherals::Peripherals,
};
use hil_test as _;
esp_bootloader_esp_idf::esp_app_desc!();
const fn pad_to<const K: usize>(input: &[u8]) -> [u8; K] {
let mut out = [0; K];
let in_bytes = input.len();
assert!(in_bytes <= K);
let mut i = 0;
while i < in_bytes {
out[i] = input[i];
i += 1;
}
out
}
const DMA_BUFFER_SIZE: usize = 16;
#[cfg(test)]
#[embedded_test::tests(default_timeout = 3)]
mod tests {
use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
use esp_hal::aes::dma::AesDma;
use super::*;
#[init]
fn init() -> Peripherals {
esp_hal::init(esp_hal::Config::default())
}
const KEY: &[u8] = b"SUp4SeCp@sSw0rd";
const PLAINTEXT: &[u8] = b"message";
const PLAINTEXT_BUF: [u8; 16] = pad_to::<16>(PLAINTEXT);
const CIPHERTEXT_ECB_128: [u8; 16] = [
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a, 0x31,
0x96,
];
const CIPHERTEXT_ECB_256: [u8; 16] = [
0x0, 0x63, 0x3f, 0x02, 0xa4, 0x53, 0x09, 0x72, 0x20, 0x6d, 0xc9, 0x08, 0x7c, 0xe5, 0xfd,
0xc,
];
#[test]
fn test_aes_128_dma_encryption(peripherals: Peripherals) {
fn test_aes_dma_ecb() {
fn test_aes_ecb<const K: usize>(
mut aes: AesDma<'_>,
plaintext: [u8; 16],
ciphertext: [u8; 16],
) -> AesDma<'_>
where
Key: From<[u8; K]>,
{
let (output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let mut output = DmaRxBuf::new(rx_descriptors, output).unwrap();
let mut input = DmaTxBuf::new(tx_descriptors, input).unwrap();
// Encrypt
input.as_mut_slice().copy_from_slice(&plaintext);
let transfer = aes
.process(
1,
output,
input,
Operation::Encrypt,
CipherMode::Ecb,
pad_to::<K>(KEY),
)
.map_err(|e| e.0)
.unwrap();
(aes, output, input) = transfer.wait();
assert_eq!(output.as_slice(), ciphertext);
// Decrypt
input.as_mut_slice().copy_from_slice(&ciphertext);
let transfer = aes
.process(
1,
output,
input,
Operation::Decrypt,
CipherMode::Ecb,
pad_to::<K>(KEY),
)
.map_err(|e| e.0)
.unwrap();
(aes, output, _) = transfer.wait();
assert_eq!(output.as_slice(), plaintext);
aes
}
let peripherals = esp_hal::init(esp_hal::Config::default().with_cpu_clock(CpuClock::max()));
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
let dma_channel = peripherals.DMA_CRYPTO;
@ -39,179 +112,9 @@ mod tests {
}
}
let (output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let mut output = DmaRxBuf::new(rx_descriptors, output).unwrap();
let mut input = DmaTxBuf::new(tx_descriptors, input).unwrap();
let aes = Aes::new(peripherals.AES).with_dma(dma_channel);
let keytext = b"SUp4SeCp@sSw0rd";
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let plaintext = b"message";
input.as_mut_slice()[..plaintext.len()].copy_from_slice(plaintext);
let encrypted_message = [
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
0x31, 0x96,
];
let transfer = aes
.process(
1,
output,
input,
Mode::Encryption128,
CipherMode::Ecb,
keybuf,
)
.map_err(|e| e.0)
.unwrap();
(_, output, _) = transfer.wait();
let mut encrypted_output = [0u8; 16];
(&mut encrypted_output[..]).copy_from_slice(output.as_slice());
assert_eq!(encrypted_output, encrypted_message);
}
#[test]
fn test_aes_128_dma_decryption(peripherals: Peripherals) {
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
let dma_channel = peripherals.DMA_CRYPTO;
} else {
let dma_channel = peripherals.DMA_CH0;
}
}
let (output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let mut output = DmaRxBuf::new(rx_descriptors, output).unwrap();
let mut input = DmaTxBuf::new(tx_descriptors, input).unwrap();
let aes = Aes::new(peripherals.AES).with_dma(dma_channel);
let keytext = b"SUp4SeCp@sSw0rd";
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let plaintext = b"message";
let encrypted_message = [
0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
0x31, 0x96,
];
input.as_mut_slice().copy_from_slice(&encrypted_message);
let transfer = aes
.process(
1,
output,
input,
Mode::Decryption128,
CipherMode::Ecb,
keybuf,
)
.map_err(|e| e.0)
.unwrap();
(_, output, _) = transfer.wait();
let mut decrypted_output = [0u8; 16];
(&mut decrypted_output[..]).copy_from_slice(output.as_slice());
assert_eq!(&decrypted_output[..plaintext.len()], plaintext);
}
#[test]
fn test_aes_256_dma_encryption(peripherals: Peripherals) {
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
let dma_channel = peripherals.DMA_CRYPTO;
} else {
let dma_channel = peripherals.DMA_CH0;
}
}
let (output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let mut output = DmaRxBuf::new(rx_descriptors, output).unwrap();
let mut input = DmaTxBuf::new(tx_descriptors, input).unwrap();
let aes = Aes::new(peripherals.AES).with_dma(dma_channel);
let keytext = b"SUp4SeCp@sSw0rd";
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let plaintext = b"message";
input.as_mut_slice()[..plaintext.len()].copy_from_slice(plaintext);
let encrypted_message = [
0x0, 0x63, 0x3f, 0x2, 0xa4, 0x53, 0x9, 0x72, 0x20, 0x6d, 0xc9, 0x8, 0x7c, 0xe5, 0xfd,
0xc,
];
let transfer = aes
.process(
1,
output,
input,
Mode::Encryption256,
CipherMode::Ecb,
keybuf,
)
.map_err(|e| e.0)
.unwrap();
(_, output, _) = transfer.wait();
let mut encrypted_output = [0u8; 16];
(&mut encrypted_output[..]).copy_from_slice(output.as_slice());
assert_eq!(encrypted_output, encrypted_message);
}
#[test]
fn test_aes_256_dma_decryption(peripherals: Peripherals) {
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
let dma_channel = peripherals.DMA_CRYPTO;
} else {
let dma_channel = peripherals.DMA_CH0;
}
}
let (output, rx_descriptors, input, tx_descriptors) = dma_buffers!(DMA_BUFFER_SIZE);
let mut output = DmaRxBuf::new(rx_descriptors, output).unwrap();
let mut input = DmaTxBuf::new(tx_descriptors, input).unwrap();
let aes = Aes::new(peripherals.AES).with_dma(dma_channel);
let keytext = b"SUp4SeCp@sSw0rd";
let mut keybuf = [0_u8; 16];
keybuf[..keytext.len()].copy_from_slice(keytext);
let plaintext = b"message";
let encrypted_message = [
0x0, 0x63, 0x3f, 0x2, 0xa4, 0x53, 0x9, 0x72, 0x20, 0x6d, 0xc9, 0x8, 0x7c, 0xe5, 0xfd,
0xc,
];
input.as_mut_slice().copy_from_slice(&encrypted_message);
let transfer = aes
.process(
1,
output,
input,
Mode::Decryption256,
CipherMode::Ecb,
keybuf,
)
.map_err(|e| e.0)
.unwrap();
(_, output, _) = transfer.wait();
let mut decrypted_output = [0u8; 16];
(&mut decrypted_output[..]).copy_from_slice(output.as_slice());
assert_eq!(&decrypted_output[..plaintext.len()], plaintext);
let aes = test_aes_ecb::<16>(aes, PLAINTEXT_BUF, CIPHERTEXT_ECB_128);
let _ = test_aes_ecb::<32>(aes, PLAINTEXT_BUF, CIPHERTEXT_ECB_256);
}
}