def __init__(self, *, config: 'SimpleConfig', daemon: 'Daemon', plugins: 'Plugins'): BaseElectrumGui.__init__(self, config=config, daemon=daemon, plugins=plugins) self.network = daemon.network storage = WalletStorage(config.get_wallet_path()) if not storage.file_exists(): print("Wallet not found. try 'electrum create'") exit() if storage.is_encrypted(): password = getpass.getpass('Password:'******'') self.encoding = locale.getpreferredencoding() self.stdscr = curses.initscr() curses.noecho() curses.cbreak() curses.start_color() curses.use_default_colors() curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_CYAN) curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE) self.stdscr.keypad(1) self.stdscr.border(0) self.maxy, self.maxx = self.stdscr.getmaxyx() self.set_cursor(0) self.w = curses.newwin(10, 50, 5, 5) self.tab = 0 self.pos = 0 self.popup_pos = 0 self.str_recipient = "" self.str_description = "" self.str_amount = "" self.str_fee = "" self.history = None self.txid = [] self.register_callbacks() self.tab_names = [ _("History"), _("Send"), _("Receive"), _("Addresses"), _("Contacts"), _("Banner") ] self.num_tabs = len(self.tab_names)
def test_read_dictionary_from_file(self): some_dict = {"a": "b", "c": "d"} contents = json.dumps(some_dict) with open(self.wallet_path, "w") as f: contents = f.write(contents) storage = WalletStorage(self.wallet_path) db = WalletDB(storage.read(), manual_upgrades=True) self.assertEqual("b", db.get("a")) self.assertEqual("d", db.get("c"))
def run_upgrades(self, storage: WalletStorage, db: 'WalletDB') -> None: path = storage.path if db.requires_split(): self.hide() msg = _( "The wallet '{}' contains multiple accounts, which are no longer supported since Electrum-NMC 2.7.\n\n" "Do you want to split your wallet into multiple files?" ).format(path) if not self.question(msg): return file_list = db.split_accounts(path) msg = _('Your accounts have been moved to') + ':\n' + '\n'.join( file_list) + '\n\n' + _( 'Do you want to delete the old file') + ':\n' + path if self.question(msg): os.remove(path) self.show_warning(_('The file was removed')) # raise now, to avoid having the old storage opened raise UserCancelled() action = db.get_action() if action and db.requires_upgrade(): raise WalletFileException( 'Incomplete wallet files cannot be upgraded.') if action: self.hide() msg = _("The file '{}' contains an incompletely created wallet.\n" "Do you want to complete its creation now?").format(path) if not self.question(msg): if self.question( _("Do you want to delete '{}'?").format(path)): os.remove(path) self.show_warning(_('The file was removed')) return self.show() self.data = json.loads(storage.read()) self.run(action) for k, v in self.data.items(): db.put(k, v) db.write(storage) return if db.requires_upgrade(): self.upgrade_db(storage, db)
def test_update_password_with_app_restarts(self): wallet_str = '{"addr_history":{"1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr":[],"15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA":[],"1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6":[]},"addresses":{"change":[],"receiving":["1364Js2VG66BwRdkaoxAaFtdPb1eQgn8Dr","1Exet2BhHsFxKTwhnfdsBMkPYLGvobxuW6","15CyDgLffJsJgQrhcyooFH4gnVDG82pUrA"]},"keystore":{"keypairs":{"0344b1588589958b0bcab03435061539e9bcf54677c104904044e4f8901f4ebdf5":"L2sED74axVXC4H8szBJ4rQJrkfem7UMc6usLCPUoEWxDCFGUaGUM","0389508c13999d08ffae0f434a085f4185922d64765c0bff2f66e36ad7f745cc5f":"L3Gi6EQLvYw8gEEUckmqawkevfj9s8hxoQDFveQJGZHTfyWnbk1U","04575f52b82f159fa649d2a4c353eb7435f30206f0a6cb9674fbd659f45082c37d559ffd19bea9c0d3b7dcc07a7b79f4cffb76026d5d4dff35341efe99056e22d2":"5JyVyXU1LiRXATvRTQvR9Kp8Rx1X84j2x49iGkjSsXipydtByUq"},"type":"imported"},"pruned_txo":{},"seed_version":13,"stored_height":-1,"transactions":{},"tx_fees":{},"txi":{},"txo":{},"use_encryption":false,"verified_tx3":{},"wallet_type":"standard","winpos-qt":[100,100,840,405]}' db = WalletDB(wallet_str, manual_upgrades=False) storage = WalletStorage(self.wallet_path) wallet = Wallet(db, storage, config=self.config) wallet.stop() storage = WalletStorage(self.wallet_path) # if storage.is_encrypted(): # storage.decrypt(password) db = WalletDB(storage.read(), manual_upgrades=False) wallet = Wallet(db, storage, config=self.config) wallet.check_password(None) wallet.update_password(None, "1234") with self.assertRaises(InvalidPassword): wallet.check_password(None) with self.assertRaises(InvalidPassword): wallet.check_password("wrong password") wallet.check_password("1234")
print( f"> tested {num_tested} passwords so far... most recently tried: {password!r}" ) if __name__ == '__main__': if len(sys.argv) < 2: print("ERROR. usage: bruteforce_pw.py <path_to_wallet_file>") sys.exit(1) path = sys.argv[1] config = SimpleConfig() storage = WalletStorage(path) if not storage.file_exists(): print(f"ERROR. wallet file not found at path: {path}") sys.exit(1) if storage.is_encrypted(): test_password = partial(test_password_for_storage_encryption, storage) print(f"wallet found: with storage encryption.") else: db = WalletDB(storage.read(), manual_upgrades=True) wallet = Wallet(db, storage, config=config) if not wallet.has_password(): print("wallet found but it is not encrypted.") sys.exit(0) test_password = partial(test_password_for_keystore_encryption, wallet) print(f"wallet found: with keystore encryption.") password = bruteforce_loop(test_password) print(f"====================") print(f"password found: {password}")
class QEWalletDB(QObject): def __init__(self, parent=None): super().__init__(parent) from .qeapp import ElectrumQmlApplication self.daemon = ElectrumQmlApplication._daemon self.reset() _logger = get_logger(__name__) fileNotFound = pyqtSignal() pathChanged = pyqtSignal([bool], arguments=["ready"]) needsPasswordChanged = pyqtSignal() needsHWDeviceChanged = pyqtSignal() passwordChanged = pyqtSignal() validPasswordChanged = pyqtSignal() requiresSplitChanged = pyqtSignal() splitFinished = pyqtSignal() readyChanged = pyqtSignal() createError = pyqtSignal([str], arguments=["error"]) createSuccess = pyqtSignal() invalidPassword = pyqtSignal() def reset(self): self._path = None self._needsPassword = False self._needsHWDevice = False self._password = '' self._requiresSplit = False self._validPassword = True self._storage = None self._db = None self._ready = False @pyqtProperty('QString', notify=pathChanged) def path(self): return self._path @path.setter def path(self, wallet_path): if wallet_path == self._path: return self._logger.info('setting path: ' + wallet_path) self.reset() self._path = wallet_path self.pathChanged.emit(self._ready) @pyqtProperty(bool, notify=needsPasswordChanged) def needsPassword(self): return self._needsPassword @needsPassword.setter def needsPassword(self, wallet_needs_password): if wallet_needs_password == self._needsPassword: return self._needsPassword = wallet_needs_password self.needsPasswordChanged.emit() @pyqtProperty(bool, notify=needsHWDeviceChanged) def needsHWDevice(self): return self._needsHWDevice @needsHWDevice.setter def needsHWDevice(self, wallet_needs_hw_device): if wallet_needs_hw_device == self._needsHWDevice: return self._needsHWDevice = wallet_needs_hw_device self.needsHWDeviceChanged.emit() @pyqtProperty('QString', notify=passwordChanged) def password(self): return '' # no read access @password.setter def password(self, wallet_password): if wallet_password == self._password: return self._password = wallet_password self.passwordChanged.emit() @pyqtProperty(bool, notify=requiresSplitChanged) def requiresSplit(self): return self._requiresSplit @pyqtProperty(bool, notify=validPasswordChanged) def validPassword(self): return self._validPassword @validPassword.setter def validPassword(self, validPassword): if self._validPassword != validPassword: self._validPassword = validPassword self.validPasswordChanged.emit() @pyqtProperty(bool, notify=readyChanged) def ready(self): return self._ready @pyqtSlot() def verify(self): self.load_storage() if self._storage: self.load_db() @pyqtSlot() def doSplit(self): self._logger.warning('doSplit') if not self._requiresSplit: return self._db.split_accounts(self._path) self.splitFinished.emit() def load_storage(self): self._storage = WalletStorage(self._path) if not self._storage.file_exists(): self._logger.warning('file does not exist') self.fileNotFound.emit() self._storage = None return if self._storage.is_encrypted(): self.needsPassword = True try: self._storage.decrypt( '' if not self._password else self._password) self.validPassword = True except InvalidPassword as e: self.validPassword = False self.invalidPassword.emit() if not self._storage.is_past_initial_decryption(): self._storage = None def load_db(self): # needs storage accessible self._db = WalletDB(self._storage.read(), manual_upgrades=True) if self._db.requires_split(): self._logger.warning('wallet requires split') self._requiresSplit = True self.requiresSplitChanged.emit() return if self._db.get_action(): self._logger.warning( 'action pending. QML version doesn\'t support continuation of wizard' ) return if self._db.requires_upgrade(): self._logger.warning('wallet requires upgrade, upgrading') self._db.upgrade() self._db.write(self._storage) self._ready = True self.readyChanged.emit() @pyqtSlot('QJSValue', bool, str) def create_storage(self, js_data, single_password_enabled, single_password): self._logger.info('Creating wallet from wizard data') data = js_data.toVariant() self._logger.debug(str(data)) if single_password_enabled and single_password: data['encrypt'] = True data['password'] = single_password try: path = os.path.join( os.path.dirname(self.daemon.config.get_wallet_path()), data['wallet_name']) if os.path.exists(path): raise Exception('file already exists at path') storage = WalletStorage(path) if data['seed_type'] in ['old', 'standard', 'segwit']: #2fa, 2fa-segwit self._logger.debug('creating keystore from electrum seed') k = keystore.from_seed(data['seed'], data['seed_extra_words'], data['wallet_type'] == 'multisig') elif data['seed_type'] == 'bip39': self._logger.debug('creating keystore from bip39 seed') root_seed = keystore.bip39_to_seed(data['seed'], data['seed_extra_words']) derivation = normalize_bip32_derivation( data['derivation_path']) script = data['script_type'] if data[ 'script_type'] != 'p2pkh' else 'standard' k = keystore.from_bip43_rootseed(root_seed, derivation, xtype=script) else: raise Exception('unsupported/unknown seed_type %s' % data['seed_type']) if data['encrypt']: if k.may_have_password(): k.update_password(None, data['password']) storage.set_password( data['password'], enc_version=StorageEncryptionVersion.USER_PASSWORD) db = WalletDB('', manual_upgrades=False) db.set_keystore_encryption( bool(data['password']) and data['encrypt']) db.put('wallet_type', data['wallet_type']) db.put('seed_type', data['seed_type']) db.put('keystore', k.dump()) if k.can_have_deterministic_lightning_xprv(): db.put( 'lightning_xprv', k.get_lightning_xprv( data['password'] if data['encrypt'] else None)) db.load_plugins() db.write(storage) # minimally populate self after create self._password = data['password'] self.path = path self.createSuccess.emit() except Exception as e: self._logger.error(str(e)) self.createError.emit(str(e))