def read_wallet_file_data(self, filename, pwd=None, wallet_dir=None): self.path = None wallet_dir = wallet_dir if wallet_dir else 'wallets' self.index_cache = [[0, 0]] * self.max_mix_depth path = os.path.join(wallet_dir, filename) if not os.path.isfile(path): if get_network() == 'testnet': log.debug('filename interpreted as seed, only available in ' 'testnet because this probably has lower entropy') return "FAKESEED" + filename else: raise IOError('wallet file not found') if not pwd: log.info("Password required for non-testnet seed wallet") return None self.path = path fd = open(path, 'r') walletfile = fd.read() fd.close() walletdata = json.loads(walletfile) if walletdata['network'] != get_network(): raise ValueError('wallet network(%s) does not match ' 'joinmarket configured network(%s)' % (walletdata['network'], get_network())) if 'index_cache' in walletdata: self.index_cache = walletdata['index_cache'] if self.max_mix_depth > len(self.index_cache): #This can happen e.g. in tumbler when we need more mixdepths #than currently exist. Since we have no info for those extra #depths, we must default to (0,0) (but sync should find used #adddresses). self.index_cache += [[0, 0]] * (self.max_mix_depth - len(self.index_cache)) password_key = btc.bin_dbl_sha256(pwd) if 'encrypted_seed' in walletdata: #accept old field name encrypted_entropy = walletdata['encrypted_seed'] elif 'encrypted_entropy' in walletdata: encrypted_entropy = walletdata['encrypted_entropy'] try: decrypted_entropy = decryptData( password_key, encrypted_entropy.decode('hex')).encode('hex') # there is a small probability of getting a valid PKCS7 # padding by chance from a wrong password; sanity check the # seed length if len(decrypted_entropy) != 32: raise ValueError except ValueError: log.info('Incorrect password') return None if 'encrypted_mnemonic_extension' in walletdata: try: cleartext = decryptData( password_key, walletdata['encrypted_mnemonic_extension'].decode('hex')) #theres a small chance of not getting a ValueError from the wrong # password so also check the sum if cleartext[-9] != '\xff': raise ValueError chunks = cleartext.split('\xff') if len(chunks) < 3 or cleartext[-8:] != btc.dbl_sha256( chunks[1])[:8]: raise ValueError mnemonic_extension = chunks[1] except ValueError: log.info('incorrect password') return None else: mnemonic_extension = None if self.storepassword: self.password_key = password_key self.walletdata = walletdata if 'imported_keys' in walletdata: for epk_m in walletdata['imported_keys']: privkey = decryptData( password_key, epk_m['encrypted_privkey'].decode('hex')).encode('hex') #Imported keys are stored as 32 byte strings only, so the #second version below is sufficient, really. if len(privkey) != 64: raise Exception( "Unexpected privkey format; already compressed?:" + privkey) privkey += "01" if epk_m['mixdepth'] not in self.imported_privkeys: self.imported_privkeys[epk_m['mixdepth']] = [] self.addr_cache[btc.privtoaddr( privkey, magicbyte=get_p2pk_vbyte())] = ( epk_m['mixdepth'], -1, len(self.imported_privkeys[epk_m['mixdepth']])) self.imported_privkeys[epk_m['mixdepth']].append(privkey) if mnemonic_extension: return (decrypted_entropy, mnemonic_extension) else: return decrypted_entropy
def get_wallet_name(wallet): return 'joinmarket-wallet-' + btc.dbl_sha256(wallet.keys[0][0])[:6]