Skip to main content

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