|
28 | 28 | kOtCryptoMldsaBufferWords = kOtCryptoMldsaBufferBytes / sizeof(uint32_t), |
29 | 29 | // Maximum size of a pre-hash message digest. |
30 | 30 | kOtcryptoMldsaPhMaxWords = 16, |
| 31 | + // Size of the rnd string. |
| 32 | + kOtcryptoMldsaRndBytes = 32, |
| 33 | + kOtcryptoMldsaRndWords = kOtcryptoMldsaRndBytes / sizeof(uint32_t), |
31 | 34 | }; |
32 | 35 |
|
33 | 36 | // Lookup table for the supported pre-hash functions, indexed by their OID. |
@@ -81,6 +84,24 @@ static otcrypto_status_t check_unblinded_key( |
81 | 84 | return OTCRYPTO_OK; |
82 | 85 | } |
83 | 86 |
|
| 87 | +// Check the integrity and length of a blinded key. |
| 88 | +static otcrypto_status_t check_blinded_key(const otcrypto_blinded_key_t *key) { |
| 89 | + // Integrity check. |
| 90 | + if (launder32(otcrypto_integrity_blinded_key_check(key)) != |
| 91 | + kHardenedBoolTrue) { |
| 92 | + return OTCRYPTO_BAD_ARGS; |
| 93 | + } |
| 94 | + HARDENED_CHECK_EQ(otcrypto_integrity_blinded_key_check(key), |
| 95 | + kHardenedBoolTrue); |
| 96 | + |
| 97 | + // Length check. |
| 98 | + if (key->keyblob_length != kOtcryptoMldsa87SkBytes) { |
| 99 | + return OTCRYPTO_BAD_ARGS; |
| 100 | + } |
| 101 | + HARDENED_CHECK_EQ(key->keyblob_length, kOtcryptoMldsa87SkBytes); |
| 102 | + return OTCRYPTO_OK; |
| 103 | +} |
| 104 | + |
84 | 105 | // Check the integrity and length of a constant byte buffer. |
85 | 106 | static otcrypto_status_t check_byte_buf(const otcrypto_const_byte_buf_t *buf, |
86 | 107 | size_t max_len) { |
@@ -233,11 +254,15 @@ otcrypto_status_t otcrypto_mldsa87_keygen( |
233 | 254 |
|
234 | 255 | otcrypto_status_t otcrypto_mldsa87_sign( |
235 | 256 | const otcrypto_blinded_key_t *private_key, |
236 | | - const otcrypto_const_byte_buf_t message, |
237 | | - const otcrypto_const_byte_buf_t context, |
238 | | - otcrypto_mldsa_hash_mode_t hash_mode, otcrypto_word32_buf_t signature) { |
239 | | - // TODO: Connect ML-DSA operations to API. |
240 | | - return OTCRYPTO_NOT_IMPLEMENTED; |
| 257 | + const otcrypto_const_byte_buf_t *message, |
| 258 | + const otcrypto_const_byte_buf_t *context, |
| 259 | + otcrypto_mldsa_hash_mode_t hash_mode, otcrypto_mldsa_sign_mode_t sign_mode, |
| 260 | + otcrypto_word32_buf_t *signature) { |
| 261 | + HARDENED_TRY(otcrypto_mldsa87_sign_async_start(private_key, message, context, |
| 262 | + hash_mode, sign_mode)); |
| 263 | + HARDENED_TRY(otcrypto_mldsa87_double_sign_async_finalize(signature)); |
| 264 | + |
| 265 | + return OTCRYPTO_OK; |
241 | 266 | } |
242 | 267 |
|
243 | 268 | otcrypto_status_t otcrypto_mldsa87_verify( |
@@ -276,20 +301,76 @@ otcrypto_status_t otcrypto_mldsa87_keygen_async_finalize( |
276 | 301 |
|
277 | 302 | otcrypto_status_t otcrypto_mldsa87_sign_async_start( |
278 | 303 | const otcrypto_blinded_key_t *private_key, |
279 | | - const otcrypto_const_byte_buf_t message, |
280 | | - const otcrypto_const_byte_buf_t context, |
281 | | - otcrypto_mldsa_hash_mode_t hash_mode, otcrypto_word32_buf_t signature) { |
282 | | - // TODO: Connect ML-DSA operations to API. |
283 | | - return OTCRYPTO_NOT_IMPLEMENTED; |
| 304 | + const otcrypto_const_byte_buf_t *message, |
| 305 | + const otcrypto_const_byte_buf_t *context, |
| 306 | + otcrypto_mldsa_hash_mode_t hash_mode, |
| 307 | + otcrypto_mldsa_sign_mode_t sign_mode) { |
| 308 | +#ifndef OTCRYPTO_DISABLE_NULL_CHECKS |
| 309 | + if (private_key == NULL || private_key->keyblob == NULL || message == NULL || |
| 310 | + context == NULL) { |
| 311 | + return OTCRYPTO_BAD_ARGS; |
| 312 | + } |
| 313 | +#endif |
| 314 | + |
| 315 | + // Check the integrity and length of the input buffers. |
| 316 | + HARDENED_TRY(check_blinded_key(private_key)); |
| 317 | + HARDENED_TRY(check_byte_buf(context, kOtcryptoMldsa87CtxMaxBytes)); |
| 318 | + HARDENED_TRY(check_byte_buf(message, kOtcryptoMldsa87MsgMaxBytes)); |
| 319 | + |
| 320 | + // Allocate the 64-byte mu digest. |
| 321 | + uint32_t mu_data[kOtcryptoMldsaMuWords] = {0}; |
| 322 | + otcrypto_hash_digest_t mu = { |
| 323 | + .data = mu_data, |
| 324 | + .len = kOtcryptoMldsaMuWords, |
| 325 | + }; |
| 326 | + |
| 327 | + // Extract tr from the secret key. |
| 328 | + otcrypto_hash_digest_t tr = { |
| 329 | + .data = private_key->keyblob + 24, |
| 330 | + .len = kOtcryptoMldsaTrWords, |
| 331 | + }; |
| 332 | + |
| 333 | + // mu = Shake256(tr || M'). |
| 334 | + HARDENED_TRY(compute_mu(&tr, context, message, hash_mode, &mu)); |
| 335 | + |
| 336 | + // Invoke the signature generation OTBN app. |
| 337 | + HARDENED_TRY_WIPE_DMEM( |
| 338 | + mldsa87_sign_internal_start(private_key, &mu, sign_mode)); |
| 339 | + |
| 340 | + // Check the buffers again before exiting. |
| 341 | + HARDENED_TRY(check_blinded_key(private_key)); |
| 342 | + HARDENED_TRY(check_byte_buf(context, kOtcryptoMldsa87CtxMaxBytes)); |
| 343 | + HARDENED_TRY(check_byte_buf(message, kOtcryptoMldsa87MsgMaxBytes)); |
| 344 | + |
| 345 | + return otcrypto_eval_exit(OTCRYPTO_OK); |
284 | 346 | } |
285 | 347 |
|
286 | 348 | otcrypto_status_t otcrypto_mldsa87_sign_async_finalize( |
287 | | - const otcrypto_blinded_key_t *private_key, |
288 | | - const otcrypto_const_byte_buf_t message, |
289 | | - const otcrypto_const_byte_buf_t context, |
290 | | - otcrypto_mldsa_hash_mode_t hash_mode, otcrypto_word32_buf_t signature) { |
291 | | - // TODO: Connect ML-DSA operations to API. |
292 | | - return OTCRYPTO_NOT_IMPLEMENTED; |
| 349 | + otcrypto_word32_buf_t *signature) { |
| 350 | +#ifndef OTCRYPTO_DISABLE_NULL_CHECKS |
| 351 | + if (signature == NULL || signature->data == NULL) { |
| 352 | + return OTCRYPTO_BAD_ARGS; |
| 353 | + } |
| 354 | +#endif |
| 355 | + |
| 356 | + HARDENED_TRY_WIPE_DMEM( |
| 357 | + mldsa87_sign_internal_finalize(signature, kMldsa87SingleSign)); |
| 358 | + |
| 359 | + return otcrypto_eval_exit(OTCRYPTO_OK); |
| 360 | +} |
| 361 | + |
| 362 | +otcrypto_status_t otcrypto_mldsa87_double_sign_async_finalize( |
| 363 | + otcrypto_word32_buf_t *signature) { |
| 364 | +#ifndef OTCRYPTO_DISABLE_NULL_CHECKS |
| 365 | + if (signature == NULL || signature->data == NULL) { |
| 366 | + return OTCRYPTO_BAD_ARGS; |
| 367 | + } |
| 368 | +#endif |
| 369 | + |
| 370 | + HARDENED_TRY_WIPE_DMEM( |
| 371 | + mldsa87_sign_internal_finalize(signature, kMldsa87DoubleSign)); |
| 372 | + |
| 373 | + return otcrypto_eval_exit(OTCRYPTO_OK); |
293 | 374 | } |
294 | 375 |
|
295 | 376 | otcrypto_status_t otcrypto_mldsa87_verify_async_start( |
@@ -358,8 +439,10 @@ otcrypto_status_t otcrypto_mldsa87_verify_async_finalize( |
358 | 439 |
|
359 | 440 | HARDENED_TRY(check_word32_buf(signature, kOtcryptoMldsa87SigWords)); |
360 | 441 |
|
361 | | - return otcrypto_eval_exit( |
| 442 | + HARDENED_TRY_WIPE_DMEM( |
362 | 443 | mldsa87_verify_internal_finalize(signature, verification_result)); |
| 444 | + |
| 445 | + return otcrypto_eval_exit(OTCRYPTO_OK); |
363 | 446 | } |
364 | 447 |
|
365 | 448 | otcrypto_status_t otcrypto_mldsa87_keycheck_async_start( |
|
0 commit comments