forked from jleni/wallet-decrypt
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwallet-decrypt.py
64 lines (50 loc) · 1.85 KB
/
wallet-decrypt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python
from __future__ import print_function
import argparse
import base64
from hashlib import md5
from Crypto.Cipher import AES
import wallet_pb2
from binascii import hexlify, unhexlify
def derive_key_and_iv(password, salt, key_len, iv_len):
data = tmp2 = b''
tmp = password.encode() + salt
while len(data) < key_len + iv_len:
msg = tmp2 + tmp
tmp2 = md5(msg).digest()
data += tmp2
key = data[:key_len]
iv = data[key_len:key_len + iv_len]
return key, iv
def get_wallet(filename, password):
with open(filename, 'rb') as f:
data = base64.b64decode(f.read())
assert (data[:8] == b'Salted__')
salt = data[8:16]
key, iv = derive_key_and_iv(password, salt, 32, AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
len(data[AES.block_size:])
padded_plain = cipher.decrypt(data[AES.block_size:])
pad_len = padded_plain[-1]
if isinstance(pad_len, str):
pad_len = ord(pad_len)
pbdata = padded_plain[:-pad_len]
w = wallet_pb2.Wallet()
w.ParseFromString(pbdata)
return w
def main():
parser = argparse.ArgumentParser(description='Decrypt Bitcon Wallet (Schildbach''s Bitcoin)')
parser.add_argument('filename')
parser.add_argument('password')
args = parser.parse_args()
print("Extracting key pairs...\n")
w = get_wallet(args.filename, args.password)
for k in w.key:
if len(k.secret_bytes) > 0 and k.type != 3: # Type 3 are mnemonic keys and they make a mess
pubkey = int('0x0' + hexlify(k.public_key).decode('utf8'), 16)
print("Public :",'{:x}'.format(pubkey))
secret = int('0x0' + hexlify(k.secret_bytes).decode('utf8'), 16)
print("Private:",'{:x}'.format(secret))
print()
if __name__ == '__main__':
main()