mmgen-wallet/mmgen-passchg
philemon 0894985bfa 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
2014-07-17 21:50:52 +04:00

128 lines
4.2 KiB
Python
Executable file

#!/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/>.
"""
mmgen-passchg: Change a mmgen deterministic wallet's passphrase, label or
hash preset
"""
import sys
from mmgen.Opts import *
from mmgen.util import *
import mmgen.config as g
help_data = {
'desc': """Change the passphrase, hash preset or label of a {}
deterministic wallet""".format(g.proj_name),
'usage': "[opts] [filename]",
'options': """
-h, --help Print this help message
-d, --outdir d Specify an alternate directory 'd' for output
-H, --show-hash-presets Show information on available hash presets
-k, --keep-old-passphrase Keep old passphrase (use when changing hash
strength or label only)
-L, --label l Change the wallet's label to 'l'
-p, --hash-preset p Change scrypt.hash() parameters to preset 'p'
(default: '{}')
-P, --passwd-file f Get new passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without
prompting
-v, --verbose Produce more verbose output
NOTE: The key ID will change if either the passphrase or hash preset
are changed
""".format(g.hash_preset)
}
short_opts = "hd:HkL:p:P:qv"
long_opts = "help","outdir=","show_hash_presets","keep_old_passphrase",\
"label=","hash_preset=","passwd_file=","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
check_opts(opts,long_opts)
if 'show_hash_presets' in opts: show_hash_presets()
if len(cmd_args) != 1:
msg("One input file must be specified")
sys.exit(2)
infile = cmd_args[0]
# Old key:
label,metadata,hash_preset,salt,enc_seed = get_data_from_wallet(infile)
seed_id,key_id = metadata[:2]
# Repeat on incorrect pw entry
prompt = "Enter %spassphrase: " % (""
if 'keep_old_passphrase' in opts else "old ")
while True:
passwd = get_mmgen_passphrase(prompt,{})
key = make_key(passwd, salt, hash_preset)
seed = decrypt_seed(enc_seed, key, seed_id, key_id)
if seed: break
changed = {}
if 'label' in opts:
if opts['label'] != label:
msg("Label changed: '%s' -> '%s'" % (label, opts['label']))
changed['label'] = True
else:
msg("Label is unchanged: '%s'" % (label))
else: opts['label'] = label # Copy the old label
if 'hash_preset' in opts:
if hash_preset != opts['hash_preset']:
qmsg("Hash preset has changed (%s -> %s)" %
(hash_preset, opts['hash_preset']))
changed['preset'] = True
else:
msg("Hash preset is unchanged")
else:
opts['hash_preset'] = hash_preset
if 'keep_old_passphrase' in opts:
msg("Keeping old passphrase by user request")
else:
new_passwd = get_new_passphrase("new passphrase", opts)
if new_passwd == passwd:
qmsg("Passphrase is unchanged")
else:
qmsg("Passphrase has changed")
passwd = new_passwd
changed['passwd'] = True
if 'preset' in changed or 'passwd' in changed: # Update key ID, salt
qmsg("Will update salt and key ID")
from hashlib import sha256
from Crypto import Random
salt = sha256(salt + Random.new().read(128)).digest()[:g.salt_len]
key = make_key(passwd, salt, opts['hash_preset'])
new_key_id = make_chksum_8(key)
qmsg("Key ID changed: %s -> %s" % (key_id,new_key_id))
key_id = new_key_id
enc_seed = encrypt_seed(seed, key)
elif not 'label' in changed:
msg("Data unchanged. No file will be written")
sys.exit(2)
write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts)