walletaid/walletaid.py

314 lines
9.9 KiB
Python

"""
Walletaid created by Dwerg using Python 2.7
Code for converting to addresses and WIF
is borrowed from pywallet.
"""
import hashlib
import binascii
from os import path
from ConfigParser import SafeConfigParser
from Tkinter import *
#Opens config.ini and gets settings, checks if wallet.dat is in folder
#config = SafeConfigParser()
"""
if not path.exists("config.ini"):
print "The config.ini file was not found"
exit(0)
"""
if not path.exists("wallet.dat"):
print "The wallet.dat file is not in folder or has different name"
exit(0)
#config.read("config.ini")
pubprefix = "169a"#config.get("settings", "pubkeyprefix")
privprefix = "ab36"#config.get("settings", "privkeyprefix")
compressed = False#config.getboolean("settings", "compressed")
#Loads wallet.dat into lists of addresses and private keys
with open('wallet.dat', 'rb') as f:
count = 0
klist = []
header = binascii.unhexlify("200001")
data = f.read()
header_index = data.find(header, 0)
key = data[header_index + len(header): header_index + len(header) + 32]
while True:
if key not in klist:
count += 1
#print "\rLoading wallet.dat {:.0f} % ".format(float(header_index) / len(data) * 100),
klist.append(key)
header_index = data.find(header,header_index + len(header) + 32)
if header_index >= 0:
key = data[header_index + len(header): header_index + len(header) + 32]
else:
break
print "\rLoading wallet.dat 100 % \nLoaded {} keys from wallet.dat\n".format(count)
#Calculates public key from a private key
class Point(object):
def __init__(self, _x, _y, _order = None): self.x, self.y, self.order = _x, _y, _order
def calc(self, top, bottom, other_x):
l = (top * inverse_mod(bottom)) % p
x3 = (l * l - self.x - other_x) % p
return Point(x3, (l * (self.x - x3) - self.y) % p)
def double(self):
if self == INFINITY: return INFINITY
return self.calc(3 * self.x * self.x, 2 * self.y, self.x)
def __add__(self, other):
if other == INFINITY: return self
if self == INFINITY: return other
if self.x == other.x:
if (self.y + other.y) % p == 0: return INFINITY
return self.double()
return self.calc(other.y - self.y, other.x - self.x, other.x)
def __mul__(self, e):
if self.order: e %= self.order
if e == 0 or self == INFINITY: return INFINITY
result, q = INFINITY, self
while e:
if e&1: result += q
e, q = e >> 1, q.double()
return result
def __str__(self):
if self == INFINITY: return "infinity"
return "%x %x" % (self.x, self.y)
def inverse_mod(a):
if a < 0 or a >= p: a = a % p
c, d, uc, vc, ud, vd = a, p, 1, 0, 0, 1
while c:
q, c, d = divmod(d, c) + (c,)
uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc
if ud > 0: return ud
return ud + p
p, INFINITY = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL, Point(None, None) # secp256k1
g = Point(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L,
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L)
#End of code used to calculate public key
#Base58 encoder
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def b58encode(v):
""" encode v, which is a string of bytes, to base58.
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += (256**i) * ord(c)
result = ''
while long_value >= __b58base:
div, mod = divmod(long_value, __b58base)
result = __b58chars[mod] + result
long_value = div
result = __b58chars[long_value] + result
nPad = 0
for c in v:
if c == '\0': nPad += 1
else: break
return (__b58chars[0]*nPad) + result
#SHA-256 hashception function
def Hash(data):
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
#Takes hexadecimal public key, spits out address
def hashtoaddr(a):
md = hashlib.new('ripemd160')
md.update(hashlib.sha256(binascii.unhexlify(a)).digest())
md160 = md.digest()
h = Hash(binascii.unhexlify(pubprefix)+md160)
addr = md160 + h[0:4]
return b58encode(binascii.unhexlify(pubprefix)+addr)
#Takes hexadecimal private key, spits out WIF
def hashtowif(b):
presha = binascii.unhexlify(privprefix) + b
if compressed: presha = presha + binascii.unhexlify("01")
h = Hash(presha)
key = presha + h[0:4]
return b58encode(key)
#Takes hexadecimal private key, spits out address
def address(c):
pubkey = str(g * c)
pubkey = ("0" * (64 - pubkey.index(" "))) + pubkey
if compressed:
if int(pubkey[-1], base=16) % 2 == 0:
pref = "02"
else:
pref = "03"
pubkey = pubkey[0:64]
else:
pref = "04"
if len(pubkey) < 129:
pubkey = pubkey[:64] + "0" + pubkey[64:]
pubkey = pubkey.replace(" ", "")
return hashtoaddr(pref + pubkey)
#GUI and code for printing output to textbox and file.
print "Opening GUI"
#Prints all keys.
def getAll():
frame1.destroy()
frame3.grid()
keyfile = open("foundkeys.txt","w")
count = 0
maxcount = len(klist)
for k in klist:
count += 1
#addr = address(int(binascii.hexlify(k), base = 16))
privkey = hashtowif(k)
#keyfile.write("Address: {}\nPrivate key: {}\n\n".format(addr, privkey))
keyfile.write("Private key: {}\n\n".format(privkey))
keyCount.set("Hashing key {}/{}".format(count, maxcount))
outBox.configure(state='normal')
#outBox.insert('end', "Address: {}\nPrivate key: {}\n\n".format(addr, privkey))
outBox.insert('end', "Private key: {}\n\n".format(privkey))
outBox.configure(state='disabled')
outBox.yview_moveto(1.0)
outBox.update()
outBox.configure(state='normal')
outBox.insert("end", "Finished search!\nSaved found keypairs to 'foundkeys.txt'")
outBox.configure(state='disabled')
outBox.yview_moveto(1.0)
#Goes to search window.
def searchWin():
frame1.destroy()
frame2.grid()
#Finds keys for addresses inputted by user, prints if found.
def submitSearch():
searchList = inField.get("1.0", END).split()
frame2.destroy()
frame3.grid()
keyfile = open("foundkeys.txt","w")
found = False
count = 0
maxcount = len(klist)
for k in klist:
count += 1
addr = address(int(binascii.hexlify(k), base = 16))
keyCount.set("Checking key {}/{}".format(count, maxcount))
for keysearch in searchList:
if addr == keysearch:
privkey = hashtowif(k)
keyfile.write("Address: {}\nPrivate key: {}\n\n".format(addr, privkey))
found = True
outBox.configure(state='normal')
outBox.insert('end', "Address: {}\nPrivate key: {}\n\n".format(addr, privkey))
outBox.configure(state='disabled')
outBox.yview_moveto(1.0)
outBox.update()
if not found:
outBox.configure(state='normal')
outBox.insert("end", "Entered address(es) was not found!")
outBox.configure(state='disabled')
else:
outBox.configure(state='normal')
outBox.insert("end", "Finished search!\nSaved found keypairs to 'foundkeys.txt'")
outBox.configure(state='disabled')
outBox.yview_moveto(1.0)
#Quits the program.
def kill():
root.destroy()
#Sets up the GUI frames.
root = Tk()
root.title("Walletaid")
root.resizable(width=False, height=False)
#Startup frame
frame1 = Frame(root)
frame1.grid()
instruction=Label(frame1,
text="Choose an option!",
font=("", 11 , "bold")
)
instruction.grid(row=0, column=1, columnspan=2)
selButton1 = Button(frame1, text="Get all keys", command=getAll)
selButton2 = Button(frame1, text="Search for specific keys", state="disabled", command=searchWin)
selButton1.grid(row=1, column=1)
selButton2.grid(row=1, column=2)
spacing1 = Frame(frame1, height=10)
spacing2 = Frame(frame1, width=10)
spacing3 = Frame(frame1, width=10)
spacing1.grid(row=2,columnspan=2)
spacing2.grid(rowspan=3)
spacing3.grid(column=3, rowspan=3)
#End startup frame
#Search frame
frame2 = Frame(root)
instruction=Label(frame2,
text="Enter a list of addresses to search for below",
font=("", 11 , "bold")
)
instruction.grid(row=0, column=1)
inField = Text(frame2, height=15, width=40)
inField.grid(row=1, column=1)
okButton = Button(frame2, text="OK", command=submitSearch)
okButton.grid(row=2, column=1, padx=55, pady=5, sticky=E)
cancelButton = Button(frame2, text="Close", command=kill)
cancelButton.grid(row=2, column=1, padx=5, pady=5, sticky=E)
spacing4 = Frame(frame2, width=10)
spacing5 = Frame(frame2, width=10)
spacing4.grid(column=0, rowspan=2)
spacing5.grid(column=2, rowspan=2)
#End search frame
#Output frame
frame3 = Frame(root)
keyCount = StringVar()
infoText = Label(frame3, textvariable=keyCount, font=("", 11 , "bold"))
infoText.grid(column=1)
scrollbar = Scrollbar(frame3)
outBox = Text(frame3, height=20, width=70, state="disabled", yscrollcommand=scrollbar.set)
outBox.grid(row=1, column=1)
scrollbar.grid(row=1, column=2, sticky=N+S)
scrollbar.config(command=outBox.yview)
closeButton = Button(frame3, height=2, width=15, text="Close", font=("", 11 , "bold"), command=kill)
closeButton.grid(row=2, column=1, pady=10)
spacing6 = Frame(frame3, width=10)
spacing7 = Frame(frame3, width=10)
spacing6.grid(column=0, rowspan=2)
spacing7.grid(column=3, rowspan=2)
#End output frame
#Launches the GUI
root.mainloop()