Browse Source

Regression fix in addr.py, improvements in mmgen-txsign.

philemon 10 years ago
parent
commit
ea449e652a
8 changed files with 72 additions and 70 deletions
  1. 2 1
      mmgen/addr.py
  2. 6 4
      mmgen/crypto.py
  3. 14 15
      mmgen/main.py
  4. 1 2
      mmgen/main_addrgen.py
  5. 11 11
      mmgen/main_txsign.py
  6. 6 6
      mmgen/tool.py
  7. 22 22
      mmgen/tx.py
  8. 10 9
      mmgen/util.py

+ 2 - 1
mmgen/addr.py

@@ -80,7 +80,8 @@ def generate_addrs(seed, addrnums, opts):
 	addrnums.sort()  # needed only if caller didn't sort
 
 	ws = 'key' if 'keys' in opts['gen_what'] else 'address'
-	if t_addrs != 1: wp = ws+"s" if ws == 'key' else ws+"es"
+	if t_addrs == 1: wp = ws
+	else: wp = ws+"s" if ws == 'key' else ws+"es"
 
 	while pos != t_addrs:
 		seed = sha512(seed).digest()

+ 6 - 4
mmgen/crypto.py

@@ -369,10 +369,11 @@ def _get_seed_from_brain_passphrase(words,opts):
 # Vars for mmgen_*crypt functions only
 salt_len,sha256_len,nonce_len = 32,32,32
 
-def mmgen_encrypt(data,what="data",hash_preset='3',opts={}):
+def mmgen_encrypt(data,what="data",hash_preset='',opts={}):
 	salt,iv,nonce = get_random(salt_len,opts),\
 		get_random(g.aesctr_iv_len,opts), get_random(nonce_len,opts)
-	hp,m = (hash_preset,"user-requested") if hash_preset else ('3',"default")
+	hp = hash_preset or get_hash_preset_from_user('3',what)
+	m = "default" if hp == '3' else "user-requested"
 	vmsg("Encrypting %s" % what)
 	qmsg("Using %s hash preset of '%s'" % (m,hp))
 	passwd = get_new_passphrase("passphrase",{})
@@ -382,11 +383,12 @@ def mmgen_encrypt(data,what="data",hash_preset='3',opts={}):
 	return salt+iv+enc_d
 
 
-def mmgen_decrypt(data,what="data",hash_preset='3',opts={}):
+def mmgen_decrypt(data,what="data",hash_preset='',opts={}):
 	dstart = salt_len + g.aesctr_iv_len
 	salt,iv,enc_d = data[:salt_len],data[salt_len:dstart],data[dstart:]
-	hp,m = (hash_preset,"user-requested") if hash_preset else ('3',"default")
 	vmsg("Preparing to decrypt %s" % what)
+	hp = hash_preset or get_hash_preset_from_user('3',what)
+	m = "default" if hp == '3' else "user-requested"
 	qmsg("Using %s hash preset of '%s'" % (m,hp))
 	passwd = get_mmgen_passphrase("Enter passphrase: ",{})
 	key = make_key(passwd, salt, hp)

+ 14 - 15
mmgen/main.py

@@ -20,25 +20,24 @@
 main.py - Script launcher for the MMGen suite
 """
 
-import sys, termios
-from mmgen.util import msg
+def launch_addrgen():    import mmgen.main_addrgen
+def launch_addrimport(): import mmgen.main_addrimport
+def launch_keygen():     import mmgen.main_addrgen
+def launch_passchg():    import mmgen.main_passchg
+def launch_pywallet():   import mmgen.main_pywallet
+def launch_tool():       import mmgen.main_tool
+def launch_txcreate():   import mmgen.main_txcreate
+def launch_txsend():     import mmgen.main_txsend
+def launch_txsign():     import mmgen.main_txsign
+def launch_walletchk():  import mmgen.main_walletchk
+def launch_walletgen():  import mmgen.main_walletgen
 
 def main(progname):
+	import sys, termios
 	fd = sys.stdin.fileno()
 	old = termios.tcgetattr(fd)
-	try:
-		if   progname == "addrgen":    import mmgen.main_addrgen
-		elif progname == "addrimport": import mmgen.main_addrimport
-		elif progname == "keygen":     import mmgen.main_addrgen
-		elif progname == "passchg":    import mmgen.main_passchg
-		elif progname == "pywallet":   import mmgen.main_pywallet
-		elif progname == "tool":       import mmgen.main_tool
-		elif progname == "txcreate":   import mmgen.main_txcreate
-		elif progname == "txsend":     import mmgen.main_txsend
-		elif progname == "txsign":     import mmgen.main_txsign
-		elif progname == "walletchk":  import mmgen.main_walletchk
-		elif progname == "walletgen":  import mmgen.main_walletgen
+	try: eval("launch_"+progname+"()")
 	except KeyboardInterrupt:
-		msg("\nUser interrupt")
+		sys.stderr.write("\nUser interrupt\n")
 		termios.tcsetattr(fd, termios.TCSADRAIN, old)
 		sys.exit(1)

+ 1 - 2
mmgen/main_addrgen.py

@@ -161,8 +161,7 @@ addr_data_str    = format_addr_data(
 outfile_base = "{}[{}]".format(seed_id, fmt_addr_idxs(addr_idxs))
 
 if 'flat_list' in opts and user_confirm("Encrypt key list?"):
-	hp = get_hash_preset_from_user('3')
-	addr_data_str = mmgen_encrypt(addr_data_str,"key list",hp,opts)
+	addr_data_str = mmgen_encrypt(addr_data_str,"key list","",opts)
 	enc_ext = "." + g.mmenc_ext
 else: enc_ext = ""
 

+ 11 - 11
mmgen/main_txsign.py

@@ -100,7 +100,6 @@ if 'from_incog_hex' in opts or 'from_incog_hidden' in opts:
 	opts['from_incog'] = True
 if 'all_keys_from_file' in opts:
 	opts['keys_from_file'] = opts['all_keys_from_file']
-#	opts['skip_key_preverify'] = True
 
 if not infiles: usage(help_data)
 for i in infiles: check_infile(i)
@@ -110,20 +109,19 @@ c = connect_to_bitcoind()
 saved_seeds = {}
 tx_files  = [i for i in set(infiles) if get_extension(i) == g.rawtx_ext]
 addrfiles = [a for a in set(infiles) if get_extension(a) == g.addrfile_ext]
-infiles  = list(set(infiles) - set(tx_files) - set(addrfiles))
+seed_files  = list(set(infiles) - set(tx_files) - set(addrfiles))
 
 if not "info" in opts: do_license_msg(immed=True)
 
 if 'keys_from_file' in opts:
-	from mmgen.crypto import mmgen_decrypt
 	fn = opts['keys_from_file']
 	d = get_data_from_file(fn,"keylist")
 	if get_extension(fn) == g.mmenc_ext or not \
-		  is_b58_str(remove_comments(d.split("\n"))[0][:55]):
+		  is_btc_key(remove_comments(d.split("\n"))[0][:55]):
 		qmsg("Keylist appears to be encrypted")
+		from mmgen.crypto import mmgen_decrypt
 		while True:
-			hp = get_hash_preset_from_user('3')
-			d_dec = mmgen_decrypt(d,"encrypted keylist",hp,opts)
+			d_dec = mmgen_decrypt(d,"encrypted keylist","",opts)
 			if d_dec: d = d_dec; break
 			else: msg("Trying again...")
 	keys_from_file = remove_comments(d.split("\n"))
@@ -157,8 +155,9 @@ for tx_file in tx_files:
 		sys.exit(2)
 
 	if other_inputs and keys and not 'skip_key_preverify' in opts:
-		a = [i['address'] for i in other_inputs]
-		preverify_keys(a, keys)
+		addrs = [i['address'] for i in other_inputs]
+		mm_inputs = mmgen_inputs if 'all_keys_from_file' in opts else []
+		preverify_keys(addrs, keys, mm_inputs)
 		opts['skip_key_preverify'] = True
 
 	if 'all_keys_from_file' in opts:
@@ -168,7 +167,7 @@ for tx_file in tx_files:
 			confirm_or_exit(txmsg['skip_mapping_checks_warning'],"continue")
 	else:
 		check_mmgen_to_btc_addr_mappings(
-				mmgen_inputs,b2m_map,infiles,saved_seeds,opts)
+				mmgen_inputs,b2m_map,seed_files,saved_seeds,opts)
 
 	if len(tx_files) > 1:
 		msg("\nTransaction %s/%s:" % (tx_files.index(tx_file)+1,len(tx_files)))
@@ -185,7 +184,7 @@ for tx_file in tx_files:
 
 	if mmgen_inputs and not 'all_keys_from_file' in opts:
 		ml = [i['account'].split()[0] for i in mmgen_inputs]
-		keys += get_keys_for_mmgen_addrs(ml,infiles,saved_seeds,opts)
+		keys += get_keys_for_mmgen_addrs(ml,seed_files,saved_seeds,opts)
 
 		if 'use_wallet_dat' in opts:
 			sig_tx = sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts)
@@ -207,7 +206,8 @@ for tx_file in tx_files:
 					repr(inputs_data),
 					repr(b2m_map)
 				)
-			write_to_file(outfile,data,opts,"signed transaction",True,True)
+			confirm = False if g.quiet else True
+			write_to_file(outfile,data,opts,"signed transaction",confirm,True)
 	else:
 		msg("failed\nSome keys were missing.  Transaction could not be signed.")
 		sys.exit(3)

+ 6 - 6
mmgen/tool.py

@@ -72,8 +72,8 @@ commands = {
 	"pubkey2addr":  ['<public key in hex format> [str]'],
 	"pubkey2hexaddr": ['<public key in hex format> [str]'],
 	"privhex2addr": ['<private key in hex format> [str]','compressed [bool=False]'],
-	"encrypt":      ['<infile> [str]','outfile [str=""]','hash_preset [str="3"]'],
-	"decrypt":      ['<infile> [str]','outfile [str=""]','hash_preset [str="3"]'],
+	"encrypt":      ['<infile> [str]','outfile [str=""]','hash_preset [str=""]'],
+	"decrypt":      ['<infile> [str]','outfile [str=""]','hash_preset [str=""]'],
 	"rand2file":    ['<outfile> [str]','<nbytes> [str]','threads [int=4]'],
 	"bytespec":     ['<bytespec> [str]'],
 }
@@ -416,9 +416,9 @@ def hex2wif(hexpriv,compressed=False):
 	print bitcoin.hextowif(hexpriv,compressed)
 
 
-def encrypt(infile,outfile="",hash_preset='3'):
+def encrypt(infile,outfile="",hash_preset=''):
 	data = get_data_from_file(infile,"data for encryption")
-	enc_d = mmgen_encrypt(data,"",hash_preset,opts)
+	enc_d = mmgen_encrypt(data,"user data","",opts)
 	if outfile == '-':
 		write_to_stdout(enc_d,"encrypted data",confirm=True)
 	else:
@@ -427,9 +427,9 @@ def encrypt(infile,outfile="",hash_preset='3'):
 		write_to_file(outfile, enc_d, opts,"encrypted data",True,True)
 
 
-def decrypt(infile,outfile="",hash_preset='3'):
+def decrypt(infile,outfile="",hash_preset=''):
 	enc_d = get_data_from_file(infile,"encrypted data")
-	dec_d = mmgen_decrypt(enc_d,"",hash_preset,opts)
+	dec_d = mmgen_decrypt(enc_d,"user data","",opts)
 	if outfile == '-':
 		write_to_stdout(dec_d,"decrypted data",confirm=True)
 	else:

+ 22 - 22
mmgen/tx.py

@@ -137,6 +137,7 @@ def is_btc_amt(amt):
 
 
 def normalize_btc_amt(amt):
+	# amt must be a string!
 	ret = is_btc_amt(amt)
 	if ret: return ret
 	else:   sys.exit(3)
@@ -460,10 +461,15 @@ def is_b58_str(s):
 		if ch not in b58a: return False
 	return True
 
+def is_btc_key(s):
+	if s == "": return False
+	compressed = False if s[0] == '5' else True
+	from mmgen.bitcoin import wiftohex
+	return True if wiftohex(s,compressed) else False
 
 def mmaddr2btcaddr_bitcoind(c,mmaddr,acct_data):
 
-	# We don't want to create a new object, so we'll use append()
+	# Don't want to create a new object, so use append()
 	if not acct_data:
 		for i in c.listaccounts():
 			acct_data.append(i)
@@ -677,31 +683,21 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,sig_data,keys,opts):
 	return sig_tx
 
 
-def preverify_keys(addrs_orig, keys_orig):
-
-	addrs,keys,wrong_keys = set(addrs_orig[0:]),set(keys_orig[0:]),[]
+def preverify_keys(addrs_in, keys_in, mm_inputs):
 
-	if len(keys) < len(addrs):
-		msg("ERROR: not enough keys (%s) for number of non-%s addresses (%s)" %
-				(len(keys),g.proj_name,len(addrs)))
-		sys.exit(2)
+	addrs,keys,extra_keys = set(addrs_in),set(keys_in),[]
 
 	import mmgen.bitcoin as b
 
 	qmsg_r('Checking that user-supplied key list contains valid keys...')
 
-	invalid_keys = []
-
-	for n,k in enumerate(keys,1):
-		c = False if k[0] == '5' else True
-		if b.wiftohex(k,compressed=c) == False:
-			invalid_keys.append(k)
-
+	invalid_keys = [k for k in keys if not is_btc_key(k)]
 	if invalid_keys:
 		s = "" if len(invalid_keys) == 1 else "s"
 		msg("\n%s/%s invalid key%s in keylist!\n" % (len(invalid_keys),len(keys),s))
 		sys.exit(2)
-	else: qmsg("OK")
+
+	qmsg("OK")
 
 	# Check that keys match addresses:
 	msg('Pre-verifying keys in user-supplied key list (Ctrl-C to skip)')
@@ -716,19 +712,23 @@ def preverify_keys(addrs_orig, keys_orig):
 				addrs.remove(addr)
 				if not addrs: break
 			else:
-				wrong_keys.append(k)
+				extra_keys.append(k)
 	except KeyboardInterrupt:
 		msg("\nSkipping")
 	else:
 		msg("")
-		if wrong_keys:
-			s = "" if len(wrong_keys) == 1 else "s"
-			msg("%s extra key%s found" % (len(wrong_keys),s))
+		if extra_keys:
+			s = "" if len(extra_keys) == 1 else "s"
+			msg("%s extra key%s found" % (len(extra_keys),s))
 
 		if addrs:
+			mms = dict([(i['address'],i['account'].split()[0])
+					for i in mm_inputs if i['address'] in addrs])
 			s = "" if len(addrs) == 1 else "es"
-			msg("No keys found for the following address%s:" % s)
-			print "  %s" % "\n  ".join(addrs)
+			msg(
+"Cannot sign transaction. No keys found for the following address%s:"%s)
+			for a in sorted(addrs):
+				print "  %s%s" % (a, "  ({})".format(mms[a]) if a in mms else "")
 			sys.exit(2)
 
 

+ 10 - 9
mmgen/util.py

@@ -347,14 +347,14 @@ def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=
 
 	if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
 
-	if confirm_overwrite:
-		from os import stat
-		try:
-			stat(outfile)
-		except:
-			pass
-		else:
+	from os import stat
+	try:    stat(outfile)
+	except: pass
+	else:
+		if confirm_overwrite:
 			confirm_or_exit("","File '%s' already exists\nOverwrite?" % outfile)
+		else:
+			msg("Overwriting file '%s'" % outfile)
 
 	f = open_file_or_exit(outfile,'w')
 	try:
@@ -685,8 +685,9 @@ def export_to_hidden_incog(incog_enc,opts):
 
 from mmgen.term import kb_hold_protect,get_char
 
-def get_hash_preset_from_user(hp='3'):
-	p = "Enter hash preset, or hit ENTER to accept the default ('%s'): " % hp
+def get_hash_preset_from_user(hp='3',what="data"):
+	p = "Enter hash preset for %s, or ENTER to accept the default ('%s'): " \
+		 % (what,hp)
 	while True:
 		ret = my_raw_input(p)
 		if ret: