From 79e5e8b052b56f8c6fc07d8407fcfc3aaf39bab3 Mon Sep 17 00:00:00 2001 From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:11:54 -0500 Subject: [PATCH] Add cryp configuration. --- embassy-stm32/src/cryp/mod.rs | 227 ++++++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + 2 files changed, 229 insertions(+) create mode 100644 embassy-stm32/src/cryp/mod.rs diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs new file mode 100644 index 000000000..dedc6ddc5 --- /dev/null +++ b/embassy-stm32/src/cryp/mod.rs @@ -0,0 +1,227 @@ +use embassy_hal_internal::{into_ref, PeripheralRef}; +use pac::cryp::Init; + +use crate::pac; +use crate::peripherals::CRYP; +use crate::rcc::sealed::RccPeripheral; +use crate::{interrupt, peripherals, Peripheral}; + +pub struct Context<'c> { + key: &'c [u8], +} + +#[derive(PartialEq)] +pub enum Algorithm { + AES, + DES, + TDES, +} + +#[derive(PartialEq)] +pub enum Mode { + ECB, + CBC, + CTR, + GCM, + GMAC, + CCM, +} + +#[derive(PartialEq)] +pub enum Direction { + Encrypt, + Decrypt, +} + +/// Crypto Accelerator Driver +pub struct Cryp<'d, T: Instance, In, Out> { + _peripheral: PeripheralRef<'d, T>, + indma: PeripheralRef<'d, In>, + outdma: PeripheralRef<'d, Out>, +} + +type InitVector<'v> = Option<&'v [u8]>; + +impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> { + /// Create a new CRYP driver. + pub fn new( + peri: impl Peripheral

+ 'd, + indma: impl Peripheral

+ 'd, + outdma: impl Peripheral

+ 'd, + ) -> Self { + CRYP::enable_and_reset(); + into_ref!(peri, indma, outdma); + let instance = Self { + _peripheral: peri, + indma: indma, + outdma: outdma, + }; + instance + } + + /// Start a new cipher operation. + /// Key size must be 128, 192, or 256 bits. + pub fn start(key: &[u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context { + T::regs().cr().modify(|w| w.set_crypen(false)); + + let keylen = key.len() * 8; + let ivlen; + if let Some(iv) = iv { + ivlen = iv.len() * 8; + } else { + ivlen = 0; + } + + // Checks for correctness + if algo == Algorithm::AES { + match keylen { + 128 => T::regs().cr().write(|w| w.set_keysize(0)), + 192 => T::regs().cr().write(|w| w.set_keysize(1)), + 256 => T::regs().cr().write(|w| w.set_keysize(2)), + _ => panic!("Key length must be 128, 192, or 256 bits."), + } + + if (mode == Mode::GCM) && (ivlen != 96) { + panic!("IV length must be 96 bits for GCM."); + } else if (mode == Mode::CBC) && (ivlen != 128) { + panic!("IV length must be 128 bits for CBC."); + } else if (mode == Mode::CCM) && (ivlen != 128) { + panic!("IV length must be 128 bits for CCM."); + } else if (mode == Mode::CTR) && (ivlen != 64) { + panic!("IV length must be 64 bits for CTR."); + } else if (mode == Mode::GCM) && (ivlen != 96) { + panic!("IV length must be 96 bits for GCM."); + } else if (mode == Mode::GMAC) && (ivlen != 96) { + panic!("IV length must be 96 bits for GMAC."); + } + } + + // Load the key into the registers. + let mut keyidx = 0; + let mut keyword: [u8; 4] = [0; 4]; + if keylen > 192 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 128 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword)); + } + if keylen > 64 { + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword)); + } + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + keyidx += 4; + T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword)); + keyword.copy_from_slice(&key[keyidx..keyidx + 4]); + T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword)); + + // Set data type to 8-bit. This will match software implementations. + T::regs().cr().modify(|w| w.set_datatype(2)); + + if algo == Algorithm::AES { + if (mode == Mode::ECB) || (mode == Mode::CBC) { + T::regs().cr().modify(|w| w.set_algomode0(7)); + T::regs().cr().modify(|w| w.set_crypen(true)); + while T::regs().sr().read().busy() {} + } + + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)), + Mode::CTR => T::regs().cr().modify(|w| w.set_algomode0(6)), + Mode::GCM => T::regs().cr().modify(|w| w.set_algomode0(8)), + Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(8)), + Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(9)), + } + } else if algo == Algorithm::DES { + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(2)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(3)), + _ => panic!("Only ECB and CBC modes are valid for DES."), + } + } else if algo == Algorithm::TDES { + match mode { + Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(0)), + Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(1)), + _ => panic!("Only ECB and CBC modes are valid for TDES."), + } + } + + // Set encrypt/decrypt + if dir == Direction::Encrypt { + T::regs().cr().modify(|w| w.set_algodir(false)); + } else { + T::regs().cr().modify(|w| w.set_algodir(true)); + } + + // Load the IV into the registers. + if let Some(iv) = iv { + let mut iv_idx = 0; + let mut iv_word: [u8; 4] = [0; 4]; + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + if iv.len() >= 12 { + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + } + if iv.len() >= 16 { + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); + } + } + + // Flush in/out FIFOs + T::regs().cr().modify(|w| w.fflush()); + + let ctx = Context { key: key }; + + ctx + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Instance { + fn regs() -> pac::cryp::Cryp; + } +} + +/// RNG instance trait. +pub trait Instance: sealed::Instance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { + /// Interrupt for this RNG instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +foreach_interrupt!( + ($inst:ident, rng, CRYP, GLOBAL, $irq:ident) => { + impl Instance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + + impl sealed::Instance for peripherals::$inst { + fn regs() -> crate::pac::cryp::Cryp { + crate::pac::$inst + } + } + }; +); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index cd1ede0fa..6859eef6c 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -34,6 +34,8 @@ pub mod adc; pub mod can; #[cfg(crc)] pub mod crc; +#[cfg(cryp)] +pub mod cryp; #[cfg(dac)] pub mod dac; #[cfg(dcmi)]