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>;
}