Added features:
* 'mmgen-tool': file encryption utility with strong encryption * 'mmgen-tool': find hidden incognito data in file using the Incog ID * User may now supply additional entropy in all cases where random data is needed. This user entropy (typed symbols + keystroke intervals) is hashed into a key with Scrypt and used to encrypt all random data produced during the session by the OS.
This commit is contained in:
parent
6a0fb49c2f
commit
e328a6a24b
9 changed files with 204 additions and 88 deletions
1
MANIFEST
1
MANIFEST
|
|
@ -2,6 +2,7 @@
|
|||
__init__.py
|
||||
mmgen-addrgen
|
||||
mmgen-addrimport
|
||||
mmgen-keygen
|
||||
mmgen-passchg
|
||||
mmgen-pywallet
|
||||
mmgen-tool
|
||||
|
|
|
|||
|
|
@ -182,4 +182,5 @@ if not 'no_addresses' in opts:
|
|||
a = "address data checksum"
|
||||
write_to_file(outfile_base+".chk",addr_data_chksum,opts,a,confirm,True)
|
||||
else:
|
||||
qmsg("Save this information to a secure location")
|
||||
qmsg("This checksum will be used to verify the address file in the future.")
|
||||
qmsg("Record it to a safe location.")
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ and has a balance, you must exit the program now and rerun it using the
|
|||
'--rescan' option. Otherwise you may ignore this message and continue.
|
||||
""".strip()
|
||||
|
||||
if g.quiet: m = ""
|
||||
confirm_or_exit(m, "continue", expect="YES")
|
||||
|
||||
err_flag = False
|
||||
|
|
@ -135,10 +136,7 @@ for n,i in enumerate(addr_data):
|
|||
break
|
||||
else:
|
||||
import_address(i[1],label,rescan=False)
|
||||
msg_r(msg_fmt % (
|
||||
("%s/%s:" % (n+1,len(addr_data))),
|
||||
i[1], "(" + label + ")"
|
||||
)
|
||||
)
|
||||
msg_r(msg_fmt % (("%s/%s:" % (n+1,len(addr_data))),
|
||||
i[1], "(" + label + ")"))
|
||||
if err_flag: msg("\nImport failed"); sys.exit(2)
|
||||
msg(" - OK")
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from mmgen.util import pretty_hexdump
|
|||
help_data = {
|
||||
'prog_name': g.prog_name,
|
||||
'desc': "Perform various BTC-related operations",
|
||||
'usage': "[opts] <command> <args>",
|
||||
'usage': "[opts] <command> <command args>",
|
||||
'options': """
|
||||
-d, --outdir= d Specify an alternate directory 'd' for output
|
||||
-h, --help Print this help message
|
||||
|
|
|
|||
|
|
@ -23,16 +23,17 @@ def usage(hd):
|
|||
print "USAGE: %s %s" % (hd['prog_name'], hd['usage'])
|
||||
sys.exit(2)
|
||||
|
||||
def print_version_info(progname):
|
||||
def print_version_info(): # MMGen only
|
||||
print """
|
||||
'{}' version {g.version}. Part of the {g.proj_name} suite.
|
||||
'{g.prog_name}' version {g.version}. Part of the {g.proj_name} suite.
|
||||
Copyright (C) {g.Cdates} by {g.author} {g.email}.
|
||||
""".format(progname, g=g).strip()
|
||||
""".format(g=g).strip()
|
||||
|
||||
def print_help(progname,help_data):
|
||||
pn_len = str(len(progname)+2)
|
||||
print (" %-"+pn_len+"s %s") % (progname.upper()+":", help_data['desc'].strip())
|
||||
print (" %-"+pn_len+"s %s %s")%("USAGE:", progname, help_data['usage'].strip())
|
||||
def print_help(help_data):
|
||||
pn = help_data['prog_name']
|
||||
pn_len = str(len(pn)+2)
|
||||
print (" %-"+pn_len+"s %s") % (pn.upper()+":", help_data['desc'].strip())
|
||||
print (" %-"+pn_len+"s %s %s")%("USAGE:", pn, help_data['usage'].strip())
|
||||
sep = "\n "
|
||||
print " OPTIONS:"+sep+"%s" % sep.join(help_data['options'].strip().split("\n"))
|
||||
if "notes" in help_data:
|
||||
|
|
@ -41,10 +42,8 @@ def print_help(progname,help_data):
|
|||
|
||||
def process_opts(argv,help_data,short_opts,long_opts):
|
||||
|
||||
progname = argv[0].split("/")[-1]
|
||||
|
||||
if len(argv) == 2 and argv[1] == '--version': # MMGen only!
|
||||
print_version_info(progname); sys.exit()
|
||||
print_version_info(); sys.exit()
|
||||
|
||||
if g.debug:
|
||||
print "Short opts: %s" % repr(short_opts)
|
||||
|
|
@ -63,7 +62,7 @@ def process_opts(argv,help_data,short_opts,long_opts):
|
|||
else: short_opts_l += i
|
||||
|
||||
for opt, arg in cl_opts:
|
||||
if opt in ("-h","--help"): print_help(progname,help_data); sys.exit()
|
||||
if opt in ("-h","--help"): print_help(help_data); sys.exit()
|
||||
elif opt[:2] == "--" and opt[2:] in long_opts:
|
||||
opts[opt[2:].replace("-","_")] = True
|
||||
elif opt[:2] == "--" and opt[2:]+"=" in long_opts:
|
||||
|
|
@ -143,7 +142,7 @@ def check_opts(opts,long_opts):
|
|||
msg("Requested %s '%s' is unwritable by you" % (what,val))
|
||||
return False
|
||||
else:
|
||||
msg("Requested %s '%s' doen not exist" % (what,val))
|
||||
msg("Requested %s '%s' does not exist" % (what,val))
|
||||
return False
|
||||
|
||||
elif opt == 'label':
|
||||
|
|
|
|||
180
mmgen/tool.py
180
mmgen/tool.py
|
|
@ -40,7 +40,7 @@ commands = {
|
|||
"hextob58": ['<hex number> [str]'],
|
||||
"b58tohex": ['<b58 number> [str]'],
|
||||
"b58randenc": [],
|
||||
"getrand": ['bytes [int=32]'],
|
||||
"randhex": ['nbytes [int=32]'],
|
||||
"randwif": ['compressed [bool=False]'],
|
||||
"randpair": ['compressed [bool=False]'],
|
||||
"wif2hex": ['<wif> [str]', 'compressed [bool=False]'],
|
||||
|
|
@ -58,7 +58,8 @@ commands = {
|
|||
"listaddresses": ['minconf [int=1]', 'showempty [bool=False]'],
|
||||
"getbalance": ['minconf [int=1]'],
|
||||
"viewtx": ['<MMGen tx file> [str]'],
|
||||
"check_addrfile": ['<MMGen addr file> [str]'],
|
||||
"check_addrfile": ['<MMGen addr file> [str]'],
|
||||
"find_incog_data": ['<file or device name> [str]','<Incog ID> [str]','keep_searching [bool=False]'],
|
||||
"hexreverse": ['<hexadecimal string> [str]'],
|
||||
"sha256x2": ['<str, hexstr or filename> [str]',
|
||||
'hex_input [bool=False]','file_input [bool=False]'],
|
||||
|
|
@ -70,48 +71,57 @@ commands = {
|
|||
"privhex2addr": ['<private key in hex format> [str]','compressed [bool=False]'],
|
||||
"encrypt": ['<infile> [str]','outfile [str=""]','hash_preset [str="3"]'],
|
||||
"decrypt": ['<infile> [str]','outfile [str=""]','hash_preset [str="3"]'],
|
||||
"rand2file": ['<outfile> [str]','<nbytes> [str]','threads [int=4]'],
|
||||
"bytespec": ['<bytespec> [str]'],
|
||||
}
|
||||
|
||||
command_help = """
|
||||
File operations
|
||||
hexdump - encode data into formatted hexadecimal form (file or stdin)
|
||||
unhexdump - decode formatted hexadecimal data (file or stdin)
|
||||
|
||||
{pnm}-specific operations
|
||||
id8 - generate 8-character {pnm} ID checksum for file (or stdin)
|
||||
id6 - generate 6-character {pnm} ID checksum for file (or stdin)
|
||||
check_addrfile - compute checksum and address list for {pnm} address file
|
||||
|
||||
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
|
||||
Bitcoin address/key operations (compressed addresses supported):
|
||||
addr2hexaddr - convert Bitcoin address from base58 to hex format
|
||||
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
|
||||
wif2hex - convert a private key from WIF to hex format
|
||||
b58tohex - convert a base 58 number to hexadecimal
|
||||
hex2wif - convert a private key from hex to WIF format
|
||||
wif2addr - generate a Bitcoin address from a key in WIF format
|
||||
hexaddr2addr - convert Bitcoin address from hex to base58 format
|
||||
hextob58 - convert a hexadecimal number to base 58
|
||||
privhex2addr - generate Bitcoin address from private key in hex format
|
||||
pubkey2addr - convert Bitcoin public key to address
|
||||
pubkey2hexaddr - convert Bitcoin public key to address in hex format
|
||||
hexaddr2addr - convert Bitcoin address from hex to base58 format
|
||||
addr2hexaddr - convert Bitcoin address from base58 to hex format
|
||||
privhex2addr - generate Bitcoin address from private key in hex format
|
||||
randpair - generate a random private key/address pair
|
||||
randwif - generate a random private key in WIF format
|
||||
strtob58 - convert a string to base 58
|
||||
wif2addr - generate a Bitcoin address from a key in WIF format
|
||||
wif2hex - convert a private key from WIF to hex format
|
||||
|
||||
Miscellaneous operations:
|
||||
hexreverse - reverse bytes of a hexadecimal string
|
||||
Wallet/TX operations (bitcoind must be running):
|
||||
getbalance - like 'bitcoind getbalance' but shows confirmed/unconfirmed,
|
||||
spendable/unspendable balances for individual {pnm} wallets
|
||||
listaddresses - list {pnm} addresses and their balances
|
||||
viewtx - show raw/signed {pnm} transaction in human-readable form
|
||||
|
||||
General utilities:
|
||||
bytespec - convert a byte specifier such as '1GB' into a plain integer
|
||||
hexdump - encode data into formatted hexadecimal form (file or stdin)
|
||||
hexlify - display string in hexadecimal format
|
||||
hexreverse - reverse bytes of a hexadecimal string
|
||||
rand2file - write 'n' bytes of random data to specified file
|
||||
randhex - print 'n' bytes (default 32) of random data in hex format
|
||||
sha256x2 - compute a double sha256 hash of data
|
||||
getrand - print 'n' bytes (default 32) of random data in hex format
|
||||
unhexdump - decode formatted hexadecimal data (file or stdin)
|
||||
|
||||
Encryption operations:
|
||||
encrypt - encrypt a file using {pnm}'s encryption suite
|
||||
decrypt - decrypt an {pnm}-encrypted file
|
||||
File encryption:
|
||||
encrypt - encrypt a file
|
||||
decrypt - decrypt a file
|
||||
{pnm} encryption suite:
|
||||
* Key: Scrypt (user-configurable hash parameters, 32-byte salt)
|
||||
* Enc: AES256_CTR, 16-byte rand IV, sha256 hash + 32-byte nonce + data
|
||||
* The encrypted file is indistinguishable from random data
|
||||
|
||||
{pnm}-specific operations:
|
||||
check_addrfile - compute checksum and address list for {pnm} address file
|
||||
find_incog_data - Use an Incog ID to find hidden incognito wallet data
|
||||
id6 - generate 6-character {pnm} ID checksum for file (or stdin)
|
||||
id8 - generate 8-character {pnm} ID checksum for file (or stdin)
|
||||
|
||||
Mnemonic operations (choose "electrum" (default), "tirosh" or "all"
|
||||
wordlists):
|
||||
mn_rand128 - generate random 128-bit mnemonic
|
||||
|
|
@ -120,12 +130,6 @@ command_help = """
|
|||
mn_stats - show stats for mnemonic wordlist
|
||||
mn_printlist - print mnemonic wordlist
|
||||
|
||||
Bitcoind operations (bitcoind must be running):
|
||||
listaddresses - show {pnm} addresses and their balances
|
||||
getbalance - like 'bitcoind getbalance' but shows confirmed/unconfirmed,
|
||||
spendable/unspendable
|
||||
viewtx - show raw/signed {pnm} transaction in human-readable form
|
||||
|
||||
IMPORTANT NOTE: Though {pnm} mnemonics use the Electrum wordlist, they're
|
||||
computed using a different algorithm and are NOT Electrum-compatible!
|
||||
""".format(pnm=g.proj_name)
|
||||
|
|
@ -234,8 +238,8 @@ def b58randenc():
|
|||
dec = bitcoin.b58decode(enc)
|
||||
print_convert_results(ba.hexlify(r),enc,ba.hexlify(dec))
|
||||
|
||||
def getrand(bytes='32'):
|
||||
print ba.hexlify(get_random(int(bytes),opts))
|
||||
def randhex(nbytes='32'):
|
||||
print ba.hexlify(get_random(int(nbytes),opts))
|
||||
|
||||
def randwif(compressed=False):
|
||||
r_hex = ba.hexlify(get_random(32,opts))
|
||||
|
|
@ -443,3 +447,107 @@ def decrypt(infile,outfile="",hash_preset=''):
|
|||
write_to_file((outfile or of),out,opts,"decrypted data",True,True)
|
||||
else:
|
||||
msg("Incorrect passphrase or hash preset")
|
||||
|
||||
|
||||
def find_incog_data(filename,iv_id,keep_searching=False):
|
||||
ivsize,bsize,mod = g.aesctr_iv_len,4096,4096*8
|
||||
n,carry = 0," "*ivsize
|
||||
f = os.open(filename,os.O_RDONLY)
|
||||
while True:
|
||||
d = os.read(f,bsize)
|
||||
if not d: break
|
||||
d = carry + d
|
||||
for i in range(bsize):
|
||||
if sha256(d[i:i+ivsize]).hexdigest()[:8].upper() == iv_id:
|
||||
if n+i < ivsize: continue
|
||||
msg("\rIncog data for ID %s found at offset %s" %
|
||||
(iv_id,n+i-ivsize))
|
||||
if not keep_searching: sys.exit(0)
|
||||
carry = d[len(d)-ivsize:]
|
||||
n += bsize
|
||||
if not n % mod: msg_r("\rSearched: %s bytes" % n)
|
||||
|
||||
msg("")
|
||||
os.close(f)
|
||||
|
||||
# From "man dd":
|
||||
# c=1, w=2, b=512, kB=1000, K=1024, MB=1000*1000, M=1024*1024,
|
||||
# GB=1000*1000*1000, G=1024*1024*1024, and so on for T, P, E, Z, Y.
|
||||
|
||||
def parse_nbytes(nbytes):
|
||||
import re
|
||||
m = re.match(r'([0123456789]+)(.*)',nbytes)
|
||||
smap = ("c",1),("w",2),("b",512),("kB",1000),("K",1024),("MB",1000*1000),\
|
||||
("M",1024*1024),("GB",1000*1000*1000),("G",1024*1024*1024)
|
||||
if m:
|
||||
if m.group(2):
|
||||
for k,v in smap:
|
||||
if k == m.group(2):
|
||||
return int(m.group(1)) * v
|
||||
else:
|
||||
msg("Valid byte specifiers: '%s'" % "' '".join([i[0] for i in smap]))
|
||||
else:
|
||||
return int(nbytes)
|
||||
|
||||
msg("'%s': invalid byte specifier" % nbytes)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def rand2file(outfile, nbytes, threads=4):
|
||||
nbytes = parse_nbytes(nbytes)
|
||||
from Crypto import Random
|
||||
rh = Random.new()
|
||||
from Queue import Queue
|
||||
from threading import Thread
|
||||
bsize = 2**20
|
||||
roll = bsize * 4
|
||||
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
|
||||
f = open(outfile,"w")
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
|
||||
key = get_random(32,opts)
|
||||
|
||||
def encrypt_worker(wid):
|
||||
while True:
|
||||
i,d = q1.get()
|
||||
c = AES.new(key, AES.MODE_CTR,
|
||||
counter=Counter.new(g.aesctr_iv_len*8,initial_value=i))
|
||||
enc_data = c.encrypt(d)
|
||||
q2.put(enc_data)
|
||||
q1.task_done()
|
||||
|
||||
def output_worker():
|
||||
while True:
|
||||
data = q2.get()
|
||||
f.write(data)
|
||||
q2.task_done()
|
||||
|
||||
q1 = Queue()
|
||||
for i in range(max(1,threads-2)):
|
||||
t = Thread(target=encrypt_worker, args=(i,))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
q2 = Queue()
|
||||
t = Thread(target=output_worker)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
i = 1; rbytes = nbytes
|
||||
while rbytes > 0:
|
||||
d = rh.read(min(bsize,rbytes))
|
||||
q1.put((i,d))
|
||||
rbytes -= bsize
|
||||
i += 1
|
||||
if not (bsize*i) % roll:
|
||||
msg_r("\rRead: %s bytes" % (bsize*i))
|
||||
|
||||
msg("\rRead: %s bytes" % nbytes)
|
||||
qmsg("\r%s bytes written to file '%s'" % (nbytes,outfile))
|
||||
q1.join()
|
||||
q2.join()
|
||||
f.close()
|
||||
|
||||
def bytespec(s): print parse_nbytes(s)
|
||||
|
|
|
|||
15
mmgen/tx.py
15
mmgen/tx.py
|
|
@ -141,18 +141,17 @@ def normalize_btc_amt(amt):
|
|||
|
||||
def get_bitcoind_cfg_options(cfg_keys):
|
||||
|
||||
if "HOME" in os.environ:
|
||||
data_dir = ".bitcoin"
|
||||
cfg_file = "%s/%s/%s" % (os.environ["HOME"], data_dir, "bitcoin.conf")
|
||||
elif "HOMEPATH" in os.environ:
|
||||
# Windows:
|
||||
data_dir = r"Application Data\Bitcoin"
|
||||
cfg_file = "%s\%s\%s" % (os.environ["HOMEPATH"],data_dir,"bitcoin.conf")
|
||||
if "HOME" in os.environ: # Linux
|
||||
homedir,datadir = os.environ["HOME"],".bitcoin"
|
||||
elif "HOMEPATH" in os.environ: # Windows:
|
||||
homedir,data_dir = os.environ["HOMEPATH"],r"Application Data\Bitcoin"
|
||||
else:
|
||||
msg("Neither $HOME nor %HOMEPATH% are set")
|
||||
msg("Don't know where to look for 'bitcoin.conf'")
|
||||
sys.exit(3)
|
||||
|
||||
cfg_file = os.sep.join((homedir, datadir, "bitcoin.conf"))
|
||||
|
||||
cfg = dict([(k,v) for k,v in [split2(line.translate(None,"\t "),"=")
|
||||
for line in get_lines_from_file(cfg_file)] if k in cfg_keys])
|
||||
|
||||
|
|
@ -535,7 +534,7 @@ def check_addr_data_hash(seed_id,addr_data):
|
|||
fl = fmt_addr_idxs([int(a[0]) for a in addr_data])
|
||||
msg("Computed checksum for addr data {}[{}]: {}".format(
|
||||
seed_id,fl,addr_data_chksum))
|
||||
msg("Check this value against your records")
|
||||
qmsg("Check this value against your records")
|
||||
|
||||
def parse_addrs_file(f):
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ def get_random_data_from_user(uchars):
|
|||
|
||||
prompt = "User random data successfully acquired. Press ENTER to continue"
|
||||
prompt_and_get_char(prompt,"",enter_ok=True)
|
||||
msg("")
|
||||
|
||||
return key_data+"".join(fmt_time_data)
|
||||
|
||||
|
|
@ -97,7 +96,7 @@ def get_random(length,opts):
|
|||
else:
|
||||
kwhat += "saved user entropy"
|
||||
key = make_key(g.user_entropy, "", '2', what=kwhat)
|
||||
return encrypt_data(os_rand,key,what="random data")
|
||||
return encrypt_data(os_rand,key,what="random data",verify=False)
|
||||
else:
|
||||
return os_rand
|
||||
|
||||
|
|
@ -137,11 +136,11 @@ def show_hash_presets():
|
|||
cmessages = {
|
||||
'null': "",
|
||||
'incog_iv_id': """
|
||||
If you know your IV ID, check it against the value above. If it's
|
||||
If you know your Incog ID, check it against the value above. If it's
|
||||
incorrect, then your incognito data is invalid.
|
||||
""",
|
||||
'incog_iv_id_hidden': """
|
||||
If you know your IV ID, check it against the value above. If it's
|
||||
If you know your Incog ID, check it against the value above. If it's
|
||||
incorrect, then your incognito data is invalid or you've supplied
|
||||
an incorrect offset.
|
||||
""",
|
||||
|
|
@ -253,6 +252,9 @@ def make_chksum_8(s,sep=False):
|
|||
def make_chksum_6(s):
|
||||
return sha256(s).hexdigest()[:6]
|
||||
|
||||
def make_iv_chksum(s):
|
||||
return sha256(s).hexdigest()[:8].upper()
|
||||
|
||||
|
||||
def check_infile(f):
|
||||
|
||||
|
|
@ -372,7 +374,7 @@ def _get_seed_from_brain_passphrase(words,opts):
|
|||
def encrypt_seed(seed, key):
|
||||
return encrypt_data(seed, key, iv=1, what="seed")
|
||||
|
||||
def encrypt_data(data, key, iv=1, what="data"):
|
||||
def encrypt_data(data, key, iv=1, what="data", verify=True):
|
||||
"""
|
||||
Encrypt arbitrary data using AES256 in counter mode
|
||||
"""
|
||||
|
|
@ -387,16 +389,17 @@ def encrypt_data(data, key, iv=1, what="data"):
|
|||
counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
enc_data = c.encrypt(data)
|
||||
|
||||
vmsg_r("Performing a test decryption of the %s..." % what)
|
||||
if verify:
|
||||
vmsg_r("Performing a test decryption of the %s..." % what)
|
||||
|
||||
c = AES.new(key, AES.MODE_CTR,
|
||||
counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
dec_data = c.decrypt(enc_data)
|
||||
c = AES.new(key, AES.MODE_CTR,
|
||||
counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
dec_data = c.decrypt(enc_data)
|
||||
|
||||
if dec_data == data: vmsg("done\n")
|
||||
else:
|
||||
msg("ERROR.\nDecrypted %s doesn't match original %s" % (what,what))
|
||||
sys.exit(2)
|
||||
if dec_data == data: vmsg("done\n")
|
||||
else:
|
||||
msg("ERROR.\nDecrypted %s doesn't match original %s" % (what,what))
|
||||
sys.exit(2)
|
||||
|
||||
return enc_data
|
||||
|
||||
|
|
@ -432,9 +435,15 @@ def open_file_or_exit(filename,mode):
|
|||
return f
|
||||
|
||||
|
||||
def make_full_path(outdir,outfile):
|
||||
import os
|
||||
return os.path.normpath(os.sep.join([outdir, os.path.basename(outfile)]))
|
||||
# os.path.join() doesn't work?
|
||||
|
||||
|
||||
def write_to_file(outfile,data,opts,what="data",confirm=False,verbose=False):
|
||||
|
||||
if 'outdir' in opts: outfile = "%s/%s" % (opts['outdir'], outfile)
|
||||
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
|
||||
|
||||
if confirm:
|
||||
from os import stat
|
||||
|
|
@ -456,7 +465,6 @@ def write_to_file(outfile,data,opts,what="data",confirm=False,verbose=False):
|
|||
if verbose: msg("%s written to file '%s'" % (what.capitalize(),outfile))
|
||||
|
||||
|
||||
|
||||
def export_to_file(outfile, data, opts, what="data"):
|
||||
|
||||
if 'stdout' in opts:
|
||||
|
|
@ -846,7 +854,8 @@ def get_seed_from_incog_wallet(
|
|||
|
||||
iv, enc_incog_data = d[0:g.aesctr_iv_len], d[g.aesctr_iv_len:]
|
||||
|
||||
qmsg("IV ID: %s. Check this value if possible." % make_chksum_8(iv))
|
||||
msg("Incog ID: %s (IV ID: %s)" % (make_iv_chksum(iv),make_chksum_8(iv)))
|
||||
qmsg("Check the applicable value against your records.")
|
||||
vmsg(cmessages['incog_iv_id_hidden' if "from_incog_hidden" in opts
|
||||
else 'incog_iv_id'])
|
||||
|
||||
|
|
@ -1047,17 +1056,18 @@ def do_pager(text):
|
|||
|
||||
|
||||
def export_to_hidden_incog(incog_enc,opts):
|
||||
fname,offset = opts['export_incog_hidden'].split(",") #Already sanity-checked
|
||||
outfile,offset = opts['export_incog_hidden'].split(",") #Already sanity-checked
|
||||
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
|
||||
|
||||
check_data_fits_file_at_offset(fname,int(offset),len(incog_enc),"write")
|
||||
check_data_fits_file_at_offset(outfile,int(offset),len(incog_enc),"write")
|
||||
|
||||
if not g.quiet: confirm_or_exit("","alter file '%s'" % fname)
|
||||
f = os.open(fname,os.O_RDWR)
|
||||
if not g.quiet: confirm_or_exit("","alter file '%s'" % outfile)
|
||||
f = os.open(outfile,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")
|
||||
msg("Data written to file '%s' at offset %s" %
|
||||
(os.path.relpath(outfile),offset))
|
||||
|
||||
|
||||
def pretty_hexdump(data,gw=2,cols=8,line_nums=False):
|
||||
|
|
@ -1090,8 +1100,8 @@ def wallet_to_incog_data(infile,opts):
|
|||
sys.exit(2)
|
||||
|
||||
iv = get_random(g.aesctr_iv_len,opts)
|
||||
iv_id = make_chksum_8(iv)
|
||||
qmsg("IV ID: %s" % iv_id)
|
||||
iv_id = make_iv_chksum(iv)
|
||||
msg("Incog ID: %s" % iv_id)
|
||||
|
||||
# IV is used BOTH to initialize counter and to salt password!
|
||||
key = make_key(passwd, iv, preset, "wrapper key")
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -3,7 +3,7 @@ from distutils.core import setup
|
|||
|
||||
setup(
|
||||
name = 'mmgen',
|
||||
version = '0.7.6a',
|
||||
version = '0.7.7',
|
||||
author = 'Philemon',
|
||||
author_email = 'mmgen-py@yandex.com',
|
||||
url = 'https://github.com/mmgen/mmgen',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue