Software APIs
mac.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 
8 #include "sw/device/lib/crypto/drivers/hmac.h"
9 #include "sw/device/lib/crypto/drivers/kmac.h"
10 #include "sw/device/lib/crypto/impl/integrity.h"
11 #include "sw/device/lib/crypto/impl/keyblob.h"
12 #include "sw/device/lib/crypto/impl/status.h"
14 
15 // Module ID for status codes.
16 #define MODULE_ID MAKE_MODULE_ID('m', 'a', 'c')
17 
18 /**
19  * Ensure that the hash context is large enough for HMAC driver struct.
20  */
21 static_assert(
22  sizeof(otcrypto_hmac_context_t) >= sizeof(hmac_ctx_t),
23  "`otcrypto_hash_context_t` must be big enough to hold `hmac_ctx_t`.");
24 
25 /**
26  * Ensure that HMAC driver struct is suitable for `hardened_memcpy()`.
27  */
28 static_assert(sizeof(hmac_ctx_t) % sizeof(uint32_t) == 0,
29  "Size of `hmac_ctx_t` must be a multiple of the word size for "
30  "`hardened_memcpy()`");
31 
32 /**
33  * Save the internal HMAC driver context to a generic Hmac context.
34  *
35  * @param[out] ctx Generic hash context to copy to.
36  * @param hmac_ctx The internal context object from HMAC driver.
37  */
38 static void hmac_ctx_save(otcrypto_hmac_context_t *restrict ctx,
39  const hmac_ctx_t *restrict hmac_ctx) {
40  // As per the `hardened_memcpy()` documentation, it is OK to cast to
41  // `uint32_t *` here as long as `state` is word-aligned, which it must be
42  // because all its fields are.
43  hardened_memcpy(ctx->data, (uint32_t *)hmac_ctx,
44  sizeof(hmac_ctx_t) / sizeof(uint32_t));
45 }
46 
47 /**
48  * Restore an internal HMAC driver context from a generic Hmac context.
49  *
50  * @param ctx Generic hash context to restore from.
51  * @param[out] hmac_ctx Destination HMAC driver context object.
52  */
53 static void hmac_ctx_restore(const otcrypto_hmac_context_t *restrict ctx,
54  hmac_ctx_t *restrict hmac_ctx) {
55  // As per the `hardened_memcpy()` documentation, it is OK to cast to
56  // `uint32_t *` here as long as `state` is word-aligned, which it must be
57  // because all its fields are.
58  hardened_memcpy((uint32_t *)hmac_ctx, ctx->data,
59  sizeof(hmac_ctx_t) / sizeof(uint32_t));
60 }
61 
62 /**
63  * For given `key_mode`, return the corresponding driver-level `hmac_mode` and
64  * `block_size`. `block_size` is the internal block size of the hash function
65  * implied by `hash_mode`, and its unit is words.
66  *
67  * This function must only be used with HMAC key modes, otherwise an error
68  * is returned.
69  *
70  * @param key_mode The input key mode.
71  * @param[out] hmac_mode HMAC driver-level equivalent of `key_mode`.
72  * @param[out] block_size The internal block size of the hash function
73  * associated with `hmac_mode`.
74  * @return Result of the operation.
75  */
76 static status_t get_hmac_mode(otcrypto_key_mode_t key_mode,
77  hmac_mode_t *hmac_mode, size_t *block_size) {
78  switch (key_mode) {
79  case kOtcryptoKeyModeHmacSha256:
80  *hmac_mode = kHmacModeHmac256;
81  *block_size = kHmacSha256BlockWords;
82  break;
83  case kOtcryptoKeyModeHmacSha384:
84  *hmac_mode = kHmacModeHmac384;
85  // Note that HMAC-384 and HMAC-512 have the same internal block size.
86  *block_size = kHmacSha512BlockWords;
87  break;
88  case kOtcryptoKeyModeHmacSha512:
89  *hmac_mode = kHmacModeHmac512;
90  *block_size = kHmacSha512BlockWords;
91  break;
92  default:
93  return OTCRYPTO_BAD_ARGS;
94  }
95  return OTCRYPTO_OK;
96 }
97 
98 /**
99  * Pad or hash HMAC key to full block. I.e. compute K0 as defined in FIPS 198-1,
100  * Section 4, Steps 1-3.
101  *
102  * For HMAC-256, `processed_key` is 512 bits, and for HMAC-384/512,
103  * `processed_key` is 1024 bits.
104  *
105  * The caller must allocate `processed_key` buffer with internal block size.
106  *
107  * @param key The blinded input key.
108  * @param[out] processed_key Padding/hashed key whose size matches the internal
109  * block size of the hash function.
110  * @return Result of the operation.
111  */
112 static status_t hmac_key_process(const otcrypto_blinded_key_t *key,
113  uint32_t *processed_key) {
114  otcrypto_hash_mode_t hash_mode;
115  size_t block_size;
116  size_t digest_size;
117  switch (key->config.key_mode) {
118  case kOtcryptoKeyModeHmacSha256:
119  hash_mode = kOtcryptoHashModeSha256;
120  block_size = kHmacSha256BlockWords;
121  digest_size = kHmacSha256DigestWords;
122  break;
123  case kOtcryptoKeyModeHmacSha384:
124  hash_mode = kOtcryptoHashModeSha384;
125  // Note that HMAC-384 and HMAC-512 have the same internal block size.
126  block_size = kHmacSha512BlockWords;
127  digest_size = kHmacSha384DigestWords;
128  break;
129  case kOtcryptoKeyModeHmacSha512:
130  hash_mode = kOtcryptoHashModeSha512;
131  block_size = kHmacSha512BlockWords;
132  digest_size = kHmacSha512DigestWords;
133  break;
134  default:
135  return OTCRYPTO_BAD_ARGS;
136  }
137 
138  // HMAC HWIP does not support masking, so we need to unmask the key.
139  size_t unmasked_key_len = keyblob_share_num_words(key->config);
140  uint32_t unmasked_key[unmasked_key_len];
141  HARDENED_TRY(keyblob_key_unmask(key, unmasked_key_len, unmasked_key));
142 
143  // Pre-populate with 0s, in order to pad keys smaller than the internal
144  // block size, according to FIPS 198-1, Section 4.
145  memset(processed_key, 0, block_size * sizeof(uint32_t));
146  // If the key is larger than the internal block size, we need to hash it
147  // according to FIPS 198-1, Section 4, Step 2.
148  if (key->config.key_length > block_size * sizeof(uint32_t)) {
149  otcrypto_hash_digest_t key_digest = {
150  .mode = hash_mode,
151  .data = processed_key,
152  .len = digest_size,
153  };
154  otcrypto_const_byte_buf_t msg_buf = {
155  .len = key->config.key_length,
156  .data = (unsigned char *)unmasked_key,
157  };
158  HARDENED_TRY(otcrypto_hash(msg_buf, key_digest));
159  } else {
160  hardened_memcpy(processed_key, unmasked_key, unmasked_key_len);
161  // If the key size isn't a multiple of the word size, zero the last few
162  // bytes.
163  size_t offset = key->config.key_length % sizeof(uint32_t);
164  if (offset != 0) {
165  unsigned char *key_end_ptr =
166  (unsigned char *)&processed_key[unmasked_key_len];
167  size_t num_zero_bytes = sizeof(uint32_t) - offset;
168  memset(key_end_ptr - num_zero_bytes, 0, num_zero_bytes);
169  }
170  }
171  return OTCRYPTO_OK;
172 }
173 
176  otcrypto_const_byte_buf_t input_message,
177  otcrypto_word32_buf_t tag) {
178  // Validate key struct.
179  if (key == NULL || key->keyblob == NULL || tag.data == NULL) {
180  return OTCRYPTO_BAD_ARGS;
181  }
182 
183  // HMAC HWIP is not masked and it does not have sideload support, so the
184  // following conditions return not implemented.
185  if (key->config.hw_backed != kHardenedBoolFalse) {
186  return OTCRYPTO_NOT_IMPLEMENTED;
187  }
188  if (key->config.security_level != kOtcryptoKeySecurityLevelLow) {
189  return OTCRYPTO_NOT_IMPLEMENTED;
190  }
191 
192  // Check for null input message with nonzero length.
193  if (input_message.data == NULL && input_message.len != 0) {
194  return OTCRYPTO_BAD_ARGS;
195  }
196 
197  hmac_mode_t hmac_mode;
198  size_t block_size;
199  HARDENED_TRY(get_hmac_mode(key->config.key_mode, &hmac_mode, &block_size));
200 
201  uint32_t processed_key[block_size];
202  HARDENED_TRY(hmac_key_process(key, processed_key));
203 
204  return hmac(hmac_mode, processed_key, block_size, input_message.data,
205  input_message.len, tag.data, tag.len);
206 }
207 
210  otcrypto_const_byte_buf_t input_message,
211  otcrypto_kmac_mode_t kmac_mode,
212  otcrypto_const_byte_buf_t customization_string,
213  size_t required_output_len,
214  otcrypto_word32_buf_t tag) {
215  // TODO (#16410) Revisit/complete error checks
216 
217  // Check for null pointers.
218  if (key == NULL || key->keyblob == NULL || tag.data == NULL) {
219  return OTCRYPTO_BAD_ARGS;
220  }
221 
222  // Check for null input message with nonzero length.
223  if (input_message.data == NULL && input_message.len != 0) {
224  return OTCRYPTO_BAD_ARGS;
225  }
226 
227  // Check for null customization string with nonzero length.
228  if (customization_string.data == NULL && customization_string.len != 0) {
229  return OTCRYPTO_BAD_ARGS;
230  }
231 
232  // Ensure that tag buffer length and `required_output_len` match each other.
233  if (required_output_len != tag.len * sizeof(uint32_t) ||
234  required_output_len == 0) {
235  return OTCRYPTO_BAD_ARGS;
236  }
237 
238  size_t key_len = keyblob_share_num_words(key->config) * sizeof(uint32_t);
239 
240  // Check `key_len` is valid/supported by KMAC HWIP.
241  HARDENED_TRY(kmac_key_length_check(key_len));
242 
243  // Check the integrity of the blinded key.
244  if (integrity_blinded_key_check(key) != kHardenedBoolTrue) {
245  return OTCRYPTO_BAD_ARGS;
246  }
247 
248  kmac_blinded_key_t kmac_key = {
249  .share0 = NULL,
250  .share1 = NULL,
251  .hw_backed = key->config.hw_backed,
252  .len = key_len,
253  };
254 
255  if (key->config.hw_backed == kHardenedBoolTrue) {
256  if (key_len != kKmacSideloadKeyLength / 8) {
257  return OTCRYPTO_BAD_ARGS;
258  }
259  // Configure keymgr with diversification input and then generate the
260  // sideload key.
261  keymgr_diversification_t diversification;
262  // Diversification call also checks that `key->keyblob_length` is 8 words
263  // long.
264  HARDENED_TRY(keyblob_to_keymgr_diversification(key, &diversification));
265  HARDENED_TRY(keymgr_generate_key_kmac(diversification));
266  } else if (key->config.hw_backed == kHardenedBoolFalse) {
267  // Check `key_len` matches `keyblob_length`.
268  if (key->keyblob_length != 2 * key->config.key_length) {
269  return OTCRYPTO_BAD_ARGS;
270  }
271  HARDENED_TRY(keyblob_to_shares(key, &kmac_key.share0, &kmac_key.share1));
272  } else {
273  return OTCRYPTO_BAD_ARGS;
274  }
275 
276  switch (kmac_mode) {
277  case kOtcryptoKmacModeKmac128:
278  // Check `key_mode` matches `mac_mode`
279  if (key->config.key_mode != kOtcryptoKeyModeKmac128) {
280  return OTCRYPTO_BAD_ARGS;
281  }
282  HARDENED_TRY(kmac_kmac_128(&kmac_key, input_message.data,
283  input_message.len, customization_string.data,
284  customization_string.len, tag.data, tag.len));
285  break;
286  case kOtcryptoKmacModeKmac256:
287  // Check `key_mode` matches `mac_mode`
288  if (key->config.key_mode != kOtcryptoKeyModeKmac256) {
289  return OTCRYPTO_BAD_ARGS;
290  }
291 
292  HARDENED_TRY(kmac_kmac_256(&kmac_key, input_message.data,
293  input_message.len, customization_string.data,
294  customization_string.len, tag.data, tag.len));
295  break;
296  default:
297  return OTCRYPTO_BAD_ARGS;
298  }
299 
300  if (key->config.hw_backed == kHardenedBoolTrue) {
301  HARDENED_TRY(keymgr_sideload_clear_kmac());
302  } else if (key->config.hw_backed != kHardenedBoolFalse) {
303  return OTCRYPTO_BAD_ARGS;
304  }
305 
306  return OTCRYPTO_OK;
307 }
308 
310  const otcrypto_blinded_key_t *key) {
311  if (ctx == NULL || key == NULL || key->keyblob == NULL) {
312  return OTCRYPTO_BAD_ARGS;
313  }
314  if (key->config.hw_backed != kHardenedBoolFalse) {
315  // TODO(#15590): Add support for sideloaded keys via a custom OTBN program.
316  return OTCRYPTO_NOT_IMPLEMENTED;
317  }
318  if (key->config.security_level != kOtcryptoKeySecurityLevelLow) {
319  // TODO: Harden SHA2 implementations.
320  return OTCRYPTO_NOT_IMPLEMENTED;
321  }
322 
323  // Ensure the key is for HMAC and the hash function matches, and remember the
324  // digest and message block sizes.
325  hmac_mode_t hmac_mode;
326  size_t block_size;
327  HARDENED_TRY(get_hmac_mode(key->config.key_mode, &hmac_mode, &block_size));
328 
329  uint32_t processed_key[block_size];
330  HARDENED_TRY(hmac_key_process(key, processed_key));
331 
333  HARDENED_TRY(hmac_init(&hmac_ctx, hmac_mode, processed_key, block_size));
334  hmac_ctx_save(ctx, &hmac_ctx);
335  return OTCRYPTO_OK;
336 }
337 
339  otcrypto_hmac_context_t *const ctx,
340  otcrypto_const_byte_buf_t input_message) {
341  if (ctx == NULL) {
342  return OTCRYPTO_BAD_ARGS;
343  }
344 
345  // Check for null input message with nonzero length.
346  if (input_message.data == NULL && input_message.len != 0) {
347  return OTCRYPTO_BAD_ARGS;
348  }
349 
351  hmac_ctx_restore(ctx, &hmac_ctx);
352  HARDENED_TRY(hmac_update(&hmac_ctx, input_message.data, input_message.len));
353  hmac_ctx_save(ctx, &hmac_ctx);
354  return OTCRYPTO_OK;
355 }
356 
358  otcrypto_word32_buf_t tag) {
359  if (ctx == NULL || tag.data == NULL) {
360  return OTCRYPTO_BAD_ARGS;
361  }
362 
364  hmac_ctx_restore(ctx, &hmac_ctx);
365  HARDENED_TRY(hmac_final(&hmac_ctx, tag.data, tag.len));
366  // TODO(#23191): Clear `ctx`.
367  hmac_ctx_save(ctx, &hmac_ctx);
368  return OTCRYPTO_OK;
369 }