crypto.py: improve get_random() implementation

This commit is contained in:
The MMGen Project 2022-02-10 12:51:43 +00:00
commit 589c37806b
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
4 changed files with 39 additions and 19 deletions

View file

@ -112,10 +112,11 @@ def decrypt_seed(enc_seed,key,seed_id,key_id):
dmsg(f'Decrypted seed: {dec_seed.hex()}')
return dec_seed
def encrypt_data(data,key,iv=aesctr_dfl_iv,desc='data',verify=True):
def encrypt_data(data,key,iv=aesctr_dfl_iv,desc='data',verify=True,silent=False):
from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes
from cryptography.hazmat.backends import default_backend
vmsg(f'Encrypting {desc}')
if not silent:
vmsg(f'Encrypting {desc}')
c = Cipher(algorithms.AES(key),modes.CTR(iv),backend=default_backend())
encryptor = c.encryptor()
enc_data = encryptor.update(data) + encryptor.finalize()
@ -127,7 +128,8 @@ def encrypt_data(data,key,iv=aesctr_dfl_iv,desc='data',verify=True):
dec_data = encryptor.update(enc_data) + encryptor.finalize()
if dec_data != data:
die(2,f'ERROR.\nDecrypted {desc} doesn’t match original {desc}')
vmsg('done')
if not silent:
vmsg('done')
return enc_data
@ -243,22 +245,42 @@ def _get_random_data_from_user(uchars,desc):
return ret.encode()
def get_random(length):
return add_user_random(
rand_bytes = os.urandom(length),
desc = 'generated by your operating system' )
def add_user_random(rand_bytes,desc):
os_rand = os.urandom(length)
assert len(os_rand) == length, f'OS random number generator returned {len(os_rand)} (!= {length}) bytes!'
return add_user_random(
rand_bytes = os_rand,
desc = 'from your operating system' )
def add_user_random(
rand_bytes,
desc,
urand = {'data':b'', 'counter':0} ):
assert type(rand_bytes) == bytes, 'add_user_random_chk1'
if opt.usr_randchars:
if not g.user_entropy:
if not urand['data']:
from hashlib import sha256
g.user_entropy = sha256(_get_random_data_from_user(opt.usr_randchars,desc)).digest()
urand_desc = 'user-supplied entropy'
else:
urand_desc = 'saved user-supplied entropy'
key = make_key(g.user_entropy,b'','2',from_what=urand_desc,verbose=True)
msg(f'Encrypting random data {desc} with key')
return encrypt_data(rand_bytes,key,desc=desc,verify=False)
urand['data'] = sha256(_get_random_data_from_user(opt.usr_randchars,desc)).digest()
# counter protects against very evil rng that might repeatedly output the same data
urand['counter'] += 1
os_rand = os.urandom(8)
assert len(os_rand) == 8, f'OS random number generator returned {len(os_rand)} (!= 8) bytes!'
import hmac
key = hmac.digest(
urand['data'],
os_rand + int.to_bytes(urand['counter'],8,'big'),
'sha256' )
msg('Encrypting random data {} with ephemeral key #{}'.format( desc, urand['counter'] ))
return encrypt_data( data=rand_bytes, key=key, desc=desc, verify=False, silent=True )
else:
return rand_bytes

View file

@ -40,7 +40,7 @@ class GlobalContext(Lockable):
3 - command line
"""
_autolock = False
_set_ok = ('user_entropy','session')
_set_ok = ('session',)
_reset_ok = ('stdout','stderr','accept_defaults')
_use_class_attr = True
@ -66,7 +66,6 @@ class GlobalContext(Lockable):
# Variables - these might be altered at runtime:
user_entropy = b''
dfl_hash_preset = '3'
usr_randchars = 30

View file

@ -253,7 +253,6 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
t = self.spawn('mmgen-walletgen', args + [self.usr_rand_arg])
t.license()
t.usr_rand(self.usr_rand_chars)
t.expect('Generating')
wcls = MMGenWallet
t.passphrase_new('new '+wcls.desc,self.wpasswd)
t.label()
@ -591,7 +590,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
t.usr_rand(self.usr_rand_chars)
if ocls.type.startswith('incog'):
m = 'Encrypting random data generated by your operating system with key'
m = 'Encrypting random data from your operating system with ephemeral key'
t.expect(m)
t.expect(m)
incog_id = t.expect_getend('New Incog Wallet ID: ')

View file

@ -210,7 +210,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
t.usr_rand(self.usr_rand_chars)
if wcls.type.startswith('incog'):
for i in (1,2,3):
t.expect('Encrypting random data generated by your operating system with key')
t.expect('Encrypting random data from your operating system with ephemeral key')
if wcls.type == 'incog_hidden':
t.hincog_create(hincog_bytes)
if out_fmt == 'w':