#!/usr/bin/env python # This software is # Copyright (c) 2012-2018 Dhiru Kholia # Copyright (c) 2019 Solar Designer # Copyright (c) 2019 exploide # Redistribution and use in source and binary forms, with or without # modification, are permitted. (This is a heavily cut-down "BSD license".) # # While the above applies to the stated copyright holders' contributions, # this software is also dual-licensed under the MIT License, to be certain # of license compatibility with that of the components listed below. # # This script (bitcoin2john.py) might still contain portions of jackjack's # pywallet.py [1] which is forked from Joric's pywallet.py whose licensing # information follows, # # [1] https://github.com/jackjack-jj/pywallet # # PyWallet 1.2.1 (Public Domain) # http://github.com/joric/pywallet # Most of the actual PyWallet code placed in the public domain. # PyWallet includes portions of free software, listed below. # # BitcoinTools (wallet.dat handling code, MIT License) # https://github.com/gavinandresen/bitcointools # Copyright (c) 2010 Gavin Andresen import binascii import logging import struct import sys try: from bsddb.db import * except: try: from bsddb3.db import * except: sys.stderr.write("Error: This script needs bsddb3 to be installed!\n") sys.exit(1) json_db = {} def hexstr(bytestr): return binascii.hexlify(bytestr).decode('ascii') # bitcointools wallet.dat handling code class SerializationError(Exception): """ Thrown when there's a problem deserializing or serializing """ class BCDataStream(object): def __init__(self): self.input = None self.read_cursor = 0 def clear(self): self.input = None self.read_cursor = 0 def write(self, bytes): # Initialize with string of bytes if self.input is None: self.input = bytes else: self.input += bytes def read_string(self): # Strings are encoded depending on length: # 0 to 252 : 1-byte-length followed by bytes (if any) # 253 to 65,535 : byte'253' 2-byte-length followed by bytes # 65,536 to 4,294,967,295 : byte '254' 4-byte-length followed by bytes # ... and the Bitcoin client is coded to understand: # greater than 4,294,967,295 : byte '255' 8-byte-length followed by bytes of string # ... but I don't think it actually handles any strings that big. if self.input is None: raise SerializationError("call write(bytes) before trying to deserialize") try: length = self.read_compact_size() except IndexError: raise SerializationError("attempt to read past end of buffer") return self.read_bytes(length).decode('ascii') def read_bytes(self, length): try: result = self.input[self.read_cursor:self.read_cursor + length] self.read_cursor += length return result except IndexError: raise SerializationError("attempt to read past end of buffer") return '' def read_uint32(self): return self._read_num('