1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Interface for computing digests (hashes, cryptographic hashes, and
//! HMACs) over data.

use crate::utilities::leasable_buffer::SubSlice;
use crate::utilities::leasable_buffer::SubSliceMut;
use crate::ErrorCode;

/// Implement this trait and use `set_client()` in order to receive callbacks
/// when data has been added to a digest.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait ClientData<const L: usize> {
    /// Called when the data has been added to the digest. `data` is
    /// the `SubSlice` passed in the call to `add_data`, whose
    /// active slice contains the data that was not added. On `Ok`,
    /// `data` has an active slice of size zero (all data was added).
    /// Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot accept more data.
    ///  - SIZE: the active slice of the SubSlice has zero size.
    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
    ///  - FAIL: an internal failure.
    fn add_data_done(&self, result: Result<(), ErrorCode>, data: SubSlice<'static, u8>);

    /// Called when the data has been added to the digest. `data` is
    /// the `SubSliceMut` passed in the call to
    /// `add_mut_data`, whose active slice contains the data that was
    /// not added. On `Ok`, `data` has an active slice of size zero
    /// (all data was added). Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot accept more data.
    ///  - SIZE: the active slice of the SubSlice has zero size.
    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
    ///  - FAIL: an internal failure.
    fn add_mut_data_done(&self, result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>);
}

/// Implement this trait and use `set_client()` in order to receive callbacks when
/// a digest is completed.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait ClientHash<const L: usize> {
    /// Called when a digest is computed. `digest` is the same
    /// reference passed to `run()` to store the hash value. If
    /// `result` is `Ok`, `digest` stores the computed hash. If
    /// `result` is `Err`, the data stored in `digest` is undefined
    /// and may have any value. Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot perform a hash.
    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
    ///  - NOSUPPORT: the requested digest algorithm is not supported,
    ///  or one was not requested.
    ///  - FAIL: an internal failure.
    fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; L]);
}

/// Implement this trait and use `set_client()` in order to receive callbacks when
/// digest verification is complete.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait ClientVerify<const L: usize> {
    /// Called when a verification is computed.  `compare` is the
    /// reference supplied to `verify()` and the data stored in
    /// `compare` is unchanged.  On `Ok` the `bool` indicates if the
    /// computed hash matches the value in `compare`. Valid
    /// `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot verify a hash.
    ///  - CANCEL: the operation was cancelled by a call to `clear_data`.
    ///  - NOSUPPORT: the requested digest algorithm is not supported,
    ///  or one was not requested.
    ///  - FAIL: an internal failure.
    fn verification_done(&self, result: Result<bool, ErrorCode>, compare: &'static mut [u8; L]);
}

pub trait Client<const L: usize>: ClientData<L> + ClientHash<L> + ClientVerify<L> {}

impl<T: ClientData<L> + ClientHash<L> + ClientVerify<L>, const L: usize> Client<L> for T {}

pub trait ClientDataHash<const L: usize>: ClientData<L> + ClientHash<L> {}
impl<T: ClientData<L> + ClientHash<L>, const L: usize> ClientDataHash<L> for T {}

pub trait ClientDataVerify<const L: usize>: ClientData<L> + ClientVerify<L> {}
impl<T: ClientData<L> + ClientVerify<L>, const L: usize> ClientDataVerify<L> for T {}

/// Adding data (mutable or immutable) to a digest. There are two
/// separate methods, `add_data` for immutable data (e.g., flash) and
/// `add_mut_data` for mutable data (e.g., RAM). Each has its own
/// callback, but only one operation may be in flight at any time.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait DigestData<'a, const L: usize> {
    /// Set the client instance which will handle the `add_data_done`
    /// and `add_mut_data_done` callbacks.
    fn set_data_client(&'a self, client: &'a dyn ClientData<L>);

    /// Add data to the input of the hash function/digest. `Ok`
    /// indicates all of the active bytes in `data` will be added.
    /// There is no guarantee the data has been added to the digest
    /// until the `add_data_done()` callback is called.  On error the
    /// cause of the error is returned along with the SubSlice
    /// unchanged (it has the same range of active bytes as the call).
    /// Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot accept more data.
    ///  - SIZE: the active slice of the SubSlice has zero size.
    fn add_data(
        &self,
        data: SubSlice<'static, u8>,
    ) -> Result<(), (ErrorCode, SubSlice<'static, u8>)>;

    /// Add data to the input of the hash function/digest. `Ok`
    /// indicates all of the active bytes in `data` will be added.
    /// There is no guarantee the data has been added to the digest
    /// until the `add_mut_data_done()` callback is called.  On error
    /// the cause of the error is returned along with the
    /// SubSlice unchanged (it has the same range of active
    /// bytes as the call).  Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot accept more data.
    ///  - SIZE: the active slice of the SubSlice has zero size.
    fn add_mut_data(
        &self,
        data: SubSliceMut<'static, u8>,
    ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)>;

    /// Clear the keys and any other internal state. Any pending
    /// operations terminate and issue a callback with an
    /// `ErrorCode::CANCEL`. This call does not clear buffers passed
    /// through `add_mut_data`, those are up to the client clear.
    fn clear_data(&self);
}

/// Computes a digest (cryptographic hash) over data provided through a
/// separate trait.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait DigestHash<'a, const L: usize> {
    /// Set the client instance which will receive the `hash_done()`
    /// callback.
    fn set_hash_client(&'a self, client: &'a dyn ClientHash<L>);

    /// Compute a digest of all of the data added with `add_data` and
    /// `add_data_mut`, storing the computed value in `digest`.  The
    /// computed value is returned in a `hash_done` callback.  On
    /// error the return value will contain a return code and the
    /// slice passed in `digest`. Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot accept more data.
    ///  - SIZE: the active slice of the SubSlice has zero size.
    ///  - NOSUPPORT: the currently selected digest algorithm is not
    ///  supported.
    ///
    /// If an appropriate `set_mode*()` wasn't called before this function the
    /// implementation should try to use a default option. In the case where
    /// there is only one digest supported this should be used. If there is no
    /// suitable or obvious default option, the implementation can return
    /// `ErrorCode::NOSUPPORT`.
    fn run(&'a self, digest: &'static mut [u8; L])
        -> Result<(), (ErrorCode, &'static mut [u8; L])>;
}

/// Verifies a digest (cryptographic hash) over data provided through a
/// separate trait
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait DigestVerify<'a, const L: usize> {
    /// Set the client instance which will receive the `verification_done()`
    /// callback.
    fn set_verify_client(&'a self, client: &'a dyn ClientVerify<L>);

    /// Compute a digest of all of the data added with `add_data` and
    /// `add_data_mut` then compare it with value in `compare`.  The
    /// compare value is returned in a `verification_done` callback, along with
    /// a boolean indicating whether it matches the computed value. On
    /// error the return value will contain a return code and the
    /// slice passed in `compare`. Valid `ErrorCode` values are:
    ///  - OFF: the underlying digest engine is powered down and
    ///  cannot be used.
    ///  - BUSY: there is an outstanding `add_data`, `add_data_mut`,
    ///  `run`, or `verify` operation, so the digest engine is busy
    ///  and cannot accept more data.
    ///  - SIZE: the active slice of the SubSlice has zero size.
    ///  - NOSUPPORT: the currently selected digest algorithm is not
    ///  supported.
    ///
    /// If an appropriate `set_mode*()` wasn't called before this function the
    /// implementation should try to use a default option. In the case where
    /// there is only one digest supported this should be used. If there is no
    /// suitable or obvious default option, the implementation can return
    /// `ErrorCode::NOSUPPORT`.
    fn verify(
        &'a self,
        compare: &'static mut [u8; L],
    ) -> Result<(), (ErrorCode, &'static mut [u8; L])>;
}

/// Computes a digest (cryptographic hash) over data or performs verification.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait Digest<'a, const L: usize>:
    DigestData<'a, L> + DigestHash<'a, L> + DigestVerify<'a, L>
{
    /// Set the client instance which will receive `hash_done()`,
    /// `add_data_done()` and `verification_done()` callbacks.
    fn set_client(&'a self, client: &'a dyn Client<L>);
}

/// Computes a digest (cryptographic hash) over data.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait DigestDataHash<'a, const L: usize>: DigestData<'a, L> + DigestHash<'a, L> {
    /// Set the client instance which will receive `hash_done()` and
    /// `add_data_done()` callbacks.
    fn set_client(&'a self, client: &'a dyn ClientDataHash<L>);
}

/// Verify a digest (cryptographic hash) over data.
///
/// 'L' is the length of the 'u8' array to store the digest output.
pub trait DigestDataVerify<'a, const L: usize>: DigestData<'a, L> + DigestVerify<'a, L> {
    /// Set the client instance which will receive `verify_done()` and
    /// `add_data_done()` callbacks.
    fn set_client(&'a self, client: &'a dyn ClientDataVerify<L>);
}

pub trait Sha224 {
    /// Call before adding data to perform Sha224
    fn set_mode_sha224(&self) -> Result<(), ErrorCode>;
}

pub trait Sha256 {
    /// Call before adding data to perform Sha256
    fn set_mode_sha256(&self) -> Result<(), ErrorCode>;
}

pub trait Sha384 {
    /// Call before adding data to perform Sha384
    fn set_mode_sha384(&self) -> Result<(), ErrorCode>;
}

pub trait Sha512 {
    /// Call before adding data to perform Sha512
    fn set_mode_sha512(&self) -> Result<(), ErrorCode>;
}

pub trait HmacSha256 {
    /// Call before adding data to perform HMACSha256
    ///
    /// The key used for the HMAC is passed to this function.
    fn set_mode_hmacsha256(&self, key: &[u8]) -> Result<(), ErrorCode>;
}

pub trait HmacSha384 {
    /// Call before adding data to perform HMACSha384
    ///
    /// The key used for the HMAC is passed to this function.
    fn set_mode_hmacsha384(&self, key: &[u8]) -> Result<(), ErrorCode>;
}

pub trait HmacSha512 {
    /// Call before adding data to perform HMACSha512
    ///
    /// The key used for the HMAC is passed to this function.
    fn set_mode_hmacsha512(&self, key: &[u8]) -> Result<(), ErrorCode>;
}