forked from ethereum/pyethsaletool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpyethsaletool.py
executable file
·291 lines (246 loc) · 9 KB
/
pyethsaletool.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#!/usr/bin/python
# Retrieved from
# https://raw.githubusercontent.com/ethereum/pyethsaletool/895aaf66312745ac3a98769d7b79f34e7f477317/aes.py
# on 2017-08-12
import python_sha3
import aes
import os
import sys
import json
import getpass
import pbkdf2 as PBKDF2
from bitcoin import *
from optparse import OptionParser
# Arguments
exodus = '1FxkfJQLJTXpW6QmxGT6oF43ZH959ns8Cq'
minimum = 1000000
# Option parsing
parser = OptionParser()
parser.add_option('-p', '--password',
default=None, dest='pw')
parser.add_option('-s', '--seed',
default=None, dest='seed')
parser.add_option('-w', '--wallet',
default='ethwallet.json', dest='wallet')
parser.add_option('-b', '--backup',
default='ethwallet.bkp.json', dest='backup')
parser.add_option('-o', '--overwrite',
default=False, dest='overwrite')
(options, args) = parser.parse_args()
# Function wrappers
def sha3(x):
return python_sha3.sha3_256(x).digest()
def pbkdf2(x):
return PBKDF2._pbkdf2(x, x, 2000)[:16]
# Prefer openssl because it's more well-tested and reviewed; otherwise,
# use pybitcointools' internal ecdsa implementation
try:
import openssl
except:
openssl = None
def openssl_tx_sign(tx, priv):
if len(priv) == 64:
priv = priv.decode('hex')
if openssl:
k = openssl.CKey()
k.generate(priv)
u = k.sign(bitcoin.bin_txhash(tx))
return u.encode('hex')
else:
return ecdsa_tx_sign(tx, priv)
def secure_sign(tx, i, priv):
i = int(i)
if not re.match('^[0-9a-fA-F]*$', tx):
return sign(tx.encode('hex'), i, priv).decode('hex')
if len(priv) <= 33:
priv = priv.encode('hex')
pub = privkey_to_pubkey(priv)
address = pubkey_to_address(pub)
signing_tx = signature_form(tx, i, mk_pubkey_script(address))
sig = openssl_tx_sign(signing_tx, priv)
txobj = deserialize(tx)
txobj["ins"][i]["script"] = serialize_script([sig, pub])
return serialize(txobj)
def secure_privtopub(priv):
if len(priv) == 64:
return secure_privtopub(priv.decode('hex')).encode('hex')
if openssl:
k = openssl.CKey()
k.generate(priv)
return k.get_pubkey()
else:
return privtopub(priv)
def tryopen(f):
try:
assert f
t = open(f).read()
try:
return json.loads(t)
except:
raise Exception("Corrupted file: "+f)
except:
return None
def eth_privtoaddr(priv):
pub = encode_pubkey(secure_privtopub(priv), 'bin_electrum')
return sha3(pub)[12:].encode('hex')
def getseed(encseed, pw, ethaddr):
seed = aes.decryptData(pw, encseed.decode('hex'))
ethpriv = sha3(seed)
if eth_privtoaddr(ethpriv) != ethaddr:
raise Exception("Ethereum address provided to getseed does not match!")
return seed
def mkbackup(wallet, pw):
seed = getseed(wallet['encseed'], pw, wallet['ethaddr'])
return {
"withpw": aes.encryptData(pw, seed).encode('hex'),
"withwallet": aes.encryptData(wallet['bkp'], seed).encode('hex'),
"ethaddr": wallet['ethaddr']
}
def genwallet(seed, pw):
encseed = aes.encryptData(pw, seed)
ethpriv = sha3(seed)
btcpriv = sha3(seed + '\x01')
ethaddr = sha3(secure_privtopub(ethpriv)[1:])[12:].encode('hex')
btcaddr = privtoaddr(btcpriv)
bkp = sha3(seed + '\x02').encode('hex')[:32]
return {
"encseed": encseed.encode('hex'),
"bkp": bkp,
"ethaddr": ethaddr,
"btcaddr": btcaddr,
}
def finalize(wallet, unspent, pw):
seed = getseed(wallet["encseed"], pw, wallet["ethaddr"])
balance = sum([o["value"] for o in unspent])
if balance == 0:
raise Exception("No funds in address")
if balance < minimum:
raise Exception("Insufficient funds. Need at least 0.001 BTC")
outs = [
exodus+':'+str(balance - 30000),
hex_to_b58check(wallet["ethaddr"])+':10000'
]
tx = mktx(unspent, outs)
btcpriv = sha3(seed+'\x01')
for i in range(len(unspent)):
tx = secure_sign(tx, i, btcpriv)
return tx
def recover_bkp_pw(bkp, pw):
return getseed(bkp['withpw'], pw, bkp['ethaddr'])
def recover_bkp_wallet(bkp, wallet):
return getseed(bkp['withwallet'], wallet['bkp'], bkp['ethaddr'])
def ask_for_password(twice=False):
if options.pw:
return pbkdf2(options.pw)
pw = getpass.getpass()
if twice:
pw2 = getpass.getpass()
if pw != pw2:
raise Exception("Passwords do not match")
return pbkdf2(pw)
def ask_for_seed():
if options.seed:
return options.seed
else:
# uses pybitcointools' 3-source random generator
return random_key().decode('hex')
def checkwrite(f, thunk):
try:
open(f)
# File already exists
if not options.overwrite:
s = "File %s already exists. Overwrite? (y/n) "
are_you_sure = raw_input(s % f)
if are_you_sure not in ['y', 'yes']:
sys.exit()
except:
# File does not already exist, we're fine
pass
open(f, 'w').write(thunk())
w = tryopen(options.wallet)
b = tryopen(options.backup)
# Generate new wallet
if not len(args):
pass
elif args[0] == 'genwallet':
pw = ask_for_password(True)
newwal = genwallet(ask_for_seed(), pw)
checkwrite(options.wallet, lambda: json.dumps(newwal))
if options.backup:
checkwrite(options.backup, lambda: json.dumps(mkbackup(newwal, pw)))
print ("Your intermediate Bitcoin address is:", newwal['btcaddr'])
# Backup existing wallet
elif args[0] == 'mkbackup':
if not w:
print ("Must specify wallet with -w")
if not opts['backup']:
opts['backup'] = 'ethwallet.bkp.json'
pw = password()
checkwrite(opts['backup'], lambda: json.dumps(mkbackup(w, pw)))
# Get wallet Bitcoin address
elif args[0] == 'getbtcaddress':
if not w:
print ("Must specify wallet with -w")
print (w["btcaddr"])
# Get wallet Ethereum address
elif args[0] == 'getethaddress':
if not w:
print ("Must specify wallet with -w")
print (w["ethaddr"])
# Get wallet Bitcoin privkey
elif args[0] == 'getbtcprivkey':
pw = ask_for_password()
print (encode_privkey(sha3(getseed(w['encseed'], pw,
w['ethaddr'])+'\x01'), 'wif'))
# Get wallet seed
elif args[0] == 'getseed':
pw = ask_for_password()
print (getseed(w['encseed'], pw, w['ethaddr']))
# Get wallet Ethereum privkey
elif args[0] == 'getethprivkey':
pw = ask_for_password()
print (encode_privkey(sha3(getseed(w['encseed'], pw, w['ethaddr'])), 'hex'))
# Recover wallet seed
elif args[0] == 'recover':
if not w and not b:
print ("Must have wallet or backup file")
elif not b:
pw = ask_for_password()
print ("Your seed is:", getseed(w['encseed'], pw, w['ethaddr']))
elif not w:
pw = ask_for_password()
print ("Your seed is:", getseed(b['withpw'], pw, b['ethaddr']))
else:
print ("Your seed is:", getseed(b['withwallet'], w['bkp'], b['ethaddr']))
# Finalize a wallet
elif args[0] == 'finalize':
try:
u = unspent(w["btcaddr"])
except:
try:
u = blockr_unspent(w["btcaddr"])
except:
raise Exception("Blockchain.info and Blockr.io both down. Cannot get transaction outputs to finalize. Remember that your funds stored in the intermediate address can always be recovered by running './pyethsaletool.py getbtcprivkey' and importing the output into a Bitcoin wallet like blockchain.info")
pw = ask_for_password()
tx = finalize(w, u, pw)
try:
print (pushtx(tx))
except:
try:
print (eligius_pushtx(tx))
except:
raise Exception("Blockchain.info and Eligius both down. Cannot send transaction. Remember that your funds stored in the intermediate address can always be recovered by running './pyethsaletool.py getbtcprivkey' and importing the output into a Bitcoin wallet like blockchain.info")
# sha3 calculator
elif args[0] == 'sha3':
print (sha3(sys.argv[2]).encode('hex'))
# Help
else:
print ('Use "pyethsaletool genwallet" to generate a wallet')
print ('Use "pyethsaletool mkbackup" to make a backup of a wallet (using -w and -b)')
print ('Use "pyethsaletool getbtcaddress" to output the intermediate Bitcoin address you need to send funds to')
print ('Use "pyethsaletool getbtcprivkey" to output the private key to your intermediate Bitcoin address')
print ('Use "pyethsaletool getethaddress" to output the Ethereum address')
print ('Use "pyethsaletool getethprivkey" to output the Ethereum private key')
print ('Use "pyethsaletool finalize" to finalize the funding process once you have deposited to the intermediate address')
print ('Use "pyethsaletool recover" to recover the seed if you are missing either your wallet or your password')
print ('Use -s to specify a seed, -w to specify a wallet file, -b to specify a backup file and -p to specify a password when creating a wallet. The -w, -b and -p options also work with other commands.')