diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 18fb077da86..9cf4967ab00 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed writes to SPI not flushing before attempting to write, causing corrupted writes (#1381) - fix AdcConfig::adc_calibrate for xtensa targets (#1379) - Fixed a divide by zero panic when setting the LEDC duty cycle to 0 with `SetDutyCycle::set_duty_cycle` (#1403) +- Support 192 and 256-bit keys for AES (#1316) ### Changed diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index b6d3a4a2999..6b756d7a955 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -37,10 +37,10 @@ //! //! ```no_run //! let mut block = block_buf.clone(); -//! aes.process(&mut block, Mode::Encryption128, &keybuf); +//! aes.process(&mut block, Mode::Encryption128, keybuf); //! let hw_encrypted = block.clone(); //! -//! aes.process(&mut block, Mode::Decryption128, &keybuf); +//! aes.process(&mut block, Mode::Decryption128, keybuf); //! let hw_decrypted = block; //! ``` //! @@ -122,14 +122,64 @@ mod aes_spec_impl; const ALIGN_SIZE: usize = core::mem::size_of::(); +/// Represents the various key sizes allowed for AES encryption and decryption. +pub enum Key { + /// 128-bit AES key + Key16([u8; 16]), + /// 192-bit AES key + #[cfg(any(feature = "esp32", feature = "esp32s2"))] + Key24([u8; 24]), + /// 256-bit AES key + Key32([u8; 32]), +} + +// Implementing From for easy conversion from array to Key enum. +impl From<[u8; 16]> for Key { + fn from(key: [u8; 16]) -> Self { + Key::Key16(key) + } +} + +#[cfg(any(feature = "esp32", feature = "esp32s2"))] +impl From<[u8; 24]> for Key { + fn from(key: [u8; 24]) -> Self { + Key::Key24(key) + } +} + +impl From<[u8; 32]> for Key { + fn from(key: [u8; 32]) -> Self { + Key::Key32(key) + } +} + +impl Key { + /// Returns a slice representation of the AES key. + fn as_slice(&self) -> &[u8] { + match self { + Key::Key16(ref key) => key, + #[cfg(any(feature = "esp32", feature = "esp32s2"))] + Key::Key24(ref key) => key, + Key::Key32(ref key) => key, + } + } +} + +/// Defines the operating modes for AES encryption and decryption. pub enum Mode { + /// Encryption mode with 128-bit key Encryption128 = 0, + /// Encryption mode with 192-bit key #[cfg(any(esp32, esp32s2))] Encryption192 = 1, + /// Encryption mode with 256-bit key Encryption256 = 2, + /// Decryption mode with 128-bit key Decryption128 = 4, + /// Decryption mode with 192-bit key #[cfg(any(esp32, esp32s2))] Decryption192 = 5, + /// Decryption mode with 256-bit key Decryption256 = 6, } @@ -141,6 +191,7 @@ pub struct Aes<'d> { } impl<'d> Aes<'d> { + /// Constructs a new `Aes` instance. pub fn new(aes: impl Peripheral

+ 'd) -> Self { crate::into_ref!(aes); let mut ret = Self { @@ -154,8 +205,12 @@ impl<'d> Aes<'d> { } /// Encrypts/Decrypts the given buffer based on `mode` parameter - pub fn process(&mut self, block: &mut [u8; 16], mode: Mode, key: &[u8; 16]) { - self.write_key(key); + pub fn process(&mut self, block: &mut [u8; 16], mode: Mode, key: K) + where + K: Into, + { + // Convert from into Key enum + self.write_key(key.into().as_slice()); self.set_mode(mode as u8); self.set_block(block); self.start(); @@ -244,12 +299,18 @@ pub enum Endianness { LittleEndian = 0, } +/// Provides DMA (Direct Memory Access) support for AES operations. +/// +/// This module enhances the AES capabilities by utilizing DMA to handle data +/// transfer, which can significantly speed up operations when dealing with +/// large data volumes. It supports various cipher modes such as ECB, CBC, OFB, +/// CTR, CFB8, and CFB128. #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] pub mod dma { use embedded_dma::{ReadBuffer, WriteBuffer}; use crate::{ - aes::Mode, + aes::{Key, Mode}, dma::{ AesPeripheral, Channel, @@ -264,12 +325,19 @@ pub mod dma { const ALIGN_SIZE: usize = core::mem::size_of::(); + /// Specifies the block cipher modes available for AES operations. pub enum CipherMode { + /// Electronic Codebook Mode Ecb = 0, + /// Cipher Block Chaining Mode Cbc, + /// Output Feedback Mode Ofb, + /// Counter Mode. Ctr, + /// Cipher Feedback Mode with 8-bit shifting. Cfb8, + /// Cipher Feedback Mode with 128-bit shifting. Cfb128, } @@ -374,12 +442,20 @@ pub mod dma { C: ChannelTypes, C::P: AesPeripheral, { - pub fn write_key(&mut self, key: &[u8]) { - debug_assert!(key.len() <= 8 * ALIGN_SIZE); - debug_assert_eq!(key.len() % ALIGN_SIZE, 0); - self.aes.write_key(key); + /// Writes the encryption key to the AES hardware, checking that its + /// length matches expected constraints. + pub fn write_key(&mut self, key: K) + where + K: Into, + { + 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); @@ -390,15 +466,16 @@ pub mod dma { /// This will return a [AesDmaTransferRxTx] owning the buffer(s) and the /// AES instance. The maximum amount of data to be sent/received /// is 32736 bytes. - pub fn process<'t, TXBUF, RXBUF>( + pub fn process<'t, K, TXBUF, RXBUF>( &'t mut self, words: &'t TXBUF, read_buffer: &'t mut RXBUF, mode: Mode, cipher_mode: CipherMode, - key: [u8; 16], + key: K, ) -> Result, crate::dma::DmaError> where + K: Into, TXBUF: ReadBuffer, RXBUF: WriteBuffer, { @@ -412,14 +489,14 @@ pub mod dma { read_len, mode, cipher_mode, - key, + key.into(), )?; Ok(AesDmaTransferRxTx { aes_dma: self }) } #[allow(clippy::too_many_arguments)] - fn start_transfer_dma( + fn start_transfer_dma( &mut self, write_buffer_ptr: *const u8, write_buffer_len: usize, @@ -427,8 +504,11 @@ pub mod dma { read_buffer_len: usize, mode: Mode, cipher_mode: CipherMode, - key: [u8; 16], - ) -> Result<(), crate::dma::DmaError> { + key: K, + ) -> Result<(), crate::dma::DmaError> + where + K: Into, + { // AES has to be restarted after each calculation self.reset_aes(); @@ -457,7 +537,7 @@ pub mod dma { self.enable_interrupt(); self.set_mode(mode); self.set_cipher_mode(cipher_mode); - self.write_key(&key); + self.write_key(key.into()); // TODO: verify 16? self.set_num_block(16); @@ -468,7 +548,7 @@ pub mod dma { } #[cfg(any(esp32c3, esp32s3))] - pub fn reset_aes(&self) { + fn reset_aes(&self) { unsafe { let s = crate::peripherals::SYSTEM::steal(); s.perip_rst_en1() @@ -479,7 +559,7 @@ pub mod dma { } #[cfg(any(esp32c6, esp32h2))] - pub fn reset_aes(&self) { + fn reset_aes(&self) { unsafe { let s = crate::peripherals::PCR::steal(); s.aes_conf().modify(|_, w| w.aes_rst_en().set_bit()); @@ -502,7 +582,7 @@ pub mod dma { self.aes.aes.int_ena().write(|w| w.int_ena().set_bit()); } - pub fn set_cipher_mode(&self, mode: CipherMode) { + fn set_cipher_mode(&self, mode: CipherMode) { self.aes .aes .block_mode() @@ -516,7 +596,7 @@ pub mod dma { } } - pub fn set_mode(&self, mode: Mode) { + fn set_mode(&self, mode: Mode) { self.aes .aes .mode() @@ -527,7 +607,7 @@ pub mod dma { self.aes.aes.trigger().write(|w| w.trigger().set_bit()); } - pub fn finish_transform(&self) { + fn finish_transform(&self) { self.aes.aes.dma_exit().write(|w| w.dma_exit().set_bit()); self.enable_dma(false); self.reset_aes(); diff --git a/examples/src/bin/aes.rs b/examples/src/bin/aes.rs index ae513f5b354..81fe8709ba6 100644 --- a/examples/src/bin/aes.rs +++ b/examples/src/bin/aes.rs @@ -37,7 +37,7 @@ fn main() -> ! { let mut block = block_buf.clone(); let pre_hw_encrypt = cycles(); - aes.process(&mut block, Mode::Encryption128, &keybuf); + aes.process(&mut block, Mode::Encryption128, keybuf); let post_hw_encrypt = cycles(); println!( "it took {} cycles for hw encrypt", @@ -45,7 +45,7 @@ fn main() -> ! { ); let hw_encrypted = block.clone(); let pre_hw_decrypt = cycles(); - aes.process(&mut block, Mode::Decryption128, &keybuf); + aes.process(&mut block, Mode::Decryption128, keybuf); let post_hw_decrypt = cycles(); println!( "it took {} cycles for hw decrypt", @@ -73,14 +73,10 @@ fn main() -> ! { ); let sw_decrypted = block; - assert!(eq(&sw_encrypted.into(), &hw_encrypted)); - assert!(eq(&sw_decrypted.into(), &hw_decrypted)); + assert!(&sw_encrypted as &[u8] == &hw_encrypted); + assert!(&sw_decrypted as &[u8] == &hw_decrypted); println!("done"); loop {} } - -fn eq(slice1: &[u8; 16], slice2: &[u8; 16]) -> bool { - slice1.iter().zip(slice2.iter()).all(|(a, b)| a == b) -} diff --git a/examples/src/bin/aes_dma.rs b/examples/src/bin/aes_dma.rs index da6aa4a0539..387c1219d3f 100644 --- a/examples/src/bin/aes_dma.rs +++ b/examples/src/bin/aes_dma.rs @@ -109,13 +109,9 @@ fn main() -> ! { ); let sw_decrypted = block.clone(); - assert!(eq(&sw_encrypted.into(), &hw_encrypted)); - assert!(eq(&sw_decrypted.into(), &hw_decrypted)); + assert!(&sw_encrypted as &[u8] == &hw_encrypted); + assert!(&sw_decrypted as &[u8] == &hw_decrypted); println!("done"); loop {} } - -fn eq(slice1: &[u8; 16], slice2: &[u8; 16]) -> bool { - slice1.iter().zip(slice2.iter()).all(|(a, b)| a == b) -} diff --git a/hil-test/tests/aes.rs b/hil-test/tests/aes.rs index ee3c30e46a8..4dee6ddcb4b 100644 --- a/hil-test/tests/aes.rs +++ b/hil-test/tests/aes.rs @@ -53,7 +53,7 @@ mod tests { block_buf[..plaintext.len()].copy_from_slice(plaintext); let mut block = block_buf.clone(); - ctx.aes.process(&mut block, Mode::Encryption128, &keybuf); + ctx.aes.process(&mut block, Mode::Encryption128, keybuf); assert_eq!(block, encrypted_message); } @@ -70,7 +70,7 @@ mod tests { keybuf[..keytext.len()].copy_from_slice(keytext); ctx.aes - .process(&mut encrypted_message, Mode::Decryption128, &keybuf); + .process(&mut encrypted_message, Mode::Decryption128, keybuf); assert_eq!(&encrypted_message[..plaintext.len()], plaintext); } @@ -91,7 +91,7 @@ mod tests { block_buf[..plaintext.len()].copy_from_slice(plaintext); let mut block = block_buf.clone(); - ctx.aes.process(&mut block, Mode::Encryption192, &keybuf); + ctx.aes.process(&mut block, Mode::Encryption192, keybuf); assert_eq!(block, encrypted_message); } @@ -109,7 +109,7 @@ mod tests { keybuf[..keytext.len()].copy_from_slice(keytext); ctx.aes - .process(&mut encrypted_message, Mode::Decryption192, &keybuf); + .process(&mut encrypted_message, Mode::Decryption192, keybuf); assert_eq!(&encrypted_message[..plaintext.len()], plaintext); } @@ -129,7 +129,7 @@ mod tests { block_buf[..plaintext.len()].copy_from_slice(plaintext); let mut block = block_buf.clone(); - ctx.aes.process(&mut block, Mode::Encryption256, &keybuf); + ctx.aes.process(&mut block, Mode::Encryption256, keybuf); assert_eq!(block, encrypted_message); } @@ -146,7 +146,7 @@ mod tests { keybuf[..keytext.len()].copy_from_slice(keytext); ctx.aes - .process(&mut encrypted_message, Mode::Decryption256, &keybuf); + .process(&mut encrypted_message, Mode::Decryption256, keybuf); assert_eq!(&encrypted_message[..plaintext.len()], plaintext); } }