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/// 'L' is the length of the 'u8' array to store the digest output.
16pub trait ClientData<const L: 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/// 'L' is the length of the 'u8' array to store the digest output.
52pub trait ClientHash<const L: 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; L]);
68}
69
70/// Implement this trait and use `set_client()` in order to receive callbacks when
71/// digest verification is complete.
72///
73/// 'L' is the length of the 'u8' array to store the digest output.
74pub trait ClientVerify<const L: 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(&self, result: Result<bool, ErrorCode>, compare: &'static mut [u8; L]);
90}
91
92pub trait Client<const L: usize>: ClientData<L> + ClientHash<L> + ClientVerify<L> {}
93
94impl<T: ClientData<L> + ClientHash<L> + ClientVerify<L>, const L: usize> Client<L> for T {}
95
96pub trait ClientDataHash<const L: usize>: ClientData<L> + ClientHash<L> {}
97impl<T: ClientData<L> + ClientHash<L>, const L: usize> ClientDataHash<L> for T {}
98
99pub trait ClientDataVerify<const L: usize>: ClientData<L> + ClientVerify<L> {}
100impl<T: ClientData<L> + ClientVerify<L>, const L: usize> ClientDataVerify<L> for T {}
101
102/// Adding data (mutable or immutable) to a digest.
103///
104/// There are two separate methods, `add_data` for immutable data
105/// (e.g., flash) and `add_mut_data` for mutable data (e.g.,
106/// RAM). Each has its own callback, but only one operation may be in
107/// flight at any time.
108///
109/// 'L' is the length of the 'u8' array to store the digest output.
110pub trait DigestData<'a, const L: usize> {
111 /// Set the client instance which will handle the `add_data_done`
112 /// and `add_mut_data_done` callbacks.
113 fn set_data_client(&'a self, client: &'a dyn ClientData<L>);
114
115 /// Add data to the input of the hash function/digest. `Ok`
116 /// indicates all of the active bytes in `data` will be added.
117 /// There is no guarantee the data has been added to the digest
118 /// until the `add_data_done()` callback is called. On error the
119 /// cause of the error is returned along with the SubSlice
120 /// unchanged (it has the same range of active bytes as the call).
121 /// Valid `ErrorCode` values are:
122 /// - OFF: the underlying digest engine is powered down and
123 /// cannot be used.
124 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
125 /// `run`, or `verify` operation, so the digest engine is busy
126 /// and cannot accept more data.
127 /// - SIZE: the active slice of the SubSlice has zero size.
128 fn add_data(
129 &self,
130 data: SubSlice<'static, u8>,
131 ) -> Result<(), (ErrorCode, SubSlice<'static, u8>)>;
132
133 /// Add data to the input of the hash function/digest. `Ok`
134 /// indicates all of the active bytes in `data` will be added.
135 /// There is no guarantee the data has been added to the digest
136 /// until the `add_mut_data_done()` callback is called. On error
137 /// the cause of the error is returned along with the
138 /// SubSlice unchanged (it has the same range of active
139 /// bytes as the call). Valid `ErrorCode` values are:
140 /// - OFF: the underlying digest engine is powered down and
141 /// cannot be used.
142 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
143 /// `run`, or `verify` operation, so the digest engine is busy
144 /// and cannot accept more data.
145 /// - SIZE: the active slice of the SubSlice has zero size.
146 fn add_mut_data(
147 &self,
148 data: SubSliceMut<'static, u8>,
149 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)>;
150
151 /// Clear the keys and any other internal state. Any pending
152 /// operations terminate and issue a callback with an
153 /// `ErrorCode::CANCEL`. This call does not clear buffers passed
154 /// through `add_mut_data`, those are up to the client clear.
155 fn clear_data(&self);
156}
157
158/// Computes a digest (cryptographic hash) over data provided through a
159/// separate trait.
160///
161/// 'L' is the length of the 'u8' array to store the digest output.
162pub trait DigestHash<'a, const L: usize> {
163 /// Set the client instance which will receive the `hash_done()`
164 /// callback.
165 fn set_hash_client(&'a self, client: &'a dyn ClientHash<L>);
166
167 /// Compute a digest of all of the data added with `add_data` and
168 /// `add_data_mut`, storing the computed value in `digest`. The
169 /// computed value is returned in a `hash_done` callback. On
170 /// error the return value will contain a return code and the
171 /// slice passed in `digest`. Valid `ErrorCode` values are:
172 /// - OFF: the underlying digest engine is powered down and
173 /// cannot be used.
174 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
175 /// `run`, or `verify` operation, so the digest engine is busy
176 /// and cannot accept more data.
177 /// - SIZE: the active slice of the SubSlice has zero size.
178 /// - NOSUPPORT: the currently selected digest algorithm is not
179 /// supported.
180 ///
181 /// If an appropriate `set_mode*()` wasn't called before this function the
182 /// implementation should try to use a default option. In the case where
183 /// there is only one digest supported this should be used. If there is no
184 /// suitable or obvious default option, the implementation can return
185 /// `ErrorCode::NOSUPPORT`.
186 fn run(&'a self, digest: &'static mut [u8; L])
187 -> Result<(), (ErrorCode, &'static mut [u8; L])>;
188}
189
190/// Verifies a digest (cryptographic hash) over data provided through a
191/// separate trait
192///
193/// 'L' is the length of the 'u8' array to store the digest output.
194pub trait DigestVerify<'a, const L: usize> {
195 /// Set the client instance which will receive the `verification_done()`
196 /// callback.
197 fn set_verify_client(&'a self, client: &'a dyn ClientVerify<L>);
198
199 /// Compute a digest of all of the data added with `add_data` and
200 /// `add_data_mut` then compare it with value in `compare`. The
201 /// compare value is returned in a `verification_done` callback, along with
202 /// a boolean indicating whether it matches the computed value. On
203 /// error the return value will contain a return code and the
204 /// slice passed in `compare`. Valid `ErrorCode` values are:
205 /// - OFF: the underlying digest engine is powered down and
206 /// cannot be used.
207 /// - BUSY: there is an outstanding `add_data`, `add_data_mut`,
208 /// `run`, or `verify` operation, so the digest engine is busy
209 /// and cannot accept more data.
210 /// - SIZE: the active slice of the SubSlice has zero size.
211 /// - NOSUPPORT: the currently selected digest algorithm is not
212 /// supported.
213 ///
214 /// If an appropriate `set_mode*()` wasn't called before this function the
215 /// implementation should try to use a default option. In the case where
216 /// there is only one digest supported this should be used. If there is no
217 /// suitable or obvious default option, the implementation can return
218 /// `ErrorCode::NOSUPPORT`.
219 fn verify(
220 &'a self,
221 compare: &'static mut [u8; L],
222 ) -> Result<(), (ErrorCode, &'static mut [u8; L])>;
223}
224
225/// Computes a digest (cryptographic hash) over data or performs verification.
226///
227/// 'L' is the length of the 'u8' array to store the digest output.
228pub trait Digest<'a, const L: usize>:
229 DigestData<'a, L> + DigestHash<'a, L> + DigestVerify<'a, L>
230{
231 /// Set the client instance which will receive `hash_done()`,
232 /// `add_data_done()` and `verification_done()` callbacks.
233 fn set_client(&'a self, client: &'a dyn Client<L>);
234}
235
236/// Computes a digest (cryptographic hash) over data.
237///
238/// 'L' is the length of the 'u8' array to store the digest output.
239pub trait DigestDataHash<'a, const L: usize>: DigestData<'a, L> + DigestHash<'a, L> {
240 /// Set the client instance which will receive `hash_done()` and
241 /// `add_data_done()` callbacks.
242 fn set_client(&'a self, client: &'a dyn ClientDataHash<L>);
243}
244
245/// Verify a digest (cryptographic hash) over data.
246///
247/// 'L' is the length of the 'u8' array to store the digest output.
248pub trait DigestDataVerify<'a, const L: usize>: DigestData<'a, L> + DigestVerify<'a, L> {
249 /// Set the client instance which will receive `verify_done()` and
250 /// `add_data_done()` callbacks.
251 fn set_client(&'a self, client: &'a dyn ClientDataVerify<L>);
252}
253
254pub trait Sha224 {
255 /// Call before adding data to perform Sha224
256 fn set_mode_sha224(&self) -> Result<(), ErrorCode>;
257}
258
259pub trait Sha256 {
260 /// Call before adding data to perform Sha256
261 fn set_mode_sha256(&self) -> Result<(), ErrorCode>;
262}
263
264pub trait Sha384 {
265 /// Call before adding data to perform Sha384
266 fn set_mode_sha384(&self) -> Result<(), ErrorCode>;
267}
268
269pub trait Sha512 {
270 /// Call before adding data to perform Sha512
271 fn set_mode_sha512(&self) -> Result<(), ErrorCode>;
272}
273
274pub trait HmacSha256 {
275 /// Call before adding data to perform HMACSha256
276 ///
277 /// The key used for the HMAC is passed to this function.
278 fn set_mode_hmacsha256(&self, key: &[u8]) -> Result<(), ErrorCode>;
279}
280
281pub trait HmacSha384 {
282 /// Call before adding data to perform HMACSha384
283 ///
284 /// The key used for the HMAC is passed to this function.
285 fn set_mode_hmacsha384(&self, key: &[u8]) -> Result<(), ErrorCode>;
286}
287
288pub trait HmacSha512 {
289 /// Call before adding data to perform HMACSha512
290 ///
291 /// The key used for the HMAC is passed to this function.
292 fn set_mode_hmacsha512(&self, key: &[u8]) -> Result<(), ErrorCode>;
293}