#!/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-addrgen: Generate a list or range of addresses from a mmgen deterministic wallet. Call as 'btc-keygen' to allow key generation as well. """ import sys from mmgen.Opts import * from mmgen.config import * from mmgen.license import * from mmgen.utils import * from mmgen.addr import * invoked_as = sys.argv[0].split("-")[-1] gen_what = "addresses" if invoked_as == "addrgen" else "keys" if invoked_as == "keygen": extra_help_data = ( "\n-A, --no-addresses Print only secret keys, no addresses", "\n-x, --b16 Print secret keys in hexadecimal too", "\nBy default, both addresses and secret keys are generated." ) else: extra_help_data = ("","","") help_data = { 'prog_name': sys.argv[0].split("/")[-1], 'desc': """Generate a list or range of {} from a {} wallet, mnemonic, seed or password""".format(gen_what,proj_name), 'usage':"[opts] [infile] <address list>", 'options': """ -h, --help Print this help message{} -d, --outdir d Specify an alternate directory 'd' for output -e, --echo-passphrase Display passphrase or mnemonic on screen upon entry -K, --no-keyconv Use internal libraries for address generation instead of 'keyconv' -l, --seed-len N Length of seed. Options: {} (default: {}) -p, --hash-preset p Use scrypt.hash() parameters from preset 'p' when hashing password (default: '{}') -P, --show-hash-presets Show information on available hash presets -q, --quiet Suppress warnings; overwrite files without asking -S, --stdout Print {W} to stdout -v, --verbose Produce more verbose output{} -b, --from-brain l,p Generate {W} from a user-created password, i.e. a "brainwallet", using seed length 'l' and hash preset 'p' (comma-separated) -m, --from-mnemonic Generate {W} from an electrum-like mnemonic -s, --from-seed Generate {W} from a seed in .{S} format Addresses are given in a comma-separated list. Hyphen-separated ranges are also allowed.{} If available, the external 'keyconv' program will be used for address generation. Data for the --from-<what> options will be taken from <infile> if <infile> is specified. Otherwise, the user will be prompted to enter the data. For passphrases all combinations of whitespace are equal, and leading and trailing space are ignored. This permits reading passphrase data from a multi-line file with free spacing and indentation. This is particularly convenient for long brainwallet passphrases, for example. BRAINWALLET NOTE: As brainwallets require especially strong hashing to thwart dictionary attacks, the brainwallet hash preset must be specified by the user, using the 'p' parameter of the '--from-brain' option The '--from-brain' option also requires the user to specify a seed length (the 'l' parameter) For a brainwallet passphrase to always generate the same keys and addresses, the same 'l' and 'p' parameters to '--from-brain' must be used in all future invocations with that passphrase """.format( extra_help_data[0], ", ".join([str(i) for i in seed_lens]), seed_len, hash_preset, extra_help_data[1], extra_help_data[2], W=gen_what, S=seed_ext ) } so = "h","A","d:","e","K","l:","p:","P","q","S","v","x","b:","m","s" lo = "help","no_addresses","outdir=","echo_passphrase","no_keyconv",\ "seed_len=","hash_preset=","show_hash_presets","quiet","stdout",\ "verbose","b16","from_brain=","from_mnemonic","from_seed" if invoked_as == "addrgen": short_opts = so[0:1] + so[2:10] + so[11:] long_opts = lo[0:1] + lo[2:10] + lo[11:] else: short_opts,long_opts = so,lo opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts) if 'show_hash_presets' in opts: show_hash_presets() # Sanity checking and processing of command-line arguments: opts['gen_what'] = gen_what set_if_unset_and_typeconvert(opts,( ('hash_preset',hash_preset,'str'), ('seed_len',seed_len,'int') )) # Exits on invalid input check_opts(opts,('hash_preset','seed_len','outdir','from_brain')) if debug: print "Processed options: %s" % repr(opts) print "Cmd args: %s" % repr(cmd_args) if len(cmd_args) == 1 and ( 'from_mnemonic' in opts or 'from_brain' in opts or 'from_seed' in opts ): infile,addr_list_arg = "",cmd_args[0] elif len(cmd_args) == 2: infile,addr_list_arg = cmd_args check_infile(infile) else: usage(help_data) addr_list = parse_address_list(addr_list_arg) if not 'quiet' in opts: do_license_msg() # Interact with user: if invoked_as == "keygen" and not 'quiet' in opts: confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue') # Generate data: if invoked_as == "addrgen": opts['print_addresses_only'] = True else: if not 'no_addresses' in opts: opts['print_secret'] = True seed = get_seed(infile,opts) seed_id = make_chksum_8(seed) addr_data = generate_addrs(seed, addr_list, opts) addr_data_str = format_addr_data(addr_data, seed_id, opts) # Output data: if 'stdout' in opts: if invoked_as == "keygen" and not 'quiet' in opts: confirm = True else: confirm = False write_to_stdout(addr_data_str,"secret keys",confirm) elif not sys.stdout.isatty(): write_to_stdout(addr_data_str,"secret keys",confirm=False) else: write_addr_data_to_file(seed, addr_data_str, addr_list, opts)