Browse Source

Various bugfixes, better password handling

philemon 11 years ago
parent
commit
3302ac774f
9 changed files with 91 additions and 43 deletions
  1. 1 1
      MANIFEST
  2. 7 1
      mmgen-addrgen
  3. 7 3
      mmgen-passchg
  4. 22 4
      mmgen-txsign
  5. 6 2
      mmgen-walletgen
  6. 4 1
      mmgen/addr.py
  7. 2 2
      mmgen/mnemonic.py
  8. 41 28
      mmgen/utils.py
  9. 1 1
      setup.py

+ 1 - 1
MANIFEST

@@ -3,6 +3,7 @@ mmgen-addrgen
 mmgen-addrimport
 mmgen-addrimport
 mmgen-keygen
 mmgen-keygen
 mmgen-passchg
 mmgen-passchg
+mmgen-pywallet
 mmgen-txcreate
 mmgen-txcreate
 mmgen-txsend
 mmgen-txsend
 mmgen-txsign
 mmgen-txsign
@@ -30,7 +31,6 @@ mmgen/rpc/proxy.py
 mmgen/rpc/util.py
 mmgen/rpc/util.py
 scripts/bitcoind-walletunlock.py
 scripts/bitcoind-walletunlock.py
 scripts/deinstall.sh
 scripts/deinstall.sh
-scripts/pywallet.py
 tests/addr.py
 tests/addr.py
 tests/bitcoin.py
 tests/bitcoin.py
 tests/mn_electrum.py
 tests/mn_electrum.py

+ 7 - 1
mmgen-addrgen

@@ -163,7 +163,13 @@ if invoked_as == "addrgen":
 else:
 else:
 	if not 'no_addresses' in opts: opts['print_secret'] = True
 	if not 'no_addresses' in opts: opts['print_secret'] = True
 
 
-seed          = get_seed(infile,opts)
+# Repeat on incorrect pw entry
+silent = False
+while True:
+	seed = get_seed(infile,opts,silent=silent)
+	silent = True
+	if seed: break
+
 seed_id       = make_chksum_8(seed)
 seed_id       = make_chksum_8(seed)
 addr_data     = generate_addrs(seed, addr_list, opts)
 addr_data     = generate_addrs(seed, addr_list, opts)
 addr_data_str = format_addr_data(addr_data, seed_id, opts)
 addr_data_str = format_addr_data(addr_data, seed_id, opts)

+ 7 - 3
mmgen-passchg

@@ -66,9 +66,13 @@ infile = cmd_args[0]
 label,metadata,hash_preset,salt,enc_seed = get_data_from_wallet(infile,opts)
 label,metadata,hash_preset,salt,enc_seed = get_data_from_wallet(infile,opts)
 seed_id,key_id = metadata[:2]
 seed_id,key_id = metadata[:2]
 oldp = "" if 'keep_old_passphrase' in opts else "old "
 oldp = "" if 'keep_old_passphrase' in opts else "old "
-passwd = " ".join(get_words("","",("Enter %spassphrase: " % oldp),opts))
-key = make_key(passwd, salt, hash_preset)
-seed = decrypt_seed(enc_seed, key, seed_id, key_id)
+
+# Repeat on incorrect pw entry
+while True:
+	passwd = " ".join(get_words("","",("Enter %spassphrase: " % oldp),opts))
+	key = make_key(passwd, salt, hash_preset)
+	seed = decrypt_seed(enc_seed, key, seed_id, key_id)
+	if seed: break
 
 
 changed = {}
 changed = {}
 
 

+ 22 - 4
mmgen-txsign

@@ -109,7 +109,7 @@ if user_confirm("View transaction data? ",default_yes=False):
 	view_tx_data(c,inputs_data,tx_hex,metadata)
 	view_tx_data(c,inputs_data,tx_hex,metadata)
 
 
 # Are inputs mmgen addresses?
 # Are inputs mmgen addresses?
-infile,mmgen_addrs,other_addrs,keys = "",[],[],[]
+mmgen_addrs,other_addrs,keys = [],[],[]
 
 
 for i in inputs_data:
 for i in inputs_data:
 	if verify_mmgen_label(i['account']):
 	if verify_mmgen_label(i['account']):
@@ -121,9 +121,11 @@ if mmgen_addrs and not 'force_wallet_dat' in opts:
 	# Check that all the seed IDs are the same:
 	# Check that all the seed IDs are the same:
 	seed_ids = list(set([i['account'][:8] for i in mmgen_addrs]))
 	seed_ids = list(set([i['account'][:8] for i in mmgen_addrs]))
 	while seed_ids:
 	while seed_ids:
+		infile = False
 		if cmd_args:
 		if cmd_args:
 			infile = cmd_args.pop()
 			infile = cmd_args.pop()
 			ext = infile.split(".")[-1]
 			ext = infile.split(".")[-1]
+			found = False
 			for e,o in (
 			for e,o in (
 				(wallet_ext, {}),
 				(wallet_ext, {}),
 				(mn_ext,     {"from_mnemonic":True}),
 				(mn_ext,     {"from_mnemonic":True}),
@@ -131,15 +133,29 @@ if mmgen_addrs and not 'force_wallet_dat' in opts:
 				(brain_ext,  {})
 				(brain_ext,  {})
 			):
 			):
 				if e == ext:
 				if e == ext:
+					found = True
 					if e == brain_ext:
 					if e == brain_ext:
 						if "from_brain" in opts: o = opts
 						if "from_brain" in opts: o = opts
 						else:
 						else:
 							msg("'--from-brain' option must be specified for brainwallet file")
 							msg("'--from-brain' option must be specified for brainwallet file")
 							sys.exit(2)
 							sys.exit(2)
-					seed = get_seed(infile,o)
+					silent = False
+					while True:
+						seed = get_seed(infile,o,silent=silent)
+						silent = True
+						if seed: break
+
+			if not found:
+				msg("%s: invalid file extension" % ext)
+				sys.exit(2)
+
 		elif "from_brain" in opts or "from_mnemonic" in opts or "from_seed" in opts:
 		elif "from_brain" in opts or "from_mnemonic" in opts or "from_seed" in opts:
 			msg("Need data for seed ID %s" % seed_ids[0])
 			msg("Need data for seed ID %s" % seed_ids[0])
-			seed = get_seed("",opts)
+			silent = False
+			while True:
+				seed = get_seed("",opts,silent=silent)
+				silent = True
+				if seed: break
 		else:
 		else:
 			msg("One of '-b', '-m' or '-s' must be specified for seed IDs: %s" %
 			msg("One of '-b', '-m' or '-s' must be specified for seed IDs: %s" %
 					" ".join(seed_ids))
 					" ".join(seed_ids))
@@ -158,7 +174,9 @@ if mmgen_addrs and not 'force_wallet_dat' in opts:
 			keys += [i['wif'] for i in generate_addrs(seed, seed_id_addrs, o)]
 			keys += [i['wif'] for i in generate_addrs(seed, seed_id_addrs, o)]
 		else:
 		else:
 			msg("Supplied seed ID (%s) is incorrect" % seed_id)
 			msg("Supplied seed ID (%s) is incorrect" % seed_id)
-			sys.exit(2)
+			if infile:
+				msg("Invalid input file: %s" % infile)
+				sys.exit(2)
 
 
 	if other_addrs:
 	if other_addrs:
 		if 'keys_from_file' in opts:
 		if 'keys_from_file' in opts:

+ 6 - 2
mmgen-walletgen

@@ -151,8 +151,12 @@ if debug: display_user_random_data(usr_keys,key_timings)
 usr_rand_data = sha256(usr_keys).digest() + \
 usr_rand_data = sha256(usr_keys).digest() + \
 				sha256("".join(key_timings)).digest()
 				sha256("".join(key_timings)).digest()
 
 
-s = get_seed(infile,opts,no_wallet=True)
-if s: seed = s
+if 'from_mnemonic' in opts or 'from_brain' in opts or 'from_seed' in opts:
+	silent = False
+	while True:
+		seed = get_seed(infile,opts,silent=silent)
+		silent = True
+		if seed: break
 else:
 else:
 	# Truncate random data for smaller seed lengths
 	# Truncate random data for smaller seed lengths
 	seed = os_rand_data[0] + usr_rand_data
 	seed = os_rand_data[0] + usr_rand_data

+ 4 - 1
mmgen/addr.py

@@ -108,7 +108,10 @@ def generate_addrs(seed, addrnums, opts):
 		out.append(el)
 		out.append(el)
 
 
 	w = opts['gen_what']
 	w = opts['gen_what']
-	if t_addrs == 1: w = w[:-1]
+	if t_addrs == 1:
+		import re
+		w = re.sub('e*s$','',w)
+
 	sys.stderr.write("\rGenerated %s %s%s\n"%(t_addrs, w, " "*15))
 	sys.stderr.write("\rGenerated %s %s%s\n"%(t_addrs, w, " "*15))
 
 
 	return out
 	return out

+ 2 - 2
mmgen/mnemonic.py

@@ -50,12 +50,12 @@ def get_seed_from_mnemonic(mn,wl):
 	if len(mn) not in mnemonic_lens:
 	if len(mn) not in mnemonic_lens:
 		msg("Bad mnemonic (%i words).  Allowed numbers of words: %s" %
 		msg("Bad mnemonic (%i words).  Allowed numbers of words: %s" %
 				(len(mn)," ".join([str(i) for i in mnemonic_lens])))
 				(len(mn)," ".join([str(i) for i in mnemonic_lens])))
-		sys.exit(2)
+		return False
 
 
 	for w in mn:
 	for w in mn:
 		if w not in wl:
 		if w not in wl:
 			msg("Bad mnemonic: '%s' is not in the wordlist" % w)
 			msg("Bad mnemonic: '%s' is not in the wordlist" % w)
-			sys.exit(2)
+			return False
 
 
 	from binascii import unhexlify
 	from binascii import unhexlify
 	seed = unhexlify(baseNtohex(mn_base,mn,wl,mn_fill(mn)))
 	seed = unhexlify(baseNtohex(mn_base,mn,wl,mn_fill(mn)))

+ 41 - 28
mmgen/utils.py

@@ -536,7 +536,7 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts):
 	if 'outdir' in opts:
 	if 'outdir' in opts:
 		outfile = "%s/%s" % (opts['outdir'], outfile)
 		outfile = "%s/%s" % (opts['outdir'], outfile)
 
 
-	label = opts['label'] if 'label' in opts else "None"
+	label = opts['label'] if 'label' in opts else "No Label"
 
 
 	from mmgen.bitcoin import b58encode_pad
 	from mmgen.bitcoin import b58encode_pad
 
 
@@ -572,14 +572,15 @@ def write_walletdat_dump_to_file(wallet_id,data,num_keys,ext,what,opts):
 	msg("wallet.dat %s saved to file '%s'" % (what,outfile))
 	msg("wallet.dat %s saved to file '%s'" % (what,outfile))
 
 
 
 
-def	compare_checksums(chksum1, desc1, chksum2, desc2):
+def compare_checksums(chksum1, desc1, chksum2, desc2):
 
 
 	if chksum1.lower() == chksum2.lower():
 	if chksum1.lower() == chksum2.lower():
 		msg("OK (%s)" % chksum1.upper())
 		msg("OK (%s)" % chksum1.upper())
 		return True
 		return True
 	else:
 	else:
-		msg("ERROR!\nComputed checksum %s (%s) doesn't match checksum %s (%s)" \
-			% (desc1,chksum1,desc2,chksum2))
+		if debug:
+			msg("ERROR!\nComputed checksum %s (%s) doesn't match checksum %s (%s)" \
+				% (desc1,chksum1,desc2,chksum2))
 		return False
 		return False
 
 
 def _is_hex(s):
 def _is_hex(s):
@@ -588,7 +589,7 @@ def _is_hex(s):
 	else: return True
 	else: return True
 
 
 
 
-def	check_mmseed_format(words):
+def _check_mmseed_format(words):
 
 
 	valid = False
 	valid = False
 	what = "%s data" % seed_ext
 	what = "%s data" % seed_ext
@@ -602,12 +603,10 @@ def	check_mmseed_format(words):
 		msg("Incorrect length of checksum (%s) in %s" % (chklen,what))
 		msg("Incorrect length of checksum (%s) in %s" % (chklen,what))
 	else: valid = True
 	else: valid = True
 
 
-	if valid == False:
-		msg("Invalid %s data" % seed_ext)
-		sys.exit(3)
+	return valid
 
 
 
 
-def	check_wallet_format(infile, lines, opts):
+def check_wallet_format(infile, lines, opts):
 
 
 	def vmsg(s):
 	def vmsg(s):
 		if 'verbose' in opts: msg(s)
 		if 'verbose' in opts: msg(s)
@@ -638,9 +637,10 @@ def _check_chksum_6(chk,val,desc,infile):
 		msg("%s checksum passed: %s" % (desc.capitalize(),chk))
 		msg("%s checksum passed: %s" % (desc.capitalize(),chk))
 
 
 
 
-def get_data_from_wallet(infile,opts):
+def get_data_from_wallet(infile,opts,silent=False):
 
 
-	msg("Getting {} wallet data from file '{}'".format(proj_name,infile))
+	if not silent:
+		msg("Getting {} wallet data from file '{}'".format(proj_name,infile))
 
 
 	f = open_file_or_exit(infile, 'r')
 	f = open_file_or_exit(infile, 'r')
 
 
@@ -719,9 +719,11 @@ def get_words(infile,what,prompt,opts):
 	return words
 	return words
 
 
 
 
-def get_seed_from_seed_data(words):
+def _get_seed_from_seed_data(words):
 
 
-	check_mmseed_format(words)
+	if not _check_mmseed_format(words):
+		msg("Invalid %s data" % seed_ext)
+		return False
 
 
 	stored_chk = words[0]
 	stored_chk = words[0]
 	seed_b58 = "".join(words[1:])
 	seed_b58 = "".join(words[1:])
@@ -733,19 +735,23 @@ def get_seed_from_seed_data(words):
 		seed = b58decode_pad(seed_b58)
 		seed = b58decode_pad(seed_b58)
 		if seed == False:
 		if seed == False:
 			msg("Invalid b58 number: %s" % val)
 			msg("Invalid b58 number: %s" % val)
-			sys.exit(9)
+			return False
 
 
 		msg("%s data produces seed ID: %s" % (seed_ext,make_chksum_8(seed)))
 		msg("%s data produces seed ID: %s" % (seed_ext,make_chksum_8(seed)))
 		return seed
 		return seed
 	else:
 	else:
 		msg("Invalid checksum for {} seed".format(proj_name))
 		msg("Invalid checksum for {} seed".format(proj_name))
-		sys.exit(9)
+		return False
 
 
 
 
-def get_seed_from_wallet(infile,opts,
-		prompt="Enter {} wallet passphrase: ".format(proj_name)):
+def get_seed_from_wallet(
+		infile,
+		opts,
+		prompt="Enter {} wallet passphrase: ".format(proj_name),
+		silent=False
+		):
 
 
-	wdata = get_data_from_wallet(infile,opts)
+	wdata = get_data_from_wallet(infile,opts,silent=silent)
 	label,metadata,hash_preset,salt,enc_seed = wdata
 	label,metadata,hash_preset,salt,enc_seed = wdata
 
 
 	if 'verbose' in opts: _display_control_data(*wdata)
 	if 'verbose' in opts: _display_control_data(*wdata)
@@ -770,8 +776,8 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
 	msg_r("Checking key...")
 	msg_r("Checking key...")
 	chk = make_chksum_8(key)
 	chk = make_chksum_8(key)
 	if not compare_checksums(chk, "of key", key_id, "in header"):
 	if not compare_checksums(chk, "of key", key_id, "in header"):
-		msg("Passphrase incorrect?")
-		sys.exit(3)
+		msg("Incorrect passphrase")
+		return False
 
 
 	msg_r("Decrypting seed with key...")
 	msg_r("Decrypting seed with key...")
 
 
@@ -793,21 +799,22 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
 			else:
 			else:
 				msg("Incorrect passphrase")
 				msg("Incorrect passphrase")
 
 
-		sys.exit(3)
+		return False
 
 
 	if debug: msg("key: %s" % hexlify(key))
 	if debug: msg("key: %s" % hexlify(key))
 
 
 	return dec_seed
 	return dec_seed
 
 
 
 
-def get_seed(infile,opts,no_wallet=False):
+def get_seed(infile,opts,silent=False):
 	if 'from_mnemonic' in opts:
 	if 'from_mnemonic' in opts:
 		prompt = "Enter mnemonic: "
 		prompt = "Enter mnemonic: "
+		what = "mnemonic"
 		words = get_words(infile,"mnemonic data",prompt,opts)
 		words = get_words(infile,"mnemonic data",prompt,opts)
 
 
 		wl = get_default_wordlist()
 		wl = get_default_wordlist()
 		from mmgen.mnemonic import get_seed_from_mnemonic
 		from mmgen.mnemonic import get_seed_from_mnemonic
-		return get_seed_from_mnemonic(words,wl)
+		seed = get_seed_from_mnemonic(words,wl)
 	elif 'from_brain' in opts:
 	elif 'from_brain' in opts:
 		if 'quiet' not in opts:
 		if 'quiet' not in opts:
 			confirm_or_exit(
 			confirm_or_exit(
@@ -816,16 +823,22 @@ def get_seed(infile,opts,no_wallet=False):
 					*_get_from_brain_opt_params(opts)),
 					*_get_from_brain_opt_params(opts)),
 			"continue")
 			"continue")
 		prompt = "Enter brainwallet passphrase: "
 		prompt = "Enter brainwallet passphrase: "
+		what = "brainwallet"
 		words = get_words(infile,"brainwallet data",prompt,opts)
 		words = get_words(infile,"brainwallet data",prompt,opts)
-		return _get_seed_from_brain_passphrase(words,opts)
+		seed = _get_seed_from_brain_passphrase(words,opts)
 	elif 'from_seed' in opts:
 	elif 'from_seed' in opts:
 		prompt = "Enter seed in %s format: " % seed_ext
 		prompt = "Enter seed in %s format: " % seed_ext
+		what = "seed"
 		words = get_words(infile,"seed data",prompt,opts)
 		words = get_words(infile,"seed data",prompt,opts)
-		return get_seed_from_seed_data(words)
-	elif no_wallet:
-		return False
+		seed = _get_seed_from_seed_data(words)
 	else:
 	else:
-		return get_seed_from_wallet(infile, opts)
+		return get_seed_from_wallet(infile, opts, silent=silent)
+
+	if infile and not seed:
+		msg("Invalid %s file: %s" % (what,infile))
+		sys.exit(2)
+
+	return seed
 
 
 
 
 def remove_blanks_comments(lines):
 def remove_blanks_comments(lines):

+ 1 - 1
setup.py

@@ -3,7 +3,7 @@ from distutils.core import setup
 
 
 setup(
 setup(
 		name         = 'mmgen',
 		name         = 'mmgen',
-		version      = '0.6.4',
+		version      = '0.6.5',
 		author       = 'Philemon',
 		author       = 'Philemon',
 		author_email = 'mmgen-py@yandex.com',
 		author_email = 'mmgen-py@yandex.com',
 		url          = 'https://github.com/mmgen/mmgen',
 		url          = 'https://github.com/mmgen/mmgen',