1
#![cfg_attr(docsrs, procmacros::doc_replace)]
2
//! # Advanced Encryption Standard (AES).
3
//!
4
//! ## Overview
5
//!
6
//! The AES accelerator is a hardware device that speeds up computation
7
//! using AES algorithm significantly, compared to AES algorithms implemented
8
//! solely in software.  The AES accelerator has two working modes, which are
9
//! Typical AES and AES-DMA.
10
//!
11
//! ## Configuration
12
//!
13
//! The AES peripheral can be configured to encrypt or decrypt data using
14
//! different encryption/decryption modes.
15
//!
16
//! When using AES-DMA, the peripheral can be configured to use different block
17
//! cipher modes such as ECB, CBC, OFB, CTR, CFB8, and CFB128.
18
//!
19
//! ## Examples
20
//!
21
//! ### Encrypting and decrypting a message
22
//!
23
//! Simple example of encrypting and decrypting a message using AES-128:
24
//!
25
//! ```rust, no_run
26
//! # {before_snippet}
27
//! # use esp_hal::aes::{Aes, Operation};
28
//! # let keytext = b"SUp4SeCp@sSw0rd";
29
//! # let plaintext = b"message";
30
//! # let mut keybuf = [0_u8; 16];
31
//! # keybuf[..keytext.len()].copy_from_slice(keytext);
32
//! #
33
//! let mut block = [0_u8; 16];
34
//! block[..plaintext.len()].copy_from_slice(plaintext);
35
//!
36
//! let mut aes = Aes::new(peripherals.AES);
37
//! aes.encrypt(&mut block, keybuf);
38
//!
39
//! // The encryption happens in-place, so the ciphertext is in `block`
40
//!
41
//! aes.decrypt(&mut block, keybuf);
42
//!
43
//! // The decryption happens in-place, so the plaintext is in `block`
44
//! # {after_snippet}
45
//! ```
46

            
47
use core::ptr::NonNull;
48

            
49
use crate::{
50
    aes::cipher_modes::{CryptoBuffers, UnsafeCryptoBuffers},
51
    pac,
52
    peripherals::AES,
53
    system::{CryptoClockGuard, GenericPeripheralGuard},
54
};
55

            
56
pub mod cipher_modes;
57

            
58
270
for_each_aes_key_length! {
59
    ($len:literal) => {
60
        // Implementing From for easy conversion from array to Key enum.
61
        impl From<[u8; $len / 8]> for Key {
62
            fn from(key: [u8; $len / 8]) -> Self {
63
                paste::paste! {
64
1
                    Key::[<Key $len>](key)
65
                }
66
            }
67
        }
68
    };
69

            
70
    (bits $( ($len:literal) ),*) => {
71
        paste::paste! {
72
            /// Represents the various key sizes allowed for AES encryption and decryption.
73
            pub enum Key {
74
                $(
75
                    #[doc = concat!(stringify!($len), "-bit AES key")]
76
                    [<Key $len>]([u8; $len / 8]),
77
                )*
78
            }
79

            
80
            impl Key {
81
                /// Returns a slice representation of the AES key.
82
                fn as_slice(&self) -> &[u8] {
83
                    match self {
84
                        $(
85
                            Self::[<Key $len>](key) => key.as_ref(),
86
                        )*
87
                    }
88
                }
89

            
90
                fn copy(&self) -> Self {
91
270
                    match self {
92
                        $(
93
                            Self::[<Key $len>](key) => Self::[<Key $len>](*key),
94
                        )*
95
                    }
96
                }
97
            }
98

            
99
            impl Drop for Key {
100
298
                fn drop(&mut self) {
101
                    use core::mem::MaybeUninit;
102
                    unsafe { (self as *mut Self).cast::<MaybeUninit<Self>>().write_volatile(MaybeUninit::zeroed()) };
103
298
                }
104
            }
105
        }
106
    };
107

            
108
    (modes $(($bits:literal, $encrypt:literal, $decrypt:literal)),*) => {
109
        paste::paste! {
110
            /// Defines the operating modes for AES encryption and decryption.
111
            #[repr(C)]
112
            #[derive(Clone, Copy, PartialEq, Eq, Debug)]
113
            enum Mode {
114
                $(
115
                    [<Encryption $bits>] = $encrypt,
116
                    [<Decryption $bits>] = $decrypt,
117
                )*
118
            }
119

            
120
            impl Key {
121
                fn encrypt_mode(&self) -> Mode {
122
                    match self {
123
                        $(Self::[<Key $bits>](_) => Mode::[<Encryption $bits>],)*
124
                    }
125
                }
126

            
127
                fn decrypt_mode(&self) -> Mode {
128
                    match self {
129
                        $(Self::[<Key $bits>](_) => Mode::[<Decryption $bits>],)*
130
                    }
131
                }
132
            }
133
        }
134
    };
135
}
136

            
137
/// The possible AES operations.
138
4
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
139
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
140
pub enum Operation {
141
    /// Produces ciphertext from plaintext.
142
    Encrypt,
143

            
144
    /// Produces plaintext from ciphertext.
145
    Decrypt,
146
}
147

            
148
/// AES peripheral container
149
pub struct Aes<'d> {
150
    aes: AES<'d>,
151
    _guard: GenericPeripheralGuard<{ crate::system::Peripheral::Aes as u8 }>,
152
    _clock_guard: CryptoClockGuard,
153
}
154

            
155
impl<'d> Aes<'d> {
156
    /// Creates a new `Aes` instance.
157
2
    pub fn new(aes: AES<'d>) -> Self {
158
        let clock_guard = CryptoClockGuard::new();
159
        let guard = GenericPeripheralGuard::new();
160

            
161
        #[cfg_attr(not(aes_supports_dma), expect(unused_mut))]
162
        let mut this = Self {
163
            aes,
164
            _guard: guard,
165
            _clock_guard: clock_guard,
166
        };
167

            
168
        #[cfg(aes_supports_dma)]
169
        this.write_dma(false);
170

            
171
        this
172
2
    }
173

            
174
    fn regs(&self) -> &pac::aes::RegisterBlock {
175
        self.aes.register_block()
176
    }
177

            
178
    /// Configures how the state matrix would be laid out.
179
    #[cfg(aes_endianness_configurable)]
180
    pub fn write_endianness(
181
        &mut self,
182
        input_text_word_endianess: Endianness,
183
        input_text_byte_endianess: Endianness,
184
        output_text_word_endianess: Endianness,
185
        output_text_byte_endianess: Endianness,
186
        key_word_endianess: Endianness,
187
        key_byte_endianess: Endianness,
188
    ) {
189
        let mut to_write = 0_u32;
190
        to_write |= key_byte_endianess as u32;
191
        to_write |= (key_word_endianess as u32) << 1;
192
        to_write |= (input_text_byte_endianess as u32) << 2;
193
        to_write |= (input_text_word_endianess as u32) << 3;
194
        to_write |= (output_text_byte_endianess as u32) << 4;
195
        to_write |= (output_text_word_endianess as u32) << 5;
196
        self.regs().endian().write(|w| unsafe { w.bits(to_write) });
197
    }
198

            
199
    fn start(&self) {
200
        cfg_select! {
201
            esp32 => {
202
                self.regs().start().write(|w| w.start().set_bit());
203
            }
204
            _ => {
205
                self.regs().trigger().write(|w| w.trigger().set_bit());
206
            }
207
        }
208
    }
209

            
210
    fn is_idle(&mut self) -> bool {
211
        cfg_select! {
212
            esp32 => self.regs().idle().read().idle().bit_is_set(),
213
256
            _ => self.regs().state().read().state().bits() == 0,
214
        }
215
    }
216

            
217
328
    fn write_key(&mut self, input: &[u8]) {
218
        for (i, word) in read_words(input).enumerate() {
219
            self.regs().key(i).write(|w| unsafe { w.bits(word) });
220
        }
221
328
    }
222

            
223
    /// Clears all key registers, no key material should be left in the peripheral.
224
    #[cfg(clear_crypto_secrets)]
225
    fn clear_key(&mut self) {
226
23
        self.write_key(&[0; 32]);
227
    }
228

            
229
822
    fn write_block(&mut self, block: &[u8]) {
230
        for (i, word) in read_words(block).enumerate() {
231
            cfg_select! {
232
                aes_has_split_text_registers => {
233
                    self.regs().text_in(i).write(|w| unsafe { w.bits(word) });
234
                }
235
                _ => {
236
                    self.regs().text(i).write(|w| unsafe { w.bits(word) });
237
                }
238
            }
239
        }
240
822
    }
241

            
242
822
    fn read_block(&self, block: &mut [u8]) {
243
        cfg_select! {
244
            aes_has_split_text_registers => {
245
                write_words(block, |i| self.regs().text_out(i).read().bits());
246
            }
247
            _ => {
248
                write_words(block, |i| self.regs().text(i).read().bits());
249
            }
250
        }
251
822
    }
252

            
253
4
    fn write_mode(&self, mode: Mode) {
254
        self.regs().mode().write(|w| unsafe { w.bits(mode as _) });
255
4
    }
256

            
257
    #[cfg(aes_supports_dma)]
258
    fn write_dma(&mut self, enable_dma: bool) {
259
        self.regs()
260
            .dma_enable()
261
            .write(|w| w.dma_enable().bit(enable_dma));
262
    }
263

            
264
4
    fn process(&mut self, block: &mut [u8; 16], mode: Mode, key: Key) {
265
4
        self.write_key(key.as_slice());
266
        self.write_mode(mode);
267
4
        self.write_block(block);
268
        self.start();
269
4
        while !(self.is_idle()) {}
270
4
        self.read_block(block);
271

            
272
        // The `key` is dropped, but the hardware retains a copy in the key registers, clear them
273
        // too.
274
        #[cfg(clear_crypto_secrets)]
275
        self.clear_key();
276
4
    }
277

            
278
    /// Encrypts the given buffer with the given key.
279
    pub fn encrypt(&mut self, block: &mut [u8; 16], key: impl Into<Key>) {
280
        let key = key.into();
281
        let mode = key.encrypt_mode();
282
1
        self.process(block, mode, key)
283
    }
284

            
285
    /// Decrypts the given buffer with the given key.
286
    pub fn decrypt(&mut self, block: &mut [u8; 16], key: impl Into<Key>) {
287
        let key = key.into();
288
        let mode = key.decrypt_mode();
289
1
        self.process(block, mode, key)
290
    }
291

            
292
    /// Encrypts or decrypts the given buffer based on the `mode` parameter.
293
23
    fn process_work_item(&mut self, work_item: &mut AesOperation) {
294
        // Note that we can't just create slices out of the input and output buffers, because they
295
        // may alias (when encrypting/decrypting data in place).
296

            
297
        let slice = work_item.key.as_slice();
298
18
        self.write_key(slice);
299
        self.write_mode(unsafe {
300
            work_item
301
                .cipher_mode
302
                .as_ref()
303
15
                .software_operating_mode(work_item.mode, &work_item.key)
304
        });
305

            
306
        let process_block = |input: NonNull<[u8]>, mut output: NonNull<[u8]>| {
307
256
            unsafe { self.write_block(input.as_ref()) };
308
            self.start();
309
256
            while !self.is_idle() {}
310
256
            unsafe { self.read_block(output.as_mut()) };
311
        };
312

            
313
        // Safety: the reference to the algorithm state is only held for the duration of the
314
        // operation.
315
10
        match unsafe { work_item.cipher_mode.as_mut() } {
316
11
            CipherState::Ecb(algo) => algo.encrypt_decrypt(work_item.buffers, process_block),
317
4
            CipherState::Cbc(algo) => {
318
4
                if work_item.mode == Operation::Encrypt {
319
                    algo.encrypt(work_item.buffers, process_block);
320
                } else {
321
                    algo.decrypt(work_item.buffers, process_block);
322
                }
323
            }
324
2
            CipherState::Ofb(algo) => algo.encrypt_decrypt(work_item.buffers, process_block),
325
2
            CipherState::Ctr(algo) => algo.encrypt_decrypt(work_item.buffers, process_block),
326
            CipherState::Cfb8(algo) => {
327
2
                if work_item.mode == Operation::Encrypt {
328
                    algo.encrypt(work_item.buffers, process_block)
329
                } else {
330
                    algo.decrypt(work_item.buffers, process_block)
331
                }
332
            }
333
            CipherState::Cfb128(algo) => {
334
4
                if work_item.mode == Operation::Encrypt {
335
1
                    algo.encrypt(work_item.buffers, process_block)
336
                } else {
337
1
                    algo.decrypt(work_item.buffers, process_block)
338
                }
339
            }
340
        }
341

            
342
        #[cfg(clear_crypto_secrets)]
343
        self.clear_key();
344
23
    }
345
}
346

            
347
/// Data endianness
348
#[cfg(aes_endianness_configurable)]
349
pub enum Endianness {
350
    /// Big endian (most-significant byte at the smallest address)
351
    BigEndian    = 1,
352
    /// Little endian (least-significant byte at the smallest address)
353
    LittleEndian = 0,
354
}
355

            
356
/// Provides DMA (Direct Memory Access) support for AES operations.
357
///
358
/// This module enhances the AES capabilities by utilizing DMA to handle data
359
/// transfer, which can significantly speed up operations when dealing with
360
/// large data volumes. It supports various cipher modes such as ECB, CBC, OFB,
361
/// CTR, CFB8, and CFB128.
362
#[cfg(aes_supports_dma)]
363
pub mod dma {
364
    use core::{mem::ManuallyDrop, ptr::NonNull};
365

            
366
    use procmacros::{handler, ram};
367

            
368
    #[cfg(dma_can_access_psram)]
369
    use crate::dma::ManualWritebackBuffer;
370
    use crate::{
371
        Blocking,
372
        aes::{
373
            AES_WORK_QUEUE,
374
            AesOperation,
375
            BLOCK_SIZE,
376
            CipherState,
377
            Key,
378
            Mode,
379
            Operation,
380
            UnsafeCryptoBuffers,
381
            cipher_modes,
382
            read_words,
383
        },
384
        dma::{
385
            Channel,
386
            DmaDescriptor,
387
            DmaEligiblePeripheral,
388
            DmaError,
389
            DmaRxBuffer,
390
            DmaTxBuffer,
391
            NoBuffer,
392
            aligned::InternalMemory,
393
            prepare_for_rx,
394
            prepare_for_tx,
395
        },
396
        peripherals::AES,
397
        system::{Peripheral, PeripheralClockControl},
398
        work_queue::{Poll, Status, VTable, WorkQueueDriver},
399
    };
400

            
401
    /// Specifies the block cipher modes available for AES operations.
402
270
    #[derive(Clone, Copy, PartialEq, Eq)]
403
    pub enum CipherMode {
404
        /// Electronic Codebook Mode
405
        #[cfg(aes_dma_mode_ecb)]
406
        Ecb    = 0,
407
        /// Cipher Block Chaining Mode
408
        #[cfg(aes_dma_mode_cbc)]
409
        Cbc    = 1,
410
        /// Output Feedback Mode
411
        #[cfg(aes_dma_mode_ofb)]
412
        Ofb    = 2,
413
        /// Counter Mode.
414
        #[cfg(aes_dma_mode_ctr)]
415
        Ctr    = 3,
416
        /// Cipher Feedback Mode with 8-bit shifting.
417
        #[cfg(aes_dma_mode_cfb8)]
418
        Cfb8   = 4,
419
        /// Cipher Feedback Mode with 128-bit shifting.
420
        #[cfg(aes_dma_mode_cfb128)]
421
        Cfb128 = 5,
422
        // TODO: GCM needs different handling, not supported yet
423
    }
424

            
425
    // If we can process from PSRAM, we need 2 extra descriptors. One will store the unaligned head,
426
    // one will store the unaligned tail.
427
    const OUT_DESCR_COUNT: usize = 1 + 2 * cfg!(dma_can_access_psram) as usize;
428

            
429
    /// A DMA capable AES instance.
430
    #[instability::unstable]
431
    pub struct AesDma<'d> {
432
        /// The underlying [`Aes`](super::Aes) driver
433
        pub aes: super::Aes<'d>,
434

            
435
        channel: Channel<Blocking, AesErased<'d>>,
436
    }
437

            
438
    impl<'d> super::Aes<'d> {
439
        /// Enables DMA for the current instance of the AES driver.
440
        pub fn with_dma(self, channel: impl AesDmaChannel<'d>) -> AesDma<'d> {
441
270
            let channel = Channel::new(channel.into());
442
270
            channel.runtime_ensure_compatible(self.aes.dma_peripheral());
443
270
            AesDma { aes: self, channel }
444
        }
445
    }
446

            
447
    impl core::fmt::Debug for AesDma<'_> {
448
        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
449
            f.debug_struct("AesDma").finish()
450
        }
451
    }
452

            
453
    impl<'d> AesDma<'d> {
454
4
        fn write_key(&mut self, key: &Key) {
455
            let key = key.as_slice();
456
270
            self.aes.write_key(key);
457
        }
458

            
459
        fn write_iv(&mut self, iv: &[u8; BLOCK_SIZE]) {
460
            for (word, reg) in read_words(iv).zip(self.aes.regs().iv_mem_iter()) {
461
                reg.write(|w| unsafe { w.bits(word) });
462
            }
463
        }
464

            
465
180
        fn read_iv(&self, iv: &mut [u8; BLOCK_SIZE]) {
466
            iv[0..4].copy_from_slice(&self.aes.regs().iv_mem(0).read().bits().to_le_bytes());
467
            iv[4..8].copy_from_slice(&self.aes.regs().iv_mem(1).read().bits().to_le_bytes());
468
            iv[8..12].copy_from_slice(&self.aes.regs().iv_mem(2).read().bits().to_le_bytes());
469
            iv[12..16].copy_from_slice(&self.aes.regs().iv_mem(3).read().bits().to_le_bytes());
470
180
        }
471

            
472
4
        fn start_dma_transfer<RXBUF, TXBUF>(
473
            mut self,
474
            number_of_blocks: usize,
475
            mut output: RXBUF,
476
            mut input: TXBUF,
477
            mode: Mode,
478
            cipher_mode: CipherMode,
479
            key: &Key,
480
        ) -> Result<AesTransfer<'d, RXBUF, TXBUF>, (DmaError, Self, RXBUF, TXBUF)>
481
        where
482
            TXBUF: DmaTxBuffer,
483
            RXBUF: DmaRxBuffer,
484
        {
485
            let peri = self.aes.aes.dma_peripheral();
486

            
487
270
            if let Err(error) = unsafe { self.channel.tx.prepare_transfer(peri, &mut input) }
488
                .and_then(|_| unsafe { self.channel.rx.prepare_transfer(peri, &mut output) })
489
                // Start them together, to avoid the latter prepare discarding data from FIFOs.
490
                .and_then(|_| self.channel.tx.start_transfer())
491
                .and_then(|_| self.channel.rx.start_transfer())
492
            {
493
                return Err((error, self, output, input));
494
            }
495

            
496
4
            self.enable_dma(true);
497
4
            self.listen();
498

            
499
4
            self.aes.write_mode(mode);
500
4
            self.write_key(key);
501

            
502
4
            self.set_cipher_mode(cipher_mode);
503
4
            self.set_num_block(number_of_blocks as u32);
504

            
505
4
            self.start_transform();
506

            
507
4
            Ok(AesTransfer {
508
270
                aes_dma: ManuallyDrop::new(self),
509
4
                rx_view: ManuallyDrop::new(output.into_view()),
510
                tx_view: ManuallyDrop::new(input.into_view()),
511
            })
512
4
        }
513

            
514
        /// Performs a DMA transfer.
515
        ///
516
        /// Returns an [`AesTransfer`].
517
        pub fn process<K, RXBUF, TXBUF>(
518
            mut self,
519
            number_of_blocks: usize,
520
            output: RXBUF,
521
            input: TXBUF,
522
            mode: Operation,
523
            cipher_state: &DmaCipherState,
524
            key: K,
525
        ) -> Result<AesTransfer<'d, RXBUF, TXBUF>, (DmaError, Self, RXBUF, TXBUF)>
526
        where
527
            K: Into<Key>,
528
            TXBUF: DmaTxBuffer,
529
            RXBUF: DmaRxBuffer,
530
        {
531
            // AES has to be restarted after each calculation
532
1
            self.reset_aes();
533

            
534
            // This unwrap is fine, the cipher state can only be constructed from supported
535
            // modes of operation.
536
1
            let cipher_mode = unwrap!(cipher_state.state.hardware_cipher_mode());
537

            
538
            let key = key.into();
539
1
            cipher_state.state.write_state(&mut self);
540

            
541
            let mode = cipher_state.state.hardware_operating_mode(mode, &key);
542

            
543
1
            self.start_dma_transfer(number_of_blocks, output, input, mode, cipher_mode, &key)
544
        }
545

            
546
4
        fn reset_aes(&self) {
547
            PeripheralClockControl::reset(Peripheral::Aes);
548
4
        }
549

            
550
4
        fn enable_dma(&self, enable: bool) {
551
            self.aes
552
                .regs()
553
                .dma_enable()
554
                .write(|w| w.dma_enable().bit(enable));
555
4
        }
556

            
557
4
        fn listen(&self) {
558
            self.aes.regs().int_ena().write(|w| w.int_ena().set_bit());
559
4
        }
560

            
561
        fn clear_interrupt(&self) {
562
            self.aes.regs().int_clr().write(|w| w.int_clr().set_bit());
563
        }
564

            
565
4
        fn set_cipher_mode(&self, mode: CipherMode) {
566
            self.aes
567
                .regs()
568
                .block_mode()
569
                .modify(|_, w| unsafe { w.block_mode().bits(mode as u8) });
570

            
571
            // FIXME
572
270
            if mode == CipherMode::Ctr {
573
                self.aes
574
                    .regs()
575
                    .inc_sel()
576
                    .modify(|_, w| w.inc_sel().clear_bit());
577
            }
578
4
        }
579

            
580
4
        fn start_transform(&self) {
581
            self.aes.start();
582
4
        }
583

            
584
4
        fn finish_transform(&self) {
585
            self.aes.regs().dma_exit().write(|w| w.dma_exit().set_bit());
586
            self.enable_dma(false);
587
            self.reset_aes();
588
4
        }
589

            
590
4
        fn set_num_block(&self, block: u32) {
591
            self.aes
592
                .regs()
593
                .block_num()
594
                .modify(|_, w| unsafe { w.block_num().bits(block) });
595
4
        }
596

            
597
4
        fn is_done(&self) -> bool {
598
            const DMA_STATUS_DONE: u8 = 2;
599
            // TODO: PAC should provide the variants
600
270
            self.aes.regs().state().read().state().bits() == DMA_STATUS_DONE
601
4
        }
602
    }
603

            
604
    /// Represents an ongoing (or potentially stopped) transfer with the Aes.
605
    #[instability::unstable]
606
    pub struct AesTransfer<'d, RX: DmaRxBuffer, TX: DmaTxBuffer> {
607
        aes_dma: ManuallyDrop<AesDma<'d>>,
608
        rx_view: ManuallyDrop<RX::View>,
609
        tx_view: ManuallyDrop<TX::View>,
610
    }
611

            
612
    impl<'d, RX: DmaRxBuffer, TX: DmaTxBuffer> AesTransfer<'d, RX, TX> {
613
        /// Returns whether [`Self::wait`] will not block.
614
        pub fn is_done(&self) -> bool {
615
1
            self.aes_dma.is_done()
616
        }
617

            
618
        /// Waits for the transfer to finish and returns the peripheral and
619
        /// buffers.
620
        pub fn wait(mut self) -> (AesDma<'d>, RX::Final, TX::Final) {
621
270
            while !self.is_done() {}
622
270
            while !self.aes_dma.channel.rx.is_done() {}
623

            
624
            // Stop the DMA as it doesn't know that the aes has stopped.
625
            self.aes_dma.channel.rx.stop_transfer();
626
1
            self.aes_dma.channel.tx.stop_transfer();
627

            
628
1
            self.aes_dma.finish_transform();
629

            
630
            unsafe {
631
                let aes_dma = ManuallyDrop::take(&mut self.aes_dma);
632
                let rx_view = ManuallyDrop::take(&mut self.rx_view);
633
                let tx_view = ManuallyDrop::take(&mut self.tx_view);
634

            
635
                core::mem::forget(self);
636

            
637
                (aes_dma, RX::from_view(rx_view), TX::from_view(tx_view))
638
            }
639
        }
640

            
641
        /// Provides shared access to the DMA rx buffer view.
642
        pub fn rx_view(&self) -> &RX::View {
643
            &self.rx_view
644
        }
645

            
646
        /// Provides exclusive access to the DMA rx buffer view.
647
        pub fn rx_view_mut(&mut self) -> &mut RX::View {
648
            &mut self.rx_view
649
        }
650

            
651
        /// Provides shared access to the DMA tx buffer view.
652
        pub fn tx_view(&self) -> &TX::View {
653
            &self.tx_view
654
        }
655

            
656
        /// Provides exclusive access to the DMA tx buffer view.
657
        pub fn tx_view_mut(&mut self) -> &mut TX::View {
658
            &mut self.tx_view
659
        }
660
    }
661

            
662
    impl<RX: DmaRxBuffer, TX: DmaTxBuffer> Drop for AesTransfer<'_, RX, TX> {
663
        fn drop(&mut self) {
664
            // Stop the DMA to prevent further memory access.
665
            self.aes_dma.channel.rx.stop_transfer();
666
            self.aes_dma.channel.tx.stop_transfer();
667

            
668
            // SAFETY: This is Drop, we know that self.aes_dma and self.buf_view
669
            // won't be touched again.
670
            unsafe {
671
                ManuallyDrop::drop(&mut self.aes_dma);
672
            }
673
            let rx_view = unsafe { ManuallyDrop::take(&mut self.rx_view) };
674
            let tx_view = unsafe { ManuallyDrop::take(&mut self.tx_view) };
675
            let _ = RX::from_view(rx_view);
676
            let _ = TX::from_view(tx_view);
677
        }
678
    }
679

            
680
    const AES_DMA_VTABLE: VTable<super::AesOperation> = VTable {
681
        post: |driver, item| {
682
            let driver = unsafe { AesDmaBackend::from_raw(driver) };
683
            driver.start_processing(item);
684
            Some(Poll::Pending(false))
685
        },
686
        poll: |driver, item| {
687
            let driver = unsafe { AesDmaBackend::from_raw(driver) };
688
            driver.poll_status(item)
689
        },
690
        cancel: |_driver, _item| {
691
            // We can't (shouldn't) abort an in-progress computation, or we may corrupt the block
692
            // cipher's state.
693
        },
694
        stop: |driver| {
695
            // Drop the AES driver to conserve power when there is nothing to do (or when the driver
696
            // was stopped).
697
            let driver = unsafe { AesDmaBackend::from_raw(driver) };
698
            driver.deinitialize()
699
        },
700
    };
701

            
702
    enum DriverState<'d> {
703
        None,
704
        Idle(AesDma<'d>),
705
        WaitingForDma {
706
            transfer: AesTransfer<'d, NoBuffer, NoBuffer>,
707
            remaining_bytes: usize,
708
        },
709
    }
710

            
711
    #[procmacros::doc_replace(
712
        "dma_channel" => {
713
            cfg(aes_dma_engine = "CRYPTO_DMA") => "DMA_CRYPTO",
714
            cfg(aes_dma_engine = "AXI_GDMA") => "DMA_AXI_CH0",
715
            _ => "DMA_CH0"
716
        }
717
    )]
718
    /// DMA-enabled AES processing backend.
719
    ///
720
    /// The backend will try its best to use hardware acceleration as much as possible. It will
721
    /// fall back to CPU-driven processing (equivalent to [`AesBackend`](super::AesBackend)) in some
722
    /// cases, including:
723
    ///
724
    /// - When the block cipher is not implemented in hardware.
725
    /// - When the data is not correctly aligned to the needs of the hardware (e.g. when using a
726
    ///   stream cipher mode, the data length is not an integer multiple of 16 bytes).
727
    ///
728
    /// # Examples
729
    ///
730
    /// ```rust, no_run
731
    /// # {before_snippet}
732
    /// use esp_hal::aes::{AesContext, Operation, cipher_modes::Ecb, dma::AesDmaBackend};
733
    ///
734
    /// let mut aes = AesDmaBackend::new(peripherals.AES, peripherals.__dma_channel__);
735
    /// // Start the backend, which allows processing AES operations.
736
    /// let _backend = aes.start();
737
    ///
738
    /// // Create a new context with a 128-bit key. The context will use the ECB block cipher mode.
739
    /// // The key length must be supported by the hardware.
740
    /// let mut ecb_encrypt = AesContext::new(Ecb, Operation::Encrypt, *b"SUp4SeCp@sSw0rd\0");
741
    ///
742
    /// // Process a block of data in this context. The ECB mode of operation requires that
743
    /// // the length of the data is a multiple of the block (16 bytes) size.
744
    /// let input_buffer: [u8; 16] = *b"message\0\0\0\0\0\0\0\0\0";
745
    /// let mut output_buffer: [u8; 16] = [0; 16];
746
    ///
747
    /// let operation_handle = ecb_encrypt.process(&input_buffer, &mut output_buffer)?;
748
    /// operation_handle.wait_blocking();
749
    ///
750
    /// // output_buffer now contains the ciphertext
751
    /// assert_eq!(
752
    ///     output_buffer,
753
    ///     [
754
    ///         0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
755
    ///         0x31, 0x96,
756
    ///     ]
757
    /// );
758
    /// #
759
    /// # {after_snippet}
760
    /// ```
761
    pub struct AesDmaBackend<'d> {
762
        peri: AES<'d>,
763
        dma: AesErased<'d>,
764
        state: DriverState<'d>,
765

            
766
        #[cfg(dma_can_access_psram)]
767
        unaligned_data_buffers: [Option<ManualWritebackBuffer>; 2],
768
        descriptors: InternalMemory<[DmaDescriptor; OUT_DESCR_COUNT + 1]>,
769
    }
770

            
771
    // The DMA descriptors prevent auto-implementing Sync and Send, but they can be treated as Send
772
    // and Sync because we only access them in a critical section (around the work queue
773
    // operations), and only when the DMA is not actively using them. `unaligned_data_buffers`
774
    // contain pointers to AesContext data, and are only accessed when the associated data is
775
    // handled by the work queue. Other parts of the backend are Send and Sync automatically.
776
    unsafe impl Sync for AesDmaBackend<'_> {}
777
    unsafe impl Send for AesDmaBackend<'_> {}
778

            
779
    impl<'d> AesDmaBackend<'d> {
780
        #[procmacros::doc_replace(
781
            "dma_channel" => {
782
                cfg(aes_dma_engine = "CRYPTO_DMA") => "DMA_CRYPTO",
783
                cfg(aes_dma_engine = "AXI_GDMA") => "DMA_AXI_CH0",
784
                _ => "DMA_CH0"
785
            }
786
        )]
787
        /// Creates a new DMA-enabled AES backend.
788
        ///
789
        /// The backend must be started with [`Self::start`] before it can execute AES operations.
790
        ///
791
        /// # Examples
792
        ///
793
        /// ```rust, no_run
794
        /// # {before_snippet}
795
        /// use esp_hal::aes::dma::AesDmaBackend;
796
        ///
797
        /// let mut aes = AesDmaBackend::new(peripherals.AES, peripherals.__dma_channel__);
798
        /// # {after_snippet}
799
        /// ```
800
        pub fn new(aes: AES<'d>, dma: impl AesDmaChannel<'d>) -> Self {
801
            Self {
802
                peri: aes,
803
                dma: dma.into(),
804
                state: DriverState::None,
805

            
806
                #[cfg(dma_can_access_psram)]
807
                unaligned_data_buffers: [const { None }; 2],
808
                descriptors: InternalMemory::new([DmaDescriptor::EMPTY; OUT_DESCR_COUNT + 1]),
809
            }
810
        }
811

            
812
        #[procmacros::doc_replace(
813
            "dma_channel" => {
814
                cfg(aes_dma_engine = "CRYPTO_DMA") => "DMA_CRYPTO",
815
                cfg(aes_dma_engine = "AXI_GDMA") => "DMA_AXI_CH0",
816
                _ => "DMA_CH0"
817
            }
818
        )]
819
        /// Registers the DMA-driven AES driver to process AES operations.
820
        ///
821
        /// The driver stops operating when the returned object is dropped.
822
        ///
823
        /// # Examples
824
        ///
825
        /// ```rust, no_run
826
        /// # {before_snippet}
827
        /// use esp_hal::aes::dma::AesDmaBackend;
828
        ///
829
        /// let mut aes = AesDmaBackend::new(peripherals.AES, peripherals.__dma_channel__);
830
        /// let _handle = aes.start();
831
        /// # {after_snippet}
832
        /// ```
833
1
        pub fn start(&mut self) -> AesDmaWorkQueueDriver<'_, 'd> {
834
            AesDmaWorkQueueDriver {
835
                _inner: WorkQueueDriver::new(self, AES_DMA_VTABLE, &super::AES_WORK_QUEUE),
836
            }
837
1
        }
838

            
839
        // WorkQueue callbacks. They may run in any context.
840

            
841
        unsafe fn from_raw<'any>(ptr: NonNull<()>) -> &'any mut Self {
842
            unsafe { ptr.cast::<AesDmaBackend<'_>>().as_mut() }
843
        }
844

            
845
        fn start_processing(&mut self, item: &mut AesOperation) -> Poll {
846
270
            let driver = match core::mem::replace(&mut self.state, DriverState::None) {
847
                DriverState::None => {
848
                    let peri = unsafe { self.peri.clone_unchecked() };
849
270
                    let dma = unsafe { self.dma.clone_unchecked() };
850
                    let driver = super::Aes::new(peri).with_dma(dma);
851

            
852
                    driver.aes.aes.bind_peri_interrupt(interrupt_handler);
853

            
854
270
                    driver
855
                }
856
                DriverState::Idle(aes_dma) => aes_dma,
857
                _ => unreachable!(),
858
270
            };
859

            
860
            // There are some constraints that make us (partially) fall back to CPU-driven mode:
861
            // - The algo isn't implemented in hardware. Not much to do here, we process the whole
862
            //   data using the CPU.
863
            // - There is data stuck in the cipher state.
864
            //   - In this case we need to flush the data before we can start using the DMA.
865
            // - The data alignment isn't appropriate to its location (PSRAM)
866
            //   - The DMA can read (transmit) any number of bytes from any address (in theory), but
867
            //     it can't write arbitrarily to PSRAM. We should be able to split the write
868
            //     transfer into two parts, and write the unaligned bytes into internal memory using
869
            //     the DMA, then copy the data out to PSRAM using the CPU at the end.
870
            // - The data length (after all the above) is not a multiple of the block length
871
            //   - We process as many blocks as we can using the DMA, then use the CPU for the
872
            //     remainder.
873

            
874
            if unsafe { !item.cipher_mode.as_ref().implemented_in_hardware() } {
875
                // Algo is either not implemented in hardware, or the data is not accessible by DMA.
876
                self.process_with_cpu(driver, item);
877
                return Poll::Ready(Status::Completed);
878
            }
879

            
880
270
            if !crate::soc::is_valid_memory_address(item.buffers.input.addr().get()) {
881
                unsafe {
882
                    // Safety:
883
                    // We've verified when constructing the buffer that input and output are the
884
                    // same length. The CryptoBuffers constructor also ensures that output is
885
                    // mutable and therefore is in RAM. If input is not, the pointers
886
                    // don't overlap.
887
                    // A buffer created via `CryptoBuffers::new_in_place` will not reach here
888
                    // because it takes a `&mut` buffer, which is always in RAM.
889
                    item.buffers.output.cast::<u8>().copy_from_nonoverlapping(
890
                        item.buffers.input.cast::<u8>(),
891
                        item.buffers.input.len(),
892
                    );
893
                }
894
                // We've copied the data, now overwrite the pointer to make this an in-place
895
                // operation.
896
                item.buffers.input = item.buffers.output;
897
            }
898

            
899
            // Flush available bytes:
900
270
            let flushed = unsafe { item.cipher_mode.as_mut().flush(item.buffers, item.mode) };
901
180
            if flushed == item.buffers.input.len() {
902
                // No more data to process
903
                self.state = DriverState::Idle(driver);
904
                return Poll::Ready(Status::Completed);
905
            }
906

            
907
            // Process the remaining data with DMA:
908
270
            let mut new_item = AesOperation {
909
                mode: item.mode,
910
                cipher_mode: item.cipher_mode,
911
270
                buffers: unsafe { item.buffers.byte_add(flushed) },
912
270
                key: item.key.copy(),
913
            };
914

            
915
            // If there is enough data for the DMA, set it up:
916
270
            if let Err(driver) = self.process_with_dma(driver, &mut new_item) {
917
                // Otherwise, process the remaining data with CPU.
918
                self.process_with_cpu(driver, &mut new_item);
919
                return Poll::Ready(Status::Completed);
920
            }
921

            
922
            Poll::Pending(false)
923
        }
924

            
925
        fn poll_status(&mut self, item: &mut AesOperation) -> Poll {
926
270
            match &self.state {
927
270
                DriverState::WaitingForDma { transfer, .. } if !transfer.is_done() => {
928
                    Poll::Pending(false)
929
                }
930

            
931
                DriverState::WaitingForDma { .. } => {
932
270
                    let DriverState::WaitingForDma {
933
270
                        transfer,
934
270
                        remaining_bytes,
935
270
                    } = core::mem::replace(&mut self.state, DriverState::None)
936
                    else {
937
                        unreachable!()
938
                    };
939

            
940
                    let (driver, _, _) = transfer.wait();
941
                    unsafe { item.cipher_mode.as_mut() }.read_state(&driver);
942

            
943
                    driver.clear_interrupt();
944

            
945
                    // Write out PSRAM data if needed:
946
                    #[cfg(dma_can_access_psram)]
947
                    for buffer in self.unaligned_data_buffers.iter_mut() {
948
                        // Avoid copying the write_back buffer
949
                        if let Some(buffer) = buffer.as_mut() {
950
                            buffer.write_back();
951
                        }
952
                        *buffer = None;
953
                    }
954

            
955
                    // Now process the remainder:
956
270
                    if remaining_bytes > 0 {
957
                        let mut temp_item = AesOperation {
958
                            mode: item.mode,
959
                            cipher_mode: item.cipher_mode,
960
                            buffers: unsafe {
961
                                item.buffers
962
                                    .byte_add(item.buffers.input.len() - remaining_bytes)
963
                            },
964
                            key: item.key.copy(),
965
                        };
966

            
967
                        // If there is enough data for the DMA, set it up again:
968
                        if let Err(driver) = self.process_with_dma(driver, &mut temp_item) {
969
                            // Otherwise, process the remaining data with CPU.
970
                            self.process_with_cpu(driver, &mut temp_item);
971
                        } else {
972
                            return Poll::Pending(false);
973
                        }
974
                    }
975

            
976
                    Poll::Ready(Status::Completed)
977
270
                }
978
                _ => unreachable!(),
979
            }
980
        }
981

            
982
        fn process_with_cpu(&mut self, mut driver: AesDma<'d>, work_item: &mut AesOperation) {
983
            driver.aes.process_work_item(work_item);
984
            self.state = DriverState::Idle(driver);
985
        }
986

            
987
270
        fn process_with_dma(
988
            &mut self,
989
            mut driver: AesDma<'d>,
990
            work_item: &mut AesOperation,
991
        ) -> Result<(), AesDma<'d>> {
992
            let input_len = work_item.buffers.input.len();
993
            let (input_dscr, output_dscr) = self.descriptors.get_mut().into_inner().split_at_mut(1);
994
270
            let (input_buffer, data_len) = unsafe {
995
                // This unwrap is infallible as AES-DMA devices don't have TX DMA alignment
996
                // requirements.
997
270
                unwrap!(prepare_for_tx(
998
                    input_dscr,
999
270
                    work_item.buffers.input,
                    BLOCK_SIZE,
                ))
            };
270
            let number_of_blocks = data_len / BLOCK_SIZE;
270
            if number_of_blocks == 0 {
                // DMA can't do anything.
                return Err(driver);
            }
270
            let (output_buffer, rx_data_len) = unsafe {
270
                prepare_for_rx(
                    output_dscr,
                    #[cfg(dma_can_access_psram)]
                    &mut self.unaligned_data_buffers,
                    // Truncate data based on how much the TX buffer can read.
270
                    NonNull::slice_from_raw_parts(work_item.buffers.output.cast::<u8>(), data_len),
                )
            };
270
            debug_assert_eq!(rx_data_len, data_len);
            let cipher_state = unsafe { work_item.cipher_mode.as_ref() };
270
            cipher_state.write_state(&mut driver);
270
            let mode = cipher_state.hardware_operating_mode(work_item.mode, &work_item.key);
            // This unwrap is fine, this function is not called for modes of operation not supported
            // by the hardware.
            let cipher_mode = unwrap!(cipher_state.hardware_cipher_mode());
270
            let Ok(transfer) = driver.start_dma_transfer(
                number_of_blocks,
                output_buffer,
                input_buffer,
                mode,
                cipher_mode,
                &work_item.key,
            ) else {
                panic!()
            };
270
            self.state = DriverState::WaitingForDma {
                transfer,
270
                remaining_bytes: input_len - data_len,
            };
270
            Ok(())
270
        }
        fn deinitialize(&mut self) {
271
            self.state = DriverState::None;
        }
    }
    #[handler]
270
    #[ram]
    fn interrupt_handler() {
        AES_WORK_QUEUE.process();
270
    }
    /// An active work queue driver.
    ///
    /// This object must be kept around, otherwise AES operations will never complete.
    pub struct AesDmaWorkQueueDriver<'t, 'd> {
        _inner: WorkQueueDriver<'t, AesDmaBackend<'d>, AesOperation>,
    }
    /// The state of block ciphers that the AES hardware implements.
    #[derive(Clone)]
    pub struct DmaCipherState {
        state: CipherState,
    }
    impl DmaCipherState {
        /// Saves the block cipher state in memory so that it can be restored by a later operation.
        pub fn save_state(&mut self, aes_dma: &AesDma<'_>) {
            self.state.read_state(aes_dma);
        }
    }
    #[cfg(aes_dma_mode_ecb)]
    impl From<cipher_modes::Ecb> for DmaCipherState {
        fn from(value: cipher_modes::Ecb) -> Self {
1
            Self {
                state: CipherState::Ecb(value),
            }
        }
    }
    #[cfg(aes_dma_mode_cbc)]
    impl From<cipher_modes::Cbc> for DmaCipherState {
        fn from(value: cipher_modes::Cbc) -> Self {
            Self {
                state: CipherState::Cbc(value),
            }
        }
    }
    #[cfg(aes_dma_mode_ofb)]
    impl From<cipher_modes::Ofb> for DmaCipherState {
        fn from(value: cipher_modes::Ofb) -> Self {
            Self {
                state: CipherState::Ofb(value),
            }
        }
    }
    #[cfg(aes_dma_mode_ctr)]
    impl From<cipher_modes::Ctr> for DmaCipherState {
        fn from(value: cipher_modes::Ctr) -> Self {
            Self {
                state: CipherState::Ctr(value),
            }
        }
    }
    #[cfg(aes_dma_mode_cfb8)]
    impl From<cipher_modes::Cfb8> for DmaCipherState {
        fn from(value: cipher_modes::Cfb8) -> Self {
            Self {
                state: CipherState::Cfb8(value),
            }
        }
    }
    #[cfg(aes_dma_mode_cfb128)]
    impl From<cipher_modes::Cfb128> for DmaCipherState {
        fn from(value: cipher_modes::Cfb128) -> Self {
            Self {
                state: CipherState::Cfb128(value),
            }
        }
    }
    impl CipherState {
        fn hardware_cipher_mode(&self) -> Option<CipherMode> {
            #[allow(unreachable_patterns)]
            match self {
                #[cfg(aes_dma_mode_ecb)]
                Self::Ecb(_) => Some(CipherMode::Ecb),
                #[cfg(aes_dma_mode_cbc)]
                Self::Cbc(_) => Some(CipherMode::Cbc),
                #[cfg(aes_dma_mode_ofb)]
                Self::Ofb(_) => Some(CipherMode::Ofb),
                #[cfg(aes_dma_mode_ctr)]
                Self::Ctr(_) => Some(CipherMode::Ctr),
                #[cfg(aes_dma_mode_cfb8)]
                Self::Cfb8(_) => Some(CipherMode::Cfb8),
                #[cfg(aes_dma_mode_cfb128)]
                Self::Cfb128(_) => Some(CipherMode::Cfb128),
                // TODO: GCM
                _ => None,
            }
        }
        fn implemented_in_hardware(&self) -> bool {
            self.hardware_cipher_mode().is_some()
        }
        fn hardware_operating_mode(&self, operation: Operation, key: &Key) -> Mode {
270
            if operation == Operation::Encrypt {
                key.encrypt_mode()
            } else {
                key.decrypt_mode()
            }
        }
        fn flush(&mut self, buffers: UnsafeCryptoBuffers, mode: Operation) -> usize {
270
            match self {
                // These operate on complete blocks, nothing to flush:
                Self::Ecb(_) | Self::Cbc(_) => 0,
                // CFB8 shifts bytes but has no internal state other than IV:
                Self::Cfb8(_) => 0,
                // These modes may have bytes to output:
                Self::Ofb(ofb) => ofb.flush(buffers),
                Self::Ctr(ctr) => ctr.flush(buffers),
                Self::Cfb128(cfb128) => {
30
                    if mode == Operation::Encrypt {
                        cfb128.flush_encrypt(buffers)
                    } else {
                        cfb128.flush_decrypt(buffers)
                    }
                }
            }
        }
274
        fn write_state(&self, aes: &mut AesDma<'_>) {
274
            match self {
                CipherState::Ecb(_ecb) => {}
60
                CipherState::Cbc(cbc) => aes.write_iv(&cbc.iv),
                CipherState::Ofb(ofb) => aes.write_iv(&ofb.iv),
                CipherState::Ctr(ctr) => aes.write_iv(&ctr.nonce),
30
                CipherState::Cfb8(cfb8) => aes.write_iv(&cfb8.iv),
                CipherState::Cfb128(cfb128) => aes.write_iv(&cfb128.iv),
            }
274
        }
        fn read_state(&mut self, aes: &AesDma<'_>) {
270
            match self {
                CipherState::Ecb(_ecb) => {}
                CipherState::Cbc(cbc) => aes.read_iv(&mut cbc.iv),
90
                CipherState::Ofb(ofb) => aes.read_iv(&mut ofb.iv),
                CipherState::Ctr(ctr) => aes.read_iv(&mut ctr.nonce),
                CipherState::Cfb8(cfb8) => aes.read_iv(&mut cfb8.iv),
                CipherState::Cfb128(cfb128) => aes.read_iv(&mut cfb128.iv),
            }
        }
    }
    /// DMA channel trait for the AES peripheral.
    ///
    /// Implemented for every channel type capable of serving AES.
    #[diagnostic::on_unimplemented(
        message = "The DMA channel cannot be used with the AES peripheral",
        label = "This DMA channel"
    )]
    pub trait AesDmaChannel<'d>: crate::private::Sealed + Into<AesErased<'d>> {}
    with_aes_dma_engine! {
        ($engine:tt, $any_channel:ident) => {
            type AesErased<'d> = crate::dma::$any_channel<'d>;
            crate::macros::impl_dma_channel_trait! {
                $engine,
                peri = AES,
                ($peri:path, $ch:path) => {
                    impl<'d> AesDmaChannel<'d> for $ch {}
                }
            }
        };
    }
}
use crate::work_queue::{
    Handle,
    Poll,
    Status,
    VTable,
    WorkQueue,
    WorkQueueDriver,
    WorkQueueFrontend,
};
/// The stored state of various block cipher modes.
#[derive(Clone)]
#[non_exhaustive]
pub enum CipherState {
    /// Electronic Codebook Mode.
    Ecb(cipher_modes::Ecb),
    /// Cipher Block Chaining Mode.
    Cbc(cipher_modes::Cbc),
    /// Output Feedback Mode.
    Ofb(cipher_modes::Ofb),
    /// Counter Mode.
    Ctr(cipher_modes::Ctr),
    /// Cipher Feedback Mode with 8-bit shifting.
    Cfb8(cipher_modes::Cfb8),
    /// Cipher Feedback Mode with 128-bit shifting.
    Cfb128(cipher_modes::Cfb128),
    // Galois Counter Mode
    // Gcm(*mut Gcm), // TODO: this is more involved
}
impl From<cipher_modes::Ecb> for CipherState {
    fn from(value: cipher_modes::Ecb) -> Self {
        Self::Ecb(value)
    }
}
impl From<cipher_modes::Cbc> for CipherState {
    fn from(value: cipher_modes::Cbc) -> Self {
        Self::Cbc(value)
    }
}
impl From<cipher_modes::Ofb> for CipherState {
    fn from(value: cipher_modes::Ofb) -> Self {
16
        Self::Ofb(value)
    }
}
impl From<cipher_modes::Ctr> for CipherState {
    fn from(value: cipher_modes::Ctr) -> Self {
16
        Self::Ctr(value)
    }
}
impl From<cipher_modes::Cfb8> for CipherState {
    fn from(value: cipher_modes::Cfb8) -> Self {
        Self::Cfb8(value)
    }
}
impl From<cipher_modes::Cfb128> for CipherState {
    fn from(value: cipher_modes::Cfb128) -> Self {
16
        Self::Cfb128(value)
    }
}
impl CipherState {
    fn software_operating_mode(&self, operation: Operation, key: &Key) -> Mode {
18
        match self {
            CipherState::Ecb(_) | CipherState::Cbc(_) => {
15
                if operation == Operation::Encrypt {
                    key.encrypt_mode()
                } else {
                    key.decrypt_mode()
                }
            }
            // For these, decryption is handled in software using the hardware in ecryption mode to
            // produce intermediate results.
            CipherState::Ofb(_)
            | CipherState::Ctr(_)
            | CipherState::Cfb8(_)
            | CipherState::Cfb128(_) => key.encrypt_mode(),
        }
    }
    /// Returns whether the mode of operation requires complete 16-byte blocks.
    fn requires_blocks(&self) -> bool {
148
        matches!(
146
            self,
            CipherState::Ecb(_) | CipherState::Ofb(_) | CipherState::Cbc(_)
        )
    }
}
const BLOCK_SIZE: usize = 16;
struct AesOperation {
    mode: Operation,
    // The block cipher mode of operation.
    cipher_mode: NonNull<CipherState>,
    // The length of the key is determined by the mode of operation. Note that the pointers may
    // change during AES operation.
    buffers: UnsafeCryptoBuffers,
    key: Key,
}
impl Clone for AesOperation {
    fn clone(&self) -> Self {
        Self {
            mode: self.mode,
            cipher_mode: self.cipher_mode,
            buffers: self.buffers,
            key: self.key.copy(),
        }
    }
}
// Safety: AesOperation is safe to share between threads, in the context of a WorkQueue. The
// WorkQueue ensures that only a single location can access the data. All the internals, except
// for the pointers, are Sync. The pointers are safe to share because they point at data that the
// AES driver ensures can be accessed safely and soundly.
unsafe impl Sync for AesOperation {}
// Safety: we will not hold on to the pointers when the work item leaves the queue.
unsafe impl Send for AesOperation {}
static AES_WORK_QUEUE: WorkQueue<AesOperation> = WorkQueue::new();
const BLOCKING_AES_VTABLE: VTable<AesOperation> = VTable {
    post: |driver, item| {
        // Fully process the work item. A single CPU-driven AES operation would complete
        // faster than we could poll the queue with all the locking around it.
        let driver = unsafe { AesBackend::from_raw(driver) };
        Some(driver.process(item))
    },
    poll: |_driver, _item| {
        // We've processed the item completely when we received it in `post`.
        unreachable!()
    },
    cancel: |_driver, _item| {
        // To achieve a decent performance in Typical AES mode, we run the operations in a blocking
        // manner and so they can't be cancelled.
    },
    stop: |driver| {
        // Drop the AES driver to conserve power when there is nothing to do (or when the driver was
        // stopped).
        let driver = unsafe { AesBackend::from_raw(driver) };
        driver.deinitialize()
    },
};
#[procmacros::doc_replace]
/// CPU-driven AES processing backend.
///
/// # Examples
///
/// ```rust, no_run
/// # {before_snippet}
/// use esp_hal::aes::{AesBackend, AesContext, Operation, cipher_modes::Ecb};
/// #
/// let mut aes = AesBackend::new(peripherals.AES);
/// // Start the backend, which allows processing AES operations.
/// let _backend = aes.start();
///
/// // Create a new context with a 128-bit key. The context will use the ECB block cipher mode.
/// // The key length must be supported by the hardware.
/// let mut ecb_encrypt = AesContext::new(Ecb, Operation::Encrypt, *b"SUp4SeCp@sSw0rd\0");
///
/// // Process a block of data in this context. The ECB mode of operation requires that
/// // the length of the data is a multiple of the block (16 bytes) size.
/// let input_buffer: [u8; 16] = *b"message\0\0\0\0\0\0\0\0\0";
/// let mut output_buffer: [u8; 16] = [0; 16];
///
/// let operation_handle = ecb_encrypt.process(&input_buffer, &mut output_buffer)?;
/// operation_handle.wait_blocking();
///
/// // output_buffer now contains the ciphertext
/// assert_eq!(
///     output_buffer,
///     [
///         0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
///         0x31, 0x96,
///     ]
/// );
/// #
/// # {after_snippet}
/// ```
pub struct AesBackend<'d> {
    peri: AES<'d>,
    driver: Option<Aes<'d>>,
}
impl<'d> AesBackend<'d> {
    #[procmacros::doc_replace]
    /// Creates a new AES backend.
    ///
    /// The backend must be started with [`Self::start`] before it can execute AES operations.
    ///
    /// # Examples
    ///
    /// ```rust, no_run
    /// # {before_snippet}
    /// use esp_hal::aes::AesBackend;
    /// #
    /// let mut aes = AesBackend::new(peripherals.AES);
    /// # {after_snippet}
    /// ```
    pub fn new(aes: AES<'d>) -> Self {
        Self {
            peri: aes,
            driver: None,
        }
    }
    #[procmacros::doc_replace]
    /// Registers the CPU-driven AES driver to process AES operations.
    ///
    /// The driver stops operating when the returned object is dropped.
    ///
    /// # Examples
    ///
    /// ```rust, no_run
    /// # {before_snippet}
    /// use esp_hal::aes::AesBackend;
    /// #
    /// let mut aes = AesBackend::new(peripherals.AES);
    /// // Start the backend, which allows processing AES operations.
    /// let _backend = aes.start();
    /// # {after_snippet}
    /// ```
5
    pub fn start(&mut self) -> AesWorkQueueDriver<'_, 'd> {
        AesWorkQueueDriver {
            inner: WorkQueueDriver::new(self, BLOCKING_AES_VTABLE, &AES_WORK_QUEUE),
        }
5
    }
    // WorkQueue callbacks. They may run in any context.
    unsafe fn from_raw<'any>(ptr: NonNull<()>) -> &'any mut Self {
        unsafe { ptr.cast::<AesBackend<'_>>().as_mut() }
    }
    fn process(&mut self, item: &mut AesOperation) -> Poll {
        let driver = self.driver.get_or_insert_with(|| {
            let peri = unsafe { self.peri.clone_unchecked() };
            Aes::new(peri)
        });
23
        driver.process_work_item(item);
        Poll::Ready(Status::Completed)
    }
    fn deinitialize(&mut self) {
5
        self.driver = None;
    }
}
/// An error related to an AES operation.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
    /// The input and output buffers have different lengths.
    BuffersNotEqual,
    /// The buffer length is not appropriate for the current cipher mode.
    IncorrectBufferLength,
}
/// An active work queue driver.
///
/// This object must be kept around, otherwise AES operations will never complete.
pub struct AesWorkQueueDriver<'t, 'd> {
    inner: WorkQueueDriver<'t, AesBackend<'d>, AesOperation>,
}
impl<'t, 'd> AesWorkQueueDriver<'t, 'd> {
    /// Finishes processing the current work queue item, then stops the driver.
    pub fn stop(self) -> impl Future<Output = ()> {
        self.inner.stop()
    }
}
/// An AES work queue user.
#[derive(Clone)]
pub struct AesContext {
    cipher_mode: CipherState,
    frontend: WorkQueueFrontend<AesOperation>,
}
impl AesContext {
    /// Creates a new context to encrypt or decrypt data with the given block cipher mode of
    /// operation.
    pub fn new(
        cipher_mode: impl Into<CipherState>,
        operation: Operation,
        key: impl Into<Key>,
    ) -> Self {
32
        Self {
            cipher_mode: cipher_mode.into(),
            frontend: WorkQueueFrontend::new(AesOperation {
                mode: operation,
                cipher_mode: NonNull::dangling(),
                buffers: unsafe { CryptoBuffers::new_in_place(&mut []).into_inner() },
                key: key.into(),
            }),
        }
    }
    fn post(&mut self) -> AesHandle<'_> {
        AesHandle(self.frontend.post(&AES_WORK_QUEUE))
    }
    fn validate(&self, buffer: &[u8]) -> Result<(), Error> {
        if self.cipher_mode.requires_blocks() && !buffer.len().is_multiple_of(BLOCK_SIZE) {
            return Err(Error::IncorrectBufferLength);
        }
        Ok(())
    }
    /// Starts transforming the input buffer, and writes the result into the output buffer.
    ///
    /// - For encryption the input is the plaintext, the output is the ciphertext.
    /// - For decryption the input is the ciphertext, the output is the plaintext.
    ///
    /// The returned Handle must be polled until it returns `true`. Dropping the handle
    /// before the operation finishes will cancel the operation.
    ///
    /// For an example, see the documentation of [`AesBackend`].
    ///
    /// # Errors
    ///
    /// - [`Error`] when the lengths of the input and output buffers do not match.
    /// - [`Error`] when ECB or OFB cipher modes are used and the data length is not a multiple of
    ///   the block size (16).
    pub fn process<'t>(
        &'t mut self,
        input: &'t [u8],
        output: &'t mut [u8],
    ) -> Result<AesHandle<'t>, Error> {
        self.validate(input)?;
        self.validate(output)?;
        let data = self.frontend.data_mut();
146
        data.cipher_mode = NonNull::from(&mut self.cipher_mode);
146
        data.buffers = unsafe { CryptoBuffers::new(input, output)?.into_inner() };
146
        Ok(self.post())
146
    }
    #[procmacros::doc_replace]
    /// Starts transforming the buffer.
    ///
    /// The processed data is written back to the `buffer`.
    ///
    /// The returned Handle must be polled until it returns `true`. Dropping the handle
    /// before the operation finishes will cancel the operation.
    ///
    /// Operates similarly to [`AesContext::process`], but overwrites the data buffer with the
    /// result of the transformation.
    ///
    /// # Examples
    ///
    /// ```rust, no_run
    /// # {before_snippet}
    /// use esp_hal::aes::{AesBackend, AesContext, Operation, cipher_modes::Ecb};
    /// #
    /// let mut aes = AesBackend::new(peripherals.AES);
    /// // Start the backend, which pins it in place and allows processing AES operations.
    /// let _backend = aes.start();
    ///
    /// // Create a new context with a 128-bit key. The context will use the ECB block cipher mode.
    /// // The key length must be supported by the hardware.
    /// let mut ecb_encrypt = AesContext::new(Ecb, Operation::Encrypt, *b"SUp4SeCp@sSw0rd\0");
    ///
    /// // Process a block of data in this context, in place. The ECB mode of operation requires that
    /// // the length of the data is a multiple of the block (16 bytes) size.
    /// let mut buffer: [u8; 16] = *b"message\0\0\0\0\0\0\0\0\0";
    ///
    /// let operation_handle = ecb_encrypt.process_in_place(&mut buffer)?;
    /// operation_handle.wait_blocking();
    ///
    /// // Instead of the plaintext message, buffer now contains the ciphertext.
    /// assert_eq!(
    ///     buffer,
    ///     [
    ///         0xb3, 0xc8, 0xd2, 0x3b, 0xa7, 0x36, 0x5f, 0x18, 0x61, 0x70, 0x0, 0x3e, 0xd9, 0x3a,
    ///         0x31, 0x96,
    ///     ]
    /// );
    /// #
    /// # {after_snippet}
    /// ```
    ///
    /// # Errors
    ///
    /// [`Error`] when ECB or OFB cipher modes are used and the data length is not a multiple of the
    /// block size (16).
148
    pub fn process_in_place<'t>(
        &'t mut self,
        buffer: &'t mut [u8],
    ) -> Result<AesHandle<'t>, Error> {
        self.validate(buffer)?;
        let data = self.frontend.data_mut();
148
        data.cipher_mode = NonNull::from(&self.cipher_mode);
148
        data.buffers = unsafe { CryptoBuffers::new_in_place(buffer).into_inner() };
148
        Ok(self.post())
148
    }
}
/// The handle to the pending AES operation.
///
/// This object is returned by [`AesContext::process`] and [`AesContext::process_in_place`].
///
/// Dropping this handle before the operation finishes will cancel the operation.
///
/// For an example, see the documentation of [`AesBackend`].
pub struct AesHandle<'t>(Handle<'t, AesOperation>);
impl AesHandle<'_> {
    /// Polls the status of the work item.
    ///
    /// Returns whether the item has been processed.
    #[inline]
    pub fn poll(&mut self) -> bool {
        self.0.poll()
    }
    /// Polls the work item to completion, by busy-looping.
    ///
    /// Returns immediately if `poll` returns `true`.
    #[inline]
    pub fn wait_blocking(self) -> Status {
        self.0.wait_blocking()
    }
    /// Waits until the work item is completed.
    #[inline]
    pub fn wait(&mut self) -> impl Future<Output = Status> {
        self.0.wait()
    }
    /// Cancels the work item and asynchronously waits until it is removed from the work queue.
    #[inline]
    pub fn cancel(&mut self) -> impl Future<Output = ()> {
        self.0.cancel()
    }
}
// Utilities
fn read_words(slice: &[u8]) -> impl Iterator<Item = u32> {
    fn bytes<const N: usize>(slice: &[u8]) -> impl Iterator<Item = [u8; N]> {
        slice.chunks(N).map(|c| {
822
            let mut bytes = [0; N];
            bytes[0..c.len()].copy_from_slice(c);
822
            bytes
        })
    }
    bytes::<4>(slice).map(u32::from_le_bytes)
}
fn write_words(slice: &mut [u8], next: impl Fn(usize) -> u32) {
    for (i, chunk) in slice.chunks_mut(4).enumerate() {
        let bytes = next(i).to_le_bytes();
        chunk.copy_from_slice(&bytes[0..chunk.len()]);
    }
}