Software APIs
ecc256_keygen_serial.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/sca/otbn_vertical/ecc256_keygen_serial.h"
6 
11 #include "sw/device/lib/testing/entropy_testutils.h"
13 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
14 #include "sw/device/sca/lib/prng.h"
16 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
17 
19 #include "otbn_regs.h"
20 
21 enum {
22  /**
23  * Number of bytes for ECDSA P-256 seeds and masked private keys.
24  */
25  kEcc256SeedNumBytes = 320 / 8,
26  /**
27  * Number of 32b words for ECDSA P-256 seeds and masked private keys.
28  */
29  kEcc256SeedNumWords = kEcc256SeedNumBytes / sizeof(uint32_t),
30  /**
31  * Number of bytes for ECDSA P-256 point coordinates.
32  */
33  kEcc256CoordNumBytes = 256 / 8,
34  /**
35  * Number of 32b words for ECDSA P-256 point coordinates.
36  */
37  kEcc256CoordNumWords = kEcc256CoordNumBytes / sizeof(uint32_t),
38  /**
39  * Mode option for the ECDSA keygen app (generates the private key only).
40  */
41  kEcc256ModePrivateKeyOnly = 1,
42  /**
43  * Mode option for the ECDSA keygen app (generates the full keypair).
44  */
45  kEcc256ModeKeypair = 2,
46  /**
47  * Max number of traces per batch.
48  */
49  kNumBatchOpsMax = 256,
50  /**
51  * Number of cycles that Ibex should sleep to minimize noise during OTBN
52  * operations. Caution: This number should be chosen to provide enough time
53  * to complete the operation. Otherwise, Ibex might wake up while OTBN is
54  * still busy and disturb the capture.
55  */
56  kIbexOtbnSleepCycles = 800,
57 };
58 
59 /**
60  * App configuration for p256_key_from_seed_sca
61  */
62 const otbn_app_t kOtbnAppP256KeyFromSeed =
63  OTBN_APP_T_INIT(p256_key_from_seed_sca);
64 
65 static const otbn_addr_t kOtbnVarMode =
66  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, mode);
67 static const otbn_addr_t kOtbnVarSeed0 =
68  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, seed0);
69 static const otbn_addr_t kOtbnVarSeed1 =
70  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, seed1);
71 static const otbn_addr_t kOtbnVarD0 =
72  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, d0);
73 static const otbn_addr_t kOtbnVarD1 =
74  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, d1);
75 static const otbn_addr_t kOtbnVarX =
76  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, x);
77 static const otbn_addr_t kOtbnVarY =
78  OTBN_ADDR_T_INIT(p256_key_from_seed_sca, y);
79 
80 /**
81  * An array of seeds to be used in a batch
82  */
83 uint32_t batch_share0[kNumBatchOpsMax][kEcc256SeedNumWords];
84 
85 /**
86  * An array of masks to be used in a batch
87  */
88 uint32_t batch_share1[kNumBatchOpsMax][kEcc256SeedNumWords];
89 
90 /**
91  * Arrays for first and second share of masked private key d to be used in a
92  * batch
93  */
94 uint32_t d0_batch[kEcc256SeedNumWords];
95 uint32_t d1_batch[kEcc256SeedNumWords];
96 
97 /**
98  * Fixed-message indicator.
99  *
100  * Used in the 'b' (batch capture) command for indicating whether to use fixed
101  * or random message.
102  */
103 static bool run_fixed = true;
104 
105 /**
106  * Masking indicator.
107  *
108  * Used in the 'b' (batch capture) command for indicating whether to use masks.
109  */
110 static bool en_masks = false;
111 
112 /**
113  * Seed value.
114  *
115  * The default value corresponds to the test data in
116  * sw/otbn/crypto/test/p256_key_from_seed_test.s
117  *
118  * This default value can be overwritten via the simpleserial command `x`
119  * (see ecc256_set_seed)
120  */
121 uint32_t ecc256_seed[kEcc256SeedNumWords] = {
122  0x016064e9, 0x11e3f4d6, 0xac3a6fa7, 0xaba11a1b, 0x8f9271d1,
123  0x22b79d5f, 0x1176f31d, 0xb5ac3a51, 0x99a082d7, 0x484eb366,
124 };
125 
126 uint32_t ecc256_C[kEcc256SeedNumWords] = {
127  0x016064e9, 0x11e3f4d6, 0xac3a6fa7, 0xaba11a1b, 0x8f9271d1,
128  0x22b79d5f, 0x1176f31d, 0xb5ac3a51, 0x99a082d7, 0x484eb366,
129 };
130 
131 uint32_t random_number[kEcc256CoordNumWords] = {
132  0x016064e9, 0x11e3f4d6, 0xac3a6fa7, 0xaba11a1b,
133  0x22b79d5f, 0x1176f31d, 0xb5ac3a51, 0x99a082d7,
134 };
135 
136 uint32_t ecc256_fixed_number[kEcc256CoordNumWords] = {
137  0x04030201, 0x00000000, 0x00000000, 0x00000000,
138  0x00000000, 0x00000000, 0x00000000, 0x00000000,
139 };
140 
141 void ecc256_en_masks(const uint8_t *enable, size_t enable_len) {
142  SS_CHECK(enable_len == 1);
143  if (*enable) {
144  en_masks = true;
145  } else {
146  en_masks = false;
147  }
148 }
149 
150 /**
151  * Simple serial 'x' (set seed) command handler.
152  *
153  * The seed must be `kEcc256SeedNumBytes` bytes long.
154  *
155  * @param seed Value for seed share.
156  * @param seed_len Length of seed share.
157  */
158 void ecc256_set_seed(const uint8_t *seed, size_t seed_len) {
159  SS_CHECK(seed_len == kEcc256SeedNumBytes);
160  memcpy(ecc256_seed, seed, seed_len);
161  // Run PRNG once to synch with capture side. There it is used also to
162  // generate the fixed seed.
163  uint32_t temp[kEcc256SeedNumWords];
164  prng_rand_bytes((unsigned char *)temp, kEcc256SeedNumBytes);
165 }
166 
167 /**
168  * Simple serial 'c' (set constant) command handler.
169  *
170  * The constant must be `kEcc256SeedNumBytes` bytes long.
171  *
172  * @param C Value of the C constant.
173  * @param len Length of the C constant.
174  */
175 void ecc256_set_c(const uint8_t *C, size_t len) {
176  SS_CHECK(len == kEcc256SeedNumBytes);
177  memcpy(ecc256_C, C, len);
178 }
179 
180 /**
181  * Callback wrapper for OTBN manual trigger function.
182  */
183 static void otbn_manual_trigger(void) { SS_CHECK_STATUS_OK(otbn_execute()); }
184 
185 /**
186  * Runs the OTBN key generation program.
187  *
188  * The seed shares must be `kEcc256SeedNumWords` words long.
189  *
190  * @param[in] mode Mode parameter (private key only or full keypair).
191  * @param[in] seed Seed for key generation.
192  * @param[in] mask Mask for seed.
193  */
194 static void p256_run_keygen(uint32_t mode, const uint32_t *share0,
195  const uint32_t *share1) {
196  // Write mode.
197  SS_CHECK_STATUS_OK(otbn_dmem_write(/*num_words=*/1, &mode, kOtbnVarMode));
198 
199  // Write seed shares.
201  otbn_dmem_write(kEcc256SeedNumWords, share0, kOtbnVarSeed0));
203  otbn_dmem_write(kEcc256SeedNumWords, share1, kOtbnVarSeed1));
204 
205  // Execute program.
206  pentest_set_trigger_high();
207  pentest_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles, false,
208  false);
209  SS_CHECK_STATUS_OK(otbn_busy_wait_for_done());
210  pentest_set_trigger_low();
211 }
212 
213 void ecc256_ecdsa_keygen_fvsr_seed_batch(const uint8_t *data, size_t data_len) {
214  uint32_t num_traces = 0;
215  uint32_t batch_digest[kEcc256SeedNumWords];
216  uint8_t dummy[kEcc256SeedNumBytes];
217  SS_CHECK(data_len == sizeof(num_traces));
218  num_traces = read_32(data);
219 
220  if (num_traces > kNumBatchOpsMax) {
221  LOG_ERROR("Too many traces for one batch.");
222  return;
223  }
224 
225  // zero the batch digest
226  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
227  batch_digest[j] = 0;
228  }
229 
230  for (uint32_t i = 0; i < num_traces; ++i) {
231  if (run_fixed) {
232  memcpy(batch_share0[i], ecc256_seed, kEcc256SeedNumBytes);
233  } else {
234  prng_rand_bytes((unsigned char *)batch_share0[i], kEcc256SeedNumBytes);
235  }
236  if (en_masks) {
237  prng_rand_bytes((unsigned char *)batch_share1[i], kEcc256SeedNumBytes);
238  } else {
239  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
240  batch_share1[i][j] = 0;
241  }
242  }
243  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
244  batch_share0[i][j] ^= batch_share1[i][j];
245  }
246  // Another PRNG run to determine 'run_fixed' for the next cycle.
247  prng_rand_bytes(dummy, kEcc256SeedNumBytes);
248  run_fixed = dummy[0] & 0x1;
249  }
250 
251  for (uint32_t i = 0; i < num_traces; ++i) {
252  p256_run_keygen(kEcc256ModePrivateKeyOnly, batch_share0[i],
253  batch_share1[i]);
254 
255  // Read results.
257  otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0_batch));
259  otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1_batch));
260 
261  // The correctness of each batch is verified by computing and sending
262  // the batch digest. This digest is computed by XORing all d0 shares of
263  // the batch.
264  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
265  batch_digest[j] ^= d0_batch[j];
266  }
267  }
268 
269  // Send the batch digest to the host for verification.
270  simple_serial_send_packet('r', (uint8_t *)batch_digest,
271  kEcc256SeedNumWords * 4);
272 }
273 
274 /**
275  * Adds two integers storred in byte arrays.
276  *
277  * Adds the integer stored in source array to the integer stored in
278  * destination aray.
279  * The user needs to ensure that dest_len isenough to store the result
280  * without overflow.
281  *
282  * @param[in] dest Location of the first input array and the result.
283  * @param[in] source Location of the second input array.
284  * @param[in] dest_len Length od the dest array in bytes.
285  * @param[in] source_len Length of the source array in bytes.
286  */
287 static void add_arrays(uint8_t *dest, uint8_t *source, size_t dest_len,
288  size_t source_len) {
289  uint16_t temp = 0;
290 
291  for (size_t i = 0; i < source_len; i++) {
292  temp += (uint16_t)source[i] + dest[i];
293  dest[i] = (uint8_t)(temp & 0x00FF);
294  temp >>= 8;
295  }
296 
297  for (size_t i = source_len; i < dest_len; i++) {
298  temp += (uint16_t)dest[i];
299  dest[i] = (uint8_t)(temp & 0x00FF);
300  temp >>= 8;
301  }
302 }
303 
304 void ecc256_ecdsa_keygen_fvsr_key_batch(const uint8_t *data, size_t data_len) {
305  uint32_t num_traces = 0;
306  uint32_t batch_digest[kEcc256SeedNumWords];
307  uint8_t dummy[kEcc256SeedNumBytes];
308  SS_CHECK(data_len == sizeof(num_traces));
309  num_traces = read_32(data);
310 
311  if (num_traces > kNumBatchOpsMax) {
312  LOG_ERROR("Too many traces for one batch.");
313  return;
314  }
315 
316  // zero the batch digest
317  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
318  batch_digest[j] = 0;
319  }
320 
321  for (uint32_t i = 0; i < num_traces; ++i) {
322  if (run_fixed) {
323  memcpy(batch_share0[i], ecc256_seed, kEcc256SeedNumBytes);
324  } else {
325  // Here change to random_number + C
326  // It is necessary to set the C first
327  memcpy(batch_share0[i], ecc256_C, kEcc256SeedNumBytes);
328  prng_rand_bytes((unsigned char *)random_number, kEcc256CoordNumBytes);
329  add_arrays((unsigned char *)batch_share0[i],
330  (unsigned char *)random_number, kEcc256SeedNumBytes,
331  kEcc256CoordNumBytes);
332  }
333  if (en_masks) {
334  prng_rand_bytes((unsigned char *)batch_share1[i], kEcc256SeedNumBytes);
335  } else {
336  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
337  batch_share1[i][j] = 0;
338  }
339  }
340  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
341  batch_share0[i][j] ^= batch_share1[i][j];
342  }
343  // Another PRNG run to determine 'run_fixed' for the next cycle.
344  prng_rand_bytes(dummy, kEcc256SeedNumBytes);
345 
346  run_fixed = dummy[0] & 0x1;
347  }
348 
349  for (uint32_t i = 0; i < num_traces; ++i) {
350  p256_run_keygen(kEcc256ModePrivateKeyOnly, batch_share0[i],
351  batch_share1[i]);
352 
353  // Read results.
355  otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0_batch));
357  otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1_batch));
358 
359  // The correctness of each batch is verified by computing and sending
360  // the batch digest. This digest is computed by XORing all d0 shares of
361  // the batch.
362  for (uint32_t j = 0; j < kEcc256SeedNumWords; ++j) {
363  batch_digest[j] ^= d0_batch[j];
364  }
365  }
366  // Send the batch digest to the host for verification.
367  simple_serial_send_packet('r', (uint8_t *)batch_digest,
368  kEcc256SeedNumWords * 4);
369 }
370 
371 /**
372  * Generates a secret key from a masked seed.
373  *
374  * The seed shares must be `kEcc256SeedNumWords` words long, and the caller
375  * must provide pre-allocated buffers of the same length for the private key
376  * shares.
377  *
378  * @param[in] seed Seed for key generation.
379  * @param[in] mask Mask for seed.
380  * @param[out] d0 First share of masked private key d.
381  * @param[out] d1 Second share of masked private key d.
382  */
383 static void p256_ecdsa_gen_secret_key(const uint32_t *seed,
384  const uint32_t *mask, uint32_t *d0,
385  uint32_t *d1) {
386  // Compute first share of seed (seed ^ mask).
387  uint32_t share0[kEcc256SeedNumWords];
388  for (size_t i = 0; i < kEcc256SeedNumWords; i++) {
389  share0[i] = seed[i] ^ mask[i];
390  }
391 
392  // Run the key generation program.
393  p256_run_keygen(kEcc256ModePrivateKeyOnly, share0, mask);
394 
395  // Read results.
396  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0));
397  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1));
398 }
399 
400 /**
401  * Generates a keypair from a masked seed.
402  *
403  * The seed shares must be `kEcc256SeedNumWords` words long, and the caller
404  * must provide pre-allocated buffers of the same length for the private key
405  * shares and of length `kEcc256CoordNumWords` for the public key coordinates.
406  *
407  * @param[in] seed Seed for key generation.
408  * @param[in] mask Mask for seed.
409  * @param[out] d0 First share of masked private key d.
410  * @param[out] d1 Second share of masked private key d.
411  * @param[out] x x-coordinate of public key Q.
412  * @param[out] y y-coordinate of public key Q.
413  */
414 static void p256_ecdsa_gen_keypair(const uint32_t *seed, const uint32_t *mask,
415  uint32_t *d0, uint32_t *d1, uint32_t *x,
416  uint32_t *y) {
417  // Compute the first share of the seed (seed ^ mask).
418  uint32_t share0[kEcc256SeedNumWords];
419  for (size_t i = 0; i < kEcc256SeedNumWords; i++) {
420  share0[i] = seed[i] ^ mask[i];
421  }
422 
423  // Run the key generation program.
424  p256_run_keygen(kEcc256ModeKeypair, share0, mask);
425 
426  // Read results.
427  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD0, d0));
428  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256SeedNumWords, kOtbnVarD1, d1));
429  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256CoordNumWords, kOtbnVarX, x));
430  SS_CHECK_STATUS_OK(otbn_dmem_read(kEcc256CoordNumWords, kOtbnVarY, y));
431 }
432 
433 void ecc256_ecdsa_secret_keygen(const uint8_t *mask, size_t mask_len) {
434  if (mask_len != kEcc256SeedNumBytes) {
435  LOG_ERROR("Invalid mask length %hu", (uint8_t)mask_len);
436  return;
437  }
438 
439  // Copy mask to an aligned buffer.
440  uint32_t ecc256_mask[kEcc256SeedNumWords];
441  memcpy(ecc256_mask, mask, kEcc256SeedNumBytes);
442 
443  uint32_t ecc256_d0[kEcc256SeedNumWords];
444  uint32_t ecc256_d1[kEcc256SeedNumWords];
445  p256_ecdsa_gen_secret_key(ecc256_seed, ecc256_mask, ecc256_d0, ecc256_d1);
446 
447  simple_serial_send_packet('r', (unsigned char *)ecc256_d0,
448  kEcc256SeedNumBytes);
449  simple_serial_send_packet('r', (unsigned char *)ecc256_d1,
450  kEcc256SeedNumBytes);
451 }
452 
453 void ecc256_ecdsa_gen_keypair(const uint8_t *mask, size_t mask_len) {
454  if (mask_len != kEcc256SeedNumBytes) {
455  LOG_ERROR("Invalid mask length %hu", (uint8_t)mask_len);
456  return;
457  }
458 
459  // Copy mask to an aligned buffer.
460  uint32_t ecc256_mask[kEcc256SeedNumWords];
461  memcpy(ecc256_mask, mask, kEcc256SeedNumBytes);
462 
463  uint32_t ecc256_d0[kEcc256SeedNumWords];
464  uint32_t ecc256_d1[kEcc256SeedNumWords];
465  uint32_t ecc256_x[kEcc256CoordNumWords];
466  uint32_t ecc256_y[kEcc256CoordNumWords];
467  p256_ecdsa_gen_keypair(ecc256_seed, ecc256_mask, ecc256_d0, ecc256_d1,
468  ecc256_x, ecc256_y);
469 
470  simple_serial_send_packet('r', (unsigned char *)ecc256_d0,
471  kEcc256SeedNumBytes);
472  simple_serial_send_packet('r', (unsigned char *)ecc256_d1,
473  kEcc256SeedNumBytes);
474  simple_serial_send_packet('r', (unsigned char *)ecc256_x,
475  kEcc256CoordNumBytes);
476  simple_serial_send_packet('r', (unsigned char *)ecc256_y,
477  kEcc256CoordNumBytes);
478 }