atsamd_hal/peripherals/aes/mod.rs
1//! # AES - Advanced Encryption Standard
2//!
3//! # Hardware Features
4//!
5//! * Compliant with FIPS Publication 197, Advanced Encryption Standard (AES)
6//! * 128/192/256 bit cryptographic key supported
7//! * Encryption time of 57/67/77 cycles with 128-bit/192-bit/256-bit
8//! cryptographic key
9//! * Five confidentiality modes of operation as recommended in NIST Special
10//! Publication 800-38A
11//! * Electronic Code Book (ECB)
12//! * Cipher Block Chaining (CBC)
13//! * Cipher Feedback (CFB)
14//! * Output Feedback (OFB)
15//! * Counter (CTR)
16//! * Supports Counter with CBC-MAC (CCM/CCM*) mode for authenticated encryption
17//! * 8,16, 32, 64, 128-bit data sizes possible in CFB mode
18//! * Galois Counter mode (GCM) encryption and authentication
19//!
20//! ## Throughput
21//!
22//! The relationship between the module's clock frequency and throughput (in
23//! bytes per second) is given by:
24//!
25//! Clock Frequency = (Throughput/2) * (Nr+1) for 2 byte parallel processing
26//! Clock Frequency = (Throughput/4) * (Nr+1) for 4 byte parallel processing
27//!
28//! # Start modes
29//!
30//! * Manual
31//! * Manually configuring all registers and processing starts when
32//! `CTRLB.START` is set
33//! * Automatic (DMA)
34//! * Similar to manual mode, but starts automatically when correct number of
35//! input data registers is written, used by DMA.
36//! * Last Output Data Mode (LOD)
37//! * Used to generate Message Authentication Code (MAC) on data in CCM mode.
38//! CCM combines counter mode for encryption and CBC-MAC generation for
39//! authentication.
40//!
41//! # Basic operation
42//!
43//! ## Peripheral setup
44//!
45//! 1. Enable `CLK_AES_APB` (default disabled) to clock AES peripheral
46//! 2. If required, setup interrupts via NVIC
47//!
48//! Note: Register Control A (CTRLA) is Enabled-protected,
49//! thus in order to modify CTRLA register AES must be disabled first.
50//!
51//! # RustCrypto backend
52//!
53//! Implements RustCrypto BlockCiphers traits for AES
54//!
55//! > **WARNING**
56//! >
57//! >AES Hardware peripheral is directly accessed, for each
58//! >call to `encrypt` and `decrypt` the peripheral is reset and reconfigured.
59//! >
60//! > User must ensure that these two interfaces are not simultaneously used
61//!
62//! If high performance is required this might not be the most
63//! efficient way, then using the hardware directly might be better.
64//!
65//! This provides the ability to use other ciphers of the RustCrypto family,
66//! such as
67//! * [Counter (CTR)][ctr]
68//! * [Cipher-based Message Authentication Code (CMAC)][cmac]
69//! * [Cipher Feedback (CFB)][cfb]
70//!
71//! [ctr]: https://docs.rs/ctr/
72//! [cmac]: https://docs.rs/cmac
73//! [cfb]: https://docs.rs/cfb-mode
74//!
75//! The examples from these crates can directly be run
76//! provided that the Aes128, Aes192 or Aes256 type
77//! comes from this implementation.
78//!
79//! See example directly from RustCrypto AES ECB:
80//!
81//! ```no_run
82//! use atsamd_hal::aes::*;
83//!
84//! // AES RustCrypto Example
85//!
86//! let key = GenericArray::from_slice(&[0u8; 16]);
87//! let mut block = aes::Block::default();
88//!
89//! // Initialize cipher
90//! let cipher = atsamd_hal::aes::Aes128::new(key);
91//!
92//! let block_copy = block;
93//!
94//! // Encrypt block in-place
95//! cipher.encrypt_block(&mut block);
96//!
97//! // And decrypt it back
98//! cipher.decrypt_block(&mut block);
99//! assert_eq!(block, block_copy);
100//! ```
101
102// Re-exports
103pub use crate::pac::aes::ctrla::{
104 Aesmodeselect, Cfbsselect, Cipherselect, Keysizeselect, Lodselect, Startmodeselect,
105 Xorkeyselect,
106};
107
108// Re-export Aes128 with hardware backing
109// TODO Should all these items here be reexported? (Aes*, Aes*Enc, Aes*Dec)
110#[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
111mod rustcrypto;
112
113#[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
114pub use rustcrypto::{Aes128, Aes192, Aes256};
115
116#[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
117pub use cipher::{
118 consts::{U1, U16, U24, U32, U8},
119 generic_array::*,
120 BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
121};
122
123use crate::pac::aes::{self, *};
124
125use bitfield::BitRange;
126
127#[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
128use aes::Block;
129
130type Dataptr = u8;
131type Indata = u32;
132
133type InitVec = [u32; 4];
134type Hashkey = [u32; 4];
135type Ghash = [u32; 4];
136type Ciplen = u32;
137type Seed = u32;
138
139bitfield::bitfield! {
140 /// Hardware Countermeasures against Differential Power Analysis Attacks
141 ///
142 /// The AES module features four types of hardware countermeasures that are
143 /// useful for protecting data against differential power analysis attacks:
144 ///
145 /// * Type 1: Randomly add one cycle to data processing
146 /// * Type 2: Randomly add one cycle to data processing (other version)
147 /// * Type 3: Add a random number of clock cycles to data processing,
148 /// subject to a maximum of 11/13/15 clock
149 /// cycles for key sizes of 128/192/256 bits
150 /// * Type 4: Add random spurious power consumption during data processing
151 ///
152 /// By default, all countermeasures are enabled, but require a write in DRNGSEED
153 /// register to be effective.
154 ///
155 /// The countermeasures use random numbers generated by a deterministic
156 /// random number generator embedded in AES module.
157 ///
158 /// The seed for the random number generator is written to the RANDSEED register.
159 ///
160 /// *Note*: also that a new seed must be written after a change in the keysize.
161 ///
162 /// *Note*: that enabling countermeasures reduces AES module’s throughput. In short,
163 /// the throughput is highest with all the countermeasures disabled.
164 pub struct Ctype(u8);
165 impl Debug;
166 u8;
167 get_ctype1, set_ctype1: 0;
168 get_ctype2, set_ctype2: 1;
169 get_ctype3, set_ctype3: 2;
170 get_ctype4, set_ctype4: 3;
171}
172
173bitfield::bitfield! {
174 /// AES->CTRLA Register
175 ///
176 /// Enable-protected configuration register
177 pub struct CtrlaConf(u32);
178 impl Debug;
179 impl Default;
180 u8;
181 get_swrst, set_swrst: 0;
182 get_enable, set_enable: 1;
183 get_aesmode, set_aesmode: 4, 2;
184 get_cfbs, set_cfbs: 7, 5;
185 get_keysize, set_keysize: 9, 8;
186 get_cipher, set_cipher: 10;
187 get_startmode, set_startmode: 11;
188 get_lod, set_lod: 12;
189 get_keygen, set_keygen: 13;
190 get_xorkey, set_xorkey: 14;
191 get_ctype, set_ctype: 19, 16;
192}
193
194/// Holding area for AES peripheral
195///
196/// > **WARNING**
197/// > RustCrypto backend assumes full ownership of AES hardware peripheral
198///
199/// Apart from creating new RustCrypto
200/// there is no AES peripheral functionality exposed
201#[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
202pub struct AesRustCrypto {
203 /// AES pac register providing hardware access
204 aes: Aes,
205}
206
207#[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
208impl AesRustCrypto {
209 /// Use the AES peripheral as hardware backend for RustCrypto AES
210 ///
211 /// Don't forget to enable the `APB` bus for AES
212 ///
213 /// `AHB` bus is on by default at reset
214 ///
215 /// Clock::v1
216 /// `mclk.apbcmask.modify(|_, w| w.aes_().set_bit());`
217 ///
218 /// Clock::v2
219 /// `tokens.apbs.aes.enable();`
220 #[inline]
221 pub fn new(aes: Aes) -> Self {
222 Self { aes }
223 }
224
225 /// Destroy the AES RustCrypto backend and return the underlying AES
226 /// register
227 #[inline]
228 pub fn destroy(self) -> Aes {
229 self.aes
230 }
231
232 #[inline]
233 pub fn new_128bit(&self, key: &GenericArray<u8, U16>) -> rustcrypto::Aes128 {
234 rustcrypto::Aes128::new(key)
235 }
236 #[inline]
237 pub fn new_192bit(&self, key: &GenericArray<u8, U24>) -> rustcrypto::Aes192 {
238 rustcrypto::Aes192::new(key)
239 }
240 #[inline]
241 pub fn new_256bit(&self, key: &GenericArray<u8, U32>) -> rustcrypto::Aes256 {
242 rustcrypto::Aes256::new(key)
243 }
244}
245
246/// AES Peripheral
247///
248/// Encapsulates the PAC which acts as a token
249/// and provides an interface to the AES hardware
250pub struct Aes {
251 /// AES pac register providing hardware access
252 aes: crate::pac::Aes,
253}
254
255impl Aes {
256 /// Create the interface for the AES peripheral
257 ///
258 /// Don't forget to enable the `APB` bus for AES
259 ///
260 /// `AHB` bus is on by default at reset
261 ///
262 /// Clock::v1
263 /// `mclk.apbcmask.modify(|_, w| w.aes_().set_bit());`
264 ///
265 /// Clock::v2
266 /// `tokens.apbs.aes.enable();`
267 #[inline]
268 pub fn new(aes: crate::pac::Aes) -> Self {
269 Self { aes }
270 }
271
272 /// Use the AES peripheral as hardware backend for RustCrypto AES
273 ///
274 /// Requires the feature `enable_unsafe_aes_newblock_cipher` to be enabled
275 ///
276 /// > **WARNING**
277 /// > RustCrypto backend assumes full ownership of AES hardware peripheral
278 ///
279 /// Don't forget to enable the `APB` bus for AES
280 ///
281 /// `AHB` bus is on by default at reset
282 ///
283 /// Clock::v1
284 /// `mclk.apbcmask.modify(|_, w| w.aes_().set_bit());`
285 ///
286 /// Clock::v2
287 /// `tokens.apbs.aes.enable();`
288 #[cfg(feature = "enable_unsafe_aes_newblock_cipher")]
289 #[inline]
290 pub fn activate_rustcrypto_backend(self) -> AesRustCrypto {
291 AesRustCrypto::new(self)
292 }
293
294 // Register Interface
295
296 /// Integrity Check Module
297 #[inline]
298 fn aes(&self) -> &RegisterBlock {
299 &self.aes
300 }
301
302 /// Control A
303 ///
304 /// Enable-protected register
305 #[inline]
306 fn ctrla(&self) -> &Ctrla {
307 self.aes().ctrla()
308 }
309
310 /// Control B
311 #[inline]
312 fn ctrlb(&self) -> &Ctrlb {
313 self.aes().ctrlb()
314 }
315
316 /// Interrupt Enable Clear
317 #[inline]
318 fn intenclr(&self) -> &Intenclr {
319 self.aes().intenclr()
320 }
321
322 /// Interrupt Enable Set
323 #[inline]
324 fn intenset(&self) -> &Intenset {
325 self.aes().intenset()
326 }
327
328 /// Interrupt Flag Status and Clear
329 #[inline]
330 fn intflag(&self) -> &Intflag {
331 self.aes().intflag()
332 }
333
334 /// Data Buffer Pointer
335 #[inline]
336 fn databufptr(&self) -> &Databufptr {
337 self.aes().databufptr()
338 }
339
340 /// Debug
341 #[inline]
342 fn dbgctrl(&self) -> &Dbgctrl {
343 self.aes().dbgctrl()
344 }
345
346 /// INDATA
347 ///
348 /// A write to or read from this register corresponds to a write to or read
349 /// from one of the four data registers. The four 32-bit Data registers
350 /// set the 128-bit data block used for encryption/decryption. The data
351 /// register that is written to or read from is given by the
352 /// DATABUFPTR.INDATPTR field.
353 ///
354 /// Note: Both input and output shares the same data buffer.
355 /// Reading INDATA register will return 0’s when AES is performing
356 /// encryption or decryption operation
357 #[inline]
358 fn indata(&self) -> &aes::Indata {
359 self.aes().indata()
360 }
361
362 /// Galois Hash x (GCM mode only)
363 ///
364 /// Cipher length
365 #[inline]
366 fn ciplen(&self) -> &aes::Ciplen {
367 self.aes().ciplen()
368 }
369
370 /// Random Seed
371 #[inline]
372 fn randseed(&self) -> &Randseed {
373 self.aes().randseed()
374 }
375
376 // User interface for AES
377
378 /// Enable the AES peripheral
379 #[inline]
380 pub fn enable(&mut self) {
381 self.ctrla().modify(|_, w| w.enable().set_bit());
382 }
383
384 /// Disable the AES peripheral
385 #[inline]
386 pub fn disable(&mut self) {
387 self.ctrla().modify(|_, w| w.enable().clear_bit());
388 }
389
390 /// Reset the AES controller
391 #[inline]
392 pub fn swrst(&self) {
393 self.ctrla().modify(|_, w| w.swrst().set_bit());
394 }
395
396 /// Destroy the AES peripheral and return the underlying AES register
397 #[inline]
398 pub fn destroy(self) -> crate::pac::Aes {
399 self.aes
400 }
401
402 // Control A
403
404 /// Set AES Mode
405 #[inline]
406 pub fn set_aesmode(self, mode: Aesmodeselect) {
407 self.ctrla().modify(|_, w| w.aesmode().variant(mode));
408 }
409
410 /// Set Cipher Feedback Block Size (CFBS)
411 #[inline]
412 pub fn set_cfbs(self, blocksize: Cfbsselect) {
413 self.ctrla().modify(|_, w| w.cfbs().variant(blocksize));
414 }
415
416 /// Set Encryption Key Size
417 #[inline]
418 pub fn set_keysize(self, keysize: Keysizeselect) {
419 self.ctrla().modify(|_, w| w.keysize().variant(keysize));
420 }
421
422 /// Set Cipher Mode
423 #[inline]
424 pub fn set_cipher(self, mode: Cipherselect) {
425 self.ctrla().modify(|_, w| w.cipher().variant(mode));
426 }
427
428 /// Set Start Mode
429 #[inline]
430 pub fn set_startmode(self, mode: Startmodeselect) {
431 self.ctrla().modify(|_, w| w.startmode().variant(mode));
432 }
433
434 /// Set Last Output Data (LOD) Mode
435 #[inline]
436 pub fn set_lod(self, mode: Lodselect) {
437 self.ctrla().modify(|_, w| w.lod().variant(mode));
438 }
439
440 /// Start Last Key Generation
441 ///
442 /// Compute last NK words of expanded key
443 #[inline]
444 pub fn set_keygen(self, keygen_start: bool) {
445 self.ctrla().modify(|_, w| w.keygen().bit(keygen_start));
446 }
447
448 /// XOR Key Generation
449 ///
450 /// The user keyword gets XORed with the previous keyword register content
451 #[inline]
452 pub fn set_xorkey(self, mode: Xorkeyselect) {
453 self.ctrla().modify(|_, w| w.xorkey().variant(mode));
454 }
455
456 /// Counter Measure Type
457 #[inline]
458 pub fn set_ctype(self, countermeasures: Ctype) {
459 self.ctrla()
460 .modify(|_, w| unsafe { w.ctype().bits(countermeasures.bit_range(3, 0)) });
461 }
462
463 // Control B
464
465 /// Start Encryption/Decryption
466 #[inline]
467 pub fn start(&self) {
468 self.ctrlb().modify(|_, w| w.start().set_bit());
469 }
470
471 /// New Message
472 /// Used in cipher block chaining (CBC), cipher feedback (CFB) and output
473 /// feedback (OFB), counter (CTR) modes to indicate that the hardware
474 /// should use Initialization Vector for encrypting the first block of a
475 /// message.
476 #[inline]
477 pub fn newmsg(&self) {
478 self.ctrlb().modify(|_, w| w.newmsg().set_bit());
479 }
480
481 /// End of Message (GCM mode only)
482 ///
483 /// This triggers generation of final `GHASH` value for the message
484 #[inline]
485 pub fn eom(&self) {
486 self.ctrlb().modify(|_, w| w.eom().set_bit());
487 }
488
489 /// GF Multiplication (GCM mode only)
490 ///
491 /// This triggers GF multiplication of data buffer content and hashkey
492 /// register content.
493 #[inline]
494 pub fn gfmul(&self) {
495 self.ctrlb().modify(|_, w| w.gfmul().set_bit());
496 }
497
498 // Interrupt Enable Clear
499
500 /// Disable Encryption Complete Interrupt
501 #[inline]
502 pub fn disable_enccmp(&self) {
503 self.intenclr().modify(|_, w| w.enccmp().set_bit());
504 }
505
506 /// Disable GF Multiplication Complete Interrupt
507 #[inline]
508 pub fn disable_gfmcmp(&self) {
509 self.intenclr().modify(|_, w| w.gfmcmp().set_bit());
510 }
511
512 // Interrupt Enable Set
513
514 /// Enable Encryption Complete Interrupt
515 #[inline]
516 pub fn enable_enccmp(&self) {
517 self.intenset().modify(|_, w| w.enccmp().set_bit());
518 }
519
520 /// Enable GF Multiplication Complete Interrupt
521 #[inline]
522 pub fn enable_gfmcmp(&self) {
523 self.intenset().modify(|_, w| w.gfmcmp().set_bit());
524 }
525
526 // Interrupt Flag Status and Clear
527
528 /// Clear Encryption Complete Interrupt
529 ///
530 /// Also automatically cleared if
531 ///
532 /// 1. Manual encryption/decryption occurs (via CTRLB.START)
533 /// 2. Reading from GHASHx register
534 #[inline]
535 pub fn clear_enccmp(&self) {
536 self.intflag().modify(|_, w| w.enccmp().set_bit());
537 }
538
539 /// Clear GF Multiplication Complete Interrupt
540 ///
541 /// Also automatically cleared if
542 ///
543 /// 1. Manual encryption/decryption occurs (via CTRLB.START)
544 /// 2. Reading from data register `INDATAx` when `LOD = 0`
545 /// 2. Writing into the data register `INDATAx` when `LOD = 1`
546 /// 2. Reading from Hash Key register (`HASHKEYx`)
547 #[inline]
548 pub fn clear_gfmcmp(&self) {
549 self.intflag().modify(|_, w| w.gfmcmp().set_bit());
550 }
551
552 /// Read Encryption Complete Interrupt
553 #[inline]
554 pub fn read_enccmp(&self) -> bool {
555 self.intflag().read().enccmp().bit_is_set()
556 }
557
558 /// Read GF Multiplication Complete Interrupt
559 #[inline]
560 pub fn read_gfmcmp(&self) -> bool {
561 self.intflag().read().gfmcmp().bit_is_set()
562 }
563
564 // Data Buffer Pointer
565
566 /// Set the Data Buffer Pointer
567 #[inline]
568 pub fn set_databufptr(&self, dataptr: Dataptr) {
569 self.databufptr()
570 .modify(|_, w| unsafe { w.indataptr().bits(dataptr) })
571 }
572
573 // Debug run control
574
575 /// Control if AES is active during debugging
576 ///
577 /// Enable protected, only possible to change when AES is disabled
578 #[inline]
579 pub fn set_debug(&self, run_during_debug: bool) {
580 self.dbgctrl()
581 .modify(|_, w| w.dbgrun().bit(run_during_debug))
582 }
583
584 // Set Keyword
585
586 /// Set keyword / cryptographic key
587 ///
588 /// Consists of four/six/eight Key Word registers
589 /// for setting the cryptographic key
590 #[inline]
591 pub fn set_keyword<const N: usize>(&self, keyword: &[u8; N]) {
592 for (index, _) in keyword.iter().step_by(4).enumerate() {
593 // Combine four u8 into one u32
594 let data = u32::from_ne_bytes([
595 keyword[index],
596 keyword[index + 1],
597 keyword[index + 2],
598 keyword[index + 3],
599 ]);
600 self.aes().keyword(index).write(|w| unsafe { w.bits(data) });
601 }
602 }
603
604 // Data
605
606 /// Set indata
607 #[inline]
608 pub fn set_data(&self, data: Indata) {
609 self.indata().write(|w| unsafe { w.bits(data) });
610 }
611
612 /// Read indata
613 pub fn get_data(&self) -> Indata {
614 self.indata().read().bits()
615 }
616
617 // Initialization Vector Register
618
619 /// Set initialization vector
620 ///
621 /// The four 32-bit Initialization Vector registers INTVECTVn set the
622 /// 128-bit Initialization Vector data block that is used by
623 /// some modes of operation as an additional initial input.
624 /// INTVECTV0.INTVECTV corresponds to the first word of the
625 /// Initialization Vector, INTVECTV3.INTVECTV to the last one.
626 ///
627 /// These registers are write-only to prevent the Initialization Vector
628 /// from being read by another application. For CBC, OFB, and CFB modes,
629 /// the Initialization Vector corresponds to the initialization vector.
630 /// For CTR mode, it corresponds to the counter value.
631 #[inline]
632 pub fn set_initialization_vector(&self, iv: InitVec) {
633 for (index, data) in iv.iter().enumerate() {
634 self.aes()
635 .intvectv(index)
636 .write(|w| unsafe { w.bits(*data) });
637 }
638 }
639
640 // Hash key (GCM mode only)
641
642 /// Set GCM hash key value (GCM mode only)
643 #[inline]
644 pub fn set_hashkey(&self, hashkey: Hashkey) {
645 for (index, data) in hashkey.iter().enumerate() {
646 self.aes()
647 .hashkey(index)
648 .write(|w| unsafe { w.bits(*data) });
649 }
650 }
651
652 pub fn get_hashkey(&self) -> Hashkey {
653 let mut output = [0; 4];
654 for (index, data) in output.iter_mut().enumerate() {
655 *data = self.aes().hashkey(index).read().bits();
656 }
657 output
658 }
659
660 // Galois Hash (GCM mode only)
661
662 /// Set Galois Hash value (GCM mode only)
663 ///
664 /// Writing a new key to keyword clears `GHASH`
665 #[inline]
666 pub fn set_ghash(&self, ghash: Ghash) {
667 for (index, data) in ghash.iter().enumerate() {
668 self.aes().ghash(index).write(|w| unsafe { w.bits(*data) });
669 }
670 }
671
672 /// Read Galois Hash value (GCM mode only)
673 #[inline]
674 pub fn get_ghash(&self) -> Ghash {
675 let mut output = [0; 4];
676 for (index, data) in output.iter_mut().enumerate() {
677 *data = self.aes().ghash(index).read().bits();
678 }
679 output
680 }
681
682 // Galois Hash x (GCM mode only)
683
684 /// Set cipher length (GCM mode only)
685 #[inline]
686 pub fn set_ciplen(&self, ciplen: Ciplen) {
687 self.ciplen().write(|w| unsafe { w.bits(ciplen) });
688 }
689
690 /// Read Cipher Length (GCM mode only)
691 #[inline]
692 pub fn get_ciplen(&self) -> Ciplen {
693 self.ciplen().read().bits()
694 }
695
696 // Random Seed
697
698 /// Set a new seed for the AES random number generator
699 #[inline]
700 pub fn set_randseed(&self, seed: Seed) {
701 self.randseed().write(|w| unsafe { w.bits(seed) });
702 }
703}