esp-hal/esp-hal-common/src/aes/mod.rs
Kirill Mikhailov 2bd10526a7
Documenting a number of peripherals and packages (#680)
* Initial documentation improvements

* More documentation improvements

* More documentation improvements


More modules documented

* Finished SOC documentation for esp32 + TWAI

* Fix: fix incorrect formatting

* Adding more documentation to rom, and soc peripherals for multiple chips

* Adding documentation for multiple peripherals

* Adding SOC module documentation

* Analog and clock modules are documented

* Adding module-level documentation for DMA and INTERRUPT peripherals

* Finishing job + minor fixes

* Fix unopened HTML break

* Rustfmt adjustment 


formatting


Fix typo

* Add CHANGELOG record


Fix typo

* Fix typos, mistakes, improving docs

Co-authored-by: Dániel Buga <bugadani@gmail.com>
Fix typo

Co-authored-by: Dániel Buga <bugadani@gmail.com>
Fix typo

Co-authored-by: Dániel Buga <bugadani@gmail.com>
Fix typo

Co-authored-by: Dániel Buga <bugadani@gmail.com>
fix typo

Co-authored-by: Dániel Buga <bugadani@gmail.com>
Fix typo

Co-authored-by: Dániel Buga <bugadani@gmail.com>
Fix typo

Co-authored-by: Scott Mabin <scott@mabez.dev>
Fixing typos, mistakes, improving docs.

* Fix formatting, mistakes and typos

* Fixing a bunch of logical, grammatical and formatting mistakes
2023-08-09 06:33:50 -07:00

239 lines
6.1 KiB
Rust

//! # Advanced Encryption Standard (AES) support.
//!
//! ## Overview
//! The AES module provides an interface to interact with the AES peripheral,
//! provides encryption and decryption capabilities for ESP chips using the AES
//! algorithm. We currently support the following AES encryption modes:
//! * AES-128
//! * AES-192
//! * AES-256
//!
//! ## Example
//! ### Initialization
//! ```no_run
//! let mut aes = Aes::new(peripherals.AES, &mut system.peripheral_clock_control);
//! ```
//! ### Creating key and block Buffer
//! ```no_run
//! let keytext = "SUp4SeCp@sSw0rd".as_bytes();
//! let plaintext = "message".as_bytes();
//!
//! // create an array with aes128 key size
//! let mut keybuf = [0_u8; 16];
//! keybuf[..keytext.len()].copy_from_slice(keytext);
//!
//! // create an array with aes block size
//! let mut block_buf = [0_u8; 16];
//! block_buf[..plaintext.len()].copy_from_slice(plaintext);
//! ```
//!
//! ### Encrypting and Decrypting (using hardware)
//! ```no_run
//! let key = Key::<Aes128>::from(&keybuf);
//!
//! let mut cipher = Cipher::new(&mut aes, &key);
//! let mut block = block_buf.clone();
//! cipher.encrypt_block(&mut block);
//!
//! let hw_encrypted = block.clone();
//! cipher.decrypt_block(&mut block);
//! let hw_decrypted = block;
//! ```
//!
//! ### Encrypting and Decrypting (using software)
//! ```no_run
//! let key = GenericArray::from(keybuf);
//!
//! let mut block = GenericArray::from(block_buf);
//! let cipher = Aes128SW::new(&key);
//! cipher.encrypt_block(&mut block);
//!
//! let sw_encrypted = block.clone();
//! cipher.decrypt_block(&mut block);
//!
//! let sw_decrypted = block;
//! ```
//!
//! ### Implementation State
//! * DMA mode is currently not supported ⚠️
use core::marker::PhantomData;
use crate::{
peripheral::{Peripheral, PeripheralRef},
peripherals::{
generic::{Readable, Reg, RegisterSpec, Resettable, Writable},
AES,
},
system::PeripheralClockControl,
};
#[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>();
/// AES peripheral container
pub struct Aes<'d> {
aes: PeripheralRef<'d, AES>,
}
impl<'d> Aes<'d> {
pub fn new(
aes: impl Peripheral<P = AES> + 'd,
peripheral_clock_control: &mut PeripheralClockControl,
) -> Self {
crate::into_ref!(aes);
let mut ret = Self { aes: aes };
ret.init(peripheral_clock_control);
ret
}
fn write_to_regset<T>(input: &[u8], n_offset: usize, reg_0: &mut Reg<T>)
where
T: RegisterSpec<Ux = u32> + Resettable + Writable,
{
let chunks = input.chunks_exact(ALIGN_SIZE);
for (offset, chunk) in (0..n_offset).zip(chunks) {
let to_write = u32::from_ne_bytes(chunk.try_into().unwrap());
unsafe {
let p = reg_0.as_ptr().add(offset);
p.write_volatile(to_write);
}
}
}
fn read_from_regset<T>(out_buf: &mut [u8], n_offset: usize, reg_0: &Reg<T>)
where
T: RegisterSpec<Ux = u32> + Readable,
{
let chunks = out_buf.chunks_exact_mut(ALIGN_SIZE);
for (offset, chunk) in (0..n_offset).zip(chunks) {
unsafe {
let p = reg_0.as_ptr().add(offset);
let read_val: [u8; ALIGN_SIZE] = p.read_volatile().to_ne_bytes();
chunk.copy_from_slice(&read_val);
}
}
}
fn write_to_register<T>(reg: &mut Reg<T>, data: u32)
where
T: RegisterSpec<Ux = u32> + Resettable + Writable,
{
reg.write(|w| unsafe { w.bits(data) });
}
}
mod sealed {
/// Specifications for AES flavours
pub trait AesFlavour {
type KeyType<'b>;
const ENCRYPT_MODE: u32;
const DECRYPT_MODE: u32;
}
}
use sealed::AesFlavour;
/// Marker type for AES-128
pub struct Aes128;
/// Marker type for AES-192
#[cfg(any(esp32, esp32s2))]
pub struct Aes192;
/// Marker type for AES-256
pub struct Aes256;
/// Block cipher
pub struct Cipher<'a, 'd, T: AesFlavour> {
aes: &'a mut Aes<'d>,
phantom: PhantomData<T>,
}
impl<'a, 'd, T: AesFlavour> Cipher<'a, 'd, T> {
/// Creates and returns a new cipher
pub fn new(aes: &'a mut Aes<'d>, key: &Key<T>) -> Self {
aes.write_key(key.key);
Self {
aes,
phantom: PhantomData,
}
}
/// Encrypts the given buffer
pub fn encrypt_block(&mut self, block: &mut [u8; 16]) {
self.set_mode(T::ENCRYPT_MODE);
self.set_block(block);
self.start();
while !(self.is_idle()) {}
self.get_block(block);
}
/// Decrypts the given buffer
pub fn decrypt_block(&mut self, block: &mut [u8; 16]) {
self.set_mode(T::DECRYPT_MODE);
self.set_block(block);
self.start();
while !(self.is_idle()) {}
self.get_block(block);
}
fn set_mode(&mut self, mode: u32) {
self.aes.write_mode(mode);
}
fn is_idle(&mut self) -> bool {
self.aes.read_idle()
}
fn set_block(&mut self, block: &[u8; 16]) {
self.aes.write_block(block);
}
fn get_block(&self, block: &mut [u8; 16]) {
self.aes.read_block(block);
}
fn start(&mut self) {
self.aes.write_start();
}
}
/// Aes cipher key
///
/// A `Key` can be initialized from an array of appropriate length:
///
/// ``` plain
/// let key = Key::<Aes128>::from(&[0_u8;16]);
/// let key = Key::<Aes192>::from(&[0_u8;24]);
/// let key = Key::<Aes256>::from(&[0_u8;32]);
/// ```
pub struct Key<'b, T: AesFlavour> {
key: &'b [u8],
phantom: PhantomData<T>,
}
impl<'b, T, const N: usize> From<&'b [u8; N]> for Key<'b, T>
where
T: AesFlavour<KeyType<'b> = &'b [u8; N]>,
{
fn from(value: T::KeyType<'b>) -> Self {
Key {
key: value,
phantom: PhantomData,
}
}
}
/// State matrix endianness
#[cfg(any(esp32, esp32s2))]
pub enum Endianness {
BigEndian = 1,
LittleEndian = 0,
}