1use capsules_core::test::capsule_test::{CapsuleTest, CapsuleTestClient};
18use core::cell::Cell;
19use kernel::debug;
20use kernel::hil;
21use kernel::hil::symmetric_encryption::{
22 AES, AES_BLOCK_SIZE, AES256, AES256_KEY_SIZE, AESCBC, AESCtr, AESECB,
23};
24use kernel::utilities::cells::OptionalCell;
25use kernel::utilities::cells::TakeCell;
26
27const DATA_OFFSET: usize = AES_BLOCK_SIZE;
31const DATA_LEN: usize = 4 * AES_BLOCK_SIZE;
32const CHUNK_LEN: usize = 2 * AES_BLOCK_SIZE; #[derive(Copy, Clone, Debug, PartialEq)]
35enum TestStep {
36 StandardEnc,
37 StandardEncInPlace,
38 StandardDec,
39 StandardDecInPlace,
40 ChunkEnc1,
41 ChunkEnc2,
42 ChunkDec1,
43 ChunkDec2,
44 Done,
45}
46
47pub struct TestAES256Ecb<'a, A: 'a> {
52 aes: &'a A,
53 key: TakeCell<'a, [u8]>,
54 source: TakeCell<'static, [u8]>,
55 data: TakeCell<'static, [u8]>,
56 test_decrypt: bool,
57 step: Cell<TestStep>,
58 client: OptionalCell<&'static dyn CapsuleTestClient>,
59}
60
61impl<'a, A: AES<'a, AES256> + AESECB> TestAES256Ecb<'a, A> {
62 pub fn new(
63 aes: &'a A,
64 key: &'a mut [u8],
65 source: &'static mut [u8],
66 data: &'static mut [u8],
67 test_decrypt: bool,
68 ) -> Self {
69 TestAES256Ecb {
70 aes,
71 key: TakeCell::new(key),
72 source: TakeCell::new(source),
73 data: TakeCell::new(data),
74 test_decrypt,
75 step: Cell::new(TestStep::StandardEnc),
76 client: OptionalCell::empty(),
77 }
78 }
79
80 pub fn run(&self) {
81 let step = self.step.get();
82 let encrypting = is_encrypting(step);
83 let in_place = is_in_place(step);
84
85 if !is_second_chunk(step) {
88 self.aes.enable();
89 self.aes.set_mode_aesecb(encrypting).unwrap();
90 self.key.map(|key| {
91 key[..KEY.len()].copy_from_slice(&KEY);
92 assert_eq!(self.aes.set_key(key), Ok(()));
93 });
94 let src = if encrypting { &PTXT } else { &CTXT_ECB };
95 self.source.map(|s| s[..src.len()].copy_from_slice(src));
96 self.aes.start_message();
97 }
98
99 prepare_in_place(step, in_place, &self.source, &self.data);
100
101 let (start, stop) = chunk_range(step);
102 run_crypt(self.aes, in_place, &self.source, &self.data, start, stop);
103 }
104}
105
106impl<'a, A: AES<'a, AES256> + AESECB> CapsuleTest for TestAES256Ecb<'a, A> {
107 fn set_client(&self, client: &'static dyn CapsuleTestClient) {
108 self.client.set(client);
109 }
110}
111
112impl<'a, A: AES<'a, AES256> + AESECB> hil::symmetric_encryption::Client<'a>
113 for TestAES256Ecb<'a, A>
114{
115 fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
116 let step = self.step.get();
117 let encrypting = is_encrypting(step);
118 let in_place = is_in_place(step);
119
120 restore_source(in_place, source, &self.source);
121 self.data.replace(dest);
122
123 if !is_first_chunk(step) {
126 let expected = if encrypting { &CTXT_ECB } else { &PTXT };
127 self.data.map(|d| {
128 assert_eq!(
129 &d[DATA_OFFSET..DATA_OFFSET + DATA_LEN],
130 expected.as_ref(),
131 "aes_test ECB failed at step {:?}",
132 step
133 );
134 });
135 debug!("aes_test ECB passed step: {:?}", step);
136 self.aes.disable();
137 }
138
139 let next = next_step(step, self.test_decrypt);
140 self.step.set(next);
141 if next == TestStep::Done {
142 self.client.map(|c| c.done(Ok(())));
143 } else {
144 self.run();
145 }
146 }
147}
148
149pub struct TestAES256Cbc<'a, A: 'a> {
154 aes: &'a A,
155 key: TakeCell<'a, [u8]>,
156 iv: TakeCell<'a, [u8]>,
157 source: TakeCell<'static, [u8]>,
158 data: TakeCell<'static, [u8]>,
159 test_decrypt: bool,
160 step: Cell<TestStep>,
161 client: OptionalCell<&'static dyn CapsuleTestClient>,
162}
163
164impl<'a, A: AES<'a, AES256> + AESCBC> TestAES256Cbc<'a, A> {
165 pub fn new(
166 aes: &'a A,
167 key: &'a mut [u8],
168 iv: &'a mut [u8],
169 source: &'static mut [u8],
170 data: &'static mut [u8],
171 test_decrypt: bool,
172 ) -> Self {
173 TestAES256Cbc {
174 aes,
175 key: TakeCell::new(key),
176 iv: TakeCell::new(iv),
177 source: TakeCell::new(source),
178 data: TakeCell::new(data),
179 test_decrypt,
180 step: Cell::new(TestStep::StandardEnc),
181 client: OptionalCell::empty(),
182 }
183 }
184
185 pub fn run(&self) {
186 let step = self.step.get();
187 let encrypting = is_encrypting(step);
188 let in_place = is_in_place(step);
189
190 if !is_second_chunk(step) {
191 self.aes.enable();
192 self.aes.set_mode_aescbc(encrypting).unwrap();
193 self.key.map(|key| {
194 key[..KEY.len()].copy_from_slice(&KEY);
195 assert_eq!(self.aes.set_key(key), Ok(()));
196 });
197 self.iv.map(|iv| {
198 iv[..IV_CBC.len()].copy_from_slice(&IV_CBC);
199 assert_eq!(self.aes.set_iv(iv), Ok(()));
200 });
201 let src = if encrypting { &PTXT } else { &CTXT_CBC };
202 self.source.map(|s| s[..src.len()].copy_from_slice(src));
203 self.aes.start_message();
204 }
205
206 prepare_in_place(step, in_place, &self.source, &self.data);
207
208 let (start, stop) = chunk_range(step);
209 run_crypt(self.aes, in_place, &self.source, &self.data, start, stop);
210 }
211}
212
213impl<'a, A: AES<'a, AES256> + AESCBC> CapsuleTest for TestAES256Cbc<'a, A> {
214 fn set_client(&self, client: &'static dyn CapsuleTestClient) {
215 self.client.set(client);
216 }
217}
218
219impl<'a, A: AES<'a, AES256> + AESCBC> hil::symmetric_encryption::Client<'a>
220 for TestAES256Cbc<'a, A>
221{
222 fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
223 let step = self.step.get();
224 let encrypting = is_encrypting(step);
225 let in_place = is_in_place(step);
226
227 restore_source(in_place, source, &self.source);
228 self.data.replace(dest);
229
230 if !is_first_chunk(step) {
231 let expected = if encrypting { &CTXT_CBC } else { &PTXT };
232 self.data.map(|d| {
233 assert_eq!(
234 &d[DATA_OFFSET..DATA_OFFSET + DATA_LEN],
235 expected.as_ref(),
236 "aes_test CBC failed at step {:?}",
237 step
238 );
239 });
240 debug!("aes_test CBC passed step: {:?}", step);
241 self.aes.disable();
242 }
243
244 let next = next_step(step, self.test_decrypt);
245 self.step.set(next);
246 if next == TestStep::Done {
247 self.client.map(|c| c.done(Ok(())));
248 } else {
249 self.run();
250 }
251 }
252}
253
254pub struct TestAES256Ctr<'a, A: 'a> {
259 aes: &'a A,
260 key: TakeCell<'a, [u8]>,
261 iv: TakeCell<'a, [u8]>,
262 source: TakeCell<'static, [u8]>,
263 data: TakeCell<'static, [u8]>,
264 test_decrypt: bool,
265 step: Cell<TestStep>,
266 client: OptionalCell<&'static dyn CapsuleTestClient>,
267}
268
269impl<'a, A: AES<'a, AES256> + AESCtr> TestAES256Ctr<'a, A> {
270 pub fn new(
271 aes: &'a A,
272 key: &'a mut [u8],
273 iv: &'a mut [u8],
274 source: &'static mut [u8],
275 data: &'static mut [u8],
276 test_decrypt: bool,
277 ) -> Self {
278 TestAES256Ctr {
279 aes,
280 key: TakeCell::new(key),
281 iv: TakeCell::new(iv),
282 source: TakeCell::new(source),
283 data: TakeCell::new(data),
284 test_decrypt,
285 step: Cell::new(TestStep::StandardEnc),
286 client: OptionalCell::empty(),
287 }
288 }
289
290 pub fn run(&self) {
291 let step = self.step.get();
292 let encrypting = is_encrypting(step);
293 let in_place = is_in_place(step);
294
295 if !is_second_chunk(step) {
296 self.aes.enable();
297 self.aes.set_mode_aesctr(encrypting).unwrap();
298 self.key.map(|key| {
299 key[..KEY.len()].copy_from_slice(&KEY);
300 assert_eq!(self.aes.set_key(key), Ok(()));
301 });
302 self.iv.map(|iv| {
303 iv[..IV_CTR.len()].copy_from_slice(&IV_CTR);
304 assert_eq!(self.aes.set_iv(iv), Ok(()));
305 });
306 let src = if encrypting { &PTXT } else { &CTXT_CTR };
307 self.source.map(|s| s[..src.len()].copy_from_slice(src));
308 self.aes.start_message();
309 }
310
311 prepare_in_place(step, in_place, &self.source, &self.data);
312
313 let (start, stop) = chunk_range(step);
314 run_crypt(self.aes, in_place, &self.source, &self.data, start, stop);
315 }
316}
317
318impl<'a, A: AES<'a, AES256> + AESCtr> CapsuleTest for TestAES256Ctr<'a, A> {
319 fn set_client(&self, client: &'static dyn CapsuleTestClient) {
320 self.client.set(client);
321 }
322}
323
324impl<'a, A: AES<'a, AES256> + AESCtr> hil::symmetric_encryption::Client<'a>
325 for TestAES256Ctr<'a, A>
326{
327 fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
328 let step = self.step.get();
329 let encrypting = is_encrypting(step);
330 let in_place = is_in_place(step);
331
332 restore_source(in_place, source, &self.source);
333 self.data.replace(dest);
334
335 if !is_first_chunk(step) {
336 let expected = if encrypting { &CTXT_CTR } else { &PTXT };
337 self.data.map(|d| {
338 assert_eq!(
339 &d[DATA_OFFSET..DATA_OFFSET + DATA_LEN],
340 expected.as_ref(),
341 "aes_test CTR failed at step {:?}",
342 step
343 );
344 assert_eq!(
346 d[..DATA_OFFSET],
347 [0u8; DATA_OFFSET],
348 "aes_test CTR: guard region corrupted at step {:?}",
349 step
350 );
351 });
352 debug!("aes_test CTR passed step: {:?}", step);
353 self.aes.disable();
354 }
355
356 let next = next_step(step, self.test_decrypt);
357 self.step.set(next);
358 if next == TestStep::Done {
359 self.client.map(|c| c.done(Ok(())));
360 } else {
361 self.run();
362 }
363 }
364}
365
366fn is_encrypting(step: TestStep) -> bool {
371 !matches!(
372 step,
373 TestStep::StandardDec
374 | TestStep::StandardDecInPlace
375 | TestStep::ChunkDec1
376 | TestStep::ChunkDec2
377 )
378}
379
380fn is_in_place(step: TestStep) -> bool {
381 matches!(
382 step,
383 TestStep::StandardEncInPlace
384 | TestStep::StandardDecInPlace
385 | TestStep::ChunkEnc1
386 | TestStep::ChunkEnc2
387 | TestStep::ChunkDec1
388 | TestStep::ChunkDec2
389 )
390}
391
392fn is_first_chunk(step: TestStep) -> bool {
393 matches!(step, TestStep::ChunkEnc1 | TestStep::ChunkDec1)
394}
395
396fn is_second_chunk(step: TestStep) -> bool {
397 matches!(step, TestStep::ChunkEnc2 | TestStep::ChunkDec2)
398}
399
400fn chunk_range(step: TestStep) -> (usize, usize) {
402 match step {
403 TestStep::ChunkEnc1 | TestStep::ChunkDec1 => (DATA_OFFSET, DATA_OFFSET + CHUNK_LEN),
404 TestStep::ChunkEnc2 | TestStep::ChunkDec2 => {
405 (DATA_OFFSET + CHUNK_LEN, DATA_OFFSET + DATA_LEN)
406 }
407 _ => (DATA_OFFSET, DATA_OFFSET + DATA_LEN),
408 }
409}
410
411fn prepare_in_place(
414 step: TestStep,
415 in_place: bool,
416 source: &TakeCell<'static, [u8]>,
417 data: &TakeCell<'static, [u8]>,
418) {
419 if !in_place {
420 return;
421 }
422 let src_start = match step {
423 TestStep::ChunkEnc2 | TestStep::ChunkDec2 => CHUNK_LEN,
424 _ => 0,
425 };
426 let dst_start = match step {
427 TestStep::ChunkEnc2 | TestStep::ChunkDec2 => DATA_OFFSET + CHUNK_LEN,
428 _ => DATA_OFFSET,
429 };
430 let copy_len = match step {
431 TestStep::ChunkEnc1 | TestStep::ChunkDec1 => DATA_LEN,
432 TestStep::ChunkEnc2 | TestStep::ChunkDec2 => 0,
433 _ => DATA_LEN,
434 };
435 source.map(|src| {
436 data.map(|dst| {
437 dst[dst_start..dst_start + copy_len]
438 .copy_from_slice(&src[src_start..src_start + copy_len]);
439 });
440 });
441}
442
443fn run_crypt<'a, A: AES<'a, AES256>>(
444 aes: &'a A,
445 in_place: bool,
446 source: &TakeCell<'static, [u8]>,
447 data: &TakeCell<'static, [u8]>,
448 start: usize,
449 stop: usize,
450) {
451 let src = if in_place { None } else { source.take() };
452 match aes.crypt(src, data.take().unwrap(), start, stop) {
453 None => {}
454 Some((result, src_back, dest_back)) => {
455 source.put(src_back);
456 data.put(Some(dest_back));
457 panic!("crypt() returned error: {:?}", result);
458 }
459 }
460}
461
462fn restore_source(
463 in_place: bool,
464 source: Option<&'static mut [u8]>,
465 cell: &TakeCell<'static, [u8]>,
466) {
467 if !in_place {
468 cell.replace(source.expect("crypt_done: expected source buffer for out-of-place op"));
469 }
470}
471
472fn next_step(step: TestStep, test_decrypt: bool) -> TestStep {
473 match step {
474 TestStep::StandardEnc => TestStep::StandardEncInPlace,
475 TestStep::StandardEncInPlace => {
476 if test_decrypt {
477 TestStep::StandardDec
478 } else {
479 TestStep::ChunkEnc1
480 }
481 }
482 TestStep::StandardDec => TestStep::StandardDecInPlace,
483 TestStep::StandardDecInPlace => TestStep::ChunkEnc1,
484 TestStep::ChunkEnc1 => TestStep::ChunkEnc2,
485 TestStep::ChunkEnc2 => {
486 if test_decrypt {
487 TestStep::ChunkDec1
488 } else {
489 TestStep::Done
490 }
491 }
492 TestStep::ChunkDec1 => TestStep::ChunkDec2,
493 TestStep::ChunkDec2 => {
494 debug!("All tests passed");
495 TestStep::Done
496 }
497 _ => TestStep::Done,
498 }
499}
500
501#[rustfmt::skip]
506const KEY: [u8; AES256_KEY_SIZE] = [
507 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
508 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
509 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
510 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
511];
512
513#[rustfmt::skip]
514const IV_CTR: [u8; AES_BLOCK_SIZE] = [
515 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
516 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
517];
518
519#[rustfmt::skip]
520const IV_CBC: [u8; AES_BLOCK_SIZE] = [
521 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
522 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
523];
524
525#[rustfmt::skip]
526const PTXT: [u8; DATA_LEN] = [
527 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
528 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
529 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
530 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
531 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
532 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
533 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
534 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
535];
536
537#[rustfmt::skip]
538const CTXT_CTR: [u8; DATA_LEN] = [
539 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5,
540 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
541 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a,
542 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
543 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c,
544 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
545 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6,
546 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
547];
548
549#[rustfmt::skip]
550const CTXT_CBC: [u8; DATA_LEN] = [
551 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
552 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
553 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
554 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
555 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
556 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
557 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
558 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
559];
560
561#[rustfmt::skip]
562const CTXT_ECB: [u8; DATA_LEN] = [
563 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c,
564 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
565 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26,
566 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
567 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9,
568 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
569 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff,
570 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7,
571];