Software APIs
hash.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 
6 
7 #include <stdbool.h>
8 
10 #include "sw/device/lib/crypto/drivers/hmac.h"
11 #include "sw/device/lib/crypto/drivers/kmac.h"
12 #include "sw/device/lib/crypto/impl/status.h"
13 
14 // Module ID for status codes.
15 #define MODULE_ID MAKE_MODULE_ID('h', 'a', 's')
16 
17 // Check that internal and publicly exposed digest values match each other.
18 static_assert(kSha256DigestBits == kHmacSha256DigestBits &&
19  kSha256DigestBytes == kHmacSha256DigestBytes &&
20  kSha256DigestWords == kHmacSha256DigestWords,
21  "Exposed and driver-level SHA-256 digest size mismatch.");
22 static_assert(kSha384DigestBits == kHmacSha384DigestBits &&
23  kSha384DigestBytes == kHmacSha384DigestBytes &&
24  kSha384DigestWords == kHmacSha384DigestWords,
25  "Exposed and driver-level SHA-384 digest size mismatch.");
26 static_assert(kSha512DigestBits == kHmacSha512DigestBits &&
27  kSha512DigestBytes == kHmacSha512DigestBytes &&
28  kSha512DigestWords == kHmacSha512DigestWords,
29  "Exposed and driver-level SHA-512 digest size mismatch.");
30 
31 // Ensure that the hash context is large enough for HMAC driver struct.
32 static_assert(
33  sizeof(otcrypto_hash_context_t) >= sizeof(hmac_ctx_t),
34  "`otcrypto_hash_context_t` must be big enough to hold `hmac_ctx_t`.");
35 
36 // Ensure that HMAC driver struct is suitable for `hardened_memcpy()`.
37 static_assert(sizeof(hmac_ctx_t) % sizeof(uint32_t) == 0,
38  "Size of `hmac_ctx_t` must be a multiple of the word size for "
39  "`hardened_memcpy()`");
40 
41 /**
42  * Save the internal HMAC driver context to a generic hash context.
43  *
44  * @param[out] ctx Generic hash context to copy to.
45  * @param hmac_ctx The internal context object from HMAC driver.
46  */
47 static void hmac_ctx_save(otcrypto_hash_context_t *restrict ctx,
48  const hmac_ctx_t *restrict hmac_ctx) {
49  // As per the `hardened_memcpy()` documentation, it is OK to cast to
50  // `uint32_t *` here as long as `state` is word-aligned, which it must be
51  // because all its fields are.
52  hardened_memcpy(ctx->data, (uint32_t *)hmac_ctx,
53  sizeof(hmac_ctx_t) / sizeof(uint32_t));
54 }
55 
56 /**
57  * Restore an internal HMAC driver context from a generic hash context.
58  *
59  * @param ctx Generic hash context to restore from.
60  * @param[out] hmac_ctx Destination HMAC driver context object.
61  */
62 static void hmac_ctx_restore(const otcrypto_hash_context_t *restrict ctx,
63  hmac_ctx_t *restrict hmac_ctx) {
64  // As per the `hardened_memcpy()` documentation, it is OK to cast to
65  // `uint32_t *` here as long as `state` is word-aligned, which it must be
66  // because all its fields are.
67  hardened_memcpy((uint32_t *)hmac_ctx, ctx->data,
68  sizeof(hmac_ctx_t) / sizeof(uint32_t));
69 }
70 
71 /**
72  * Checks that the `mode` and `len` fields of the digest match.
73  *
74  * Ignores the digest `data` field; safe to use on uninitialized digests.
75  *
76  * @param digest Digest struct with `mode` and `len` set.
77  * @return Error status.
78  */
80 static status_t check_digest_len(otcrypto_hash_digest_t digest) {
81  switch (launder32(digest.mode)) {
82  case kOtcryptoHashModeSha3_224:
83  if (launder32(digest.len) == (224 / 32)) {
84  HARDENED_CHECK_EQ(digest.len * sizeof(uint32_t) * 8, 224);
85  return OTCRYPTO_OK;
86  }
87  return OTCRYPTO_BAD_ARGS;
88  case kOtcryptoHashModeSha256:
90  case kOtcryptoHashModeSha3_256:
91  if (launder32(digest.len) == (256 / 32)) {
92  HARDENED_CHECK_EQ(digest.len * sizeof(uint32_t) * 8, 256);
93  return OTCRYPTO_OK;
94  }
95  return OTCRYPTO_BAD_ARGS;
96  case kOtcryptoHashModeSha384:
98  case kOtcryptoHashModeSha3_384:
99  if (launder32(digest.len) == (384 / 32)) {
100  HARDENED_CHECK_EQ(digest.len * sizeof(uint32_t) * 8, 384);
101  return OTCRYPTO_OK;
102  }
103  return OTCRYPTO_BAD_ARGS;
104  case kOtcryptoHashModeSha512:
106  case kOtcryptoHashModeSha3_512:
107  if (launder32(digest.len) == (512 / 32)) {
108  HARDENED_CHECK_EQ(digest.len * sizeof(uint32_t) * 8, 512);
109  return OTCRYPTO_OK;
110  }
111  return OTCRYPTO_BAD_ARGS;
112  default:
113  return OTCRYPTO_BAD_ARGS;
114  }
115  // Should be unreachable.
116  HARDENED_TRAP();
117  return OTCRYPTO_FATAL_ERR;
118 }
119 
121  otcrypto_hash_digest_t digest) {
122  if (input_message.data == NULL && input_message.len != 0) {
123  return OTCRYPTO_BAD_ARGS;
124  }
125 
126  if (digest.data == NULL) {
127  return OTCRYPTO_BAD_ARGS;
128  }
129 
130  // Check that digest length and mode match.
131  HARDENED_TRY(check_digest_len(digest));
132 
133  switch (digest.mode) {
134  case kOtcryptoHashModeSha3_224:
135  return kmac_sha3_224(input_message.data, input_message.len, digest.data);
136  case kOtcryptoHashModeSha3_256:
137  return kmac_sha3_256(input_message.data, input_message.len, digest.data);
138  case kOtcryptoHashModeSha3_384:
139  return kmac_sha3_384(input_message.data, input_message.len, digest.data);
140  case kOtcryptoHashModeSha3_512:
141  return kmac_sha3_512(input_message.data, input_message.len, digest.data);
142  case kOtcryptoHashModeSha256:
143  return hmac(kHmacModeSha256, /*key=*/NULL, /*key_wordlen=*/0,
144  input_message.data, input_message.len, digest.data,
145  digest.len);
146  break;
147  case kOtcryptoHashModeSha384:
148  return hmac(kHmacModeSha384, /*key=*/NULL, /*key_wordlen=*/0,
149  input_message.data, input_message.len, digest.data,
150  digest.len);
151  break;
152  case kOtcryptoHashModeSha512:
153  return hmac(kHmacModeSha512, /*key=*/NULL, /*key_wordlen=*/0,
154  input_message.data, input_message.len, digest.data,
155  digest.len);
156  break;
157  default:
158  // Invalid hash mode.
159  return OTCRYPTO_BAD_ARGS;
160  }
161  return OTCRYPTO_OK;
162 }
163 
165  otcrypto_hash_digest_t digest) {
166  switch (digest.mode) {
167  case kOtcryptoHashXofModeShake128:
168  return kmac_shake_128(input_message.data, input_message.len, digest.data,
169  digest.len);
170  case kOtcryptoHashXofModeShake256:
171  return kmac_shake_256(input_message.data, input_message.len, digest.data,
172  digest.len);
173  default:
174  return OTCRYPTO_BAD_ARGS;
175  }
176 
177  // Should be unreachable.
178  HARDENED_TRAP();
179  return OTCRYPTO_FATAL_ERR;
180 }
181 
183  otcrypto_const_byte_buf_t input_message,
184  otcrypto_const_byte_buf_t function_name_string,
185  otcrypto_const_byte_buf_t customization_string,
186  otcrypto_hash_digest_t digest) {
187  // According to NIST SP 800-185 Section 3.2, cSHAKE call should use SHAKE, if
188  // both `customization_string` and `function_name_string` are empty string
189  if (customization_string.len == 0 && function_name_string.len == 0) {
190  switch (digest.mode) {
191  case kOtcryptoHashXofModeCshake128:
192  return kmac_shake_128(input_message.data, input_message.len,
193  digest.data, digest.len);
194  case kOtcryptoHashXofModeCshake256:
195  return kmac_shake_256(input_message.data, input_message.len,
196  digest.data, digest.len);
197  default:
198  return OTCRYPTO_BAD_ARGS;
199  }
200  }
201 
202  switch (digest.mode) {
203  case kOtcryptoHashXofModeCshake128:
204  return kmac_cshake_128(
205  input_message.data, input_message.len, function_name_string.data,
206  function_name_string.len, customization_string.data,
207  customization_string.len, digest.data, digest.len);
208  break;
209  case kOtcryptoHashXofModeCshake256:
210  return kmac_cshake_256(
211  input_message.data, input_message.len, function_name_string.data,
212  function_name_string.len, customization_string.data,
213  customization_string.len, digest.data, digest.len);
214  default:
215  return OTCRYPTO_BAD_ARGS;
216  }
217 
218  // Should be unreachable.
219  HARDENED_TRAP();
220  return OTCRYPTO_FATAL_ERR;
221 }
222 
224  otcrypto_hash_mode_t hash_mode) {
225  if (ctx == NULL) {
226  return OTCRYPTO_BAD_ARGS;
227  }
228 
230  switch (hash_mode) {
231  case kOtcryptoHashModeSha256: {
232  HARDENED_TRY(hmac_init(&hmac_ctx, kHmacModeSha256, /*hmac_key=*/NULL,
233  /*key_wordlen=*/0));
234  break;
235  }
236  case kOtcryptoHashModeSha384: {
237  HARDENED_TRY(hmac_init(&hmac_ctx, kHmacModeSha384, /*hmac_key=*/NULL,
238  /*key_wordlen=*/0));
239  break;
240  }
241  case kOtcryptoHashModeSha512: {
242  HARDENED_TRY(hmac_init(&hmac_ctx, kHmacModeSha512, /*hmac_key=*/NULL,
243  /*key_wordlen=*/0));
244  break;
245  }
246  default:
247  // Unrecognized or unsupported hash mode.
248  return OTCRYPTO_BAD_ARGS;
249  }
250 
251  hmac_ctx_save(ctx, &hmac_ctx);
252  return OTCRYPTO_OK;
253 }
254 
256  otcrypto_hash_context_t *const ctx,
257  otcrypto_const_byte_buf_t input_message) {
258  if (ctx == NULL || (input_message.data == NULL && input_message.len != 0)) {
259  return OTCRYPTO_BAD_ARGS;
260  }
262  hmac_ctx_restore(ctx, &hmac_ctx);
263  HARDENED_TRY(hmac_update(&hmac_ctx, input_message.data, input_message.len));
264  hmac_ctx_save(ctx, &hmac_ctx);
265  return OTCRYPTO_OK;
266 }
267 
269  otcrypto_hash_digest_t digest) {
270  if (ctx == NULL || digest.data == NULL) {
271  return OTCRYPTO_BAD_ARGS;
272  }
273 
274  // Check that digest length and mode are consistent.
275  HARDENED_TRY(check_digest_len(digest));
276 
278  hmac_ctx_restore(ctx, &hmac_ctx);
279  HARDENED_TRY(hmac_final(&hmac_ctx, digest.data, digest.len));
280  // TODO(#23191): Clear `ctx`.
281  hmac_ctx_save(ctx, &hmac_ctx);
282  return OTCRYPTO_OK;
283 }