Software APIs
ecdh_p256_functest.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/lib/crypto/drivers/otbn.h"
6 #include "sw/device/lib/crypto/impl/keyblob.h"
9 #include "sw/device/lib/testing/entropy_testutils.h"
10 #include "sw/device/lib/testing/test_framework/check.h"
12 
13 enum {
14  /* Number of 32-bit words in a P-256 public key. */
15  kP256PublicKeyWords = 512 / 32,
16  /* Number of 32-bit words in a P-256 signature. */
17  kP256SignatureWords = 512 / 32,
18  /* Number of bytes in a P-256 private key. */
19  kP256PrivateKeyBytes = 256 / 8,
20  /* Number of bytes in an ECDH/P-256 shared key. */
21  kP256SharedKeyBytes = 256 / 8,
22  /* Number of 32-bit words in an ECDH/P-256 shared key. */
23  kP256SharedKeyWords = kP256SharedKeyBytes / sizeof(uint32_t),
24 };
25 
26 // Configuration for the private key.
27 static const otcrypto_key_config_t kEcdhPrivateKeyConfig = {
28  .version = kOtcryptoLibVersion1,
29  .key_mode = kOtcryptoKeyModeEcdhP256,
30  .key_length = kP256PrivateKeyBytes,
31  .hw_backed = kHardenedBoolFalse,
32  .security_level = kOtcryptoKeySecurityLevelLow,
33 };
34 
35 // Configuration for the ECDH shared (symmetric) key. This configuration
36 // specifies an AES key, but any symmetric mode that supports 256-bit keys is
37 // OK here.
38 static const otcrypto_key_config_t kEcdhSharedKeyConfig = {
39  .version = kOtcryptoLibVersion1,
40  .key_mode = kOtcryptoKeyModeAesCtr,
41  .key_length = kP256SharedKeyBytes,
42  .hw_backed = kHardenedBoolFalse,
43  .security_level = kOtcryptoKeySecurityLevelLow,
44 };
45 
46 status_t key_exchange_test(void) {
47  // Allocate space for two private keys.
48  uint32_t keyblobA[keyblob_num_words(kEcdhPrivateKeyConfig)];
49  otcrypto_blinded_key_t private_keyA = {
50  .config = kEcdhPrivateKeyConfig,
51  .keyblob_length = sizeof(keyblobA),
52  .keyblob = keyblobA,
53  .checksum = 0,
54  };
55  uint32_t keyblobB[keyblob_num_words(kEcdhPrivateKeyConfig)];
56  otcrypto_blinded_key_t private_keyB = {
57  .config = kEcdhPrivateKeyConfig,
58  .keyblob_length = sizeof(keyblobB),
59  .keyblob = keyblobB,
60  .checksum = 0,
61  };
62 
63  // Allocate space for two public keys.
64  uint32_t pkA[kP256PublicKeyWords] = {0};
65  uint32_t pkB[kP256PublicKeyWords] = {0};
66  otcrypto_unblinded_key_t public_keyA = {
67  .key_mode = kOtcryptoKeyModeEcdhP256,
68  .key_length = sizeof(pkA),
69  .key = pkA,
70  };
71  otcrypto_unblinded_key_t public_keyB = {
72  .key_mode = kOtcryptoKeyModeEcdhP256,
73  .key_length = sizeof(pkB),
74  .key = pkB,
75  };
76 
77  // Generate a keypair.
78  LOG_INFO("Generating keypair A...");
79  TRY(otcrypto_ecdh_p256_keygen(&private_keyA, &public_keyA));
80 
81  // Generate a second keypair.
82  LOG_INFO("Generating keypair B...");
83  TRY(otcrypto_ecdh_p256_keygen(&private_keyB, &public_keyB));
84 
85  // Sanity check; public keys should be different from each other.
86  CHECK_ARRAYS_NE(pkA, pkB, ARRAYSIZE(pkA));
87 
88  // Allocate space for two shared keys.
89  uint32_t shared_keyblobA[keyblob_num_words(kEcdhSharedKeyConfig)];
90  otcrypto_blinded_key_t shared_keyA = {
91  .config = kEcdhSharedKeyConfig,
92  .keyblob_length = sizeof(shared_keyblobA),
93  .keyblob = shared_keyblobA,
94  .checksum = 0,
95  };
96  uint32_t shared_keyblobB[keyblob_num_words(kEcdhSharedKeyConfig)];
97  otcrypto_blinded_key_t shared_keyB = {
98  .config = kEcdhSharedKeyConfig,
99  .keyblob_length = sizeof(shared_keyblobB),
100  .keyblob = shared_keyblobB,
101  .checksum = 0,
102  };
103 
104  // Compute the shared secret from A's side of the computation (using A's
105  // private key and B's public key).
106  LOG_INFO("Generating shared secret (A)...");
107  TRY(otcrypto_ecdh_p256(&private_keyA, &public_keyB, &shared_keyA));
108 
109  // Compute the shared secret from B's side of the computation (using B's
110  // private key and A's public key).
111  LOG_INFO("Generating shared secret (B)...");
112  TRY(otcrypto_ecdh_p256(&private_keyB, &public_keyA, &shared_keyB));
113 
114  // Get pointers to individual shares of both shared keys.
115  uint32_t *keyA0;
116  uint32_t *keyA1;
117  TRY(keyblob_to_shares(&shared_keyA, &keyA0, &keyA1));
118  uint32_t *keyB0;
119  uint32_t *keyB1;
120  TRY(keyblob_to_shares(&shared_keyB, &keyB0, &keyB1));
121 
122  // Unmask the keys and check that they match.
123  uint32_t keyA[kP256SharedKeyWords];
124  uint32_t keyB[kP256SharedKeyWords];
125  for (size_t i = 0; i < ARRAYSIZE(keyA); i++) {
126  keyA[i] = keyA0[i] ^ keyA1[i];
127  keyB[i] = keyB0[i] ^ keyB1[i];
128  }
129  CHECK_ARRAYS_EQ(keyA, keyB, ARRAYSIZE(keyA));
130 
131  return OTCRYPTO_OK;
132 }
133 
134 OTTF_DEFINE_TEST_CONFIG();
135 
136 bool test_main(void) {
137  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
138 
139  status_t err = key_exchange_test();
140  if (!status_ok(err)) {
141  // If there was an error, print the OTBN error bits and instruction count.
142  LOG_INFO("OTBN error bits: 0x%08x", otbn_err_bits_get());
143  LOG_INFO("OTBN instruction count: 0x%08x", otbn_instruction_count_get());
144  // Print the error.
145  CHECK_STATUS_OK(err);
146  return false;
147  }
148 
149  return true;
150 }