crypto.py: reimplement AES routines using the cryptography library
- the pycrypto library is now no longer used by MMGen - cryptography initializes the counter with bytes instead of an int, leading to a small API change
This commit is contained in:
parent
7cc69a2725
commit
8a3b9216f6
3 changed files with 25 additions and 34 deletions
|
|
@ -20,8 +20,9 @@
|
|||
crypto.py: Cryptographic and related routines for the MMGen suite
|
||||
"""
|
||||
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from hashlib import sha256
|
||||
|
||||
from mmgen.common import *
|
||||
|
||||
crmsg = {
|
||||
|
|
@ -49,7 +50,7 @@ def scramble_seed(seed,scramble_key,hash_rounds):
|
|||
return sha256_rounds(scr_seed,hash_rounds)
|
||||
|
||||
def encrypt_seed(seed,key):
|
||||
return encrypt_data(seed,key,iv=1,desc='seed')
|
||||
return encrypt_data(seed,key,desc='seed')
|
||||
|
||||
def decrypt_seed(enc_seed,key,seed_id,key_id):
|
||||
vmsg_r('Checking key...')
|
||||
|
|
@ -59,7 +60,7 @@ def decrypt_seed(enc_seed,key,seed_id,key_id):
|
|||
msg('Incorrect passphrase or hash preset')
|
||||
return False
|
||||
|
||||
dec_seed = decrypt_data(enc_seed,key,iv=1,desc='seed')
|
||||
dec_seed = decrypt_data(enc_seed,key,desc='seed')
|
||||
chk2 = make_chksum_8(dec_seed)
|
||||
if seed_id:
|
||||
if compare_chksums(seed_id,'Seed ID',chk2,'decrypted seed'):
|
||||
|
|
@ -79,31 +80,28 @@ def decrypt_seed(enc_seed,key,seed_id,key_id):
|
|||
dmsg('Decrypted seed: {}'.format(dec_seed.hex()))
|
||||
return dec_seed
|
||||
|
||||
def encrypt_data(data,key,iv=1,desc='data',verify=True):
|
||||
# 192-bit seed is 24 bytes -> not multiple of 16. Must use MODE_CTR
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
def encrypt_data(data,key,iv=g.aesctr_dfl_iv,desc='data',verify=True):
|
||||
vmsg('Encrypting {}'.format(desc))
|
||||
c = AES.new(key,AES.MODE_CTR,counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
enc_data = c.encrypt(data)
|
||||
c = Cipher(algorithms.AES(key),modes.CTR(iv),backend=default_backend())
|
||||
encryptor = c.encryptor()
|
||||
enc_data = encryptor.update(data) + encryptor.finalize()
|
||||
|
||||
if verify:
|
||||
vmsg_r('Performing a test decryption of the {}...'.format(desc))
|
||||
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')
|
||||
else:
|
||||
c = Cipher(algorithms.AES(key),modes.CTR(iv),backend=default_backend())
|
||||
encryptor = c.encryptor()
|
||||
dec_data = encryptor.update(enc_data) + encryptor.finalize()
|
||||
if dec_data != data:
|
||||
die(2,"ERROR.\nDecrypted {s} doesn't match original {s}".format(s=desc))
|
||||
vmsg('done')
|
||||
|
||||
return enc_data
|
||||
|
||||
def decrypt_data(enc_data,key,iv=1,desc='data'):
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
def decrypt_data(enc_data,key,iv=g.aesctr_dfl_iv,desc='data'):
|
||||
vmsg_r('Decrypting {} with key...'.format(desc))
|
||||
c = AES.new(key,AES.MODE_CTR,counter=Counter.new(g.aesctr_iv_len*8,initial_value=iv))
|
||||
return c.decrypt(enc_data)
|
||||
c = Cipher(algorithms.AES(key),modes.CTR(iv),backend=default_backend())
|
||||
encryptor = c.encryptor()
|
||||
return encryptor.update(enc_data) + encryptor.finalize()
|
||||
|
||||
def scrypt_hash_passphrase(passwd,salt,hash_preset,buflen=32):
|
||||
|
||||
|
|
@ -153,8 +151,7 @@ def _get_random_data_from_user(uchars):
|
|||
return key_data+''.join(fmt_time_data).encode()
|
||||
|
||||
def get_random(length):
|
||||
from Crypto import Random
|
||||
os_rand = Random.new().read(length)
|
||||
os_rand = os.urandom(length)
|
||||
if opt.usr_randchars:
|
||||
from_what = 'OS random data'
|
||||
if not g.user_entropy:
|
||||
|
|
@ -163,7 +160,7 @@ def get_random(length):
|
|||
from_what += ' plus user-supplied entropy'
|
||||
else:
|
||||
from_what += ' plus saved user-supplied entropy'
|
||||
key = make_key(g.user_entropy,'','2',from_what=from_what,verbose=True)
|
||||
key = make_key(g.user_entropy,b'','2',from_what=from_what,verbose=True)
|
||||
return encrypt_data(os_rand,key,desc='random data',verify=False)
|
||||
else:
|
||||
return os_rand
|
||||
|
|
@ -195,7 +192,7 @@ def mmgen_encrypt(data,desc='data',hash_preset=''):
|
|||
qmsg("Using {} hash preset of '{}'".format(m,hp))
|
||||
passwd = get_new_passphrase(desc,{})
|
||||
key = make_key(passwd,salt,hp)
|
||||
enc_d = encrypt_data(sha256(nonce+data).digest()+nonce+data,key,int(iv.hex(),16),desc=desc)
|
||||
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=''):
|
||||
|
|
@ -210,7 +207,7 @@ def mmgen_decrypt(data,desc='data',hash_preset=''):
|
|||
qmsg("Using {} hash preset of '{}'".format(m,hp))
|
||||
passwd = get_mmgen_passphrase(desc)
|
||||
key = make_key(passwd,salt,hp)
|
||||
dec_d = decrypt_data(enc_d,key,int(iv.hex(),16),desc)
|
||||
dec_d = decrypt_data(enc_d,key,iv,desc)
|
||||
if dec_d[:_sha256_len] == sha256(dec_d[_sha256_len:]).digest():
|
||||
vmsg('OK')
|
||||
return dec_d[_sha256_len+_nonce_len:]
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ class g(object):
|
|||
mmenc_ext = 'mmenc'
|
||||
salt_len = 16
|
||||
aesctr_iv_len = 16
|
||||
aesctr_dfl_iv = b'\x00' * (aesctr_iv_len-1) + b'\x01'
|
||||
hincog_chk_len = 8
|
||||
|
||||
key_generators = 'python-ecdsa','secp256k1' # '1','2'
|
||||
|
|
|
|||
|
|
@ -855,7 +855,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
|
|||
d.salt = get_random(g.salt_len)
|
||||
key = make_key(d.passwd, d.salt, d.hash_preset, 'incog wallet key')
|
||||
chk = sha256(self.seed.data).digest()[:8]
|
||||
d.enc_seed = encrypt_data(chk + self.seed.data, key, 1, 'seed')
|
||||
d.enc_seed = encrypt_data(chk+self.seed.data, key, g.aesctr_dfl_iv, 'seed')
|
||||
|
||||
d.wrapper_key = make_key(d.passwd, d.iv, d.hash_preset, 'incog wrapper key')
|
||||
d.key_id = make_chksum_8(d.wrapper_key)
|
||||
|
|
@ -864,13 +864,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
|
|||
|
||||
def _format(self):
|
||||
d = self.ssdata
|
||||
# print len(d.iv), len(d.salt), len(d.enc_seed), len(d.wrapper_key)
|
||||
self.fmt_data = d.iv + encrypt_data(
|
||||
d.salt + d.enc_seed,
|
||||
d.wrapper_key,
|
||||
int(d.iv.hex(),16),
|
||||
self.desc)
|
||||
# print len(self.fmt_data)
|
||||
self.fmt_data = d.iv + encrypt_data(d.salt+d.enc_seed, d.wrapper_key, d.iv, self.desc)
|
||||
|
||||
def _filename(self):
|
||||
s = self.seed
|
||||
|
|
@ -921,8 +915,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
|
|||
|
||||
# IV is used BOTH to initialize counter and to salt password!
|
||||
key = make_key(d.passwd, d.iv, d.hash_preset, 'wrapper key')
|
||||
dd = decrypt_data(d.enc_incog_data, key,
|
||||
int(d.iv.hex(),16), 'incog data')
|
||||
dd = decrypt_data(d.enc_incog_data, key, d.iv, 'incog data')
|
||||
|
||||
d.salt = dd[0:g.salt_len]
|
||||
d.enc_seed = dd[g.salt_len:]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue