Skip to main content

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