lowrisc/
hmac.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//! SHA256 HMAC (Hash-based Message Authentication Code).
6
7use core::cell::Cell;
8use core::ops::Index;
9use kernel::hil;
10use kernel::hil::digest::{self, DigestData, DigestHash};
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::leasable_buffer::SubSlice;
13use kernel::utilities::leasable_buffer::SubSliceMut;
14use kernel::utilities::leasable_buffer::SubSliceMutImmut;
15use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
16use kernel::utilities::registers::{
17    register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
18};
19use kernel::utilities::StaticRef;
20use kernel::ErrorCode;
21
22register_structs! {
23    pub HmacRegisters {
24        (0x00 => intr_state: ReadWrite<u32, INTR_STATE::Register>),
25        (0x04 => intr_enable: ReadWrite<u32, INTR_ENABLE::Register>),
26        (0x08 => intr_test: ReadWrite<u32, INTR_TEST::Register>),
27        (0x0C => alert_test: ReadWrite<u32>),
28        (0x10 => cfg: ReadWrite<u32, CFG::Register>),
29        (0x14 => cmd: ReadWrite<u32, CMD::Register>),
30        (0x18 => status: ReadOnly<u32, STATUS::Register>),
31        (0x1C => err_code: ReadOnly<u32>),
32        (0x20 => wipe_secret: WriteOnly<u32>),
33        (0x24 => key: [WriteOnly<u32>; 8]),
34        (0x44 => digest: [ReadOnly<u32>; 8]),
35        (0x64 => msg_length_lower: ReadOnly<u32>),
36        (0x68 => msg_length_upper: ReadOnly<u32>),
37        (0x6C => _reserved0),
38        (0x800 => msg_fifo: WriteOnly<u32>),
39        (0x804 => msg_fifo_8: WriteOnly<u8>),
40        (0x805 => _reserved1),
41        (0x808 => @END),
42    }
43}
44
45register_bitfields![u32,
46    INTR_STATE [
47        HMAC_DONE OFFSET(0) NUMBITS(1) [],
48        FIFO_EMPTY OFFSET(1) NUMBITS(1) [],
49        HMAC_ERR OFFSET(2) NUMBITS(1) []
50    ],
51    INTR_ENABLE [
52        HMAC_DONE OFFSET(0) NUMBITS(1) [],
53        FIFO_EMPTY OFFSET(1) NUMBITS(1) [],
54        HMAC_ERR OFFSET(2) NUMBITS(1) []
55    ],
56    INTR_TEST [
57        HMAC_DONE OFFSET(0) NUMBITS(1) [],
58        FIFO_EMPTY OFFSET(1) NUMBITS(1) [],
59        HMAC_ERR OFFSET(2) NUMBITS(1) []
60    ],
61    CFG [
62        HMAC_EN OFFSET(0) NUMBITS(1) [],
63        SHA_EN OFFSET(1) NUMBITS(1) [],
64        ENDIAN_SWAP OFFSET(2) NUMBITS(1) [],
65        DIGEST_SWAP OFFSET(3) NUMBITS(1) []
66    ],
67    CMD [
68        START OFFSET(0) NUMBITS(1) [],
69        PROCESS OFFSET(1) NUMBITS(1) []
70    ],
71    STATUS [
72        FIFO_EMPTY OFFSET(0) NUMBITS(1) [],
73        FIFO_FULL OFFSET(1) NUMBITS(1) [],
74        FIFO_DEPTH OFFSET(4) NUMBITS(5) []
75    ]
76];
77
78pub struct Hmac<'a> {
79    registers: StaticRef<HmacRegisters>,
80    client: OptionalCell<&'a dyn hil::digest::Client<32>>,
81    data: Cell<Option<SubSliceMutImmut<'static, u8>>>,
82    verify: Cell<bool>,
83    digest: Cell<Option<&'static mut [u8; 32]>>,
84    cancelled: Cell<bool>,
85    busy: Cell<bool>,
86}
87
88impl Hmac<'_> {
89    pub fn new(base: StaticRef<HmacRegisters>) -> Self {
90        Hmac {
91            registers: base,
92            client: OptionalCell::empty(),
93            data: Cell::new(None),
94            verify: Cell::new(false),
95            digest: Cell::new(None),
96            cancelled: Cell::new(false),
97            busy: Cell::new(false),
98        }
99    }
100
101    fn process(&self, data: &dyn Index<usize, Output = u8>, count: usize) -> usize {
102        let regs = self.registers;
103        for i in 0..(count / 4) {
104            if regs.status.is_set(STATUS::FIFO_FULL) {
105                return i * 4;
106            }
107
108            let data_idx = i * 4;
109
110            let mut d = (data[data_idx + 3] as u32) << 0;
111            d |= (data[data_idx + 2] as u32) << 8;
112            d |= (data[data_idx + 1] as u32) << 16;
113            d |= (data[data_idx + 0] as u32) << 24;
114
115            regs.msg_fifo.set(d);
116        }
117
118        if (count % 4) != 0 {
119            for i in 0..(count % 4) {
120                let data_idx = (count - (count % 4)) + i;
121                regs.msg_fifo_8.set(data[data_idx]);
122            }
123        }
124        count
125    }
126
127    // Return true if processing more data, false if the buffer
128    // is completely processed.
129    fn data_progress(&self) -> bool {
130        self.data.take().is_some_and(|buf| match buf {
131            SubSliceMutImmut::Immutable(mut b) => {
132                if b.len() == 0 {
133                    self.data.set(Some(SubSliceMutImmut::Immutable(b)));
134                    false
135                } else {
136                    let count = self.process(&b, b.len());
137                    b.slice(count..);
138                    self.data.set(Some(SubSliceMutImmut::Immutable(b)));
139                    true
140                }
141            }
142            SubSliceMutImmut::Mutable(mut b) => {
143                if b.len() == 0 {
144                    self.data.set(Some(SubSliceMutImmut::Mutable(b)));
145                    false
146                } else {
147                    let count = self.process(&b, b.len());
148                    b.slice(count..);
149                    self.data.set(Some(SubSliceMutImmut::Mutable(b)));
150                    true
151                }
152            }
153        })
154    }
155
156    pub fn handle_interrupt(&self) {
157        let regs = self.registers;
158        let intrs = regs.intr_state.extract();
159        regs.intr_enable.modify(
160            INTR_ENABLE::HMAC_DONE::CLEAR
161                + INTR_ENABLE::FIFO_EMPTY::CLEAR
162                + INTR_ENABLE::HMAC_ERR::CLEAR,
163        );
164        self.busy.set(false);
165        if intrs.is_set(INTR_STATE::HMAC_DONE) {
166            self.client.map(|client| {
167                let digest = self.digest.take().unwrap();
168
169                regs.intr_state.modify(INTR_STATE::HMAC_DONE::SET);
170
171                if self.verify.get() {
172                    let mut equal = true;
173
174                    for i in 0..8 {
175                        let d = regs.digest[i].get().to_ne_bytes();
176
177                        let idx = i * 4;
178
179                        if digest[idx + 0] != d[0]
180                            || digest[idx + 1] != d[1]
181                            || digest[idx + 2] != d[2]
182                            || digest[idx + 3] != d[3]
183                        {
184                            equal = false;
185                        }
186                    }
187
188                    if self.cancelled.get() {
189                        self.clear_data();
190                        self.cancelled.set(false);
191                        client.verification_done(Err(ErrorCode::CANCEL), digest);
192                    } else {
193                        self.clear_data();
194                        self.cancelled.set(false);
195                        client.verification_done(Ok(equal), digest);
196                    }
197                } else {
198                    for i in 0..8 {
199                        let d = regs.digest[i].get().to_ne_bytes();
200
201                        let idx = i * 4;
202
203                        digest[idx + 0] = d[0];
204                        digest[idx + 1] = d[1];
205                        digest[idx + 2] = d[2];
206                        digest[idx + 3] = d[3];
207                    }
208                    if self.cancelled.get() {
209                        self.clear_data();
210                        self.cancelled.set(false);
211                        client.hash_done(Err(ErrorCode::CANCEL), digest);
212                    } else {
213                        self.clear_data();
214                        self.cancelled.set(false);
215                        client.hash_done(Ok(()), digest);
216                    }
217                }
218            });
219        } else if intrs.is_set(INTR_STATE::FIFO_EMPTY) {
220            // Clear the FIFO empty interrupt
221            regs.intr_state.modify(INTR_STATE::FIFO_EMPTY::SET);
222            let rval = if self.cancelled.get() {
223                self.cancelled.set(false);
224                Err(ErrorCode::CANCEL)
225            } else {
226                Ok(())
227            };
228            if !self.data_progress() {
229                // False means we are done
230                self.client.map(move |client| {
231                    self.data.take().map(|buf| match buf {
232                        SubSliceMutImmut::Mutable(b) => client.add_mut_data_done(rval, b),
233                        SubSliceMutImmut::Immutable(b) => client.add_data_done(rval, b),
234                    })
235                });
236                // Make sure we don't get any more FIFO empty interrupts
237                regs.intr_enable.modify(INTR_ENABLE::FIFO_EMPTY::CLEAR);
238            } else {
239                // Processing more data
240                // Enable interrupts
241                regs.intr_enable.modify(INTR_ENABLE::FIFO_EMPTY::SET);
242            }
243        } else if intrs.is_set(INTR_STATE::HMAC_ERR) {
244            regs.intr_state.modify(INTR_STATE::HMAC_ERR::SET);
245
246            self.client.map(|client| {
247                let errval = if self.cancelled.get() {
248                    self.cancelled.set(false);
249                    ErrorCode::CANCEL
250                } else {
251                    ErrorCode::FAIL
252                };
253                if self.verify.get() {
254                    client.hash_done(Err(errval), self.digest.take().unwrap());
255                } else {
256                    client.hash_done(Err(errval), self.digest.take().unwrap());
257                }
258            });
259        }
260    }
261}
262
263impl<'a> hil::digest::DigestData<'a, 32> for Hmac<'a> {
264    fn add_data(
265        &self,
266        data: SubSlice<'static, u8>,
267    ) -> Result<(), (ErrorCode, SubSlice<'static, u8>)> {
268        if self.busy.get() {
269            Err((ErrorCode::BUSY, data))
270        } else {
271            self.busy.set(true);
272            self.data.set(Some(SubSliceMutImmut::Immutable(data)));
273
274            let regs = self.registers;
275            regs.cmd.modify(CMD::START::SET);
276            // Clear the FIFO empty interrupt
277            regs.intr_state.modify(INTR_STATE::FIFO_EMPTY::SET);
278            // Enable interrupts
279            regs.intr_enable.modify(INTR_ENABLE::FIFO_EMPTY::SET);
280            let ret = self.data_progress();
281
282            if ret {
283                regs.intr_test.modify(INTR_TEST::FIFO_EMPTY::SET);
284            }
285
286            Ok(())
287        }
288    }
289
290    fn add_mut_data(
291        &self,
292        data: SubSliceMut<'static, u8>,
293    ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)> {
294        if self.busy.get() {
295            Err((ErrorCode::BUSY, data))
296        } else {
297            self.busy.set(true);
298            self.data.set(Some(SubSliceMutImmut::Mutable(data)));
299
300            let regs = self.registers;
301            regs.cmd.modify(CMD::START::SET);
302            // Clear the FIFO empty interrupt
303            regs.intr_state.modify(INTR_STATE::FIFO_EMPTY::SET);
304            // Enable interrupts
305            regs.intr_enable.modify(INTR_ENABLE::FIFO_EMPTY::SET);
306            let ret = self.data_progress();
307
308            if ret {
309                regs.intr_test.modify(INTR_TEST::FIFO_EMPTY::SET);
310            }
311
312            Ok(())
313        }
314    }
315
316    fn clear_data(&self) {
317        let regs = self.registers;
318        regs.cmd.modify(CMD::START::CLEAR);
319        regs.wipe_secret.set(1_u32);
320        self.cancelled.set(true);
321    }
322
323    fn set_data_client(&'a self, _client: &'a (dyn digest::ClientData<32> + 'a)) {
324        unimplemented!()
325    }
326}
327
328impl<'a> hil::digest::DigestHash<'a, 32> for Hmac<'a> {
329    fn run(
330        &'a self,
331        digest: &'static mut [u8; 32],
332    ) -> Result<(), (ErrorCode, &'static mut [u8; 32])> {
333        let regs = self.registers;
334
335        // Enable interrupts
336        regs.intr_state
337            .modify(INTR_STATE::HMAC_DONE::SET + INTR_STATE::HMAC_ERR::SET);
338        regs.intr_enable
339            .modify(INTR_ENABLE::HMAC_DONE::SET + INTR_ENABLE::HMAC_ERR::SET);
340
341        // Start the process
342        regs.cmd.modify(CMD::PROCESS::SET);
343        self.busy.set(true);
344        self.digest.set(Some(digest));
345
346        Ok(())
347    }
348
349    fn set_hash_client(&'a self, _client: &'a (dyn digest::ClientHash<32> + 'a)) {
350        unimplemented!()
351    }
352}
353
354impl<'a> hil::digest::DigestVerify<'a, 32> for Hmac<'a> {
355    fn verify(
356        &'a self,
357        compare: &'static mut [u8; 32],
358    ) -> Result<(), (ErrorCode, &'static mut [u8; 32])> {
359        self.verify.set(true);
360
361        self.run(compare)
362    }
363
364    fn set_verify_client(&'a self, _client: &'a (dyn digest::ClientVerify<32> + 'a)) {
365        unimplemented!()
366    }
367}
368
369impl<'a> hil::digest::Digest<'a, 32> for Hmac<'a> {
370    fn set_client(&'a self, client: &'a dyn digest::Client<32>) {
371        self.client.set(client);
372    }
373}
374
375impl hil::digest::HmacSha256 for Hmac<'_> {
376    fn set_mode_hmacsha256(&self, key: &[u8]) -> Result<(), ErrorCode> {
377        if self.busy.get() {
378            return Err(ErrorCode::BUSY);
379        }
380        let regs = self.registers;
381        let mut key_idx = 0;
382
383        if key.len() > 32 {
384            return Err(ErrorCode::NOSUPPORT);
385        }
386
387        // Ensure the HMAC is setup
388        regs.cfg.write(
389            CFG::HMAC_EN::SET + CFG::SHA_EN::SET + CFG::ENDIAN_SWAP::CLEAR + CFG::DIGEST_SWAP::SET,
390        );
391
392        for i in 0..(key.len() / 4) {
393            let idx = i * 4;
394
395            let mut k = *key.get(idx + 3).ok_or(ErrorCode::INVAL)? as u32;
396            k |= (*key.get(i * 4 + 2).ok_or(ErrorCode::INVAL)? as u32) << 8;
397            k |= (*key.get(i * 4 + 1).ok_or(ErrorCode::INVAL)? as u32) << 16;
398            k |= (*key.get(i * 4 + 0).ok_or(ErrorCode::INVAL)? as u32) << 24;
399
400            regs.key.get(i).ok_or(ErrorCode::INVAL)?.set(k);
401            key_idx = i + 1;
402        }
403
404        if (key.len() % 4) != 0 {
405            let mut k = 0;
406
407            for i in 0..(key.len() % 4) {
408                k |= (*key.get(key_idx * 4 + 1).ok_or(ErrorCode::INVAL)? as u32) << (8 * (3 - i));
409            }
410
411            regs.key.get(key_idx).ok_or(ErrorCode::INVAL)?.set(k);
412            key_idx += 1;
413        }
414
415        for i in key_idx..8 {
416            regs.key.get(i).ok_or(ErrorCode::INVAL)?.set(0);
417        }
418
419        Ok(())
420    }
421}
422
423impl hil::digest::HmacSha384 for Hmac<'_> {
424    fn set_mode_hmacsha384(&self, _key: &[u8]) -> Result<(), ErrorCode> {
425        Err(ErrorCode::NOSUPPORT)
426    }
427}
428
429impl hil::digest::HmacSha512 for Hmac<'_> {
430    fn set_mode_hmacsha512(&self, _key: &[u8]) -> Result<(), ErrorCode> {
431        Err(ErrorCode::NOSUPPORT)
432    }
433}
434
435impl hil::digest::Sha256 for Hmac<'_> {
436    fn set_mode_sha256(&self) -> Result<(), ErrorCode> {
437        if self.busy.get() {
438            return Err(ErrorCode::BUSY);
439        }
440        let regs = self.registers;
441
442        // Ensure the SHA is setup
443        regs.cfg.write(
444            CFG::HMAC_EN::CLEAR
445                + CFG::SHA_EN::SET
446                + CFG::ENDIAN_SWAP::CLEAR
447                + CFG::DIGEST_SWAP::SET,
448        );
449
450        Ok(())
451    }
452}
453
454impl hil::digest::Sha384 for Hmac<'_> {
455    fn set_mode_sha384(&self) -> Result<(), ErrorCode> {
456        Err(ErrorCode::NOSUPPORT)
457    }
458}
459
460impl hil::digest::Sha512 for Hmac<'_> {
461    fn set_mode_sha512(&self) -> Result<(), ErrorCode> {
462        Err(ErrorCode::NOSUPPORT)
463    }
464}