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 
6 
8 #include "sw/device/lib/crypto/drivers/hmac.h"
9 #include "sw/device/lib/crypto/impl/integrity.h"
10 #include "sw/device/lib/crypto/impl/keyblob.h"
11 #include "sw/device/lib/crypto/impl/status.h"
13 
14 // Module ID for status codes.
15 #define MODULE_ID MAKE_MODULE_ID('h', 'm', 'c')
16 
17 /**
18  * Ensure that the hash context is large enough for HMAC driver struct.
19  */
20 static_assert(
21  sizeof(otcrypto_hmac_context_t) >= sizeof(hmac_ctx_t),
22  "`otcrypto_hash_context_t` must be big enough to hold `hmac_ctx_t`.");
23 
24 /**
25  * Ensure that HMAC driver struct is suitable for `hardened_memcpy()`.
26  */
27 static_assert(sizeof(hmac_ctx_t) % sizeof(uint32_t) == 0,
28  "Size of `hmac_ctx_t` must be a multiple of the word size for "
29  "`hardened_memcpy()`");
30 
31 /**
32  * Save the internal HMAC driver context to a generic Hmac context.
33  *
34  * @param[out] ctx Generic hash context to copy to.
35  * @param hmac_ctx The internal context object from HMAC driver.
36  */
37 static void hmac_ctx_save(otcrypto_hmac_context_t *restrict ctx,
38  const hmac_ctx_t *restrict hmac_ctx) {
39  // As per the `hardened_memcpy()` documentation, it is OK to cast to
40  // `uint32_t *` here as long as `state` is word-aligned, which it must be
41  // because all its fields are.
42  hardened_memcpy(ctx->data, (uint32_t *)hmac_ctx,
43  sizeof(hmac_ctx_t) / sizeof(uint32_t));
44 }
45 
46 /**
47  * Restore an internal HMAC driver context from a generic Hmac context.
48  *
49  * @param ctx Generic hash context to restore from.
50  * @param[out] hmac_ctx Destination HMAC driver context object.
51  */
52 static void hmac_ctx_restore(const otcrypto_hmac_context_t *restrict ctx,
53  hmac_ctx_t *restrict hmac_ctx) {
54  // As per the `hardened_memcpy()` documentation, it is OK to cast to
55  // `uint32_t *` here as long as `state` is word-aligned, which it must be
56  // because all its fields are.
57  hardened_memcpy((uint32_t *)hmac_ctx, ctx->data,
58  sizeof(hmac_ctx_t) / sizeof(uint32_t));
59 }
60 
61 /**
62  * For given `key_mode`, return the corresponding driver-level `hmac_mode` and
63  * `block_size`. `block_size` is the internal block size of the hash function
64  * implied by `hash_mode`, and its unit is words.
65  *
66  * This function must only be used with HMAC key modes, otherwise an error
67  * is returned.
68  *
69  * @param key_mode The input key mode.
70  * @param[out] hmac_mode HMAC driver-level equivalent of `key_mode`.
71  * @param[out] block_size The internal block size of the hash function
72  * associated with `hmac_mode`.
73  * @return Result of the operation.
74  */
75 static status_t get_hmac_mode(otcrypto_key_mode_t key_mode,
76  hmac_mode_t *hmac_mode, size_t *block_size) {
77  switch (key_mode) {
78  case kOtcryptoKeyModeHmacSha256:
79  *hmac_mode = kHmacModeHmac256;
80  *block_size = kHmacSha256BlockWords;
81  break;
82  case kOtcryptoKeyModeHmacSha384:
83  *hmac_mode = kHmacModeHmac384;
84  // Note that HMAC-384 and HMAC-512 have the same internal block size.
85  *block_size = kHmacSha512BlockWords;
86  break;
87  case kOtcryptoKeyModeHmacSha512:
88  *hmac_mode = kHmacModeHmac512;
89  *block_size = kHmacSha512BlockWords;
90  break;
91  default:
92  return OTCRYPTO_BAD_ARGS;
93  }
94  return OTCRYPTO_OK;
95 }
96 
97 /**
98  * Pad or hash HMAC key to full block. I.e. compute K0 as defined in FIPS 198-1,
99  * Section 4, Steps 1-3.
100  *
101  * For HMAC-256, `processed_key` is 512 bits, and for HMAC-384/512,
102  * `processed_key` is 1024 bits.
103  *
104  * The caller must allocate `processed_key` buffer with internal block size.
105  *
106  * @param key The blinded input key.
107  * @param[out] processed_key Padding/hashed key whose size matches the internal
108  * block size of the hash function.
109  * @return Result of the operation.
110  */
111 static status_t hmac_key_process(const otcrypto_blinded_key_t *key,
112  uint32_t *processed_key) {
113  otcrypto_hash_mode_t hash_mode;
114  size_t block_size;
115  size_t digest_size;
116  switch (key->config.key_mode) {
117  case kOtcryptoKeyModeHmacSha256:
118  hash_mode = kOtcryptoHashModeSha256;
119  block_size = kHmacSha256BlockWords;
120  digest_size = kHmacSha256DigestWords;
121  break;
122  case kOtcryptoKeyModeHmacSha384:
123  hash_mode = kOtcryptoHashModeSha384;
124  // Note that HMAC-384 and HMAC-512 have the same internal block size.
125  block_size = kHmacSha512BlockWords;
126  digest_size = kHmacSha384DigestWords;
127  break;
128  case kOtcryptoKeyModeHmacSha512:
129  hash_mode = kOtcryptoHashModeSha512;
130  block_size = kHmacSha512BlockWords;
131  digest_size = kHmacSha512DigestWords;
132  break;
133  default:
134  return OTCRYPTO_BAD_ARGS;
135  }
136 
137  // HMAC HWIP does not support masking, so we need to unmask the key.
138  size_t unmasked_key_len = keyblob_share_num_words(key->config);
139  uint32_t unmasked_key[unmasked_key_len];
140  HARDENED_TRY(keyblob_key_unmask(key, unmasked_key_len, unmasked_key));
141 
142  // Pre-populate with 0s, in order to pad keys smaller than the internal
143  // block size, according to FIPS 198-1, Section 4.
144  memset(processed_key, 0, block_size * sizeof(uint32_t));
145  // If the key is larger than the internal block size, we need to hash it
146  // according to FIPS 198-1, Section 4, Step 2.
147  if (key->config.key_length > block_size * sizeof(uint32_t)) {
148  otcrypto_hash_digest_t key_digest = {
149  .mode = hash_mode,
150  .data = processed_key,
151  .len = digest_size,
152  };
153  otcrypto_const_byte_buf_t msg_buf = {
154  .len = key->config.key_length,
155  .data = (unsigned char *)unmasked_key,
156  };
157  HARDENED_TRY(otcrypto_hash(msg_buf, key_digest));
158  } else {
159  hardened_memcpy(processed_key, unmasked_key, unmasked_key_len);
160  // If the key size isn't a multiple of the word size, zero the last few
161  // bytes.
162  size_t offset = key->config.key_length % sizeof(uint32_t);
163  if (offset != 0) {
164  unsigned char *key_end_ptr =
165  (unsigned char *)&processed_key[unmasked_key_len];
166  size_t num_zero_bytes = sizeof(uint32_t) - offset;
167  memset(key_end_ptr - num_zero_bytes, 0, num_zero_bytes);
168  }
169  }
170  return OTCRYPTO_OK;
171 }
172 
175  otcrypto_const_byte_buf_t input_message,
176  otcrypto_word32_buf_t tag) {
177  // Validate key struct.
178  if (key == NULL || key->keyblob == NULL || tag.data == NULL) {
179  return OTCRYPTO_BAD_ARGS;
180  }
181 
182  // HMAC HWIP is not masked and it does not have sideload support, so the
183  // following conditions return not implemented.
184  if (key->config.hw_backed != kHardenedBoolFalse) {
185  return OTCRYPTO_NOT_IMPLEMENTED;
186  }
187  if (key->config.security_level != kOtcryptoKeySecurityLevelLow) {
188  return OTCRYPTO_NOT_IMPLEMENTED;
189  }
190 
191  // Check for null input message with nonzero length.
192  if (input_message.data == NULL && input_message.len != 0) {
193  return OTCRYPTO_BAD_ARGS;
194  }
195 
196  hmac_mode_t hmac_mode;
197  size_t block_size;
198  HARDENED_TRY(get_hmac_mode(key->config.key_mode, &hmac_mode, &block_size));
199 
200  uint32_t processed_key[block_size];
201  HARDENED_TRY(hmac_key_process(key, processed_key));
202 
203  return hmac(hmac_mode, processed_key, block_size, input_message.data,
204  input_message.len, tag.data, tag.len);
205 }
206 
208  const otcrypto_blinded_key_t *key) {
209  if (ctx == NULL || key == NULL || key->keyblob == NULL) {
210  return OTCRYPTO_BAD_ARGS;
211  }
212  if (key->config.hw_backed != kHardenedBoolFalse) {
213  // TODO(#15590): Add support for sideloaded keys via a custom OTBN program.
214  return OTCRYPTO_NOT_IMPLEMENTED;
215  }
216  if (key->config.security_level != kOtcryptoKeySecurityLevelLow) {
217  // TODO: Harden SHA2 implementations.
218  return OTCRYPTO_NOT_IMPLEMENTED;
219  }
220 
221  // Ensure the key is for HMAC and the hash function matches, and remember the
222  // digest and message block sizes.
223  hmac_mode_t hmac_mode;
224  size_t block_size;
225  HARDENED_TRY(get_hmac_mode(key->config.key_mode, &hmac_mode, &block_size));
226 
227  uint32_t processed_key[block_size];
228  HARDENED_TRY(hmac_key_process(key, processed_key));
229 
231  HARDENED_TRY(hmac_init(&hmac_ctx, hmac_mode, processed_key, block_size));
232  hmac_ctx_save(ctx, &hmac_ctx);
233  return OTCRYPTO_OK;
234 }
235 
237  otcrypto_hmac_context_t *const ctx,
238  otcrypto_const_byte_buf_t input_message) {
239  if (ctx == NULL) {
240  return OTCRYPTO_BAD_ARGS;
241  }
242 
243  // Check for null input message with nonzero length.
244  if (input_message.data == NULL && input_message.len != 0) {
245  return OTCRYPTO_BAD_ARGS;
246  }
247 
249  hmac_ctx_restore(ctx, &hmac_ctx);
250  HARDENED_TRY(hmac_update(&hmac_ctx, input_message.data, input_message.len));
251  hmac_ctx_save(ctx, &hmac_ctx);
252  return OTCRYPTO_OK;
253 }
254 
256  otcrypto_word32_buf_t tag) {
257  if (ctx == NULL || tag.data == NULL) {
258  return OTCRYPTO_BAD_ARGS;
259  }
260 
262  hmac_ctx_restore(ctx, &hmac_ctx);
263  HARDENED_TRY(hmac_final(&hmac_ctx, tag.data, tag.len));
264  // TODO(#23191): Clear `ctx`.
265  hmac_ctx_save(ctx, &hmac_ctx);
266  return OTCRYPTO_OK;
267 }