Software APIs
hmac_sca.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/tests/penetrationtests/firmware/sca/hmac_sca.h"
6 
8 #include "sw/device/lib/base/status.h"
9 #include "sw/device/lib/crypto/impl/keyblob.h"
13 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
14 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
15 #include "sw/device/lib/ujson/ujson.h"
16 #include "sw/device/sca/lib/prng.h"
17 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
18 #include "sw/device/tests/penetrationtests/json/hmac_sca_commands.h"
19 
21 
22 enum {
23  /**
24  * Key length in bytes.
25  */
26  kKeyLength = HMACSCA_CMD_MAX_KEY_BYTES,
27  /**
28  * Message length in bytes.
29  */
30  kMessageLength = HMACSCA_CMD_MAX_MESSAGE_BYTES,
31  /**
32  * Tag length in bytes.
33  */
34  kTagLength = HMACSCA_CMD_MAX_TAG_BYTES,
35  /**
36  * Tag length in words.
37  */
38  kTagLengthWord = kTagLength / sizeof(uint32_t),
39  /**
40  * Max number of traces per batch.
41  */
42  kNumBatchOpsMax = 128,
43 };
44 
45 static status_t trigger_hmac(uint8_t key_buf[], uint8_t mask_buf[],
46  uint8_t msg_buf[], uint32_t tag_buf[]) {
47  // Build the key configuration
48  otcrypto_key_config_t config = {
49  .version = kOtcryptoLibVersion1,
50  .key_mode = kOtcryptoKeyModeHmacSha256,
51  .key_length = kKeyLength,
52  .hw_backed = kHardenedBoolFalse,
53  .security_level = kOtcryptoKeySecurityLevelLow,
54  };
55 
56  // Create keyblob.
57  uint32_t keyblob[keyblob_num_words(config)];
58 
59  // Create blinded key.
60  TRY(keyblob_from_key_and_mask((uint32_t *)key_buf, (uint32_t *)mask_buf,
61  config, keyblob));
63  .config = config,
64  .keyblob_length = sizeof(keyblob),
65  .keyblob = keyblob,
66  };
67 
68  // Create input message.
69  otcrypto_const_byte_buf_t input_message = {
70  .len = kMessageLength,
71  .data = msg_buf,
72  };
73 
74  // Create tag.
75  otcrypto_word32_buf_t tag = {
76  .len = kTagLengthWord,
77  .data = tag_buf,
78  };
79 
80  pentest_set_trigger_high();
81  TRY(otcrypto_hmac(&key, input_message, tag));
82  pentest_set_trigger_low();
83  return OK_STATUS();
84 }
85 
86 status_t handle_hmac_pentest_init(ujson_t *uj) {
87  penetrationtest_cpuctrl_t uj_data;
88  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
89 
90  // Setup trigger and enable peripherals needed for the test.
91  pentest_select_trigger_type(kPentestTriggerTypeSw);
92  // Enable the HMAC module and disable unused IP blocks to improve
93  // SCA measurements.
94  pentest_init(kPentestTriggerSourceHmac,
95  kPentestPeripheralEntropy | kPentestPeripheralIoDiv4 |
96  kPentestPeripheralOtbn | kPentestPeripheralCsrng |
97  kPentestPeripheralEdn | kPentestPeripheralHmac);
98 
99  // Disable the instruction cache and dummy instructions for SCA.
100  penetrationtest_device_info_t uj_output;
101  TRY(pentest_configure_cpu(
102  uj_data.icache_disable, uj_data.dummy_instr_disable,
103  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
104  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
105  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
106  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
107 
108  // Read device ID and return to host.
109  TRY(pentest_read_device_id(uj_output.device_id));
110  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
111 
112  return OK_STATUS();
113 }
114 
115 status_t handle_hmac_sca_batch_fvsr(ujson_t *uj) {
116  penetrationtest_hmac_sca_key_t uj_key;
117  penetrationtest_hmac_sca_num_it_t uj_it;
118 
119  TRY(ujson_deserialize_penetrationtest_hmac_sca_key_t(uj, &uj_key));
120  TRY(ujson_deserialize_penetrationtest_hmac_sca_num_it_t(uj, &uj_it));
121 
122  uint8_t batch_messages[kNumBatchOpsMax][kMessageLength];
123  uint8_t batch_keys[kNumBatchOpsMax][kKeyLength];
124  uint8_t batch_masks[kNumBatchOpsMax][kKeyLength];
125 
126  // First generate all FvsR data sets. When sample_fixed,
127  // the provided key/masks is used and the message is random. When
128  // not sample_fixed, a random key/mask and a random message is
129  // generated.
130  bool sample_fixed = true;
131  for (size_t it = 0; it < uj_it.num_iterations; it++) {
132  if (sample_fixed) {
133  memcpy(batch_keys[it], uj_key.key, kKeyLength);
134  memcpy(batch_masks[it], uj_key.mask, kKeyLength);
135  } else {
136  prng_rand_bytes(batch_keys[it], kKeyLength);
137  prng_rand_bytes(batch_masks[it], kKeyLength);
138  }
139  prng_rand_bytes(batch_messages[it], kMessageLength);
140  sample_fixed = batch_messages[it][0] & 0x1;
141  }
142 
143  // Invoke HMAC for each data set.
144  uint32_t tag_buf[kTagLengthWord];
145  for (size_t it = 0; it < uj_it.num_iterations; it++) {
146  TRY(trigger_hmac(batch_keys[it], batch_masks[it], batch_messages[it],
147  tag_buf));
148  }
149 
150  // Send the last tag to host via UART.
151  penetrationtest_hmac_sca_tag_t uj_tag;
152  memcpy(uj_tag.tag, tag_buf, kTagLength);
153  RESP_OK(ujson_serialize_penetrationtest_hmac_sca_tag_t, uj, &uj_tag);
154 
155  return OK_STATUS();
156 }
157 
158 status_t handle_hmac_sca_batch_random(ujson_t *uj) {
159  penetrationtest_hmac_sca_num_it_t uj_it;
160 
161  TRY(ujson_deserialize_penetrationtest_hmac_sca_num_it_t(uj, &uj_it));
162 
163  uint8_t batch_messages[kNumBatchOpsMax][kMessageLength];
164  uint8_t batch_keys[kNumBatchOpsMax][kKeyLength];
165  uint8_t batch_masks[kNumBatchOpsMax][kKeyLength];
166 
167  // Generate random keys and messages.
168  for (size_t it = 0; it < uj_it.num_iterations; it++) {
169  prng_rand_bytes(batch_keys[it], kKeyLength);
170  prng_rand_bytes(batch_masks[it], kKeyLength);
171  prng_rand_bytes(batch_messages[it], kMessageLength);
172  }
173 
174  // Invoke HMAC for each data set.
175  uint32_t tag_buf[kTagLengthWord];
176  for (size_t it = 0; it < uj_it.num_iterations; it++) {
177  TRY(trigger_hmac(batch_keys[it], batch_masks[it], batch_messages[it],
178  tag_buf));
179  }
180 
181  // Send the last tag to host via UART.
182  penetrationtest_hmac_sca_tag_t uj_tag;
183  memcpy(uj_tag.tag, tag_buf, kTagLength);
184  RESP_OK(ujson_serialize_penetrationtest_hmac_sca_tag_t, uj, &uj_tag);
185 
186  return OK_STATUS();
187 }
188 
189 status_t handle_hmac_sca_single(ujson_t *uj) {
190  penetrationtest_hmac_sca_key_t uj_key;
191  penetrationtest_hmac_sca_message_t uj_message;
192 
193  TRY(ujson_deserialize_penetrationtest_hmac_sca_key_t(uj, &uj_key));
194  TRY(ujson_deserialize_penetrationtest_hmac_sca_message_t(uj, &uj_message));
195 
196  // Create buffer to store key, mask, message, and tag.
197  uint8_t key_buf[kKeyLength];
198  memcpy(key_buf, uj_key.key, kKeyLength);
199  uint8_t mask_buf[kKeyLength];
200  memcpy(mask_buf, uj_key.mask, kKeyLength);
201  uint8_t msg_buf[kMessageLength];
202  memcpy(msg_buf, uj_message.message, kMessageLength);
203  uint32_t tag_buf[kTagLengthWord];
204 
205  // Trigger HMAC operation.
206  TRY(trigger_hmac(key_buf, mask_buf, msg_buf, tag_buf));
207 
208  // Copy tag to uJSON type.
209  penetrationtest_hmac_sca_tag_t uj_tag;
210  memcpy(uj_tag.tag, tag_buf, kTagLength);
211 
212  // Send tag to host via UART.
213  RESP_OK(ujson_serialize_penetrationtest_hmac_sca_tag_t, uj, &uj_tag);
214 
215  return OK_STATUS();
216 }
217 
218 status_t handle_hmac_sca(ujson_t *uj) {
219  hmac_sca_subcommand_t cmd;
220  TRY(ujson_deserialize_hmac_sca_subcommand_t(uj, &cmd));
221  switch (cmd) {
222  case kHmacScaSubcommandInit:
223  return handle_hmac_pentest_init(uj);
224  case kHmacScaSubcommandBatchFvsr:
225  return handle_hmac_sca_batch_fvsr(uj);
226  case kHmacScaSubcommandBatchRandom:
227  return handle_hmac_sca_batch_random(uj);
228  case kHmacScaSubcommandSingle:
229  return handle_hmac_sca_single(uj);
230  default:
231  LOG_ERROR("Unrecognized HMAC SCA subcommand: %d", cmd);
232  return INVALID_ARGUMENT();
233  }
234  return OK_STATUS();
235 }