capsules_extra/test/
sha256.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 software implementation of SHA256 by performing a hash
6//! and checking it against the expected hash value. It uses
7//! DigestData::add_date and DigestVerify::verify through the
8//! Digest trait.
9
10use core::cell::Cell;
11use core::cmp;
12
13use crate::sha256::Sha256Software;
14use capsules_core::test::capsule_test::{CapsuleTest, CapsuleTestClient};
15use kernel::debug;
16use kernel::hil::digest;
17use kernel::hil::digest::{Digest, DigestData, DigestVerify};
18use kernel::utilities::cells::{OptionalCell, TakeCell};
19use kernel::utilities::leasable_buffer::SubSlice;
20use kernel::utilities::leasable_buffer::SubSliceMut;
21use kernel::ErrorCode;
22
23pub struct TestSha256 {
24    sha: &'static Sha256Software<'static>,
25    data: TakeCell<'static, [u8]>,     // The data to hash
26    hash: TakeCell<'static, [u8; 32]>, // The supplied hash
27    position: Cell<usize>,             // Keep track of position in data
28    correct: Cell<bool>,               // Whether supplied hash is correct
29    client: OptionalCell<&'static dyn CapsuleTestClient>,
30}
31
32// We add data in chunks of 12 bytes to ensure that the underlying
33// buffering mechanism works correctly (it can handle filling blocks
34// as well as zeroing out incomplete blocks).
35const CHUNK_SIZE: usize = 12;
36
37impl TestSha256 {
38    pub fn new(
39        sha: &'static Sha256Software<'static>,
40        data: &'static mut [u8],
41        hash: &'static mut [u8; 32],
42        correct: bool,
43    ) -> Self {
44        TestSha256 {
45            sha,
46            data: TakeCell::new(data),
47            hash: TakeCell::new(hash),
48            position: Cell::new(0),
49            correct: Cell::new(correct),
50            client: OptionalCell::empty(),
51        }
52    }
53
54    pub fn run(&'static self) {
55        self.sha.set_client(self);
56        let data = self.data.take().unwrap();
57        let chunk_size = cmp::min(CHUNK_SIZE, data.len());
58        self.position.set(chunk_size);
59        let mut buffer = SubSliceMut::new(data);
60        buffer.slice(0..chunk_size);
61        let r = self.sha.add_mut_data(buffer);
62        if r.is_err() {
63            panic!("Sha256Test: failed to add data: {:?}", r);
64        }
65    }
66}
67
68impl digest::ClientData<32> for TestSha256 {
69    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {
70        unimplemented!()
71    }
72
73    fn add_mut_data_done(&self, result: Result<(), ErrorCode>, mut data: SubSliceMut<'static, u8>) {
74        if data.len() != 0 {
75            let r = self.sha.add_mut_data(data);
76            if r.is_err() {
77                panic!("Sha256Test: failed to add data: {:?}", r);
78            }
79        } else {
80            data.reset();
81            if self.position.get() < data.len() {
82                let new_position = cmp::min(data.len(), self.position.get() + CHUNK_SIZE);
83                data.slice(self.position.get()..new_position);
84                debug!(
85                    "Sha256Test: Setting slice to {}..{}",
86                    self.position.get(),
87                    new_position
88                );
89                let r = self.sha.add_mut_data(data);
90                if r.is_err() {
91                    panic!("Sha256Test: failed to add data: {:?}", r);
92                }
93                self.position.set(new_position);
94            } else {
95                data.reset();
96                self.data.put(Some(data.take()));
97                match result {
98                    Ok(()) => {
99                        let v = self.sha.verify(self.hash.take().unwrap());
100                        if v.is_err() {
101                            panic!("Sha256Test: failed to verify: {:?}", v);
102                        }
103                    }
104                    Err(e) => {
105                        panic!("Sha256Test: adding data failed: {:?}", e);
106                    }
107                }
108            }
109        }
110    }
111}
112
113impl digest::ClientVerify<32> for TestSha256 {
114    fn verification_done(&self, result: Result<bool, ErrorCode>, compare: &'static mut [u8; 32]) {
115        self.hash.put(Some(compare));
116        debug!("Sha256Test: Verification result: {:?}", result);
117        match result {
118            Ok(success) => {
119                if success != self.correct.get() {
120                    panic!(
121                        "Sha256Test: Verification should have been {}, was {}",
122                        self.correct.get(),
123                        success
124                    );
125                } else {
126                    self.client.map(|client| {
127                        client.done(Ok(()));
128                    });
129                }
130            }
131            Err(e) => {
132                panic!("Sha256Test: Error in verification: {:?}", e);
133            }
134        }
135    }
136}
137
138impl digest::ClientHash<32> for TestSha256 {
139    fn hash_done(&self, _result: Result<(), ErrorCode>, _digest: &'static mut [u8; 32]) {}
140}
141
142impl CapsuleTest for TestSha256 {
143    fn set_client(&self, client: &'static dyn CapsuleTestClient) {
144        self.client.set(client);
145    }
146}