Skip to content

Commit 5e7e65e

Browse files
siemen11nasahlpa
authored andcommitted
[25519] Move to blinded private keys
The private is shared using subtraction modulo 2^256. Since the seed of the 25519 is a value not modulo the curve order but mod 2^256, this sharing is similar to that of p256. We do not extend the 256-bit sharing further to 320 bits at the API. Change the functest to reflect how the sharing is made. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent 297f7c1 commit 5e7e65e

7 files changed

Lines changed: 304 additions & 109 deletions

File tree

sw/device/lib/crypto/impl/ecc/curve25519.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,56 @@ enum {
8080
* Magic value for verify success response.
8181
*/
8282
kCurve25519VerifySuccess = 0xf77fe650,
83+
/**
84+
* Length of a Curve25519 curve point coordinate in bits.
85+
*/
86+
kCurve25519CoordBits = 256,
87+
/**
88+
* Length of a Curve25519 curve point coordinate in bytes.
89+
*/
90+
kCurve25519CoordBytes = kCurve25519CoordBits / 8,
91+
/**
92+
* Length of a Curve25519 curve point coordinate in words.
93+
*/
94+
kCurve25519CoordWords = kCurve25519CoordBytes / sizeof(uint32_t),
95+
/**
96+
* Length of an element in the Curve25519 scalar field in bits.
97+
*/
98+
kCurve25519ScalarBits = 256,
99+
/**
100+
* Length of a masked secret scalar share.
101+
*
102+
* Ed25519 uses no extra redundant bits for the initial seed sharing.
103+
*/
104+
kCurve25519MaskedScalarShareBits = kCurve25519ScalarBits,
105+
/**
106+
* Length of a masked secret scalar share in bytes.
107+
*/
108+
kCurve25519MaskedScalarShareBytes = kCurve25519MaskedScalarShareBits / 8,
109+
/**
110+
* Length of masked secret scalar share in words.
111+
*/
112+
kCurve25519MaskedScalarShareWords =
113+
kCurve25519MaskedScalarShareBytes / sizeof(uint32_t),
114+
/**
115+
* Number of shares for the scalar.
116+
*/
117+
kCurve25519MaskedScalarNumShares = 2,
118+
/**
119+
* Length of the full masked secret scalar share in bits.
120+
*/
121+
kCurve25519MaskedScalarTotalShareBits =
122+
kCurve25519MaskedScalarNumShares * kCurve25519MaskedScalarShareBits,
123+
/**
124+
* Length of the full masked secret scalar share in bytes.
125+
*/
126+
kCurve25519MaskedScalarTotalShareBytes =
127+
kCurve25519MaskedScalarNumShares * kCurve25519MaskedScalarShareBytes,
128+
/**
129+
* Length of the full masked secret scalar share in words.
130+
*/
131+
kCurve25519MaskedScalarTotalShareWords =
132+
kCurve25519MaskedScalarNumShares * kCurve25519MaskedScalarShareWords,
83133
};
84134

85135
/**

sw/device/lib/crypto/impl/ecc_curve25519.c

Lines changed: 121 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,66 @@ static const uint8_t kDom2Prefix[34] = {
2626
};
2727

2828
/**
29-
* Check the lengths of public/private keys for curve 25519.
29+
* Check the lengths of private keys for curve 25519.
30+
*
31+
* Checks the length of caller-allocated buffers for a 25519 private key.
32+
*
33+
* @param private_key Private key struct to check.
34+
* @return OK if the lengths are correct or BAD_ARGS otherwise.
35+
*/
36+
OT_WARN_UNUSED_RESULT
37+
static status_t ed25519_private_key_length_check(
38+
const otcrypto_blinded_key_t *private_key) {
39+
if (private_key == NULL || private_key->keyblob == NULL) {
40+
return OTCRYPTO_BAD_ARGS;
41+
}
42+
43+
if (private_key->config.hw_backed == kHardenedBoolTrue) {
44+
// Skip the length check in this case; if the salt is the wrong length, the
45+
// keyblob library will catch it before we sideload the key.
46+
return OTCRYPTO_OK;
47+
}
48+
HARDENED_CHECK_NE(launder32(private_key->config.hw_backed),
49+
kHardenedBoolTrue);
50+
51+
// Check the unmasked length.
52+
if (private_key->config.key_length != kCurve25519KeyBytes) {
53+
return OTCRYPTO_BAD_ARGS;
54+
}
55+
HARDENED_CHECK_EQ(launder32(private_key->config.key_length),
56+
kCurve25519KeyBytes);
57+
58+
// Check the key mode.
59+
if (private_key->config.key_mode != kOtcryptoKeyModeEd25519) {
60+
return OTCRYPTO_BAD_ARGS;
61+
}
62+
HARDENED_CHECK_EQ(launder32(private_key->config.key_mode),
63+
kOtcryptoKeyModeEd25519);
64+
65+
// Check the integrity of the key.
66+
if (integrity_blinded_key_check(private_key) != kHardenedBoolTrue) {
67+
return OTCRYPTO_BAD_ARGS;
68+
}
69+
HARDENED_CHECK_EQ(launder32(integrity_blinded_key_check(private_key)),
70+
kHardenedBoolTrue);
71+
72+
return OTCRYPTO_OK;
73+
}
74+
75+
/**
76+
* Check the lengths of public keys for curve 25519.
3077
*
3178
* This function also does some basic checks on the key struct.
3279
*
3380
* Checks the length of caller-allocated buffers for a 25519 unblinded
3481
* key.
3582
*
36-
* @param key Public/private key struct to check.
83+
* @param key Public key struct to check.
3784
* @return OK if the lengths are correct or BAD_ARGS otherwise.
3885
*/
3986
OT_WARN_UNUSED_RESULT
40-
static status_t ed25519_key_check(const otcrypto_unblinded_key_t *key) {
87+
static status_t ed25519_public_key_length_check(
88+
const otcrypto_unblinded_key_t *key) {
4189
// Check the key struct and key length.
4290
if (key == NULL || key->key_length != kCurve25519KeyBytes ||
4391
key->key == NULL || key->key_mode != kOtcryptoKeyModeEd25519) {
@@ -213,16 +261,15 @@ static status_t ed25519_mask_scalar(uint32_t *scalar, size_t scalar_len,
213261
// can be of different sizes, we resort here to a VLA.
214262
uint32_t buf[share_len];
215263
memset(buf, 0, share_len << 2);
216-
HARDENED_TRY(hardened_memshred(buf, scalar_len));
264+
hardened_memshred(buf, scalar_len);
217265
HARDENED_TRY(hardened_memcpy(buf, scalar, scalar_len));
218266

219267
// Set share1 to a random value and unset its MSB.
220268
otcrypto_word32_buf_t share1_buf =
221269
OTCRYPTO_MAKE_BUF(otcrypto_word32_buf_t, share1, share_len);
222270
otcrypto_const_byte_buf_t kEmptyBuffer =
223271
OTCRYPTO_MAKE_BUF(otcrypto_const_byte_buf_t, NULL, 0);
224-
HARDENED_TRY(otcrypto_drbg_instantiate(&kEmptyBuffer));
225-
HARDENED_TRY(otcrypto_drbg_generate(&kEmptyBuffer, &share1_buf));
272+
hardened_memshred(share1, share_len);
226273
share1[share_len - 1] &= 0x7fffffff;
227274

228275
// Compute share0 = share + share1.
@@ -231,8 +278,58 @@ static status_t ed25519_mask_scalar(uint32_t *scalar, size_t scalar_len,
231278
return OTCRYPTO_OK;
232279
}
233280

281+
/**
282+
* Unmasks the private key, computes the SHA-512 digest, clamps the lower half,
283+
* and returns the arithmetically masked scalar 's'.
284+
*
285+
* The full key digest is also returned because the upper half is needed as a
286+
* prefix during the first stage of signature generation.
287+
*
288+
* @param private_key The blinded private key.
289+
* @param[out] key_digest The 512-bit SHA-512 hash of the unmasked key.
290+
* @param[out] masked_s The clamped and masked scalar 's'.
291+
* @return OK or error status.
292+
*/
293+
OT_WARN_UNUSED_RESULT
294+
static otcrypto_status_t ed25519_compute_scalar_and_prefix(
295+
const otcrypto_blinded_key_t *private_key,
296+
otcrypto_hash_digest_t *key_digest,
297+
curve25519_masked_scalar_s_t *masked_s) {
298+
// Compute hash_h.
299+
if (private_key->config.hw_backed == kHardenedBoolFalse) {
300+
uint32_t seed_data[kCurve25519KeyBytes / sizeof(uint32_t)];
301+
uint32_t *share0 = private_key->keyblob;
302+
uint32_t *share1 =
303+
private_key->keyblob + keyblob_share_num_words(private_key->config);
304+
305+
// Unmask the seed using addition modulo 2^256.
306+
HARDENED_TRY(hardened_add(share0, share1, ARRAYSIZE(seed_data), seed_data));
307+
308+
otcrypto_const_byte_buf_t key_buf =
309+
OTCRYPTO_MAKE_BUF(otcrypto_const_byte_buf_t,
310+
(const uint8_t *const)seed_data, kCurve25519KeyBytes);
311+
HARDENED_TRY(otcrypto_sha2_512(&key_buf, key_digest));
312+
313+
// Memshred the unmasked seed.
314+
HARDENED_TRY(hardened_memshred(seed_data, ARRAYSIZE(seed_data)));
315+
} else {
316+
// Hardware-backed keys are not supported at the moment.
317+
return OTCRYPTO_NOT_IMPLEMENTED;
318+
}
319+
320+
// Immediately clamp the lower half of hash_h to create the secret scalar s.
321+
HARDENED_TRY(ed25519_clamp(key_digest->data));
322+
323+
// Arithmetically mask s before passing it to the OTBN app.
324+
HARDENED_TRY(ed25519_mask_scalar(key_digest->data, kCurve25519ScalarWords,
325+
masked_s->share0, masked_s->share1,
326+
kCurve25519MaskedScalarSWords));
327+
328+
return OTCRYPTO_OK;
329+
}
330+
234331
otcrypto_status_t otcrypto_ed25519_public_key_from_private(
235-
const otcrypto_unblinded_key_t *private_key,
332+
const otcrypto_blinded_key_t *private_key,
236333
otcrypto_unblinded_key_t *public_key) {
237334
if (public_key == NULL || public_key->key == NULL) {
238335
return OTCRYPTO_BAD_ARGS;
@@ -245,7 +342,7 @@ otcrypto_status_t otcrypto_ed25519_public_key_from_private(
245342
}
246343

247344
otcrypto_status_t otcrypto_ed25519_sign(
248-
const otcrypto_unblinded_key_t *private_key,
345+
const otcrypto_blinded_key_t *private_key,
249346
const otcrypto_const_byte_buf_t *input_message,
250347
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_word32_buf_t *signature) {
251348
// Validate signature buffer
@@ -315,7 +412,7 @@ otcrypto_status_t otcrypto_ed25519_verify(
315412
}
316413

317414
otcrypto_status_t otcrypto_ed25519_sign_verify(
318-
const otcrypto_unblinded_key_t *private_key,
415+
const otcrypto_blinded_key_t *private_key,
319416
const otcrypto_unblinded_key_t *public_key,
320417
const otcrypto_const_byte_buf_t *input_message,
321418
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_word32_buf_t *signature) {
@@ -336,9 +433,9 @@ otcrypto_status_t otcrypto_ed25519_sign_verify(
336433
}
337434

338435
otcrypto_status_t otcrypto_ed25519_public_key_from_private_async_start(
339-
const otcrypto_unblinded_key_t *private_key) {
436+
const otcrypto_blinded_key_t *private_key) {
340437
// Check the private key.
341-
HARDENED_TRY(ed25519_key_check(private_key));
438+
HARDENED_TRY(ed25519_private_key_length_check(private_key));
342439

343440
// Instantiate struct to store the secret key digest.
344441
uint32_t key_digest_data[kCurve25519HashWords];
@@ -347,20 +444,10 @@ otcrypto_status_t otcrypto_ed25519_public_key_from_private_async_start(
347444
.len = ARRAYSIZE(key_digest_data),
348445
};
349446

350-
// Compute hash_h.
351-
otcrypto_const_byte_buf_t key_buf = OTCRYPTO_MAKE_BUF(
352-
otcrypto_const_byte_buf_t, (const uint8_t *const)private_key->key,
353-
private_key->key_length);
354-
HARDENED_TRY(otcrypto_sha2_512(&key_buf, &key_digest));
355-
356-
// Immediately clamp the lower half of hash_h to create the secret scalar s.
357-
HARDENED_TRY(ed25519_clamp(key_digest.data));
358-
359-
// Arithmetically mask s before passing it to the OTBN app.
360447
curve25519_masked_scalar_s_t s;
361-
HARDENED_TRY(ed25519_mask_scalar(key_digest.data, kCurve25519ScalarWords,
362-
s.share0, s.share1,
363-
kCurve25519MaskedScalarSWords));
448+
449+
// Compute the digest and scalar
450+
HARDENED_TRY(ed25519_compute_scalar_and_prefix(private_key, &key_digest, &s));
364451

365452
// Start the OTBN keygen app.
366453
HARDENED_TRY(curve25519_keygen_start(&s));
@@ -378,41 +465,29 @@ otcrypto_status_t otcrypto_ed25519_public_key_from_private_async_finalize(
378465
}
379466

380467
otcrypto_status_t otcrypto_ed25519_sign_part1_async_start(
381-
const otcrypto_unblinded_key_t *private_key,
468+
const otcrypto_blinded_key_t *private_key,
382469
const otcrypto_const_byte_buf_t *input_message_ph,
383470
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_word32_buf_t *s0,
384471
otcrypto_word32_buf_t *s1, otcrypto_word32_buf_t *r0,
385472
otcrypto_word32_buf_t *r1) {
386473
// Check the private key.
387-
HARDENED_TRY(ed25519_key_check(private_key));
474+
HARDENED_TRY(ed25519_private_key_length_check(private_key));
388475

389476
// Instantiate struct to store the secret key digest.
390477
uint32_t key_digest_data[kCurve25519HashWords];
391478
otcrypto_hash_digest_t key_digest = {
392479
.data = key_digest_data,
393480
.len = ARRAYSIZE(key_digest_data),
394481
};
482+
curve25519_masked_scalar_s_t s;
395483

396-
// Compute hash_h.
397-
// TODO(#28964) Check SCA hardening of the key digest.
398-
otcrypto_const_byte_buf_t key_buf = OTCRYPTO_MAKE_BUF(
399-
otcrypto_const_byte_buf_t, (const uint8_t *const)private_key->key,
400-
private_key->key_length);
401-
HARDENED_TRY(otcrypto_sha2_512(&key_buf, &key_digest));
402-
403-
// Immediately clamp the lower half of hash_h to create the secret scalar s.
404-
HARDENED_TRY(ed25519_clamp(key_digest.data));
405-
406-
// Arithmetically mask s before passing it to the OTBN app.
407-
HARDENED_TRY(ed25519_mask_scalar(key_digest.data, kCurve25519ScalarWords,
408-
s0->data, s1->data,
409-
kCurve25519MaskedScalarSWords));
484+
// Compute the digest and scalar
485+
HARDENED_TRY(ed25519_compute_scalar_and_prefix(private_key, &key_digest, &s));
410486

411-
curve25519_masked_scalar_s_t s;
412487
HARDENED_TRY(
413-
hardened_memcpy(s.share0, s0->data, kCurve25519MaskedScalarSWords));
488+
hardened_memcpy(s0->data, s.share0, kCurve25519MaskedScalarSWords));
414489
HARDENED_TRY(
415-
hardened_memcpy(s.share1, s1->data, kCurve25519MaskedScalarSWords));
490+
hardened_memcpy(s1->data, s.share1, kCurve25519MaskedScalarSWords));
416491

417492
// Prepend the dom2 prefix
418493
size_t dom2_len =
@@ -463,7 +538,7 @@ otcrypto_status_t otcrypto_ed25519_sign_part1_async_start(
463538
}
464539

465540
otcrypto_status_t otcrypto_ed25519_sign_part2_async_start(
466-
const otcrypto_unblinded_key_t *private_key,
541+
const otcrypto_blinded_key_t *private_key,
467542
const otcrypto_const_byte_buf_t *input_message_ph,
468543
otcrypto_eddsa_sign_mode_t sign_mode, otcrypto_word32_buf_t *signature,
469544
otcrypto_word32_buf_t *s0, otcrypto_word32_buf_t *s1,
@@ -472,7 +547,7 @@ otcrypto_status_t otcrypto_ed25519_sign_part2_async_start(
472547
HARDENED_TRY(ed25519_signature_check(signature));
473548

474549
// Check the private key.
475-
HARDENED_TRY(ed25519_key_check(private_key));
550+
HARDENED_TRY(ed25519_private_key_length_check(private_key));
476551

477552
// Finalize the signature stage 1 and retrieve the signature commitment R and
478553
// public key A.
@@ -549,7 +624,7 @@ otcrypto_status_t otcrypto_ed25519_verify_async_start(
549624
otcrypto_eddsa_sign_mode_t sign_mode,
550625
const otcrypto_const_word32_buf_t *signature) {
551626
// Check the public key.
552-
HARDENED_TRY(ed25519_key_check(public_key));
627+
HARDENED_TRY(ed25519_public_key_length_check(public_key));
553628

554629
// Do some signature struct validity checks.
555630
HARDENED_TRY(ed25519_signature_check((otcrypto_word32_buf_t *)signature));

0 commit comments

Comments
 (0)