Projects STRLCPY btcrecover Commits 5978c15e
🤬
  • removed dependence on bsddb for PyPy support

    initial testing with a Bitcoin Core wallet isn't very promising,
    maybe pypy's hashing library is too slow?
  • Loading...
  • Christopher Gurnee committed 1 decade ago
    5978c15e
    1 parent e6d92e63
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■
    btcrecover.py
    skipped 213 lines
    214 214   
    215 215  # Load a Bitcoin Core BDB wallet file given the filename and extract the first encrypted master key
    216 216  def load_bitcoincore_wallet(wallet_filename):
    217  - global wallet
     217 + global wallet, has_bsddb
    218 218   load_aes256_library()
    219  - import bsddb.db
    220  - db_env = bsddb.db.DBEnv()
    221  - db_env.open(os.path.dirname(wallet_filename), bsddb.db.DB_CREATE | bsddb.db.DB_INIT_MPOOL)
    222  - db = bsddb.db.DB(db_env)
    223  - db.open(wallet_filename, "main", bsddb.db.DB_BTREE, bsddb.db.DB_RDONLY)
    224  - mkey = db.get("\x04mkey\x01\x00\x00\x00")
    225  - db.close()
    226  - db_env.close()
     219 + 
     220 + mkey = None
     221 + try:
     222 + import bsddb.db
     223 + has_bsddb = True
     224 + except: has_bsddb = False
     225 + if has_bsddb:
     226 + db_env = bsddb.db.DBEnv()
     227 + db_env.open(os.path.dirname(wallet_filename), bsddb.db.DB_CREATE | bsddb.db.DB_INIT_MPOOL)
     228 + db = bsddb.db.DB(db_env)
     229 + db.open(wallet_filename, "main", bsddb.db.DB_BTREE, bsddb.db.DB_RDONLY)
     230 + mkey = db.get("\x04mkey\x01\x00\x00\x00")
     231 + db.close()
     232 + db_env.close()
     233 + 
     234 + else:
     235 + def align_32bits(i):
     236 + m = i % 4
     237 + return i+4-m if m else i
     238 + with open(wallet_filename, "rb") as wallet_file:
     239 + wallet_file_size=os.path.getsize(wallet_filename)
     240 + 
     241 + wallet_file.seek(12)
     242 + assert wallet_file.read(8) == "\x62\x31\x05\x00\x09\x00\x00\x00", "is a Btree v9 file"
     243 + wallet_file.seek(20)
     244 + (page_size,) = struct.unpack("<I", wallet_file.read(4))
     245 + 
     246 + # Don't actually try walking the btree, just look through every btree leaf page
     247 + # for the value/key pair (yes they are in that order...) we're searching for
     248 + for page_base in xrange(page_size, wallet_file_size, page_size): # skip the header page
     249 + wallet_file.seek(page_base+20)
     250 + (item_count, first_item_pos, btree_level, page_type) = struct.unpack("< H H B B", wallet_file.read(6))
     251 + if page_type != 5 or btree_level != 1: continue # skip non-btree and non-leaf pages
     252 + pos = align_32bits(page_base + first_item_pos)
     253 + wallet_file.seek(pos)
     254 + for i in xrange(item_count):
     255 + (item_len, item_type) = struct.unpack("< H B", wallet_file.read(3))
     256 + if item_type & ~0x80 == 1: # it's a variable-length key or value
     257 + if item_type == 1: # if it's not marked as deleted
     258 + if i % 2 == 0: # if it's a value, save it's position
     259 + value_pos = pos+3
     260 + value_len = item_len
     261 + elif item_len == 9 and wallet_file.read(item_len) == "\x04mkey\x01\x00\x00\x00":
     262 + wallet_file.seek(value_pos)
     263 + mkey = wallet_file.read(value_len) # found it!
     264 + break
     265 + pos = align_32bits(pos + 3 + item_len) # calc the position of the next item
     266 + else:
     267 + pos += 12 # the two other item types have a fixed length
     268 + if i+1 < item_count: # don't need to seek if this is the last item in the page
     269 + assert pos < page_base + page_size, "next item is located in current page"
     270 + wallet_file.seek(pos)
     271 + else: continue # if not found on this page, continue to next page
     272 + break # if we broke out of inner loop, break out of this one
     273 + 
    227 274   if not mkey:
    228 275   raise Exception("Encrypted master key #1 not found in the Bitcoin Core wallet file.\n"+
    229 276   "(is this wallet encrypted? is this a standard Bitcoin Core wallet?)")
    230 277   # This is a little fragile because it assumes the encrypted key and salt sizes are
    231 278   # 48 and 8 bytes long respectively, which although currently true may not always be:
    232 279   (encrypted_master_key, salt, method, iter_count) = struct.unpack_from("< 49p 9p I I", mkey)
    233  - if method != 0: raise NotImplementedError("Unsupported Bitcoin Core key derivation method " + method)
     280 + if method != 0: raise NotImplementedError("Unsupported Bitcoin Core key derivation method " + str(method))
    234 281   wallet = (encrypted_master_key, salt, iter_count)
    235 282   
    236 283  # Estimate the time it takes to try a single password (on a single CPU) for Bitcoin Core
    skipped 110 lines
    347 394   i += 16
    348 395   return str(plaintext)
    349 396   
     397 + 
    350 398  ############################## Argument Parsing ##############################
    351 399   
    352 400   
    skipped 94 lines
    447 495   elif os.path.isfile("btcrecover-tokens-auto.txt"): tokenlist_file = open("btcrecover-tokens-auto.txt")
    448 496   if tokenlist_file:
    449 497   if tokenlist_file.read(3) == "#--":
    450  - print(parser.prog+": warning: all options loaded from restore file; ignoring options in tokenlist file '"+tokenlist_file.name+"'")
     498 + print(parser.prog+": warning: all options loaded from restore file; ignoring options in tokenlist file '"+tokenlist_file.name+"'", file=sys.stderr)
    451 499   tokenlist_file.readline()
    452 500   else:
    453 501   tokenlist_file.seek(0)
    skipped 147 lines
    601 649   elif not args.listpass:
    602 650   print(parser.prog+": error: argument --wallet (or --listpass) is required", file=sys.stderr)
    603 651   sys.exit(2)
     652 + 
     653 + if not has_bsddb:
     654 + print(parser.prog+": warning: can't load bsddb, falling back to experimental Bitcoin Core wallet parsing mode", file=sys.stderr)
    604 655   
    605 656   # Open a new autosave file (if --restore was specified, the restore file
    606 657   # is still open and has already been assigned to autosave_file instead)
    skipped 609 lines
Please wait...
Page is in error, reload to recover