Skip to content

Commit 78fe627

Browse files
siemen11nasahlpa
authored andcommitted
[crypto/test] Use key import/export in ecdh
Use the key import/export functions in the ecdh functests (p256 and p384) and in the kat firmware. Show the user how to use the API calls from the cryptolib to move from unshared keys, to the API, back to unshared outputs. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent b3d6da0 commit 78fe627

5 files changed

Lines changed: 151 additions & 76 deletions

File tree

sw/device/tests/crypto/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,12 @@ opentitan_test(
458458
timeout = "eternal",
459459
),
460460
deps = [
461+
"//sw/device/lib/base:hardened_memory",
461462
"//sw/device/lib/crypto/drivers:otbn",
462463
"//sw/device/lib/crypto/impl:config",
463464
"//sw/device/lib/crypto/impl:ecc_p256",
464465
"//sw/device/lib/crypto/impl:entropy_src",
466+
"//sw/device/lib/crypto/impl:key_transport",
465467
"//sw/device/lib/runtime:log",
466468
"//sw/device/lib/testing/test_framework:ottf_main",
467469
],
@@ -478,10 +480,12 @@ opentitan_test(
478480
tags = ["manual"],
479481
),
480482
deps = [
483+
"//sw/device/lib/base:hardened_memory",
481484
"//sw/device/lib/crypto/drivers:otbn",
482485
"//sw/device/lib/crypto/impl:config",
483486
"//sw/device/lib/crypto/impl:ecc_p384",
484487
"//sw/device/lib/crypto/impl:entropy_src",
488+
"//sw/device/lib/crypto/impl:key_transport",
485489
"//sw/device/lib/runtime:log",
486490
"//sw/device/lib/testing/test_framework:ottf_main",
487491
],

sw/device/tests/crypto/cryptotest/firmware/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ cc_library(
6262
srcs = ["ecdh.c"],
6363
hdrs = ["ecdh.h"],
6464
deps = [
65+
"//sw/device/lib/base:hardened_memory",
6566
"//sw/device/lib/base:memory",
6667
"//sw/device/lib/base:status",
6768
"//sw/device/lib/crypto",

sw/device/tests/crypto/cryptotest/firmware/ecdh.c

Lines changed: 99 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "sw/device/lib/base/hardened_memory.h"
56
#include "sw/device/lib/base/memory.h"
67
#include "sw/device/lib/crypto/include/datatypes.h"
78
#include "sw/device/lib/crypto/include/ecc_p256.h"
@@ -75,7 +76,7 @@ enum {
7576
*
7677
* @param d Private key.
7778
* @param qx Public key x coordinate.
78-
* @param qx Public key y coordinate.
79+
* @param qy Public key y coordinate.
7980
* @param[out] ss Shared secret key.
8081
* @param[out] valid Whether the input arguments were valid.
8182
* @return Status code (OK or error).
@@ -102,11 +103,7 @@ static status_t ecdh_p256(cryptotest_ecdh_private_key_t d,
102103
}
103104

104105
// Construct the private key object.
105-
// TODO(#20762): once key-import exists for ECDH, use that instead.
106106
uint32_t private_keyblob[kP256MaskedPrivateKeyWords * 2];
107-
memset(private_keyblob, 0, sizeof(private_keyblob));
108-
memcpy(private_keyblob, d.d0, d.d0_len);
109-
memcpy(private_keyblob + kP256MaskedPrivateKeyWords, d.d1, d.d1_len);
110107
otcrypto_blinded_key_t private_key = {
111108
.config =
112109
{
@@ -120,21 +117,54 @@ static status_t ecdh_p256(cryptotest_ecdh_private_key_t d,
120117
.keyblob_length = sizeof(private_keyblob),
121118
.keyblob = private_keyblob,
122119
};
123-
private_key.checksum = integrity_blinded_checksum(&private_key);
120+
121+
uint32_t p256_share0_data[kP256MaskedPrivateKeyWords] = {0};
122+
uint32_t p256_share1_data[kP256MaskedPrivateKeyWords] = {0};
123+
memcpy(p256_share0_data, d.d0, d.d0_len);
124+
memcpy(p256_share1_data, d.d1, d.d1_len);
125+
126+
otcrypto_const_word32_buf_t share0 =
127+
OTCRYPTO_MAKE_BUF(otcrypto_const_word32_buf_t, p256_share0_data,
128+
kP256MaskedPrivateKeyWords);
129+
otcrypto_const_word32_buf_t share1 =
130+
OTCRYPTO_MAKE_BUF(otcrypto_const_word32_buf_t, p256_share1_data,
131+
kP256MaskedPrivateKeyWords);
132+
133+
otcrypto_status_t priv_status =
134+
otcrypto_ecc_p256_private_key_import(share0, share1, &private_key);
135+
if (priv_status.value == kOtcryptoStatusValueBadArgs) {
136+
*valid = false;
137+
memset(ss, 0, kP256SharedSecretBytes);
138+
return OK_STATUS();
139+
}
140+
TRY(priv_status);
124141

125142
// Construct the public key object.
126-
// TODO(#20762): once key-import exists for ECDH, use that instead.
127143
uint32_t public_key_buf[kP256CoordinateWords * 2];
128-
memset(public_key_buf, 0, sizeof(public_key_buf));
129-
memcpy(public_key_buf, qx.coordinate, qx.coordinate_len);
130-
memcpy(public_key_buf + kP256CoordinateWords, qy.coordinate,
131-
qy.coordinate_len);
132144
otcrypto_unblinded_key_t public_key = {
133145
.key_mode = kOtcryptoKeyModeEcdhP256,
134146
.key_length = sizeof(public_key_buf),
135147
.key = public_key_buf,
136148
};
137-
public_key.checksum = integrity_unblinded_checksum(&public_key);
149+
150+
uint32_t p256_x_data[kP256CoordinateWords] = {0};
151+
uint32_t p256_y_data[kP256CoordinateWords] = {0};
152+
memcpy(p256_x_data, qx.coordinate, qx.coordinate_len);
153+
memcpy(p256_y_data, qy.coordinate, qy.coordinate_len);
154+
155+
otcrypto_const_word32_buf_t x = OTCRYPTO_MAKE_BUF(
156+
otcrypto_const_word32_buf_t, p256_x_data, kP256CoordinateWords);
157+
otcrypto_const_word32_buf_t y = OTCRYPTO_MAKE_BUF(
158+
otcrypto_const_word32_buf_t, p256_y_data, kP256CoordinateWords);
159+
160+
otcrypto_status_t pub_status =
161+
otcrypto_ecc_p256_public_key_import(x, y, &public_key);
162+
if (pub_status.value == kOtcryptoStatusValueBadArgs) {
163+
*valid = false;
164+
memset(ss, 0, kP256SharedSecretBytes);
165+
return OK_STATUS();
166+
}
167+
TRY(pub_status);
138168

139169
// Create a destination for the shared secret.
140170
size_t shared_secret_words = kP256SharedSecretBytes / sizeof(uint32_t);
@@ -174,16 +204,14 @@ static status_t ecdh_p256(cryptotest_ecdh_private_key_t d,
174204
}
175205

176206
// Unmask the shared secret.
177-
uint32_t share0[shared_secret_words];
178-
uint32_t share1[shared_secret_words];
179-
otcrypto_word32_buf_t share0_buf =
180-
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, share0, ARRAYSIZE(share0));
181-
otcrypto_word32_buf_t share1_buf =
182-
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, share1, ARRAYSIZE(share1));
207+
uint32_t dest_share0[shared_secret_words];
208+
uint32_t dest_share1[shared_secret_words];
209+
otcrypto_word32_buf_t share0_buf = OTCRYPTO_MAKE_BUF(
210+
otcrypto_word32_buf_t, dest_share0, ARRAYSIZE(dest_share0));
211+
otcrypto_word32_buf_t share1_buf = OTCRYPTO_MAKE_BUF(
212+
otcrypto_word32_buf_t, dest_share1, ARRAYSIZE(dest_share1));
183213
TRY(otcrypto_export_blinded_key(&shared_secret, &share0_buf, &share1_buf));
184-
for (size_t i = 0; i < shared_secret_words; i++) {
185-
ss[i] = share0[i] ^ share1[i];
186-
}
214+
TRY(hardened_xor(dest_share0, dest_share1, shared_secret_words, ss));
187215
return OK_STATUS();
188216
}
189217

@@ -198,7 +226,7 @@ static status_t ecdh_p256(cryptotest_ecdh_private_key_t d,
198226
*
199227
* @param d Private key.
200228
* @param qx Public key x coordinate.
201-
* @param qx Public key y coordinate.
229+
* @param qy Public key y coordinate.
202230
* @param[out] ss Shared secret key.
203231
* @param[out] valid Whether the input arguments were valid.
204232
* @return Status code (OK or error).
@@ -225,13 +253,7 @@ static status_t ecdh_p384(cryptotest_ecdh_private_key_t d,
225253
}
226254

227255
// Construct the private key object.
228-
// TODO(#20762): once key-import exists for ECDH, use that instead.
229-
// Note: the test harness does not produce the extra masking bytes; leave
230-
// them zeroed.
231256
uint32_t private_keyblob[kP384MaskedPrivateKeyWords * 2];
232-
memset(private_keyblob, 0, sizeof(private_keyblob));
233-
memcpy(private_keyblob, d.d0, d.d0_len);
234-
memcpy(private_keyblob + kP384MaskedPrivateKeyWords, d.d1, d.d1_len);
235257
otcrypto_blinded_key_t private_key = {
236258
.config =
237259
{
@@ -245,21 +267,56 @@ static status_t ecdh_p384(cryptotest_ecdh_private_key_t d,
245267
.keyblob_length = sizeof(private_keyblob),
246268
.keyblob = private_keyblob,
247269
};
248-
private_key.checksum = integrity_blinded_checksum(&private_key);
270+
271+
// Note: the test harness might not produce the extra masking bytes; leaving
272+
// them safely zeroed by explicitly copying into padded buffers.
273+
uint32_t p384_share0_data[kP384MaskedPrivateKeyWords] = {0};
274+
uint32_t p384_share1_data[kP384MaskedPrivateKeyWords] = {0};
275+
memcpy(p384_share0_data, d.d0, d.d0_len);
276+
memcpy(p384_share1_data, d.d1, d.d1_len);
277+
278+
otcrypto_const_word32_buf_t share0 =
279+
OTCRYPTO_MAKE_BUF(otcrypto_const_word32_buf_t, p384_share0_data,
280+
kP384MaskedPrivateKeyWords);
281+
otcrypto_const_word32_buf_t share1 =
282+
OTCRYPTO_MAKE_BUF(otcrypto_const_word32_buf_t, p384_share1_data,
283+
kP384MaskedPrivateKeyWords);
284+
285+
otcrypto_status_t priv_status =
286+
otcrypto_ecc_p384_private_key_import(share0, share1, &private_key);
287+
if (priv_status.value == kOtcryptoStatusValueBadArgs) {
288+
*valid = false;
289+
memset(ss, 0, kP384SharedSecretBytes);
290+
return OK_STATUS();
291+
}
292+
TRY(priv_status);
249293

250294
// Construct the public key object.
251-
// TODO(#20762): once key-import exists for ECDH, use that instead.
252295
uint32_t public_key_buf[kP384CoordinateWords * 2];
253-
memset(public_key_buf, 0, sizeof(public_key_buf));
254-
memcpy(public_key_buf, qx.coordinate, qx.coordinate_len);
255-
memcpy(public_key_buf + kP384CoordinateWords, qy.coordinate,
256-
qy.coordinate_len);
257296
otcrypto_unblinded_key_t public_key = {
258297
.key_mode = kOtcryptoKeyModeEcdhP384,
259298
.key_length = sizeof(public_key_buf),
260299
.key = public_key_buf,
261300
};
262-
public_key.checksum = integrity_unblinded_checksum(&public_key);
301+
302+
uint32_t p384_x_data[kP384CoordinateWords] = {0};
303+
uint32_t p384_y_data[kP384CoordinateWords] = {0};
304+
memcpy(p384_x_data, qx.coordinate, qx.coordinate_len);
305+
memcpy(p384_y_data, qy.coordinate, qy.coordinate_len);
306+
307+
otcrypto_const_word32_buf_t x = OTCRYPTO_MAKE_BUF(
308+
otcrypto_const_word32_buf_t, p384_x_data, kP384CoordinateWords);
309+
otcrypto_const_word32_buf_t y = OTCRYPTO_MAKE_BUF(
310+
otcrypto_const_word32_buf_t, p384_y_data, kP384CoordinateWords);
311+
312+
otcrypto_status_t pub_status =
313+
otcrypto_ecc_p384_public_key_import(x, y, &public_key);
314+
if (pub_status.value == kOtcryptoStatusValueBadArgs) {
315+
*valid = false;
316+
memset(ss, 0, kP384SharedSecretBytes);
317+
return OK_STATUS();
318+
}
319+
TRY(pub_status);
263320

264321
// Create a destination for the shared secret.
265322
size_t shared_secret_words = kP384SharedSecretBytes / sizeof(uint32_t);
@@ -299,16 +356,14 @@ static status_t ecdh_p384(cryptotest_ecdh_private_key_t d,
299356
}
300357

301358
// Unmask the shared secret.
302-
uint32_t share0[shared_secret_words];
303-
uint32_t share1[shared_secret_words];
304-
otcrypto_word32_buf_t share0_buf =
305-
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, share0, ARRAYSIZE(share0));
306-
otcrypto_word32_buf_t share1_buf =
307-
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, share1, ARRAYSIZE(share1));
359+
uint32_t dest_share0[shared_secret_words];
360+
uint32_t dest_share1[shared_secret_words];
361+
otcrypto_word32_buf_t share0_buf = OTCRYPTO_MAKE_BUF(
362+
otcrypto_word32_buf_t, dest_share0, ARRAYSIZE(dest_share0));
363+
otcrypto_word32_buf_t share1_buf = OTCRYPTO_MAKE_BUF(
364+
otcrypto_word32_buf_t, dest_share1, ARRAYSIZE(dest_share1));
308365
TRY(otcrypto_export_blinded_key(&shared_secret, &share0_buf, &share1_buf));
309-
for (size_t i = 0; i < shared_secret_words; i++) {
310-
ss[i] = share0[i] ^ share1[i];
311-
}
366+
TRY(hardened_xor(dest_share0, dest_share1, shared_secret_words, ss));
312367
return OK_STATUS();
313368
}
314369

sw/device/tests/crypto/ecdh_p256_functest.c

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
#include "sw/device/lib/base/hardened_memory.h"
56
#include "sw/device/lib/crypto/drivers/otbn.h"
67
#include "sw/device/lib/crypto/impl/keyblob.h"
78
#include "sw/device/lib/crypto/include/config.h"
89
#include "sw/device/lib/crypto/include/ecc_p256.h"
910
#include "sw/device/lib/crypto/include/entropy_src.h"
1011
#include "sw/device/lib/crypto/include/integrity.h"
12+
#include "sw/device/lib/crypto/include/key_transport.h"
1113
#include "sw/device/lib/runtime/log.h"
1214
#include "sw/device/lib/testing/test_framework/check.h"
1315
#include "sw/device/lib/testing/test_framework/ottf_main.h"
@@ -31,17 +33,17 @@ static const otcrypto_key_config_t kEcdhPrivateKeyConfig = {
3133
.key_mode = kOtcryptoKeyModeEcdhP256,
3234
.key_length = kP256PrivateKeyBytes,
3335
.hw_backed = kHardenedBoolFalse,
36+
.exportable = kHardenedBoolFalse,
3437
.security_level = kOtcryptoKeySecurityLevelLow,
3538
};
3639

37-
// Configuration for the ECDH shared (symmetric) key. This configuration
38-
// specifies an AES key, but any symmetric mode that supports 256-bit keys is
39-
// OK here.
40+
// Configuration for the ECDH shared (symmetric) key.
4041
static const otcrypto_key_config_t kEcdhSharedKeyConfig = {
4142
.version = kOtcryptoLibVersion1,
4243
.key_mode = kOtcryptoKeyModeAesCtr,
4344
.key_length = kP256SharedKeyBytes,
4445
.hw_backed = kHardenedBoolFalse,
46+
.exportable = kHardenedBoolTrue,
4547
.security_level = kOtcryptoKeySecurityLevelLow,
4648
};
4749

@@ -87,47 +89,51 @@ status_t key_exchange_test(void) {
8789
// Sanity check; public keys should be different from each other.
8890
CHECK_ARRAYS_NE(pkA, pkB, ARRAYSIZE(pkA));
8991

90-
// Allocate space for two shared keys.
91-
uint32_t shared_keyblobA[keyblob_num_words(kEcdhSharedKeyConfig)];
92+
uint32_t shared_keyblobA[kP256SharedKeyWords * 2];
9293
otcrypto_blinded_key_t shared_keyA = {
9394
.config = kEcdhSharedKeyConfig,
9495
.keyblob_length = sizeof(shared_keyblobA),
9596
.keyblob = shared_keyblobA,
9697
.checksum = 0,
9798
};
98-
uint32_t shared_keyblobB[keyblob_num_words(kEcdhSharedKeyConfig)];
99+
uint32_t shared_keyblobB[kP256SharedKeyWords * 2];
99100
otcrypto_blinded_key_t shared_keyB = {
100101
.config = kEcdhSharedKeyConfig,
101102
.keyblob_length = sizeof(shared_keyblobB),
102103
.keyblob = shared_keyblobB,
103104
.checksum = 0,
104105
};
105106

106-
// Compute the shared secret from A's side of the computation (using A's
107-
// private key and B's public key).
107+
// Compute the shared secret from A's side of the computation.
108108
LOG_INFO("Generating shared secret (A)...");
109109
TRY(otcrypto_ecdh_p256(&private_keyA, &public_keyB, &shared_keyA));
110110

111-
// Compute the shared secret from B's side of the computation (using B's
112-
// private key and A's public key).
111+
// Compute the shared secret from B's side of the computation.
113112
LOG_INFO("Generating shared secret (B)...");
114113
TRY(otcrypto_ecdh_p256(&private_keyB, &public_keyA, &shared_keyB));
115114

116115
// Get pointers to individual shares of both shared keys.
117-
uint32_t *keyA0;
118-
uint32_t *keyA1;
119-
TRY(keyblob_to_shares(&shared_keyA, &keyA0, &keyA1));
120-
uint32_t *keyB0;
121-
uint32_t *keyB1;
122-
TRY(keyblob_to_shares(&shared_keyB, &keyB0, &keyB1));
116+
uint32_t keyA0[kP256SharedKeyWords];
117+
uint32_t keyA1[kP256SharedKeyWords];
118+
otcrypto_word32_buf_t keyA0_buf =
119+
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, keyA0, ARRAYSIZE(keyA0));
120+
otcrypto_word32_buf_t keyA1_buf =
121+
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, keyA1, ARRAYSIZE(keyA1));
122+
TRY(otcrypto_export_blinded_key(&shared_keyA, &keyA0_buf, &keyA1_buf));
123+
124+
uint32_t keyB0[kP256SharedKeyWords];
125+
uint32_t keyB1[kP256SharedKeyWords];
126+
otcrypto_word32_buf_t keyB0_buf =
127+
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, keyB0, ARRAYSIZE(keyB0));
128+
otcrypto_word32_buf_t keyB1_buf =
129+
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, keyB1, ARRAYSIZE(keyB1));
130+
TRY(otcrypto_export_blinded_key(&shared_keyB, &keyB0_buf, &keyB1_buf));
123131

124132
// Unmask the keys and check that they match.
125133
uint32_t keyA[kP256SharedKeyWords];
126134
uint32_t keyB[kP256SharedKeyWords];
127-
for (size_t i = 0; i < ARRAYSIZE(keyA); i++) {
128-
keyA[i] = keyA0[i] ^ keyA1[i];
129-
keyB[i] = keyB0[i] ^ keyB1[i];
130-
}
135+
TRY(hardened_xor(keyA0, keyA1, kP256SharedKeyWords, keyA));
136+
TRY(hardened_xor(keyB0, keyB1, kP256SharedKeyWords, keyB));
131137
CHECK_ARRAYS_EQ(keyA, keyB, ARRAYSIZE(keyA));
132138

133139
return OTCRYPTO_OK;

0 commit comments

Comments
 (0)