def wipe_flash_filesystem(): # erase and re-format the flash filesystem (/flash/) import ckcc, pyb from main import dis, settings dis.fullscreen('Erasing...') os.umount('/flash') # from extmod/vfs.h BP_IOCTL_SEC_COUNT = (4) BP_IOCTL_SEC_SIZE = (5) # block-level erase fl = pyb.Flash() bsize = fl.ioctl(BP_IOCTL_SEC_SIZE, 0) assert bsize == 512 bcount = fl.ioctl(BP_IOCTL_SEC_COUNT, 0) blk = bytearray(bsize) ckcc.rng_bytes(blk) # trickiness: actual flash blocks are offset by 0x100 (FLASH_PART1_START_BLOCK) # so fake MBR can be inserted. Count also inflated by 2X, but not from ioctl above. for n in range(bcount): fl.writeblocks(n + 0x100, blk) ckcc.rng_bytes(blk) dis.progress_bar_show(n * 2 / bcount) # rebuild and mount /flash dis.fullscreen('Rebuilding...') ckcc.wipe_fs() # re-store settings settings.save()
async def make_complete_backup(fname_pattern='backup.7z', write_sflash=False): # pick a password: like bip39 but no checksum word # b = bytearray(32) while 1: ckcc.rng_bytes(b) words = tcc.bip39.from_data(b).split(' ')[0:num_pw_words] ch = await seed.show_words(words, prompt="Record this (%d word) backup file password:\n", escape='6') if ch == '6' and not write_sflash: # Secret feature: plaintext mode # - only safe for people living in faraday cages inside locked vaults. if await ux_confirm("The file will **NOT** be encrypted and " "anyone who finds the file will get all of your money for free!"): words = [] fname_pattern = 'backup.txt' break continue if ch == 'x': return break if words: # quiz them, but be nice and do a shorter test. ch = await seed.word_quiz(words, limited=(num_pw_words//3)) if ch == 'x': return return await write_complete_backup(words, fname_pattern, write_sflash)
def wipe_microsd_card(): import ckcc, pyb from main import dis try: os.umount('/sd') except: pass sd = pyb.SDCard() assert sd if not sd.present(): return # power cycle so card details (like size) are re-read from current card sd.power(0) sd.power(1) dis.fullscreen('Part Erase...') cutoff = 1024 # arbitrary blk = bytearray(512) for bnum in range(cutoff): ckcc.rng_bytes(blk) sd.writeblocks(bnum, blk) dis.progress_bar_show(bnum / cutoff) dis.fullscreen('Formating...') # remount, with newfs option os.mount(sd, '/sd', readonly=0, mkfs=1)
def pick_secret(cls, auth_mode): # always 10 bytes for no reason => 80 bits of entropy # return binary secret, and encoded value for new user to see import ckcc b = bytearray(10) ckcc.rng_bytes(b) picked = b32encode(b) if auth_mode == USER_AUTH_HMAC: picked = picked.lower() b = calc_hmac_key(picked.encode('ascii')) return b, picked
async def make_new_wallet(): # Pick a new random seed, and await ux_dramatic_pause('Generating...', 4) # always full 24-word (256 bit) entropy seed = bytearray(32) rng_bytes(seed) assert len(set(seed)) > 4 # TRNG failure # hash to mitigate bias in TRNG seed = tcc.sha256(seed).digest() await approve_word_list(seed)
def random_bytes(count): assert 8 <= count < 1024 rv = bytearray(count) rng_bytes(rv) return rv
async def make_new_wallet(): # pick a new random seed, and force them to # write it down, then save it. from main import dis from uasyncio import sleep_ms # CONCERN: memory is really contaminated with secrets in this process, much more so # than during normal operation. Maybe we should block USB and force a reboot as well? # LESSON LEARNED: if the user is writting down the words, as we have # vividly instructed, then it's a big deal to lose those words and have to start # over. So confirm that action, and don't volunteer it. # dramatic pause await ux_dramatic_pause('Generating...', 4) # always full 24-word (256 bit) entropy seed = bytearray(32) rng_bytes(seed) assert len(set(seed)) > 4, "impossible luck?" # hash to mitigate bias in TRNG seed = tcc.sha256(seed).digest() words = tcc.bip39.from_data(seed).split(' ') assert len(words) == 24 #print('words: ' + ' '.join(words)) while 1: # show the seed words ch = await show_words(words, escape='6') if ch == 'x': # user abort if await ux_confirm("Throw away those words and stop this process?" ): return else: continue if ch == '6': # wants to skip the quiz (undocumented) if await ux_confirm( "Skipping the quiz means you might have " "recorded the seed wrong and will be crying later."): break # Perform a test, to check they wrote them down ch = await word_quiz(words) if ch == 'x': # user abort quiz if await ux_confirm( "Throw away those words and stop this process? Press X to see the word list again and restart the quiz." ): return # show the words again, but don't change them continue # quiz passed break # Done! set_seed_value(words) # send them to home menu, now with a wallet enabled goto_top_menu()
def urandom(l): rv = bytearray(l) ckcc.rng_bytes(rv) return rv