Skip to content

Instantly share code, notes, and snippets.

@anfedorov
Created May 20, 2012 07:21
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save anfedorov/2757171 to your computer and use it in GitHub Desktop.
Save anfedorov/2757171 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import base64, hashlib, hmac, json, sys, getpass
from Crypto.Cipher import AES
from Crypto.Hash import RIPEMD, SHA256
base58_chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def prompt(p):
return getpass.getpass(p + ": ")
def decrypt(encrypted, password):
encrypted = base64.b64decode(encrypted)
iv, encrypted = encrypted[:16], encrypted[16:]
aeshash = pbkdf2(password, iv, 10, 32)
clear = remove_iso10126_padding(AES.new(aeshash, AES.MODE_CBC, iv).decrypt(encrypted))
return clear
def remove_iso10126_padding(s):
ba = bytearray(s)
pad_len = ba[-1]
return str(ba[:-pad_len])
def base58_decode(v):
value = 0; ret = ''
for c in v: value = value*58 + base58_chars.find(c)
for i in range(32):
ret = "%c"%(value%256) + ret; value /= 256
return ret
def base58_encode(v):
value = 0; ret = ''
for c in v: value = value*256 + ord(c)
while value > 0:
ret = base58_chars[value%58] + ret; value /= 58
return ret
def to_sipa(s):
version = 128 # or 239 for testnet
key = chr(version) + base58_decode(s)
return base58_encode(key + SHA256.new(SHA256.new(key).digest()).digest()[:4])
# pbkdf2 from http://matt.ucc.asn.au/src/pbkdf2.py
from struct import pack
# this is what you want to call.
def pbkdf2( password, salt, itercount, keylen, hashfn = hashlib.sha1 ):
digest_size = hashfn().digest_size
# l - number of output blocks to produce
l = keylen / digest_size
if keylen % digest_size != 0:
l += 1
h = hmac.new( password, None, hashfn )
T = ""
for i in range(1, l+1):
T += pbkdf2_F( h, salt, itercount, i )
return T[0: keylen]
def xorstr( a, b ):
if len(a) != len(b):
raise "xorstr(): lengths differ"
ret = ''
for i in range(len(a)):
ret += chr(ord(a[i]) ^ ord(b[i]))
return ret
def prf( h, data ):
hm = h.copy()
hm.update( data )
return hm.digest()
# Helper as per the spec. h is a hmac which has been created seeded with the
# password, it will be copy()ed and not modified.
def pbkdf2_F( h, salt, itercount, blocknum ):
U = prf( h, salt + pack('>i',blocknum ) )
T = U
for i in range(2, itercount+1):
U = prf( h, U )
T = xorstr( T, U )
return T
clear = decrypt(prompt("encrypted wallet"), prompt("password"))
obj = json.loads(clear)
if (obj.has_key('double_encryption')):
print("wallet uses double encryption")
password = obj['sharedKey'].encode('ascii') + prompt("2nd password")
for key in obj['keys']: key['priv'] = decrypt(key['priv'], password)
for key in obj['keys']: key['priv_sipa'] = to_sipa(key['priv'])
print(json.dumps(obj, indent=4, sort_keys = True))
@kyledrake
Copy link

Anyone have a JS version of this handy?

@fedaykinofdune
Copy link

Any clue how to make this work to bruteforce the 2nd password? I found one of my wallet backups and I've got .2 btc on it, I know the 1st pass no problem, but forgot my 2nd pass, mnemonic and stuff is long gone. If someone can hook me up with a script to force the 2nd password I'll split the loot with them!

@doge2021
Copy link

you may reach BTC recover , there is a chance to recover it.

Any clue how to make this work to bruteforce the 2nd password? I found one of my wallet backups and I've got .2 btc on it, I know the 1st pass no problem, but forgot my 2nd pass, mnemonic and stuff is long gone. If someone can hook me up with a script to force the 2nd password I'll split the loot with them!

you may reach BTC recover , there is a chance to recover it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment