mmgen-wallet/mmgen-walletchk
philemon a3c4bd8731 New feature: export wallet to incognito format
Incognito wallet is 48, 56 or 64 bytes of apparently random data.

  Allows user to hide wallet data in a pre-existing file or on a disk
  partition (preferably filled in advance with random data).

  Can be used to hide wallet securely in unencrypted cloud storage or
  on paper, without revealing the nature of the data.

  Data may be written at a user-specified offset into the file or
  partition, in which case user must remember the offset.

  Each export operation uses a new random init vector to create different
  data each time.  This allows the user to hide wallets at different
  locations on the Net without detection.

  User must remember hash preset in addition to passphrase (though trial
  and error can be used if it's forgotten).

  Fully integrated with address generation and tx signing operations.
2014-07-14 18:31:00 +04:00

134 lines
4.8 KiB
Python
Executable file

#!/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-walletchk: Check integrity of a mmgen deterministic wallet, display
information about it and export seed and mnemonic data
"""
import sys
from mmgen.Opts import *
from mmgen.util import *
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'desc': """Check integrity of a %s deterministic wallet, display
its information and export seed and mnemonic data."""\
% g.proj_name,
'usage': "[opts] [filename]",
'options': """
-h, --help Print this help message
-d, --outdir d Specify an alternate directory 'd' for output
-e, --echo-passphrase Print passphrase to screen when typing it
-P, --passwd-file f Get passphrase from file 'f'
-q, --quiet Suppress warnings; overwrite files without prompting
-S, --stdout Print seed or mnemonic data to standard output
-v, --verbose Produce more verbose output
-g, --export-incognito Export wallet to incognito format
-G, --hide-incog-data f,o Hide incognito data in existing file 'f'
at offset 'o' (comma-separated)
-m, --export-mnemonic Export the wallet's mnemonic to file
-s, --export-seed Export the wallet's seed to file
"""
}
short_opts = "hd:eP:qSvgG:ms"
long_opts = "help","outdir=","echo_passphrase","passwd_file=","quiet",\
"stdout","verbose",\
"export_incognito","hide_incog_data=","export_mnemonic","export_seed"
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 'hide_incog_data' in opts: opts['export_incognito'] = True
# Argument sanity checks and processing:
check_opts(opts,long_opts)
if len(cmd_args) != 1: usage(help_data)
check_infile(cmd_args[0])
if 'export_mnemonic' in opts:
qmsg("Exporting mnemonic data to file by user request")
elif 'export_seed' in opts:
qmsg("Exporting seed data to file by user request")
elif 'export_incognito' in opts:
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))
if "hide_incog_data" in opts:
fname,offset = opts['hide_incog_data'].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")
else:
fn = "%s-%s-%s[%s,%s].%s" % (seed_id, key_id, iv_id,
len(enc_seed)*8, preset, g.incog_ext)
export_to_file(fn, iv + incog_enc, "incognito wallet data", opts)
sys.exit()
seed = get_seed_from_wallet(cmd_args[0], opts)
if seed: qmsg("Wallet is OK")
else:
msg("Error opening wallet")
sys.exit(2)
if 'export_mnemonic' in opts:
wl = get_default_wordlist()
from mmgen.mnemonic import get_mnemonic_from_seed
p = True if g.debug else False
mn = get_mnemonic_from_seed(seed, wl, g.default_wl, print_info=p)
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.mn_ext)
export_to_file(fn, " ".join(mn)+"\n", "mnemonic data", opts)
elif 'export_seed' in opts:
from mmgen.bitcoin import b58encode_pad
data = col4(b58encode_pad(seed))
chk = make_chksum_6(b58encode_pad(seed))
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.seed_ext)
export_to_file(fn, "%s %s\n" % (chk,data), "seed data", opts)