Software APIs
aes_gcm.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 
11 #include "sw/device/lib/crypto/drivers/aes.h"
12 #include "sw/device/lib/crypto/drivers/entropy.h"
13 #include "sw/device/lib/crypto/drivers/keymgr.h"
14 #include "sw/device/lib/crypto/drivers/rv_core_ibex.h"
15 #include "sw/device/lib/crypto/impl/aes_gcm/aes_gcm.h"
16 #include "sw/device/lib/crypto/impl/aes_gcm/ghash.h"
17 #include "sw/device/lib/crypto/impl/integrity.h"
18 #include "sw/device/lib/crypto/impl/keyblob.h"
19 #include "sw/device/lib/crypto/impl/status.h"
21 
22 // Module ID for status codes.
23 #define MODULE_ID MAKE_MODULE_ID('a', 'g', 'c')
24 
25 // Check GHASH context size against the underlying implementation.
26 static_assert(sizeof(otcrypto_aes_gcm_context_t) >= sizeof(aes_gcm_context_t),
27  "Size of AES-GCM context object for top-level API must be at "
28  "least as large as the context for the "
29  "underlying implementation.");
30 static_assert(alignof(aes_gcm_context_t) >= alignof(uint32_t),
31  "Internal AES-GCM context object must be word-aligned for use "
32  "with `hardened_memcpy`.");
33 static_assert(sizeof(otcrypto_key_config_t) % sizeof(uint32_t) == 0,
34  "Key configuration size should be a multiple of 32 bits");
35 
36 // Ensure the internal AES-GCM context size is a multiple of the word size and
37 // calculate the number of words.
38 static_assert(sizeof(aes_gcm_context_t) % sizeof(uint32_t) == 0,
39  "Internal AES-GCM context object must be a multiple of the word "
40  "size for use with `hardened_memcpy`.");
41 enum {
42  kAesGcmContextNumWords = sizeof(aes_gcm_context_t) / sizeof(uint32_t),
43 };
44 
45 /**
46  * Save an AES-GCM context.
47  *
48  * @param internal_ctx Internal context object to save.
49  * @param[out] api_ctx Resulting API-facing context object.
50  */
51 static inline void gcm_context_save(aes_gcm_context_t *internal_ctx,
52  otcrypto_aes_gcm_context_t *api_ctx) {
53  hardened_memcpy(api_ctx->data, (uint32_t *)internal_ctx,
54  kAesGcmContextNumWords);
55 }
56 
57 /**
58  * Restore an AES-GCM context.
59  *
60  * @param api_ctx API-facing context object to restore from.
61  * @param[out] internal_ctx Resulting internal context object.
62  */
63 static inline void gcm_context_restore(otcrypto_aes_gcm_context_t *api_ctx,
64  aes_gcm_context_t *internal_ctx) {
65  hardened_memcpy((uint32_t *)internal_ctx, api_ctx->data,
66  kAesGcmContextNumWords);
67 }
68 
69 /**
70  * Construct the underlying AES key for AES-GCM.
71  *
72  * Also performs integrity, mode, and null-pointer checks on the key.
73  *
74  * @param blinded_key Blinded key struct.
75  * @param[out] aes_key Destination AES key struct.
76  * @return Result of the operation.
77  */
78 static status_t aes_gcm_key_construct(const otcrypto_blinded_key_t *blinded_key,
79  aes_key_t *aes_key) {
80  // Key integrity check.
81  if (launder32(integrity_blinded_key_check(blinded_key)) !=
83  return OTCRYPTO_BAD_ARGS;
84  }
85  HARDENED_CHECK_EQ(integrity_blinded_key_check(blinded_key),
87 
88  // Check the key mode.
89  if (launder32((uint32_t)blinded_key->config.key_mode) !=
90  kOtcryptoKeyModeAesGcm) {
91  return OTCRYPTO_BAD_ARGS;
92  }
93  HARDENED_CHECK_EQ(blinded_key->config.key_mode, kOtcryptoKeyModeAesGcm);
94 
95  // Set the mode of the underlying AES key to CTR (since this is the
96  // underlying block cipher mode for GCM).
97  aes_key->mode = kAesCipherModeCtr;
98 
99  // Set the AES key length (in words).
100  aes_key->key_len = keyblob_share_num_words(blinded_key->config);
101 
102  // Check for null pointer.
103  if (blinded_key->keyblob == NULL) {
104  return OTCRYPTO_BAD_ARGS;
105  }
106 
107  if (launder32(blinded_key->config.hw_backed) == kHardenedBoolTrue) {
108  // In this case, we use an implementation-specific representation; the
109  // first "share" is the keyblob and the second share is ignored.
110  if (launder32(blinded_key->keyblob_length) != kKeyblobHwBackedBytes) {
111  return OTCRYPTO_BAD_ARGS;
112  }
113  HARDENED_CHECK_EQ(blinded_key->keyblob_length, kKeyblobHwBackedBytes);
114  aes_key->key_shares[0] = blinded_key->keyblob;
115  aes_key->key_shares[1] = NULL;
116  aes_key->sideload = launder32(kHardenedBoolTrue);
117  } else if (launder32(blinded_key->config.hw_backed) == kHardenedBoolFalse) {
118  HARDENED_CHECK_EQ(blinded_key->config.hw_backed, kHardenedBoolFalse);
119  // Get pointers to the individual shares.
120  uint32_t *share0;
121  uint32_t *share1;
122  HARDENED_TRY(keyblob_to_shares(blinded_key, &share0, &share1));
123  aes_key->key_shares[0] = share0;
124  aes_key->key_shares[1] = share1;
125  aes_key->sideload = launder32(kHardenedBoolFalse);
126  } else {
127  return OTCRYPTO_BAD_ARGS;
128  }
129  HARDENED_CHECK_EQ(aes_key->sideload, blinded_key->config.hw_backed);
130 
131  return OTCRYPTO_OK;
132 }
133 
134 /**
135  * Checks if the given byte-length matches the tag length enum value.
136  *
137  * @param word_len Allocated tag length in 32-bit words.
138  * @param tag_len Tag length enum value.
139  * @return OK if the tag length is acceptable, BAD_ARGS otherwise.
140  */
141 status_t aes_gcm_check_tag_length(size_t word_len,
142  otcrypto_aes_gcm_tag_len_t tag_len) {
143  size_t bit_len = 0;
144  switch (launder32(tag_len)) {
145  case kOtcryptoAesGcmTagLen128:
146  HARDENED_CHECK_EQ(tag_len, kOtcryptoAesGcmTagLen128);
147  bit_len = 128;
148  break;
149  case kOtcryptoAesGcmTagLen96:
150  HARDENED_CHECK_EQ(tag_len, kOtcryptoAesGcmTagLen96);
151  bit_len = 96;
152  break;
153  case kOtcryptoAesGcmTagLen64:
154  HARDENED_CHECK_EQ(tag_len, kOtcryptoAesGcmTagLen64);
155  bit_len = 64;
156  break;
157  case kOtcryptoAesGcmTagLen32:
158  HARDENED_CHECK_EQ(tag_len, kOtcryptoAesGcmTagLen32);
159  bit_len = 32;
160  break;
161  default:
162  // Invalid tag length.
163  return OTCRYPTO_BAD_ARGS;
164  }
165  HARDENED_CHECK_GT(bit_len, 0);
166  HARDENED_CHECK_EQ(bit_len % 32, 0);
167 
168  if (launder32(word_len) != bit_len / 32) {
169  return OTCRYPTO_BAD_ARGS;
170  }
171  HARDENED_CHECK_EQ(word_len, bit_len / 32);
172 
173  // Extra hardening checks; the word length must be nonzero and at most the
174  // size of an AES block.
175  HARDENED_CHECK_LT(0, word_len);
176  HARDENED_CHECK_LE(word_len, kAesBlockNumWords);
177 
178  return OTCRYPTO_OK;
179 }
180 
181 /**
182  * Actuate the key manager to generate a sideloaded AES-GCM key.
183  *
184  * The AES driver will not load or clear sideloaded keys by itself, so we need
185  * to do it separately at each stage of the AES-GCM operation.
186  *
187  * Sideloaded keys are stored in the `aes_key_t` struct in a format specific to
188  * this AES-GCM implementation: the first "key share" is the diversification
189  * data as it would be stored in a blinded keyblob, and the second "share" is
190  * completely ignored.
191  *
192  * If the key is not a sideloaded key, this function does nothing.
193  *
194  * @param key Key to load.
195  * @return OK or errror.
196  */
197 static status_t load_key_if_sideloaded(const aes_key_t key) {
198  if (launder32(key.sideload) == kHardenedBoolFalse) {
199  return OTCRYPTO_OK;
200  } else if (key.sideload != kHardenedBoolTrue) {
201  return OTCRYPTO_BAD_ARGS;
202  }
204  keymgr_diversification_t diversification;
205  HARDENED_TRY(keyblob_buffer_to_keymgr_diversification(
206  key.key_shares[0], kOtcryptoKeyModeAesGcm, &diversification));
207  return keymgr_generate_key_aes(diversification);
208 }
209 
210 /**
211  * Clear the sideload slot if the AES key was sideloaded.
212  *
213  * It is important to clear the sideload slot before returning to the caller so
214  * that other applications can't access the key in between operations.
215  *
216  * If the key is not a sideloaded key, this function does nothing.
217  *
218  * @param key Key that was possibly loaded.
219  * @return OK or errror.
220  */
221 static status_t clear_key_if_sideloaded(const aes_key_t key) {
222  if (launder32(key.sideload) == kHardenedBoolFalse) {
224  return OTCRYPTO_OK;
225  } else if (launder32(key.sideload) != kHardenedBoolTrue) {
226  return OTCRYPTO_BAD_ARGS;
227  }
229  return keymgr_sideload_clear_aes();
230 }
231 
233  otcrypto_const_byte_buf_t plaintext,
237  otcrypto_byte_buf_t ciphertext,
238  otcrypto_word32_buf_t auth_tag) {
239  // Check for NULL pointers in input pointers and required-nonzero-length data
240  // buffers.
241  if (key == NULL || iv.data == NULL || auth_tag.data == NULL) {
242  return OTCRYPTO_BAD_ARGS;
243  }
244 
245  // Conditionally check for null pointers in data buffers that may be
246  // 0-length.
247  if ((aad.len != 0 && aad.data == NULL) ||
248  (ciphertext.len != 0 && ciphertext.data == NULL) ||
249  (plaintext.len != 0 && plaintext.data == NULL)) {
250  return OTCRYPTO_BAD_ARGS;
251  }
252 
253  // Ensure the plaintext and ciphertext lengths match.
254  if (launder32(ciphertext.len) != plaintext.len) {
255  return OTCRYPTO_BAD_ARGS;
256  }
257  HARDENED_CHECK_EQ(ciphertext.len, plaintext.len);
258 
259  // Check the tag length.
260  HARDENED_TRY(aes_gcm_check_tag_length(auth_tag.len, tag_len));
261 
262  // Construct the AES key.
264  HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
265  HARDENED_TRY(load_key_if_sideloaded(aes_key));
266 
267  // Call the core encryption operation.
268  HARDENED_TRY(aes_gcm_encrypt(aes_key, iv.len, iv.data, plaintext.len,
269  plaintext.data, aad.len, aad.data, auth_tag.len,
270  auth_tag.data, ciphertext.data));
271 
272  HARDENED_TRY(clear_key_if_sideloaded(aes_key));
273  return OTCRYPTO_OK;
274 }
275 
277  const otcrypto_blinded_key_t *key, otcrypto_const_byte_buf_t ciphertext,
280  otcrypto_byte_buf_t plaintext, hardened_bool_t *success) {
281  // Check for NULL pointers in input pointers and required-nonzero-length data
282  // buffers.
283  if (key == NULL || iv.data == NULL || auth_tag.data == NULL) {
284  return OTCRYPTO_BAD_ARGS;
285  }
286 
287  // Conditionally check for null pointers in data buffers that may be
288  // 0-length.
289  if ((aad.len != 0 && aad.data == NULL) ||
290  (ciphertext.len != 0 && ciphertext.data == NULL) ||
291  (plaintext.len != 0 && plaintext.data == NULL)) {
292  return OTCRYPTO_BAD_ARGS;
293  }
294 
295  // Construct the AES key.
297  HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
298  HARDENED_TRY(load_key_if_sideloaded(aes_key));
299 
300  // Ensure the plaintext and ciphertext lengths match.
301  if (launder32(ciphertext.len) != plaintext.len) {
302  return OTCRYPTO_BAD_ARGS;
303  }
304  HARDENED_CHECK_EQ(ciphertext.len, plaintext.len);
305 
306  // Check the tag length.
307  HARDENED_TRY(aes_gcm_check_tag_length(auth_tag.len, tag_len));
308 
309  // Call the core decryption operation.
310  HARDENED_TRY(aes_gcm_decrypt(aes_key, iv.len, iv.data, ciphertext.len,
311  ciphertext.data, aad.len, aad.data, auth_tag.len,
312  auth_tag.data, plaintext.data, success));
313 
314  HARDENED_TRY(clear_key_if_sideloaded(aes_key));
315  return OTCRYPTO_OK;
316 }
317 
321  if (key == NULL || key->keyblob == NULL || iv.data == NULL || ctx == NULL) {
322  return OTCRYPTO_BAD_ARGS;
323  }
324 
325  // Construct the AES key.
327  HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
328  HARDENED_TRY(load_key_if_sideloaded(aes_key));
329 
330  // Call the internal init operation.
331  aes_gcm_context_t internal_ctx;
332  HARDENED_TRY(aes_gcm_encrypt_init(aes_key, iv.len, iv.data, &internal_ctx));
333 
334  // Save the context and clear the key if needed.
335  gcm_context_save(&internal_ctx, ctx);
336  HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
337  return OTCRYPTO_OK;
338 }
339 
343  if (key == NULL || key->keyblob == NULL || iv.data == NULL || ctx == NULL) {
344  return OTCRYPTO_BAD_ARGS;
345  }
346 
347  // Construct the AES key.
349  HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
350  HARDENED_TRY(load_key_if_sideloaded(aes_key));
351 
352  // Call the internal init operation.
353  aes_gcm_context_t internal_ctx;
354  HARDENED_TRY(aes_gcm_decrypt_init(aes_key, iv.len, iv.data, &internal_ctx));
355 
356  // Save the context and clear the key if needed.
357  gcm_context_save(&internal_ctx, ctx);
358  HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
359  return OTCRYPTO_OK;
360 }
361 
364  if (ctx == NULL || aad.data == NULL) {
365  return OTCRYPTO_BAD_ARGS;
366  }
367 
368  if (aad.len == 0) {
369  // Nothing to do.
370  return OTCRYPTO_OK;
371  }
372 
373  // Restore the AES-GCM context object and load the key if needed.
374  aes_gcm_context_t internal_ctx;
375  gcm_context_restore(ctx, &internal_ctx);
376  HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
377 
378  // Call the internal update operation.
379  HARDENED_TRY(aes_gcm_update_aad(&internal_ctx, aad.len, aad.data));
380 
381  // Save the context and clear the key if needed.
382  gcm_context_save(&internal_ctx, ctx);
383  HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
384  return OTCRYPTO_OK;
385 }
386 
389  otcrypto_byte_buf_t output, size_t *output_bytes_written) {
390  if (ctx == NULL || input.data == NULL || output.data == NULL ||
391  output_bytes_written == NULL) {
392  return OTCRYPTO_BAD_ARGS;
393  }
394  *output_bytes_written = 0;
395 
396  if (input.len == 0) {
397  // Nothing to do.
398  return OTCRYPTO_OK;
399  }
400 
401  // Restore the AES-GCM context object and load the key if needed.
402  aes_gcm_context_t internal_ctx;
403  gcm_context_restore(ctx, &internal_ctx);
404  HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
405 
406  // The output buffer must be long enough to hold all full blocks that will
407  // exist after `input` is added.
408  size_t partial_block_len = internal_ctx.input_len % kAesBlockNumBytes;
409  if (input.len > UINT32_MAX - partial_block_len) {
410  return OTCRYPTO_BAD_ARGS;
411  }
412  size_t min_output_blocks =
413  (partial_block_len + input.len) / kAesBlockNumBytes;
414  size_t min_output_len = min_output_blocks * kAesBlockNumBytes;
415  if (output.len < min_output_len) {
416  return OTCRYPTO_BAD_ARGS;
417  }
418 
419  // Call the internal update operation.
420  HARDENED_TRY(aes_gcm_update_encrypted_data(
421  &internal_ctx, input.len, input.data, output_bytes_written, output.data));
422 
423  // Save the context and clear the key if needed.
424  gcm_context_save(&internal_ctx, ctx);
425  HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
426  return OTCRYPTO_OK;
427 }
428 
431  otcrypto_byte_buf_t ciphertext, size_t *ciphertext_bytes_written,
432  otcrypto_word32_buf_t auth_tag) {
433  if (ctx == NULL || ciphertext_bytes_written == NULL ||
434  auth_tag.data == NULL) {
435  return OTCRYPTO_BAD_ARGS;
436  }
437  if (ciphertext.len != 0 && ciphertext.data == NULL) {
438  return OTCRYPTO_BAD_ARGS;
439  }
440  *ciphertext_bytes_written = 0;
441 
442  // Entropy complex needs to be initialized for `memshred`.
443  HARDENED_TRY(entropy_complex_check());
444 
445  // Check the tag length.
446  HARDENED_TRY(aes_gcm_check_tag_length(auth_tag.len, tag_len));
447 
448  // Restore the AES-GCM context object and load the key if needed.
449  aes_gcm_context_t internal_ctx;
450  gcm_context_restore(ctx, &internal_ctx);
451  HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
452 
453  // If the partial block is nonempty, the output must be at least as long as
454  // the partial block.
455  size_t partial_block_len = internal_ctx.input_len % kAesBlockNumBytes;
456  if (ciphertext.len < partial_block_len) {
457  return OTCRYPTO_BAD_ARGS;
458  }
459 
460  // Call the internal final operation.
461  HARDENED_TRY(aes_gcm_encrypt_final(&internal_ctx, auth_tag.len, auth_tag.data,
462  ciphertext_bytes_written,
463  ciphertext.data));
464 
465  // Clear the context and the key if needed.
466  hardened_memshred(ctx->data, ARRAYSIZE(ctx->data));
467  HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
468  return OTCRYPTO_OK;
469 }
470 
474  size_t *plaintext_bytes_written, hardened_bool_t *success) {
475  if (ctx == NULL || plaintext_bytes_written == NULL || auth_tag.data == NULL ||
476  success == NULL) {
477  return OTCRYPTO_BAD_ARGS;
478  }
479  if (plaintext.len != 0 && plaintext.data == NULL) {
480  return OTCRYPTO_BAD_ARGS;
481  }
482  *plaintext_bytes_written = 0;
483  *success = kHardenedBoolFalse;
484 
485  // Entropy complex needs to be initialized for `memshred`.
486  HARDENED_TRY(entropy_complex_check());
487 
488  // Check the tag length.
489  HARDENED_TRY(aes_gcm_check_tag_length(auth_tag.len, tag_len));
490 
491  // Restore the AES-GCM context object and load the key if needed.
492  aes_gcm_context_t internal_ctx;
493  gcm_context_restore(ctx, &internal_ctx);
494  HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
495 
496  // If the partial block is nonempty, the output must be at least as long as
497  // the partial block.
498  size_t partial_block_len = internal_ctx.input_len % kAesBlockNumBytes;
499  if (plaintext.len < partial_block_len) {
500  return OTCRYPTO_BAD_ARGS;
501  }
502 
503  // Call the internal final operation.
504  HARDENED_TRY(aes_gcm_decrypt_final(&internal_ctx, auth_tag.len, auth_tag.data,
505  plaintext_bytes_written, plaintext.data,
506  success));
507 
508  // Clear the context and the key if needed.
509  hardened_memshred(ctx->data, ARRAYSIZE(ctx->data));
510  HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
511  return OTCRYPTO_OK;
512 }