capsules_extra/test/
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//! Test the AES CCM implementation on top of AES hardware.
6
7use core::cell::Cell;
8use kernel::debug;
9use kernel::hil::symmetric_encryption::{CCMClient, AES128CCM, AES128_KEY_SIZE, CCM_NONCE_LENGTH};
10use kernel::utilities::cells::TakeCell;
11use kernel::ErrorCode;
12
13pub struct Test<'a, A: AES128CCM<'a>> {
14    aes_ccm: &'a A,
15
16    buf: TakeCell<'static, [u8]>,
17    current_test: Cell<usize>,
18    encrypting: Cell<bool>,
19
20    // (a_data, m_data, c_data, nonce, confidential, mic_len)
21    tests: [(
22        &'static [u8],
23        &'static [u8],
24        &'static [u8],
25        &'static [u8],
26        bool,
27        usize,
28    ); 3],
29}
30
31impl<'a, A: AES128CCM<'a>> Test<'a, A> {
32    pub fn new(aes_ccm: &'a A, buf: &'static mut [u8]) -> Test<'a, A> {
33        Test {
34            aes_ccm,
35            buf: TakeCell::new(buf),
36            current_test: Cell::new(0),
37            encrypting: Cell::new(true),
38            tests: [
39                (
40                    &BEACON_UNSECURED[0..26],
41                    &[],
42                    &BEACON_SECURED[26..34],
43                    &BEACON_NONCE,
44                    false,
45                    8,
46                ),
47                (
48                    &DATA_UNSECURED[0..26],
49                    &DATA_UNSECURED[26..30],
50                    &DATA_SECURED[26..30],
51                    &DATA_NONCE,
52                    true,
53                    0,
54                ),
55                (
56                    &MAC_UNSECURED[0..29],
57                    &MAC_UNSECURED[29..30],
58                    &MAC_SECURED[29..38],
59                    &MAC_NONCE,
60                    true,
61                    8,
62                ),
63            ],
64        }
65    }
66
67    pub fn run(&self) {
68        debug!("AES CCM* encryption/decryption tests");
69        self.trigger_test();
70    }
71
72    fn next_test(&self) -> bool {
73        if self.encrypting.get() {
74            self.encrypting.set(false);
75        } else {
76            self.encrypting.set(true);
77            self.current_test.set(self.current_test.get() + 1);
78            if self.current_test.get() >= self.tests.len() {
79                return false;
80            }
81        }
82        true
83    }
84
85    fn trigger_test(&self) {
86        let (a_data, m_data, c_data, nonce, confidential, mic_len) =
87            self.tests[self.current_test.get()];
88        let (a_off, m_off, m_len) = (0, a_data.len(), m_data.len());
89        let encrypting = self.encrypting.get();
90
91        let buf = match self.buf.take() {
92            None => panic!("aes_ccm_test failed: buffer is not present in trigger_test."),
93            Some(buf) => buf,
94        };
95
96        if encrypting {
97            buf[a_off..m_off].copy_from_slice(a_data);
98            buf[m_off..m_off + m_len].copy_from_slice(m_data);
99        } else {
100            buf[a_off..m_off].copy_from_slice(a_data);
101            buf[m_off..m_off + m_len + mic_len].copy_from_slice(c_data);
102        }
103
104        if self.aes_ccm.set_key(&KEY) != Ok(()) || self.aes_ccm.set_nonce(nonce) != Ok(()) {
105            panic!("aes_ccm_test failed: cannot set key or nonce.");
106        }
107
108        let _ = self
109            .aes_ccm
110            .crypt(buf, a_off, m_off, m_len, mic_len, confidential, encrypting)
111            .map_err(|(_code, buf)| {
112                debug!("Failed to start test.");
113                self.buf.replace(buf);
114            });
115    }
116
117    fn check_test(&self, tag_is_valid: bool) {
118        let (a_data, m_data, c_data, _nonce, _confidential, mic_len) =
119            self.tests[self.current_test.get()];
120        let (a_off, m_off, m_len) = (0, a_data.len(), m_data.len());
121        let encrypting = self.encrypting.get();
122
123        let buf = match self.buf.take() {
124            None => panic!("aes_ccm_test failed: buffer is not present in check_test."),
125            Some(buf) => buf,
126        };
127
128        if encrypting {
129            let a_matches = buf[a_off..m_off]
130                .iter()
131                .zip(a_data.iter())
132                .all(|(a, b)| *a == *b);
133            let c_matches = buf[m_off..m_off + m_len + mic_len]
134                .iter()
135                .zip(c_data.iter())
136                .all(|(a, b)| *a == *b);
137            if a_matches && c_matches && tag_is_valid {
138                debug!(
139                    "aes_ccm_test passed: (current_test={}, encrypting={}, tag_is_valid={})",
140                    self.current_test.get(),
141                    self.encrypting.get(),
142                    tag_is_valid
143                );
144            } else {
145                debug!("aes_ccm_test failed: a_matches={}, c_matches={}, (current_test={}, encrypting={}, tag_is_valid={}",
146                       a_matches,
147                       c_matches,
148                       self.current_test.get(),
149                       self.encrypting.get(),
150                       tag_is_valid);
151                for (a, b) in buf[m_off..m_off + m_len + mic_len]
152                    .iter()
153                    .zip(c_data.iter())
154                {
155                    debug!("{:x} vs {:x}", *a, *b);
156                }
157                panic!("aes_ccm_test failed");
158            }
159        } else {
160            let a_matches = buf[a_off..m_off]
161                .iter()
162                .zip(a_data.iter())
163                .all(|(a, b)| *a == *b);
164            let m_matches = buf[m_off..m_off + m_len]
165                .iter()
166                .zip(m_data.iter())
167                .all(|(a, b)| *a == *b);
168            if a_matches && m_matches && tag_is_valid {
169                debug!(
170                    "aes_ccm_test passed: (current_test={}, encrypting={}, tag_is_valid={})",
171                    self.current_test.get(),
172                    self.encrypting.get(),
173                    tag_is_valid
174                );
175            } else {
176                panic!("aes_ccm_test failed: a_matches={}, m_matches={}, (current_test={}, encrypting={}, tag_is_valid={}",
177                       a_matches,
178                       m_matches,
179                       self.current_test.get(),
180                       self.encrypting.get(),
181                       tag_is_valid);
182            }
183        }
184
185        self.buf.replace(buf);
186    }
187}
188
189impl<'a, A: AES128CCM<'a>> CCMClient for Test<'a, A> {
190    fn crypt_done(&self, buf: &'static mut [u8], res: Result<(), ErrorCode>, tag_is_valid: bool) {
191        self.buf.replace(buf);
192        if res != Ok(()) {
193            panic!("aes_ccm_test failed: crypt_done returned {:?}", res);
194        } else {
195            self.check_test(tag_is_valid);
196            if self.next_test() {
197                self.trigger_test()
198            }
199        }
200    }
201}
202
203static KEY: [u8; AES128_KEY_SIZE] = [
204    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
205];
206
207// IEEE 802.15.4-2015, Annex C.2.1.1, Secured beacon frame
208static BEACON_SECURED: [u8; 34] = [
209    0x08, 0xD0, 0x84, 0x21, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x02, 0x05, 0x00,
210    0x00, 0x00, 0x55, 0xCF, 0x00, 0x00, 0x51, 0x52, 0x53, 0x54, 0x22, 0x3B, 0xC1, 0xEC, 0x84, 0x1A,
211    0xB5, 0x53,
212];
213
214// IEEE 802.15.4-2015, Annex C.2.1.2, Unsecured beacon frame with auxiliary
215// security header included and the security bits set
216static BEACON_UNSECURED: [u8; 26] = [
217    0x08, 0xD0, 0x84, 0x21, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x02, 0x05, 0x00,
218    0x00, 0x00, 0x55, 0xCF, 0x00, 0x00, 0x51, 0x52, 0x53, 0x54,
219];
220
221// IEEE 802.15.4-2015, Annex C.2.1.3, Nonce for beacon frame
222static BEACON_NONCE: [u8; CCM_NONCE_LENGTH] = [
223    0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02,
224];
225
226// IEEE 802.15.4-2015, Annex C.2.2.1, Secured data frame
227static DATA_SECURED: [u8; 30] = [
228    0x69, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x01, 0x00, 0x00,
229    0x00, 0x00, 0x48, 0xDE, 0xAC, 0x04, 0x05, 0x00, 0x00, 0x00, 0xD4, 0x3E, 0x02, 0x2B,
230];
231
232// IEEE 802.15.4-2015, Annex C.2.2.2, Unsecured data frame with auxiliary
233// security header included and the security bits set
234static DATA_UNSECURED: [u8; 30] = [
235    0x69, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x01, 0x00, 0x00,
236    0x00, 0x00, 0x48, 0xDE, 0xAC, 0x04, 0x05, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,
237];
238
239// IEEE 802.15.4-2015, Annex C.2.2.2, Nonce for data frame
240static DATA_NONCE: [u8; CCM_NONCE_LENGTH] = [
241    0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x04,
242];
243
244// IEEE 802.15.4-2015, Annex C.2.3.1, Secured MAC command frame
245static MAC_SECURED: [u8; 38] = [
246    0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0xFF, 0xFF, 0x01,
247    0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00, 0x00, 0x00, 0x01, 0xD8, 0x4F, 0xDE,
248    0x52, 0x90, 0x61, 0xF9, 0xC6, 0xF1,
249];
250
251// IEEE 802.15.4-2015, Annex C.2.3.2, Unsecured MAC command frame with auxiliary
252// security header included and the security bits set
253static MAC_UNSECURED: [u8; 30] = [
254    0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0xFF, 0xFF, 0x01,
255    0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00, 0x00, 0x00, 0x01, 0xCE,
256];
257
258// IEEE 802.15.4-2015, Annex C.2.3.2, Nonce for MAC frame
259static MAC_NONCE: [u8; CCM_NONCE_LENGTH] = [
260    0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x06,
261];