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}