crypto.py:get_*passphrase(),get_hash_preset*(): merge with duplicating code in wallet.py

This commit is contained in:
The MMGen Project 2022-01-22 14:26:14 +00:00
commit ccb4894583
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
5 changed files with 79 additions and 97 deletions

View file

@ -215,78 +215,101 @@ def add_user_random(rand_bytes,desc):
else:
return rand_bytes
def get_hash_preset_from_user(hp=g.dfl_hash_preset,desc='data'):
def get_hash_preset_from_user(
hash_preset = g.dfl_hash_preset,
data_desc = 'data',
prompt = None ):
prompt = prompt or (
f'Enter hash preset for {data_desc},\n' +
f'or hit ENTER to accept the default value ({hash_preset!r}): ' )
while True:
ret = line_input(
f'Enter hash preset for {desc},\n' +
f'or hit ENTER to accept the default value ({hp!r}): ' )
ret = line_input(prompt)
if ret:
if ret in g.hash_presets:
return ret
else:
msg(f'Invalid input. Valid choices are {", ".join(g.hash_presets)}')
continue
msg('Invalid input. Valid choices are {}'.format(', '.join(g.hash_presets)))
else:
return hp
return hash_preset
def get_new_passphrase(desc,passchg=False):
pw_desc = f"{'new ' if passchg else ''}passphrase for {desc}"
if opt.passwd_file:
def get_new_passphrase(data_desc,hash_preset,passwd_file,pw_desc='passphrase'):
message = f"""
You must choose a passphrase to encrypt your {data_desc} with.
A key will be generated from your passphrase using a hash preset of '{hash_preset}'.
Please note that no strength checking of passphrases is performed.
For an empty passphrase, just hit ENTER twice.
"""
if passwd_file:
from .fileutil import get_words_from_file
pw = ' '.join(get_words_from_file(opt.passwd_file,pw_desc))
elif opt.echo_passphrase:
pw = ' '.join(get_words_from_user(f'Enter {pw_desc}: '))
pw = ' '.join(get_words_from_file(
infile = passwd_file,
desc = f'{pw_desc} for {data_desc}',
quiet = pwfile_reuse_warning(passwd_file).warning_shown ))
else:
for i in range(g.passwd_max_tries):
pw = ' '.join(get_words_from_user(f'Enter {pw_desc}: '))
pw_chk = ' '.join(get_words_from_user('Repeat passphrase: '))
dmsg(f'Passphrases: [{pw}] [{pw_chk}]')
if pw == pw_chk:
vmsg('Passphrases match'); break
else: msg('Passphrases do not match. Try again.')
qmsg('\n'+fmt(message,indent=' '))
if opt.echo_passphrase:
pw = ' '.join(get_words_from_user(f'Enter {pw_desc} for {data_desc}: '))
else:
die(2,f'User failed to duplicate passphrase in {g.passwd_max_tries} attempts')
for i in range(g.passwd_max_tries):
pw = ' '.join(get_words_from_user(f'Enter {pw_desc} for {data_desc}: '))
pw_chk = ' '.join(get_words_from_user(f'Repeat {pw_desc}: '))
dmsg(f'Passphrases: [{pw}] [{pw_chk}]')
if pw == pw_chk:
vmsg('Passphrases match')
break
else:
msg('Passphrases do not match. Try again.')
else:
die(2,f'User failed to duplicate passphrase in {g.passwd_max_tries} attempts')
if pw == '':
qmsg('WARNING: Empty passphrase')
return pw
def get_passphrase(desc,passchg=False):
pw_desc = f"{'old ' if passchg else ''}passphrase for {desc}"
if opt.passwd_file:
def get_passphrase(data_desc,passwd_file,pw_desc='passphrase'):
if passwd_file:
from .fileutil import get_words_from_file
pwfile_reuse_warning(opt.passwd_file)
return ' '.join(get_words_from_file(opt.passwd_file,pw_desc))
return ' '.join(get_words_from_file(
infile = passwd_file,
desc = f'{pw_desc} for {data_desc}',
quiet = pwfile_reuse_warning(passwd_file).warning_shown ))
else:
return ' '.join(get_words_from_user(f'Enter {pw_desc}: '))
return ' '.join(get_words_from_user(f'Enter {pw_desc} for {data_desc}: '))
mmenc_salt_len = 32
mmenc_nonce_len = 32
def mmgen_encrypt(data,desc='data',hash_preset=''):
def mmgen_encrypt(data,desc='data',hash_preset=None):
salt = get_random(mmenc_salt_len)
iv = get_random(g.aesctr_iv_len)
nonce = get_random(mmenc_nonce_len)
hp = hash_preset or opt.hash_preset or get_hash_preset_from_user('3',desc)
hp = hash_preset or opt.hash_preset or get_hash_preset_from_user(data_desc=desc)
m = ('user-requested','default')[hp=='3']
vmsg(f'Encrypting {desc}')
qmsg(f'Using {m} hash preset of {hp!r}')
passwd = get_new_passphrase(desc)
passwd = get_new_passphrase(
data_desc = desc,
hash_preset = hp,
passwd_file = opt.passwd_file )
key = make_key(passwd,salt,hp)
enc_d = encrypt_data( sha256(nonce+data).digest() + nonce + data, key, iv, desc=desc )
return salt+iv+enc_d
def mmgen_decrypt(data,desc='data',hash_preset=''):
def mmgen_decrypt(data,desc='data',hash_preset=None):
vmsg(f'Preparing to decrypt {desc}')
dstart = mmenc_salt_len + g.aesctr_iv_len
salt = data[:mmenc_salt_len]
iv = data[mmenc_salt_len:dstart]
enc_d = data[dstart:]
hp = hash_preset or opt.hash_preset or get_hash_preset_from_user('3',desc)
hp = hash_preset or opt.hash_preset or get_hash_preset_from_user(data_desc=desc)
m = ('user-requested','default')[hp=='3']
qmsg(f'Using {m} hash preset of {hp!r}')
passwd = get_passphrase(desc)
passwd = get_passphrase(
data_desc = desc,
passwd_file = opt.passwd_file )
key = make_key(passwd,salt,hp)
dec_d = decrypt_data( enc_d, key, iv, desc )
sha256_len = 32

View file

@ -298,15 +298,8 @@ class WalletEnc(Wallet):
('',' '+add_desc)[bool(add_desc)],
('accept the default','reuse the old')[self.op=='pwchg_new'],
hp )
while True:
ret = line_input(prompt)
if ret:
if ret in g.hash_presets:
return ret
else:
msg('Invalid input. Valid choices are {}'.format(', '.join(g.hash_presets)))
else:
return hp
from .crypto import get_hash_preset_from_user
return get_hash_preset_from_user( hash_preset=hp, prompt=prompt )
def _get_hash_preset(self,add_desc=''):
if hasattr(self,'ss_in') and hasattr(self.ss_in.ssdata,'hash_preset'):
@ -329,54 +322,20 @@ class WalletEnc(Wallet):
self.ssdata.hash_preset = hp
def _get_new_passphrase(self):
desc = '{}passphrase for {}{}'.format(
('','new ')[self.op=='pwchg_new'],
('','new ')[self.op in ('new','conv')],
self.desc
)
if self.passwd_file:
from .fileutil import get_words_from_file
pw = ' '.join(get_words_from_file(
self.passwd_file,
desc,
quiet = pwfile_reuse_warning(self.passwd_file).warning_shown ))
else:
qmsg('\n'+fmt(self.msg['choose_passphrase'].format(self.desc,self.ssdata.hash_preset),indent=' '))
if opt.echo_passphrase:
pw = ' '.join(get_words_from_user(f'Enter {desc}: '))
else:
for i in range(g.passwd_max_tries):
pw = ' '.join(get_words_from_user(f'Enter {desc}: '))
pw_chk = ' '.join(get_words_from_user('Repeat passphrase: '))
dmsg(f'Passphrases: [{pw}] [{pw_chk}]')
if pw == pw_chk:
vmsg('Passphrases match')
break
else:
msg('Passphrases do not match. Try again.')
else:
die(2,f'User failed to duplicate passphrase in {g.passwd_max_tries} attempts')
if pw == '':
qmsg('WARNING: Empty passphrase')
self.ssdata.passwd = pw
return pw
from .crypto import get_new_passphrase
self.ssdata.passwd = get_new_passphrase(
data_desc = ('new ' if self.op in ('new','conv') else '') + self.desc,
hash_preset = self.ssdata.hash_preset,
passwd_file = self.passwd_file,
pw_desc = ('new ' if self.op=='pwchg_new' else '') + 'passphrase' )
return self.ssdata.passwd
def _get_passphrase(self,add_desc=''):
desc = '{}passphrase for {}{}'.format(
('','old ')[self.op=='pwchg_old'],
self.desc,
('',' '+add_desc)[bool(add_desc)]
)
if self.passwd_file:
from .fileutil import get_words_from_file
ret = ' '.join(get_words_from_file(
self.passwd_file,
desc,
quiet = pwfile_reuse_warning(self.passwd_file).warning_shown ))
else:
ret = ' '.join(get_words_from_user(f'Enter {desc}: '))
self.ssdata.passwd = ret
from .crypto import get_passphrase
self.ssdata.passwd = get_passphrase(
data_desc = self.desc + (f' {add_desc}' if add_desc else ''),
passwd_file = self.passwd_file,
pw_desc = ('old ' if self.op == 'pwchg_old' else '') + 'passphrase' )
def _get_first_pw_and_hp_and_encrypt_seed(self):
d = self.ssdata
@ -826,7 +785,7 @@ class MMGenWallet(WalletEnc):
d.hash_preset = hp = hpdata[0][:-1] # a string!
qmsg(f'Hash preset of wallet: {hp!r}')
if opt.hash_preset and opt.hash_preset != hp:
qmsg('Warning: ignoring user-requested hash preset {opt.hash_preset}')
qmsg(f'Warning: ignoring user-requested hash preset {opt.hash_preset!r}')
hash_params = tuple(map(int,hpdata[1:]))

View file

@ -27,16 +27,16 @@ from mmgen.wallet import Wallet
def crypto():
desc = 'test data'
pw = get_new_passphrase(desc=desc)
pw = get_new_passphrase(data_desc=desc,hash_preset=g.dfl_hash_preset,passwd_file=None)
msg(f'==> got new passphrase: [{pw}]\n')
pw = get_passphrase(desc=desc)
pw = get_passphrase(data_desc=desc,passwd_file=None)
msg(f'==> got passphrase: [{pw}]\n')
hp = get_hash_preset_from_user(desc=desc)
hp = get_hash_preset_from_user(data_desc=desc)
msg(f'==> got hash preset: [{hp}]')
hp = get_hash_preset_from_user(desc=desc)
hp = get_hash_preset_from_user(data_desc=desc)
msg(f'==> got hash preset: [{hp}]')
def seed():

View file

@ -76,7 +76,7 @@ class TestSuiteInput(TestSuiteBase):
t.expect('unchanged')
t.expect('new passphrase.*: ','pass1\n',regex=True)
t.expect('peat passphrase: ','pass1\n')
t.expect('peat new passphrase: ','pass1\n')
t.expect('unchanged')
t.expect('reuse the label .*: ','\n',regex=True)
@ -90,7 +90,7 @@ class TestSuiteInput(TestSuiteBase):
t.expect(' changed to')
t.expect('new passphrase.*: ','pass2\n',regex=True)
t.expect('peat passphrase: ','pass2\n')
t.expect('peat new passphrase: ','pass2\n')
t.expect(' changed')
t.expect('reuse the label .*: ','lbl2\n',regex=True)

View file

@ -300,7 +300,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
t.passphrase(wcls.desc,self.cfgs['1']['wpasswd'],pwtype='old')
t.expect_getend('Hash preset changed to ')
t.passphrase(wcls.desc,self.wpasswd,pwtype='new') # reuse passphrase?
t.expect('Repeat passphrase: ',self.wpasswd+'\n')
t.expect('Repeat new passphrase: ',self.wpasswd+'\n')
t.usr_rand(self.usr_rand_chars)
if label_action == 'user':
t.expect('Enter a wallet label.*: ','Interactive Label (UTF-8) α\n',regex=True)