capsules_extra/hmac_sha256.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 2023.
4
5//! Software implementation of HMAC-SHA256.
6
7use core::cell::Cell;
8
9use kernel::hil;
10use kernel::hil::digest::DigestData;
11use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
12use kernel::utilities::leasable_buffer::SubSlice;
13use kernel::utilities::leasable_buffer::SubSliceMut;
14use kernel::utilities::leasable_buffer::SubSliceMutImmut;
15use kernel::ErrorCode;
16
17#[derive(Clone, Copy, PartialEq)]
18pub enum State {
19 Idle,
20 InnerHashAddKeyPending,
21 InnerHashAddKey,
22 InnerHashAddData,
23 InnerHash,
24 OuterHashAddKey,
25 OuterHashAddHash,
26 OuterHash,
27}
28
29#[derive(Copy, Clone)]
30pub enum RunMode {
31 Hash,
32 Verify,
33}
34
35/// Value to XOR the key with on the inner hash.
36const INNER_PAD_BYTE: u8 = 0x36;
37/// Value to XOR the key with on the outer hash.
38const OUTER_PAD_BYTE: u8 = 0x5c;
39
40const SHA_BLOCK_LEN_BYTES: usize = 64;
41const SHA_256_OUTPUT_LEN_BYTES: usize = 32;
42
43pub struct HmacSha256Software<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> {
44 /// SHA256 hasher implementation.
45 sha256: &'a S,
46 /// The current operation for the internal state machine in this capsule.
47 state: Cell<State>,
48 /// The current mode of operation as requested by a call to either
49 /// [`DigestHash::run`](kernel::hil::digest::DigestHash::run) or
50 /// [`DigestVerify::verify`](kernel::hil::digest::DigestVerify::verify).
51 mode: Cell<RunMode>,
52 /// Location to store incoming temporarily before we are able to pass it to
53 /// the hasher.
54 input_data: OptionalCell<SubSliceMutImmut<'static, u8>>,
55 /// Static buffer to store the key and to pass to the hasher. This must be
56 /// at least `SHA_BLOCK_LEN_BYTES` bytes.
57 data_buffer: TakeCell<'static, [u8]>,
58 /// Storage buffer to keep a copy of the key. This allows us to keep it
59 /// persistent if the user wants to do multiple HMACs with the same key.
60 key_buffer: MapCell<[u8; SHA_BLOCK_LEN_BYTES]>,
61 /// Holding cell for the output digest buffer while we calculate the HMAC.
62 digest_buffer: MapCell<&'static mut [u8; 32]>,
63 /// Buffer-slot used for a _verify_ operation. When not active, this
64 /// contains a buffer to place the current digest in. On a call to `verify`,
65 /// where the digest to compare to is provided in another buffer, this
66 /// buffer is swapped into this TakeCell. When the operation completes, we
67 /// swap them back and compare:
68 verify_buffer: MapCell<&'static mut [u8; 32]>,
69 /// Clients for callbacks.
70 // error[E0658]: cannot cast `dyn kernel::hil::digest::Client<32>` to `dyn ClientData<32>`, trait upcasting coercion is experimental
71 // data_client: OptionalCell<&'a dyn hil::digest::ClientData<SHA_256_OUTPUT_LEN_BYTES>>,
72 // hash_client: OptionalCell<&'a dyn hil::digest::ClientHash<SHA_256_OUTPUT_LEN_BYTES>>,
73 // verify_client: OptionalCell<&'a dyn hil::digest::ClientVerify<SHA_256_OUTPUT_LEN_BYTES>>,
74 client: OptionalCell<&'a dyn hil::digest::Client<SHA_256_OUTPUT_LEN_BYTES>>,
75}
76
77impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> HmacSha256Software<'a, S> {
78 pub fn new(
79 sha256: &'a S,
80 data_buffer: &'static mut [u8],
81 verify_buffer: &'static mut [u8; 32],
82 ) -> Self {
83 Self {
84 sha256,
85 state: Cell::new(State::Idle),
86 mode: Cell::new(RunMode::Hash),
87 input_data: OptionalCell::empty(),
88 data_buffer: TakeCell::new(data_buffer),
89 key_buffer: MapCell::new([0; SHA_BLOCK_LEN_BYTES]),
90 digest_buffer: MapCell::empty(),
91 verify_buffer: MapCell::new(verify_buffer),
92 // data_client: OptionalCell::empty(),
93 // hash_client: OptionalCell::empty(),
94 // verify_client: OptionalCell::empty(),
95 client: OptionalCell::empty(),
96 }
97 }
98}
99
100impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>>
101 hil::digest::DigestData<'a, 32> for HmacSha256Software<'a, S>
102{
103 fn add_data(
104 &self,
105 data: SubSlice<'static, u8>,
106 ) -> Result<(), (ErrorCode, SubSlice<'static, u8>)> {
107 match self.state.get() {
108 State::InnerHashAddKeyPending => {
109 // We need to write the key before we write the data.
110 if let Some(data_buf) = self.data_buffer.take() {
111 self.key_buffer.map(|key_buf| {
112 // Copy the key XOR with inner pad (0x36).
113 for i in 0..64 {
114 data_buf[i] = key_buf[i] ^ INNER_PAD_BYTE;
115 }
116 });
117
118 let mut lease_buf = SubSliceMut::new(data_buf);
119 lease_buf.slice(0..64);
120
121 match self.sha256.add_mut_data(lease_buf) {
122 Ok(()) => {
123 self.state.set(State::InnerHashAddKey);
124 // Save the incoming data to add to the hasher
125 // on the next iteration.
126 self.input_data.set(SubSliceMutImmut::Immutable(data));
127 Ok(())
128 }
129 Err((e, leased_data_buf)) => {
130 self.data_buffer.replace(leased_data_buf.take());
131 Err((e, data))
132 }
133 }
134 } else {
135 Err((ErrorCode::BUSY, data))
136 }
137 }
138
139 State::InnerHashAddData => {
140 // In this state the hasher is ready to take more input data so
141 // we can provide more input data. This is the only state after
142 // setting the key we can accept new data in.
143 self.sha256.add_data(data)
144 }
145
146 State::Idle => {
147 // We need a key before we can accept data, so we must return
148 // error here. `OFF` is the closest error to this issue so we
149 // return that.
150 Err((ErrorCode::OFF, data))
151 }
152
153 _ => {
154 // Any other state we cannot accept new data.
155 Err((ErrorCode::BUSY, data))
156 }
157 }
158 }
159
160 fn add_mut_data(
161 &self,
162 data: SubSliceMut<'static, u8>,
163 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)> {
164 match self.state.get() {
165 State::InnerHashAddKeyPending => {
166 // We need to write the key before we write the data.
167
168 if let Some(data_buf) = self.data_buffer.take() {
169 // Copy the key XOR with inner pad (0x36).
170 self.key_buffer.map(|key_buf| {
171 // Copy the key XOR with inner pad (0x36).
172 for i in 0..64 {
173 data_buf[i] = key_buf[i] ^ INNER_PAD_BYTE;
174 }
175 });
176
177 let mut lease_buf = SubSliceMut::new(data_buf);
178 lease_buf.slice(0..64);
179
180 match self.sha256.add_mut_data(lease_buf) {
181 Ok(()) => {
182 self.state.set(State::InnerHashAddKey);
183 // Save the incoming data to add to the hasher
184 // on the next iteration.
185 self.input_data.set(SubSliceMutImmut::Mutable(data));
186 Ok(())
187 }
188 Err((e, leased_data_buf)) => {
189 self.data_buffer.replace(leased_data_buf.take());
190 Err((e, data))
191 }
192 }
193 } else {
194 Err((ErrorCode::BUSY, data))
195 }
196 }
197
198 State::InnerHashAddData => {
199 // In this state the hasher is ready to take more input data so
200 // we can provide more input data. This is the only state after
201 // setting the key we can accept new data in.
202 self.sha256.add_mut_data(data)
203 }
204
205 State::Idle => {
206 // We need a key before we can accept data, so we must return
207 // error here. `OFF` is the closest error to this issue so we
208 // return that.
209 Err((ErrorCode::OFF, data))
210 }
211
212 _ => {
213 // Any other state we cannot accept new data.
214 Err((ErrorCode::BUSY, data))
215 }
216 }
217 }
218
219 fn clear_data(&self) {
220 self.state.set(State::Idle);
221 self.sha256.clear_data();
222 }
223
224 fn set_data_client(&'a self, _client: &'a dyn hil::digest::ClientData<32>) {
225 // self.data_client.set(client);
226 unimplemented!()
227 }
228}
229
230impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>>
231 hil::digest::DigestHash<'a, 32> for HmacSha256Software<'a, S>
232{
233 fn run(
234 &'a self,
235 digest: &'static mut [u8; 32],
236 ) -> Result<(), (ErrorCode, &'static mut [u8; 32])> {
237 // User called run, we start with the inner hash.
238 self.state.set(State::InnerHash);
239 self.mode.set(RunMode::Hash);
240 self.sha256.run(digest)
241 }
242
243 fn set_hash_client(&'a self, _client: &'a dyn hil::digest::ClientHash<32>) {
244 // self.hash_client.set(client);
245 unimplemented!()
246 }
247}
248
249impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>>
250 hil::digest::DigestVerify<'a, 32> for HmacSha256Software<'a, S>
251{
252 fn verify(
253 &'a self,
254 compare: &'static mut [u8; 32],
255 ) -> Result<(), (ErrorCode, &'static mut [u8; 32])> {
256 // User called verify, we start with the inner hash.
257 self.state.set(State::InnerHash);
258 self.mode.set(RunMode::Verify);
259
260 // Swap the `compare` buffer into `self.verify_buffer`, and use that to
261 // perform the actual digest calculation:
262 let digest = self.verify_buffer.replace(compare).unwrap();
263 self.sha256.run(digest)
264 }
265
266 fn set_verify_client(&'a self, _client: &'a dyn hil::digest::ClientVerify<32>) {
267 // self.verify_client.set(client);
268 unimplemented!()
269 }
270}
271
272impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>>
273 hil::digest::DigestDataHash<'a, 32> for HmacSha256Software<'a, S>
274{
275 fn set_client(&'a self, _client: &'a dyn hil::digest::ClientDataHash<32>) {
276 // self.data_client.set(client);
277 // self.hash_client.set(client);
278 unimplemented!()
279 }
280}
281
282impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::Digest<'a, 32>
283 for HmacSha256Software<'a, S>
284{
285 fn set_client(&'a self, client: &'a dyn hil::digest::Client<32>) {
286 // self.data_client.set(client);
287 // self.hash_client.set(client);
288 // self.verify_client.set(client);
289 self.client.set(client);
290 }
291}
292
293impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::ClientData<32>
294 for HmacSha256Software<'a, S>
295{
296 fn add_data_done(&self, result: Result<(), ErrorCode>, data: SubSlice<'static, u8>) {
297 // This callback is only used for the user to pass in additional data
298 // for the HMAC, we do not use `add_data()` internally in this capsule
299 // so we can just directly issue the callback.
300 // self.data_client.map(|client| {
301 self.client.map(|client| {
302 client.add_data_done(result, data);
303 });
304 }
305
306 fn add_mut_data_done(&self, result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>) {
307 if result.is_err() {
308 // self.data_client.map(|client| {
309 self.client.map(|client| {
310 client.add_mut_data_done(result, data);
311 });
312 } else {
313 match self.state.get() {
314 State::InnerHashAddKey => {
315 self.data_buffer.replace(data.take());
316
317 // We just added the key, so we can now add the stored data.
318 self.input_data.take().map(|in_data| match in_data {
319 SubSliceMutImmut::Mutable(buffer) => {
320 match self.sha256.add_mut_data(buffer) {
321 Ok(()) => {
322 self.state.set(State::InnerHashAddData);
323 }
324 Err((e, leased_data_buf)) => {
325 self.clear_data();
326 // self.data_client.map(|c| {
327 self.client.map(|c| {
328 c.add_mut_data_done(Err(e), leased_data_buf);
329 });
330 }
331 }
332 }
333 SubSliceMutImmut::Immutable(buffer) => match self.sha256.add_data(buffer) {
334 Ok(()) => {
335 self.state.set(State::InnerHashAddData);
336 }
337 Err((e, leased_data_buf)) => {
338 self.clear_data();
339 self.client.map(|c| {
340 c.add_data_done(Err(e), leased_data_buf);
341 });
342 }
343 },
344 });
345 }
346 State::OuterHashAddKey => {
347 // We just added the key, now we add the result of the first
348 // hash.
349 self.digest_buffer.take().map(|digest_buf| {
350 let data_buf = data.take();
351
352 // Copy the digest result into our data buffer. We must
353 // use our data buffer because it does not have a fixed
354 // size and we can use it with `SubSliceMut`.
355 data_buf[..32].copy_from_slice(&digest_buf[..32]);
356
357 let mut lease_buf = SubSliceMut::new(data_buf);
358 lease_buf.slice(0..32);
359
360 match self.sha256.add_mut_data(lease_buf) {
361 Ok(()) => {
362 self.state.set(State::OuterHashAddHash);
363 self.digest_buffer.replace(digest_buf);
364 }
365 Err((e, leased_data_buf)) => {
366 self.data_buffer.replace(leased_data_buf.take());
367 self.clear_data();
368 // self.data_client.map(|c| {
369 self.client.map(|c| {
370 c.hash_done(Err(e), digest_buf);
371 });
372 }
373 }
374 });
375 }
376 State::OuterHashAddHash => {
377 // We've now added both the key and the result of the first
378 // hash, so we can run the second hash to get our HMAC.
379 self.data_buffer.replace(data.take());
380
381 self.digest_buffer
382 .take()
383 .map(|digest_buf| match self.sha256.run(digest_buf) {
384 Ok(()) => {
385 self.state.set(State::OuterHash);
386 }
387 Err((e, digest)) => {
388 self.clear_data();
389 // self.data_client.map(|c| {
390 self.client.map(|c| {
391 c.hash_done(Err(e), digest);
392 });
393 }
394 });
395 }
396 _ => {
397 // In other states, we can just issue the callback like
398 // normal.
399 // self.data_client.map(|client| {
400 self.client.map(|client| {
401 client.add_mut_data_done(Ok(()), data);
402 });
403 }
404 }
405 }
406 }
407}
408
409impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::ClientHash<32>
410 for HmacSha256Software<'a, S>
411{
412 fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; 32]) {
413 let hash_done_error = |error: Result<(), ErrorCode>,
414 error_digest: &'static mut [u8; 32]| {
415 match self.mode.get() {
416 RunMode::Hash => {
417 // self.hash_client.map(|c| {
418 self.client.map(|c| {
419 c.hash_done(error, error_digest);
420 })
421 }
422 RunMode::Verify => {
423 // Also swap back the verify_buffer, and return the original
424 // buffer to the client:
425 let compare = self.verify_buffer.replace(error_digest).unwrap();
426 // self.verify_client.map(|c| {
427 self.client.map(|c| {
428 // Convert to Result<bool, ErrorCode>
429 c.verification_done(error.map(|()| false), compare);
430 })
431 }
432 }
433 };
434
435 if result.is_err() {
436 // If hashing fails, we have to propagate that error up with a
437 // callback.
438 self.clear_data();
439 hash_done_error(result, digest);
440 } else {
441 match self.state.get() {
442 State::InnerHash => {
443 // Completed inner hash, now work on outer hash.
444 self.sha256.clear_data();
445
446 self.data_buffer.take().map(|data_buf| {
447 self.key_buffer.map(|key_buf| {
448 // Copy the key XOR with outer pad (0x5c).
449 for i in 0..64 {
450 data_buf[i] = key_buf[i] ^ OUTER_PAD_BYTE;
451 }
452 });
453
454 let mut lease_buf = SubSliceMut::new(data_buf);
455 lease_buf.slice(0..64);
456
457 match self.sha256.add_mut_data(lease_buf) {
458 Ok(()) => {
459 self.state.set(State::OuterHashAddKey);
460 self.digest_buffer.replace(digest);
461 }
462 Err((e, leased_data_buf)) => {
463 // If we cannot add data, we need to replace the
464 // buffer and issue a callback with an error.
465 self.data_buffer.replace(leased_data_buf.take());
466 self.clear_data();
467 hash_done_error(Err(e), digest);
468 }
469 }
470 });
471 }
472
473 State::OuterHash => {
474 match self.mode.get() {
475 RunMode::Hash => {
476 // self.hash_client.map(|c| {
477 self.client.map(|c| {
478 c.hash_done(Ok(()), digest);
479 });
480 }
481
482 RunMode::Verify => {
483 let compare = self.verify_buffer.take().unwrap();
484 let res = compare == digest;
485 self.verify_buffer.replace(digest);
486 // self.verify_client.map(|c| {
487 self.client.map(|c| {
488 c.verification_done(Ok(res), compare);
489 });
490 }
491 }
492 }
493 _ => {}
494 }
495 }
496 }
497}
498
499impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::ClientVerify<32>
500 for HmacSha256Software<'a, S>
501{
502 fn verification_done(&self, _result: Result<bool, ErrorCode>, _compare: &'static mut [u8; 32]) {
503 }
504}
505
506impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::HmacSha256
507 for HmacSha256Software<'a, S>
508{
509 fn set_mode_hmacsha256(&self, key: &[u8]) -> Result<(), ErrorCode> {
510 if key.len() > SHA_BLOCK_LEN_BYTES {
511 // Key size must be no longer than the internal block size (which is
512 // 64 bytes).
513 Err(ErrorCode::SIZE)
514 } else {
515 self.key_buffer.map_or(Err(ErrorCode::FAIL), |key_buf| {
516 // Save the key in our key buffer.
517 for i in 0..64 {
518 key_buf[i] = *key.get(i).unwrap_or(&0);
519 }
520
521 // Make sure our hasher is in the expected mode.
522 self.sha256.set_mode_sha256()?;
523
524 // Mark that we have the key pending which we can add once we
525 // get additional data to add. We can't add the key in the
526 // underlying hash now because we don't have a callback to use,
527 // so we have to just store the key. We need to use the key
528 // again anyway, so this is ok.
529 self.state.set(State::InnerHashAddKeyPending);
530 Ok(())
531 })
532 }
533 }
534}
535
536impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::HmacSha384
537 for HmacSha256Software<'a, S>
538{
539 fn set_mode_hmacsha384(&self, _key: &[u8]) -> Result<(), ErrorCode> {
540 Err(ErrorCode::NOSUPPORT)
541 }
542}
543
544impl<'a, S: hil::digest::Sha256 + hil::digest::DigestDataHash<'a, 32>> hil::digest::HmacSha512
545 for HmacSha256Software<'a, S>
546{
547 fn set_mode_hmacsha512(&self, _key: &[u8]) -> Result<(), ErrorCode> {
548 Err(ErrorCode::NOSUPPORT)
549 }
550}