kernel/hil/digest.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//! Interface for computing digests (hashes, cryptographic hashes, and
6//! HMACs) over data.
7
8use crate::utilities::leasable_buffer::SubSlice;
9use crate::utilities::leasable_buffer::SubSliceMut;
10use crate::ErrorCode;
11
12/// Implement this trait and use `set_client()` in order to receive callbacks
13/// when data has been added to a digest.
14///
15/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
16pub trait ClientData<const DIGEST_LEN: usize> {
17 /// Called when the data has been added to the digest. `data` is
18 /// the `SubSlice` passed in the call to `add_data`, whose
19 /// active slice contains the data that was not added. On `Ok`,
20 /// `data` has an active slice of size zero (all data was added).
21 /// Valid `ErrorCode` values are:
22 /// - OFF: the underlying digest engine is powered down and
23 /// cannot be used.
24 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
25 /// `run`, or `verify` operation, so the digest engine is busy
26 /// and cannot accept more data.
27 /// - SIZE: the active slice of the SubSlice has zero size.
28 /// - CANCEL: the operation was cancelled by a call to `clear_data`.
29 /// - FAIL: an internal failure.
30 fn add_data_done(&self, result: Result<(), ErrorCode>, data: SubSlice<'static, u8>);
31
32 /// Called when the data has been added to the digest. `data` is
33 /// the `SubSliceMut` passed in the call to
34 /// `add_mut_data`, whose active slice contains the data that was
35 /// not added. On `Ok`, `data` has an active slice of size zero
36 /// (all data was added). Valid `ErrorCode` values are:
37 /// - OFF: the underlying digest engine is powered down and
38 /// cannot be used.
39 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
40 /// `run`, or `verify` operation, so the digest engine is busy
41 /// and cannot accept more data.
42 /// - SIZE: the active slice of the SubSlice has zero size.
43 /// - CANCEL: the operation was cancelled by a call to `clear_data`.
44 /// - FAIL: an internal failure.
45 fn add_mut_data_done(&self, result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>);
46}
47
48/// Implement this trait and use `set_client()` in order to receive callbacks when
49/// a digest is completed.
50///
51/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
52pub trait ClientHash<const DIGEST_LEN: usize> {
53 /// Called when a digest is computed. `digest` is the same
54 /// reference passed to `run()` to store the hash value. If
55 /// `result` is `Ok`, `digest` stores the computed hash. If
56 /// `result` is `Err`, the data stored in `digest` is undefined
57 /// and may have any value. Valid `ErrorCode` values are:
58 /// - OFF: the underlying digest engine is powered down and
59 /// cannot be used.
60 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
61 /// `run`, or `verify` operation, so the digest engine is busy
62 /// and cannot perform a hash.
63 /// - CANCEL: the operation was cancelled by a call to `clear_data`.
64 /// - NOSUPPORT: the requested digest algorithm is not supported,
65 /// or one was not requested.
66 /// - FAIL: an internal failure.
67 fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; DIGEST_LEN]);
68}
69
70/// Implement this trait and use `set_client()` in order to receive callbacks when
71/// digest verification is complete.
72///
73/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
74pub trait ClientVerify<const DIGEST_LEN: usize> {
75 /// Called when a verification is computed. `compare` is the
76 /// reference supplied to `verify()` and the data stored in
77 /// `compare` is unchanged. On `Ok` the `bool` indicates if the
78 /// computed hash matches the value in `compare`. Valid
79 /// `ErrorCode` values are:
80 /// - OFF: the underlying digest engine is powered down and
81 /// cannot be used.
82 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
83 /// `run`, or `verify` operation, so the digest engine is busy
84 /// and cannot verify a hash.
85 /// - CANCEL: the operation was cancelled by a call to `clear_data`.
86 /// - NOSUPPORT: the requested digest algorithm is not supported,
87 /// or one was not requested.
88 /// - FAIL: an internal failure.
89 fn verification_done(
90 &self,
91 result: Result<bool, ErrorCode>,
92 compare: &'static mut [u8; DIGEST_LEN],
93 );
94}
95
96pub trait Client<const DIGEST_LEN: usize>:
97 ClientData<DIGEST_LEN> + ClientHash<DIGEST_LEN> + ClientVerify<DIGEST_LEN>
98{
99}
100
101impl<
102 T: ClientData<DIGEST_LEN> + ClientHash<DIGEST_LEN> + ClientVerify<DIGEST_LEN>,
103 const DIGEST_LEN: usize,
104 > Client<DIGEST_LEN> for T
105{
106}
107
108pub trait ClientDataHash<const DIGEST_LEN: usize>:
109 ClientData<DIGEST_LEN> + ClientHash<DIGEST_LEN>
110{
111}
112impl<T: ClientData<DIGEST_LEN> + ClientHash<DIGEST_LEN>, const DIGEST_LEN: usize>
113 ClientDataHash<DIGEST_LEN> for T
114{
115}
116
117pub trait ClientDataVerify<const DIGEST_LEN: usize>:
118 ClientData<DIGEST_LEN> + ClientVerify<DIGEST_LEN>
119{
120}
121impl<T: ClientData<DIGEST_LEN> + ClientVerify<DIGEST_LEN>, const DIGEST_LEN: usize>
122 ClientDataVerify<DIGEST_LEN> for T
123{
124}
125
126/// Adding data (mutable or immutable) to a digest.
127///
128/// There are two separate methods, `add_data` for immutable data
129/// (e.g., flash) and `add_mut_data` for mutable data (e.g.,
130/// RAM). Each has its own callback, but only one operation may be in
131/// flight at any time.
132///
133/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
134pub trait DigestData<'a, const DIGEST_LEN: usize> {
135 /// Set the client instance which will handle the `add_data_done`
136 /// and `add_mut_data_done` callbacks.
137 fn set_data_client(&'a self, client: &'a dyn ClientData<DIGEST_LEN>);
138
139 /// Add data to the input of the hash function/digest. `Ok`
140 /// indicates all of the active bytes in `data` will be added.
141 /// There is no guarantee the data has been added to the digest
142 /// until the `add_data_done()` callback is called. On error the
143 /// cause of the error is returned along with the SubSlice
144 /// unchanged (it has the same range of active bytes as the call).
145 /// Valid `ErrorCode` values are:
146 /// - OFF: the underlying digest engine is powered down and
147 /// cannot be used.
148 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
149 /// `run`, or `verify` operation, so the digest engine is busy
150 /// and cannot accept more data.
151 /// - SIZE: the active slice of the SubSlice has zero size.
152 fn add_data(
153 &self,
154 data: SubSlice<'static, u8>,
155 ) -> Result<(), (ErrorCode, SubSlice<'static, u8>)>;
156
157 /// Add data to the input of the hash function/digest. `Ok`
158 /// indicates all of the active bytes in `data` will be added.
159 /// There is no guarantee the data has been added to the digest
160 /// until the `add_mut_data_done()` callback is called. On error
161 /// the cause of the error is returned along with the
162 /// SubSlice unchanged (it has the same range of active
163 /// bytes as the call). Valid `ErrorCode` values are:
164 /// - OFF: the underlying digest engine is powered down and
165 /// cannot be used.
166 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
167 /// `run`, or `verify` operation, so the digest engine is busy
168 /// and cannot accept more data.
169 /// - SIZE: the active slice of the SubSlice has zero size.
170 fn add_mut_data(
171 &self,
172 data: SubSliceMut<'static, u8>,
173 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)>;
174
175 /// Clear the keys and any other internal state. Any pending
176 /// operations terminate and issue a callback with an
177 /// `ErrorCode::CANCEL`. This call does not clear buffers passed
178 /// through `add_mut_data`, those are up to the client clear.
179 fn clear_data(&self);
180}
181
182/// Computes a digest (cryptographic hash) over data provided through a
183/// separate trait.
184///
185/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
186pub trait DigestHash<'a, const DIGEST_LEN: usize> {
187 /// Set the client instance which will receive the `hash_done()`
188 /// callback.
189 fn set_hash_client(&'a self, client: &'a dyn ClientHash<DIGEST_LEN>);
190
191 /// Compute a digest of all of the data added with `add_data` and
192 /// `add_data_mut`, storing the computed value in `digest`. The
193 /// computed value is returned in a `hash_done` callback. On
194 /// error the return value will contain a return code and the
195 /// slice passed in `digest`. Valid `ErrorCode` values are:
196 /// - OFF: the underlying digest engine is powered down and
197 /// cannot be used.
198 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
199 /// `run`, or `verify` operation, so the digest engine is busy
200 /// and cannot accept more data.
201 /// - SIZE: the active slice of the SubSlice has zero size.
202 /// - NOSUPPORT: the currently selected digest algorithm is not
203 /// supported.
204 ///
205 /// If an appropriate `set_mode*()` wasn't called before this function the
206 /// implementation should try to use a default option. In the case where
207 /// there is only one digest supported this should be used. If there is no
208 /// suitable or obvious default option, the implementation can return
209 /// `ErrorCode::NOSUPPORT`.
210 fn run(
211 &'a self,
212 digest: &'static mut [u8; DIGEST_LEN],
213 ) -> Result<(), (ErrorCode, &'static mut [u8; DIGEST_LEN])>;
214}
215
216/// Verifies a digest (cryptographic hash) over data provided through a
217/// separate trait
218///
219/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
220pub trait DigestVerify<'a, const DIGEST_LEN: usize> {
221 /// Set the client instance which will receive the `verification_done()`
222 /// callback.
223 fn set_verify_client(&'a self, client: &'a dyn ClientVerify<DIGEST_LEN>);
224
225 /// Compute a digest of all of the data added with `add_data` and
226 /// `add_data_mut` then compare it with value in `compare`. The
227 /// compare value is returned in a `verification_done` callback, along with
228 /// a boolean indicating whether it matches the computed value. On
229 /// error the return value will contain a return code and the
230 /// slice passed in `compare`. Valid `ErrorCode` values are:
231 /// - OFF: the underlying digest engine is powered down and
232 /// cannot be used.
233 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
234 /// `run`, or `verify` operation, so the digest engine is busy
235 /// and cannot accept more data.
236 /// - SIZE: the active slice of the SubSlice has zero size.
237 /// - NOSUPPORT: the currently selected digest algorithm is not
238 /// supported.
239 ///
240 /// If an appropriate `set_mode*()` wasn't called before this function the
241 /// implementation should try to use a default option. In the case where
242 /// there is only one digest supported this should be used. If there is no
243 /// suitable or obvious default option, the implementation can return
244 /// `ErrorCode::NOSUPPORT`.
245 fn verify(
246 &'a self,
247 compare: &'static mut [u8; DIGEST_LEN],
248 ) -> Result<(), (ErrorCode, &'static mut [u8; DIGEST_LEN])>;
249}
250
251/// Computes a digest (cryptographic hash) over data or performs verification.
252///
253/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
254pub trait Digest<'a, const DIGEST_LEN: usize>:
255 DigestData<'a, DIGEST_LEN> + DigestHash<'a, DIGEST_LEN> + DigestVerify<'a, DIGEST_LEN>
256{
257 /// Set the client instance which will receive `hash_done()`,
258 /// `add_data_done()` and `verification_done()` callbacks.
259 fn set_client(&'a self, client: &'a dyn Client<DIGEST_LEN>);
260}
261
262/// Computes a digest (cryptographic hash) over data.
263///
264/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
265pub trait DigestDataHash<'a, const DIGEST_LEN: usize>:
266 DigestData<'a, DIGEST_LEN> + DigestHash<'a, DIGEST_LEN>
267{
268 /// Set the client instance which will receive `hash_done()` and
269 /// `add_data_done()` callbacks.
270 fn set_client(&'a self, client: &'a dyn ClientDataHash<DIGEST_LEN>);
271}
272
273/// Verify a digest (cryptographic hash) over data.
274///
275/// 'DIGEST_LEN' is the length of the 'u8' array to store the digest output.
276pub trait DigestDataVerify<'a, const DIGEST_LEN: usize>:
277 DigestData<'a, DIGEST_LEN> + DigestVerify<'a, DIGEST_LEN>
278{
279 /// Set the client instance which will receive `verify_done()` and
280 /// `add_data_done()` callbacks.
281 fn set_client(&'a self, client: &'a dyn ClientDataVerify<DIGEST_LEN>);
282}
283
284pub trait Sha224 {
285 /// Call before adding data to perform Sha224
286 fn set_mode_sha224(&self) -> Result<(), ErrorCode>;
287}
288
289pub trait Sha256 {
290 /// Call before adding data to perform Sha256
291 fn set_mode_sha256(&self) -> Result<(), ErrorCode>;
292}
293
294pub trait Sha384 {
295 /// Call before adding data to perform Sha384
296 fn set_mode_sha384(&self) -> Result<(), ErrorCode>;
297}
298
299pub trait Sha512 {
300 /// Call before adding data to perform Sha512
301 fn set_mode_sha512(&self) -> Result<(), ErrorCode>;
302}
303
304pub trait HmacSha256 {
305 /// Call before adding data to perform HMACSha256
306 ///
307 /// The key used for the HMAC is passed to this function.
308 fn set_mode_hmacsha256(&self, key: &[u8]) -> Result<(), ErrorCode>;
309}
310
311pub trait HmacSha384 {
312 /// Call before adding data to perform HMACSha384
313 ///
314 /// The key used for the HMAC is passed to this function.
315 fn set_mode_hmacsha384(&self, key: &[u8]) -> Result<(), ErrorCode>;
316}
317
318pub trait HmacSha512 {
319 /// Call before adding data to perform HMACSha512
320 ///
321 /// The key used for the HMAC is passed to this function.
322 fn set_mode_hmacsha512(&self, key: &[u8]) -> Result<(), ErrorCode>;
323}