forked from surg0r/bip38
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathbip38.py
executable file
·76 lines (70 loc) · 2.86 KB
/
bip38.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
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/python
#import Crypto
from Crypto.Cipher import AES
import scrypt
import hashlib
from bitcoin import *
import binascii
import base58
def bip38_encrypt(privkey,passphrase):
'''BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey.'''
privformat = get_privkey_format(privkey)
if privformat in ['wif_compressed','hex_compressed']:
compressed = True
flagbyte = '\xe0'
if privformat == 'wif_compressed':
privkey = encode_privkey(privkey,'hex_compressed')
privformat = get_privkey_format(privkey)
if privformat in ['wif', 'hex']:
compressed = False
flagbyte = '\xc0'
if privformat == 'wif':
privkey = encode_privkey(privkey,'hex')
privformat = get_privkey_format(privkey)
pubkey = privtopub(privkey)
addr = pubtoaddr(pubkey)
addresshash = hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4]
key = scrypt.hash(passphrase, addresshash, 16384, 8, 8)
derivedhalf1 = key[0:32]
derivedhalf2 = key[32:64]
aes = AES.new(derivedhalf2)
encryptedhalf1 = aes.encrypt(binascii.unhexlify('%0.32x' % (long(privkey[0:32], 16) ^ long(binascii.hexlify(derivedhalf1[0:16]), 16))))
encryptedhalf2 = aes.encrypt(binascii.unhexlify('%0.32x' % (long(privkey[32:64], 16) ^ long(binascii.hexlify(derivedhalf1[16:32]), 16))))
encrypted_privkey = ('\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2)
encrypted_privkey += hashlib.sha256(hashlib.sha256(encrypted_privkey).digest()).digest()[:4] # b58check for encrypted privkey
encrypted_privkey = base58.b58encode(encrypted_privkey)
return encrypted_privkey
def bip38_decrypt(encrypted_privkey,passphrase):
'''BIP0038 non-ec-multiply decryption. Returns WIF privkey.'''
d = base58.b58decode(encrypted_privkey)
d = d[2:]
flagbyte = d[0:1]
d = d[1:]
if flagbyte == '\xc0':
compressed = False
if flagbyte == '\xe0':
compressed = True
addresshash = d[0:4]
d = d[4:-4]
key = scrypt.hash(passphrase,addresshash, 16384, 8, 8)
derivedhalf1 = key[0:32]
derivedhalf2 = key[32:64]
encryptedhalf1 = d[0:16]
encryptedhalf2 = d[16:32]
aes = AES.new(derivedhalf2)
decryptedhalf2 = aes.decrypt(encryptedhalf2)
decryptedhalf1 = aes.decrypt(encryptedhalf1)
priv = decryptedhalf1 + decryptedhalf2
priv = binascii.unhexlify('%064x' % (long(binascii.hexlify(priv), 16) ^ long(binascii.hexlify(derivedhalf1), 16)))
pub = privtopub(priv)
if compressed:
pub = encode_pubkey(pub,'hex_compressed')
wif = encode_privkey(priv,'wif_compressed')
else:
wif = encode_privkey(priv,'wif')
addr = pubtoaddr(pub)
if hashlib.sha256(hashlib.sha256(addr).digest()).digest()[0:4] != addresshash:
print('Verification failed. Password is incorrect.')
return ''
else:
return wif