Skip to content

Commit 5ad7500

Browse files
committed
AES driver
1 parent aee685c commit 5ad7500

File tree

4 files changed

+351
-0
lines changed

4 files changed

+351
-0
lines changed

examples/aes.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// #![deny(warnings)]
2+
#![no_main]
3+
#![no_std]
4+
5+
extern crate cortex_m;
6+
extern crate cortex_m_rt as rt;
7+
extern crate panic_probe;
8+
extern crate stm32g0xx_hal as hal;
9+
10+
#[cfg(not(any(feature = "stm32g041", feature = "stm32g081")))]
11+
compile_error!("Only stm32g041 and stm32g081 have the AES peripheral");
12+
13+
use defmt_rtt as _;
14+
use hal::aes::Key;
15+
use hal::prelude::*;
16+
use hal::stm32;
17+
use rt::entry;
18+
19+
#[entry]
20+
fn main() -> ! {
21+
let dp = stm32::Peripherals::take().expect("cannot take peripherals");
22+
let mut rcc = dp.RCC.constrain();
23+
let aes = dp.AES.constrain(&mut rcc);
24+
defmt::info!(">>");
25+
let message = b"The quick brown ";
26+
let key = Key::try_from_slice(&[01; 32]).unwrap();
27+
28+
let mut aes_ecb_encrypt = aes.ecb_encrypt(key);
29+
let encrypted = aes_ecb_encrypt.process(&message).unwrap();
30+
defmt::info!("encrypred: {:02x}, check: [c9, ca, 52, 28, e5, f8, f2, 7e, ce, b9, 5b, 4d, 3c, 51, 77, 10]", encrypted);
31+
32+
let mut aes_ecb_decrypt = aes_ecb_encrypt.disable().ecb_decrypt(key);
33+
let decrypted = aes_ecb_decrypt.process(&encrypted).unwrap();
34+
defmt::info!(
35+
"decrypted: \"{}\"",
36+
core::str::from_utf8(&decrypted).unwrap()
37+
);
38+
39+
loop {}
40+
}

src/aes.rs

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
//! Interface to the AES peripheral.
2+
use crate::{
3+
pac,
4+
rcc::{Enable, Rcc, Reset},
5+
};
6+
use core::{convert::TryInto, marker::PhantomData};
7+
use nb::block;
8+
use void::Void;
9+
10+
/// Used to identify encryption mode
11+
pub struct Encrypt;
12+
13+
/// Used to identify decryption mode
14+
pub struct Decrypt;
15+
16+
/// A 128-bit block
17+
///
18+
/// The AES peripheral processes 128 bits at a time, so this represents one unit
19+
/// of processing.
20+
pub type Block = [u8; 16];
21+
22+
#[derive(Debug, Copy, Clone)]
23+
pub enum Key {
24+
Key128([u32; 4]),
25+
Key256([u32; 8]),
26+
}
27+
28+
impl Key {
29+
pub fn try_from_slice(key: &[u8]) -> Result<Self, Error> {
30+
match key.len() {
31+
16 => {
32+
let mut res = [0; 4];
33+
for (idx, w) in res.iter_mut().enumerate() {
34+
let i = idx * 4;
35+
let word = key[i..i + 4].try_into().unwrap();
36+
*w = u32::from_be_bytes(word);
37+
}
38+
Ok(Self::Key128(res))
39+
}
40+
32 => {
41+
let mut res = [0; 8];
42+
for (idx, w) in res.iter_mut().enumerate() {
43+
let i = idx * 4;
44+
let word = key[i..i + 4].try_into().unwrap();
45+
*w = u32::from_be_bytes(word);
46+
}
47+
Ok(Self::Key256(res))
48+
}
49+
_ => Err(Error::InvalidKeySize),
50+
}
51+
}
52+
}
53+
54+
#[derive(Debug)]
55+
pub enum Error {
56+
Busy,
57+
InvalidKeySize,
58+
}
59+
60+
/// Entry point to the AES API
61+
pub struct AES {
62+
rb: pac::AES,
63+
}
64+
65+
impl AES {
66+
/// Initialize the AES peripheral
67+
pub fn new(aes: pac::AES, rcc: &mut Rcc) -> Self {
68+
pac::AES::enable(rcc);
69+
pac::AES::reset(rcc);
70+
aes.cr().write(|w| {
71+
w.en()
72+
.clear_bit()
73+
.dmaouten()
74+
.clear_bit()
75+
.dmainen()
76+
.clear_bit()
77+
.errie()
78+
.clear_bit()
79+
.ccfie()
80+
.clear_bit()
81+
.ccfc()
82+
.set_bit()
83+
.errc()
84+
.set_bit()
85+
});
86+
Self { rb: aes }
87+
}
88+
89+
pub fn ecb_encrypt(self, key: Key) -> Stream {
90+
self.enable(
91+
ECB {
92+
_mode: PhantomData::<Encrypt>,
93+
},
94+
key,
95+
)
96+
}
97+
98+
pub fn ecb_decrypt(self, key: Key) -> Stream {
99+
self.enable(
100+
ECB {
101+
_mode: PhantomData::<Decrypt>,
102+
},
103+
key,
104+
)
105+
}
106+
107+
pub fn cbc_encrypt(self, key: Key, init_vector: [u32; 4]) -> Stream {
108+
self.enable(
109+
CBC {
110+
_mode: PhantomData::<Encrypt>,
111+
init_vector,
112+
},
113+
key,
114+
)
115+
}
116+
117+
pub fn cbc_decrypt(self, key: Key, init_vector: [u32; 4]) -> Stream {
118+
self.enable(
119+
CBC {
120+
_mode: PhantomData::<Decrypt>,
121+
init_vector,
122+
},
123+
key,
124+
)
125+
}
126+
127+
pub fn ctr(self, key: Key, init_vector: [u32; 3]) -> Stream {
128+
self.enable(CTR { init_vector }, key)
129+
}
130+
131+
fn enable<M>(self, mode: M, key: Key) -> Stream
132+
where
133+
M: Mode,
134+
{
135+
mode.enable(&self.rb, key);
136+
self.rb.cr().modify(|_, w| w.en().set_bit());
137+
Stream { aes: self }
138+
}
139+
}
140+
141+
/// An active encryption/decryption stream
142+
///
143+
/// You can get an instance of this struct by calling [`AES::enable`].
144+
pub struct Stream {
145+
aes: AES,
146+
}
147+
148+
impl Stream {
149+
/// Processes one block of data
150+
///
151+
/// Writes one block of data to the AES peripheral, wait until it is
152+
/// processed then reads the processed block and returns it.
153+
pub fn process(&mut self, input: &Block) -> Result<Block, Error> {
154+
self.write(input)?;
155+
let output = block!(self.read()).unwrap();
156+
Ok(output)
157+
}
158+
159+
/// Disable the AES peripheral
160+
pub fn disable(self) -> AES {
161+
self.aes.rb.cr().modify(|_, w| w.en().clear_bit());
162+
self.aes
163+
}
164+
165+
fn write(&mut self, block: &Block) -> Result<(), Error> {
166+
if self.aes.rb.sr().read().wrerr().bit_is_set() {
167+
return Err(Error::Busy);
168+
}
169+
for i in 0..4 {
170+
let i = i * 4;
171+
let word = &block[i..i + 4];
172+
let word = word.try_into().unwrap();
173+
let word = u32::from_be_bytes(word);
174+
self.aes.rb.dinr().write(|w| unsafe { w.bits(word) });
175+
}
176+
Ok(())
177+
}
178+
179+
fn read(&mut self) -> nb::Result<Block, Void> {
180+
if self.aes.rb.sr().read().ccf().bit_is_clear() {
181+
return Err(nb::Error::WouldBlock);
182+
}
183+
let mut block = [0; 16];
184+
for i in 0..4 {
185+
let i = i * 4;
186+
let word = self.aes.rb.doutr().read().bits();
187+
let word = word.to_be_bytes();
188+
(block[i..i + 4]).copy_from_slice(&word);
189+
}
190+
self.aes.rb.cr().modify(|_, w| w.ccfc().set_bit());
191+
Ok(block)
192+
}
193+
}
194+
195+
/// Implemented for all chaining modes
196+
pub trait Mode {
197+
fn enable(&self, rb: &pac::AES, key: Key);
198+
199+
fn write_key(&self, rb: &pac::AES, key: Key) {
200+
match key {
201+
Key::Key128(key) => unsafe {
202+
rb.cr().modify(|_, w| w.keysize().bit(false));
203+
rb.keyr0().write(|w| w.bits(key[0]));
204+
rb.keyr1().write(|w| w.bits(key[1]));
205+
rb.keyr2().write(|w| w.bits(key[2]));
206+
rb.keyr3().write(|w| w.bits(key[3]));
207+
},
208+
Key::Key256(key) => unsafe {
209+
rb.cr().modify(|_, w| w.keysize().bit(true));
210+
rb.keyr0().write(|w| w.bits(key[0]));
211+
rb.keyr1().write(|w| w.bits(key[1]));
212+
rb.keyr2().write(|w| w.bits(key[2]));
213+
rb.keyr3().write(|w| w.bits(key[3]));
214+
rb.keyr4().write(|w| w.bits(key[4]));
215+
rb.keyr5().write(|w| w.bits(key[5]));
216+
rb.keyr6().write(|w| w.bits(key[6]));
217+
rb.keyr7().write(|w| w.bits(key[7]));
218+
},
219+
}
220+
}
221+
222+
fn derive_key(&self, rb: &pac::AES, key: Key) {
223+
rb.cr().modify(|_, w| unsafe { w.mode().bits(0b01) });
224+
Self::write_key(self, rb, key);
225+
rb.cr().modify(|_, w| w.en().set_bit());
226+
while rb.sr().read().ccf().bit_is_clear() {}
227+
rb.cr().modify(|_, w| w.ccfc().set_bit());
228+
}
229+
}
230+
231+
/// The ECB chaining mode
232+
pub struct ECB<Mode> {
233+
_mode: PhantomData<Mode>,
234+
}
235+
236+
impl Mode for ECB<Encrypt> {
237+
fn enable(&self, rb: &pac::AES, key: Key) {
238+
Self::write_key(self, rb, key);
239+
rb.cr()
240+
.modify(|_, w| unsafe { w.mode().bits(0b00).chmod10().bits(0b00).chmod2().bit(false) });
241+
}
242+
}
243+
244+
impl Mode for ECB<Decrypt> {
245+
fn enable(&self, rb: &pac::AES, key: Key) {
246+
Self::derive_key(self, rb, key);
247+
rb.cr()
248+
.modify(|_, w| unsafe { w.mode().bits(0b10).chmod10().bits(0b00).chmod2().bit(false) });
249+
}
250+
}
251+
252+
/// The CBC chaining mode
253+
pub struct CBC<Mode> {
254+
init_vector: [u32; 4],
255+
_mode: PhantomData<Mode>,
256+
}
257+
258+
impl Mode for CBC<Encrypt> {
259+
fn enable(&self, rb: &pac::AES, key: Key) {
260+
Self::write_key(self, rb, key);
261+
rb.ivr3().write(|w| unsafe { w.bits(self.init_vector[0]) });
262+
rb.ivr2().write(|w| unsafe { w.bits(self.init_vector[1]) });
263+
rb.ivr1().write(|w| unsafe { w.bits(self.init_vector[2]) });
264+
rb.ivr0().write(|w| unsafe { w.bits(self.init_vector[3]) });
265+
rb.cr()
266+
.modify(|_, w| unsafe { w.chmod10().bits(0b01).chmod2().bit(false).mode().bits(0b00) });
267+
}
268+
}
269+
270+
impl Mode for CBC<Decrypt> {
271+
fn enable(&self, rb: &pac::AES, key: Key) {
272+
Self::derive_key(self, rb, key);
273+
rb.ivr3().write(|w| unsafe { w.bits(self.init_vector[0]) });
274+
rb.ivr2().write(|w| unsafe { w.bits(self.init_vector[1]) });
275+
rb.ivr1().write(|w| unsafe { w.bits(self.init_vector[2]) });
276+
rb.ivr0().write(|w| unsafe { w.bits(self.init_vector[3]) });
277+
rb.cr()
278+
.modify(|_, w| unsafe { w.chmod10().bits(0b01).chmod2().bit(false).mode().bits(0b10) });
279+
}
280+
}
281+
282+
/// The CTR chaining mode
283+
pub struct CTR {
284+
init_vector: [u32; 3],
285+
}
286+
287+
impl Mode for CTR {
288+
fn enable(&self, rb: &pac::AES, key: Key) {
289+
Self::write_key(self, rb, key);
290+
rb.ivr3().write(|w| unsafe { w.bits(self.init_vector[0]) });
291+
rb.ivr2().write(|w| unsafe { w.bits(self.init_vector[1]) });
292+
rb.ivr1().write(|w| unsafe { w.bits(self.init_vector[2]) });
293+
rb.ivr0().write(|w| unsafe { w.bits(0x0001) });
294+
rb.cr()
295+
.modify(|_, w| unsafe { w.chmod10().bits(0b10).chmod2().bit(false).mode().bits(0b00) });
296+
}
297+
}
298+
299+
pub trait AesExt {
300+
fn constrain(self, rcc: &mut Rcc) -> AES;
301+
}
302+
303+
impl AesExt for pac::AES {
304+
fn constrain(self, rcc: &mut Rcc) -> AES {
305+
AES::new(self, rcc)
306+
}
307+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ pub use stm32g0::stm32g0b1 as stm32;
4343
#[cfg(feature = "rt")]
4444
pub use crate::stm32::interrupt;
4545

46+
#[cfg(any(feature = "stm32g041", feature = "stm32g081"))]
47+
pub mod aes;
4648
pub mod analog;
4749
pub mod crc;
4850
pub mod dma;

src/prelude.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(any(feature = "stm32g041", feature = "stm32g081"))]
2+
pub use crate::aes::AesExt as _;
13
pub use crate::analog::adc::AdcExt as _;
24
#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
35
pub use crate::analog::comparator::ComparatorExt as _;

0 commit comments

Comments
 (0)