URI: 
       tbruteforce_pw.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
       tbruteforce_pw.py (3913B)
       ---
            1 #!/usr/bin/env python3
            2 #
            3 # This script is just a demonstration how one could go about bruteforcing an
            4 # Electrum wallet file password. As it is pure-python and runs in the CPU,
            5 # it is horribly slow. It could be changed to utilise multiple threads
            6 # but any serious attempt would need at least GPU acceleration.
            7 #
            8 # There are two main types of password encryption that need to be disambiguated
            9 # for Electrum wallets:
           10 # (1) keystore-encryption: The wallet file itself is mostly plaintext (json),
           11 #                          only the Bitcoin private keys themselves are encrypted.
           12 #                          (e.g. seed words, xprv are encrypted; addresses are not)
           13 #                          Even in memory (at runtime), the private keys are typically
           14 #                          stored encrypted, and only when needed the user is prompted
           15 #                          for their password to decrypt the keys briefly.
           16 # (2) storage-encryption: The file itself is encrypted. When opened in a text editor,
           17 #                         it is base64 ascii text. Normally storage-encrypted wallets
           18 #                         also have keystore-encryption (unless they don't have private keys).
           19 # Storage-encryption was introduced in Electrum 2.8, keystore-encryption predates that.
           20 # Newly created wallets in modern Electrum have storage-encryption enabled by default.
           21 #
           22 # Storage encryption uses a stronger KDF than keystore-encryption.
           23 # As is, this script can test around ~1000 passwords per second for storage-encryption.
           24 
           25 import sys
           26 from string import digits, ascii_uppercase, ascii_lowercase
           27 from itertools import product
           28 from typing import Callable
           29 from functools import partial
           30 
           31 from electrum.wallet import Wallet, Abstract_Wallet
           32 from electrum.storage import WalletStorage
           33 from electrum.wallet_db import WalletDB
           34 from electrum.simple_config import SimpleConfig
           35 from electrum.util import InvalidPassword
           36 
           37 
           38 ALLOWED_CHARS = digits + ascii_uppercase + ascii_lowercase
           39 MAX_PASSWORD_LEN = 12
           40 
           41 
           42 def test_password_for_storage_encryption(storage: WalletStorage, password: str) -> bool:
           43     try:
           44         storage.decrypt(password)
           45     except InvalidPassword:
           46         return False
           47     else:
           48         return True
           49 
           50 
           51 def test_password_for_keystore_encryption(wallet: Abstract_Wallet, password: str) -> bool:
           52     try:
           53         wallet.check_password(password)
           54     except InvalidPassword:
           55         return False
           56     else:
           57         return True
           58 
           59 
           60 def bruteforce_loop(test_password: Callable[[str], bool]) -> str:
           61     num_tested = 0
           62     for pw_len in range(1, MAX_PASSWORD_LEN + 1):
           63         for pw_tuple in product(ALLOWED_CHARS, repeat=pw_len):
           64             password = "".join(pw_tuple)
           65             if test_password(password):
           66                 return password
           67             num_tested += 1
           68             if num_tested % 5000 == 0:
           69                 print(f"> tested {num_tested} passwords so far... most recently tried: {password!r}")
           70 
           71 
           72 if __name__ == '__main__':
           73     if len(sys.argv) < 2:
           74         print("ERROR. usage: bruteforce_pw.py <path_to_wallet_file>")
           75         sys.exit(1)
           76     path = sys.argv[1]
           77 
           78     config = SimpleConfig()
           79     storage = WalletStorage(path)
           80     if not storage.file_exists():
           81         print(f"ERROR. wallet file not found at path: {path}")
           82         sys.exit(1)
           83     if storage.is_encrypted():
           84         test_password = partial(test_password_for_storage_encryption, storage)
           85         print(f"wallet found: with storage encryption.")
           86     else:
           87         db = WalletDB(storage.read(), manual_upgrades=True)
           88         wallet = Wallet(db, storage, config=config)
           89         if not wallet.has_password():
           90             print("wallet found but it is not encrypted.")
           91             sys.exit(0)
           92         test_password = partial(test_password_for_keystore_encryption, wallet)
           93         print(f"wallet found: with keystore encryption.")
           94     password = bruteforce_loop(test_password)
           95     print(f"====================")
           96     print(f"password found: {password}")