From ccb489458306afb3f94f377e66420600f1cf515b Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 22 Jan 2022 14:26:14 +0000 Subject: [PATCH] crypto.py:get_*passphrase(),get_hash_preset*(): merge with duplicating code in wallet.py --- mmgen/crypto.py | 89 +++++++++++++++++++++++-------------- mmgen/wallet.py | 71 +++++++---------------------- test/misc/get_passphrase.py | 8 ++-- test/test_py_d/ts_input.py | 4 +- test/test_py_d/ts_main.py | 2 +- 5 files changed, 78 insertions(+), 96 deletions(-) diff --git a/mmgen/crypto.py b/mmgen/crypto.py index 4bbec4f6..9b1e3fd5 100755 --- a/mmgen/crypto.py +++ b/mmgen/crypto.py @@ -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 diff --git a/mmgen/wallet.py b/mmgen/wallet.py index 7684722a..cfef364e 100755 --- a/mmgen/wallet.py +++ b/mmgen/wallet.py @@ -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:])) diff --git a/test/misc/get_passphrase.py b/test/misc/get_passphrase.py index 45728793..57ef0d87 100755 --- a/test/misc/get_passphrase.py +++ b/test/misc/get_passphrase.py @@ -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(): diff --git a/test/test_py_d/ts_input.py b/test/test_py_d/ts_input.py index f71fbd1b..c5177d25 100755 --- a/test/test_py_d/ts_input.py +++ b/test/test_py_d/ts_input.py @@ -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) diff --git a/test/test_py_d/ts_main.py b/test/test_py_d/ts_main.py index 561b3d6f..a5977ddd 100755 --- a/test/test_py_d/ts_main.py +++ b/test/test_py_d/ts_main.py @@ -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)