@@ -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 */
3986OT_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+
234331otcrypto_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
247344otcrypto_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
317414otcrypto_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
338435otcrypto_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
380467otcrypto_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
465540otcrypto_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