aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Garrett <[email protected]>2024-02-14 20:24:52 -0500
committerCaleb Garrett <[email protected]>2024-02-25 20:59:07 -0500
commita0a8a4ec864763948d4a965ccf8ec11ca91cb15f (patch)
tree57fde5d557ddb6dd9446b1b33e3b5d70bf5d0066
parent79e5e8b052b56f8c6fc07d8407fcfc3aaf39bab3 (diff)
Support CBC, ECB, CTR modes.
-rw-r--r--embassy-stm32/src/cryp/mod.rs350
1 files 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 @@
1use embassy_hal_internal::{into_ref, PeripheralRef}; 1use embassy_hal_internal::{into_ref, PeripheralRef};
2use pac::cryp::Init;
3 2
4use crate::pac; 3use crate::pac;
5use crate::peripherals::CRYP; 4use crate::peripherals::CRYP;
6use crate::rcc::sealed::RccPeripheral; 5use crate::rcc::sealed::RccPeripheral;
7use crate::{interrupt, peripherals, Peripheral}; 6use crate::{interrupt, Peripheral};
7
8const DES_BLOCK_SIZE: usize = 8; // 64 bits
9const AES_BLOCK_SIZE: usize = 16; // 128 bits
8 10
9pub struct Context<'c> { 11pub struct Context<'c> {
12 algo: Algorithm,
13 mode: Mode,
14 dir: Direction,
15 last_block_processed: bool,
16 aad_complete: bool,
17 cr: u32,
18 iv: [u32; 4],
10 key: &'c [u8], 19 key: &'c [u8],
20 csgcmccm: [u32; 8],
21 csgcm: [u32; 8],
11} 22}
12 23
13#[derive(PartialEq)] 24#[derive(PartialEq, Clone, Copy)]
14pub enum Algorithm { 25pub enum Algorithm {
15 AES, 26 AES,
16 DES, 27 DES,
17 TDES, 28 TDES,
18} 29}
19 30
20#[derive(PartialEq)] 31#[derive(PartialEq, Clone, Copy)]
21pub enum Mode { 32pub enum Mode {
22 ECB, 33 ECB,
23 CBC, 34 CBC,
@@ -27,53 +38,55 @@ pub enum Mode {
27 CCM, 38 CCM,
28} 39}
29 40
30#[derive(PartialEq)] 41#[derive(PartialEq, Clone, Copy)]
31pub enum Direction { 42pub enum Direction {
32 Encrypt, 43 Encrypt,
33 Decrypt, 44 Decrypt,
34} 45}
35 46
36/// Crypto Accelerator Driver 47/// Crypto Accelerator Driver
37pub struct Cryp<'d, T: Instance, In, Out> { 48pub struct Cryp<'d, T: Instance> {
38 _peripheral: PeripheralRef<'d, T>, 49 _peripheral: PeripheralRef<'d, T>,
39 indma: PeripheralRef<'d, In>,
40 outdma: PeripheralRef<'d, Out>,
41} 50}
42 51
43type InitVector<'v> = Option<&'v [u8]>; 52type InitVector<'v> = Option<&'v [u8]>;
44 53
45impl<'d, T: Instance, In, Out> Cryp<'d, T, In, Out> { 54impl<'d, T: Instance> Cryp<'d, T> {
46 /// Create a new CRYP driver. 55 /// Create a new CRYP driver.
47 pub fn new( 56 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
48 peri: impl Peripheral<P = T> + 'd,
49 indma: impl Peripheral<P = In> + 'd,
50 outdma: impl Peripheral<P = Out> + 'd,
51 ) -> Self {
52 CRYP::enable_and_reset(); 57 CRYP::enable_and_reset();
53 into_ref!(peri, indma, outdma); 58 into_ref!(peri);
54 let instance = Self { 59 let instance = Self { _peripheral: peri };
55 _peripheral: peri,
56 indma: indma,
57 outdma: outdma,
58 };
59 instance 60 instance
60 } 61 }
61 62
62 /// Start a new cipher operation. 63 /// Start a new cipher operation.
63 /// Key size must be 128, 192, or 256 bits. 64 /// Key size must be 128, 192, or 256 bits.
64 pub fn start(key: &[u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context { 65 pub fn start<'c>(&self, key: &'c [u8], iv: InitVector, algo: Algorithm, mode: Mode, dir: Direction) -> Context<'c> {
65 T::regs().cr().modify(|w| w.set_crypen(false)); 66 let mut ctx = Context {
67 algo,
68 mode,
69 dir,
70 last_block_processed: false,
71 cr: 0,
72 iv: [0; 4],
73 key,
74 csgcmccm: [0; 8],
75 csgcm: [0; 8],
76 aad_complete: false,
77 };
66 78
67 let keylen = key.len() * 8; 79 T::regs().cr().modify(|w| w.set_crypen(false));
68 let ivlen;
69 if let Some(iv) = iv {
70 ivlen = iv.len() * 8;
71 } else {
72 ivlen = 0;
73 }
74 80
75 // Checks for correctness 81 // Checks for correctness
76 if algo == Algorithm::AES { 82 if algo == Algorithm::AES {
83 let keylen = key.len() * 8;
84 let ivlen;
85 if let Some(iv) = iv {
86 ivlen = iv.len() * 8;
87 } else {
88 ivlen = 0;
89 }
77 match keylen { 90 match keylen {
78 128 => T::regs().cr().write(|w| w.set_keysize(0)), 91 128 => T::regs().cr().write(|w| w.set_keysize(0)),
79 192 => T::regs().cr().write(|w| w.set_keysize(1)), 92 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> {
96 } 109 }
97 } 110 }
98 111
99 // Load the key into the registers. 112 self.load_key(key);
100 let mut keyidx = 0;
101 let mut keyword: [u8; 4] = [0; 4];
102 if keylen > 192 {
103 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
104 keyidx += 4;
105 T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword));
106 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
107 keyidx += 4;
108 T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword));
109 }
110 if keylen > 128 {
111 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
112 keyidx += 4;
113 T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword));
114 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
115 keyidx += 4;
116 T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword));
117 }
118 if keylen > 64 {
119 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
120 keyidx += 4;
121 T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword));
122 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
123 keyidx += 4;
124 T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword));
125 }
126 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
127 keyidx += 4;
128 T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword));
129 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
130 T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword));
131 113
132 // Set data type to 8-bit. This will match software implementations. 114 // Set data type to 8-bit. This will match software implementations.
133 T::regs().cr().modify(|w| w.set_datatype(2)); 115 T::regs().cr().modify(|w| w.set_datatype(2));
134 116
135 if algo == Algorithm::AES { 117 self.prepare_key(&ctx);
136 if (mode == Mode::ECB) || (mode == Mode::CBC) {
137 T::regs().cr().modify(|w| w.set_algomode0(7));
138 T::regs().cr().modify(|w| w.set_crypen(true));
139 while T::regs().sr().read().busy() {}
140 }
141 118
119 if algo == Algorithm::AES {
142 match mode { 120 match mode {
143 Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)), 121 Mode::ECB => T::regs().cr().modify(|w| w.set_algomode0(4)),
144 Mode::CBC => T::regs().cr().modify(|w| w.set_algomode0(5)), 122 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> {
192 // Flush in/out FIFOs 170 // Flush in/out FIFOs
193 T::regs().cr().modify(|w| w.fflush()); 171 T::regs().cr().modify(|w| w.fflush());
194 172
195 let ctx = Context { key: key }; 173 if mode == Mode::GCM {
174 // GCM init phase
175 T::regs().cr().modify(|w| w.set_gcm_ccmph(0));
176 T::regs().cr().modify(|w| w.set_crypen(true));
177 while T::regs().cr().read().crypen() {}
178 }
179
180 self.store_context(&mut ctx);
196 181
197 ctx 182 ctx
198 } 183 }
184
185 // pub fn aad_blocking(&self, ctx: &mut Context, aad: &[u8]) {
186 // if ctx.aad_complete {
187 // panic!("Cannot update AAD after calling 'update'!")
188 // }
189 // if (ctx.mode != Mode::GCM) && (ctx.mode != Mode::GMAC) && (ctx.mode != Mode::CCM) {
190 // panic!("Associated data only valid for GCM, GMAC, and CCM modes.")
191 // }
192
193 // let mut header_size = 0;
194 // let mut header: [u8;]
195
196 // if aad.len() < 65280 {
197
198 // }
199
200 // // GCM header phase
201 // T::regs().cr().modify(|w| w.set_gcm_ccmph(1));
202 // T::regs().cr().modify(|w| w.set_crypen(true));
203 // }
204
205 pub fn update_blocking(&self, ctx: &mut Context, input: &[u8], output: &mut [u8], last_block: bool) {
206 self.load_context(ctx);
207
208 ctx.aad_complete = true;
209 if last_block {
210 ctx.last_block_processed = true;
211 }
212
213 let block_size;
214 if ctx.algo == Algorithm::DES {
215 block_size = 8;
216 } else {
217 block_size = 16;
218 }
219 let last_block_remainder = input.len() % block_size;
220
221 // Perform checks for correctness.
222
223 if ctx.mode == Mode::GMAC {
224 panic!("GMAC works on header data only. Do not call this function for GMAC.");
225 }
226 if ctx.last_block_processed {
227 panic!("The last block has already been processed!");
228 }
229 if input.len() != output.len() {
230 panic!("Output buffer length must match input length.");
231 }
232 if !last_block {
233 if last_block_remainder != 0 {
234 panic!("Input length must be a multiple of {block_size} bytes.");
235 }
236 }
237 if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
238 if last_block_remainder != 0 {
239 panic!("Input must be a multiple of {block_size} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.");
240 }
241 }
242
243 // Load data into core, block by block.
244 let num_full_blocks = input.len() / block_size;
245 for block in 0..num_full_blocks {
246 let mut index = block * block_size;
247 let end_index = index + block_size;
248 // Write block in
249 while index < end_index {
250 let mut in_word: [u8; 4] = [0; 4];
251 in_word.copy_from_slice(&input[index..index + 4]);
252 T::regs().din().write_value(u32::from_ne_bytes(in_word));
253 index += 4;
254 }
255 let mut index = block * block_size;
256 let end_index = index + block_size;
257 // Block until there is output to read.
258 while !T::regs().sr().read().ofne() {}
259 // Read block out
260 while index < end_index {
261 let out_word: u32 = T::regs().dout().read();
262 output[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
263 index += 4;
264 }
265 }
266
267 // Handle the final block, which is incomplete.
268 if last_block_remainder > 0 {
269 if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
270 //Handle special GCM partial block process.
271 T::regs().cr().modify(|w| w.set_crypen(false));
272 T::regs().cr().write(|w| w.set_algomode0(6));
273 let iv1r = T::regs().csgcmccmr(7).read() - 1;
274 T::regs().init(1).ivrr().write_value(iv1r);
275 T::regs().cr().modify(|w| w.set_crypen(true));
276 }
277
278 let mut intermediate_data: [u8; 16] = [0; 16];
279 let mut last_block: [u8; 16] = [0; 16];
280 last_block.copy_from_slice(&input[input.len() - last_block_remainder..input.len()]);
281 let mut index = 0;
282 let end_index = block_size;
283 // Write block in
284 while index < end_index {
285 let mut in_word: [u8; 4] = [0; 4];
286 in_word.copy_from_slice(&last_block[index..index + 4]);
287 T::regs().din().write_value(u32::from_ne_bytes(in_word));
288 index += 4;
289 }
290 let mut index = 0;
291 let end_index = block_size;
292 // Block until there is output to read.
293 while !T::regs().sr().read().ofne() {}
294 // Read block out
295 while index < end_index {
296 let out_word: u32 = T::regs().dout().read();
297 intermediate_data[index..index + 4].copy_from_slice(u32::to_ne_bytes(out_word).as_slice());
298 index += 4;
299 }
300
301 // Handle the last block depending on mode.
302 output[output.len() - last_block_remainder..output.len()]
303 .copy_from_slice(&intermediate_data[0..last_block_remainder]);
304
305 if ctx.mode == Mode::GCM && ctx.dir == Direction::Encrypt {
306 //Handle special GCM partial block process.
307 T::regs().cr().modify(|w| w.set_crypen(false));
308 T::regs().cr().write(|w| w.set_algomode0(8));
309 T::regs().init(1).ivrr().write_value(2);
310 T::regs().cr().modify(|w| w.set_crypen(true));
311 T::regs().cr().modify(|w| w.set_gcm_ccmph(3));
312 let mut index = 0;
313 let end_index = block_size;
314 while index < end_index {
315 let mut in_word: [u8; 4] = [0; 4];
316 in_word.copy_from_slice(&intermediate_data[index..index + 4]);
317 T::regs().din().write_value(u32::from_ne_bytes(in_word));
318 index += 4;
319 }
320 for _ in 0..4 {
321 T::regs().dout().read();
322 }
323 }
324 }
325 }
326
327 fn prepare_key(&self, ctx: &Context) {
328 if ctx.algo == Algorithm::AES {
329 if (ctx.mode == Mode::ECB) || (ctx.mode == Mode::CBC) {
330 T::regs().cr().modify(|w| w.set_algomode0(7));
331 T::regs().cr().modify(|w| w.set_crypen(true));
332 while T::regs().sr().read().busy() {}
333 }
334 }
335 }
336
337 fn load_key(&self, key: &[u8]) {
338 // Load the key into the registers.
339 let mut keyidx = 0;
340 let mut keyword: [u8; 4] = [0; 4];
341 let keylen = key.len() * 8;
342 if keylen > 192 {
343 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
344 keyidx += 4;
345 T::regs().key(0).klr().write_value(u32::from_be_bytes(keyword));
346 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
347 keyidx += 4;
348 T::regs().key(0).krr().write_value(u32::from_be_bytes(keyword));
349 }
350 if keylen > 128 {
351 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
352 keyidx += 4;
353 T::regs().key(1).klr().write_value(u32::from_be_bytes(keyword));
354 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
355 keyidx += 4;
356 T::regs().key(1).krr().write_value(u32::from_be_bytes(keyword));
357 }
358 if keylen > 64 {
359 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
360 keyidx += 4;
361 T::regs().key(2).klr().write_value(u32::from_be_bytes(keyword));
362 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
363 keyidx += 4;
364 T::regs().key(2).krr().write_value(u32::from_be_bytes(keyword));
365 }
366 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
367 keyidx += 4;
368 T::regs().key(3).klr().write_value(u32::from_be_bytes(keyword));
369 keyword.copy_from_slice(&key[keyidx..keyidx + 4]);
370 T::regs().key(3).krr().write_value(u32::from_be_bytes(keyword));
371 }
372
373 fn store_context(&self, ctx: &mut Context) {
374 // Wait for data block processing to finish.
375 while !T::regs().sr().read().ifem() {}
376 while T::regs().sr().read().ofne() {}
377 while T::regs().sr().read().busy() {}
378
379 // Disable crypto processor.
380 T::regs().cr().modify(|w| w.set_crypen(false));
381
382 // Save the peripheral state.
383 ctx.cr = T::regs().cr().read().0;
384 ctx.iv[0] = T::regs().init(0).ivlr().read();
385 ctx.iv[1] = T::regs().init(0).ivrr().read();
386 ctx.iv[2] = T::regs().init(1).ivlr().read();
387 ctx.iv[3] = T::regs().init(1).ivrr().read();
388 for i in 0..8 {
389 ctx.csgcmccm[i] = T::regs().csgcmccmr(i).read();
390 ctx.csgcm[i] = T::regs().csgcmr(i).read();
391 }
392 }
393
394 fn load_context(&self, ctx: &Context) {
395 // Reload state registers.
396 T::regs().cr().write(|w| w.0 = ctx.cr);
397 T::regs().init(0).ivlr().write_value(ctx.iv[0]);
398 T::regs().init(0).ivrr().write_value(ctx.iv[1]);
399 T::regs().init(1).ivlr().write_value(ctx.iv[2]);
400 T::regs().init(1).ivrr().write_value(ctx.iv[3]);
401 for i in 0..8 {
402 T::regs().csgcmccmr(i).write_value(ctx.csgcmccm[i]);
403 T::regs().csgcmr(i).write_value(ctx.csgcm[i]);
404 }
405 self.load_key(ctx.key);
406
407 // Prepare key if applicable.
408 self.prepare_key(ctx);
409
410 // Enable crypto processor.
411 T::regs().cr().modify(|w| w.set_crypen(true));
412 }
199} 413}
200 414
201pub(crate) mod sealed { 415pub(crate) mod sealed {