Software APIs
hmac.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
6 
7 #include "dt/dt_hmac.h"
12 #include "sw/device/silicon_creator/lib/error.h"
13 
14 #include "hmac_regs.h" // Generated.
15 
16 static const dt_hmac_t kHmacDt = kDtHmac;
17 
18 static inline uint32_t hmac_base(void) {
19  return dt_hmac_primary_reg_block(kHmacDt);
20 }
21 
22 void hmac_sha256_configure(bool big_endian_digest) {
23  // Clear the config, stopping the SHA engine.
24  abs_mmio_write32(hmac_base() + HMAC_CFG_REG_OFFSET, 0u);
25 
26  // Disable and clear interrupts. INTR_STATE register is rw1c.
27  abs_mmio_write32(hmac_base() + HMAC_INTR_ENABLE_REG_OFFSET, 0u);
28  abs_mmio_write32(hmac_base() + HMAC_INTR_STATE_REG_OFFSET, UINT32_MAX);
29 
30  uint32_t reg = 0;
31  reg = bitfield_bit32_write(reg, HMAC_CFG_DIGEST_SWAP_BIT, big_endian_digest);
32  reg = bitfield_bit32_write(reg, HMAC_CFG_ENDIAN_SWAP_BIT, false);
33  reg = bitfield_bit32_write(reg, HMAC_CFG_SHA_EN_BIT, true);
34  reg = bitfield_bit32_write(reg, HMAC_CFG_HMAC_EN_BIT, false);
35  // configure to run SHA-2 256 with 256-bit key
36  reg = bitfield_field32_write(reg, HMAC_CFG_DIGEST_SIZE_FIELD,
37  HMAC_CFG_DIGEST_SIZE_VALUE_SHA2_256);
38  reg = bitfield_field32_write(reg, HMAC_CFG_KEY_LENGTH_FIELD,
39  HMAC_CFG_KEY_LENGTH_VALUE_KEY_256);
40  abs_mmio_write32(hmac_base() + HMAC_CFG_REG_OFFSET, reg);
41 }
42 
43 inline void hmac_sha256_start(void) {
44  uint32_t cmd = bitfield_bit32_write(0, HMAC_CMD_HASH_START_BIT, true);
45  abs_mmio_write32(hmac_base() + HMAC_CMD_REG_OFFSET, cmd);
46 }
47 
48 void hmac_sha256_update(const void *data, size_t len) {
49  const uint8_t *data_sent = (const uint8_t *)data;
50 
51  // Individual byte writes are needed if the buffer isn't word aligned.
52  for (; len != 0 && (uintptr_t)data_sent & 3; --len) {
53  abs_mmio_write8(hmac_base() + HMAC_MSG_FIFO_REG_OFFSET, *data_sent++);
54  }
55 
56  for (; len >= sizeof(uint32_t); len -= sizeof(uint32_t)) {
57  uint32_t data_aligned = read_32(data_sent);
58  abs_mmio_write32(hmac_base() + HMAC_MSG_FIFO_REG_OFFSET, data_aligned);
59  data_sent += sizeof(uint32_t);
60  }
61 
62  // Handle non-32bit aligned bytes at the end of the buffer.
63  for (; len != 0; --len) {
64  abs_mmio_write8(hmac_base() + HMAC_MSG_FIFO_REG_OFFSET, *data_sent++);
65  }
66 }
67 
68 void hmac_sha256_update_words(const uint32_t *data, size_t len) {
69  for (size_t i = 0; i < len; i++) {
70  abs_mmio_write32(hmac_base() + HMAC_MSG_FIFO_REG_OFFSET, data[i]);
71  }
72 }
73 
74 inline void hmac_sha256_process(void) {
75  uint32_t cmd = bitfield_bit32_write(0, HMAC_CMD_HASH_PROCESS_BIT, true);
76  abs_mmio_write32(hmac_base() + HMAC_CMD_REG_OFFSET, cmd);
77 }
78 
79 /**
80  * Wait for the `hmac_done` interrupt and then clear it.
81  *
82  * Should only be called after a `process` or `stop` command.
83  */
84 static void wait_for_done(void) {
85  uint32_t reg = 0;
86  do {
87  reg = abs_mmio_read32(hmac_base() + HMAC_INTR_STATE_REG_OFFSET);
88  } while (!bitfield_bit32_read(reg, HMAC_INTR_STATE_HMAC_DONE_BIT));
89  abs_mmio_write32(hmac_base() + HMAC_INTR_STATE_REG_OFFSET, reg);
90 }
91 
92 void hmac_sha256_final_truncated(uint32_t *digest, size_t len) {
93  wait_for_done();
94 
95  uint32_t result, incr;
96  uint32_t reg = abs_mmio_read32(hmac_base() + HMAC_CFG_REG_OFFSET);
97  if (bitfield_bit32_read(reg, HMAC_CFG_DIGEST_SWAP_BIT)) {
98  // Big-endian output.
99  result = HMAC_DIGEST_0_REG_OFFSET;
100  incr = sizeof(uint32_t);
101  } else {
102  // Little-endian output.
103  // Note: we rely on 32-bit integer wraparound to cause the result register
104  // index to count down from 7 to 0.
105  result = HMAC_DIGEST_7_REG_OFFSET;
106  incr = (uint32_t) - sizeof(uint32_t);
107  }
108 
109  // Ensure len is at most the digest length; this function should never be
110  // called with a `len` that is too big, but this helps ensure it at runtime
111  // just in case.
112  len = len <= kHmacDigestNumWords ? len : kHmacDigestNumWords;
113  for (uint32_t i = 0; i < len; ++i, result += incr) {
114  digest[i] = abs_mmio_read32(hmac_base() + result);
115  }
116 }
117 
118 void hmac_sha256(const void *data, size_t len, hmac_digest_t *digest) {
119  hmac_sha256_init();
120  hmac_sha256_update(data, len);
121  hmac_sha256_process();
122  hmac_sha256_final(digest);
123 }
124 
125 void hmac_sha256_save(hmac_context_t *ctx) {
126  // Issue the STOP command to halt the operation and compute the intermediate
127  // digest.
128  uint32_t cmd = bitfield_bit32_write(0, HMAC_CMD_HASH_STOP_BIT, true);
129  abs_mmio_write32(hmac_base() + HMAC_CMD_REG_OFFSET, cmd);
130  wait_for_done();
131 
132  // Read the digest registers. Note that endianness does not matter here,
133  // because we will simply restore the registers in the same order as we saved
134  // them.
135  for (uint32_t i = 0; i < kHmacDigestNumWords; i++) {
136  ctx->digest[i] = abs_mmio_read32(hmac_base() + HMAC_DIGEST_0_REG_OFFSET +
137  i * sizeof(uint32_t));
138  }
139 
140  // Read the message length registers.
141  ctx->msg_len_lower =
142  abs_mmio_read32(hmac_base() + HMAC_MSG_LENGTH_LOWER_REG_OFFSET);
143  ctx->msg_len_upper =
144  abs_mmio_read32(hmac_base() + HMAC_MSG_LENGTH_UPPER_REG_OFFSET);
145 
146  // Momentarily clear the `sha_en` bit, which clears the digest.
147  uint32_t cfg = abs_mmio_read32(hmac_base() + HMAC_CFG_REG_OFFSET);
148  abs_mmio_write32(hmac_base() + HMAC_CFG_REG_OFFSET,
149  bitfield_bit32_write(cfg, HMAC_CFG_SHA_EN_BIT, false));
150 
151  // Restore the full original configuration.
152  abs_mmio_write32(hmac_base() + HMAC_CFG_REG_OFFSET, cfg);
153 }
154 
155 void hmac_sha256_restore(const hmac_context_t *ctx) {
156  // Clear the `sha_en` bit to ensure the message length registers are
157  // writeable. Leave the rest of the configuration unchanged.
158  uint32_t cfg = abs_mmio_read32(hmac_base() + HMAC_CFG_REG_OFFSET);
159  cfg = bitfield_bit32_write(cfg, HMAC_CFG_SHA_EN_BIT, false);
160  abs_mmio_write32(hmac_base() + HMAC_CFG_REG_OFFSET, cfg);
161 
162  // Write the digest registers. Note that endianness does not matter here,
163  // because we will simply restore the registers in the same order as we saved
164  // them.
165  for (uint32_t i = 0; i < kHmacDigestNumWords; i++) {
166  abs_mmio_write32(
167  hmac_base() + HMAC_DIGEST_0_REG_OFFSET + i * sizeof(uint32_t),
168  ctx->digest[i]);
169  }
170 
171  // Write the message length registers.
172  abs_mmio_write32(hmac_base() + HMAC_MSG_LENGTH_LOWER_REG_OFFSET,
173  ctx->msg_len_lower);
174  abs_mmio_write32(hmac_base() + HMAC_MSG_LENGTH_UPPER_REG_OFFSET,
175  ctx->msg_len_upper);
176 
177  // Re-enable the SHA engine.
178  cfg = bitfield_bit32_write(cfg, HMAC_CFG_SHA_EN_BIT, true);
179  abs_mmio_write32(hmac_base() + HMAC_CFG_REG_OFFSET, cfg);
180 
181  // Issue the CONTINUE command to restart the operation.
182  uint32_t cmd = bitfield_bit32_write(0, HMAC_CMD_HASH_CONTINUE_BIT, true);
183  abs_mmio_write32(hmac_base() + HMAC_CMD_REG_OFFSET, cmd);
184 }
185 
186 extern void hmac_sha256_init(void);
187 extern void hmac_sha256_final(hmac_digest_t *digest);