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}