capsules_core/virtualizers/
virtual_aes_ccm.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implements and virtualizes AES-CCM* encryption/decryption/authentication using an underlying
6//! AES-CBC and AES-CTR implementation.
7//!
8//! IEEE 802.15.4-2015: Appendix B.4.1, CCM* transformations. CCM* is
9//! defined so that both encryption and decryption can be done by preparing two
10//! fields: the AuthData and either the PlaintextData or the CiphertextData.
11//! Then, two passes of AES are performed with one block of overlap.
12//!
13//! ```text
14//! crypt_buf: [ -------- AuthData -------- | -------- PData/CData -------- ]
15//! aes_cbc:    \__________________________/
16//! aes_ctr:                        \ 1 blk | _____________________________/
17//! ```
18//!
19//! The overlapping block is then the encrypted authentication tag U. For
20//! encryption, we append U to the data as a message integrity code (MIC).
21//! For decryption, we compare U with the provided MIC.
22//
23//! This is true only if data confidentiality is not needed. If it is, then
24//! the AuthData includes the PlaintextData. At encryption, we perform CBC over
25//! both fields, then copy the last block to just before the PData. Then,
26//! CTR mode is performed over the same overlapping region, forming the encrypted
27//! authentication tag U.
28//!
29//! ```text
30//! crypt_buf: [ -------- AuthData -------- | -------- PData/CData -------- ]
31//! aes_cbc:    \__________________________________________________________/
32//! aes_ctr:                        \ 1 blk | _____________________________/
33//! ```
34//!
35//! At decryption, there is no choice but the reverse the order of operations.
36//! First, we zero out the overlapping block and perform ctr over it and the
37//! PlaintextData. This produces Enc(Key, A_i), which we save in saved_tag.
38//! Then, we restore the previous value of the last block of AuthData and re-pad
39//! PlaintextData before running CBC over both fields. The last step is to
40//! combine saved_tag and the unencrypted tag to form the encrypted tag and
41//! verify its correctness.
42//!
43//! Usage
44//! -----
45//!
46//! ```rust,ignore
47//! # use capsules_core::test::aes_ccm::Test;
48//! # use capsules_core::virtual_aes_ccm;
49//! # use kernel::common::deferred_call::DeferredCallClient;
50//! # use kernel::hil::symmetric_encryption::{AES128, AES128CCM, AES128_BLOCK_SIZE};
51//! # use kernel::static_init;
52//! # use sam4l::aes::{Aes, AES};
53//! type AESCCMMUX = virtual_aes_ccm::MuxAES128CCM<'static, Aes<'static>>;
54//! type AESCCMCLIENT = virtual_aes_ccm::VirtualAES128CCM<'static, AESCCMMUX>;
55//! // mux
56//! let ccm_mux = static_init!(AESCCMMUX, virtual_aes_ccm::MuxAES128CCM::new(&AES));
57//! ccm_mux.register();
58//! AES.set_client(ccm_mux);
59//! const CRYPT_SIZE: usize = 7 * AES128_BLOCK_SIZE;
60//! let crypt_buf1 = static_init!([u8; CRYPT_SIZE], [0x00; CRYPT_SIZE]);
61//! let ccm_client1 = static_init!(
62//!     AESCCMCLIENT,
63//!     virtual_aes_ccm::VirtualAES128CCM::new(ccm_mux, crypt_buf1)
64//! );
65//! ccm_client1.setup();
66//! let data1 = static_init!([u8; 4 * AES128_BLOCK_SIZE], [0x00; 4 * AES128_BLOCK_SIZE]);
67//! let t1 = static_init!(Test<'static, AESCCMCLIENT>, Test::new(ccm_client1, data1));
68//! ccm_client1.set_client(t1);
69//! let crypt_buf2 = static_init!([u8; CRYPT_SIZE], [0x00; CRYPT_SIZE]);
70//! let ccm_client2 = static_init!(
71//!     AESCCMCLIENT,
72//!     virtual_aes_ccm::VirtualAES128CCM::new(ccm_mux, crypt_buf2)
73//! );
74//! ccm_client2.setup();
75//! let data2 = static_init!([u8; 4 * AES128_BLOCK_SIZE], [0x00; 4 * AES128_BLOCK_SIZE]);
76//! let t2 = static_init!(Test<'static, AESCCMCLIENT>, Test::new(ccm_client2, data2));
77//! ccm_client2.set_client(t2);
78//! t1.run();
79//! t2.run();
80//!
81//! ```
82
83use core::cell::Cell;
84
85use kernel::collections::list::{List, ListLink, ListNode};
86use kernel::debug;
87use kernel::deferred_call::{DeferredCall, DeferredCallClient};
88use kernel::hil::symmetric_encryption;
89use kernel::hil::symmetric_encryption::{
90    AES128Ctr, AES128, AES128CBC, AES128ECB, AES128_BLOCK_SIZE, AES128_KEY_SIZE, CCM_NONCE_LENGTH,
91};
92use kernel::utilities::cells::{OptionalCell, TakeCell};
93use kernel::ErrorCode;
94
95use crate::stream::SResult;
96use crate::stream::{encode_bytes, encode_u16};
97
98#[derive(Copy, Clone, Eq, PartialEq, Debug)]
99enum CCMState {
100    Idle,
101    Auth,
102    Encrypt,
103}
104
105// to cache up the function parameters of the crypt() function
106struct CryptFunctionParameters {
107    buf: &'static mut [u8],
108    a_off: usize,
109    m_off: usize,
110    m_len: usize,
111    mic_len: usize,
112    confidential: bool,
113    encrypting: bool,
114}
115
116impl CryptFunctionParameters {
117    pub fn new(
118        buf: &'static mut [u8],
119        a_off: usize,
120        m_off: usize,
121        m_len: usize,
122        mic_len: usize,
123        confidential: bool,
124        encrypting: bool,
125    ) -> CryptFunctionParameters {
126        CryptFunctionParameters {
127            buf,
128            a_off,
129            m_off,
130            m_len,
131            mic_len,
132            confidential,
133            encrypting,
134        }
135    }
136}
137
138pub struct MuxAES128CCM<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> {
139    aes: &'a A,
140    client: OptionalCell<&'a dyn symmetric_encryption::Client<'a>>,
141    ccm_clients: List<'a, VirtualAES128CCM<'a, A>>,
142    inflight: OptionalCell<&'a VirtualAES128CCM<'a, A>>,
143    deferred_call: DeferredCall,
144}
145
146impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> MuxAES128CCM<'a, A> {
147    pub fn new(aes: &'a A) -> Self {
148        aes.enable(); // enable the hardware, in case it's forgotten elsewhere
149        Self {
150            aes,
151            client: OptionalCell::empty(),
152            ccm_clients: List::new(),
153            inflight: OptionalCell::empty(),
154            deferred_call: DeferredCall::new(),
155        }
156    }
157
158    /// Asynchronously executes the next operation, if any. Used by calls
159    /// to trigger do_next_op such that it will execute after the call
160    /// returns.
161    /// See virtual_uart::MuxUart<'a>::do_next_op_async
162    fn do_next_op_async(&self) {
163        self.deferred_call.set();
164    }
165
166    fn do_next_op(&self) {
167        if self.inflight.is_none() {
168            let mnode = self
169                .ccm_clients
170                .iter()
171                .find(|node| node.queued_up.is_some());
172            mnode.map(|node| {
173                self.inflight.set(node);
174                let parameters: CryptFunctionParameters = node.queued_up.take().unwrap();
175                // now, eat the parameters
176                let _ = node.crypt_r(parameters).map_err(|(ecode, _)| {
177                    // notice that we didn't put the parameters back...
178                    // because it's already eaten
179                    if node.ccm_client.is_none() {
180                        debug!("virtual_aes_ccm: no ccm_client is registered in VirtualAES128CCM");
181                    }
182                    if node.buf.is_none() {
183                        debug!("virtual_aes_ccm: no buffer is binded with VirtualAES128CCM");
184                    }
185                    // notify the client that there's a failure
186                    node.buf.take().map(|buf| {
187                        node.ccm_client.map(move |client| {
188                            client.crypt_done(buf, Err(ecode), false);
189                        });
190                    });
191                    // if it fails to trigger encryption, remove it and perform the next
192                    node.remove_from_queue();
193                    self.do_next_op();
194                });
195                // otherwise, wait for crypt_done
196            });
197        }
198    }
199}
200
201impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> DeferredCallClient
202    for MuxAES128CCM<'a, A>
203{
204    fn handle_deferred_call(&self) {
205        self.do_next_op();
206    }
207
208    fn register(&'static self) {
209        self.deferred_call.register(self);
210    }
211}
212
213impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> symmetric_encryption::Client<'a>
214    for MuxAES128CCM<'a, A>
215{
216    fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
217        if self.inflight.is_none() {
218            self.client.map(move |client| {
219                client.crypt_done(source, dest);
220            });
221            return;
222        }
223        self.inflight.map(move |vaes_ccm| {
224            // vaes_ccm.crypt_done might call additional start_ccm_crypt / start_ccm_auth
225            // when the encryption is *really* done, inflight will be cleared by remove_from_queue
226            // and it will call do_next_op to perform the next operation
227            // self.do_next_op() will be called when the encryption is failed or is really done
228            // search for self.ccm_client
229            vaes_ccm.crypt_done(source, dest);
230        });
231    }
232}
233
234pub struct VirtualAES128CCM<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> {
235    mux: &'a MuxAES128CCM<'a, A>,
236    aes: &'a A,
237    next: ListLink<'a, VirtualAES128CCM<'a, A>>,
238
239    crypt_buf: TakeCell<'static, [u8]>,
240    crypt_auth_len: Cell<usize>,
241    crypt_enc_len: Cell<usize>,
242    ccm_client: OptionalCell<&'a dyn symmetric_encryption::CCMClient>,
243
244    state: Cell<CCMState>,
245    confidential: Cell<bool>,
246    encrypting: Cell<bool>,
247
248    buf: TakeCell<'static, [u8]>,
249    pos: Cell<(usize, usize, usize, usize)>,
250    key: Cell<[u8; AES128_KEY_SIZE]>,
251    nonce: Cell<[u8; CCM_NONCE_LENGTH]>,
252    saved_tag: Cell<[u8; AES128_BLOCK_SIZE]>,
253    queued_up: OptionalCell<CryptFunctionParameters>,
254}
255
256impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> VirtualAES128CCM<'a, A> {
257    pub fn new(
258        mux: &'a MuxAES128CCM<'a, A>,
259        crypt_buf: &'static mut [u8],
260    ) -> VirtualAES128CCM<'a, A> {
261        VirtualAES128CCM {
262            mux,
263            aes: mux.aes,
264            next: ListLink::empty(),
265            crypt_buf: TakeCell::new(crypt_buf),
266            crypt_auth_len: Cell::new(0),
267            crypt_enc_len: Cell::new(0),
268            ccm_client: OptionalCell::empty(),
269            state: Cell::new(CCMState::Idle),
270            confidential: Cell::new(false),
271            encrypting: Cell::new(false),
272            buf: TakeCell::empty(),
273            pos: Cell::new((0, 0, 0, 0)),
274            key: Cell::new(Default::default()),
275            nonce: Cell::new(Default::default()),
276            saved_tag: Cell::new(Default::default()),
277            queued_up: OptionalCell::empty(),
278        }
279    }
280
281    /// bind itself to self.mux, should be called after static_init!
282    pub fn setup(&'a self) {
283        self.mux.ccm_clients.push_head(self);
284    }
285
286    /// Prepares crypt_buf with the input for the CCM* authentication and
287    /// encryption/decryption transformations. Returns NOMEM if crypt_buf is
288    /// not present or if it is not long enough.
289    fn prepare_ccm_buffer(
290        &self,
291        nonce: &[u8; CCM_NONCE_LENGTH],
292        mic_len: usize,
293        a_data: &[u8],
294        m_data: &[u8],
295    ) -> Result<(), ErrorCode> {
296        self.crypt_buf.map_or(Err(ErrorCode::NOMEM), |cbuf| {
297            let (auth_len, enc_len) =
298                match Self::encode_ccm_buffer(cbuf, nonce, mic_len, a_data, m_data) {
299                    SResult::Done(_, out) => out,
300                    SResult::Needed(_) => {
301                        return Err(ErrorCode::NOMEM);
302                    }
303                    SResult::Error(()) => {
304                        return Err(ErrorCode::FAIL);
305                    }
306                };
307            // debug!("auth: ({})", auth_len);
308            // for i in 0..auth_len {
309            //     debug!("{:02x}", cbuf[i]);
310            // }
311            // debug!("enc: ({})", enc_len);
312            // for i in auth_len..enc_len {
313            //     debug!("{:02x}", cbuf[i]);
314            // }
315
316            self.crypt_auth_len.set(auth_len);
317            self.crypt_enc_len.set(enc_len);
318            Ok(())
319        })
320    }
321
322    /// This function encodes AuthData (a_data) and PData/CData (m_data) into a
323    /// buffer, along with the prerequisite metadata/padding bytes. On success,
324    /// `auth_len` (the length of the AuthData field) and `enc_len` (the
325    /// combined length of AuthData and PData/CData) are returned. `auth_len` is
326    /// guaranteed to be >= AES128_BLOCK_SIZE
327    fn encode_ccm_buffer(
328        buf: &mut [u8],
329        nonce: &[u8; CCM_NONCE_LENGTH],
330        mic_len: usize,
331        a_data: &[u8],
332        m_data: &[u8],
333    ) -> SResult<(usize, usize)> {
334        // IEEE 802.15.4-2015: Appendix B.4.1.2, CCM* authentication
335        // The authentication tag T is computed with AES128-CBC-MAC on
336        // B_0 | AuthData, where
337        //   B_0 = Flags (1 byte) | nonce (13 bytes) | m length (2 bytes)
338        //   Flags = 0 | A data present? (1 bit) | M (3 bits) | L (3 bits)
339        //   AuthData = AddAuthData | PlaintextData
340        //   AddAuthData = L(a) (encoding of a_data.len()) | a_data
341        //   PlaintextData = m_data
342        //   Both AddAuthData and PlaintextData are 0-padded to 16-byte blocks.
343        // The following code places B_0 | AuthData into crypt_buf.
344
345        // flags = reserved | Adata | (M - 2) / 2 | (L - 1)
346        let mut flags: u8 = 0;
347        if a_data.len() != 0 {
348            flags |= 1 << 6;
349        }
350        if mic_len != 0 {
351            flags |= (((mic_len - 2) / 2) as u8) << 3;
352        }
353        flags |= 1;
354
355        stream_len_cond!(buf, AES128_BLOCK_SIZE);
356        // The first block is flags | nonce | m length
357        buf[0] = flags;
358        buf[1..14].copy_from_slice(nonce.as_ref());
359        let mut off = enc_consume!(buf, 14; encode_u16,
360                                            (m_data.len() as u16).to_le());
361
362        // After that comes L(a) | a, where L(a) is the following
363        // encoding of a_len:
364        if a_data.len() == 0 {
365            // L(a) is empty, and the Adata flag is zero
366        } else if a_data.len() < 0xff00_usize {
367            // L(a) is l(a) in 2 bytes of little-endian
368            off = enc_consume!(buf, off; encode_u16,
369                                         (a_data.len() as u16).to_le());
370        } else {
371            // These length encoding branches are defined in the specification
372            // but should never be reached because our MTU is 127.
373            stream_err!(());
374        }
375
376        // Append the auth data and 0-pad to a multiple of 16 bytes
377        off = enc_consume!(buf, off; encode_bytes, a_data);
378        let auth_len = off.div_ceil(AES128_BLOCK_SIZE) * AES128_BLOCK_SIZE;
379        stream_len_cond!(buf, auth_len);
380        buf[off..auth_len].iter_mut().for_each(|b| *b = 0);
381        off = auth_len;
382
383        // Append plaintext data and 0-pad to a multiple of 16 bytes
384        off = enc_consume!(buf, off; encode_bytes, m_data);
385        let enc_len = off.div_ceil(AES128_BLOCK_SIZE) * AES128_BLOCK_SIZE;
386        stream_len_cond!(buf, enc_len);
387        buf[off..enc_len].iter_mut().for_each(|b| *b = 0);
388        off = enc_len;
389
390        stream_done!(off, (auth_len, enc_len));
391    }
392
393    fn reversed(&self) -> bool {
394        self.confidential.get() && !self.encrypting.get()
395    }
396
397    // Assumes that the state is Idle, which means that crypt_buf must be
398    // present. Panics if this is not the case.
399    fn start_ccm_auth(&self) -> Result<(), ErrorCode> {
400        if !(self.state.get() == CCMState::Idle)
401            && !(self.state.get() == CCMState::Encrypt && self.reversed())
402        {
403            panic!("Called start_ccm_auth when not idle");
404        }
405
406        // We are performing CBC-MAC, so always encrypting.
407        self.aes.set_mode_aes128cbc(true)?;
408
409        let iv = [0u8; AES128_BLOCK_SIZE];
410        let res = self.aes.set_iv(&iv);
411        if res != Ok(()) {
412            return res;
413        }
414        let res = self.aes.set_key(&self.key.get());
415        if res != Ok(()) {
416            return res;
417        }
418
419        let crypt_buf = match self.crypt_buf.take() {
420            None => panic!("Cannot perform CCM* auth because crypt_buf is not present."),
421            Some(buf) => buf,
422        };
423
424        // If confidentiality is needed, authenticate over message data.
425        let auth_end = if self.confidential.get() {
426            self.crypt_enc_len.get()
427        } else {
428            self.crypt_auth_len.get()
429        };
430
431        self.aes.start_message();
432        match self.aes.crypt(None, crypt_buf, 0, auth_end) {
433            None => {
434                self.state.set(CCMState::Auth);
435                Ok(())
436            }
437            Some((res, _, crypt_buf)) => {
438                // Request failed
439                self.crypt_buf.replace(crypt_buf);
440                res
441            }
442        }
443    }
444
445    fn start_ccm_encrypt(&self) -> Result<(), ErrorCode> {
446        if !(self.state.get() == CCMState::Auth)
447            && !(self.state.get() == CCMState::Idle && self.reversed())
448        {
449            return Err(ErrorCode::FAIL);
450        }
451        self.state.set(CCMState::Idle); // default to fail
452
453        // debug!("after auth:");
454        // self.crypt_buf.map(|buf| {
455        //     for i in 0..self.crypt_auth_len.get() {
456        //         debug!("{:02x}", buf[i]);
457        //     }
458        // });
459
460        self.aes.set_mode_aes128ctr(self.encrypting.get())?;
461
462        let res = self.aes.set_key(&self.key.get());
463        if res != Ok(()) {
464            return res;
465        }
466
467        let mut iv = [0u8; AES128_BLOCK_SIZE];
468        // flags = reserved | reserved | 0 | (L - 1)
469        // Since L = 2, flags = 1.
470        iv[0] = 1;
471        iv[1..1 + CCM_NONCE_LENGTH].copy_from_slice(&self.nonce.get());
472        let res = self.aes.set_iv(&iv);
473        if res != Ok(()) {
474            return res;
475        }
476
477        self.aes.start_message();
478        let crypt_buf = match self.crypt_buf.take() {
479            None => panic!("Cannot perform CCM* encrypt because crypt_buf is not present."),
480            Some(buf) => buf,
481        };
482
483        match self.aes.crypt(
484            None,
485            crypt_buf,
486            self.crypt_auth_len.get() - AES128_BLOCK_SIZE,
487            self.crypt_enc_len.get(),
488        ) {
489            None => {
490                self.state.set(CCMState::Encrypt);
491                Ok(())
492            }
493            Some((res, _, crypt_buf)) => {
494                self.crypt_buf.replace(crypt_buf);
495                res
496            }
497        }
498    }
499
500    fn end_ccm(&self) {
501        let tag_valid = self.buf.map_or(false, |buf| {
502            self.crypt_buf.map_or_else(
503                || {
504                    panic!("We lost track of crypt_buf!");
505                },
506                |cbuf| {
507                    // Copy the encrypted/decrypted message data
508                    let (_, m_off, m_len, mic_len) = self.pos.get();
509                    let auth_len = self.crypt_auth_len.get();
510                    buf[m_off..m_off + m_len].copy_from_slice(&cbuf[auth_len..auth_len + m_len]);
511
512                    let m_end = m_off + m_len;
513                    let tag_off = auth_len - AES128_BLOCK_SIZE;
514                    if self.encrypting.get() {
515                        // Copy the encrypted tag to the end of the message
516                        buf[m_end..m_end + mic_len]
517                            .copy_from_slice(&cbuf[tag_off..tag_off + mic_len]);
518                        true
519                    } else {
520                        // Compare the computed encrypted tag to the received
521                        // encrypted tag
522                        buf[m_end..m_end + mic_len]
523                            .iter()
524                            .zip(cbuf[tag_off..tag_off + mic_len].iter())
525                            .all(|(a, b)| *a == *b)
526                    }
527                },
528            )
529        });
530        // encryption is successful
531        self.state.set(CCMState::Idle);
532        self.remove_from_queue();
533        self.mux.do_next_op();
534        self.ccm_client.map(|client| {
535            self.buf.take().map(|buf| {
536                client.crypt_done(buf, Ok(()), tag_valid);
537            });
538        });
539    }
540
541    fn reverse_end_ccm(&self) {
542        // Finalize CCM process only in the case where we did CTR before CBC
543        let tag_valid = self.buf.map_or(false, |buf| {
544            self.crypt_buf.map_or_else(
545                || {
546                    panic!("We lost track of crypt_buf!");
547                },
548                |cbuf| {
549                    let (_, m_off, m_len, mic_len) = self.pos.get();
550
551                    // Combine unencrypted tag at end of crypt_buf with saved
552                    // CTR-encrypted block to obtain encrypted tag
553                    let tag_off = self.crypt_enc_len.get() - AES128_BLOCK_SIZE;
554                    self.saved_tag.get()[..mic_len]
555                        .iter()
556                        .zip(cbuf[tag_off..tag_off + mic_len].iter_mut())
557                        .for_each(|(a, b)| *b ^= *a);
558
559                    // Compare the computed encrypted tag to the received
560                    // encrypted tag
561                    buf[m_off + m_len..m_off + m_len + mic_len]
562                        .iter()
563                        .zip(cbuf[tag_off..tag_off + mic_len].iter())
564                        .all(|(a, b)| *a == *b)
565                },
566            )
567        });
568        // encryption is successful
569        self.state.set(CCMState::Idle);
570        self.remove_from_queue();
571        self.mux.do_next_op();
572        self.ccm_client.map(|client| {
573            self.buf.take().map(|buf| {
574                client.crypt_done(buf, Ok(()), tag_valid);
575            });
576        });
577    }
578
579    fn save_tag_block(&self) {
580        // Copies [auth_len - AES128_BLOCK_SIZE..auth_len] to saved_tag
581        // and zeroes it out
582        let auth_len = self.crypt_auth_len.get();
583        self.crypt_buf.map(|cbuf| {
584            let mut cbuf_block = [0u8; AES128_BLOCK_SIZE];
585            cbuf_block.copy_from_slice(&cbuf[auth_len - AES128_BLOCK_SIZE..auth_len]);
586            self.saved_tag.set(cbuf_block);
587            cbuf[auth_len - AES128_BLOCK_SIZE..auth_len]
588                .iter_mut()
589                .for_each(|b| *b = 0);
590        });
591    }
592
593    fn swap_tag_block(&self) {
594        // Swaps [auth_len - AES128_BLOCK_SIZE..auth_len] with
595        // the value in saved_tag
596        let auth_len = self.crypt_auth_len.get();
597        self.crypt_buf.map(|cbuf| {
598            let mut cbuf_block = [0u8; AES128_BLOCK_SIZE];
599            cbuf_block.copy_from_slice(&cbuf[auth_len - AES128_BLOCK_SIZE..auth_len]);
600            cbuf[auth_len - AES128_BLOCK_SIZE..auth_len].copy_from_slice(&self.saved_tag.get());
601            self.saved_tag.set(cbuf_block);
602        });
603    }
604
605    fn crypt_r(
606        &self,
607        parameter: CryptFunctionParameters,
608    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
609        // just expanding the parameters......
610        let buf: &'static mut [u8] = parameter.buf;
611        let a_off: usize = parameter.a_off;
612        let m_off: usize = parameter.m_off;
613        let m_len: usize = parameter.m_len;
614        let mic_len: usize = parameter.mic_len;
615        let confidential: bool = parameter.confidential;
616        let encrypting: bool = parameter.encrypting;
617        //
618        if self.state.get() != CCMState::Idle {
619            return Err((ErrorCode::BUSY, buf));
620        }
621        if !(a_off <= m_off && m_off + m_len + mic_len <= buf.len()) {
622            return Err((ErrorCode::INVAL, buf));
623        }
624
625        self.confidential.set(confidential);
626        self.encrypting.set(encrypting);
627
628        let res = self.prepare_ccm_buffer(
629            &self.nonce.get(),
630            mic_len,
631            &buf[a_off..m_off],
632            &buf[m_off..m_off + m_len],
633        );
634        if res != Ok(()) {
635            return Err((res.unwrap_err(), buf));
636        }
637
638        let res = if !confidential || encrypting {
639            // Perform CBC before CTR
640            self.start_ccm_auth()
641        } else {
642            // Perform CTR before CBC
643            self.save_tag_block();
644            self.start_ccm_encrypt()
645        };
646
647        if res != Ok(()) {
648            Err((res.unwrap_err(), buf))
649        } else {
650            self.buf.replace(buf);
651            self.pos.set((a_off, m_off, m_len, mic_len));
652            Ok(())
653        }
654    }
655
656    fn remove_from_queue(&self) {
657        self.queued_up.clear();
658        self.mux.inflight.clear();
659    }
660}
661
662impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> symmetric_encryption::AES128CCM<'a>
663    for VirtualAES128CCM<'a, A>
664{
665    fn set_client(&self, client: &'a dyn symmetric_encryption::CCMClient) {
666        self.ccm_client.set(client);
667    }
668
669    fn set_key(&self, key: &[u8]) -> Result<(), ErrorCode> {
670        if key.len() < AES128_KEY_SIZE {
671            Err(ErrorCode::INVAL)
672        } else {
673            let mut new_key = [0u8; AES128_KEY_SIZE];
674            new_key.copy_from_slice(key);
675            self.key.set(new_key);
676            Ok(())
677        }
678    }
679
680    fn set_nonce(&self, nonce: &[u8]) -> Result<(), ErrorCode> {
681        if nonce.len() < CCM_NONCE_LENGTH {
682            Err(ErrorCode::INVAL)
683        } else {
684            let mut new_nonce = [0u8; CCM_NONCE_LENGTH];
685            new_nonce.copy_from_slice(nonce);
686            self.nonce.set(new_nonce);
687            Ok(())
688        }
689    }
690    /// Try to begin the encryption/decryption process
691    fn crypt(
692        &self,
693        buf: &'static mut [u8],
694        a_off: usize,
695        m_off: usize,
696        m_len: usize,
697        mic_len: usize,
698        confidential: bool,
699        encrypting: bool,
700    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
701        if self.queued_up.is_some() {
702            return Err((ErrorCode::BUSY, buf));
703        }
704        if self.state.get() != CCMState::Idle {
705            return Err((ErrorCode::BUSY, buf));
706        }
707        if !(a_off <= m_off && m_off + m_len + mic_len <= buf.len()) {
708            return Err((ErrorCode::INVAL, buf));
709        }
710
711        self.queued_up.set(CryptFunctionParameters::new(
712            buf,
713            a_off,
714            m_off,
715            m_len,
716            mic_len,
717            confidential,
718            encrypting,
719        ));
720        self.mux.do_next_op_async();
721        Ok(())
722    }
723}
724
725impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> symmetric_encryption::AES128<'a>
726    for VirtualAES128CCM<'a, A>
727{
728    fn enable(&self) {
729        self.aes.enable();
730    }
731
732    fn disable(&self) {
733        self.aes.disable();
734    }
735
736    fn set_client(&'a self, client: &'a dyn symmetric_encryption::Client<'a>) {
737        self.mux.client.set(client);
738    }
739
740    fn set_key(&self, key: &[u8]) -> Result<(), ErrorCode> {
741        if self.mux.inflight.is_none() {
742            self.mux.aes.set_key(key)
743        } else {
744            Err(ErrorCode::BUSY)
745        }
746    }
747
748    fn set_iv(&self, iv: &[u8]) -> Result<(), ErrorCode> {
749        if self.mux.inflight.is_none() {
750            self.mux.aes.set_iv(iv)
751        } else {
752            Err(ErrorCode::BUSY)
753        }
754    }
755
756    fn start_message(&self) {
757        if self.mux.inflight.is_none() {
758            self.mux.aes.start_message()
759        }
760    }
761
762    fn crypt(
763        &self,
764        source: Option<&'static mut [u8]>,
765        dest: &'static mut [u8],
766        start_index: usize,
767        stop_index: usize,
768    ) -> Option<(
769        Result<(), ErrorCode>,
770        Option<&'static mut [u8]>,
771        &'static mut [u8],
772    )> {
773        if self.mux.inflight.is_none() {
774            self.mux.aes.crypt(source, dest, start_index, stop_index)
775        } else {
776            Some((Err(ErrorCode::BUSY), source, dest))
777        }
778    }
779}
780
781impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> AES128Ctr for VirtualAES128CCM<'a, A> {
782    fn set_mode_aes128ctr(&self, encrypting: bool) -> Result<(), ErrorCode> {
783        if self.mux.inflight.is_none() {
784            self.mux.aes.set_mode_aes128ctr(encrypting)
785        } else {
786            Err(ErrorCode::BUSY)
787        }
788    }
789}
790
791impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> AES128ECB for VirtualAES128CCM<'a, A> {
792    fn set_mode_aes128ecb(&self, encrypting: bool) -> Result<(), ErrorCode> {
793        if self.mux.inflight.is_none() {
794            self.mux.aes.set_mode_aes128ecb(encrypting)
795        } else {
796            Err(ErrorCode::BUSY)
797        }
798    }
799}
800
801impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> AES128CBC for VirtualAES128CCM<'a, A> {
802    fn set_mode_aes128cbc(&self, encrypting: bool) -> Result<(), ErrorCode> {
803        if self.mux.inflight.is_none() {
804            self.mux.aes.set_mode_aes128cbc(encrypting)
805        } else {
806            Err(ErrorCode::BUSY)
807        }
808    }
809}
810
811impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> symmetric_encryption::Client<'a>
812    for VirtualAES128CCM<'a, A>
813{
814    fn crypt_done(&self, _: Option<&'static mut [u8]>, crypt_buf: &'static mut [u8]) {
815        self.crypt_buf.replace(crypt_buf);
816        match self.state.get() {
817            CCMState::Idle => {}
818            CCMState::Auth => {
819                if !self.reversed() {
820                    if self.confidential.get() {
821                        let (_, m_off, m_len, _) = self.pos.get();
822                        let auth_len = self.crypt_auth_len.get();
823                        let enc_len = self.crypt_enc_len.get();
824                        self.crypt_buf.map(|cbuf| {
825                            // If we authenticated over the plaintext, copy the last
826                            // block over to the beginning again so that it becomes
827                            // the encrypted tag after ctr mode
828                            let auth_last = auth_len - AES128_BLOCK_SIZE;
829                            let enc_last = enc_len - AES128_BLOCK_SIZE;
830                            for i in 0..AES128_BLOCK_SIZE {
831                                cbuf[auth_last + i] = cbuf[enc_last + i];
832                            }
833
834                            // Then repopulate the plaintext data field
835                            self.buf.map(|buf| {
836                                cbuf[auth_len..auth_len + m_len]
837                                    .copy_from_slice(&buf[m_off..m_off + m_len]);
838                            });
839                            cbuf[auth_len + m_len..enc_len]
840                                .iter_mut()
841                                .for_each(|b| *b = 0);
842                        });
843                    }
844
845                    let res = self.start_ccm_encrypt();
846                    if res != Ok(()) {
847                        // The operation fails, immediately remove the request and perform the next operation
848                        self.state.set(CCMState::Idle);
849                        self.remove_from_queue();
850                        self.mux.do_next_op();
851
852                        // Return client buffer to client
853                        self.buf.take().map(|buf| {
854                            self.ccm_client.map(move |client| {
855                                client.crypt_done(buf, res, false);
856                            });
857                        });
858                    }
859                } else {
860                    self.reverse_end_ccm();
861                }
862            }
863            CCMState::Encrypt => {
864                if !self.reversed() {
865                    self.end_ccm();
866                } else {
867                    self.swap_tag_block();
868                    self.crypt_buf.map(|cbuf| {
869                        // Copy the encrypted/decrypted message data
870                        let (_, m_off, m_len, _) = self.pos.get();
871                        let auth_len = self.crypt_auth_len.get();
872                        self.buf.map(|buf| {
873                            buf[m_off..m_off + m_len]
874                                .copy_from_slice(&cbuf[auth_len..auth_len + m_len]);
875                        });
876
877                        // Reset the rest of the padding
878                        cbuf[self.crypt_auth_len.get() + m_len..self.crypt_enc_len.get()]
879                            .iter_mut()
880                            .for_each(|b| *b = 0);
881                    });
882                    let res = self.start_ccm_auth();
883                    if res != Ok(()) {
884                        // Return client buffer to ccm_clients
885                        self.buf.take().map(|buf| {
886                            self.ccm_client.map(move |client| {
887                                client.crypt_done(buf, res, false);
888                            });
889                        });
890                        // The operation fails, immediately remove the request and perform the next operation
891                        self.state.set(CCMState::Idle);
892                        self.remove_from_queue();
893                        self.mux.do_next_op();
894                    }
895                }
896            }
897        }
898    }
899}
900
901// Fit in the linked list
902impl<'a, A: AES128<'a> + AES128Ctr + AES128CBC + AES128ECB> ListNode<'a, VirtualAES128CCM<'a, A>>
903    for VirtualAES128CCM<'a, A>
904{
905    fn next(&'a self) -> &'a ListLink<'a, VirtualAES128CCM<'a, A>> {
906        &self.next
907    }
908}