1use 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 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
207static 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
214static 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
221static BEACON_NONCE: [u8; CCM_NONCE_LENGTH] = [
223 0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02,
224];
225
226static 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
232static 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
239static DATA_NONCE: [u8; CCM_NONCE_LENGTH] = [
241 0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x04,
242];
243
244static 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
251static 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
258static MAC_NONCE: [u8; CCM_NONCE_LENGTH] = [
260 0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x06,
261];