Browse Source

Added 'mmgen-tool' utility with following commands:

  General operations:
  hexdump      - encode binary data in formatted hexadecimal form
  unhexdump    - decode formatted hexadecimal data

  Bitcoin operations:
  strtob58     - convert a string to base 58
  hextob58     - convert a hexadecimal number to base 58
  b58tohex     - convert a base 58 number to hexadecimal
  b58randenc   - generate a random 32-byte number and convert it to base 58
  randwif      - generate a random private key in WIF format
  randpair     - generate a random private key/address pair
  wif2addr     - generate a Bitcoin address from a key in WIF format

  Mnemonic operations (choose "electrum" (default), "tirosh" or "all" wordlists):
  mn_rand128   - generate random 128-bit mnemonic
  mn_rand192   - generate random 192-bit mnemonic
  mn_rand256   - generate random 256-bit mnemonic
  mn_stats     - show stats for mnemonic wordlist
  mn_printlist - print mnemonic wordlist
philemon 10 years ago
parent
commit
0894985bfa

+ 1 - 1
mmgen-addrgen

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen-addrimport

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen-passchg

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 68 - 0
mmgen-tool

@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
+# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+mmgen-tool: Perform various Bitcoin-related operations - part of the MMGen suite
+"""
+
+import sys, os
+from hashlib import sha256
+
+from mmgen.Opts import *
+import mmgen.config as g
+from mmgen.util import pretty_hexdump
+from mmgen.tool import *
+prog_name = sys.argv[0].split("/")[-1]
+
+help_data = {
+	'prog_name': prog_name,
+	'desc':    "Perform various BTC-related operations",
+	'usage':   "[opts] <command> <args>",
+	'options': """
+-h, --help                 Print this help message
+-q, --quiet                Produce quieter output
+-v, --verbose              Produce more verbose output
+
+COMMANDS:{}
+Type '{} <command> --help for usage information on a particular command
+""".format(command_help,prog_name)
+}
+
+short_opts = "hqv"
+long_opts  = "help","quiet","verbose"
+
+opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
+if 'quiet' in opts: g.quiet = True
+if 'verbose' in opts: g.verbose = True
+
+if len(cmd_args) < 1:
+	usage(help_data)
+	sys.exit(1)
+else: command = cmd_args.pop(0)
+
+if command not in commands.keys():
+	msg("'%s': No such command" % command)
+	sys.exit(1)
+
+if cmd_args and cmd_args[0] == '--help':
+	tool_usage(prog_name, command)
+	sys.exit(0)
+
+args = process_args(prog_name, command, cmd_args) if cmd_args else []
+
+#print command + "(" + ", ".join(args) + ")"
+eval(command + "(" + ", ".join(args) + ")")

+ 23 - 21
mmgen-txcreate

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by
@@ -79,36 +79,36 @@ if not 'info' in opts:
 			check_infile(a)
 			check_infile(a)
 			addr_data.append(parse_addrs_file(a))
 			addr_data.append(parse_addrs_file(a))
 
 
-	def mm2btc_addr_proc(c,mmadr,acct_data,addr_data,b2m_map):
-		btaddr,label = mmgen_addr_to_walletd(c,mmadr,acct_data)
-		if not btaddr:
-			btaddr,label = mmgen_addr_to_addr_data(mmadr,addr_data)
-		b2m_map[btaddr] = mmadr,label
-		return btaddr
+	def mm_addr2btc_addr(c,mmadr,acct_data,addr_data,b2m_map):
+		btcaddr,label = mmgen_addr_to_walletd(c,mmadr,acct_data)
+		if not btcaddr:
+			btcaddr,label = mmgen_addr_to_addr_data(mmadr,addr_data)
+		b2m_map[btcaddr] = mmadr,label
+		return btcaddr
 
 
 	for a in [i for i in cmd_args if not match_ext(i,g.addrfile_ext)]:
 	for a in [i for i in cmd_args if not match_ext(i,g.addrfile_ext)]:
 		if "," in a:
 		if "," in a:
 			a1,a2 = a.split(",")
 			a1,a2 = a.split(",")
-			if is_mmgen_addr(a1) or is_btc_addr(a1):
-				btaddr = mm2btc_addr_proc(c,a1,acct_data,addr_data,b2m_map) \
-					if is_mmgen_addr(a1) else a1
-				if is_btc_amt(a2):
-					tx_out[btaddr] = check_btc_amt(a2)
-				else:
-					msg("%s: invalid amount in argument '%s'" % (a2,a))
-					sys.exit(2)
+			if is_btc_addr(a1):
+				btcaddr = a1
+			elif is_mmgen_addr(a1):
+				btcaddr = mm_addr2btc_addr(c,a1,acct_data,addr_data,b2m_map)
 			else:
 			else:
 				msg("%s: unrecognized subargument in argument '%s'" % (a1,a))
 				msg("%s: unrecognized subargument in argument '%s'" % (a1,a))
 				sys.exit(2)
 				sys.exit(2)
+
+			if is_btc_amt(a2):
+				tx_out[btcaddr] = check_btc_amt(a2)
+			else:
+				msg("%s: invalid amount in argument '%s'" % (a2,a))
+				sys.exit(2)
 		elif is_mmgen_addr(a) or is_btc_addr(a):
 		elif is_mmgen_addr(a) or is_btc_addr(a):
 			if change_addr:
 			if change_addr:
-				msg("More than one change address specified: %s, %s" %
+				msg("ERROR: More than one change address specified: %s, %s" %
 						(change_addr, a))
 						(change_addr, a))
 				sys.exit(2)
 				sys.exit(2)
-			if is_mmgen_addr(a):
-				change_addr = mm2btc_addr_proc(c,a,acct_data,addr_data,b2m_map)
-			else:
-				change_addr = a
+			change_addr = a if is_btc_addr(a) else \
+				mm_addr2btc_addr(c,a,acct_data,addr_data,b2m_map)
 			tx_out[change_addr] = 0
 			tx_out[change_addr] = 0
 		else:
 		else:
 			msg("%s: unrecognized argument" % a)
 			msg("%s: unrecognized argument" % a)
@@ -157,7 +157,9 @@ msg("Total amount to spend: %s%s" % (
 while True:
 while True:
 	sel_nums = select_outputs(unspent,
 	sel_nums = select_outputs(unspent,
 			"Enter a range or space-separated list of outputs to spend: ")
 			"Enter a range or space-separated list of outputs to spend: ")
-	msg("Selected outputs: %s" % " ".join(str(i) for i in sel_nums))
+	msg("Selected output%s: %s" %
+		(("" if len(sel_nums) == 1 else "s"), " ".join(str(i) for i in sel_nums))
+	)
 	sel_unspent = [unspent[i-1] for i in sel_nums]
 	sel_unspent = [unspent[i-1] for i in sel_nums]
 
 
 	mmaddrs = set([parse_mmgen_label(i.account)[0] for i in sel_unspent])
 	mmaddrs = set([parse_mmgen_label(i.account)[0] for i in sel_unspent])

+ 1 - 1
mmgen-txsend

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen-txsign

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 8 - 39
mmgen-walletchk

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by
@@ -73,50 +73,19 @@ elif 'export_seed' in opts:
 	qmsg("Exporting seed data to file by user request")
 	qmsg("Exporting seed data to file by user request")
 elif 'export_incog' in opts:
 elif 'export_incog' in opts:
 	qmsg("Exporting wallet to incognito format by user request")
 	qmsg("Exporting wallet to incognito format by user request")
-
-	d = get_data_from_wallet(cmd_args[0],silent=True)
-	seed_id,key_id,preset,salt,enc_seed = \
-			d[1][0], d[1][1], d[2].split(":")[0], d[3], d[4]
-
-	passwd = get_mmgen_passphrase("Enter mmgen passphrase: ",opts)
-	key = make_key(passwd, salt, preset, "main key")
-	# We don't need the seed; just do this to verify password.
-	if decrypt_seed(enc_seed, key, seed_id, key_id) == False:
-		sys.exit(2)
-
-	from Crypto import Random
-	iv = Random.new().read(g.aesctr_iv_len)
-	iv_id = make_chksum_8(iv)
-	qmsg("IV ID: %s" % iv_id)
-
-	from binascii import hexlify
-	from hashlib import sha256
-	# IV is used BOTH to initialize counter and to salt password!
-	key = make_key(passwd, iv, preset, "wrapper key")
-	incog_enc = encrypt_seed(salt + enc_seed, key, iv=int(hexlify(iv),16))
+	incog_enc,seed_id,key_id,iv_id,preset = \
+		wallet_to_incog_data(cmd_args[0],opts)
 
 
 	if "export_incog_hidden" in opts:
 	if "export_incog_hidden" in opts:
-		fname,offset = opts['export_incog_hidden'].split(",") #Already sanity-checked
-		offset = int(offset)
-
-		check_data_fits_file_at_offset(fname,offset,len(iv + incog_enc),"write")
-
-		if not g.quiet: confirm_or_exit("","alter file '%s'" % fname)
-		f = os.open(fname,os.O_RDWR)
-		os.lseek(f, offset, os.SEEK_SET)
-		os.write(f, iv + incog_enc)
-		os.close(f)
-		qmsg("Data written to file '%s' at offset %s" % (fname,offset),
-				"Data written to file")
+		export_to_hidden_incog(incog_enc,opts)
 	else:
 	else:
+		seed_len = (len(incog_enc)-g.salt_len-g.aesctr_iv_len)*8
 		fn = "%s-%s-%s[%s,%s].%s" % (
 		fn = "%s-%s-%s[%s,%s].%s" % (
-			seed_id, key_id, iv_id, len(enc_seed)*8, preset,
+			seed_id, key_id, iv_id, seed_len, preset,
 			g.incog_hex_ext if "export_incog_hex" in opts else g.incog_ext
 			g.incog_hex_ext if "export_incog_hex" in opts else g.incog_ext
 		)
 		)
-		data = iv + incog_enc
-		if "export_incog_hex" in opts:
-			data = "".join([hexlify(data[i*2:i*2+2]) + (" " if (i+1)%8 else "\n")
-				for i in range(len(data)/2)])
+		data = pretty_hexdump(incog_enc,2,8,line_nums=False) \
+					if "export_incog_hex" in opts else incog_enc
 		export_to_file(fn, data, "incognito wallet data", opts)
 		export_to_file(fn, data, "incognito wallet data", opts)
 
 
 	sys.exit()
 	sys.exit()

+ 1 - 1
mmgen-walletgen

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen/Opts.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen/__init__.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen/addr.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen/bitcoin.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # MMGen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # MMGen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen/config.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 4 - 4
mmgen/license.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by
@@ -24,9 +24,9 @@ from mmgen.util import msg, msg_r, get_char
 
 
 gpl = {
 gpl = {
 	'warning': """
 	'warning': """
-  MMGen Copyright (C) 2013 by Philemon <mmgen-py@yandex.com>.  This
-  program comes with ABSOLUTELY NO WARRANTY.  This is free software,
-  and you are welcome to redistribute it under certain conditions.
+  MMGen Copyright (C) 2013-2014 by Philemon <mmgen-py@yandex.com>.  This
+  program comes with ABSOLUTELY NO WARRANTY.  This is free software, and
+  you are welcome to redistribute it under certain conditions.
 """,
 """,
 	'prompt': """
 	'prompt': """
 Press 'w' for conditions and warranty info, or 'c' to continue:
 Press 'w' for conditions and warranty info, or 'c' to continue:

+ 1 - 1
mmgen/mn_electrum.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 1 - 1
mmgen/mn_tirosh.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 2 - 2
mmgen/mnemonic.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by
@@ -95,7 +95,7 @@ def check_wordlist(wl_str,label):
 
 
 	from hashlib import sha256
 	from hashlib import sha256
 
 
-	print "Length:   %i" % len(wl)
+	print "Length:   %i words" % len(wl)
 	new_chksum = sha256(" ".join(wl)).hexdigest()[:8]
 	new_chksum = sha256(" ".join(wl)).hexdigest()[:8]
 
 
 	if new_chksum != wl_checksums[label]:
 	if new_chksum != wl_checksums[label]:

+ 1 - 1
mmgen/term.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 0 - 1
mmgen/tests/bitcoin.py

@@ -218,6 +218,5 @@ tests = {
 	"wiftoaddr_comp":           ['wif [str]'],
 	"wiftoaddr_comp":           ['wif [str]'],
 }
 }
 
 
-
 args = process_test_args(sys.argv, tests)
 args = process_test_args(sys.argv, tests)
 eval(sys.argv[1])(*args)
 eval(sys.argv[1])(*args)

+ 2 - 1
mmgen/tests/mnemonic.py

@@ -19,11 +19,12 @@
 mnemonic.py:  Test suite for mmgen.mnemonic module
 mnemonic.py:  Test suite for mmgen.mnemonic module
 """
 """
 
 
-from mmgen.mnemonic import *
 from test import *
 from test import *
 
 
 import sys
 import sys
 from binascii import hexlify
 from binascii import hexlify
+
+from mmgen.mnemonic import *
 from mmgen.mn_electrum  import electrum_words as el
 from mmgen.mn_electrum  import electrum_words as el
 from mmgen.mn_tirosh    import tirosh_words   as tl
 from mmgen.mn_tirosh    import tirosh_words   as tl
 
 

+ 244 - 0
mmgen/tool.py

@@ -0,0 +1,244 @@
+#!/usr/bin/env python
+#
+# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+tool.py:  Routines and data for the mmgen-tool utility
+"""
+
+import sys
+import mmgen.bitcoin as bitcoin
+
+from mmgen.util import *
+
+commands = {
+#	"keyconv_compare":          ['wif [str]'],
+#	"keyconv_compare_randloop": ['iterations [int]'],
+#	"hextob58_pad":             ['hexnum [str]],
+#	"b58tohex_pad":             ['b58num [str]'],
+#	"hextob58_pad_randloop":    ['iterations [int]'],
+#	"test_wiftohex":            ['wif [str]'],
+#	"hextosha256":              ['hexnum [str]'],
+#	"hextowiftopubkey":         ['hexnum [str]'],
+#	"pubhextoaddr":             ['hexnum [str]'],
+#	"hextowif_comp":            ['hexnum [str]'],
+#	"wiftohex_comp":            ['wif [str]'],
+#	"privhextoaddr_comp":       ['hexnum [str]'],
+#	"wiftoaddr_comp":           ['wif [str]'],
+	"strtob58":     ['<string> [str]'],
+	"hextob58":     ['<hex number> [str]'],
+	"b58tohex":     ['<b58 number> [str]'],
+	"b58randenc":   [],
+	"randwif":      ['compressed [bool=False]'],
+	"randpair":     ['compressed [bool=False]'],
+	"wif2addr":     ['<wif> [str]', 'compressed [bool=False]'],
+	"hexdump":      ['<infile> [str]', 'cols [int=8]', 'line_nums [bool=True]'],
+	"unhexdump":    ['<infile> [str]'],
+	"mn_rand128":   ['wordlist [str="electrum"]'],
+	"mn_rand192":   ['wordlist [str="electrum"]'],
+	"mn_rand256":   ['wordlist [str="electrum"]'],
+	"mn_stats":     ['wordlist [str="electrum"]'],
+	"mn_printlist": ['wordlist [str="electrum"]']
+}
+
+command_help = """
+General operations:
+hexdump      - encode binary data in formatted hexadecimal form
+unhexdump    - decode formatted hexadecimal data
+
+Bitcoin operations:
+strtob58     - convert a string to base 58
+hextob58     - convert a hexadecimal number to base 58
+b58tohex     - convert a base 58 number to hexadecimal
+b58randenc   - generate a random 32-byte number and convert it to base 58
+randwif      - generate a random private key in WIF format
+randpair     - generate a random private key/address pair
+wif2addr     - generate a Bitcoin address from a key in WIF format
+
+Mnemonic operations (choose "electrum" (default), "tirosh" or "all" wordlists):
+mn_rand128   - generate random 128-bit mnemonic
+mn_rand192   - generate random 192-bit mnemonic
+mn_rand256   - generate random 256-bit mnemonic
+mn_stats     - show stats for mnemonic wordlist
+mn_printlist - print mnemonic wordlist
+
+IMPORTANT NOTE: Though MMGen mnemonics use the Electrum wordlist, they're
+computed using a different algorithm and are NOT Electrum-compatible!
+"""
+
+def tool_usage(prog_name, command):
+	print "USAGE: '%s %s%s'" % (prog_name, command,
+		(" "+" ".join(commands[command]) if commands[command] else ""))
+
+def process_args(prog_name, command, uargs):
+	cargs = commands[command]
+	cargs_req = [[i.split(" [")[0],i.split(" [")[1][:-1]]
+		for i in cargs if "=" not in i]
+	cargs_nam = dict([[
+			i.split(" [")[0],
+			[i.split(" [")[1].split("=")[0], i.split(" [")[1].split("=")[1][:-1]]
+		] for i in cargs if "=" in i])
+	uargs_req = [i for i in uargs if "=" not in i]
+	uargs_nam = dict([i.split("=") for i in uargs if "=" in i])
+
+#	print cargs_req; print cargs_nam; print uargs_req; print uargs_nam; sys.exit()
+
+	n = len(cargs_req)
+	if len(uargs_req) != n:
+		print "ERROR: %s argument%s required" % (n, " is" if n==1 else "s are")
+		tool_usage(prog_name, command)
+		sys.exit(1)
+
+	for a in uargs_nam.keys():
+		if a not in cargs_nam.keys():
+			print "'%s' invalid named argument" % a
+			sys.exit(1)
+
+	def test_type(arg_type,arg,name=""):
+		try:
+			t = type(eval(arg))
+			assert(t == eval(arg_type))
+		except:
+			print "'%s': Invalid argument for argument %s ('%s' required)" % \
+				(arg, name, arg_type)
+			sys.exit(1)
+		return True
+
+	ret = []
+
+	for i in range(len(cargs_req)):
+		arg,arg_type = uargs_req[i], cargs_req[i][1]
+		if arg == "true" or arg == "false": arg = arg.capitalize()
+		if arg_type == "str":
+			ret.append('"%s"' % (arg))
+		elif test_type(arg_type, arg, "#"+str(i+1)):
+			ret.append('%s' % (arg))
+
+	for k in uargs_nam.keys():
+		arg,arg_type = uargs_nam[k], cargs_nam[k][0]
+		if arg == "true" or arg == "false": arg = arg.capitalize()
+		if arg_type == "str":
+			ret.append('%s="%s"' % (k, arg))
+		elif test_type(arg_type, arg, "'"+k+"'"):
+			ret.append('%s=%s' % (k, arg))
+
+	return ret
+
+
+# Individual commands
+
+def print_convert_results(indata,enc,dec,no_recode=False):
+	vmsg("Input:         [%s]" % indata)
+	vmsg_r("Encoded data:  ["); msg_r(enc); vmsg_r("]"); msg("")
+	if not no_recode:
+		vmsg("Recoded data:  [%s]" % dec)
+		if indata != dec:
+			msg("WARNING! Recoded number doesn't match input stringwise!")
+
+def hexdump(infile, cols=8, line_nums=True):
+	data = get_data_from_file(infile)
+	o = pretty_hexdump(data, 2, cols, line_nums)
+	print o
+
+def unhexdump(infile):
+	data = get_data_from_file(infile)
+	o = decode_pretty_hexdump(data)
+	sys.stdout.write(o)
+
+def strtob58(s):
+	enc = bitcoin.b58encode(s)
+	dec = bitcoin.b58decode(enc)
+	print_convert_results(s,enc,dec)
+
+def hextob58(s,f_enc=bitcoin.b58encode, f_dec=bitcoin.b58decode):
+	enc = f_enc(unhexlify(s))
+	dec = hexlify(f_dec(enc))
+	print_convert_results(s,enc,dec)
+
+def b58tohex(s,f_enc=bitcoin.b58decode, f_dec=bitcoin.b58encode):
+	tmp = f_enc(s)
+	if tmp == False: sys.exit(1)
+	enc = hexlify(tmp)
+	dec = f_dec(unhexlify(enc))
+	print_convert_results(s,enc,dec)
+
+def get_random(length):
+	from Crypto import Random
+	return Random.new().read(length)
+
+def b58randenc():
+	r = get_random(32)
+	enc = bitcoin.b58encode(r)
+	dec = bitcoin.b58decode(enc)
+	print_convert_results(hexlify(r),enc,hexlify(dec))
+
+def randwif(compressed=False):
+	r_hex = hexlify(get_random(32))
+	enc = bitcoin.hextowif(r_hex,compressed)
+	print_convert_results(r_hex,enc,"",no_recode=True)
+
+def randpair(compressed=False):
+	r_hex = hexlify(get_random(32))
+	wif = bitcoin.hextowif(r_hex,compressed)
+	addr = bitcoin.privnum2addr(int(r_hex,16),compressed)
+	vmsg("Key (hex):  %s" % r_hex)
+	vmsg_r("Key (WIF):  "); msg(wif)
+	vmsg_r("Addr:       "); msg(addr)
+
+def wif2addr(s_in,compressed=False):
+	s_enc = bitcoin.wiftohex(s_in,compressed)
+	if s_enc == False:
+		msg("Invalid address")
+		sys.exit(1)
+	addr = bitcoin.privnum2addr(int(s_enc,16),compressed)
+	vmsg_r("Addr: "); msg(addr)
+
+from mmgen.mnemonic import *
+from mmgen.mn_electrum  import electrum_words as el
+from mmgen.mn_tirosh    import tirosh_words   as tl
+
+wordlists = sorted(wl_checksums.keys())
+
+def get_wordlist(wordlist):
+	wordlist = wordlist.lower()
+	if wordlist not in wordlists:
+		msg('"%s": invalid wordlist.  Valid choices: %s' %
+			(wordlist,'"'+'" "'.join(wordlists)+'"'))
+		sys.exit(1)
+	return el if wordlist == "electrum" else tl
+
+def do_random_mn(nbytes,wordlist):
+	r = get_random(nbytes)
+	wlists = wordlists if wordlist == "all" else [wordlist]
+	for wl in wlists:
+		l = get_wordlist(wl)
+		if wl == wlists[0]: vmsg("Seed: %s" % hexlify(r))
+		mn = get_mnemonic_from_seed(r,l.strip().split("\n"),
+				wordlist,print_info=False)
+		vmsg("%s wordlist mnemonic:" % (wl.capitalize()))
+		print " ".join(mn)
+
+def mn_rand128(wordlist="electrum"): do_random_mn(16,wordlist)
+def mn_rand192(wordlist="electrum"): do_random_mn(24,wordlist)
+def mn_rand256(wordlist="electrum"): do_random_mn(32,wordlist)
+
+def mn_stats(wordlist="electrum"):
+	l = get_wordlist(wordlist)
+	check_wordlist(l,wordlist)
+
+def mn_printlist(wordlist="electrum"):
+	l = get_wordlist(wordlist)
+	print "%s" % l.strip()

+ 1 - 1
mmgen/tx.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 57 - 1
mmgen/util.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by
@@ -994,5 +994,61 @@ def do_pager(text):
 	else: print text+end
 	else: print text+end
 
 
 
 
+def export_to_hidden_incog(incog_enc,opts):
+	fname,offset = opts['export_incog_hidden'].split(",") #Already sanity-checked
+
+	check_data_fits_file_at_offset(fname,int(offset),len(incog_enc),"write")
+
+	if not g.quiet: confirm_or_exit("","alter file '%s'" % fname)
+	f = os.open(fname,os.O_RDWR)
+	os.lseek(f, int(offset), os.SEEK_SET)
+	os.write(f, incog_enc)
+	os.close(f)
+	qmsg("Data written to file '%s' at offset %s" % (fname,offset),
+			"Data written to file")
+
+
+def pretty_hexdump(data,gw,cols,line_nums=False):
+	r = 1 if len(data) % gw else 0
+	return "".join(
+		[
+			("" if (line_nums == False or i % cols) else "%03i: " % (i/cols)) +
+			hexlify(data[i*gw:i*gw+gw]) +
+			(" " if (i+1) % cols else "\n")
+				for i in range(len(data)/gw + r)
+		]
+	).rstrip()
+
+def decode_pretty_hexdump(data):
+	import re
+	lines = [re.sub('^\d+:\s+','',l) for l in data.split("\n")]
+	return unhexlify("".join(("".join(lines).split())))
+
+def wallet_to_incog_data(infile,opts):
+
+	d = get_data_from_wallet(infile,silent=True)
+	seed_id,key_id,preset,salt,enc_seed = \
+			d[1][0], d[1][1], d[2].split(":")[0], d[3], d[4]
+
+	passwd = get_mmgen_passphrase("Enter mmgen passphrase: ",opts)
+	key = make_key(passwd, salt, preset, "main key")
+	# We don't need the seed; just do this to verify password.
+	if decrypt_seed(enc_seed, key, seed_id, key_id) == False:
+		sys.exit(2)
+
+	from Crypto import Random
+	iv = Random.new().read(g.aesctr_iv_len)
+	iv_id = make_chksum_8(iv)
+	qmsg("IV ID: %s" % iv_id)
+
+	from binascii import hexlify
+	from hashlib import sha256
+	# IV is used BOTH to initialize counter and to salt password!
+	key = make_key(passwd, iv, preset, "wrapper key")
+	wrap_enc = encrypt_seed(salt + enc_seed, key, iv=int(hexlify(iv),16))
+
+	return iv+wrap_enc,seed_id,key_id,iv_id,preset
+
+
 if __name__ == "__main__":
 if __name__ == "__main__":
 	print "util.py"
 	print "util.py"

+ 1 - 1
mmgen/walletgen.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 #!/usr/bin/env python
 #
 #
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
 # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
-# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
+# Copyright (C) 2013-2014 by philemon <mmgen-py@yandex.com>
 #
 #
 # This program is free software: you can redistribute it and/or modify
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # it under the terms of the GNU General Public License as published by

+ 2 - 0
setup.py

@@ -20,6 +20,7 @@ setup(
 			'mmgen.mn_tirosh',
 			'mmgen.mn_tirosh',
 			'mmgen.Opts',
 			'mmgen.Opts',
 			'mmgen.term',
 			'mmgen.term',
+			'mmgen.tool',
 			'mmgen.tx',
 			'mmgen.tx',
 			'mmgen.util',
 			'mmgen.util',
 			'mmgen.walletgen',
 			'mmgen.walletgen',
@@ -52,5 +53,6 @@ setup(
 			'mmgen-txsign',
 			'mmgen-txsign',
 			'mmgen-txsend',
 			'mmgen-txsend',
 			'mmgen-pywallet'
 			'mmgen-pywallet'
+			'mmgen-tool',
 		]
 		]
 	)
 	)