Software APIs
sha256.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/lib/crypto/impl/sha2/sha256.h"
6 
11 #include "sw/device/lib/crypto/drivers/otbn.h"
12 #include "sw/device/lib/crypto/drivers/rv_core_ibex.h"
13 #include "sw/device/lib/crypto/impl/status.h"
14 
15 // Module ID for status codes.
16 #define MODULE_ID MAKE_MODULE_ID('s', '2', '2')
17 
18 enum {
19  /**
20  * Maximum number of message chunks that the OTBN app can accept.
21  *
22  * This number is based on the DMEM size limit and usage by the SHA-256 app
23  * itself; see `run_sha256.s` for the detailed calculation.
24  */
25  kSha256MaxMessageChunksPerOtbnRun = 41,
26 };
27 
28 /**
29  * A type to hold message blocks.
30  */
31 typedef struct sha256_message_block {
32  uint32_t data[kSha256MessageBlockWords];
34 
35 /**
36  * Context object for the OTBN message buffer.
37  */
38 typedef struct sha256_otbn_ctx {
39  /**
40  * Number of message blocks currently loaded.
41  */
42  size_t num_blocks;
44 
45 // Initial state for SHA-256 (see FIPS 180-4, section 5.3.3). The SHA-256 OTBN
46 // app represents the state with little-endian words and in reverse word-order
47 // compared with FIPS 180-4.
48 static const uint32_t kSha256InitialState[kSha256StateWords] = {
49  0x5be0cd19, 0x1f83d9ab, 0x9b05688c, 0x510e527f,
50  0xa54ff53a, 0x3c6ef372, 0xbb67ae85, 0x6a09e667,
51 };
52 static_assert(sizeof(kSha256InitialState) == kSha256StateBytes,
53  "Initial state for SHA-256 has an unexpected size.");
54 
55 OTBN_DECLARE_APP_SYMBOLS(run_sha256); // The OTBN SHA-256 app.
56 OTBN_DECLARE_SYMBOL_ADDR(run_sha256, state); // Hash state.
57 OTBN_DECLARE_SYMBOL_ADDR(run_sha256, msg); // Input message.
58 OTBN_DECLARE_SYMBOL_ADDR(run_sha256,
59  num_msg_chunks); // Message length in blocks.
60 
61 static const otbn_app_t kOtbnAppSha256 = OTBN_APP_T_INIT(run_sha256);
62 static const otbn_addr_t kOtbnVarSha256State =
63  OTBN_ADDR_T_INIT(run_sha256, state);
64 static const otbn_addr_t kOtbnVarSha256Msg = OTBN_ADDR_T_INIT(run_sha256, msg);
65 static const otbn_addr_t kOtbnVarSha256NumMsgChunks =
66  OTBN_ADDR_T_INIT(run_sha256, num_msg_chunks);
67 
68 void sha256_init(sha256_state_t *state) {
69  // Set the initial state.
70  hardened_memcpy(state->H, kSha256InitialState, kSha256StateWords);
71  // Set the partial block to 0 (the value is ignored).
72  memset(state->partial_block, 0, kSha256MessageBlockBytes);
73  // Set the message length so far to 0.
74  state->total_len = 0ull;
75 }
76 
77 /**
78  * Run OTBN to process the data currently in DMEM.
79  *
80  * @param ctx OTBN message buffer context information (updated in place).
81  * @return Result of the operation.
82  */
83 static status_t process_message_buffer(sha256_otbn_ctx_t *ctx) {
84  // Write the number of blocks to DMEM.
85  HARDENED_TRY(
86  otbn_dmem_write(1, &ctx->num_blocks, kOtbnVarSha256NumMsgChunks));
87 
88  // Run the OTBN program.
89  HARDENED_TRY(otbn_execute());
90  HARDENED_TRY(otbn_busy_wait_for_done());
91 
92  // Reset the message buffer counter.
93  ctx->num_blocks = 0;
94  return OTCRYPTO_OK;
95 }
96 
97 /**
98  * Add a single message block to the processing buffer.
99  *
100  * Runs OTBN if the maximum number of message blocks has been reached.
101  *
102  * @param ctx OTBN message buffer context information (updated in place).
103  * @param block Block to write.
104  * @return Result of the operation.
105  */
106 static status_t process_block(sha256_otbn_ctx_t *ctx,
107  const sha256_message_block_t *block) {
108  // Calculate the offset within the message buffer.
109  size_t offset = ctx->num_blocks * kSha256MessageBlockBytes;
110  otbn_addr_t dst = kOtbnVarSha256Msg + offset;
111 
112  // Copy the message block into DMEM.
113  otbn_dmem_write(kSha256MessageBlockWords, block->data, dst);
114  ctx->num_blocks += 1;
115 
116  // If we've reached the maximum number of message chunks for a single run,
117  // then run the OTBN program to update the state in-place. Note that there
118  // is no need to read back and then re-write the state; it'll stay updated
119  // in DMEM for the next run.
120  if (ctx->num_blocks == kSha256MaxMessageChunksPerOtbnRun) {
121  HARDENED_TRY(process_message_buffer(ctx));
122  }
123  return OTCRYPTO_OK;
124 }
125 
126 /**
127  * Pad the block as described in FIPS 180-4, section 5.1.1.
128  *
129  * Padding fills the current block and may require one additional block. This
130  * function calls `process_block` to load the padded block(s) into OTBN.
131  *
132  * The length of real data in the partial block should be the byte-length of
133  * the message so far (total_len >> 3) modulo `kSha256MessageBlockBytes`.
134  *
135  * @param ctx OTBN message buffer context information (updated in place).
136  * @param total_len Total length of message so far.
137  * @param block Current (partial) block.
138  * @return Result of the operation.
139  */
140 static status_t process_padding(sha256_otbn_ctx_t *ctx,
141  const uint64_t total_len,
142  sha256_message_block_t *block) {
143  size_t partial_block_len = (total_len >> 3) % kSha256MessageBlockBytes;
144 
145  // Get a byte-sized pointer to the end of the real data within the block.
146  unsigned char *data_end = (unsigned char *)block->data + partial_block_len;
147 
148  // Fill the remainder of the block with zeroes.
149  size_t padding_len = kSha256MessageBlockBytes - partial_block_len;
150  memset(data_end, 0, padding_len);
151 
152  // Set the last byte after the message to 0x80. There must be at least one
153  // unfilled byte in the partial block, since partial_block_len is always <
154  // kSha256MessageBlockBytes.
155  memset(data_end, 0x80, 1);
156 
157  if (partial_block_len + 1 + sizeof(total_len) > kSha256MessageBlockBytes) {
158  // We need to use the additional block. The first block is already
159  // complete, so process it and then zero out the block data again to
160  // prepare the next one.
161  HARDENED_TRY(process_block(ctx, block));
162  memset(block, 0, kSha256MessageBlockBytes);
163  }
164 
165  // Set the last 64 bits of the final block to the bit-length in big-endian
166  // form.
167  block->data[kSha256MessageBlockWords - 1] =
168  __builtin_bswap32(total_len & UINT32_MAX);
169  block->data[kSha256MessageBlockWords - 2] =
170  __builtin_bswap32(total_len >> 32);
171 
172  // Process the last block.
173  return process_block(ctx, block);
174 }
175 
176 /**
177  * Update the hash state to include new data, optionally adding padding.
178  *
179  * @param state Context object.
180  * @param msg Input message.
181  * @param msg_len Input message length in bytes.
182  * @param padding_needed Whether to pad the message.
183  * @return Result of the operation.
184  */
185 static status_t process_message(sha256_state_t *state, const uint8_t *msg,
186  size_t msg_len,
187  hardened_bool_t padding_needed) {
188  // Load the SHA-256 app. Fails if OTBN is non-idle.
189  HARDENED_TRY(otbn_load_app(kOtbnAppSha256));
190 
191  // Check the message length. SHA-256 messages must be less than 2^64 bits
192  // long in total.
193  uint64_t msg_bits = ((uint64_t)msg_len) << 3;
194  uint64_t max_msg_bits = UINT64_MAX - state->total_len;
195  if (msg_bits > max_msg_bits) {
196  return OTCRYPTO_BAD_ARGS;
197  }
198 
199  // Calculate the new value of state->total_len. Do NOT update the state yet
200  // (because if we get an OTBN error, it would become out of sync).
201  sha256_state_t new_state;
202  new_state.total_len = state->total_len + msg_bits;
203 
204  // Set the initial state if at least one block has been received before now.
205  if (state->total_len >= kSha256MessageBlockBytes) {
206  HARDENED_TRY(
207  otbn_dmem_write(kSha256StateWords, state->H, kOtbnVarSha256State));
208  }
209 
210  // Start computing the first block for the hash computation by simply copying
211  // the partial block. We won't use the partial block directly to avoid
212  // contaminating the context object if this operation fails later.
214  size_t partial_block_len = (state->total_len >> 3) % kSha256MessageBlockBytes;
215  memcpy(block.data, state->partial_block, partial_block_len);
216 
217  // Initialize the context for the OTBN message buffer.
218  sha256_otbn_ctx_t ctx = {.num_blocks = 0};
219 
220  // Process the message one block at a time, including partial data if it is
221  // present (which is only possible on the first iteration).
222  while (msg_len >= kSha256MessageBlockBytes - partial_block_len) {
223  size_t available_len = kSha256MessageBlockBytes - partial_block_len;
224  memcpy((unsigned char *)block.data + partial_block_len, msg, available_len);
225  msg += available_len;
226  msg_len -= available_len;
227  HARDENED_TRY(process_block(&ctx, &block));
228  partial_block_len = 0;
229  }
230 
231  // Copy remaining mesage data into the working block (after partial data, if
232  // it is present). Because of the loop condition above, this must not be a
233  // full block.
234  memcpy((unsigned char *)block.data + partial_block_len, msg, msg_len);
235 
236  // Add padding if necessary.
237  if (padding_needed == kHardenedBoolTrue) {
238  HARDENED_TRY(process_padding(&ctx, new_state.total_len, &block));
239  }
240 
241  // If there are any unprocessed blocks currently in DMEM, run the program one
242  // final time.
243  if (ctx.num_blocks > 0) {
244  HARDENED_TRY(process_message_buffer(&ctx));
245  }
246 
247  // Read the final state from OTBN dmem.
248  HARDENED_TRY(
249  otbn_dmem_read(kSha256StateWords, kOtbnVarSha256State, new_state.H));
250 
251  // Clear OTBN's memory.
252  HARDENED_TRY(otbn_dmem_sec_wipe());
253 
254  // At this point, no more errors are possible; it is safe to update the
255  // context object.
256  hardened_memcpy(state->H, new_state.H, kSha256StateWords);
257  hardened_memcpy(state->partial_block, block.data, kSha256MessageBlockWords);
258  state->total_len = new_state.total_len;
259  return OTCRYPTO_OK;
260 }
261 
262 status_t sha256_update(sha256_state_t *state, const uint8_t *msg,
263  const size_t msg_len) {
264  // Process new data with no padding.
265  return process_message(state, msg, msg_len, kHardenedBoolFalse);
266 }
267 
268 /**
269  * Replace sensitive data in a SHA-256 context with non-sensitive values.
270  *
271  * The entropy complex must be initialized before calling this function.
272  *
273  * @param state The context object to shred.
274  */
275 static void state_shred(sha256_state_t *state) {
276  hardened_memshred(state->H, kSha256StateWords);
277  hardened_memshred(state->partial_block, kSha256MessageBlockWords);
278  state->total_len = 0;
279 }
280 
281 /**
282  * Copy the final digest as a byte-string.
283  *
284  * SHA-256 intermediate computations use words in little-endian format, but the
285  * FIPS 180-4 spec requires big-endian words (see section 3.1). Therefore, to
286  * get the right final byte-order, we need to reverse each word in the state.
287  *
288  * Also, in the SHA-256 computation, the order of the words is reversed
289  * compared to FIPS 180-4, so we switch the word order as well.
290  *
291  * @param state Context object.
292  * @param[out] digest Destination buffer for digest.
293  */
294 static void digest_get(sha256_state_t *state, uint32_t *digest) {
295  for (size_t i = 0; i < kSha256StateWords / 2; i++) {
296  uint32_t tmp = __builtin_bswap32(state->H[i]);
297  state->H[i] = __builtin_bswap32(state->H[kSha256StateWords - 1 - i]);
298  state->H[kSha256StateWords - 1 - i] = tmp;
299  }
300  hardened_memcpy(digest, state->H, kSha256StateWords);
301 }
302 
303 status_t sha256_final(sha256_state_t *state, uint32_t *digest) {
304  // Entropy complex needs to be initialized for `state_shred`.
305  HARDENED_TRY(entropy_complex_check());
306 
307  // Construct padding.
308  HARDENED_TRY(process_message(state, NULL, 0, kHardenedBoolTrue));
309 
310  // Retrieve the final digest and destroy the state.
311  digest_get(state, digest);
312  state_shred(state);
313  return OTCRYPTO_OK;
314 }
315 
316 status_t sha256(const uint8_t *msg, const size_t msg_len, uint32_t *digest) {
317  // Entropy complex needs to be initialized for `state_shred`.
318  HARDENED_TRY(entropy_complex_check());
319 
320  sha256_state_t state;
321  sha256_init(&state);
322 
323  // Process data with padding enabled.
324  HARDENED_TRY(process_message(&state, msg, msg_len, kHardenedBoolTrue));
325 
326  // Retrieve the final digest and destroy the state.
327  digest_get(&state, digest);
328  state_shred(&state);
329  return OTCRYPTO_OK;
330 }