@@ -37,6 +37,9 @@ static uint8_t _unstretched_retained_seed_encryption_key[32] = {0};
3737// Stores the encrypted seed after unlock.
3838static uint8_t _retained_seed_encrypted [KEYSTORE_MAX_SEED_LENGTH + 64 ] = {0 };
3939static 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 };
4043
4144// Change this ONLY via keystore_unlock_bip39().
4245static bool _is_unlocked_bip39 = false;
@@ -205,103 +208,47 @@ static keystore_error_t _get_and_decrypt_seed(
205208}
206209
207210static bool _verify_seed (
208- const char * password ,
211+ const uint8_t * encryption_key ,
209212 const uint8_t * expected_seed ,
210213 size_t expected_seed_len )
211214{
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 ) ) {
216219 return false;
217220 }
218- if (expected_seed_len != seed_len ) {
219- return false ;
221+ if (encrypted_len < 49 ) {
222+ Abort ( "_verify_seed: underflow / zero size" ) ;
220223 }
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 ) {
222229 return false;
223230 }
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;
260234 }
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;
266238 }
267- return KEYSTORE_OK ;
239+ util_zero (decrypted , sizeof (decrypted ));
240+ return true;
268241}
269242
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 )
274244{
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 )) {
298247 return KEYSTORE_ERR_SALT ;
299248 }
300249
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 ;
305252}
306253
307254USE_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
333280 return KEYSTORE_ERR_ENCRYPT ;
334281 }
335282 _retained_seed_encrypted_len = len ;
336- return KEYSTORE_OK ;
283+
284+ return _hash_seed (seed , seed_len , _retained_seed_hash );
337285}
338286
339287USE_RESULT static bool _retain_bip39_seed (const uint8_t * bip39_seed )
@@ -378,13 +326,102 @@ static void _delete_retained_seeds(void)
378326 sizeof (_unstretched_retained_seed_encryption_key ));
379327 util_zero (_retained_seed_encrypted , sizeof (_retained_seed_encrypted ));
380328 _retained_seed_encrypted_len = 0 ;
329+ util_zero (_retained_seed_hash , sizeof (_retained_seed_hash ));
330+
381331 util_zero (
382332 _unstretched_retained_bip39_seed_encryption_key ,
383333 sizeof (_unstretched_retained_seed_encryption_key ));
384334 util_zero (_retained_bip39_seed_encrypted , sizeof (_retained_bip39_seed_encrypted ));
385335 _retained_bip39_seed_encrypted_len = 0 ;
386336}
387337
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+
388425keystore_error_t keystore_unlock (
389426 const char * password ,
390427 uint8_t * remaining_attempts_out ,
@@ -448,17 +485,23 @@ keystore_error_t keystore_unlock(
448485 return result ;
449486}
450487
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 )
452493{
453494 if (!_is_unlocked_device ) {
454495 return false;
455496 }
456497 usb_processing_timeout_reset (LONG_TIMEOUT );
457498
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 ))) {
462505 return false;
463506 }
464507
0 commit comments