44from .javacard .util import get_connection
55from platform import CriticalErrorWipeImmediately
66import platform
7- from rng import get_random_bytes
87from embit import bip39
98from helpers import tagged_hash , aead_encrypt , aead_decrypt
109import hmac
11- from gui .screens import Alert , Progress , Menu , MnemonicScreen , Prompt
10+ from gui .screens import Alert , Progress , Menu , Prompt
1211import asyncio
1312from io import BytesIO
14- from uscard import SmartcardException
1513from binascii import hexlify
1614import lvgl as lv
1715
@@ -228,15 +226,35 @@ def _set_pin(self, pin):
228226
229227 async def save_mnemonic (self ):
230228 await self .check_card (check_pin = True )
231- encrypt = await self .show (Prompt ("Encrypt the secret?" ,
229+ data_saved , encrypted , decryptable , same_mnemonic = self .get_secret_info ()
230+ if data_saved :
231+ if not decryptable :
232+ msg = ("There is data on the card, but its nature is unknown since we are unable to decrypt it.\n \n "
233+ "Thus, we cannot confirm whether a mnemonic is already saved on your card or if it matches the one you are about to save." )
234+ elif same_mnemonic :
235+ msg = ("The mnemonic you are about to save is already stored on the smart card.\n "
236+ "If you proceed, the existing data will be overwritten with the same mnemonic.\n \n "
237+ "This can be useful if you want to store this mnemonic in a different form (plaintext vs. encrypted) on the card.\n \n "
238+ "Currently, your mnemonic is saved in {} form on the card." .format ('encrypted' if encrypted else 'plaintext' ))
239+ else :
240+ msg = ("A different mnemonic is already saved on the card.\n \n "
241+ "Continuing will replace the existing mnemonic with the one you are about to save." )
242+
243+ confirm = await self .show (Prompt ("Overwrite data?" ,
244+ "\n %s" % msg + "\n \n Do you want to continue?" , 'Continue' , warning = "Irreversibly overwrite the data on the card"
245+ ))
246+ if not confirm :
247+ return
248+ keep_as_plain_text = await self .show (Prompt ("Encrypt the secret?" ,
232249 "\n If you encrypt the secret on the card "
233- "it will only work with this device.\n \n "
234- "Otherwise it will be readable on any device "
250+ "it will only work with the device you are currently using .\n \n "
251+ "If you keep it as plain text, it will be readable on any Specter DIY device "
235252 "after you enter the PIN code.\n \n "
236- "Keep in mind that with encryption enabled "
237- "wiping the device makes the secret unusable!" ,
238- confirm_text = "Yes, encrypt" ,
239- cancel_text = "Keep as plain text" ))
253+ "Activating encryption means that if the device is wiped, the stored secret on the card becomes inaccessible." ,
254+ confirm_text = "Keep as plain text" ,
255+ cancel_text = "Encrypt" ,
256+ ))
257+ encrypt = not keep_as_plain_text
240258 self .show_loader ("Saving secret to the card..." )
241259 d = self .serialize_data (
242260 {"entropy" : bip39 .mnemonic_to_bytes (self .mnemonic )},
@@ -246,6 +264,13 @@ async def save_mnemonic(self):
246264 self ._is_key_saved = True
247265 # check it's ok
248266 await self .load_mnemonic ()
267+ await self .show (
268+ Alert (
269+ "Success!" ,
270+ "Your key is stored on the smartcard now." ,
271+ button_text = "OK" ,
272+ )
273+ )
249274
250275 @property
251276 def is_key_saved (self ):
@@ -359,13 +384,6 @@ async def storage_menu(self):
359384 return False
360385 elif menuitem == 0 :
361386 await self .save_mnemonic ()
362- await self .show (
363- Alert (
364- "Success!" ,
365- "Your key is stored on the smartcard now." ,
366- button_text = "OK" ,
367- )
368- )
369387 elif menuitem == 1 :
370388 await self .load_mnemonic ()
371389 await self .show (
@@ -407,23 +425,27 @@ async def storage_menu(self):
407425 else :
408426 raise KeyStoreError ("Invalid menu" )
409427
410- async def show_card_info (self ):
411- note = "Card fingerprint: %s" % self .hexid
412- version = "%s v%s" % (self .applet .NAME , self .applet .version )
413- platform = self .applet .platform
428+ def get_secret_info (self ):
414429 data = self .applet .get_secret ()
415- key_saved = len (data ) > 0
430+ data_saved = len (data ) > 0
416431 encrypted = True
417432 decryptable = True
418433 same_mnemonic = False
419- if key_saved :
434+ if data_saved :
420435 try :
421436 d , encrypted = self .parse_data (data )
422437 if "entropy" in d :
423438 self ._is_key_saved = True
424439 same_mnemonic = (self .mnemonic == bip39 .mnemonic_from_bytes (d ["entropy" ]))
425- except KeyStoreError as e :
440+ except KeyStoreError :
426441 decryptable = False
442+ return data_saved , encrypted , decryptable , same_mnemonic
443+
444+ async def show_card_info (self ):
445+ note = "Card fingerprint: %s" % self .hexid
446+ version = "%s v%s" % (self .applet .NAME , self .applet .version )
447+ platform = self .applet .platform
448+ data_saved , encrypted , decryptable , same_mnemonic = self .get_secret_info ()
427449 # yes = lv.SYMBOL.OK+" Yes"
428450 # no = lv.SYMBOL.CLOSE+" No"
429451 yes = "Yes"
@@ -433,9 +455,9 @@ async def show_card_info(self):
433455 "Implementation: %s" % platform ,
434456 "Version: %s" % version ,
435457 "\n #7f8fa4 KEY INFO: #" ,
436- "Key saved : " + (yes if key_saved else no ),
458+ "Card has data : " + (yes if data_saved else no ),
437459 ]
438- if key_saved :
460+ if data_saved :
439461 if decryptable :
440462 props .append ("Same as current key: " + (yes if same_mnemonic else no ))
441463 props .append ("Encrypted: " + (yes if encrypted else no ))
0 commit comments