@@ -37,6 +37,9 @@ static uint8_t _unstretched_retained_seed_encryption_key[32] = {0};
37
37
// Stores the encrypted seed after unlock.
38
38
static uint8_t _retained_seed_encrypted [KEYSTORE_MAX_SEED_LENGTH + 64 ] = {0 };
39
39
static size_t _retained_seed_encrypted_len = 0 ;
40
+ // A hash of the unencrypted retained seed, used for comparing seeds without knowing their
41
+ // plaintext.
42
+ static uint8_t _retained_seed_hash [32 ] = {0 };
40
43
41
44
// Change this ONLY via keystore_unlock_bip39().
42
45
static bool _is_unlocked_bip39 = false;
@@ -205,103 +208,47 @@ static keystore_error_t _get_and_decrypt_seed(
205
208
}
206
209
207
210
static bool _verify_seed (
208
- const char * password ,
211
+ const uint8_t * encryption_key ,
209
212
const uint8_t * expected_seed ,
210
213
size_t expected_seed_len )
211
214
{
212
- uint8_t decrypted_seed [ KEYSTORE_MAX_SEED_LENGTH ] = { 0 } ;
213
- size_t seed_len ;
214
- UTIL_CLEANUP_32 ( decrypted_seed ) ;
215
- if (_get_and_decrypt_seed ( password , decrypted_seed , & seed_len , NULL ) != KEYSTORE_OK ) {
215
+ uint8_t encrypted_seed_and_hmac [ 96 ] ;
216
+ UTIL_CLEANUP_32 ( encrypted_seed_and_hmac ) ;
217
+ uint8_t encrypted_len ;
218
+ if (! memory_get_encrypted_seed_and_hmac ( encrypted_seed_and_hmac , & encrypted_len ) ) {
216
219
return false;
217
220
}
218
- if (expected_seed_len != seed_len ) {
219
- return false ;
221
+ if (encrypted_len < 49 ) {
222
+ Abort ( "_verify_seed: underflow / zero size" ) ;
220
223
}
221
- if (!MEMEQ (expected_seed , decrypted_seed , seed_len )) {
224
+ size_t decrypted_len = encrypted_len - 48 ;
225
+ uint8_t decrypted [decrypted_len ];
226
+ bool password_correct = cipher_aes_hmac_decrypt (
227
+ encrypted_seed_and_hmac , encrypted_len , decrypted , & decrypted_len , encryption_key );
228
+ if (!password_correct ) {
222
229
return false;
223
230
}
224
- return true;
225
- }
226
-
227
- keystore_error_t keystore_encrypt_and_store_seed (
228
- const uint8_t * seed ,
229
- size_t seed_length ,
230
- const char * password )
231
- {
232
- if (memory_is_initialized ()) {
233
- return KEYSTORE_ERR_MEMORY ;
234
- }
235
- keystore_lock ();
236
- if (!_validate_seed_length (seed_length )) {
237
- return KEYSTORE_ERR_SEED_SIZE ;
238
- }
239
- if (securechip_init_new_password (password )) {
240
- return KEYSTORE_ERR_SECURECHIP ;
241
- }
242
- uint8_t secret [32 ] = {0 };
243
- UTIL_CLEANUP_32 (secret );
244
- if (securechip_stretch_password (password , secret )) {
245
- return KEYSTORE_ERR_SECURECHIP ;
246
- }
247
-
248
- size_t encrypted_seed_len = seed_length + 64 ;
249
- uint8_t encrypted_seed [encrypted_seed_len ];
250
- UTIL_CLEANUP_32 (encrypted_seed );
251
- if (!cipher_aes_hmac_encrypt (seed , seed_length , encrypted_seed , & encrypted_seed_len , secret )) {
252
- return KEYSTORE_ERR_ENCRYPT ;
253
- }
254
- if (encrypted_seed_len > 255 ) { // sanity check, can't happen
255
- Abort ("keystore_encrypt_and_store_seed" );
256
- }
257
- uint8_t encrypted_seed_len_u8 = (uint8_t )encrypted_seed_len ;
258
- if (!memory_set_encrypted_seed_and_hmac (encrypted_seed , encrypted_seed_len_u8 )) {
259
- return KEYSTORE_ERR_MEMORY ;
231
+ if (expected_seed_len != decrypted_len ) {
232
+ util_zero (decrypted , sizeof (decrypted ));
233
+ return false;
260
234
}
261
- if (!_verify_seed (password , seed , seed_length )) {
262
- if (!memory_reset_hww ()) {
263
- return KEYSTORE_ERR_MEMORY ;
264
- }
265
- return KEYSTORE_ERR_MEMORY ;
235
+ if (!MEMEQ (expected_seed , decrypted , expected_seed_len )) {
236
+ util_zero (decrypted , sizeof (decrypted ));
237
+ return false;
266
238
}
267
- return KEYSTORE_OK ;
239
+ util_zero (decrypted , sizeof (decrypted ));
240
+ return true;
268
241
}
269
242
270
- keystore_error_t keystore_create_and_store_seed (
271
- const char * password ,
272
- const uint8_t * host_entropy ,
273
- size_t host_entropy_size )
243
+ static keystore_error_t _hash_seed (const uint8_t * seed , size_t seed_len , uint8_t * out )
274
244
{
275
- if (host_entropy_size != 16 && host_entropy_size != 32 ) {
276
- return KEYSTORE_ERR_SEED_SIZE ;
277
- }
278
- if (KEYSTORE_MAX_SEED_LENGTH != RANDOM_NUM_SIZE ) {
279
- Abort ("keystore create: size mismatch" );
280
- }
281
- uint8_t seed [KEYSTORE_MAX_SEED_LENGTH ];
282
- UTIL_CLEANUP_32 (seed );
283
- random_32_bytes (seed );
284
-
285
- // Mix in Host entropy.
286
- for (size_t i = 0 ; i < host_entropy_size ; i ++ ) {
287
- seed [i ] ^= host_entropy [i ];
288
- }
289
-
290
- // Mix in entropy derived from the user password.
291
- uint8_t password_salted_hashed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
292
- UTIL_CLEANUP_32 (password_salted_hashed );
293
- if (!salt_hash_data (
294
- (const uint8_t * )password ,
295
- strlen (password ),
296
- "keystore_seed_generation" ,
297
- password_salted_hashed )) {
245
+ uint8_t salted_key [32 ] = {0 };
246
+ if (!salt_hash_data (NULL , 0 , "keystore_retain_seed_hash" , salted_key )) {
298
247
return KEYSTORE_ERR_SALT ;
299
248
}
300
249
301
- for (size_t i = 0 ; i < host_entropy_size ; i ++ ) {
302
- seed [i ] ^= password_salted_hashed [i ];
303
- }
304
- return keystore_encrypt_and_store_seed (seed , host_entropy_size , password );
250
+ rust_hmac_sha256 (salted_key , sizeof (salted_key ), seed , seed_len , out );
251
+ return KEYSTORE_OK ;
305
252
}
306
253
307
254
USE_RESULT static keystore_error_t _retain_seed (const uint8_t * seed , size_t seed_len )
@@ -333,7 +280,8 @@ USE_RESULT static keystore_error_t _retain_seed(const uint8_t* seed, size_t seed
333
280
return KEYSTORE_ERR_ENCRYPT ;
334
281
}
335
282
_retained_seed_encrypted_len = len ;
336
- return KEYSTORE_OK ;
283
+
284
+ return _hash_seed (seed , seed_len , _retained_seed_hash );
337
285
}
338
286
339
287
USE_RESULT static bool _retain_bip39_seed (const uint8_t * bip39_seed )
@@ -378,13 +326,102 @@ static void _delete_retained_seeds(void)
378
326
sizeof (_unstretched_retained_seed_encryption_key ));
379
327
util_zero (_retained_seed_encrypted , sizeof (_retained_seed_encrypted ));
380
328
_retained_seed_encrypted_len = 0 ;
329
+ util_zero (_retained_seed_hash , sizeof (_retained_seed_hash ));
330
+
381
331
util_zero (
382
332
_unstretched_retained_bip39_seed_encryption_key ,
383
333
sizeof (_unstretched_retained_seed_encryption_key ));
384
334
util_zero (_retained_bip39_seed_encrypted , sizeof (_retained_bip39_seed_encrypted ));
385
335
_retained_bip39_seed_encrypted_len = 0 ;
386
336
}
387
337
338
+ keystore_error_t keystore_encrypt_and_store_seed (
339
+ const uint8_t * seed ,
340
+ size_t seed_length ,
341
+ const char * password )
342
+ {
343
+ if (memory_is_initialized ()) {
344
+ return KEYSTORE_ERR_MEMORY ;
345
+ }
346
+ keystore_lock ();
347
+ if (!_validate_seed_length (seed_length )) {
348
+ return KEYSTORE_ERR_SEED_SIZE ;
349
+ }
350
+ if (securechip_init_new_password (password )) {
351
+ return KEYSTORE_ERR_SECURECHIP ;
352
+ }
353
+ uint8_t secret [32 ] = {0 };
354
+ UTIL_CLEANUP_32 (secret );
355
+ if (securechip_stretch_password (password , secret )) {
356
+ return KEYSTORE_ERR_SECURECHIP ;
357
+ }
358
+
359
+ size_t encrypted_seed_len = seed_length + 64 ;
360
+ uint8_t encrypted_seed [encrypted_seed_len ];
361
+ UTIL_CLEANUP_32 (encrypted_seed );
362
+ if (!cipher_aes_hmac_encrypt (seed , seed_length , encrypted_seed , & encrypted_seed_len , secret )) {
363
+ return KEYSTORE_ERR_ENCRYPT ;
364
+ }
365
+ if (encrypted_seed_len > 255 ) { // sanity check, can't happen
366
+ Abort ("keystore_encrypt_and_store_seed" );
367
+ }
368
+ uint8_t encrypted_seed_len_u8 = (uint8_t )encrypted_seed_len ;
369
+ if (!memory_set_encrypted_seed_and_hmac (encrypted_seed , encrypted_seed_len_u8 )) {
370
+ return KEYSTORE_ERR_MEMORY ;
371
+ }
372
+ if (!_verify_seed (secret , seed , seed_length )) {
373
+ if (!memory_reset_hww ()) {
374
+ return KEYSTORE_ERR_MEMORY ;
375
+ }
376
+ return KEYSTORE_ERR_MEMORY ;
377
+ }
378
+
379
+ keystore_error_t retain_seed_result = _retain_seed (seed , seed_length );
380
+ if (retain_seed_result != KEYSTORE_OK ) {
381
+ return retain_seed_result ;
382
+ }
383
+ _is_unlocked_device = true;
384
+
385
+ return KEYSTORE_OK ;
386
+ }
387
+
388
+ keystore_error_t keystore_create_and_store_seed (
389
+ const char * password ,
390
+ const uint8_t * host_entropy ,
391
+ size_t host_entropy_size )
392
+ {
393
+ if (host_entropy_size != 16 && host_entropy_size != 32 ) {
394
+ return KEYSTORE_ERR_SEED_SIZE ;
395
+ }
396
+ if (KEYSTORE_MAX_SEED_LENGTH != RANDOM_NUM_SIZE ) {
397
+ Abort ("keystore create: size mismatch" );
398
+ }
399
+ uint8_t seed [KEYSTORE_MAX_SEED_LENGTH ];
400
+ UTIL_CLEANUP_32 (seed );
401
+ random_32_bytes (seed );
402
+
403
+ // Mix in Host entropy.
404
+ for (size_t i = 0 ; i < host_entropy_size ; i ++ ) {
405
+ seed [i ] ^= host_entropy [i ];
406
+ }
407
+
408
+ // Mix in entropy derived from the user password.
409
+ uint8_t password_salted_hashed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
410
+ UTIL_CLEANUP_32 (password_salted_hashed );
411
+ if (!salt_hash_data (
412
+ (const uint8_t * )password ,
413
+ strlen (password ),
414
+ "keystore_seed_generation" ,
415
+ password_salted_hashed )) {
416
+ return KEYSTORE_ERR_SALT ;
417
+ }
418
+
419
+ for (size_t i = 0 ; i < host_entropy_size ; i ++ ) {
420
+ seed [i ] ^= password_salted_hashed [i ];
421
+ }
422
+ return keystore_encrypt_and_store_seed (seed , host_entropy_size , password );
423
+ }
424
+
388
425
keystore_error_t keystore_unlock (
389
426
const char * password ,
390
427
uint8_t * remaining_attempts_out ,
@@ -448,17 +485,23 @@ keystore_error_t keystore_unlock(
448
485
return result ;
449
486
}
450
487
451
- bool keystore_unlock_bip39 (const char * mnemonic_passphrase , uint8_t * root_fingerprint_out )
488
+ bool keystore_unlock_bip39 (
489
+ const uint8_t * seed ,
490
+ size_t seed_length ,
491
+ const char * mnemonic_passphrase ,
492
+ uint8_t * root_fingerprint_out )
452
493
{
453
494
if (!_is_unlocked_device ) {
454
495
return false;
455
496
}
456
497
usb_processing_timeout_reset (LONG_TIMEOUT );
457
498
458
- uint8_t seed [KEYSTORE_MAX_SEED_LENGTH ] = {0 };
459
- UTIL_CLEANUP_32 (seed );
460
- size_t seed_length = 0 ;
461
- if (!keystore_copy_seed (seed , & seed_length )) {
499
+ uint8_t seed_hashed [32 ] = {0 };
500
+ UTIL_CLEANUP_32 (seed_hashed );
501
+ if (_hash_seed (seed , seed_length , seed_hashed ) != KEYSTORE_OK ) {
502
+ return false;
503
+ }
504
+ if (!MEMEQ (seed_hashed , _retained_seed_hash , sizeof (_retained_seed_hash ))) {
462
505
return false;
463
506
}
464
507
0 commit comments