Skip to main content

capsules_extra/test/
sha224.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 Oxidos Automotive 2026.
4
5//! Test the implementation of SHA224 driver 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 capsules_core::test::capsule_test::{CapsuleTest, CapsuleTestClient};
14use kernel::ErrorCode;
15use kernel::debug;
16use kernel::hil::digest;
17use kernel::utilities::cells::{OptionalCell, TakeCell};
18use kernel::utilities::leasable_buffer::SubSlice;
19use kernel::utilities::leasable_buffer::SubSliceMut;
20
21const SHA224_DIGEST_LEN: usize = 28;
22
23pub struct TestSha224<'a, H: digest::Digest<'a, SHA224_DIGEST_LEN>> {
24    sha: &'a H,
25    data: TakeCell<'static, [u8]>, // The data to hash
26    hash: TakeCell<'static, [u8; SHA224_DIGEST_LEN]>, // 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<'a, H: digest::Digest<'a, SHA224_DIGEST_LEN> + digest::Sha224> TestSha224<'a, H> {
38    pub fn new(
39        sha: &'a H,
40        data: &'static mut [u8],
41        hash: &'static mut [u8; SHA224_DIGEST_LEN],
42        correct: bool,
43    ) -> Self {
44        TestSha224 {
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(&'a self) {
55        let r = self.sha.set_mode_sha224();
56        if r.is_err() {
57            panic!("Sha224Test: failed to set mode: {:?}", r)
58        }
59        self.sha.set_client(self);
60        let data = self.data.take().unwrap();
61        let chunk_size = cmp::min(CHUNK_SIZE, data.len());
62        self.position.set(chunk_size);
63        let mut buffer = SubSliceMut::new(data);
64        buffer.slice(0..chunk_size);
65        let r = self.sha.add_mut_data(buffer);
66        if r.is_err() {
67            panic!("Sha224Test: failed to add data: {:?}", r);
68        }
69    }
70}
71
72impl<'a, H: digest::Digest<'a, SHA224_DIGEST_LEN>> digest::ClientData<SHA224_DIGEST_LEN>
73    for TestSha224<'a, H>
74{
75    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {
76        unimplemented!()
77    }
78
79    fn add_mut_data_done(&self, result: Result<(), ErrorCode>, mut data: SubSliceMut<'static, u8>) {
80        if data.len() != 0 {
81            let r = self.sha.add_mut_data(data);
82            if r.is_err() {
83                panic!("Sha224Test: failed to add data: {:?}", r);
84            }
85        } else {
86            data.reset();
87            if self.position.get() < data.len() {
88                let new_position = cmp::min(data.len(), self.position.get() + CHUNK_SIZE);
89                data.slice(self.position.get()..new_position);
90                debug!(
91                    "Sha224Test: Setting slice to {}..{}",
92                    self.position.get(),
93                    new_position
94                );
95                let r = self.sha.add_mut_data(data);
96                if r.is_err() {
97                    panic!("Sha224Test: failed to add data: {:?}", r);
98                }
99                self.position.set(new_position);
100            } else {
101                data.reset();
102                self.data.put(Some(data.take()));
103                match result {
104                    Ok(()) => {
105                        let v = self.sha.verify(self.hash.take().unwrap());
106                        if v.is_err() {
107                            panic!("Sha224Test: failed to verify: {:?}", v);
108                        }
109                    }
110                    Err(e) => {
111                        panic!("Sha224Test: adding data failed: {:?}", e);
112                    }
113                }
114            }
115        }
116    }
117}
118
119impl<'a, H: digest::Digest<'a, SHA224_DIGEST_LEN>> digest::ClientVerify<SHA224_DIGEST_LEN>
120    for TestSha224<'a, H>
121{
122    fn verification_done(
123        &self,
124        result: Result<bool, ErrorCode>,
125        compare: &'static mut [u8; SHA224_DIGEST_LEN],
126    ) {
127        self.hash.put(Some(compare));
128        debug!("Sha256Test: Verification result: {:?}", result);
129        match result {
130            Ok(success) => {
131                if success != self.correct.get() {
132                    panic!(
133                        "Sha256Test: Verification should have been {}, was {}",
134                        self.correct.get(),
135                        success
136                    );
137                } else {
138                    self.client.map(|client| {
139                        client.done(Ok(()));
140                    });
141                }
142            }
143            Err(e) => {
144                panic!("Sha256Test: Error in verification: {:?}", e);
145            }
146        }
147    }
148}
149
150impl<'a, H: digest::Digest<'a, SHA224_DIGEST_LEN>> digest::ClientHash<SHA224_DIGEST_LEN>
151    for TestSha224<'a, H>
152{
153    fn hash_done(
154        &self,
155        _result: Result<(), ErrorCode>,
156        _digest: &'static mut [u8; SHA224_DIGEST_LEN],
157    ) {
158    }
159}
160
161impl<'a, H: digest::Digest<'a, SHA224_DIGEST_LEN>> CapsuleTest for TestSha224<'a, H> {
162    fn set_client(&self, client: &'static dyn CapsuleTestClient) {
163        self.client.set(client);
164    }
165}