capsules_extra/test/
aes.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 hardware.
6
7use capsules_core::test::capsule_test::{CapsuleTest, CapsuleTestClient};
8use core::cell::Cell;
9use kernel::debug;
10use kernel::hil;
11use kernel::hil::symmetric_encryption::{
12    AES128Ctr, AES128, AES128CBC, AES128ECB, AES128_BLOCK_SIZE, AES128_KEY_SIZE,
13};
14use kernel::utilities::cells::OptionalCell;
15use kernel::utilities::cells::TakeCell;
16
17pub struct TestAes128Ctr<'a, A: 'a> {
18    aes: &'a A,
19
20    key: TakeCell<'a, [u8]>,
21    iv: TakeCell<'a, [u8]>,
22    source: TakeCell<'static, [u8]>,
23    data: TakeCell<'static, [u8]>,
24    test_decrypt: bool,
25
26    encrypting: Cell<bool>,
27    use_source: Cell<bool>,
28
29    client: OptionalCell<&'static dyn CapsuleTestClient>,
30}
31
32pub struct TestAes128Cbc<'a, A: 'a> {
33    aes: &'a A,
34
35    key: TakeCell<'a, [u8]>,
36    iv: TakeCell<'a, [u8]>,
37    source: TakeCell<'static, [u8]>,
38    data: TakeCell<'static, [u8]>,
39    test_decrypt: bool,
40
41    encrypting: Cell<bool>,
42    use_source: Cell<bool>,
43
44    client: OptionalCell<&'static dyn CapsuleTestClient>,
45}
46
47pub struct TestAes128Ecb<'a, A: 'a> {
48    aes: &'a A,
49
50    key: TakeCell<'a, [u8]>,
51    source: TakeCell<'static, [u8]>,
52    data: TakeCell<'static, [u8]>,
53    test_decrypt: bool,
54
55    encrypting: Cell<bool>,
56    use_source: Cell<bool>,
57
58    client: OptionalCell<&'static dyn CapsuleTestClient>,
59}
60
61const DATA_OFFSET: usize = AES128_BLOCK_SIZE;
62const DATA_LEN: usize = 4 * AES128_BLOCK_SIZE;
63
64impl<'a, A: AES128<'a> + AES128ECB> TestAes128Ecb<'a, A> {
65    pub fn new(
66        aes: &'a A,
67        key: &'a mut [u8],
68        source: &'static mut [u8],
69        data: &'static mut [u8],
70        test_decrypt: bool,
71    ) -> Self {
72        TestAes128Ecb {
73            aes,
74
75            key: TakeCell::new(key),
76            source: TakeCell::new(source),
77            data: TakeCell::new(data),
78            test_decrypt,
79
80            encrypting: Cell::new(true),
81            use_source: Cell::new(true),
82
83            client: OptionalCell::empty(),
84        }
85    }
86
87    pub fn run(&self) {
88        self.aes.enable();
89
90        self.aes.set_mode_aes128ecb(self.encrypting.get()).unwrap();
91
92        // Copy key into key buffer and configure it in the hardware
93        self.key.map(|key| {
94            for (i, b) in KEY.iter().enumerate() {
95                key[i] = *b;
96            }
97
98            assert!(self.aes.set_key(key) == Ok(()));
99        });
100
101        // Copy mode-appropriate source into source buffer
102        let source_mode = if self.encrypting.get() {
103            &PTXT
104        } else {
105            &CTXT_ECB
106        };
107        self.source.map(|source| {
108            for (i, b) in source_mode.iter().enumerate() {
109                source[i] = *b;
110            }
111        });
112
113        if !self.use_source.get() {
114            // Copy source into dest for in-place encryption
115            self.source.map_or_else(
116                || panic!("No source"),
117                |source| {
118                    self.data.map_or_else(
119                        || panic!("No data"),
120                        |data| {
121                            for (i, b) in source.iter().enumerate() {
122                                data[DATA_OFFSET + i] = *b;
123                            }
124                        },
125                    );
126                },
127            );
128        }
129
130        self.aes.start_message();
131
132        let start = DATA_OFFSET;
133        let stop = DATA_OFFSET + DATA_LEN;
134
135        match self.aes.crypt(
136            if self.use_source.get() {
137                self.source.take()
138            } else {
139                None
140            },
141            self.data.take().unwrap(),
142            start,
143            stop,
144        ) {
145            None => {
146                // await crypt_done()
147            }
148            Some((result, source, dest)) => {
149                self.source.put(source);
150                self.data.put(Some(dest));
151                panic!("crypt() failed: {:?}", result);
152            }
153        }
154    }
155}
156
157impl<'a, A: AES128<'a> + AES128ECB> CapsuleTest for TestAes128Ecb<'a, A> {
158    fn set_client(&self, client: &'static dyn CapsuleTestClient) {
159        self.client.set(client);
160    }
161}
162
163impl<'a, A: AES128<'a> + AES128Ctr> TestAes128Ctr<'a, A> {
164    pub fn new(
165        aes: &'a A,
166        key: &'a mut [u8],
167        iv: &'a mut [u8],
168        source: &'static mut [u8],
169        data: &'static mut [u8],
170        test_decrypt: bool,
171    ) -> Self {
172        TestAes128Ctr {
173            aes,
174
175            key: TakeCell::new(key),
176            iv: TakeCell::new(iv),
177            source: TakeCell::new(source),
178            data: TakeCell::new(data),
179            test_decrypt,
180
181            encrypting: Cell::new(true),
182            use_source: Cell::new(true),
183
184            client: OptionalCell::empty(),
185        }
186    }
187
188    pub fn run(&self) {
189        self.aes.enable();
190
191        self.aes.set_mode_aes128ctr(self.encrypting.get()).unwrap();
192
193        // Copy key into key buffer and configure it in the hardware
194        self.key.map(|key| {
195            for (i, b) in KEY.iter().enumerate() {
196                key[i] = *b;
197            }
198
199            assert!(self.aes.set_key(key) == Ok(()));
200        });
201
202        // Copy mode-appropriate IV into IV buffer and configure it in the hardware
203        self.iv.map(|iv| {
204            let iv_mode = &IV_CTR;
205            for (i, b) in iv_mode.iter().enumerate() {
206                iv[i] = *b;
207            }
208
209            assert!(self.aes.set_iv(iv) == Ok(()));
210        });
211
212        // Copy mode-appropriate source into source buffer
213        let source_mode = if self.encrypting.get() {
214            &PTXT
215        } else {
216            &CTXT_CTR
217        };
218        self.source.map(|source| {
219            for (i, b) in source_mode.iter().enumerate() {
220                source[i] = *b;
221            }
222        });
223
224        if !self.use_source.get() {
225            // Copy source into dest for in-place encryption
226            self.source.map_or_else(
227                || panic!("No source"),
228                |source| {
229                    self.data.map_or_else(
230                        || panic!("No data"),
231                        |data| {
232                            for (i, b) in source.iter().enumerate() {
233                                data[DATA_OFFSET + i] = *b;
234                            }
235                        },
236                    );
237                },
238            );
239        }
240
241        self.aes.start_message();
242
243        let start = DATA_OFFSET;
244        let stop = DATA_OFFSET + DATA_LEN;
245
246        match self.aes.crypt(
247            if self.use_source.get() {
248                self.source.take()
249            } else {
250                None
251            },
252            self.data.take().unwrap(),
253            start,
254            stop,
255        ) {
256            None => {
257                // await crypt_done()
258            }
259            Some((result, source, dest)) => {
260                self.source.put(source);
261                self.data.put(Some(dest));
262                panic!("crypt() failed: {:?}", result);
263            }
264        }
265    }
266}
267
268impl<'a, A: AES128<'a> + AES128Ctr> hil::symmetric_encryption::Client<'a> for TestAes128Ctr<'a, A> {
269    fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
270        if self.use_source.get() {
271            // Take back the source buffer
272            self.source.put(source);
273        }
274
275        // Take back the destination buffer
276        self.data.replace(dest);
277
278        let expected = if self.encrypting.get() {
279            &CTXT_CTR
280        } else {
281            &PTXT
282        };
283
284        if self.data.map_or(false, |data| {
285            &data[DATA_OFFSET..DATA_OFFSET + DATA_LEN] == expected.as_ref()
286        }) {
287            debug!(
288                "aes_test CTR passed: (CTR {} {} {})",
289                if self.encrypting.get() { "Enc" } else { "Dec" },
290                "Ctr",
291                if self.use_source.get() {
292                    "Src/Dst"
293                } else {
294                    "In-place"
295                }
296            );
297        } else {
298            panic!(
299                "aes_test failed: (CTR {} {} {})",
300                if self.encrypting.get() { "Enc" } else { "Dec" },
301                "Ctr",
302                if self.use_source.get() {
303                    "Src/Dst"
304                } else {
305                    "In-place"
306                }
307            );
308        }
309        self.aes.disable();
310
311        // Continue testing with other configurations
312        if self.use_source.get() {
313            self.use_source.set(false);
314            self.run();
315        } else {
316            if self.encrypting.get() && self.test_decrypt {
317                self.encrypting.set(false);
318                self.use_source.set(true);
319                self.run();
320            } else {
321                self.client.map(|client| {
322                    client.done(Ok(()));
323                });
324            }
325        }
326    }
327}
328
329impl<'a, A: AES128<'a> + AES128Ctr> CapsuleTest for TestAes128Ctr<'a, A> {
330    fn set_client(&self, client: &'static dyn CapsuleTestClient) {
331        self.client.set(client);
332    }
333}
334
335impl<'a, A: AES128<'a> + AES128CBC> TestAes128Cbc<'a, A> {
336    pub fn new(
337        aes: &'a A,
338        key: &'a mut [u8],
339        iv: &'a mut [u8],
340        source: &'static mut [u8],
341        data: &'static mut [u8],
342        test_decrypt: bool,
343    ) -> Self {
344        TestAes128Cbc {
345            aes,
346
347            key: TakeCell::new(key),
348            iv: TakeCell::new(iv),
349            source: TakeCell::new(source),
350            data: TakeCell::new(data),
351            test_decrypt,
352
353            encrypting: Cell::new(true),
354            use_source: Cell::new(true),
355
356            client: OptionalCell::empty(),
357        }
358    }
359
360    pub fn run(&self) {
361        self.aes.enable();
362
363        self.aes.set_mode_aes128cbc(self.encrypting.get()).unwrap();
364
365        // Copy key into key buffer and configure it in the hardware
366        self.key.map(|key| {
367            for (i, b) in KEY.iter().enumerate() {
368                key[i] = *b;
369            }
370
371            assert!(self.aes.set_key(key) == Ok(()));
372        });
373
374        // Copy mode-appropriate IV into IV buffer and configure it in the hardware
375        self.iv.map(|iv| {
376            let iv_mode = &IV_CBC;
377
378            for (i, b) in iv_mode.iter().enumerate() {
379                iv[i] = *b;
380            }
381
382            assert!(self.aes.set_iv(iv) == Ok(()));
383        });
384
385        // Copy mode-appropriate source into source buffer
386        let source_mode = if self.encrypting.get() {
387            &PTXT
388        } else {
389            &CTXT_CBC
390        };
391        self.source.map(|source| {
392            for (i, b) in source_mode.iter().enumerate() {
393                source[i] = *b;
394            }
395        });
396
397        if !self.use_source.get() {
398            // Copy source into dest for in-place encryption
399            self.source.map_or_else(
400                || panic!("aes_test: no source"),
401                |source| {
402                    self.data.map_or_else(
403                        || panic!("aes_test: no data"),
404                        |data| {
405                            for (i, b) in source.iter().enumerate() {
406                                data[DATA_OFFSET + i] = *b;
407                            }
408                        },
409                    );
410                },
411            );
412        }
413
414        self.aes.start_message();
415
416        let start = DATA_OFFSET;
417        let stop = DATA_OFFSET + DATA_LEN;
418
419        match self.aes.crypt(
420            if self.use_source.get() {
421                self.source.take()
422            } else {
423                None
424            },
425            self.data.take().unwrap(),
426            start,
427            stop,
428        ) {
429            None => {
430                // await crypt_done()
431            }
432            Some((result, source, dest)) => {
433                self.source.put(source);
434                self.data.put(Some(dest));
435                panic!("crypt() failed: {:?}", result);
436            }
437        }
438    }
439}
440
441impl<'a, A: AES128<'a> + AES128CBC> hil::symmetric_encryption::Client<'a> for TestAes128Cbc<'a, A> {
442    fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
443        if self.use_source.get() {
444            // Take back the source buffer
445            self.source.put(source);
446        }
447
448        // Take back the destination buffer
449        self.data.replace(dest);
450
451        let expected = if self.encrypting.get() {
452            &CTXT_CBC
453        } else {
454            &PTXT
455        };
456
457        if self.data.map_or(false, |data| {
458            &data[DATA_OFFSET..DATA_OFFSET + DATA_LEN] == expected.as_ref()
459        }) {
460            debug!(
461                "aes_test passed (CBC {} {})",
462                if self.encrypting.get() { "Enc" } else { "Dec" },
463                if self.use_source.get() {
464                    "Src/Dst"
465                } else {
466                    "In-place"
467                }
468            );
469        } else {
470            panic!(
471                "aes_test failed: (CBC {} {})",
472                if self.encrypting.get() { "Enc" } else { "Dec" },
473                if self.use_source.get() {
474                    "Src/Dst"
475                } else {
476                    "In-place"
477                }
478            );
479        }
480        self.aes.disable();
481
482        // Continue testing with other configurations
483        if self.use_source.get() {
484            self.use_source.set(false);
485            self.run();
486        } else {
487            if self.encrypting.get() && self.test_decrypt {
488                self.encrypting.set(false);
489                self.use_source.set(true);
490                self.run();
491            } else {
492                self.client.map(|client| {
493                    client.done(Ok(()));
494                });
495            }
496        }
497    }
498}
499
500impl<'a, A: AES128<'a> + AES128CBC> CapsuleTest for TestAes128Cbc<'a, A> {
501    fn set_client(&self, client: &'static dyn CapsuleTestClient) {
502        self.client.set(client);
503    }
504}
505
506impl<'a, A: AES128<'a> + AES128ECB> hil::symmetric_encryption::Client<'a> for TestAes128Ecb<'a, A> {
507    fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]) {
508        if self.use_source.get() {
509            // Take back the source buffer
510            self.source.put(source);
511        }
512
513        // Take back the destination buffer
514        self.data.replace(dest);
515
516        let expected = if self.encrypting.get() {
517            &CTXT_ECB
518        } else {
519            &PTXT
520        };
521
522        if self.data.map_or(false, |data| {
523            &data[DATA_OFFSET..DATA_OFFSET + DATA_LEN] == expected.as_ref()
524        }) {
525            debug!(
526                "aes_test passed (ECB {} {})",
527                if self.encrypting.get() { "Enc" } else { "Dec" },
528                if self.use_source.get() {
529                    "Src/Dst"
530                } else {
531                    "In-place"
532                }
533            );
534        } else {
535            panic!(
536                "aes_test failed: (ECB {} {})",
537                if self.encrypting.get() { "Enc" } else { "Dec" },
538                if self.use_source.get() {
539                    "Src/Dst"
540                } else {
541                    "In-place"
542                }
543            );
544        }
545        self.aes.disable();
546
547        // Continue testing with other configurations
548        if self.use_source.get() {
549            self.use_source.set(false);
550            self.run();
551        } else {
552            if self.encrypting.get() && self.test_decrypt {
553                self.encrypting.set(false);
554                self.use_source.set(true);
555                self.run();
556            } else {
557                self.client.map(|client| {
558                    client.done(Ok(()));
559                });
560            }
561        }
562    }
563}
564
565#[rustfmt::skip]
566const KEY: [u8; AES128_KEY_SIZE] = [
567    0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
568    0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
569];
570
571#[rustfmt::skip]
572const IV_CTR: [u8; AES128_BLOCK_SIZE] = [
573    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
574    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
575];
576
577#[rustfmt::skip]
578const IV_CBC: [u8; AES128_BLOCK_SIZE] = [
579    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
580    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
581];
582
583#[rustfmt::skip]
584const PTXT: [u8; 4 * AES128_BLOCK_SIZE] = [
585    0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
586    0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
587    0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
588    0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
589    0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
590    0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
591    0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
592    0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
593];
594
595#[rustfmt::skip]
596const CTXT_CTR: [u8; 4 * AES128_BLOCK_SIZE] = [
597    0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
598    0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
599    0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
600    0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
601    0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
602    0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
603    0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
604    0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
605];
606
607#[rustfmt::skip]
608const CTXT_CBC: [u8; 4 * AES128_BLOCK_SIZE] = [
609    0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
610    0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
611    0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
612    0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
613    0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b,
614    0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
615    0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
616    0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7
617];
618
619#[rustfmt::skip]
620const CTXT_ECB: [u8; 4 * AES128_BLOCK_SIZE] = [
621    0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
622    0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
623    0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d,
624    0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
625    0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23,
626    0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
627    0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f,
628    0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4
629];