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 01/29] 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<P = T> + 'd,
+        indma: impl Peripheral<P = In> + 'd,
+        outdma: impl Peripheral<P = Out> + '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<P = Self> + 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)]

From a0a8a4ec864763948d4a965ccf8ec11ca91cb15f Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Wed, 14 Feb 2024 20:24:52 -0500
Subject: [PATCH 02/29] Support CBC, ECB, CTR modes.

---
 embassy-stm32/src/cryp/mod.rs | 350 +++++++++++++++++++++++++++-------
 1 file changed, 282 insertions(+), 68 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index dedc6ddc5..f266313c1 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1,23 +1,34 @@
 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};
+use crate::{interrupt, Peripheral};
+
+const DES_BLOCK_SIZE: usize = 8; // 64 bits
+const AES_BLOCK_SIZE: usize = 16; // 128 bits
 
 pub struct Context<'c> {
+    algo: Algorithm,
+    mode: Mode,
+    dir: Direction,
+    last_block_processed: bool,
+    aad_complete: bool,
+    cr: u32,
+    iv: [u32; 4],
     key: &'c [u8],
+    csgcmccm: [u32; 8],
+    csgcm: [u32; 8],
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 pub enum Algorithm {
     AES,
     DES,
     TDES,
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 pub enum Mode {
     ECB,
     CBC,
@@ -27,53 +38,55 @@ pub enum Mode {
     CCM,
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 pub enum Direction {
     Encrypt,
     Decrypt,
 }
 
 /// Crypto Accelerator Driver
-pub struct Cryp<'d, T: Instance, In, Out> {
+pub struct Cryp<'d, T: Instance> {
     _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> {
+impl<'d, T: Instance> Cryp<'d, T> {
     /// Create a new CRYP driver.
-    pub fn new(
-        peri: impl Peripheral<P = T> + 'd,
-        indma: impl Peripheral<P = In> + 'd,
-        outdma: impl Peripheral<P = Out> + 'd,
-    ) -> Self {
+    pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
         CRYP::enable_and_reset();
-        into_ref!(peri, indma, outdma);
-        let instance = Self {
-            _peripheral: peri,
-            indma: indma,
-            outdma: outdma,
-        };
+        into_ref!(peri);
+        let instance = Self { _peripheral: peri };
         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));
+    pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> {
+        let mut ctx = Context {
+            algo,
+            mode,
+            dir,
+            last_block_processed: false,
+            cr: 0,
+            iv: [0; 4],
+            key,
+            csgcmccm: [0; 8],
+            csgcm: [0; 8],
+            aad_complete: false,
+        };
 
-        let keylen = key.len() * 8;
-        let ivlen;
-        if let Some(iv) = iv {
-            ivlen = iv.len() * 8;
-        } else {
-            ivlen = 0;
-        }
+        T::regs().cr().modify(|w| w.set_crypen(false));
 
         // Checks for correctness
         if algo == Algorithm::AES {
+            let keylen = key.len() * 8;
+            let ivlen;
+            if let Some(iv) = iv {
+                ivlen = iv.len() * 8;
+            } else {
+                ivlen = 0;
+            }
             match keylen {
                 128 => T::regs().cr().write(|w| w.set_keysize(0)),
                 192 => T::regs().cr().write(|w| w.set_keysize(1)),
@@ -96,49 +109,14 @@ impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> {
             }
         }
 
-        // 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));
+        self.load_key(key);
 
         // 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() {}
-            }
+        self.prepare_key(&ctx);
 
+        if algo == Algorithm::AES {
             match mode {
                 Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)),
                 Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)),
@@ -192,10 +170,246 @@ impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> {
         // Flush in/out FIFOs
         T::regs().cr().modify(|w| w.fflush());
 
-        let ctx = Context { key: key };
+        if mode == Mode::GCM {
+            // GCM init phase
+            T::regs().cr().modify(|w| w.set_gcm_ccmph(0));
+            T::regs().cr().modify(|w| w.set_crypen(true));
+            while T::regs().cr().read().crypen() {}
+        }
+
+        self.store_context(&mut ctx);
 
         ctx
     }
+
+    // pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8]) {
+    //     if ctx.aad_complete {
+    //         panic!("Cannot update AAD after calling 'update'!")
+    //     }
+    //     if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) {
+    //         panic!("Associated data only valid for GCM, GMAC, and CCM modes.")
+    //     }
+
+    //     let mut header_size = 0;
+    //     let mut header: [u8;]
+
+    //     if aad.len() < 65280 {
+
+    //     }
+
+    //     // GCM header phase
+    //     T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
+    //     T::regs().cr().modify(|w| w.set_crypen(true));
+    // }
+
+    pub fn update_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) {
+        self.load_context(ctx);
+
+        ctx.aad_complete = true;
+        if last_block {
+            ctx.last_block_processed = true;
+        }
+
+        let block_size;
+        if ctx.algo == Algorithm::DES {
+            block_size = 8;
+        } else {
+            block_size = 16;
+        }
+        let last_block_remainder = input.len() % block_size;
+
+        // Perform checks for correctness.
+
+        if ctx.mode == Mode::GMAC {
+            panic!("GMAC works on header data only. Do not call this function for GMAC.");
+        }
+        if ctx.last_block_processed {
+            panic!("The last block has already been processed!");
+        }
+        if input.len() != output.len() {
+            panic!("Output buffer length must match input length.");
+        }
+        if !last_block {
+            if last_block_remainder != 0 {
+                panic!("Input length must be a multiple of {block_size} bytes.");
+            }
+        }
+        if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
+            if last_block_remainder != 0 {
+                panic!("Input must be a multiple of {block_size} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.");
+            }
+        }
+
+        // Load data into core, block by block.
+        let num_full_blocks = input.len() / block_size;
+        for block in 0..num_full_blocks {
+            let mut index = block * block_size;
+            let end_index = index + block_size;
+            // Write block in
+            while index < end_index {
+                let mut in_word: [u8; 4] = [0; 4];
+                in_word.copy_from_slice(&input[index..index + 4]);
+                T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                index += 4;
+            }
+            let mut index = block * block_size;
+            let end_index = index + block_size;
+            // Block until there is output to read.
+            while !T::regs().sr().read().ofne() {}
+            // Read block out
+            while index < end_index {
+                let out_word: u32 = T::regs().dout().read();
+                output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
+                index += 4;
+            }
+        }
+
+        // Handle the final block, which is incomplete.
+        if last_block_remainder > 0 {
+            if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
+                //Handle special GCM partial block process.
+                T::regs().cr().modify(|w| w.set_crypen(false));
+                T::regs().cr().write(|w| w.set_algomode0(6));
+                let iv1r = T::regs().csgcmccmr(7).read() - 1;
+                T::regs().init(1).ivrr().write_value(iv1r);
+                T::regs().cr().modify(|w| w.set_crypen(true));
+            }
+
+            let mut intermediate_data: [u8; 16] = [0; 16];
+            let mut last_block: [u8; 16] = [0; 16];
+            last_block.copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
+            let mut index = 0;
+            let end_index = block_size;
+            // Write block in
+            while index < end_index {
+                let mut in_word: [u8; 4] = [0; 4];
+                in_word.copy_from_slice(&last_block[index..index + 4]);
+                T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                index += 4;
+            }
+            let mut index = 0;
+            let end_index = block_size;
+            // Block until there is output to read.
+            while !T::regs().sr().read().ofne() {}
+            // Read block out
+            while index < end_index {
+                let out_word: u32 = T::regs().dout().read();
+                intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
+                index += 4;
+            }
+
+            // Handle the last block depending on mode.
+            output[output.len() - last_block_remainder..output.len()]
+                .copy_from_slice(&intermediate_data[0..last_block_remainder]);
+
+            if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
+                //Handle special GCM partial block process.
+                T::regs().cr().modify(|w| w.set_crypen(false));
+                T::regs().cr().write(|w| w.set_algomode0(8));
+                T::regs().init(1).ivrr().write_value(2);
+                T::regs().cr().modify(|w| w.set_crypen(true));
+                T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
+                let mut index = 0;
+                let end_index = block_size;
+                while index < end_index {
+                    let mut in_word: [u8; 4] = [0; 4];
+                    in_word.copy_from_slice(&intermediate_data[index..index + 4]);
+                    T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                    index += 4;
+                }
+                for _ in 0..4 {
+                    T::regs().dout().read();
+                }
+            }
+        }
+    }
+
+    fn prepare_key(&self, ctx: &Context) {
+        if ctx.algo == Algorithm::AES {
+            if (ctx.mode == Mode::ECB) || (ctx.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() {}
+            }
+        }
+    }
+
+    fn load_key(&self, key: &[u8]) {
+        // Load the key into the registers.
+        let mut keyidx = 0;
+        let mut keyword: [u8; 4] = [0; 4];
+        let keylen = key.len() * 8;
+        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));
+    }
+
+    fn store_context(&self, ctx: &mut Context) {
+        // Wait for data block processing to finish.
+        while !T::regs().sr().read().ifem() {}
+        while T::regs().sr().read().ofne() {}
+        while T::regs().sr().read().busy() {}
+
+        // Disable crypto processor.
+        T::regs().cr().modify(|w| w.set_crypen(false));
+
+        // Save the peripheral state.
+        ctx.cr = T::regs().cr().read().0;
+        ctx.iv[0] = T::regs().init(0).ivlr().read();
+        ctx.iv[1] = T::regs().init(0).ivrr().read();
+        ctx.iv[2] = T::regs().init(1).ivlr().read();
+        ctx.iv[3] = T::regs().init(1).ivrr().read();
+        for i in 0..8 {
+            ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read();
+            ctx.csgcm[i] = T::regs().csgcmr(i).read();
+        }
+    }
+
+    fn load_context(&self, ctx: &Context) {
+        // Reload state registers.
+        T::regs().cr().write(|w| w.0 = ctx.cr);
+        T::regs().init(0).ivlr().write_value(ctx.iv[0]);
+        T::regs().init(0).ivrr().write_value(ctx.iv[1]);
+        T::regs().init(1).ivlr().write_value(ctx.iv[2]);
+        T::regs().init(1).ivrr().write_value(ctx.iv[3]);
+        for i in 0..8 {
+            T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
+            T::regs().csgcmr(i).write_value(ctx.csgcm[i]);
+        }
+        self.load_key(ctx.key);
+
+        // Prepare key if applicable.
+        self.prepare_key(ctx);
+
+        // Enable crypto processor.
+        T::regs().cr().modify(|w| w.set_crypen(true));
+    }
 }
 
 pub(crate) mod sealed {

From 72e4cacd914195352c9760856e8b8e40a7851752 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Wed, 14 Feb 2024 22:11:38 -0500
Subject: [PATCH 03/29] CBC and ECB AES modes functional.

---
 embassy-stm32/src/cryp/mod.rs | 39 +++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index f266313c1..b368930da 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -3,7 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
 use crate::pac;
 use crate::peripherals::CRYP;
 use crate::rcc::sealed::RccPeripheral;
-use crate::{interrupt, Peripheral};
+use crate::{interrupt, peripherals, Peripheral};
 
 const DES_BLOCK_SIZE: usize = 8; // 64 bits
 const AES_BLOCK_SIZE: usize = 16; // 128 bits
@@ -49,7 +49,7 @@ pub struct Cryp<'d, T: Instance> {
     _peripheral: PeripheralRef<'d, T>,
 }
 
-type InitVector<'v> = Option<&'v [u8]>;
+pub type InitVector<'v> = Option<&'v [u8]>;
 
 impl<'d, T: Instance> Cryp<'d, T> {
     /// Create a new CRYP driver.
@@ -88,9 +88,9 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 ivlen = 0;
             }
             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)),
+                128 => T::regs().cr().modify(|w| w.set_keysize(0)),
+                192 => T::regs().cr().modify(|w| w.set_keysize(1)),
+                256 => T::regs().cr().modify(|w| w.set_keysize(2)),
                 _ => panic!("Key length must be 128, 192, or 256 bits."),
             }
 
@@ -155,13 +155,13 @@ impl<'d, T: Instance> Cryp<'d, T> {
             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;
+            T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
             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;
+                T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
             }
             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));
             }
@@ -206,9 +206,6 @@ impl<'d, T: Instance> Cryp<'d, T> {
         self.load_context(ctx);
 
         ctx.aad_complete = true;
-        if last_block {
-            ctx.last_block_processed = true;
-        }
 
         let block_size;
         if ctx.algo == Algorithm::DES {
@@ -231,15 +228,19 @@ impl<'d, T: Instance> Cryp<'d, T> {
         }
         if !last_block {
             if last_block_remainder != 0 {
-                panic!("Input length must be a multiple of {block_size} bytes.");
+                panic!("Input length must be a multiple of {} bytes.", block_size);
             }
         }
         if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
             if last_block_remainder != 0 {
-                panic!("Input must be a multiple of {block_size} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.");
+                panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", block_size);
             }
         }
 
+        if last_block {
+            ctx.last_block_processed = true;
+        }
+
         // Load data into core, block by block.
         let num_full_blocks = input.len() / block_size;
         for block in 0..num_full_blocks {
@@ -277,7 +278,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
             let mut intermediate_data: [u8; 16] = [0; 16];
             let mut last_block: [u8; 16] = [0; 16];
-            last_block.copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
+            last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
             let mut index = 0;
             let end_index = block_size;
             // Write block in
@@ -299,7 +300,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
             }
 
             // Handle the last block depending on mode.
-            output[output.len() - last_block_remainder..output.len()]
+            let output_len = output.len();
+            output[output_len - last_block_remainder..output_len]
                 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
 
             if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
@@ -325,7 +327,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
     }
 
     fn prepare_key(&self, ctx: &Context) {
-        if ctx.algo == Algorithm::AES {
+        if ctx.algo == Algorithm::AES && ctx.dir == Direction::Decrypt {
             if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
                 T::regs().cr().modify(|w| w.set_algomode0(7));
                 T::regs().cr().modify(|w| w.set_crypen(true));
@@ -406,6 +408,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
         // Prepare key if applicable.
         self.prepare_key(ctx);
+        T::regs().cr().write(|w| w.0 = ctx.cr);
 
         // Enable crypto processor.
         T::regs().cr().modify(|w| w.set_crypen(true));
@@ -420,14 +423,14 @@ pub(crate) mod sealed {
     }
 }
 
-/// RNG instance trait.
+/// CRYP instance trait.
 pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
-    /// Interrupt for this RNG instance.
+    /// Interrupt for this CRYP instance.
     type Interrupt: interrupt::typelevel::Interrupt;
 }
 
 foreach_interrupt!(
-    ($inst:ident, rng, CRYP, GLOBAL, $irq:ident) => {
+    ($inst:ident, cryp, CRYP, GLOBAL, $irq:ident) => {
         impl Instance for peripherals::$inst {
             type Interrupt = crate::interrupt::typelevel::$irq;
         }

From 565acdf24301a72fe084aa18b7c55a6110609374 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Wed, 14 Feb 2024 22:38:05 -0500
Subject: [PATCH 04/29] CTR mode functional.

---
 embassy-stm32/src/cryp/mod.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index b368930da..4db95d55c 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -100,8 +100,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 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::CTR) && (ivlen != 128) {
+                panic!("IV length must be 128 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) {

From c2b03eff62245bd325a781e1e260c150e0a5040c Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Fri, 16 Feb 2024 13:15:14 -0500
Subject: [PATCH 05/29] GCM mode functional.

---
 embassy-stm32/src/cryp/mod.rs | 244 +++++++++++++++++++++++++++-------
 1 file changed, 198 insertions(+), 46 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 4db95d55c..447bcf2f8 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1,3 +1,4 @@
+//! Crypto Accelerator (CRYP)
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
 use crate::pac;
@@ -8,6 +9,8 @@ use crate::{interrupt, peripherals, Peripheral};
 const DES_BLOCK_SIZE: usize = 8; // 64 bits
 const AES_BLOCK_SIZE: usize = 16; // 128 bits
 
+/// Holds the state information for a cipher operation.
+/// Allows suspending/resuming of cipher operations.
 pub struct Context<'c> {
     algo: Algorithm,
     mode: Mode,
@@ -19,28 +22,44 @@ pub struct Context<'c> {
     key: &'c [u8],
     csgcmccm: [u32; 8],
     csgcm: [u32; 8],
+    header_len: u64,
+    payload_len: u64,
 }
 
+/// Selects the encryption algorithm.
 #[derive(PartialEq, Clone, Copy)]
 pub enum Algorithm {
+    /// Advanced Encryption Standard
     AES,
+    /// Data Encryption Standard
     DES,
+    /// Triple-DES
     TDES,
 }
 
+/// Selects the cipher mode.
 #[derive(PartialEq, Clone, Copy)]
 pub enum Mode {
+    /// Electronic Codebook
     ECB,
+    /// Cipher Block Chaining
     CBC,
+    /// Counter Mode
     CTR,
+    /// Galois Counter Mode
     GCM,
+    /// Galois Message Authentication Code
     GMAC,
+    /// Counter with CBC-MAC
     CCM,
 }
 
+/// Selects whether the crypto processor operates in encryption or decryption mode.
 #[derive(PartialEq, Clone, Copy)]
 pub enum Direction {
+    /// Encryption mode
     Encrypt,
+    /// Decryption mode
     Decrypt,
 }
 
@@ -49,6 +68,8 @@ pub struct Cryp<'d, T: Instance> {
     _peripheral: PeripheralRef<'d, T>,
 }
 
+/// Initialization vector of arbitrary length.
+/// When an initialization vector is not needed, `None` may be supplied.
 pub type InitVector<'v> = Option<&'v [u8]>;
 
 impl<'d, T: Instance> Cryp<'d, T> {
@@ -62,6 +83,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
     /// Start a new cipher operation.
     /// Key size must be 128, 192, or 256 bits.
+    /// Initialization vector must only be supplied if necessary.
+    /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode.
     pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> {
         let mut ctx = Context {
             algo,
@@ -74,6 +97,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
             csgcmccm: [0; 8],
             csgcm: [0; 8],
             aad_complete: false,
+            header_len: 0,
+            payload_len: 0,
         };
 
         T::regs().cr().modify(|w| w.set_crypen(false));
@@ -102,8 +127,6 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 panic!("IV length must be 128 bits for CCM.");
             } else if (mode == Mode::CTR) && (ivlen != 128) {
                 panic!("IV length must be 128 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.");
             }
@@ -121,17 +144,27 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 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)),
+                Mode::GCM => T::regs().cr().modify(|w| w.set_algomode0(0)),
+                Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(0)),
+                Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(1)),
+            }
+            match mode {
+                Mode::ECB => T::regs().cr().modify(|w| w.set_algomode3(false)),
+                Mode::CBC => T::regs().cr().modify(|w| w.set_algomode3(false)),
+                Mode::CTR => T::regs().cr().modify(|w| w.set_algomode3(false)),
+                Mode::GCM => T::regs().cr().modify(|w| w.set_algomode3(true)),
+                Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode3(true)),
+                Mode::CCM => T::regs().cr().modify(|w| w.set_algomode3(true)),
             }
         } else if algo == Algorithm::DES {
+            T::regs().cr().modify(|w| w.set_algomode3(false));
             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 {
+            T::regs().cr().modify(|w| w.set_algomode3(false));
             match mode {
                 Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(0)),
                 Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(1)),
@@ -148,23 +181,26 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
         // Load the IV into the registers.
         if let Some(iv) = iv {
+            let mut full_iv: [u8; 16] = [0; 16];
+            full_iv[0..iv.len()].copy_from_slice(iv);
+
+            if (mode == Mode::GCM) || (mode == Mode::GMAC) {
+                full_iv[15] = 2;
+            }
+
             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_word.copy_from_slice(&full_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_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
             iv_idx += 4;
             T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
-            if iv.len() >= 12 {
-                iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]);
-                iv_idx += 4;
-                T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
-            }
-            if iv.len() >= 16 {
-                iv_word.copy_from_slice(&iv[iv_idx..iv_idx + 4]);
-                T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
-            }
+            iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
+            iv_idx += 4;
+            T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
+            iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
+            T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
         }
 
         // Flush in/out FIFOs
@@ -182,41 +218,116 @@ impl<'d, T: Instance> Cryp<'d, T> {
         ctx
     }
 
-    // pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8]) {
-    //     if ctx.aad_complete {
-    //         panic!("Cannot update AAD after calling 'update'!")
-    //     }
-    //     if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) {
-    //         panic!("Associated data only valid for GCM, GMAC, and CCM modes.")
-    //     }
-
-    //     let mut header_size = 0;
-    //     let mut header: [u8;]
-
-    //     if aad.len() < 65280 {
-
-    //     }
-
-    //     // GCM header phase
-    //     T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
-    //     T::regs().cr().modify(|w| w.set_crypen(true));
-    // }
-
-    pub fn update_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) {
+    /// Controls the header phase of cipher processing.
+    /// This function is only valid for GCM, CCM, and GMAC modes.
+    /// It only needs to be called if using one of these modes and there is associated data.
+    /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`.
+    /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block.
+    /// When supplying the last block of AAD, `last_aad_block` must be `true`.
+    pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8], last_aad_block: bool) {
         self.load_context(ctx);
 
-        ctx.aad_complete = true;
-
         let block_size;
         if ctx.algo == Algorithm::DES {
-            block_size = 8;
+            block_size = DES_BLOCK_SIZE;
         } else {
-            block_size = 16;
+            block_size = AES_BLOCK_SIZE;
+        }
+        let last_block_remainder = aad.len() % block_size;
+
+        // Perform checks for correctness.
+        if ctx.aad_complete {
+            panic!("Cannot update AAD after calling 'update'!")
+        }
+        if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) {
+            panic!("Associated data only valid for GCM, GMAC, and CCM modes.")
+        }
+        if !last_aad_block {
+            if last_block_remainder != 0 {
+                panic!("Input length must be a multiple of {} bytes.", block_size);
+            }
+        }
+
+        ctx.header_len += aad.len() as u64;
+
+        // GCM header phase
+        T::regs().cr().modify(|w| w.set_crypen(false));
+        T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
+        T::regs().cr().modify(|w| w.set_crypen(true));
+
+        // Load data into core, block by block.
+        let num_full_blocks = aad.len() / block_size;
+        for block in 0..num_full_blocks {
+            let mut index = block * block_size;
+            let end_index = index + block_size;
+            // Write block in
+            while index < end_index {
+                let mut in_word: [u8; 4] = [0; 4];
+                in_word.copy_from_slice(&aad[index..index + 4]);
+                T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                index += 4;
+            }
+            // Block until input FIFO is empty.
+            while !T::regs().sr().read().ifem() {}
+        }
+
+        // Handle the final block, which is incomplete.
+        if last_block_remainder > 0 {
+            let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
+            last_block[..last_block_remainder].copy_from_slice(&aad[aad.len() - last_block_remainder..aad.len()]);
+            let mut index = 0;
+            let end_index = block_size;
+            // Write block in
+            while index < end_index {
+                let mut in_word: [u8; 4] = [0; 4];
+                in_word.copy_from_slice(&last_block[index..index + 4]);
+                T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                index += 4;
+            }
+            // Block until input FIFO is empty
+            while !T::regs().sr().read().ifem() {}
+        }
+
+        if last_aad_block {
+            // Switch to payload phase.
+            ctx.aad_complete = true;
+            T::regs().cr().modify(|w| w.set_crypen(false));
+            T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
+            T::regs().cr().modify(|w| w.fflush());
+        }
+
+        self.store_context(ctx);
+    }
+
+    /// Performs encryption/decryption on the provided context.
+    /// The context determines algorithm, mode, and state of the crypto accelerator.
+    /// When the last piece of data is supplied, `last_block` should be `true`.
+    /// This function panics under various mismatches of parameters.
+    /// Input and output buffer lengths must match.
+    /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
+    /// Padding or ciphertext stealing must be managed by the application for these modes.
+    /// Data must also be a multiple of block size unless `last_block` is `true`.
+    pub fn payload_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) {
+        self.load_context(ctx);
+
+        let block_size;
+        if ctx.algo == Algorithm::DES {
+            block_size = DES_BLOCK_SIZE;
+        } else {
+            block_size = AES_BLOCK_SIZE;
         }
         let last_block_remainder = input.len() % block_size;
 
         // Perform checks for correctness.
-
+        if !ctx.aad_complete && ctx.header_len > 0 {
+            panic!("Additional associated data must be processed first!");
+        } else if !ctx.aad_complete {
+            ctx.aad_complete = true;
+            T::regs().cr().modify(|w| w.set_crypen(false));
+            T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
+            T::regs().cr().modify(|w| w.fflush());
+            T::regs().cr().modify(|w| w.set_crypen(true));
+        }
         if ctx.mode == Mode::GMAC {
             panic!("GMAC works on header data only. Do not call this function for GMAC.");
         }
@@ -270,14 +381,15 @@ impl<'d, T: Instance> Cryp<'d, T> {
             if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
                 //Handle special GCM partial block process.
                 T::regs().cr().modify(|w| w.set_crypen(false));
-                T::regs().cr().write(|w| w.set_algomode0(6));
+                T::regs().cr().modify(|w| w.set_algomode3(false));
+                T::regs().cr().modify(|w| w.set_algomode0(6));
                 let iv1r = T::regs().csgcmccmr(7).read() - 1;
                 T::regs().init(1).ivrr().write_value(iv1r);
                 T::regs().cr().modify(|w| w.set_crypen(true));
             }
 
-            let mut intermediate_data: [u8; 16] = [0; 16];
-            let mut last_block: [u8; 16] = [0; 16];
+            let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
+            let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
             last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
             let mut index = 0;
             let end_index = block_size;
@@ -307,7 +419,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
             if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
                 //Handle special GCM partial block process.
                 T::regs().cr().modify(|w| w.set_crypen(false));
-                T::regs().cr().write(|w| w.set_algomode0(8));
+                T::regs().cr().write(|w| w.set_algomode3(true));
+                T::regs().cr().write(|w| w.set_algomode0(0));
                 T::regs().init(1).ivrr().write_value(2);
                 T::regs().cr().modify(|w| w.set_crypen(true));
                 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
@@ -324,12 +437,51 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 }
             }
         }
+
+        ctx.payload_len += input.len() as u64;
+    }
+
+    /// This function only needs to be called for GCM, CCM, and GMAC modes to
+    /// generate an authentication tag. Calling this function on any other mode
+    /// does nothing except consumes the context. A buffer for the authentication
+    /// tag must be supplied.
+    pub fn finish_blocking(&self, mut ctx: Context, tag: &mut [u8; 16]) {
+        // Just consume the context if called for any other mode.
+        if (ctx.mode != Mode::GCM) || (ctx.mode != Mode::CCM) || (ctx.mode != Mode::GMAC) {
+            return;
+        }
+
+        self.load_context(&mut ctx);
+
+        T::regs().cr().modify(|w| w.set_crypen(false));
+        T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
+        T::regs().cr().modify(|w| w.set_crypen(true));
+
+        let headerlen1: u32 = (ctx.header_len >> 32) as u32;
+        let headerlen2: u32 = ctx.header_len as u32;
+        let payloadlen1: u32 = (ctx.payload_len >> 32) as u32;
+        let payloadlen2: u32 = ctx.payload_len as u32;
+
+        T::regs().din().write_value(headerlen1.swap_bytes());
+        T::regs().din().write_value(headerlen2.swap_bytes());
+        T::regs().din().write_value(payloadlen1.swap_bytes());
+        T::regs().din().write_value(payloadlen2.swap_bytes());
+
+        while !T::regs().sr().read().ofne() {}
+
+        tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+
+        T::regs().cr().modify(|w| w.set_crypen(false));
     }
 
     fn prepare_key(&self, ctx: &Context) {
         if ctx.algo == Algorithm::AES && ctx.dir == Direction::Decrypt {
             if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
                 T::regs().cr().modify(|w| w.set_algomode0(7));
+                T::regs().cr().modify(|w| w.set_algomode3(false));
                 T::regs().cr().modify(|w| w.set_crypen(true));
                 while T::regs().sr().read().busy() {}
             }

From fec26e896052cc0eac6bfa6415a4ebad5352d1d9 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sun, 18 Feb 2024 21:40:18 -0500
Subject: [PATCH 06/29] Refactored ciphers into traits.

---
 embassy-stm32/src/cryp/mod.rs | 651 ++++++++++++++++++++++------------
 1 file changed, 431 insertions(+), 220 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 447bcf2f8..29c1db12e 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1,4 +1,6 @@
 //! Crypto Accelerator (CRYP)
+use core::marker::PhantomData;
+
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
 use crate::pac;
@@ -9,51 +11,375 @@ use crate::{interrupt, peripherals, Peripheral};
 const DES_BLOCK_SIZE: usize = 8; // 64 bits
 const AES_BLOCK_SIZE: usize = 16; // 128 bits
 
+/// This trait encapsulates all cipher-specific behavior/
+pub trait Cipher<'c> {
+    /// Processing block size. Determined by the processor and the algorithm.
+    const BLOCK_SIZE: usize;
+
+    /// Indicates whether the cipher requires the application to provide padding.
+    /// If `true`, no partial blocks will be accepted (a panic will occur).
+    const REQUIRES_PADDING: bool = false;
+
+    /// Returns the symmetric key.
+    fn key(&self) -> &'c [u8];
+
+    /// Returns the initialization vector.
+    fn iv(&self) -> &[u8];
+
+    /// Sets the processor algorithm mode according to the associated cipher.
+    fn set_algomode(&self, p: &pac::cryp::Cryp);
+
+    /// Performs any key preparation within the processor, if necessary.
+    fn prepare_key(&self, _p: &pac::cryp::Cryp) {}
+
+    /// Performs any cipher-specific initialization.
+    fn init_phase(&self, _p: &pac::cryp::Cryp) {}
+
+    /// Called prior to processing the last data block for cipher-specific operations.
+    fn pre_final_block(&self, _p: &pac::cryp::Cryp) {}
+
+    /// Called after processing the last data block for cipher-specific operations.
+    fn post_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _int_data: &[u8; AES_BLOCK_SIZE]) {}
+}
+
+/// This trait enables restriction of ciphers to specific key sizes.
+pub trait CipherSized {}
+
+/// This trait enables restriction of a header phase to authenticated ciphers only.
+pub trait CipherAuthenticated {}
+
+/// AES-ECB Cipher Mode
+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> {
+    /// Constructs a new AES-ECB cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
+        return Self { key: key, iv: &[0; 0] };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+    const REQUIRES_PADDING: bool = true;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn prepare_key(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(7));
+        p.cr().modify(|w| w.set_algomode3(false));
+        p.cr().modify(|w| w.set_crypen(true));
+        while p.sr().read().busy() {}
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(4));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {}
+impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {}
+impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {}
+
+/// AES-CBC Cipher Mode
+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> {
+    /// Constructs a new AES-CBC cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
+        return Self { key: key, iv: iv };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+    const REQUIRES_PADDING: bool = true;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn prepare_key(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(7));
+        p.cr().modify(|w| w.set_algomode3(false));
+        p.cr().modify(|w| w.set_crypen(true));
+        while p.sr().read().busy() {}
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(5));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {}
+impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {}
+impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {}
+
+/// AES-CTR Cipher Mode
+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> {
+    /// Constructs a new AES-CTR cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 16]) -> Self {
+        return Self { key: key, iv: iv };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(6));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {}
+impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {}
+impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
+
+///AES-GCM Cipher Mode
+pub struct AesGcm<'c, const KEY_SIZE: usize> {
+    iv: [u8; 16],
+    key: &'c [u8; KEY_SIZE],
+}
+
+impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
+    /// Constucts a new AES-GCM cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
+        let mut new_gcm = Self { key: key, iv: [0; 16] };
+        new_gcm.iv[..12].copy_from_slice(iv);
+        new_gcm.iv[15] = 2;
+        new_gcm
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &[u8] {
+        self.iv.as_slice()
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(0));
+        p.cr().modify(|w| w.set_algomode3(true));
+    }
+
+    fn init_phase(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_gcm_ccmph(0));
+        p.cr().modify(|w| w.set_crypen(true));
+        while p.cr().read().crypen() {}
+    }
+
+    fn pre_final_block(&self, p: &pac::cryp::Cryp) {
+        //Handle special GCM partial block process.
+        p.cr().modify(|w| w.set_crypen(false));
+        p.cr().modify(|w| w.set_algomode3(false));
+        p.cr().modify(|w| w.set_algomode0(6));
+        let iv1r = p.csgcmccmr(7).read() - 1;
+        p.init(1).ivrr().write_value(iv1r);
+        p.cr().modify(|w| w.set_crypen(true));
+    }
+
+    fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) {
+        if dir == Direction::Encrypt {
+            //Handle special GCM partial block process.
+            p.cr().modify(|w| w.set_crypen(false));
+            p.cr().write(|w| w.set_algomode3(true));
+            p.cr().write(|w| w.set_algomode0(0));
+            p.init(1).ivrr().write_value(2);
+            p.cr().modify(|w| w.set_crypen(true));
+            p.cr().modify(|w| w.set_gcm_ccmph(3));
+            let mut index = 0;
+            let end_index = Self::BLOCK_SIZE;
+            while index < end_index {
+                let mut in_word: [u8; 4] = [0; 4];
+                in_word.copy_from_slice(&int_data[index..index + 4]);
+                p.din().write_value(u32::from_ne_bytes(in_word));
+                index += 4;
+            }
+            for _ in 0..4 {
+                p.dout().read();
+            }
+        }
+    }
+}
+
+impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
+impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {}
+impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGcm<'c, KEY_SIZE> {}
+
+/// AES-GMAC Cipher Mode
+pub struct AesGmac<'c, const KEY_SIZE: usize> {
+    iv: [u8; 16],
+    key: &'c [u8; KEY_SIZE],
+}
+
+impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
+    /// Constructs a new AES-GMAC cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
+        let mut new_gmac = Self { key: key, iv: [0; 16] };
+        new_gmac.iv[..12].copy_from_slice(iv);
+        new_gmac.iv[15] = 2;
+        new_gmac
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &[u8] {
+        self.iv.as_slice()
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(0));
+        p.cr().modify(|w| w.set_algomode3(true));
+    }
+
+    fn init_phase(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_gcm_ccmph(0));
+        p.cr().modify(|w| w.set_crypen(true));
+        while p.cr().read().crypen() {}
+    }
+
+    fn pre_final_block(&self, p: &pac::cryp::Cryp) {
+        //Handle special GCM partial block process.
+        p.cr().modify(|w| w.set_crypen(false));
+        p.cr().modify(|w| w.set_algomode3(false));
+        p.cr().modify(|w| w.set_algomode0(6));
+        let iv1r = p.csgcmccmr(7).read() - 1;
+        p.init(1).ivrr().write_value(iv1r);
+        p.cr().modify(|w| w.set_crypen(true));
+    }
+
+    fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) {
+        if dir == Direction::Encrypt {
+            //Handle special GCM partial block process.
+            p.cr().modify(|w| w.set_crypen(false));
+            p.cr().write(|w| w.set_algomode3(true));
+            p.cr().write(|w| w.set_algomode0(0));
+            p.init(1).ivrr().write_value(2);
+            p.cr().modify(|w| w.set_crypen(true));
+            p.cr().modify(|w| w.set_gcm_ccmph(3));
+            let mut index = 0;
+            let end_index = Self::BLOCK_SIZE;
+            while index < end_index {
+                let mut in_word: [u8; 4] = [0; 4];
+                in_word.copy_from_slice(&int_data[index..index + 4]);
+                p.din().write_value(u32::from_ne_bytes(in_word));
+                index += 4;
+            }
+            for _ in 0..4 {
+                p.dout().read();
+            }
+        }
+    }
+}
+
+impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
+impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
+impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGmac<'c, KEY_SIZE> {}
+
+// struct AesCcm<'c, const KEY_SIZE: usize> {
+//     iv: &'c [u8],
+//     key: &'c [u8; KEY_SIZE],
+//     aad_len: usize,
+//     payload_len: usize,
+// }
+
+// impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> {
+//     pub fn new(&self, key: &[u8; KEY_SIZE], iv: &[u8], aad_len: usize, payload_len: usize) {
+//         if iv.len() > 13 {
+//             panic!("CCM IV length must be 13 bytes or less.");
+//         }
+//         self.key = key;
+//         self.iv = iv;
+//         self.aad_len = aad_len;
+//         self.payload_len = payload_len;
+//     }
+// }
+
+// impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
+//     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+
+//     fn key(&self) -> &'c [u8] {
+//         self.key
+//     }
+
+//     fn iv(&self) -> &'c [u8] {
+//         self.iv
+//     }
+
+//     fn set_algomode(&self, p: &pac::cryp::Cryp) {
+//         p.cr().modify(|w| w.set_algomode0(1));
+//         p.cr().modify(|w| w.set_algomode3(true));
+//     }
+
+//     fn init_phase(&self, p: &pac::cryp::Cryp) {
+//         todo!();
+//     }
+// }
+
+// impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {}
+// impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {}
+// impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {}
+
 /// Holds the state information for a cipher operation.
 /// Allows suspending/resuming of cipher operations.
-pub struct Context<'c> {
-    algo: Algorithm,
-    mode: Mode,
+pub struct Context<'c, C: Cipher<'c> + CipherSized> {
+    phantom_data: PhantomData<&'c C>,
+    cipher: &'c C,
     dir: Direction,
     last_block_processed: bool,
     aad_complete: bool,
     cr: u32,
     iv: [u32; 4],
-    key: &'c [u8],
     csgcmccm: [u32; 8],
     csgcm: [u32; 8],
     header_len: u64,
     payload_len: u64,
 }
 
-/// Selects the encryption algorithm.
-#[derive(PartialEq, Clone, Copy)]
-pub enum Algorithm {
-    /// Advanced Encryption Standard
-    AES,
-    /// Data Encryption Standard
-    DES,
-    /// Triple-DES
-    TDES,
-}
-
-/// Selects the cipher mode.
-#[derive(PartialEq, Clone, Copy)]
-pub enum Mode {
-    /// Electronic Codebook
-    ECB,
-    /// Cipher Block Chaining
-    CBC,
-    /// Counter Mode
-    CTR,
-    /// Galois Counter Mode
-    GCM,
-    /// Galois Message Authentication Code
-    GMAC,
-    /// Counter with CBC-MAC
-    CCM,
-}
-
 /// Selects whether the crypto processor operates in encryption or decryption mode.
 #[derive(PartialEq, Clone, Copy)]
 pub enum Direction {
@@ -68,10 +394,6 @@ pub struct Cryp<'d, T: Instance> {
     _peripheral: PeripheralRef<'d, T>,
 }
 
-/// Initialization vector of arbitrary length.
-/// When an initialization vector is not needed, `None` may be supplied.
-pub type InitVector<'v> = Option<&'v [u8]>;
-
 impl<'d, T: Instance> Cryp<'d, T> {
     /// Create a new CRYP driver.
     pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
@@ -85,51 +407,31 @@ impl<'d, T: Instance> Cryp<'d, T> {
     /// Key size must be 128, 192, or 256 bits.
     /// Initialization vector must only be supplied if necessary.
     /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode.
-    pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> {
-        let mut ctx = Context {
-            algo,
-            mode,
+    pub fn start<'c, C: Cipher<'c> + CipherSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> {
+        let mut ctx: Context<'c, C> = Context {
             dir,
             last_block_processed: false,
             cr: 0,
             iv: [0; 4],
-            key,
             csgcmccm: [0; 8],
             csgcm: [0; 8],
             aad_complete: false,
             header_len: 0,
             payload_len: 0,
+            cipher: cipher,
+            phantom_data: PhantomData,
         };
 
         T::regs().cr().modify(|w| w.set_crypen(false));
 
-        // Checks for correctness
-        if algo == Algorithm::AES {
-            let keylen = key.len() * 8;
-            let ivlen;
-            if let Some(iv) = iv {
-                ivlen = iv.len() * 8;
-            } else {
-                ivlen = 0;
-            }
-            match keylen {
-                128 => T::regs().cr().modify(|w| w.set_keysize(0)),
-                192 => T::regs().cr().modify(|w| w.set_keysize(1)),
-                256 => T::regs().cr().modify(|w| w.set_keysize(2)),
-                _ => panic!("Key length must be 128, 192, or 256 bits."),
-            }
+        let key = ctx.cipher.key();
 
-            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 != 128) {
-                panic!("IV length must be 128 bits for CTR.");
-            } else if (mode == Mode::GMAC) && (ivlen != 96) {
-                panic!("IV length must be 96 bits for GMAC.");
-            }
+        if key.len() == (128 / 8) {
+            T::regs().cr().modify(|w| w.set_keysize(0));
+        } else if key.len() == (192 / 8) {
+            T::regs().cr().modify(|w| w.set_keysize(1));
+        } else if key.len() == (256 / 8) {
+            T::regs().cr().modify(|w| w.set_keysize(2));
         }
 
         self.load_key(key);
@@ -137,40 +439,9 @@ impl<'d, T: Instance> Cryp<'d, T> {
         // Set data type to 8-bit. This will match software implementations.
         T::regs().cr().modify(|w| w.set_datatype(2));
 
-        self.prepare_key(&ctx);
+        ctx.cipher.prepare_key(&T::regs());
 
-        if algo == Algorithm::AES {
-            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(0)),
-                Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode0(0)),
-                Mode::CCM => T::regs().cr().modify(|w| w.set_algomode0(1)),
-            }
-            match mode {
-                Mode::ECB => T::regs().cr().modify(|w| w.set_algomode3(false)),
-                Mode::CBC => T::regs().cr().modify(|w| w.set_algomode3(false)),
-                Mode::CTR => T::regs().cr().modify(|w| w.set_algomode3(false)),
-                Mode::GCM => T::regs().cr().modify(|w| w.set_algomode3(true)),
-                Mode::GMAC => T::regs().cr().modify(|w| w.set_algomode3(true)),
-                Mode::CCM => T::regs().cr().modify(|w| w.set_algomode3(true)),
-            }
-        } else if algo == Algorithm::DES {
-            T::regs().cr().modify(|w| w.set_algomode3(false));
-            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 {
-            T::regs().cr().modify(|w| w.set_algomode3(false));
-            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."),
-            }
-        }
+        ctx.cipher.set_algomode(&T::regs());
 
         // Set encrypt/decrypt
         if dir == Direction::Encrypt {
@@ -180,38 +451,27 @@ impl<'d, T: Instance> Cryp<'d, T> {
         }
 
         // Load the IV into the registers.
-        if let Some(iv) = iv {
-            let mut full_iv: [u8; 16] = [0; 16];
-            full_iv[0..iv.len()].copy_from_slice(iv);
-
-            if (mode == Mode::GCM) || (mode == Mode::GMAC) {
-                full_iv[15] = 2;
-            }
-
-            let mut iv_idx = 0;
-            let mut iv_word: [u8; 4] = [0; 4];
-            iv_word.copy_from_slice(&full_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(&full_iv[iv_idx..iv_idx + 4]);
-            iv_idx += 4;
-            T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
-            iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
-            iv_idx += 4;
-            T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
-            iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
-            T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word));
-        }
+        let iv = ctx.cipher.iv();
+        let mut full_iv: [u8; 16] = [0; 16];
+        full_iv[0..iv.len()].copy_from_slice(iv);
+        let mut iv_idx = 0;
+        let mut iv_word: [u8; 4] = [0; 4];
+        iv_word.copy_from_slice(&full_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(&full_iv[iv_idx..iv_idx + 4]);
+        iv_idx += 4;
+        T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word));
+        iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]);
+        iv_idx += 4;
+        T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word));
+        iv_word.copy_from_slice(&full_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());
 
-        if mode == Mode::GCM {
-            // GCM init phase
-            T::regs().cr().modify(|w| w.set_gcm_ccmph(0));
-            T::regs().cr().modify(|w| w.set_crypen(true));
-            while T::regs().cr().read().crypen() {}
-        }
+        ctx.cipher.init_phase(&T::regs());
 
         self.store_context(&mut ctx);
 
@@ -224,42 +484,38 @@ impl<'d, T: Instance> Cryp<'d, T> {
     /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`.
     /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block.
     /// When supplying the last block of AAD, `last_aad_block` must be `true`.
-    pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8], last_aad_block: bool) {
+    pub fn aad_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>(
+        &self,
+        ctx: &mut Context<'c, C>,
+        aad: &[u8],
+        last_aad_block: bool,
+    ) {
         self.load_context(ctx);
 
-        let block_size;
-        if ctx.algo == Algorithm::DES {
-            block_size = DES_BLOCK_SIZE;
-        } else {
-            block_size = AES_BLOCK_SIZE;
-        }
-        let last_block_remainder = aad.len() % block_size;
+        let last_block_remainder = aad.len() % C::BLOCK_SIZE;
 
         // Perform checks for correctness.
         if ctx.aad_complete {
             panic!("Cannot update AAD after calling 'update'!")
         }
-        if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) {
-            panic!("Associated data only valid for GCM, GMAC, and CCM modes.")
-        }
         if !last_aad_block {
             if last_block_remainder != 0 {
-                panic!("Input length must be a multiple of {} bytes.", block_size);
+                panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
             }
         }
 
         ctx.header_len += aad.len() as u64;
 
-        // GCM header phase
+        // Header phase
         T::regs().cr().modify(|w| w.set_crypen(false));
         T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
         T::regs().cr().modify(|w| w.set_crypen(true));
 
         // Load data into core, block by block.
-        let num_full_blocks = aad.len() / block_size;
+        let num_full_blocks = aad.len() / C::BLOCK_SIZE;
         for block in 0..num_full_blocks {
-            let mut index = block * block_size;
-            let end_index = index + block_size;
+            let mut index = block * C::BLOCK_SIZE;
+            let end_index = index + C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
@@ -276,7 +532,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
             let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
             last_block[..last_block_remainder].copy_from_slice(&aad[aad.len() - last_block_remainder..aad.len()]);
             let mut index = 0;
-            let end_index = block_size;
+            let end_index = C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
@@ -307,16 +563,16 @@ impl<'d, T: Instance> Cryp<'d, T> {
     /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
     /// Padding or ciphertext stealing must be managed by the application for these modes.
     /// Data must also be a multiple of block size unless `last_block` is `true`.
-    pub fn payload_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) {
+    pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized>(
+        &self,
+        ctx: &mut Context<'c, C>,
+        input: &[u8],
+        output: &mut [u8],
+        last_block: bool,
+    ) {
         self.load_context(ctx);
 
-        let block_size;
-        if ctx.algo == Algorithm::DES {
-            block_size = DES_BLOCK_SIZE;
-        } else {
-            block_size = AES_BLOCK_SIZE;
-        }
-        let last_block_remainder = input.len() % block_size;
+        let last_block_remainder = input.len() % C::BLOCK_SIZE;
 
         // Perform checks for correctness.
         if !ctx.aad_complete && ctx.header_len > 0 {
@@ -328,9 +584,6 @@ impl<'d, T: Instance> Cryp<'d, T> {
             T::regs().cr().modify(|w| w.fflush());
             T::regs().cr().modify(|w| w.set_crypen(true));
         }
-        if ctx.mode == Mode::GMAC {
-            panic!("GMAC works on header data only. Do not call this function for GMAC.");
-        }
         if ctx.last_block_processed {
             panic!("The last block has already been processed!");
         }
@@ -339,24 +592,23 @@ impl<'d, T: Instance> Cryp<'d, T> {
         }
         if !last_block {
             if last_block_remainder != 0 {
-                panic!("Input length must be a multiple of {} bytes.", block_size);
+                panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
             }
         }
-        if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
+        if C::REQUIRES_PADDING {
             if last_block_remainder != 0 {
-                panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", block_size);
+                panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE);
             }
         }
-
         if last_block {
             ctx.last_block_processed = true;
         }
 
         // Load data into core, block by block.
-        let num_full_blocks = input.len() / block_size;
+        let num_full_blocks = input.len() / C::BLOCK_SIZE;
         for block in 0..num_full_blocks {
-            let mut index = block * block_size;
-            let end_index = index + block_size;
+            let mut index = block * C::BLOCK_SIZE;
+            let end_index = index + C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
@@ -364,8 +616,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 T::regs().din().write_value(u32::from_ne_bytes(in_word));
                 index += 4;
             }
-            let mut index = block * block_size;
-            let end_index = index + block_size;
+            let mut index = block * C::BLOCK_SIZE;
+            let end_index = index + C::BLOCK_SIZE;
             // Block until there is output to read.
             while !T::regs().sr().read().ofne() {}
             // Read block out
@@ -378,21 +630,13 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
         // Handle the final block, which is incomplete.
         if last_block_remainder > 0 {
-            if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
-                //Handle special GCM partial block process.
-                T::regs().cr().modify(|w| w.set_crypen(false));
-                T::regs().cr().modify(|w| w.set_algomode3(false));
-                T::regs().cr().modify(|w| w.set_algomode0(6));
-                let iv1r = T::regs().csgcmccmr(7).read() - 1;
-                T::regs().init(1).ivrr().write_value(iv1r);
-                T::regs().cr().modify(|w| w.set_crypen(true));
-            }
+            ctx.cipher.pre_final_block(&T::regs());
 
             let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
             let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
             last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
             let mut index = 0;
-            let end_index = block_size;
+            let end_index = C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
@@ -401,7 +645,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 index += 4;
             }
             let mut index = 0;
-            let end_index = block_size;
+            let end_index = C::BLOCK_SIZE;
             // Block until there is output to read.
             while !T::regs().sr().read().ofne() {}
             // Read block out
@@ -416,41 +660,19 @@ impl<'d, T: Instance> Cryp<'d, T> {
             output[output_len - last_block_remainder..output_len]
                 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
 
-            if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
-                //Handle special GCM partial block process.
-                T::regs().cr().modify(|w| w.set_crypen(false));
-                T::regs().cr().write(|w| w.set_algomode3(true));
-                T::regs().cr().write(|w| w.set_algomode0(0));
-                T::regs().init(1).ivrr().write_value(2);
-                T::regs().cr().modify(|w| w.set_crypen(true));
-                T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
-                let mut index = 0;
-                let end_index = block_size;
-                while index < end_index {
-                    let mut in_word: [u8; 4] = [0; 4];
-                    in_word.copy_from_slice(&intermediate_data[index..index + 4]);
-                    T::regs().din().write_value(u32::from_ne_bytes(in_word));
-                    index += 4;
-                }
-                for _ in 0..4 {
-                    T::regs().dout().read();
-                }
-            }
+            ctx.cipher.post_final_block(&T::regs(), ctx.dir, &intermediate_data);
         }
 
         ctx.payload_len += input.len() as u64;
     }
 
     /// This function only needs to be called for GCM, CCM, and GMAC modes to
-    /// generate an authentication tag. Calling this function on any other mode
-    /// does nothing except consumes the context. A buffer for the authentication
-    /// tag must be supplied.
-    pub fn finish_blocking(&self, mut ctx: Context, tag: &mut [u8; 16]) {
-        // Just consume the context if called for any other mode.
-        if (ctx.mode != Mode::GCM) || (ctx.mode != Mode::CCM) || (ctx.mode != Mode::GMAC) {
-            return;
-        }
-
+    /// generate an authentication tag.
+    pub fn finish_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>(
+        &self,
+        mut ctx: Context<'c, C>,
+        tag: &mut [u8; 16],
+    ) {
         self.load_context(&mut ctx);
 
         T::regs().cr().modify(|w| w.set_crypen(false));
@@ -477,17 +699,6 @@ impl<'d, T: Instance> Cryp<'d, T> {
         T::regs().cr().modify(|w| w.set_crypen(false));
     }
 
-    fn prepare_key(&self, ctx: &Context) {
-        if ctx.algo == Algorithm::AES && ctx.dir == Direction::Decrypt {
-            if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
-                T::regs().cr().modify(|w| w.set_algomode0(7));
-                T::regs().cr().modify(|w| w.set_algomode3(false));
-                T::regs().cr().modify(|w| w.set_crypen(true));
-                while T::regs().sr().read().busy() {}
-            }
-        }
-    }
-
     fn load_key(&self, key: &[u8]) {
         // Load the key into the registers.
         let mut keyidx = 0;
@@ -524,7 +735,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword));
     }
 
-    fn store_context(&self, ctx: &mut Context) {
+    fn store_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &mut Context<'c, C>) {
         // Wait for data block processing to finish.
         while !T::regs().sr().read().ifem() {}
         while T::regs().sr().read().ofne() {}
@@ -545,7 +756,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         }
     }
 
-    fn load_context(&self, ctx: &Context) {
+    fn load_context<'c, C: Cipher<'c> + CipherSized>(&self, ctx: &Context<'c, C>) {
         // Reload state registers.
         T::regs().cr().write(|w| w.0 = ctx.cr);
         T::regs().init(0).ivlr().write_value(ctx.iv[0]);
@@ -556,10 +767,10 @@ impl<'d, T: Instance> Cryp<'d, T> {
             T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
             T::regs().csgcmr(i).write_value(ctx.csgcm[i]);
         }
-        self.load_key(ctx.key);
+        self.load_key(ctx.cipher.key());
 
         // Prepare key if applicable.
-        self.prepare_key(ctx);
+        ctx.cipher.prepare_key(&T::regs());
         T::regs().cr().write(|w| w.0 = ctx.cr);
 
         // Enable crypto processor.

From 690b2118c6fdad88bf1e595b6a0c0afdb0583d28 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Tue, 20 Feb 2024 11:54:39 -0500
Subject: [PATCH 07/29] CCM mode functional.

---
 embassy-stm32/src/cryp/mod.rs | 372 ++++++++++++++++++++++++++--------
 1 file changed, 293 insertions(+), 79 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 29c1db12e..fe248def1 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1,6 +1,6 @@
 //! Crypto Accelerator (CRYP)
+use core::cmp::min;
 use core::marker::PhantomData;
-
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
 use crate::pac;
@@ -21,7 +21,7 @@ pub trait Cipher<'c> {
     const REQUIRES_PADDING: bool = false;
 
     /// Returns the symmetric key.
-    fn key(&self) -> &'c [u8];
+    fn key(&self) -> &[u8];
 
     /// Returns the initialization vector.
     fn iv(&self) -> &[u8];
@@ -36,10 +36,25 @@ pub trait Cipher<'c> {
     fn init_phase(&self, _p: &pac::cryp::Cryp) {}
 
     /// Called prior to processing the last data block for cipher-specific operations.
-    fn pre_final_block(&self, _p: &pac::cryp::Cryp) {}
+    fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction) -> [u32; 4] {
+        return [0; 4];
+    }
 
     /// Called after processing the last data block for cipher-specific operations.
-    fn post_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _int_data: &[u8; AES_BLOCK_SIZE]) {}
+    fn post_final_block(
+        &self,
+        _p: &pac::cryp::Cryp,
+        _dir: Direction,
+        _int_data: &[u8; AES_BLOCK_SIZE],
+        _temp1: [u32; 4],
+        _padding_mask: [u8; 16],
+    ) {
+    }
+
+    /// Called prior to processing the first associated data block for cipher-specific operations.
+    fn get_header_block(&self) -> &[u8] {
+        return [0; 0].as_slice();
+    }
 }
 
 /// This trait enables restriction of ciphers to specific key sizes.
@@ -204,17 +219,27 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
         while p.cr().read().crypen() {}
     }
 
-    fn pre_final_block(&self, p: &pac::cryp::Cryp) {
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] {
         //Handle special GCM partial block process.
-        p.cr().modify(|w| w.set_crypen(false));
-        p.cr().modify(|w| w.set_algomode3(false));
-        p.cr().modify(|w| w.set_algomode0(6));
-        let iv1r = p.csgcmccmr(7).read() - 1;
-        p.init(1).ivrr().write_value(iv1r);
-        p.cr().modify(|w| w.set_crypen(true));
+        if dir == Direction::Encrypt {
+            p.cr().modify(|w| w.set_crypen(false));
+            p.cr().modify(|w| w.set_algomode3(false));
+            p.cr().modify(|w| w.set_algomode0(6));
+            let iv1r = p.csgcmccmr(7).read() - 1;
+            p.init(1).ivrr().write_value(iv1r);
+            p.cr().modify(|w| w.set_crypen(true));
+        }
+        [0; 4]
     }
 
-    fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) {
+    fn post_final_block(
+        &self,
+        p: &pac::cryp::Cryp,
+        dir: Direction,
+        int_data: &[u8; AES_BLOCK_SIZE],
+        _temp1: [u32; 4],
+        _padding_mask: [u8; 16],
+    ) {
         if dir == Direction::Encrypt {
             //Handle special GCM partial block process.
             p.cr().modify(|w| w.set_crypen(false));
@@ -281,17 +306,27 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
         while p.cr().read().crypen() {}
     }
 
-    fn pre_final_block(&self, p: &pac::cryp::Cryp) {
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] {
         //Handle special GCM partial block process.
-        p.cr().modify(|w| w.set_crypen(false));
-        p.cr().modify(|w| w.set_algomode3(false));
-        p.cr().modify(|w| w.set_algomode0(6));
-        let iv1r = p.csgcmccmr(7).read() - 1;
-        p.init(1).ivrr().write_value(iv1r);
-        p.cr().modify(|w| w.set_crypen(true));
+        if dir == Direction::Encrypt {
+            p.cr().modify(|w| w.set_crypen(false));
+            p.cr().modify(|w| w.set_algomode3(false));
+            p.cr().modify(|w| w.set_algomode0(6));
+            let iv1r = p.csgcmccmr(7).read() - 1;
+            p.init(1).ivrr().write_value(iv1r);
+            p.cr().modify(|w| w.set_crypen(true));
+        }
+        [0; 4]
     }
 
-    fn post_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, int_data: &[u8; AES_BLOCK_SIZE]) {
+    fn post_final_block(
+        &self,
+        p: &pac::cryp::Cryp,
+        dir: Direction,
+        int_data: &[u8; AES_BLOCK_SIZE],
+        _temp1: [u32; 4],
+        _padding_mask: [u8; 16],
+    ) {
         if dir == Direction::Encrypt {
             //Handle special GCM partial block process.
             p.cr().modify(|w| w.set_crypen(false));
@@ -320,49 +355,180 @@ impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
 impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGmac<'c, KEY_SIZE> {}
 
-// struct AesCcm<'c, const KEY_SIZE: usize> {
-//     iv: &'c [u8],
-//     key: &'c [u8; KEY_SIZE],
-//     aad_len: usize,
-//     payload_len: usize,
-// }
+pub struct AesCcm<'c, const KEY_SIZE: usize> {
+    key: &'c [u8; KEY_SIZE],
+    aad_header: [u8; 6],
+    aad_header_len: usize,
+    block0: [u8; 16],
+    ctr: [u8; 16],
+}
 
-// impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> {
-//     pub fn new(&self, key: &[u8; KEY_SIZE], iv: &[u8], aad_len: usize, payload_len: usize) {
-//         if iv.len() > 13 {
-//             panic!("CCM IV length must be 13 bytes or less.");
-//         }
-//         self.key = key;
-//         self.iv = iv;
-//         self.aad_len = aad_len;
-//         self.payload_len = payload_len;
-//     }
-// }
+impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> {
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8], aad_len: usize, payload_len: usize, tag_len: u8) -> Self {
+        if (iv.len()) > 13 || (iv.len() < 7) {
+            panic!("CCM IV length must be 7-13 bytes.");
+        }
+        if (tag_len < 4) || (tag_len > 16) {
+            panic!("Tag length must be between 4 and 16 bytes.");
+        }
+        if tag_len % 2 > 0 {
+            panic!("Tag length must be a multiple of 2 bytes.");
+        }
 
-// impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
-//     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
+        let mut aad_header: [u8; 6] = [0; 6];
+        let mut aad_header_len = 0;
+        let mut block0: [u8; 16] = [0; 16];
+        if aad_len != 0 {
+            if aad_len < 65280 {
+                aad_header[0] = (aad_len >> 8) as u8 & 0xFF;
+                aad_header[1] = aad_len as u8 & 0xFF;
+                aad_header_len = 2;
+            } else {
+                aad_header[0] = 0xFF;
+                aad_header[1] = 0xFE;
+                let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes();
+                aad_header[2] = aad_len_bytes[0];
+                aad_header[3] = aad_len_bytes[1];
+                aad_header[4] = aad_len_bytes[2];
+                aad_header[5] = aad_len_bytes[3];
+                aad_header_len = 6;
+            }
+        }
+        let total_aad_len = aad_header_len + aad_len;
+        let mut aad_padding_len = 16 - (total_aad_len % 16);
+        if aad_padding_len == 16 {
+            aad_padding_len = 0;
+        }
+        aad_header_len += aad_padding_len;
+        let total_aad_len_padded = aad_header_len + aad_len;
+        if total_aad_len_padded > 0 {
+            block0[0] = 0x40;
+        }
+        block0[0] |= (((tag_len - 2) >> 1) & 0x07) << 3;
+        block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07;
+        block0[1..1 + iv.len()].copy_from_slice(iv);
+        let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes();
+        if iv.len() <= 11 {
+            block0[12] = payload_len_bytes[0];
+        } else if payload_len_bytes[0] > 0 {
+            panic!("Message is too large for given IV size.");
+        }
+        if iv.len() <= 12 {
+            block0[13] = payload_len_bytes[1];
+        } else if payload_len_bytes[1] > 0 {
+            panic!("Message is too large for given IV size.");
+        }
+        block0[14] = payload_len_bytes[2];
+        block0[15] = payload_len_bytes[3];
+        let mut ctr: [u8; 16] = [0; 16];
+        ctr[0] = block0[0] & 0x07;
+        ctr[1..1 + iv.len()].copy_from_slice(&block0[1..1 + iv.len()]);
+        ctr[15] = 0x01;
 
-//     fn key(&self) -> &'c [u8] {
-//         self.key
-//     }
+        return Self {
+            key: key,
+            aad_header: aad_header,
+            aad_header_len: aad_header_len,
+            block0: block0,
+            ctr: ctr,
+        };
+    }
+}
 
-//     fn iv(&self) -> &'c [u8] {
-//         self.iv
-//     }
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
 
-//     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-//         p.cr().modify(|w| w.set_algomode0(1));
-//         p.cr().modify(|w| w.set_algomode3(true));
-//     }
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
 
-//     fn init_phase(&self, p: &pac::cryp::Cryp) {
-//         todo!();
-//     }
-// }
+    fn iv(&self) -> &[u8] {
+        self.ctr.as_slice()
+    }
 
-// impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {}
-// impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {}
-// impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {}
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(1));
+        p.cr().modify(|w| w.set_algomode3(true));
+    }
+
+    fn init_phase(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_gcm_ccmph(0));
+
+        let mut index = 0;
+        let end_index = index + Self::BLOCK_SIZE;
+        // Write block in
+        while index < end_index {
+            let mut in_word: [u8; 4] = [0; 4];
+            in_word.copy_from_slice(&self.block0[index..index + 4]);
+            p.din().write_value(u32::from_ne_bytes(in_word));
+            index += 4;
+        }
+        p.cr().modify(|w| w.set_crypen(true));
+        while p.cr().read().crypen() {}
+    }
+
+    fn get_header_block(&self) -> &[u8] {
+        return &self.aad_header[0..self.aad_header_len];
+    }
+
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] {
+        //Handle special CCM partial block process.
+        let mut temp1 = [0; 4];
+        if dir == Direction::Decrypt {
+            p.cr().modify(|w| w.set_crypen(false));
+            let iv1temp = p.init(1).ivrr().read();
+            temp1[0] = p.csgcmccmr(0).read();
+            temp1[1] = p.csgcmccmr(1).read();
+            temp1[2] = p.csgcmccmr(2).read();
+            temp1[3] = p.csgcmccmr(3).read();
+            p.init(1).ivrr().write_value(iv1temp);
+            p.cr().modify(|w| w.set_algomode3(false));
+            p.cr().modify(|w| w.set_algomode0(6));
+            p.cr().modify(|w| w.set_crypen(true));
+        }
+        return temp1;
+    }
+
+    fn post_final_block(
+        &self,
+        p: &pac::cryp::Cryp,
+        dir: Direction,
+        int_data: &[u8; AES_BLOCK_SIZE],
+        temp1: [u32; 4],
+        padding_mask: [u8; 16],
+    ) {
+        if dir == Direction::Decrypt {
+            //Handle special CCM partial block process.
+            let mut intdata_o: [u32; 4] = [0; 4];
+            for i in 0..intdata_o.len() {
+                intdata_o[i] = p.dout().read();
+            }
+            let mut temp2 = [0; 4];
+            temp2[0] = p.csgcmccmr(0).read();
+            temp2[1] = p.csgcmccmr(1).read();
+            temp2[2] = p.csgcmccmr(2).read();
+            temp2[3] = p.csgcmccmr(3).read();
+            p.cr().write(|w| w.set_algomode3(true));
+            p.cr().write(|w| w.set_algomode0(1));
+            p.cr().modify(|w| w.set_gcm_ccmph(3));
+            // Header phase
+            p.cr().modify(|w| w.set_gcm_ccmph(1));
+            let mut in_data: [u32; 4] = [0; 4];
+            for i in 0..in_data.len() {
+                let mut mask_bytes: [u8; 4] = [0; 4];
+                mask_bytes.copy_from_slice(&padding_mask[(i * 4)..(i * 4) + 4]);
+                let mask_word = u32::from_le_bytes(mask_bytes);
+                in_data[i] = intdata_o[i] & mask_word;
+                in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
+            }
+        }
+    }
+}
+
+impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {}
+impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {}
+impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesCcm<'c, KEY_SIZE> {}
 
 /// Holds the state information for a cipher operation.
 /// Allows suspending/resuming of cipher operations.
@@ -371,6 +537,7 @@ pub struct Context<'c, C: Cipher<'c> + CipherSized> {
     cipher: &'c C,
     dir: Direction,
     last_block_processed: bool,
+    header_processed: bool,
     aad_complete: bool,
     cr: u32,
     iv: [u32; 4],
@@ -378,6 +545,8 @@ pub struct Context<'c, C: Cipher<'c> + CipherSized> {
     csgcm: [u32; 8],
     header_len: u64,
     payload_len: u64,
+    aad_buffer: [u8; 16],
+    aad_buffer_len: usize,
 }
 
 /// Selects whether the crypto processor operates in encryption or decryption mode.
@@ -420,6 +589,9 @@ impl<'d, T: Instance> Cryp<'d, T> {
             payload_len: 0,
             cipher: cipher,
             phantom_data: PhantomData,
+            header_processed: false,
+            aad_buffer: [0; 16],
+            aad_buffer_len: 0,
         };
 
         T::regs().cr().modify(|w| w.set_crypen(false));
@@ -492,16 +664,9 @@ impl<'d, T: Instance> Cryp<'d, T> {
     ) {
         self.load_context(ctx);
 
-        let last_block_remainder = aad.len() % C::BLOCK_SIZE;
-
         // Perform checks for correctness.
         if ctx.aad_complete {
-            panic!("Cannot update AAD after calling 'update'!")
-        }
-        if !last_aad_block {
-            if last_block_remainder != 0 {
-                panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
-            }
+            panic!("Cannot update AAD after starting payload!")
         }
 
         ctx.header_len += aad.len() as u64;
@@ -511,11 +676,49 @@ impl<'d, T: Instance> Cryp<'d, T> {
         T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
         T::regs().cr().modify(|w| w.set_crypen(true));
 
-        // Load data into core, block by block.
-        let num_full_blocks = aad.len() / C::BLOCK_SIZE;
-        for block in 0..num_full_blocks {
-            let mut index = block * C::BLOCK_SIZE;
-            let end_index = index + C::BLOCK_SIZE;
+        // First write the header B1 block if not yet written.
+        if !ctx.header_processed {
+            ctx.header_processed = true;
+            let header = ctx.cipher.get_header_block();
+            ctx.aad_buffer[0..header.len()].copy_from_slice(header);
+            ctx.aad_buffer_len += header.len();
+        }
+
+        // Fill the header block to make a full block.
+        let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len);
+        ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]);
+        ctx.aad_buffer_len += len_to_copy;
+        ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
+        let mut aad_len_remaining = aad.len() - len_to_copy;
+
+        if ctx.aad_buffer_len < C::BLOCK_SIZE {
+            // The buffer isn't full and this is the last buffer, so process it as is (already padded).
+            if last_aad_block {
+                let mut index = 0;
+                let end_index = C::BLOCK_SIZE;
+                // Write block in
+                while index < end_index {
+                    let mut in_word: [u8; 4] = [0; 4];
+                    in_word.copy_from_slice(&aad[index..index + 4]);
+                    T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                    index += 4;
+                }
+                // Block until input FIFO is empty.
+                while !T::regs().sr().read().ifem() {}
+
+                // Switch to payload phase.
+                ctx.aad_complete = true;
+                T::regs().cr().modify(|w| w.set_crypen(false));
+                T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
+                T::regs().cr().modify(|w| w.fflush());
+            } else {
+                // Just return because we don't yet have a full block to process.
+                return;
+            }
+        } else {
+            // Load the full block from the buffer.
+            let mut index = 0;
+            let end_index = C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
@@ -527,20 +730,26 @@ impl<'d, T: Instance> Cryp<'d, T> {
             while !T::regs().sr().read().ifem() {}
         }
 
-        // Handle the final block, which is incomplete.
-        if last_block_remainder > 0 {
-            let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
-            last_block[..last_block_remainder].copy_from_slice(&aad[aad.len() - last_block_remainder..aad.len()]);
-            let mut index = 0;
-            let end_index = C::BLOCK_SIZE;
+        // Handle a partial block that is passed in.
+        ctx.aad_buffer_len = 0;
+        let leftovers = aad_len_remaining % C::BLOCK_SIZE;
+        ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
+        aad_len_remaining -= leftovers;
+        assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
+
+        // Load full data blocks into core.
+        let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
+        for _ in 0..num_full_blocks {
+            let mut index = len_to_copy;
+            let end_index = len_to_copy + C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
-                in_word.copy_from_slice(&last_block[index..index + 4]);
+                in_word.copy_from_slice(&aad[index..index + 4]);
                 T::regs().din().write_value(u32::from_ne_bytes(in_word));
                 index += 4;
             }
-            // Block until input FIFO is empty
+            // Block until input FIFO is empty.
             while !T::regs().sr().read().ifem() {}
         }
 
@@ -630,7 +839,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
         // Handle the final block, which is incomplete.
         if last_block_remainder > 0 {
-            ctx.cipher.pre_final_block(&T::regs());
+            let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir);
 
             let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
             let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
@@ -660,10 +869,15 @@ impl<'d, T: Instance> Cryp<'d, T> {
             output[output_len - last_block_remainder..output_len]
                 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
 
-            ctx.cipher.post_final_block(&T::regs(), ctx.dir, &intermediate_data);
+            let mut mask: [u8; 16] = [0; 16];
+            mask[..last_block_remainder].fill(0xFF);
+            ctx.cipher
+                .post_final_block(&T::regs(), ctx.dir, &intermediate_data, temp1, mask);
         }
 
         ctx.payload_len += input.len() as u64;
+
+        self.store_context(ctx);
     }
 
     /// This function only needs to be called for GCM, CCM, and GMAC modes to

From 1e21b758f795b5cc8a2331aacbc2a9a39bb7a7fb Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Tue, 20 Feb 2024 14:27:37 -0500
Subject: [PATCH 08/29] Corrected GCM tag generation.

---
 embassy-stm32/src/cryp/mod.rs | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index fe248def1..81446e39e 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -45,7 +45,7 @@ pub trait Cipher<'c> {
         &self,
         _p: &pac::cryp::Cryp,
         _dir: Direction,
-        _int_data: &[u8; AES_BLOCK_SIZE],
+        _int_data: &mut [u8; AES_BLOCK_SIZE],
         _temp1: [u32; 4],
         _padding_mask: [u8; 16],
     ) {
@@ -236,16 +236,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
         &self,
         p: &pac::cryp::Cryp,
         dir: Direction,
-        int_data: &[u8; AES_BLOCK_SIZE],
+        int_data: &mut [u8; AES_BLOCK_SIZE],
         _temp1: [u32; 4],
-        _padding_mask: [u8; 16],
+        padding_mask: [u8; AES_BLOCK_SIZE],
     ) {
         if dir == Direction::Encrypt {
             //Handle special GCM partial block process.
             p.cr().modify(|w| w.set_crypen(false));
-            p.cr().write(|w| w.set_algomode3(true));
-            p.cr().write(|w| w.set_algomode0(0));
-            p.init(1).ivrr().write_value(2);
+            p.cr().modify(|w| w.set_algomode3(true));
+            p.cr().modify(|w| w.set_algomode0(0));
+            for i in 0..AES_BLOCK_SIZE {
+                int_data[i] = int_data[i] & padding_mask[i];
+            }
             p.cr().modify(|w| w.set_crypen(true));
             p.cr().modify(|w| w.set_gcm_ccmph(3));
             let mut index = 0;
@@ -323,7 +325,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
         &self,
         p: &pac::cryp::Cryp,
         dir: Direction,
-        int_data: &[u8; AES_BLOCK_SIZE],
+        int_data: &mut [u8; AES_BLOCK_SIZE],
         _temp1: [u32; 4],
         _padding_mask: [u8; 16],
     ) {
@@ -493,7 +495,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
         &self,
         p: &pac::cryp::Cryp,
         dir: Direction,
-        int_data: &[u8; AES_BLOCK_SIZE],
+        int_data: &mut [u8; AES_BLOCK_SIZE],
         temp1: [u32; 4],
         padding_mask: [u8; 16],
     ) {
@@ -872,7 +874,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
             let mut mask: [u8; 16] = [0; 16];
             mask[..last_block_remainder].fill(0xFF);
             ctx.cipher
-                .post_final_block(&T::regs(), ctx.dir, &intermediate_data, temp1, mask);
+                .post_final_block(&T::regs(), ctx.dir, &mut intermediate_data, temp1, mask);
         }
 
         ctx.payload_len += input.len() as u64;

From f64a62149e423f6fdb643f7343d971eedc4a3a12 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Tue, 20 Feb 2024 15:26:31 -0500
Subject: [PATCH 09/29] Corrected CCM partial block ops.

---
 embassy-stm32/src/cryp/mod.rs | 46 ++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 81446e39e..634c85883 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -327,14 +327,16 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
         dir: Direction,
         int_data: &mut [u8; AES_BLOCK_SIZE],
         _temp1: [u32; 4],
-        _padding_mask: [u8; 16],
+        padding_mask: [u8; AES_BLOCK_SIZE],
     ) {
         if dir == Direction::Encrypt {
             //Handle special GCM partial block process.
             p.cr().modify(|w| w.set_crypen(false));
-            p.cr().write(|w| w.set_algomode3(true));
-            p.cr().write(|w| w.set_algomode0(0));
-            p.init(1).ivrr().write_value(2);
+            p.cr().modify(|w| w.set_algomode3(true));
+            p.cr().modify(|w| w.set_algomode0(0));
+            for i in 0..AES_BLOCK_SIZE {
+                int_data[i] = int_data[i] & padding_mask[i];
+            }
             p.cr().modify(|w| w.set_crypen(true));
             p.cr().modify(|w| w.set_gcm_ccmph(3));
             let mut index = 0;
@@ -479,10 +481,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
         if dir == Direction::Decrypt {
             p.cr().modify(|w| w.set_crypen(false));
             let iv1temp = p.init(1).ivrr().read();
-            temp1[0] = p.csgcmccmr(0).read();
-            temp1[1] = p.csgcmccmr(1).read();
-            temp1[2] = p.csgcmccmr(2).read();
-            temp1[3] = p.csgcmccmr(3).read();
+            temp1[0] = p.csgcmccmr(0).read().swap_bytes();
+            temp1[1] = p.csgcmccmr(1).read().swap_bytes();
+            temp1[2] = p.csgcmccmr(2).read().swap_bytes();
+            temp1[3] = p.csgcmccmr(3).read().swap_bytes();
             p.init(1).ivrr().write_value(iv1temp);
             p.cr().modify(|w| w.set_algomode3(false));
             p.cr().modify(|w| w.set_algomode0(6));
@@ -501,27 +503,27 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
     ) {
         if dir == Direction::Decrypt {
             //Handle special CCM partial block process.
-            let mut intdata_o: [u32; 4] = [0; 4];
-            for i in 0..intdata_o.len() {
-                intdata_o[i] = p.dout().read();
-            }
             let mut temp2 = [0; 4];
-            temp2[0] = p.csgcmccmr(0).read();
-            temp2[1] = p.csgcmccmr(1).read();
-            temp2[2] = p.csgcmccmr(2).read();
-            temp2[3] = p.csgcmccmr(3).read();
-            p.cr().write(|w| w.set_algomode3(true));
-            p.cr().write(|w| w.set_algomode0(1));
+            temp2[0] = p.csgcmccmr(0).read().swap_bytes();
+            temp2[1] = p.csgcmccmr(1).read().swap_bytes();
+            temp2[2] = p.csgcmccmr(2).read().swap_bytes();
+            temp2[3] = p.csgcmccmr(3).read().swap_bytes();
+            p.cr().modify(|w| w.set_algomode3(true));
+            p.cr().modify(|w| w.set_algomode0(1));
             p.cr().modify(|w| w.set_gcm_ccmph(3));
             // Header phase
             p.cr().modify(|w| w.set_gcm_ccmph(1));
+            for i in 0..AES_BLOCK_SIZE {
+                int_data[i] = int_data[i] & padding_mask[i];
+            }
             let mut in_data: [u32; 4] = [0; 4];
             for i in 0..in_data.len() {
-                let mut mask_bytes: [u8; 4] = [0; 4];
-                mask_bytes.copy_from_slice(&padding_mask[(i * 4)..(i * 4) + 4]);
-                let mask_word = u32::from_le_bytes(mask_bytes);
-                in_data[i] = intdata_o[i] & mask_word;
+                let mut int_bytes: [u8; 4] = [0; 4];
+                int_bytes.copy_from_slice(&int_data[(i * 4)..(i * 4) + 4]);
+                let int_word = u32::from_le_bytes(int_bytes);
+                in_data[i] = int_word;
                 in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i];
+                p.din().write_value(in_data[i]);
             }
         }
     }

From 14c2c28e068d6e506c372611800e6dded8d8f440 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Tue, 20 Feb 2024 18:05:35 -0500
Subject: [PATCH 10/29] Corrected additional associated data operation.

---
 embassy-stm32/src/cryp/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 634c85883..d53252a6a 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -703,7 +703,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
                 // Write block in
                 while index < end_index {
                     let mut in_word: [u8; 4] = [0; 4];
-                    in_word.copy_from_slice(&aad[index..index + 4]);
+                    in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
                     T::regs().din().write_value(u32::from_ne_bytes(in_word));
                     index += 4;
                 }

From 29d8b459568b53f1e281d0914b5c897206c9bd4b Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Wed, 21 Feb 2024 12:07:53 -0500
Subject: [PATCH 11/29] Add DES and TDES support. Support variable tag sizes.

---
 embassy-stm32/src/cryp/mod.rs | 237 +++++++++++++++++++++++++++++-----
 1 file changed, 203 insertions(+), 34 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index d53252a6a..a4f1e42dc 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -60,8 +60,152 @@ pub trait Cipher<'c> {
 /// This trait enables restriction of ciphers to specific key sizes.
 pub trait CipherSized {}
 
+/// This trait enables restriction of initialization vectors to sizes compatibile with a cipher mode.
+pub trait IVSized {}
+
 /// This trait enables restriction of a header phase to authenticated ciphers only.
-pub trait CipherAuthenticated {}
+pub trait CipherAuthenticated<const TAG_SIZE: usize> {
+    /// Defines the authentication tag size.
+    const TAG_SIZE: usize = TAG_SIZE;
+}
+
+/// TDES-ECB Cipher Mode
+pub struct TdesEcb<'c, const KEY_SIZE: usize> {
+    iv: &'c [u8; 0],
+    key: &'c [u8; KEY_SIZE],
+}
+
+impl<'c, const KEY_SIZE: usize> TdesEcb<'c, KEY_SIZE> {
+    /// Constructs a new AES-ECB cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
+        return Self { key: key, iv: &[0; 0] };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
+    const REQUIRES_PADDING: bool = true;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(0));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for TdesEcb<'c, { 112 / 8 }> {}
+impl<'c> CipherSized for TdesEcb<'c, { 168 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for TdesEcb<'c, KEY_SIZE> {}
+
+/// TDES-CBC Cipher Mode
+pub struct TdesCbc<'c, const KEY_SIZE: usize> {
+    iv: &'c [u8; 8],
+    key: &'c [u8; KEY_SIZE],
+}
+
+impl<'c, const KEY_SIZE: usize> TdesCbc<'c, KEY_SIZE> {
+    /// Constructs a new TDES-CBC cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self {
+        return Self { key: key, iv: iv };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
+    const REQUIRES_PADDING: bool = true;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(1));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for TdesCbc<'c, { 112 / 8 }> {}
+impl<'c> CipherSized for TdesCbc<'c, { 168 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for TdesCbc<'c, KEY_SIZE> {}
+
+/// DES-ECB Cipher Mode
+pub struct DesEcb<'c, const KEY_SIZE: usize> {
+    iv: &'c [u8; 0],
+    key: &'c [u8; KEY_SIZE],
+}
+
+impl<'c, const KEY_SIZE: usize> DesEcb<'c, KEY_SIZE> {
+    /// Constructs a new AES-ECB cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE]) -> Self {
+        return Self { key: key, iv: &[0; 0] };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
+    const REQUIRES_PADDING: bool = true;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(2));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for DesEcb<'c, { 56 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for DesEcb<'c, KEY_SIZE> {}
+
+/// DES-CBC Cipher Mode
+pub struct DesCbc<'c, const KEY_SIZE: usize> {
+    iv: &'c [u8; 8],
+    key: &'c [u8; KEY_SIZE],
+}
+
+impl<'c, const KEY_SIZE: usize> DesCbc<'c, KEY_SIZE> {
+    /// Constructs a new AES-CBC cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 8]) -> Self {
+        return Self { key: key, iv: iv };
+    }
+}
+
+impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> {
+    const BLOCK_SIZE: usize = DES_BLOCK_SIZE;
+    const REQUIRES_PADDING: bool = true;
+
+    fn key(&self) -> &'c [u8] {
+        self.key
+    }
+
+    fn iv(&self) -> &'c [u8] {
+        self.iv
+    }
+
+    fn set_algomode(&self, p: &pac::cryp::Cryp) {
+        p.cr().modify(|w| w.set_algomode0(3));
+        p.cr().modify(|w| w.set_algomode3(false));
+    }
+}
+
+impl<'c> CipherSized for DesCbc<'c, { 56 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for DesCbc<'c, KEY_SIZE> {}
 
 /// AES-ECB Cipher Mode
 pub struct AesEcb<'c, const KEY_SIZE: usize> {
@@ -96,7 +240,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(4));
+        p.cr().modify(|w| w.set_algomode0(2));
         p.cr().modify(|w| w.set_algomode3(false));
     }
 }
@@ -104,6 +248,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
 impl<'c> CipherSized for AesEcb<'c, { 128 / 8 }> {}
 impl<'c> CipherSized for AesEcb<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesEcb<'c, { 256 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for AesEcb<'c, KEY_SIZE> {}
 
 /// AES-CBC Cipher Mode
 pub struct AesCbc<'c, const KEY_SIZE: usize> {
@@ -146,6 +291,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
 impl<'c> CipherSized for AesCbc<'c, { 128 / 8 }> {}
 impl<'c> CipherSized for AesCbc<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesCbc<'c, { 256 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for AesCbc<'c, KEY_SIZE> {}
 
 /// AES-CTR Cipher Mode
 pub struct AesCtr<'c, const KEY_SIZE: usize> {
@@ -180,6 +326,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
 impl<'c> CipherSized for AesCtr<'c, { 128 / 8 }> {}
 impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
+impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {}
 
 ///AES-GCM Cipher Mode
 pub struct AesGcm<'c, const KEY_SIZE: usize> {
@@ -268,7 +415,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
 impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
 impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
-impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGcm<'c, KEY_SIZE> {}
+impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {}
+impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {}
 
 /// AES-GMAC Cipher Mode
 pub struct AesGmac<'c, const KEY_SIZE: usize> {
@@ -357,9 +505,11 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
 impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
 impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
-impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesGmac<'c, KEY_SIZE> {}
+impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {}
+impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {}
 
-pub struct AesCcm<'c, const KEY_SIZE: usize> {
+/// AES-CCM Cipher Mode
+pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> {
     key: &'c [u8; KEY_SIZE],
     aad_header: [u8; 6],
     aad_header_len: usize,
@@ -367,18 +517,9 @@ pub struct AesCcm<'c, const KEY_SIZE: usize> {
     ctr: [u8; 16],
 }
 
-impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> {
-    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8], aad_len: usize, payload_len: usize, tag_len: u8) -> Self {
-        if (iv.len()) > 13 || (iv.len() < 7) {
-            panic!("CCM IV length must be 7-13 bytes.");
-        }
-        if (tag_len < 4) || (tag_len > 16) {
-            panic!("Tag length must be between 4 and 16 bytes.");
-        }
-        if tag_len % 2 > 0 {
-            panic!("Tag length must be a multiple of 2 bytes.");
-        }
-
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> {
+    /// Constructs a new AES-CCM cipher for a cryptographic operation.
+    pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self {
         let mut aad_header: [u8; 6] = [0; 6];
         let mut aad_header_len = 0;
         let mut block0: [u8; 16] = [0; 16];
@@ -408,7 +549,7 @@ impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> {
         if total_aad_len_padded > 0 {
             block0[0] = 0x40;
         }
-        block0[0] |= (((tag_len - 2) >> 1) & 0x07) << 3;
+        block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3;
         block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07;
         block0[1..1 + iv.len()].copy_from_slice(iv);
         let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes();
@@ -439,7 +580,9 @@ impl<'c, const KEY_SIZE: usize> AesCcm<'c, KEY_SIZE> {
     }
 }
 
-impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c>
+    for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE>
+{
     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
 
     fn key(&self) -> &'c [u8] {
@@ -529,10 +672,23 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCcm<'c, KEY_SIZE> {
     }
 }
 
-impl<'c> CipherSized for AesCcm<'c, { 128 / 8 }> {}
-impl<'c> CipherSized for AesCcm<'c, { 192 / 8 }> {}
-impl<'c> CipherSized for AesCcm<'c, { 256 / 8 }> {}
-impl<'c, const KEY_SIZE: usize> CipherAuthenticated for AesCcm<'c, KEY_SIZE> {}
+impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {}
+impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {}
+impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {}
+impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {}
 
 /// Holds the state information for a cipher operation.
 /// Allows suspending/resuming of cipher operations.
@@ -580,7 +736,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
     /// Key size must be 128, 192, or 256 bits.
     /// Initialization vector must only be supplied if necessary.
     /// Panics if there is any mismatch in parameters, such as an incorrect IV length or invalid mode.
-    pub fn start<'c, C: Cipher<'c> + CipherSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> {
+    pub fn start<'c, C: Cipher<'c> + CipherSized + IVSized>(&self, cipher: &'c C, dir: Direction) -> Context<'c, C> {
         let mut ctx: Context<'c, C> = Context {
             dir,
             last_block_processed: false,
@@ -660,7 +816,11 @@ impl<'d, T: Instance> Cryp<'d, T> {
     /// All AAD must be supplied to this function prior to starting the payload phase with `payload_blocking`.
     /// The AAD must be supplied in multiples of the block size (128 bits), except when supplying the last block.
     /// When supplying the last block of AAD, `last_aad_block` must be `true`.
-    pub fn aad_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>(
+    pub fn aad_blocking<
+        'c,
+        const TAG_SIZE: usize,
+        C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
+    >(
         &self,
         ctx: &mut Context<'c, C>,
         aad: &[u8],
@@ -776,7 +936,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
     /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes.
     /// Padding or ciphertext stealing must be managed by the application for these modes.
     /// Data must also be a multiple of block size unless `last_block` is `true`.
-    pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized>(
+    pub fn payload_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>(
         &self,
         ctx: &mut Context<'c, C>,
         input: &[u8],
@@ -886,11 +1046,14 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
     /// This function only needs to be called for GCM, CCM, and GMAC modes to
     /// generate an authentication tag.
-    pub fn finish_blocking<'c, C: Cipher<'c> + CipherSized + CipherAuthenticated>(
+    pub fn finish_blocking<
+        'c,
+        const TAG_SIZE: usize,
+        C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated<TAG_SIZE>,
+    >(
         &self,
         mut ctx: Context<'c, C>,
-        tag: &mut [u8; 16],
-    ) {
+    ) -> [u8; TAG_SIZE] {
         self.load_context(&mut ctx);
 
         T::regs().cr().modify(|w| w.set_crypen(false));
@@ -909,12 +1072,17 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
         while !T::regs().sr().read().ofne() {}
 
-        tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
-        tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
-        tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
-        tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        let mut full_tag: [u8; 16] = [0; 16];
+        full_tag[0..4].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        full_tag[4..8].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        full_tag[8..12].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        full_tag[12..16].copy_from_slice(T::regs().dout().read().to_ne_bytes().as_slice());
+        let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE];
+        tag.copy_from_slice(&full_tag[0..TAG_SIZE]);
 
         T::regs().cr().modify(|w| w.set_crypen(false));
+
+        tag
     }
 
     fn load_key(&self, key: &[u8]) {
@@ -949,7 +1117,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
         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]);
+        keyword = [0; 4];
+        keyword[0..key.len() - keyidx].copy_from_slice(&key[keyidx..key.len()]);
         T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword));
     }
 

From cbca3a5c9f8f46582287b88db173ad6876686141 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Wed, 21 Feb 2024 12:39:10 -0500
Subject: [PATCH 12/29] Support v1 and v2 cryp variants.

---
 embassy-stm32/src/cryp/mod.rs | 156 +++++++++++++++++++++++++++++-----
 1 file changed, 133 insertions(+), 23 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index a4f1e42dc..965e4a35d 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1,4 +1,5 @@
 //! Crypto Accelerator (CRYP)
+#[cfg(cryp_v2)]
 use core::cmp::min;
 use core::marker::PhantomData;
 use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -95,8 +96,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(0));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(0));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(0));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -130,8 +138,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> {
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(1));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(1));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(1));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -165,8 +180,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> {
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(2));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(2));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(2));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -199,8 +221,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> {
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(3));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(3));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(3));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -233,15 +262,29 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
     }
 
     fn prepare_key(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(7));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(7));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(7));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
         p.cr().modify(|w| w.set_crypen(true));
         while p.sr().read().busy() {}
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(2));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(2));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(2));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -276,15 +319,29 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
     }
 
     fn prepare_key(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(7));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(7));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(7));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
         p.cr().modify(|w| w.set_crypen(true));
         while p.sr().read().busy() {}
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(5));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(5));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(5));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -318,8 +375,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
     }
 
     fn set_algomode(&self, p: &pac::cryp::Cryp) {
-        p.cr().modify(|w| w.set_algomode0(6));
-        p.cr().modify(|w| w.set_algomode3(false));
+        #[cfg(cryp_v1)]
+        {
+            p.cr().modify(|w| w.set_algomode(6));
+        }
+        #[cfg(cryp_v2)]
+        {
+            p.cr().modify(|w| w.set_algomode0(6));
+            p.cr().modify(|w| w.set_algomode3(false));
+        }
     }
 }
 
@@ -328,12 +392,14 @@ impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
 impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {}
 
+#[cfg(cryp_v2)]
 ///AES-GCM Cipher Mode
 pub struct AesGcm<'c, const KEY_SIZE: usize> {
     iv: [u8; 16],
     key: &'c [u8; KEY_SIZE],
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
     /// Constucts a new AES-GCM cipher for a cryptographic operation.
     pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
@@ -344,6 +410,7 @@ impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
     }
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
 
@@ -412,18 +479,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
     }
 }
 
+#[cfg(cryp_v2)]
 impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
+#[cfg(cryp_v2)]
 impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {}
+#[cfg(cryp_v2)]
 impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {}
 
+#[cfg(cryp_v2)]
 /// AES-GMAC Cipher Mode
 pub struct AesGmac<'c, const KEY_SIZE: usize> {
     iv: [u8; 16],
     key: &'c [u8; KEY_SIZE],
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
     /// Constructs a new AES-GMAC cipher for a cryptographic operation.
     pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
@@ -434,6 +508,7 @@ impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
     }
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
 
@@ -502,12 +577,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
     }
 }
 
+#[cfg(cryp_v2)]
 impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
+#[cfg(cryp_v2)]
 impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
+#[cfg(cryp_v2)]
 impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {}
 
+#[cfg(cryp_v2)]
 /// AES-CCM Cipher Mode
 pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> {
     key: &'c [u8; KEY_SIZE],
@@ -517,6 +598,7 @@ pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZ
     ctr: [u8; 16],
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> {
     /// Constructs a new AES-CCM cipher for a cryptographic operation.
     pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self {
@@ -580,6 +662,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes
     }
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c>
     for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE>
 {
@@ -672,24 +755,42 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
     }
 }
 
+#[cfg(cryp_v2)]
 impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {}
+#[cfg(cryp_v2)]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {}
 
+#[allow(dead_code)]
 /// Holds the state information for a cipher operation.
 /// Allows suspending/resuming of cipher operations.
 pub struct Context<'c, C: Cipher<'c> + CipherSized> {
@@ -810,6 +911,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         ctx
     }
 
+    #[cfg(cryp_v2)]
     /// Controls the header phase of cipher processing.
     /// This function is only valid for GCM, CCM, and GMAC modes.
     /// It only needs to be called if using one of these modes and there is associated data.
@@ -951,11 +1053,14 @@ impl<'d, T: Instance> Cryp<'d, T> {
         if !ctx.aad_complete && ctx.header_len > 0 {
             panic!("Additional associated data must be processed first!");
         } else if !ctx.aad_complete {
-            ctx.aad_complete = true;
-            T::regs().cr().modify(|w| w.set_crypen(false));
-            T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
-            T::regs().cr().modify(|w| w.fflush());
-            T::regs().cr().modify(|w| w.set_crypen(true));
+            #[cfg(cryp_v2)]
+            {
+                ctx.aad_complete = true;
+                T::regs().cr().modify(|w| w.set_crypen(false));
+                T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
+                T::regs().cr().modify(|w| w.fflush());
+                T::regs().cr().modify(|w| w.set_crypen(true));
+            }
         }
         if ctx.last_block_processed {
             panic!("The last block has already been processed!");
@@ -1044,6 +1149,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         self.store_context(ctx);
     }
 
+    #[cfg(cryp_v2)]
     /// This function only needs to be called for GCM, CCM, and GMAC modes to
     /// generate an authentication tag.
     pub fn finish_blocking<
@@ -1137,6 +1243,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
         ctx.iv[1] = T::regs().init(0).ivrr().read();
         ctx.iv[2] = T::regs().init(1).ivlr().read();
         ctx.iv[3] = T::regs().init(1).ivrr().read();
+
+        #[cfg(cryp_v2)]
         for i in 0..8 {
             ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read();
             ctx.csgcm[i] = T::regs().csgcmr(i).read();
@@ -1150,6 +1258,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
         T::regs().init(0).ivrr().write_value(ctx.iv[1]);
         T::regs().init(1).ivlr().write_value(ctx.iv[2]);
         T::regs().init(1).ivrr().write_value(ctx.iv[3]);
+
+        #[cfg(cryp_v2)]
         for i in 0..8 {
             T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
             T::regs().csgcmr(i).write_value(ctx.csgcm[i]);

From bf4cbd75779b230e9e33a9d2a849f67335a68cf9 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Thu, 22 Feb 2024 15:47:36 -0500
Subject: [PATCH 13/29] Add CRYP example.

---
 examples/stm32f7/Cargo.toml      |  1 +
 examples/stm32f7/src/bin/cryp.rs | 69 ++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 examples/stm32f7/src/bin/cryp.rs

diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 736e81723..305816a2b 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -30,6 +30,7 @@ embedded-storage = "0.3.1"
 static_cell = "2"
 sha2 = { version = "0.10.8", default-features = false }
 hmac = "0.12.1"
+aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
 
 [profile.release]
 debug = 2
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
new file mode 100644
index 000000000..c1b80ddc3
--- /dev/null
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -0,0 +1,69 @@
+#![no_std]
+#![no_main]
+
+use aes_gcm::{
+    aead::{heapless::Vec, AeadInPlace, KeyInit},
+    Aes128Gcm,
+};
+use defmt::info;
+use embassy_executor::Spawner;
+use embassy_stm32::cryp::*;
+use embassy_stm32::Config;
+use embassy_time::Instant;
+use {defmt_rtt as _, panic_probe as _};
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) -> ! {
+    let config = Config::default();
+    let p = embassy_stm32::init(config);
+
+    let payload: &[u8] = b"hello world";
+    let aad: &[u8] = b"additional data";
+
+    let hw_cryp = Cryp::new(p.CRYP);
+    let key: [u8; 16] = [0; 16];
+    let mut ciphertext: [u8; 11] = [0; 11];
+    let mut plaintext: [u8; 11] = [0; 11];
+    let iv: [u8; 12] = [0; 12];
+
+    let hw_start_time = Instant::now();
+
+    // Encrypt in hardware using AES-GCM 128-bit
+    let aes_gcm = AesGcm::new(&key, &iv);
+    let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt);
+    hw_cryp.aad_blocking(&mut gcm_encrypt, aad, true);
+    hw_cryp.payload_blocking(&mut gcm_encrypt, payload, &mut ciphertext, true);
+    let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
+
+    // Decrypt in hardware using AES-GCM 128-bit
+    let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt);
+    hw_cryp.aad_blocking(&mut gcm_decrypt, aad, true);
+    hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true);
+    let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt);
+
+    let hw_end_time = Instant::now();
+    let hw_execution_time = hw_end_time - hw_start_time;
+
+    info!("AES-GCM Ciphertext: {:?}", ciphertext);
+    info!("AES-GCM Plaintext: {:?}", plaintext);
+    assert_eq!(payload, plaintext);
+    assert_eq!(encrypt_tag, decrypt_tag);
+
+    let sw_start_time = Instant::now();
+
+    //Encrypt in software using AES-GCM 128-bit
+    let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap();
+    let cipher = Aes128Gcm::new(&key.into());
+    let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
+
+    //Decrypt in software using AES-GCM 128-bit
+    let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
+
+    let sw_end_time = Instant::now();
+    let sw_execution_time = sw_end_time - sw_start_time;
+
+    info!("Hardware Execution Time: {:?}", hw_execution_time);
+    info!("Software Execution Time: {:?}", sw_execution_time);
+
+    loop {}
+}

From 967b4927b002dbcdcfbe968bf9c15014fc1de2a0 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Fri, 23 Feb 2024 16:05:18 -0500
Subject: [PATCH 14/29] Correct tag generation.

---
 embassy-stm32/src/cryp/mod.rs    | 8 ++++----
 examples/stm32f7/src/bin/cryp.rs | 9 ++++++---
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 965e4a35d..038923870 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1166,10 +1166,10 @@ impl<'d, T: Instance> Cryp<'d, T> {
         T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
         T::regs().cr().modify(|w| w.set_crypen(true));
 
-        let headerlen1: u32 = (ctx.header_len >> 32) as u32;
-        let headerlen2: u32 = ctx.header_len as u32;
-        let payloadlen1: u32 = (ctx.payload_len >> 32) as u32;
-        let payloadlen2: u32 = ctx.payload_len as u32;
+        let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32;
+        let headerlen2: u32 = (ctx.header_len * 8) as u32;
+        let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
+        let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
 
         T::regs().din().write_value(headerlen1.swap_bytes());
         T::regs().din().write_value(headerlen2.swap_bytes());
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
index c1b80ddc3..be41955c5 100644
--- a/examples/stm32f7/src/bin/cryp.rs
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -51,13 +51,16 @@ async fn main(_spawner: Spawner) -> ! {
 
     let sw_start_time = Instant::now();
 
-    //Encrypt in software using AES-GCM 128-bit
+    // Encrypt in software using AES-GCM 128-bit
     let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap();
     let cipher = Aes128Gcm::new(&key.into());
     let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
+    
+    assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]);
+    assert_eq!(encrypt_tag, payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]);
 
-    //Decrypt in software using AES-GCM 128-bit
-    let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
+    // Decrypt in software using AES-GCM 128-bit
+    let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
 
     let sw_end_time = Instant::now();
     let sw_execution_time = sw_end_time - sw_start_time;

From 25ec838af597cc2e39c530b44f1a101c80b24260 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sat, 24 Feb 2024 15:55:20 -0500
Subject: [PATCH 15/29] Correct AAD ingest.

---
 embassy-stm32/src/cryp/mod.rs | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 038923870..9d1a62905 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -988,7 +988,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
-                in_word.copy_from_slice(&aad[index..index + 4]);
+                in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
                 T::regs().din().write_value(u32::from_ne_bytes(in_word));
                 index += 4;
             }
@@ -1000,14 +1000,16 @@ impl<'d, T: Instance> Cryp<'d, T> {
         ctx.aad_buffer_len = 0;
         let leftovers = aad_len_remaining % C::BLOCK_SIZE;
         ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]);
+        ctx.aad_buffer_len += leftovers;
+        ctx.aad_buffer[ctx.aad_buffer_len..].fill(0);
         aad_len_remaining -= leftovers;
         assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0);
 
         // Load full data blocks into core.
         let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE;
-        for _ in 0..num_full_blocks {
-            let mut index = len_to_copy;
-            let end_index = len_to_copy + C::BLOCK_SIZE;
+        for block in 0..num_full_blocks {
+            let mut index = len_to_copy + (block * C::BLOCK_SIZE);
+            let end_index = index + C::BLOCK_SIZE;
             // Write block in
             while index < end_index {
                 let mut in_word: [u8; 4] = [0; 4];
@@ -1020,6 +1022,19 @@ impl<'d, T: Instance> Cryp<'d, T> {
         }
 
         if last_aad_block {
+            if leftovers > 0 {
+                let mut index = 0;
+                let end_index = C::BLOCK_SIZE;
+                // Write block in
+                while index < end_index {
+                    let mut in_word: [u8; 4] = [0; 4];
+                    in_word.copy_from_slice(&ctx.aad_buffer[index..index + 4]);
+                    T::regs().din().write_value(u32::from_ne_bytes(in_word));
+                    index += 4;
+                }
+                // Block until input FIFO is empty.
+                while !T::regs().sr().read().ifem() {}
+            }
             // Switch to payload phase.
             ctx.aad_complete = true;
             T::regs().cr().modify(|w| w.set_crypen(false));
@@ -1065,7 +1080,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         if ctx.last_block_processed {
             panic!("The last block has already been processed!");
         }
-        if input.len() != output.len() {
+        if input.len() > output.len() {
             panic!("Output buffer length must match input length.");
         }
         if !last_block {

From f352b6d68b17fee886af58494b7e793cea3ea383 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sat, 24 Feb 2024 16:14:44 -0500
Subject: [PATCH 16/29] Address CI build issues.

---
 embassy-stm32/Cargo.toml         |  4 ++--
 embassy-stm32/src/cryp/mod.rs    |  7 +++----
 examples/stm32f7/src/bin/cryp.rs | 14 ++++++++------
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index d585d2cd6..4c856141b 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
 sdio-host = "0.5.0"
 critical-section = "1.1"
 #stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6097928f720646c73d6483a3245f922bd5faee2f" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ca48d946840840c5b311c96ff17cf4f8a865f9fb" }
 vcell = "0.1.3"
 bxcan = "0.7.0"
 nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
 proc-macro2 = "1.0.36"
 quote = "1.0.15"
 #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6097928f720646c73d6483a3245f922bd5faee2f", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ca48d946840840c5b311c96ff17cf4f8a865f9fb", default-features = false, features = ["metadata"]}
 
 
 [features]
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 9d1a62905..fef5def6a 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -2,12 +2,11 @@
 #[cfg(cryp_v2)]
 use core::cmp::min;
 use core::marker::PhantomData;
+
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
-use crate::pac;
-use crate::peripherals::CRYP;
 use crate::rcc::sealed::RccPeripheral;
-use crate::{interrupt, peripherals, Peripheral};
+use crate::{interrupt, pac, peripherals, Peripheral};
 
 const DES_BLOCK_SIZE: usize = 8; // 64 bits
 const AES_BLOCK_SIZE: usize = 16; // 128 bits
@@ -827,7 +826,7 @@ pub struct Cryp<'d, T: Instance> {
 impl<'d, T: Instance> Cryp<'d, T> {
     /// Create a new CRYP driver.
     pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
-        CRYP::enable_and_reset();
+        T::enable_and_reset();
         into_ref!(peri);
         let instance = Self { _peripheral: peri };
         instance
diff --git a/examples/stm32f7/src/bin/cryp.rs b/examples/stm32f7/src/bin/cryp.rs
index be41955c5..04927841a 100644
--- a/examples/stm32f7/src/bin/cryp.rs
+++ b/examples/stm32f7/src/bin/cryp.rs
@@ -1,10 +1,9 @@
 #![no_std]
 #![no_main]
 
-use aes_gcm::{
-    aead::{heapless::Vec, AeadInPlace, KeyInit},
-    Aes128Gcm,
-};
+use aes_gcm::aead::heapless::Vec;
+use aes_gcm::aead::{AeadInPlace, KeyInit};
+use aes_gcm::Aes128Gcm;
 use defmt::info;
 use embassy_executor::Spawner;
 use embassy_stm32::cryp::*;
@@ -55,9 +54,12 @@ async fn main(_spawner: Spawner) -> ! {
     let mut payload_vec: Vec<u8, 32> = Vec::from_slice(&payload).unwrap();
     let cipher = Aes128Gcm::new(&key.into());
     let _ = cipher.encrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);
-    
+
     assert_eq!(ciphertext, payload_vec[0..ciphertext.len()]);
-    assert_eq!(encrypt_tag, payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]);
+    assert_eq!(
+        encrypt_tag,
+        payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]
+    );
 
     // Decrypt in software using AES-GCM 128-bit
     let _ = cipher.decrypt_in_place(&iv.into(), aad.into(), &mut payload_vec);

From 236fc6f650af41980af05ef03a3901b2dfcfc381 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sat, 24 Feb 2024 16:31:43 -0500
Subject: [PATCH 17/29] Add CRYP test.

---
 embassy-stm32/src/cryp/mod.rs |  1 -
 tests/stm32/Cargo.toml        | 11 +++++-
 tests/stm32/src/bin/cryp.rs   | 71 +++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+), 3 deletions(-)
 create mode 100644 tests/stm32/src/bin/cryp.rs

diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index fef5def6a..bb64fa423 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -5,7 +5,6 @@ use core::marker::PhantomData;
 
 use embassy_hal_internal::{into_ref, PeripheralRef};
 
-use crate::rcc::sealed::RccPeripheral;
 use crate::{interrupt, pac, peripherals, Peripheral};
 
 const DES_BLOCK_SIZE: usize = 8; // 64 bits
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 828a28e2c..37519ba11 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -16,8 +16,8 @@ stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
 stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
 stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
 stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"]
-stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash"]
-stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash"]
+stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
+stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
 stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
 stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
 stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
@@ -33,6 +33,7 @@ stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
 stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"]
 stm32h503rb = ["embassy-stm32/stm32h503rb", "rng"]
 
+cryp = []
 hash = []
 eth = ["embassy-executor/task-arena-size-16384"]
 rng = []
@@ -80,6 +81,7 @@ portable-atomic = { version = "1.5", features = [] }
 chrono = { version = "^0.4", default-features = false, optional = true}
 sha2 = { version = "0.10.8", default-features = false }
 hmac = "0.12.1"
+aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
 
 # BEGIN TESTS
 # Generated by gen_test.py. DO NOT EDIT.
@@ -88,6 +90,11 @@ name = "can"
 path = "src/bin/can.rs"
 required-features = [ "can",]
 
+[[bin]]
+name = "cryp"
+path = "src/bin/cryp.rs"
+required-features = [ "hash",]
+
 [[bin]]
 name = "dac"
 path = "src/bin/dac.rs"
diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs
new file mode 100644
index 000000000..59c85f258
--- /dev/null
+++ b/tests/stm32/src/bin/cryp.rs
@@ -0,0 +1,71 @@
+// required-features: cryp
+#![no_std]
+#![no_main]
+
+#[path = "../common.rs"]
+mod common;
+
+use aes_gcm::aead::heapless::Vec;
+use aes_gcm::aead::{AeadInPlace, KeyInit};
+use aes_gcm::Aes128Gcm;
+use common::*;
+use embassy_executor::Spawner;
+use embassy_stm32::cryp::*;
+use {defmt_rtt as _, panic_probe as _};
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+    let p: embassy_stm32::Peripherals = embassy_stm32::init(config());
+
+    const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567";
+    const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh";
+    const AAD1: &[u8] = b"additional data 1 stdargadrhaethaethjatjatjaetjartjstrjsfkk;'jopofyuisrteytweTASTUIKFUKIXTRDTEREharhaeryhaterjartjarthaethjrtjarthaetrhartjatejatrjsrtjartjyt1";
+    const AAD2: &[u8] = b"additional data 2 stdhthsthsthsrthsrthsrtjdykjdukdyuldadfhsdghsdghsdghsadghjk'hioethjrtjarthaetrhartjatecfgjhzdfhgzdfhzdfghzdfhzdfhzfhjatrjsrtjartjytjfytjfyg";
+
+    let hw_cryp = Cryp::new(p.CRYP);
+    let key: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+    let mut ciphertext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
+    let mut plaintext: [u8; PAYLOAD1.len() + PAYLOAD2.len()] = [0; PAYLOAD1.len() + PAYLOAD2.len()];
+    let iv: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+    // Encrypt in hardware using AES-GCM 128-bit
+    let aes_gcm = AesGcm::new(&key, &iv);
+    let mut gcm_encrypt = hw_cryp.start(&aes_gcm, Direction::Encrypt);
+    hw_cryp.aad_blocking(&mut gcm_encrypt, AAD1, false);
+    hw_cryp.aad_blocking(&mut gcm_encrypt, AAD2, true);
+    hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD1, &mut ciphertext[..PAYLOAD1.len()], false);
+    hw_cryp.payload_blocking(&mut gcm_encrypt, PAYLOAD2, &mut ciphertext[PAYLOAD1.len()..], true);
+    let encrypt_tag = hw_cryp.finish_blocking(gcm_encrypt);
+
+    // Decrypt in hardware using AES-GCM 128-bit
+    let mut gcm_decrypt = hw_cryp.start(&aes_gcm, Direction::Decrypt);
+    hw_cryp.aad_blocking(&mut gcm_decrypt, AAD1, false);
+    hw_cryp.aad_blocking(&mut gcm_decrypt, AAD2, true);
+    hw_cryp.payload_blocking(&mut gcm_decrypt, &ciphertext, &mut plaintext, true);
+    let decrypt_tag = hw_cryp.finish_blocking(gcm_decrypt);
+
+    info!("AES-GCM Ciphertext: {:?}", ciphertext);
+    info!("AES-GCM Plaintext: {:?}", plaintext);
+    defmt::assert!(PAYLOAD1 == &plaintext[..PAYLOAD1.len()]);
+    defmt::assert!(PAYLOAD2 == &plaintext[PAYLOAD1.len()..]);
+    defmt::assert!(encrypt_tag == decrypt_tag);
+
+    // Encrypt in software using AES-GCM 128-bit
+    let mut payload_vec: Vec<u8, { PAYLOAD1.len() + PAYLOAD2.len() + 16 }> = Vec::from_slice(&PAYLOAD1).unwrap();
+    payload_vec.extend_from_slice(&PAYLOAD2).unwrap();
+    let cipher = Aes128Gcm::new(&key.into());
+    let mut aad: Vec<u8, { AAD1.len() + AAD2.len() }> = Vec::from_slice(&AAD1).unwrap();
+    aad.extend_from_slice(&AAD2).unwrap();
+    let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec);
+
+    defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]);
+    defmt::assert!(
+        encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]
+    );
+
+    // Decrypt in software using AES-GCM 128-bit
+    let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec);
+
+    info!("Test OK");
+    cortex_m::asm::bkpt();
+}

From d9c0da8102226cebc36c92b874b8f0bf966ac959 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sun, 25 Feb 2024 20:58:35 -0500
Subject: [PATCH 18/29] Update metapac to address CI build issue.

---
 embassy-stm32/Cargo.toml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 4c856141b..e0bee6a92 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
 sdio-host = "0.5.0"
 critical-section = "1.1"
 #stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ca48d946840840c5b311c96ff17cf4f8a865f9fb" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-88f71cbcd2f048c40bad162c7e7864cc3897eba4" }
 vcell = "0.1.3"
 bxcan = "0.7.0"
 nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
 proc-macro2 = "1.0.36"
 quote = "1.0.15"
 #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ca48d946840840c5b311c96ff17cf4f8a865f9fb", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-88f71cbcd2f048c40bad162c7e7864cc3897eba4", default-features = false, features = ["metadata"]}
 
 
 [features]

From 766372e06a413352dc07b864dd76e85e03782790 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sun, 25 Feb 2024 21:16:43 -0500
Subject: [PATCH 19/29] rustfmt

---
 tests/stm32/src/bin/cryp.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs
index 59c85f258..f105abf26 100644
--- a/tests/stm32/src/bin/cryp.rs
+++ b/tests/stm32/src/bin/cryp.rs
@@ -59,9 +59,7 @@ async fn main(_spawner: Spawner) {
     let _ = cipher.encrypt_in_place(&iv.into(), &aad, &mut payload_vec);
 
     defmt::assert!(ciphertext == payload_vec[0..ciphertext.len()]);
-    defmt::assert!(
-        encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]
-    );
+    defmt::assert!(encrypt_tag == payload_vec[ciphertext.len()..ciphertext.len() + encrypt_tag.len()]);
 
     // Decrypt in software using AES-GCM 128-bit
     let _ = cipher.decrypt_in_place(&iv.into(), &aad, &mut payload_vec);

From 54f502e5e6a355e0f132f33f3eecd2a0abe298bc Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Sun, 25 Feb 2024 21:31:25 -0500
Subject: [PATCH 20/29] Run gen_test.py

---
 tests/stm32/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 37519ba11..bfe003a11 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -93,7 +93,7 @@ required-features = [ "can",]
 [[bin]]
 name = "cryp"
 path = "src/bin/cryp.rs"
-required-features = [ "hash",]
+required-features = [ "cryp",]
 
 [[bin]]
 name = "dac"

From e954d1716a229bae94cd4739d1349a487bdaa8ae Mon Sep 17 00:00:00 2001
From: Andreas Schmidt <ndrscodes@gmail.com>
Date: Thu, 29 Feb 2024 20:27:35 +0100
Subject: [PATCH 21/29] docs: update basic example references in
 basic_application.adoc

---
 docs/modules/ROOT/pages/basic_application.adoc | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 95792d5a0..02b8981c9 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -17,15 +17,6 @@ The first thing you’ll notice are two attributes at the top of the file. These
 include::example$basic/src/main.rs[lines="1..2"]
 ----
 
-=== Rust Nightly
-
-The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly:
-
-[source,rust]
-----
-include::example$basic/src/main.rs[lines="3"]
-----
-
 === Dealing with errors
 
 Then, what follows are some declarations on how to deal with panics and faults. During development, a good practice is to rely on `defmt-rtt` and `panic-probe` to print diagnostics to the terminal:
@@ -41,7 +32,7 @@ After a bit of import declaration, the tasks run by the application should be de
 
 [source,rust]
 ----
-include::example$basic/src/main.rs[lines="12..20"]
+include::example$basic/src/main.rs[lines="10..18"]
 ----
 
 An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@@ -56,7 +47,7 @@ We then initialize the HAL with a default config, which gives us a `Peripherals`
 
 [source,rust]
 ----
-include::example$basic/src/main.rs[lines="22..-1"]
+include::example$basic/src/main.rs[lines="20..-1"]
 ----
 
 What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:

From c9cca3c007eb4b85c559f74655c6cb018d9e28f1 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Thu, 29 Feb 2024 19:09:44 -0500
Subject: [PATCH 22/29] Fix H7 CRYP operation.

---
 embassy-stm32/Cargo.toml      |   4 +-
 embassy-stm32/src/cryp/mod.rs | 159 +++++++++++++++++++++-------------
 tests/stm32/Cargo.toml        |   4 +-
 3 files changed, 103 insertions(+), 64 deletions(-)

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 08ccd35ae..460184920 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
 sdio-host = "0.5.0"
 critical-section = "1.1"
 #stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54" }
 vcell = "0.1.3"
 bxcan = "0.7.0"
 nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
 proc-macro2 = "1.0.36"
 quote = "1.0.15"
 #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a0bcec33362449fb733c066936d25cbabab396a", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]}
 
 
 [features]
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index bb64fa423..8f259520a 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1,5 +1,5 @@
 //! Crypto Accelerator (CRYP)
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 use core::cmp::min;
 use core::marker::PhantomData;
 
@@ -35,7 +35,7 @@ pub trait Cipher<'c> {
     fn init_phase(&self, _p: &pac::cryp::Cryp) {}
 
     /// Called prior to processing the last data block for cipher-specific operations.
-    fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction) -> [u32; 4] {
+    fn pre_final_block(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
         return [0; 4];
     }
 
@@ -98,7 +98,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(0));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(0));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -140,7 +140,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(1));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(1));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -182,7 +182,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(2));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(2));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -223,7 +223,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(3));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(3));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -264,7 +264,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(7));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(7));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -278,7 +278,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(2));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(2));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -321,7 +321,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(7));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(7));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -335,7 +335,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(5));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(5));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -377,7 +377,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
         {
             p.cr().modify(|w| w.set_algomode(6));
         }
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         {
             p.cr().modify(|w| w.set_algomode0(6));
             p.cr().modify(|w| w.set_algomode3(false));
@@ -390,14 +390,14 @@ impl<'c> CipherSized for AesCtr<'c, { 192 / 8 }> {}
 impl<'c> CipherSized for AesCtr<'c, { 256 / 8 }> {}
 impl<'c, const KEY_SIZE: usize> IVSized for AesCtr<'c, KEY_SIZE> {}
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 ///AES-GCM Cipher Mode
 pub struct AesGcm<'c, const KEY_SIZE: usize> {
     iv: [u8; 16],
     key: &'c [u8; KEY_SIZE],
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
     /// Constucts a new AES-GCM cipher for a cryptographic operation.
     pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
@@ -408,7 +408,7 @@ impl<'c, const KEY_SIZE: usize> AesGcm<'c, KEY_SIZE> {
     }
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
 
@@ -431,7 +431,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
         while p.cr().read().crypen() {}
     }
 
-    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] {
+    #[cfg(cryp_v2)]
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
         //Handle special GCM partial block process.
         if dir == Direction::Encrypt {
             p.cr().modify(|w| w.set_crypen(false));
@@ -444,6 +445,14 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
         [0; 4]
     }
 
+    #[cfg(cryp_v3)]
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
+        //Handle special GCM partial block process.
+        p.cr().modify(|w| w.set_npblb(padding_len as u8));
+        [0; 4]
+    }
+
+    #[cfg(cryp_v2)]
     fn post_final_block(
         &self,
         p: &pac::cryp::Cryp,
@@ -477,25 +486,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
     }
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c> CipherSized for AesGcm<'c, { 128 / 8 }> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c> CipherSized for AesGcm<'c, { 192 / 8 }> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c> CipherSized for AesGcm<'c, { 256 / 8 }> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGcm<'c, KEY_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> IVSized for AesGcm<'c, KEY_SIZE> {}
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 /// AES-GMAC Cipher Mode
 pub struct AesGmac<'c, const KEY_SIZE: usize> {
     iv: [u8; 16],
     key: &'c [u8; KEY_SIZE],
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
     /// Constructs a new AES-GMAC cipher for a cryptographic operation.
     pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; 12]) -> Self {
@@ -506,7 +515,7 @@ impl<'c, const KEY_SIZE: usize> AesGmac<'c, KEY_SIZE> {
     }
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
     const BLOCK_SIZE: usize = AES_BLOCK_SIZE;
 
@@ -529,7 +538,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
         while p.cr().read().crypen() {}
     }
 
-    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] {
+    #[cfg(cryp_v2)]
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
         //Handle special GCM partial block process.
         if dir == Direction::Encrypt {
             p.cr().modify(|w| w.set_crypen(false));
@@ -542,6 +552,14 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
         [0; 4]
     }
 
+    #[cfg(cryp_v3)]
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
+        //Handle special GCM partial block process.
+        p.cr().modify(|w| w.set_npblb(padding_len as u8));
+        [0; 4]
+    }
+
+    #[cfg(cryp_v2)]
     fn post_final_block(
         &self,
         p: &pac::cryp::Cryp,
@@ -575,18 +593,18 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
     }
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c> CipherSized for AesGmac<'c, { 128 / 8 }> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c> CipherSized for AesGmac<'c, { 192 / 8 }> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c> CipherSized for AesGmac<'c, { 256 / 8 }> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> CipherAuthenticated<16> for AesGmac<'c, KEY_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize> IVSized for AesGmac<'c, KEY_SIZE> {}
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 /// AES-CCM Cipher Mode
 pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> {
     key: &'c [u8; KEY_SIZE],
@@ -596,7 +614,7 @@ pub struct AesCcm<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZ
     ctr: [u8; 16],
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE> {
     /// Constructs a new AES-CCM cipher for a cryptographic operation.
     pub fn new(key: &'c [u8; KEY_SIZE], iv: &'c [u8; IV_SIZE], aad_len: usize, payload_len: usize) -> Self {
@@ -660,7 +678,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes
     }
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cipher<'c>
     for AesCcm<'c, KEY_SIZE, TAG_SIZE, IV_SIZE>
 {
@@ -699,7 +717,8 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
         return &self.aad_header[0..self.aad_header_len];
     }
 
-    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction) -> [u32; 4] {
+    #[cfg(cryp_v2)]
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
         //Handle special CCM partial block process.
         let mut temp1 = [0; 4];
         if dir == Direction::Decrypt {
@@ -717,6 +736,14 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
         return temp1;
     }
 
+    #[cfg(cryp_v3)]
+    fn pre_final_block(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
+        //Handle special GCM partial block process.
+        p.cr().modify(|w| w.set_npblb(padding_len as u8));
+        [0; 4]
+    }
+
+    #[cfg(cryp_v2)]
     fn post_final_block(
         &self,
         p: &pac::cryp::Cryp,
@@ -753,39 +780,39 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
     }
 }
 
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 128 / 8 }, TAG_SIZE, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 192 / 8 }, TAG_SIZE, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const TAG_SIZE: usize, const IV_SIZE: usize> CipherSized for AesCcm<'c, { 256 / 8 }, TAG_SIZE, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<4> for AesCcm<'c, KEY_SIZE, 4, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<6> for AesCcm<'c, KEY_SIZE, 6, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<8> for AesCcm<'c, KEY_SIZE, 8, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<10> for AesCcm<'c, KEY_SIZE, 10, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<12> for AesCcm<'c, KEY_SIZE, 12, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<14> for AesCcm<'c, KEY_SIZE, 14, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const IV_SIZE: usize> CipherAuthenticated<16> for AesCcm<'c, KEY_SIZE, 16, IV_SIZE> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 7> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 8> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 9> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 10> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 11> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 12> {}
-#[cfg(cryp_v2)]
+#[cfg(any(cryp_v2, cryp_v3))]
 impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize> IVSized for AesCcm<'c, KEY_SIZE, TAG_SIZE, 13> {}
 
 #[allow(dead_code)]
@@ -909,7 +936,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         ctx
     }
 
-    #[cfg(cryp_v2)]
+    #[cfg(any(cryp_v2, cryp_v3))]
     /// Controls the header phase of cipher processing.
     /// This function is only valid for GCM, CCM, and GMAC modes.
     /// It only needs to be called if using one of these modes and there is associated data.
@@ -1066,7 +1093,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         if !ctx.aad_complete && ctx.header_len > 0 {
             panic!("Additional associated data must be processed first!");
         } else if !ctx.aad_complete {
-            #[cfg(cryp_v2)]
+            #[cfg(any(cryp_v2, cryp_v3))]
             {
                 ctx.aad_complete = true;
                 T::regs().cr().modify(|w| w.set_crypen(false));
@@ -1121,7 +1148,8 @@ impl<'d, T: Instance> Cryp<'d, T> {
 
         // Handle the final block, which is incomplete.
         if last_block_remainder > 0 {
-            let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir);
+            let padding_len = C::BLOCK_SIZE - last_block_remainder;
+            let temp1 = ctx.cipher.pre_final_block(&T::regs(), ctx.dir, padding_len);
 
             let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
             let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
@@ -1162,7 +1190,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         self.store_context(ctx);
     }
 
-    #[cfg(cryp_v2)]
+    #[cfg(any(cryp_v2, cryp_v3))]
     /// This function only needs to be called for GCM, CCM, and GMAC modes to
     /// generate an authentication tag.
     pub fn finish_blocking<
@@ -1184,10 +1212,21 @@ impl<'d, T: Instance> Cryp<'d, T> {
         let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32;
         let payloadlen2: u32 = (ctx.payload_len * 8) as u32;
 
-        T::regs().din().write_value(headerlen1.swap_bytes());
-        T::regs().din().write_value(headerlen2.swap_bytes());
-        T::regs().din().write_value(payloadlen1.swap_bytes());
-        T::regs().din().write_value(payloadlen2.swap_bytes());
+        #[cfg(cryp_v2)]
+        {
+            T::regs().din().write_value(headerlen1.swap_bytes());
+            T::regs().din().write_value(headerlen2.swap_bytes());
+            T::regs().din().write_value(payloadlen1.swap_bytes());
+            T::regs().din().write_value(payloadlen2.swap_bytes());
+        }
+
+        #[cfg(cryp_v3)]
+        {
+            T::regs().din().write_value(headerlen1);
+            T::regs().din().write_value(headerlen2);
+            T::regs().din().write_value(payloadlen1);
+            T::regs().din().write_value(payloadlen2);
+        }
 
         while !T::regs().sr().read().ofne() {}
 
@@ -1257,7 +1296,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         ctx.iv[2] = T::regs().init(1).ivlr().read();
         ctx.iv[3] = T::regs().init(1).ivrr().read();
 
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         for i in 0..8 {
             ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read();
             ctx.csgcm[i] = T::regs().csgcmr(i).read();
@@ -1272,7 +1311,7 @@ impl<'d, T: Instance> Cryp<'d, T> {
         T::regs().init(1).ivlr().write_value(ctx.iv[2]);
         T::regs().init(1).ivrr().write_value(ctx.iv[3]);
 
-        #[cfg(cryp_v2)]
+        #[cfg(any(cryp_v2, cryp_v3))]
         for i in 0..8 {
             T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
             T::regs().csgcmr(i).write_value(ctx.csgcm[i]);
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index bfe003a11..3d7db2025 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -10,7 +10,7 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
 stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"]
 stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"]
 stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
-stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
+stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng", "cryp"]
 stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
 stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
 stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
@@ -18,7 +18,7 @@ stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"
 stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"]
 stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
 stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
-stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
+stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan", "cryp"]
 stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
 stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
 stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]

From 27fac380cfe05439adbe4f0256765f906e403733 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Thu, 29 Feb 2024 19:15:32 -0500
Subject: [PATCH 23/29] Remove CRYP from H7A3.

---
 tests/stm32/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 3d7db2025..c5f605565 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -18,7 +18,7 @@ stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"
 stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"]
 stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
 stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
-stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan", "cryp"]
+stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
 stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
 stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
 stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]

From 97e125872e707e96bf81cd8e601f92f0f9f688a1 Mon Sep 17 00:00:00 2001
From: Caleb Garrett <47389035+caleb-garrett@users.noreply.github.com>
Date: Thu, 29 Feb 2024 19:18:25 -0500
Subject: [PATCH 24/29] Remove CRYP from F429.

---
 tests/stm32/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index c5f605565..bfe003a11 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -10,7 +10,7 @@ stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
 stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"]
 stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"]
 stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
-stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng", "cryp"]
+stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
 stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
 stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
 stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]

From 4c0d63ce6188a340bd75388c3e772ba5d89ca8d4 Mon Sep 17 00:00:00 2001
From: Andreas Schmidt <ndrscodes@gmail.com>
Date: Fri, 1 Mar 2024 10:13:59 +0100
Subject: [PATCH 25/29] docs: update broken reference in basic_application.adoc

---
 docs/modules/ROOT/pages/basic_application.adoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 02b8981c9..d5aad806d 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -23,7 +23,7 @@ Then, what follows are some declarations on how to deal with panics and faults.
 
 [source,rust]
 ----
-include::example$basic/src/main.rs[lines="10"]
+include::example$basic/src/main.rs[lines="8"]
 ----
 
 === Task declaration

From 96af20cf5b1af90029bd5119c2f4918b844d9fc3 Mon Sep 17 00:00:00 2001
From: Siebe Claes <siebe.claes@gmail.com>
Date: Fri, 1 Mar 2024 19:15:49 +0100
Subject: [PATCH 26/29] stm32: can: fd: Fix Frame is_extended() function

---
 embassy-stm32/src/can/frame.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs
index 00a441db6..9c293035d 100644
--- a/embassy-stm32/src/can/frame.rs
+++ b/embassy-stm32/src/can/frame.rs
@@ -206,7 +206,7 @@ impl embedded_can::Frame for ClassicFrame {
     fn is_extended(&self) -> bool {
         match self.can_header.id {
             embedded_can::Id::Extended(_) => true,
-            embedded_can::Id::Standard(_) => true,
+            embedded_can::Id::Standard(_) => false,
         }
     }
     fn is_remote_frame(&self) -> bool {
@@ -369,7 +369,7 @@ impl embedded_can::Frame for FdFrame {
     fn is_extended(&self) -> bool {
         match self.can_header.id {
             embedded_can::Id::Extended(_) => true,
-            embedded_can::Id::Standard(_) => true,
+            embedded_can::Id::Standard(_) => false,
         }
     }
     fn is_remote_frame(&self) -> bool {

From 95234cddbac6f21fce0f5df510d49816f343b87d Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 26 Feb 2024 03:28:27 +0100
Subject: [PATCH 27/29] stm32: autogenerate mux config for all chips.

---
 embassy-stm32/Cargo.toml               |   4 +-
 embassy-stm32/build.rs                 | 315 +++++++++++++++----------
 embassy-stm32/src/ipcc.rs              |  19 +-
 embassy-stm32/src/rcc/c0.rs            |  34 +--
 embassy-stm32/src/rcc/f013.rs          |   6 +-
 embassy-stm32/src/rcc/f247.rs          |  10 +-
 embassy-stm32/src/rcc/g0.rs            |  63 ++---
 embassy-stm32/src/rcc/g4.rs            |  78 ++----
 embassy-stm32/src/rcc/h.rs             |  72 +-----
 embassy-stm32/src/rcc/l.rs             |  56 ++---
 embassy-stm32/src/rcc/mod.rs           |   4 +-
 embassy-stm32/src/rcc/u5.rs            |   7 +-
 embassy-stm32/src/rcc/wba.rs           |  13 +-
 embassy-stm32/src/usb_otg/usb.rs       |  14 --
 examples/stm32f334/src/bin/pwm.rs      |   2 +-
 examples/stm32g0/src/bin/hf_timer.rs   |  40 ++--
 examples/stm32g0/src/bin/usb_serial.rs |  10 +-
 examples/stm32g4/src/bin/adc.rs        |  29 ++-
 examples/stm32g4/src/bin/can.rs        |  21 +-
 examples/stm32g4/src/bin/pll.rs        |   1 +
 examples/stm32g4/src/bin/usb_serial.rs |  50 ++--
 examples/stm32h5/src/bin/can.rs        |   2 +-
 examples/stm32h5/src/bin/usb_serial.rs |   7 +-
 examples/stm32h7/src/bin/adc.rs        |   2 +-
 examples/stm32h7/src/bin/can.rs        |   2 +-
 examples/stm32h7/src/bin/dac.rs        |   2 +-
 examples/stm32h7/src/bin/dac_dma.rs    |   2 +-
 examples/stm32l4/src/bin/adc.rs        |  14 +-
 tests/stm32/src/bin/fdcan.rs           |   4 +-
 tests/stm32/src/common.rs              |  47 ++--
 30 files changed, 412 insertions(+), 518 deletions(-)

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 460184920..4bbd43c47 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
 sdio-host = "0.5.0"
 critical-section = "1.1"
 #stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" }
 vcell = "0.1.3"
 bxcan = "0.7.0"
 nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
 proc-macro2 = "1.0.36"
 quote = "1.0.15"
 #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]}
 
 
 [features]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 08c051956..84e8be25d 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -5,7 +5,9 @@ use std::{env, fs};
 
 use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
-use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA};
+use stm32_metapac::metadata::{
+    MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
+};
 
 fn main() {
     let target = env::var("TARGET").unwrap();
@@ -374,12 +376,130 @@ fn main() {
         }
     }
 
-    let force_refcount = HashSet::from(["usart"]);
-    let mut refcount_statics = BTreeSet::new();
+    struct ClockGen<'a> {
+        rcc_registers: &'a PeripheralRegisters,
+        chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
+        force_refcount: HashSet<&'a str>,
 
-    let mut clock_names = BTreeSet::new();
+        refcount_statics: BTreeSet<Ident>,
+        clock_names: BTreeSet<String>,
+        muxes: BTreeSet<(Ident, Ident, Ident)>,
+    }
 
-    let mut rcc_cfgr_regs = BTreeSet::new();
+    let mut clock_gen = ClockGen {
+        rcc_registers,
+        chained_muxes: HashMap::new(),
+        force_refcount: HashSet::from(["usart"]),
+
+        refcount_statics: BTreeSet::new(),
+        clock_names: BTreeSet::new(),
+        muxes: BTreeSet::new(),
+    };
+    if chip_name.starts_with("stm32h5") {
+        clock_gen.chained_muxes.insert(
+            "PER",
+            &PeripheralRccRegister {
+                register: "CCIPR5",
+                field: "PERSEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32h7") {
+        clock_gen.chained_muxes.insert(
+            "PER",
+            &PeripheralRccRegister {
+                register: "D1CCIPR",
+                field: "PERSEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32u5") {
+        clock_gen.chained_muxes.insert(
+            "ICLK",
+            &PeripheralRccRegister {
+                register: "CCIPR1",
+                field: "ICLKSEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") {
+        clock_gen.chained_muxes.insert(
+            "CLK48",
+            &PeripheralRccRegister {
+                register: "CCIPR",
+                field: "CLK48SEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32f7") {
+        clock_gen.chained_muxes.insert(
+            "CLK48",
+            &PeripheralRccRegister {
+                register: "DCKCFGR2",
+                field: "CLK48SEL",
+            },
+        );
+    }
+    if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") {
+        clock_gen.chained_muxes.insert(
+            "CLK48",
+            &PeripheralRccRegister {
+                register: "DCKCFGR",
+                field: "CLK48SEL",
+            },
+        );
+    }
+
+    impl<'a> ClockGen<'a> {
+        fn gen_clock(&mut self, name: &str) -> TokenStream {
+            let clock_name = format_ident!("{}", name.to_ascii_lowercase());
+            self.clock_names.insert(name.to_ascii_lowercase());
+            quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } )
+        }
+
+        fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream {
+            let ir = &self.rcc_registers.ir;
+            let fieldset_name = mux.register.to_ascii_lowercase();
+            let fieldset = ir
+                .fieldsets
+                .iter()
+                .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
+                .unwrap();
+            let field_name = mux.field.to_ascii_lowercase();
+            let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
+            let enum_name = field.enumm.unwrap();
+            let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
+
+            let fieldset_name = format_ident!("{}", fieldset_name);
+            let field_name = format_ident!("{}", field_name);
+            let enum_name = format_ident!("{}", enum_name);
+
+            self.muxes
+                .insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
+
+            let mut match_arms = TokenStream::new();
+
+            for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") {
+                let variant_name = format_ident!("{}", v.name);
+                let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
+                    self.gen_mux(mux)
+                } else {
+                    self.gen_clock(&v.name)
+                };
+                match_arms.extend(quote! {
+                    crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
+                });
+            }
+
+            quote! {
+                match crate::pac::RCC.#fieldset_name().read().#field_name() {
+                    #match_arms
+                    #[allow(unreachable_patterns)]
+                    _ => unreachable!(),
+                }
+            }
+        }
+    }
 
     for p in METADATA.peripherals {
         if !singletons.contains(&p.name.to_string()) {
@@ -416,12 +536,12 @@ fn main() {
             let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
 
             let refcount =
-                force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
+                clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
             let (before_enable, before_disable) = if refcount {
                 let refcount_static =
                     format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
 
-                refcount_statics.insert(refcount_static.clone());
+                clock_gen.refcount_statics.insert(refcount_static.clone());
 
                 (
                     quote! {
@@ -442,63 +562,12 @@ fn main() {
             };
 
             let clock_frequency = match &rcc.kernel_clock {
-                PeripheralRccKernelClock::Mux(mux) => {
-                    let ir = &rcc_registers.ir;
-                    let fieldset_name = mux.register.to_ascii_lowercase();
-                    let fieldset = ir
-                        .fieldsets
-                        .iter()
-                        .find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
-                        .unwrap();
-                    let field_name = mux.field.to_ascii_lowercase();
-                    let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
-                    let enum_name = field.enumm.unwrap();
-                    let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
-
-                    let fieldset_name = format_ident!("{}", fieldset_name);
-                    let field_name = format_ident!("{}", field_name);
-                    let enum_name = format_ident!("{}", enum_name);
-
-                    rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
-
-                    let match_arms: TokenStream = enumm
-                        .variants
-                        .iter()
-                        .filter(|v| v.name != "DISABLE")
-                        .map(|v| {
-                            let variant_name = format_ident!("{}", v.name);
-                            let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
-                            clock_names.insert(v.name.to_ascii_lowercase());
-                            quote! {
-                                #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
-                            }
-                        })
-                        .collect();
-
-                    quote! {
-                        use crate::pac::rcc::vals::#enum_name;
-
-                        #[allow(unreachable_patterns)]
-                        match crate::pac::RCC.#fieldset_name().read().#field_name() {
-                            #match_arms
-                            _ => unreachable!(),
-                        }
-                    }
-                }
-                PeripheralRccKernelClock::Clock(clock) => {
-                    let clock = clock.to_ascii_lowercase();
-                    let clock_name = format_ident!("{}", clock);
-                    clock_names.insert(clock.to_string());
-                    quote! {
-                        unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }
-                    }
-                }
+                PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux),
+                PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock),
             };
 
-            /*
-                A refcount leak can result if the same field is shared by peripherals with different stop modes
-                This condition should be checked in stm32-data
-            */
+            // A refcount leak can result if the same field is shared by peripherals with different stop modes
+            // This condition should be checked in stm32-data
             let stop_refcount = match rcc.stop_mode {
                 StopMode::Standby => None,
                 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
@@ -543,74 +612,79 @@ fn main() {
         }
     }
 
-    if !rcc_cfgr_regs.is_empty() {
-        println!("cargo:rustc-cfg=clock_mux");
+    let struct_fields: Vec<_> = clock_gen
+        .muxes
+        .iter()
+        .map(|(_fieldset, fieldname, enum_name)| {
+            quote! {
+                pub #fieldname: #enum_name
+            }
+        })
+        .collect();
 
-        let struct_fields: Vec<_> = rcc_cfgr_regs
+    let mut inits = TokenStream::new();
+    for fieldset in clock_gen
+        .muxes
+        .iter()
+        .map(|(f, _, _)| f)
+        .collect::<BTreeSet<_>>()
+        .into_iter()
+    {
+        let setters: Vec<_> = clock_gen
+            .muxes
             .iter()
-            .map(|(_fieldset, fieldname, enum_name)| {
-                quote! {
-                    pub #fieldname: Option<#enum_name>
-                }
-            })
-            .collect();
-
-        let field_names: Vec<_> = rcc_cfgr_regs
-            .iter()
-            .map(|(_fieldset, fieldname, _enum_name)| fieldname)
-            .collect();
-
-        let inits: Vec<_> = rcc_cfgr_regs
-            .iter()
-            .map(|(fieldset, fieldname, _enum_name)| {
+            .filter(|(f, _, _)| f == fieldset)
+            .map(|(_, fieldname, _)| {
                 let setter = format_ident!("set_{}", fieldname);
                 quote! {
-                    match self.#fieldname {
-                        None => {}
-                        Some(val) => {
-                            crate::pac::RCC.#fieldset()
-                                .modify(|w| w.#setter(val));
-                        }
-                    };
+                    w.#setter(self.#fieldname);
                 }
             })
             .collect();
 
-        let enum_names: BTreeSet<_> = rcc_cfgr_regs
-            .iter()
-            .map(|(_fieldset, _fieldname, enum_name)| enum_name)
-            .collect();
-
-        g.extend(quote! {
-            pub mod mux {
-                #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
-
-                #[derive(Clone, Copy)]
-                pub struct ClockMux {
-                    #( #struct_fields, )*
-                }
-
-                impl Default for ClockMux {
-                    fn default() -> Self {
-                        Self {
-                            #( #field_names: None, )*
-                        }
-                    }
-                }
-
-                impl ClockMux {
-                    pub fn init(self) {
-                        #( #inits )*
-                    }
-                }
-            }
-        });
+        inits.extend(quote! {
+            crate::pac::RCC.#fieldset().modify(|w| {
+                #(#setters)*
+            });
+        })
     }
 
+    let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect();
+
+    g.extend(quote! {
+        pub mod mux {
+            #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
+
+            #[derive(Clone, Copy)]
+            pub struct ClockMux {
+                #( #struct_fields, )*
+            }
+
+            impl ClockMux {
+                pub(crate) const fn default() -> Self {
+                    // safety: zero value is valid for all PAC enums.
+                    unsafe { ::core::mem::zeroed() }
+                }
+            }
+
+            impl Default for ClockMux {
+                fn default() -> Self {
+                    Self::default()
+                }
+            }
+
+            impl ClockMux {
+                pub(crate) fn init(&self) {
+                    #inits
+                }
+            }
+        }
+    });
+
     // Generate RCC
-    clock_names.insert("sys".to_string());
-    clock_names.insert("rtc".to_string());
-    let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect();
+    clock_gen.clock_names.insert("sys".to_string());
+    clock_gen.clock_names.insert("rtc".to_string());
+    let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
     g.extend(quote! {
         #[derive(Clone, Copy, Debug)]
         #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -640,7 +714,8 @@ fn main() {
         }
     );
 
-    let refcount_mod: TokenStream = refcount_statics
+    let refcount_mod: TokenStream = clock_gen
+        .refcount_statics
         .iter()
         .map(|refcount_static| {
             quote! {
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 663a7f59d..523719bb9 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -7,7 +7,6 @@ use core::task::Poll;
 use self::sealed::Instance;
 use crate::interrupt;
 use crate::interrupt::typelevel::Interrupt;
-use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel};
 use crate::peripherals::IPCC;
 use crate::rcc::sealed::RccPeripheral;
 
@@ -105,7 +104,8 @@ impl Ipcc {
         IPCC::enable_and_reset();
         IPCC::set_cpu2(true);
 
-        _configure_pwr();
+        // set RF wake-up clock = LSE
+        crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
 
         let regs = IPCC::regs();
 
@@ -271,18 +271,3 @@ pub(crate) mod sealed {
         fn state() -> &'static State;
     }
 }
-
-fn _configure_pwr() {
-    // TODO: move the rest of this to rcc
-    let rcc = crate::pac::RCC;
-
-    // TODO: required
-    // set RF wake-up clock = LSE
-    rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
-
-    // set LPTIM1 & LPTIM2 clock source
-    rcc.ccipr().modify(|w| {
-        w.set_lptim1sel(Lptim1sel::PCLK1);
-        w.set_lptim2sel(Lptim2sel::PCLK1);
-    });
-}
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index ec6ec34e8..1946c5a15 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -21,6 +21,9 @@ pub struct Config {
     pub ahb_pre: AHBPrescaler,
     pub apb_pre: APBPrescaler,
     pub ls: super::LsConfig,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -31,6 +34,7 @@ impl Default for Config {
             ahb_pre: AHBPrescaler::DIV1,
             apb_pre: APBPrescaler::DIV1,
             ls: Default::default(),
+            mux: Default::default(),
         }
     }
 }
@@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) {
 
     if !set_flash_latency_after {
         // Spin until the effective flash latency is compatible with the clock change
-        while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
+        while FLASH.acr().read().latency() < target_flash_latency {}
     }
 
     // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
-    let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
     RCC.cfgr().modify(|w| {
         w.set_sw(sw);
-        w.set_hpre(hpre);
-        w.set_ppre(ppre);
+        w.set_hpre(config.ahb_pre);
+        w.set_ppre(config.apb_pre);
     });
-
-    if set_flash_latency_after {
-        // We can make the flash require fewer wait states
-        // Spin until the SYSCLK changes have taken effect
-        loop {
-            let cfgr = RCC.cfgr().read();
-            if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
-                break;
-            }
+    // Spin until the SYSCLK changes have taken effect
+    loop {
+        let cfgr = RCC.cfgr().read();
+        if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre {
+            break;
         }
+    }
 
-        // Set the flash latency to require fewer wait states
+    // Set the flash latency to require fewer wait states
+    if set_flash_latency_after {
         FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
     }
 
@@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) {
         }
     };
 
+    config.mux.init();
+
+    // without this, the ringbuffered uart test fails.
+    cortex_m::asm::dsb();
+
     set_clocks!(
         hsi: None,
         lse: None,
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 5046f0a3a..215f8a3d2 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -98,8 +98,8 @@ pub struct Config {
     #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
     pub adc34: AdcClockSource,
 
-    #[cfg(clock_mux)]
-    pub mux: crate::rcc::mux::ClockMux,
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 
     pub ls: super::LsConfig,
 }
@@ -128,7 +128,6 @@ impl Default for Config {
             #[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
             adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
 
-            #[cfg(clock_mux)]
             mux: Default::default(),
         }
     }
@@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) {
     };
      */
 
-    #[cfg(clock_mux)]
     config.mux.init();
 
     set_clocks!(
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 343d075cd..7b252870c 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -95,6 +95,9 @@ pub struct Config {
 
     pub ls: super::LsConfig,
 
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
+
     #[cfg(stm32f2)]
     pub voltage: VoltageScale,
 }
@@ -120,6 +123,7 @@ impl Default for Config {
 
             #[cfg(stm32f2)]
             voltage: VoltageScale::Range3,
+            mux: Default::default(),
         }
     }
 }
@@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) {
     });
     while RCC.cfgr().read().sws() != config.sys {}
 
+    config.mux.init();
+
     set_clocks!(
         hsi: hsi,
         hse: hse,
@@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) {
         #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
         pllsai1_r: pllsai.r,
 
-        clk48: pll.q,
+        // TODO workaround until f4 rcc is fixed in stm32-data
+        #[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))]
+        pllsai1_q: None,
 
         hsi_div488: hsi.map(|hsi| hsi/488u32),
         hsi_hse: None,
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index ae502dd9c..5cfe9953b 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -71,22 +71,6 @@ pub enum PllSource {
     HSE(Hertz, HseMode),
 }
 
-/// Sets the source for the 48MHz clock to the USB peripheral.
-#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-pub enum UsbSrc {
-    /// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the
-    /// oscillator to comply with the USB specification for oscillator tolerance.
-    #[cfg(any(stm32g0b1, stm32g0c1))]
-    Hsi48(super::Hsi48Config),
-    /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The
-    /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
-    /// tolerance.
-    PllQ,
-    /// Use the HSE source directly.  The HSE must be a 48MHz source.  The HSE source must comply
-    /// with the USB specification for oscillator tolerance.
-    HSE,
-}
-
 /// Clocks configutation
 pub struct Config {
     pub sys: Sysclk,
@@ -94,8 +78,10 @@ pub struct Config {
     pub apb_pre: APBPrescaler,
     pub low_power_run: bool,
     pub ls: super::LsConfig,
-    #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-    pub usb_src: Option<UsbSrc>,
+    #[cfg(crs)]
+    pub hsi48: Option<super::Hsi48Config>,
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -107,8 +93,9 @@ impl Default for Config {
             apb_pre: APBPrescaler::DIV1,
             low_power_run: false,
             ls: Default::default(),
-            #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-            usb_src: None,
+            #[cfg(crs)]
+            hsi48: Some(Default::default()),
+            mux: Default::default(),
         }
     }
 }
@@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) {
     let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ);
     let hse_freq = (sw == Sw::HSE).then_some(sys_clk);
 
-    #[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
-    let hsi48_freq = config.usb_src.and_then(|config| {
-        match config {
-            UsbSrc::PllQ => {
-                // Make sure the PLLQ is enabled and running at 48Mhz
-                assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000);
-                RCC.ccipr2()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q));
-                None
-            }
-            UsbSrc::HSE => {
-                // Make sure the HSE is enabled and running at 48Mhz
-                assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000);
-                RCC.ccipr2()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE));
-                None
-            }
-            #[cfg(any(stm32g0b1, stm32g0c1))]
-            UsbSrc::Hsi48(config) => {
-                let freq = super::init_hsi48(config);
-                RCC.ccipr2()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48));
-                Some(freq)
-            }
-        }
-    });
-    #[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))]
-    let hsi48_freq: Option<Hertz> = None;
+    #[cfg(crs)]
+    let hsi48 = config.hsi48.map(super::init_hsi48);
+    #[cfg(not(crs))]
+    let hsi48: Option<Hertz> = None;
+
+    config.mux.init();
 
     set_clocks!(
         sys: Some(sys_clk),
@@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
         pclk1: Some(apb_freq),
         pclk1_tim: Some(apb_tim_freq),
         hsi: hsi_freq,
-        hsi48: hsi48_freq,
+        hsi48: hsi48,
         hsi_div_8: hsi_div_8_freq,
         hse: hse_freq,
         lse: lse_freq,
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 6ed266284..79bdbeb77 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,11 +1,10 @@
 use stm32_metapac::flash::vals::Latency;
-use stm32_metapac::rcc::vals::{Adcsel, Sw};
+use stm32_metapac::rcc::vals::Sw;
 use stm32_metapac::FLASH;
 
 pub use crate::pac::rcc::vals::{
-    Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler,
-    Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler,
-    Sw as Sysclk,
+    Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc,
+    Ppre as APBPrescaler, Sw as Sysclk,
 };
 use crate::pac::{PWR, RCC};
 use crate::time::Hertz;
@@ -82,24 +81,15 @@ pub struct Config {
 
     pub low_power_run: bool,
 
-    /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
-    pub clk48_src: Clk48Src,
-
     /// Low-Speed Clock Configuration
     pub ls: super::LsConfig,
 
-    /// Clock Source for ADCs 1 and 2
-    pub adc12_clock_source: AdcClockSource,
-
-    /// Clock Source for ADCs 3, 4 and 5
-    pub adc345_clock_source: AdcClockSource,
-
-    /// Clock Source for FDCAN
-    pub fdcan_clock_source: FdCanClockSource,
-
     /// Enable range1 boost mode
     /// Recommended when the SYSCLK frequency is greater than 150MHz.
     pub boost: bool,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -115,12 +105,9 @@ impl Default for Config {
             apb1_pre: APBPrescaler::DIV1,
             apb2_pre: APBPrescaler::DIV1,
             low_power_run: false,
-            clk48_src: Clk48Src::HSI48,
             ls: Default::default(),
-            adc12_clock_source: Adcsel::DISABLE,
-            adc345_clock_source: Adcsel::DISABLE,
-            fdcan_clock_source: FdCanClockSource::PCLK1,
             boost: false,
+            mux: Default::default(),
         }
     }
 }
@@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) {
     };
 
     // Configure HSI48 if required
-    if let Some(hsi48_config) = config.hsi48 {
-        super::init_hsi48(hsi48_config);
-    }
+    let hsi48 = config.hsi48.map(super::init_hsi48);
 
     let pll_freq = config.pll.map(|pll_config| {
         let src_freq = match pll_config.source {
@@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) {
             _ => unreachable!(),
         };
 
-        assert!(max::PLL_IN.contains(&src_freq));
-
         // Disable PLL before configuration
         RCC.cr().modify(|w| w.set_pllon(false));
         while RCC.cr().read().pllrdy() {}
 
-        let internal_freq = src_freq / pll_config.prediv * pll_config.mul;
+        let in_freq = src_freq / pll_config.prediv;
+        assert!(max::PLL_IN.contains(&in_freq));
+        let internal_freq = in_freq * pll_config.mul;
 
         assert!(max::PLL_VCO.contains(&internal_freq));
 
@@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) {
     let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
     let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
 
-    // Configure the 48MHz clock source for USB and RNG peripherals.
-    RCC.ccipr().modify(|w| {
-        w.set_clk48sel(match config.clk48_src {
-            Clk48Src::PLL1_Q => {
-                // Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock.
-                // Peripherals which require one (USB, RNG) should check that they‘re driven by a valid 48MHz
-                // clock at init.
-                crate::pac::rcc::vals::Clk48sel::PLL1_Q
-            }
-            Clk48Src::HSI48 => {
-                // Make sure HSI48 is enabled
-                assert!(config.hsi48.is_some());
-                crate::pac::rcc::vals::Clk48sel::HSI48
-            }
-            _ => unreachable!(),
-        })
-    });
-
-    RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
-    RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
-    RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
-
-    let adc12_ck = match config.adc12_clock_source {
-        AdcClockSource::DISABLE => None,
-        AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
-        AdcClockSource::SYS => Some(sys_clk),
-        _ => unreachable!(),
-    };
-
-    let adc345_ck = match config.adc345_clock_source {
-        AdcClockSource::DISABLE => None,
-        AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
-        AdcClockSource::SYS => Some(sys_clk),
-        _ => unreachable!(),
-    };
-
     if config.low_power_run {
         assert!(sys_clk <= Hertz(2_000_000));
         PWR.cr1().modify(|w| w.set_lpr(true));
@@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) {
 
     let rtc = config.ls.init();
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys_clk),
         hclk1: Some(hclk),
@@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) {
         pclk1_tim: Some(apb1_tim_freq),
         pclk2: Some(apb2_freq),
         pclk2_tim: Some(apb2_tim_freq),
-        adc: adc12_ck,
-        adc34: adc345_ck,
         pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p),
         pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q),
         pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r),
         hse: hse,
+        hsi48: hsi48,
         rtc: rtc,
     );
 }
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 7b2255cc6..bab8bb19e 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -2,15 +2,10 @@ use core::ops::RangeInclusive;
 
 use crate::pac;
 use crate::pac::pwr::vals::Vos;
-#[cfg(stm32h5)]
-pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
-#[cfg(stm32h7)]
-pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
 pub use crate::pac::rcc::vals::{
-    Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv,
-    Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
+    Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
 };
-use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
+use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre};
 use crate::pac::{FLASH, PWR, RCC};
 use crate::time::Hertz;
 
@@ -194,16 +189,15 @@ pub struct Config {
     #[cfg(stm32h7)]
     pub apb4_pre: APBPrescaler,
 
-    pub per_clock_source: PerClockSource,
-    pub adc_clock_source: AdcClockSource,
-    pub fdcan_clock_source: FdCanClockSource,
-
     pub timer_prescaler: TimerPrescaler,
     pub voltage_scale: VoltageScale,
     pub ls: super::LsConfig,
 
     #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
     pub supply_config: SupplyConfig,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -227,21 +221,14 @@ impl Default for Config {
             #[cfg(stm32h7)]
             apb4_pre: APBPrescaler::DIV1,
 
-            per_clock_source: PerClockSource::HSI,
-
-            #[cfg(stm32h5)]
-            adc_clock_source: AdcClockSource::HCLK1,
-            #[cfg(stm32h7)]
-            adc_clock_source: AdcClockSource::PER,
-
-            fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
-
             timer_prescaler: TimerPrescaler::DefaultX2,
             voltage_scale: VoltageScale::Scale0,
             ls: Default::default(),
 
             #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
             supply_config: SupplyConfig::Default,
+
+            mux: Default::default(),
         }
     }
 }
@@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) {
     #[cfg(stm32h7)]
     assert!(apb4 <= pclk_max);
 
-    let _per_ck = match config.per_clock_source {
-        Ckpersel::HSI => hsi,
-        Ckpersel::CSI => csi,
-        Ckpersel::HSE => hse,
-        _ => unreachable!(),
-    };
-
-    #[cfg(stm32h7)]
-    let adc = match config.adc_clock_source {
-        AdcClockSource::PLL2_P => pll2.p,
-        AdcClockSource::PLL3_R => pll3.r,
-        AdcClockSource::PER => _per_ck,
-        _ => unreachable!(),
-    };
-    #[cfg(stm32h5)]
-    let adc = match config.adc_clock_source {
-        AdcClockSource::HCLK1 => Some(hclk),
-        AdcClockSource::SYS => Some(sys),
-        AdcClockSource::PLL2_R => pll2.r,
-        AdcClockSource::HSE => hse,
-        AdcClockSource::HSI => hsi,
-        AdcClockSource::CSI => csi,
-        _ => unreachable!(),
-    };
-
     flash_setup(hclk, config.voltage_scale);
 
     let rtc = config.ls.init();
@@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) {
         RCC.d3cfgr().modify(|w| {
             w.set_d3ppre(config.apb4_pre);
         });
-
-        RCC.d1ccipr().modify(|w| {
-            w.set_ckpersel(config.per_clock_source);
-        });
-        RCC.d3ccipr().modify(|w| {
-            w.set_adcsel(config.adc_clock_source);
-        });
-        RCC.d2ccip1r().modify(|w| {
-            w.set_fdcansel(config.fdcan_clock_source);
-        });
     }
     #[cfg(stm32h5)]
     {
@@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) {
             w.set_ppre2(config.apb2_pre);
             w.set_ppre3(config.apb3_pre);
         });
-
-        RCC.ccipr5().modify(|w| {
-            w.set_ckpersel(config.per_clock_source);
-            w.set_adcdacsel(config.adc_clock_source);
-            w.set_fdcan12sel(config.fdcan_clock_source)
-        });
     }
 
     RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
@@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) {
         while !pac::SYSCFG.cccsr().read().ready() {}
     }
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys),
         hclk1: Some(hclk),
@@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) {
         pclk4: Some(apb4),
         pclk1_tim: Some(apb1_tim),
         pclk2_tim: Some(apb2_tim),
-        adc: adc,
         rtc: rtc,
 
         hsi: hsi,
@@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) {
 
         #[cfg(stm32h5)]
         audioclk: None,
-        per: None,
         i2s_ckin: None,
     );
 }
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index aa4245d4e..9079ddd41 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -1,10 +1,6 @@
 #[cfg(any(stm32l0, stm32l1))]
 pub use crate::pac::pwr::vals::Vos as VoltageScale;
 use crate::pac::rcc::regs::Cfgr;
-#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
-#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
 #[cfg(any(stm32wb, stm32wl))]
 pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
 pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk};
@@ -59,18 +55,14 @@ pub struct Config {
     #[cfg(any(stm32wl, stm32wb))]
     pub shared_ahb_pre: AHBPrescaler,
 
-    // muxes
-    #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-    pub clk48_src: Clk48Src,
-
     // low speed LSI/LSE/RTC
     pub ls: super::LsConfig,
 
-    #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-    pub adc_clock_source: AdcClockSource,
-
     #[cfg(any(stm32l0, stm32l1))]
     pub voltage_scale: VoltageScale,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -95,13 +87,10 @@ impl Default for Config {
             pllsai2: None,
             #[cfg(crs)]
             hsi48: Some(Default::default()),
-            #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-            clk48_src: Clk48Src::HSI48,
             ls: Default::default(),
-            #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-            adc_clock_source: AdcClockSource::SYS,
             #[cfg(any(stm32l0, stm32l1))]
             voltage_scale: VoltageScale::RANGE1,
+            mux: Default::default(),
         }
     }
 }
@@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config {
     hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
     msi: None,
     hsi: false,
-    clk48_src: Clk48Src::PLL1_Q,
 
     ls: super::LsConfig::default_lse(),
 
@@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config {
     shared_ahb_pre: AHBPrescaler::DIV1,
     apb1_pre: APBPrescaler::DIV1,
     apb2_pre: APBPrescaler::DIV1,
-    adc_clock_source: AdcClockSource::SYS,
+
+    mux: super::mux::ClockMux::default(),
 };
 
 fn msi_enable(range: MSIRange) {
@@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) {
         Sysclk::PLL1_R => pll.r.unwrap(),
     };
 
-    #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-    RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
-    #[cfg(any(rcc_l0_v2))]
-    let clk48 = match config.clk48_src {
-        Clk48Src::HSI48 => hsi48,
-        Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
-    };
-    #[cfg(any(stm32l4, stm32l5, stm32wb))]
-    let clk48 = match config.clk48_src {
-        Clk48Src::HSI48 => hsi48,
-        Clk48Src::MSI => msi,
-        Clk48Src::PLLSAI1_Q => pllsai1.q,
-        Clk48Src::PLL1_Q => pll.q,
-    };
-
     #[cfg(rcc_l4plus)]
     assert!(sys_clk.0 <= 120_000_000);
     #[cfg(all(stm32l4, not(rcc_l4plus)))]
@@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) {
     });
     while RCC.cfgr().read().sws() != config.sys {}
 
-    #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
-    RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source));
-
     #[cfg(any(stm32wl, stm32wb))]
     {
         RCC.extcfgr().modify(|w| {
@@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) {
         while !RCC.extcfgr().read().c2hpref() {}
     }
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys_clk),
         hclk1: Some(hclk1),
@@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) {
         hsi: hsi,
         hse: hse,
         msi: msi,
-        #[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
-        clk48: clk48,
         hsi48: hsi48,
 
+        #[cfg(any(stm32l0, stm32l1))]
+        pll1_vco_div_2: pll.vco.map(|c| c/2u32),
+
         #[cfg(not(any(stm32l0, stm32l1)))]
         pll1_p: pll.p,
         #[cfg(not(any(stm32l0, stm32l1)))]
@@ -511,7 +485,7 @@ mod pll {
     #[derive(Default)]
     pub(super) struct PllOutput {
         pub r: Option<Hertz>,
-        pub clk48: Option<Hertz>,
+        pub vco: Option<Hertz>,
     }
 
     pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
@@ -528,7 +502,6 @@ mod pll {
         let vco_freq = pll_src * pll.mul;
 
         let r = vco_freq / pll.div;
-        let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000));
 
         assert!(r <= Hertz(32_000_000));
 
@@ -541,7 +514,10 @@ mod pll {
         // Enable PLL
         pll_enable(instance, true);
 
-        PllOutput { r: Some(r), clk48 }
+        PllOutput {
+            r: Some(r),
+            vco: Some(vco_freq),
+        }
     }
 }
 
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c8ca713de..910ebe205 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -31,9 +31,7 @@ mod _version;
 
 pub use _version::*;
 
-#[cfg(clock_mux)]
-pub use crate::_generated::mux;
-pub use crate::_generated::Clocks;
+pub use crate::_generated::{mux, Clocks};
 
 #[cfg(feature = "low-power")]
 /// Must be written within a critical section
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index c8814ed69..9533e16c4 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -85,6 +85,9 @@ pub struct Config {
     /// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
     pub voltage_range: VoltageScale,
     pub ls: super::LsConfig,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -104,6 +107,7 @@ impl Default for Config {
             apb3_pre: APBPrescaler::DIV1,
             voltage_range: VoltageScale::RANGE1,
             ls: Default::default(),
+            mux: Default::default(),
         }
     }
 }
@@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) {
 
     let rtc = config.ls.init();
 
+    config.mux.init();
+
     set_clocks!(
         sys: Some(sys_clk),
         hclk1: Some(hclk),
@@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) {
         lse: None,
         lsi: None,
         msik: None,
-        iclk: None,
         shsi: None,
         shsi_div_2: None,
     );
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 9d5dcfc4b..8e1779d7c 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -1,8 +1,6 @@
 pub use crate::pac::pwr::vals::Vos as VoltageScale;
 use crate::pac::rcc::regs::Cfgr1;
-pub use crate::pac::rcc::vals::{
-    Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk,
-};
+pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk};
 use crate::pac::{FLASH, RCC};
 use crate::time::Hertz;
 
@@ -32,9 +30,10 @@ pub struct Config {
     // low speed LSI/LSE/RTC
     pub ls: super::LsConfig,
 
-    pub adc_clock_source: AdcClockSource,
-
     pub voltage_scale: VoltageScale,
+
+    /// Per-peripheral kernel clock selection muxes
+    pub mux: super::mux::ClockMux,
 }
 
 impl Default for Config {
@@ -49,8 +48,8 @@ impl Default for Config {
             apb2_pre: APBPrescaler::DIV1,
             apb7_pre: APBPrescaler::DIV1,
             ls: Default::default(),
-            adc_clock_source: AdcClockSource::HCLK4,
             voltage_scale: VoltageScale::RANGE2,
+            mux: Default::default(),
         }
     }
 }
@@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) {
         w.set_ppre2(config.apb2_pre);
     });
 
-    RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
+    config.mux.init();
 
     set_clocks!(
         sys: Some(sys_clk),
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 190fb274f..373697ec8 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> {
             // Wait for USB power to stabilize
             while !crate::pac::PWR.cr3().read().usb33rdy() {}
 
-            // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
-            critical_section::with(|_| {
-                crate::pac::RCC
-                    .d2ccip2r()
-                    .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
-            });
-
             // Enable ULPI clock if external PHY is used
             let ulpien = !self.phy_type.internal();
             critical_section::with(|_| {
@@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> {
 
             // Wait for USB power to stabilize
             while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
-
-            // Select HSI48 as USB clock source.
-            critical_section::with(|_| {
-                crate::pac::RCC.ccipr1().modify(|w| {
-                    w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
-                })
-            });
         }
 
         <T as RccPeripheral>::enable_and_reset();
diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs
index 7c6d6cd71..e6d1a6c02 100644
--- a/examples/stm32f334/src/bin/pwm.rs
+++ b/examples/stm32f334/src/bin/pwm.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb1_pre = APBPrescaler::DIV2;
         config.rcc.apb2_pre = APBPrescaler::DIV1;
 
-        config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P);
+        config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P;
     }
     let p = embassy_stm32::init(config);
 
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 3f63d0dfd..647ff0419 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -4,37 +4,35 @@
 use defmt::info;
 use embassy_executor::Spawner;
 use embassy_stm32::gpio::OutputType;
-use embassy_stm32::pac::rcc::vals::Tim1sel;
-use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk};
 use embassy_stm32::time::khz;
 use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
 use embassy_stm32::timer::simple_pwm::PwmPin;
 use embassy_stm32::timer::Channel;
-use embassy_stm32::{pac, Config as PeripheralConfig};
+use embassy_stm32::Config as PeripheralConfig;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
-    let mut rcc_config = RccConfig::default();
-    rcc_config.sys = Sysclk::PLL(PllConfig {
-        source: PllSource::HSI,
-        m: Pllm::DIV1,
-        n: Plln::MUL16,
-        r: Pllr::DIV4,       // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
-        q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
-        p: None,
-    });
+    let mut config = PeripheralConfig::default();
+    {
+        use embassy_stm32::rcc::*;
 
-    let mut peripheral_config = PeripheralConfig::default();
-    peripheral_config.rcc = rcc_config;
+        config.rcc.sys = Sysclk::PLL(PllConfig {
+            source: PllSource::HSI,
+            m: Pllm::DIV1,
+            n: Plln::MUL16,
+            r: Pllr::DIV4,       // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
+            q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
+            p: None,
+        });
 
-    let p = embassy_stm32::init(peripheral_config);
-
-    // configure TIM1 mux to select PLLQ as clock source
-    // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
-    // RM0444 page 210
-    // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
-    pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q));
+        // configure TIM1 mux to select PLLQ as clock source
+        // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
+        // RM0444 page 210
+        // RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
+        config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q;
+    }
+    let p = embassy_stm32::init(config);
 
     let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
     let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);
diff --git a/examples/stm32g0/src/bin/usb_serial.rs b/examples/stm32g0/src/bin/usb_serial.rs
index f5aaa5624..8b9915626 100644
--- a/examples/stm32g0/src/bin/usb_serial.rs
+++ b/examples/stm32g0/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
 use defmt::{panic, *};
 use embassy_executor::Spawner;
 use embassy_futures::join::join;
-use embassy_stm32::rcc::{Hsi48Config, UsbSrc};
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-    config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config {
-        sync_from_usb: true,
-        ..Default::default()
-    }));
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
+        config.rcc.mux.usbsel = mux::Usbsel::HSI48;
+    }
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index 6c6de1ffe..f81335f93 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -4,7 +4,6 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::adc::{Adc, SampleTime};
-use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
 use embassy_stm32::Config;
 use embassy_time::{Delay, Timer};
 use {defmt_rtt as _, panic_probe as _};
@@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _};
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-
-    config.rcc.pll = Some(Pll {
-        source: Pllsrc::HSI,
-        prediv: PllPreDiv::DIV4,
-        mul: PllMul::MUL85,
-        divp: None,
-        divq: None,
-        // Main system clock at 170 MHz
-        divr: Some(PllRDiv::DIV2),
-    });
-
-    config.rcc.adc12_clock_source = AdcClockSource::SYS;
-    config.rcc.sys = Sysclk::PLL1_R;
-
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSI,
+            prediv: PllPreDiv::DIV4,
+            mul: PllMul::MUL85,
+            divp: None,
+            divq: None,
+            // Main system clock at 170 MHz
+            divr: Some(PllRDiv::DIV2),
+        });
+        config.rcc.mux.adc12sel = mux::Adcsel::SYS;
+        config.rcc.sys = Sysclk::PLL1_R;
+    }
     let mut p = embassy_stm32::init(config);
     info!("Hello World!");
 
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index a41f765c1..7551b2a55 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -3,6 +3,7 @@
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_stm32::peripherals::*;
+use embassy_stm32::time::Hertz;
 use embassy_stm32::{bind_interrupts, can, Config};
 use embassy_time::Timer;
 use static_cell::StaticCell;
@@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs {
 
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
-    let config = Config::default();
-
+    let mut config = Config::default();
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(24_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSE,
+            prediv: PllPreDiv::DIV6,
+            mul: PllMul::MUL85,
+            divp: None,
+            divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
+            divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
+        });
+        config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
+        config.rcc.sys = Sysclk::PLL1_R;
+    }
     let peripherals = embassy_stm32::init(config);
 
     let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 5274de79d..2609abfa2 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -12,6 +12,7 @@ use {defmt_rtt as _, panic_probe as _};
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
 
+    config.rcc.hsi = true;
     config.rcc.pll = Some(Pll {
         source: Pllsrc::HSI,
         prediv: PllPreDiv::DIV4,
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 989fef5b0..90caaae14 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -3,9 +3,6 @@
 
 use defmt::{panic, *};
 use embassy_executor::Spawner;
-use embassy_stm32::rcc::{
-    Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk,
-};
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{self, Driver, Instance};
 use embassy_stm32::{bind_interrupts, peripherals, Config};
@@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs {
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let mut config = Config::default();
-
-    // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
-    const USE_HSI48: bool = true;
-
-    let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) };
-
-    config.rcc.hse = Some(Hse {
-        freq: Hertz(8_000_000),
-        mode: HseMode::Oscillator,
-    });
-
-    config.rcc.pll = Some(Pll {
-        source: Pllsrc::HSE,
-        prediv: PllPreDiv::DIV2,
-        mul: PllMul::MUL72,
-        divp: None,
-        divq: plldivq,
-        // Main system clock at 144 MHz
-        divr: Some(PllRDiv::DIV2),
-    });
-
-    config.rcc.sys = Sysclk::PLL1_R;
-    config.rcc.boost = true; // BOOST!
-
-    if USE_HSI48 {
+    {
+        use embassy_stm32::rcc::*;
         // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
         config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
-        config.rcc.clk48_src = Clk48Src::HSI48;
-    } else {
-        config.rcc.clk48_src = Clk48Src::PLL1_Q;
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(8_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSE,
+            prediv: PllPreDiv::DIV2,
+            mul: PllMul::MUL72,
+            divp: None,
+            divq: Some(PllQDiv::DIV6), // 48mhz
+            divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz
+        });
+        config.rcc.sys = Sysclk::PLL1_R;
+        config.rcc.boost = true; // BOOST!
+        config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
+        //config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead.
     }
-
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs
index e5ccfe4f7..643df27f9 100644
--- a/examples/stm32h5/src/bin/can.rs
+++ b/examples/stm32h5/src/bin/can.rs
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE;
 
     let peripherals = embassy_stm32::init(config);
 
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
index 208493d8c..83477c8fa 100644
--- a/examples/stm32h5/src/bin/usb_serial.rs
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -5,7 +5,7 @@ use defmt::{panic, *};
 use embassy_executor::Spawner;
 use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{Driver, Instance};
-use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
+use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
 use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::Builder;
@@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb3_pre = APBPrescaler::DIV4;
         config.rcc.sys = Sysclk::PLL1_P;
         config.rcc.voltage_scale = VoltageScale::Scale0;
+        config.rcc.mux.usbsel = mux::Usbsel::HSI48;
     }
     let p = embassy_stm32::init(config);
 
     info!("Hello World!");
 
-    pac::RCC.ccipr4().write(|w| {
-        w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
-    });
-
     // Create the driver, from the HAL.
     let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
 
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index f0278239f..a5594d10c 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
     let mut p = embassy_stm32::init(config);
 
diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs
index e5ccfe4f7..13a6a5051 100644
--- a/examples/stm32h7/src/bin/can.rs
+++ b/examples/stm32h7/src/bin/can.rs
@@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
 
     let peripherals = embassy_stm32::init(config);
 
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index a9bf46de0..a6f969aba 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -40,7 +40,7 @@ fn main() -> ! {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
     let p = embassy_stm32::init(config);
 
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index d88bd838f..feec28993 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
 
     // Initialize the board and obtain a Peripherals instance
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 910944673..a9f4604aa 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -3,7 +3,7 @@
 
 use defmt::*;
 use embassy_stm32::adc::{Adc, Resolution};
-use embassy_stm32::pac;
+use embassy_stm32::Config;
 use embassy_time::Delay;
 use {defmt_rtt as _, panic_probe as _};
 
@@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _};
 fn main() -> ! {
     info!("Hello World!");
 
-    pac::RCC.ccipr().modify(|w| {
-        w.set_adcsel(pac::rcc::vals::Adcsel::SYS);
-    });
-    pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
-
-    let p = embassy_stm32::init(Default::default());
+    let mut config = Config::default();
+    {
+        use embassy_stm32::rcc::*;
+        config.rcc.mux.adcsel = mux::Adcsel::SYS;
+    }
+    let p = embassy_stm32::init(config);
 
     let mut adc = Adc::new(p.ADC1, &mut Delay);
     //adc.enable_vref();
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index f21aa797c..dd78d7fb3 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -33,7 +33,7 @@ fn options() -> TestOptions {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
     TestOptions {
         config: c,
         max_latency: Duration::from_micros(1200),
@@ -50,7 +50,7 @@ fn options() -> TestOptions {
         freq: embassy_stm32::time::Hertz(25_000_000),
         mode: rcc::HseMode::Oscillator,
     });
-    c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
+    c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
     TestOptions {
         config: c,
         max_latency: Duration::from_micros(1200),
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 7b9585afd..cf3e04a4b 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -2,6 +2,8 @@
 
 pub use defmt::*;
 #[allow(unused)]
+use embassy_stm32::rcc::*;
+#[allow(unused)]
 use embassy_stm32::time::Hertz;
 use embassy_stm32::Config;
 use {defmt_rtt as _, panic_probe as _};
@@ -265,7 +267,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f091rc")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -281,7 +282,6 @@ pub fn config() -> Config {
     }
     #[cfg(feature = "stm32f103c8")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Oscillator,
@@ -298,7 +298,6 @@ pub fn config() -> Config {
     }
     #[cfg(feature = "stm32f207zg")]
     {
-        use embassy_stm32::rcc::*;
         // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
@@ -327,7 +326,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f303ze")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -345,7 +343,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f429zi")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -366,7 +363,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f446re")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Oscillator,
@@ -387,7 +383,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32f767zi")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(8_000_000),
             mode: HseMode::Bypass,
@@ -408,7 +403,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32h563zi")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = None;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.hse = Some(Hse {
@@ -433,7 +427,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32h503rb")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = None;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
         config.rcc.hse = Some(Hse {
@@ -456,9 +449,26 @@ pub fn config() -> Config {
         config.rcc.voltage_scale = VoltageScale::Scale0;
     }
 
+    #[cfg(feature = "stm32g491re")]
+    {
+        config.rcc.hse = Some(Hse {
+            freq: Hertz(24_000_000),
+            mode: HseMode::Oscillator,
+        });
+        config.rcc.pll = Some(Pll {
+            source: Pllsrc::HSE,
+            prediv: PllPreDiv::DIV6,
+            mul: PllMul::MUL85,
+            divp: None,
+            divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
+            divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
+        });
+        config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
+        config.rcc.sys = Sysclk::PLL1_R;
+    }
+
     #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -485,7 +495,7 @@ pub fn config() -> Config {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale1;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
         #[cfg(any(feature = "stm32h755zi"))]
         {
             config.rcc.supply_config = SupplyConfig::DirectSMPS;
@@ -494,7 +504,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32h7a3zi"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = Some(HSIPrescaler::DIV1);
         config.rcc.csi = true;
         config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@@ -521,12 +530,11 @@ pub fn config() -> Config {
         config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz
         config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz
         config.rcc.voltage_scale = VoltageScale::Scale0;
-        config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
+        config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
     }
 
     #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.sys = Sysclk::PLL1_R;
         config.rcc.hsi = true;
         config.rcc.pll = Some(Pll {
@@ -541,7 +549,6 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32wl55jc")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hse = Some(Hse {
             freq: Hertz(32_000_000),
             mode: HseMode::Bypass,
@@ -560,7 +567,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32l552ze"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.sys = Sysclk::PLL1_R;
         config.rcc.pll = Some(Pll {
@@ -576,7 +582,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.pll1 = Some(Pll {
             source: PllSource::HSI, // 16 MHz
@@ -593,17 +598,12 @@ pub fn config() -> Config {
 
     #[cfg(feature = "stm32wba52cg")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.sys = Sysclk::HSI;
-
-        embassy_stm32::pac::RCC.ccipr2().write(|w| {
-            w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI);
-        });
+        config.rcc.mux.rngsel = mux::Rngsel::HSI;
     }
 
     #[cfg(feature = "stm32l073rz")]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.pll = Some(Pll {
             source: PllSource::HSI,
@@ -615,7 +615,6 @@ pub fn config() -> Config {
 
     #[cfg(any(feature = "stm32l152re"))]
     {
-        use embassy_stm32::rcc::*;
         config.rcc.hsi = true;
         config.rcc.pll = Some(Pll {
             source: PllSource::HSI,

From df8f508ffa2bec79f6e3fba4ac3cfe0e5545b5b2 Mon Sep 17 00:00:00 2001
From: Corey Schuhen <cschuhen@gmail.com>
Date: Sat, 2 Mar 2024 09:00:54 +1000
Subject: [PATCH 28/29] Writing to TX buffer also needs to fire an interrupt to
 kick off transmission if it is idle.

Formatting
---
 embassy-stm32/src/can/fdcan.rs  | 62 ++++++++++++++++++++++++++++++---
 examples/stm32g4/src/bin/can.rs |  6 +++-
 2 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 6a4a25cb7..77db774fc 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -436,7 +436,31 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S
 }
 
 /// Sender that can be used for sending CAN frames.
-pub type BufferedCanSender = embassy_sync::channel::DynamicSender<'static, ClassicFrame>;
+#[derive(Copy, Clone)]
+pub struct BufferedCanSender {
+    tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
+    waker: fn(),
+}
+
+impl BufferedCanSender {
+    /// Async write frame to TX buffer.
+    pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> {
+        self.tx_buf.try_send(frame)?;
+        (self.waker)();
+        Ok(())
+    }
+
+    /// Async write frame to TX buffer.
+    pub async fn write(&mut self, frame: ClassicFrame) {
+        self.tx_buf.send(frame).await;
+        (self.waker)();
+    }
+
+    /// Allows a poll_fn to poll until the channel is ready to write
+    pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
+        self.tx_buf.poll_ready_to_send(cx)
+    }
+}
 
 /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
 pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (ClassicFrame, Timestamp)>;
@@ -489,7 +513,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
 
     /// Returns a sender that can be used for sending CAN frames.
     pub fn writer(&self) -> BufferedCanSender {
-        self.tx_buf.sender().into()
+        BufferedCanSender {
+            tx_buf: self.tx_buf.sender().into(),
+            waker: T::IT0Interrupt::pend,
+        }
     }
 
     /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
@@ -525,7 +552,31 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF
 }
 
 /// Sender that can be used for sending CAN frames.
-pub type BufferedFdCanSender = embassy_sync::channel::DynamicSender<'static, FdFrame>;
+#[derive(Copy, Clone)]
+pub struct BufferedFdCanSender {
+    tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>,
+    waker: fn(),
+}
+
+impl BufferedFdCanSender {
+    /// Async write frame to TX buffer.
+    pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError<FdFrame>> {
+        self.tx_buf.try_send(frame)?;
+        (self.waker)();
+        Ok(())
+    }
+
+    /// Async write frame to TX buffer.
+    pub async fn write(&mut self, frame: FdFrame) {
+        self.tx_buf.send(frame).await;
+        (self.waker)();
+    }
+
+    /// Allows a poll_fn to poll until the channel is ready to write
+    pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
+        self.tx_buf.poll_ready_to_send(cx)
+    }
+}
 
 /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
 pub type BufferedFdCanReceiver = embassy_sync::channel::DynamicReceiver<'static, (FdFrame, Timestamp)>;
@@ -578,7 +629,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
 
     /// Returns a sender that can be used for sending CAN frames.
     pub fn writer(&self) -> BufferedFdCanSender {
-        self.tx_buf.sender().into()
+        BufferedFdCanSender {
+            tx_buf: self.tx_buf.sender().into(),
+            waker: T::IT0Interrupt::pend,
+        }
     }
 
     /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index a41f765c1..11e96361e 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -184,7 +184,11 @@ async fn main(_spawner: Spawner) {
             let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
             info!("Writing frame");
 
-            _ = can.write(frame).await;
+            // You can use any of these approaches to send. The writer makes it
+            // easy to share sending from multiple tasks.
+            //_ = can.write(frame).await;
+            //can.writer().try_write(frame).unwrap();
+            can.writer().write(frame).await;
 
             match can.read().await {
                 Ok((rx_frame, ts)) => {

From 2c42463205dae7e38535fb18f58e872df99e125a Mon Sep 17 00:00:00 2001
From: Zheng Li <875543533@qq.com>
Date: Sat, 2 Mar 2024 00:21:56 +0100
Subject: [PATCH 29/29] executor: remove portable-atomic for riscv.

---
 embassy-executor/Cargo.toml          | 5 ++---
 embassy-executor/src/arch/riscv32.rs | 2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 409df0d75..431165cee 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -40,8 +40,7 @@ critical-section = "1.1"
 
 document-features = "0.2.7"
 
-# needed for riscv and avr
-# remove when https://github.com/rust-lang/rust/pull/114499 lands on stable (on 1.76)
+# needed for AVR
 portable-atomic = { version = "1.5", optional = true }
 
 # arch-cortex-m dependencies
@@ -78,7 +77,7 @@ arch-std = ["_arch", "critical-section/std"]
 ## Cortex-M
 arch-cortex-m = ["_arch", "dep:cortex-m"]
 ## RISC-V 32
-arch-riscv32 = ["_arch", "dep:portable-atomic"]
+arch-riscv32 = ["_arch"]
 ## WASM
 arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
 ## AVR
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index c56f502d3..01e63a9fd 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -6,9 +6,9 @@ pub use thread::*;
 #[cfg(feature = "executor-thread")]
 mod thread {
     use core::marker::PhantomData;
+    use core::sync::atomic::{AtomicBool, Ordering};
 
     pub use embassy_executor_macros::main_riscv as main;
-    use portable_atomic::{AtomicBool, Ordering};
 
     use crate::{raw, Spawner};