Browse Source

use dumpprivkeys to efficiently dump private keys

283
thomasv 12 years ago
parent
commit
96d459ab88
  1. 18
      electrum
  2. 7
      lib/bitcoin.py
  3. 9
      lib/commands.py
  4. 30
      lib/wallet.py

18
electrum

@ -89,6 +89,7 @@ options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address
'prioritize':'', 'prioritize':'',
'unprioritize':'', 'unprioritize':'',
'dumpprivkey':'similar to bitcoind\'s command', 'dumpprivkey':'similar to bitcoind\'s command',
'dumpprivkeys':'dump all private keys',
'listunspent':'similar to bitcoind\'s command', 'listunspent':'similar to bitcoind\'s command',
'createmultisig':'similar to bitcoind\'s command', 'createmultisig':'similar to bitcoind\'s command',
'createrawtransaction':'similar to bitcoind\'s command', 'createrawtransaction':'similar to bitcoind\'s command',
@ -138,7 +139,6 @@ def arg_parser():
parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline")
parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses")
parser.add_option("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses") parser.add_option("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses")
parser.add_option("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses")
parser.add_option("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee") parser.add_option("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee")
parser.add_option("-F", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.") parser.add_option("-F", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.")
parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet") parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet")
@ -384,13 +384,13 @@ if __name__ == '__main__':
# important warning # important warning
if cmd=='addresses' and options.show_keys: if cmd in ['dumpprivkey', 'dumpprivkeys']:
print_msg("WARNING: ALL your private keys are secret.") print_msg("WARNING: ALL your private keys are secret.")
print_msg("Exposing a single private key can compromise your entire wallet!") print_msg("Exposing a single private key can compromise your entire wallet!")
print_msg("In particular, DO NOT use 'redeem private key' services proposed by third parties.") print_msg("In particular, DO NOT use 'redeem private key' services proposed by third parties.")
# commands needing password # commands needing password
if cmd in protected_commands or ( cmd=='addresses' and options.show_keys): if cmd in protected_commands:
if wallet.use_encryption: if wallet.use_encryption:
password = prompt_password('Password:', False) password = prompt_password('Password:', False)
if not password: if not password:
@ -440,7 +440,6 @@ if __name__ == '__main__':
args = [ cmd, address, signature, message] args = [ cmd, address, signature, message]
elif cmd == 'signrawtransaction': elif cmd == 'signrawtransaction':
args = [ cmd, args[1], ast.literal_eval(args[2]) if len(args)>2 else [], ast.literal_eval(args[3]) if len(args)>3 else []] args = [ cmd, args[1], ast.literal_eval(args[2]) if len(args)>2 else [], ast.literal_eval(args[3]) if len(args)>3 else []]
elif cmd == 'createmultisig': elif cmd == 'createmultisig':
@ -448,6 +447,13 @@ if __name__ == '__main__':
elif cmd == 'createrawtransaction': elif cmd == 'createrawtransaction':
args = [ cmd, ast.literal_eval(args[1]), ast.literal_eval(args[2])] args = [ cmd, ast.literal_eval(args[1]), ast.literal_eval(args[2])]
elif cmd == 'dumpprivkeys':
if options.show_all:
addresses = wallet.all_addresses()
else:
addresses = wallet.addresses + wallet.imported_keys.keys()
args = [cmd, addresses]
elif cmd == 'setlabel': elif cmd == 'setlabel':
try: try:
@ -565,8 +571,6 @@ if __name__ == '__main__':
b = format_satoshis(wallet.get_addr_balance(addr)[0]) b = format_satoshis(wallet.get_addr_balance(addr)[0])
else: b='' else: b=''
m_addr = "%34s"%addr m_addr = "%34s"%addr
if options.show_keys:
m_addr += ':' + str(wallet.get_private_key(addr, password))
print_msg(flags, m_addr, b, label) print_msg(flags, m_addr, b, label)
@ -580,7 +584,7 @@ if __name__ == '__main__':
cmd_runner = Commands(wallet, interface) cmd_runner = Commands(wallet, interface)
func = eval('cmd_runner.' + cmd) func = eval('cmd_runner.' + cmd)
if password: if password:
args.append( password ) cmd_runner.password = password
func(*args[1:]) func(*args[1:])

7
lib/bitcoin.py

@ -435,13 +435,16 @@ class DeterministicSequence:
public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 ) public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
return '04' + public_key2.to_string().encode('hex') return '04' + public_key2.to_string().encode('hex')
def get_private_key(self, n, for_change, seed): def get_private_key_from_stretched_exponent(self, n, for_change, secexp):
order = generator_secp256k1.order() order = generator_secp256k1.order()
secexp = self.stretch_key(seed)
secexp = ( secexp + self.get_sequence(n,for_change) ) % order secexp = ( secexp + self.get_sequence(n,for_change) ) % order
pk = number_to_string( secexp, generator_secp256k1.order() ) pk = number_to_string( secexp, generator_secp256k1.order() )
compressed = False compressed = False
return SecretToASecret( pk, compressed ) return SecretToASecret( pk, compressed )
def get_private_key(self, n, for_change, seed):
secexp = self.stretch_key(seed)
return self.get_private_key_from_stretched_exponent(n, for_change, secexp)
def check_seed(self, seed): def check_seed(self, seed):
curve = SECP256k1 curve = SECP256k1

9
lib/commands.py

@ -22,7 +22,7 @@ from bitcoin import *
from decimal import Decimal from decimal import Decimal
import bitcoin import bitcoin
protected_commands = ['payto', 'password', 'mktx', 'get_seed', 'importprivkey','signmessage', 'signrawtransaction','dumpprivkey' ] protected_commands = ['payto', 'password', 'mktx', 'get_seed', 'importprivkey','signmessage', 'signrawtransaction', 'dumpprivkey', 'dumpprivkeys' ]
class Commands: class Commands:
@ -135,8 +135,11 @@ class Commands:
print_msg(self.wallet.unprioritize(addr)) print_msg(self.wallet.unprioritize(addr))
def dumpprivkey(self, addr): def dumpprivkey(self, addr):
sec = self.wallet.get_private_key(addr, self.password) print_msg( self.wallet.get_private_key(addr, self.password) )
print_msg( sec )
def dumpprivkeys(self, addresses):
print_json( self.wallet.get_private_keys(addresses, self.password) )
def validateaddress(self,addr): def validateaddress(self,addr):
is_valid = self.wallet.is_valid(addr) is_valid = self.wallet.is_valid(addr)

30
lib/wallet.py

@ -213,23 +213,29 @@ class Wallet:
return seed return seed
def get_private_key(self, address, password): def get_private_key(self, address, password):
return self.get_private_keys([address], password)[address]
def get_private_keys(self, addresses, password):
# decode seed in any case, in order to test the password # decode seed in any case, in order to test the password
seed = self.decode_seed(password) seed = self.decode_seed(password)
secexp = self.sequence.stretch_key(seed)
if address in self.imported_keys.keys(): out = {}
return pw_decode( self.imported_keys[address], password ) for address in addresses:
else: if address in self.imported_keys.keys():
if address in self.addresses: pk = pw_decode( self.imported_keys[address], password )
n = self.addresses.index(address)
for_change = False
elif address in self.change_addresses:
n = self.change_addresses.index(address)
for_change = True
else: else:
raise BaseException("unknown address", address) if address in self.addresses:
n = self.addresses.index(address)
for_change = False
elif address in self.change_addresses:
n = self.change_addresses.index(address)
for_change = True
else:
raise BaseException("unknown address", address)
pk = self.sequence.get_private_key_from_stretched_exponent(n, for_change, secexp)
out[address] = pk
return out
return self.sequence.get_private_key(n, for_change, seed)
def sign_message(self, address, message, password): def sign_message(self, address, message, password):

Loading…
Cancel
Save