Skip to content

Commit

Permalink
Merge #1522: Deduplicate AES code
Browse files Browse the repository at this point in the history
e4f74b5 Deduplicate AES code (Kristaps Kaupe)

Pull request description:

  There was almost identical code in `jmbitcoin/jmbitcoin/secp256k1_ecies.py` and `jmclient/jmclient/storage.py`, moved it to `jmbase`.

ACKs for top commit:
  AdamISZ:
    tACK e4f74b5

Tree-SHA512: 6dfe347b9a9c1efc126f42fa4e7f55587cb142454f349256c30bc4a2224ee62263bb6635d5bbe8ccd0d1d32ece5f554ab55cdf3bb7b61adde6bce2ae2d0a5108
  • Loading branch information
kristapsk committed Aug 5, 2023
2 parents da8ab56 + e4f74b5 commit 7731bcf
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 36 deletions.
2 changes: 1 addition & 1 deletion jmbase/jmbase/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
JMHTTPResource, set_custom_stop_reactor)
from .bytesprod import BytesProducer
from .commands import *

from .crypto import aes_cbc_encrypt, aes_cbc_decrypt
15 changes: 15 additions & 0 deletions jmbase/jmbase/crypto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import pyaes

def aes_cbc_encrypt(key: bytes, data: bytes, iv: bytes) -> bytes:
encrypter = pyaes.Encrypter(
pyaes.AESModeOfOperationCBC(key, iv=iv))
enc_data = encrypter.feed(data)
enc_data += encrypter.feed()
return enc_data

def aes_cbc_decrypt(key: bytes, data: bytes, iv: bytes) -> bytes:
decrypter = pyaes.Decrypter(
pyaes.AESModeOfOperationCBC(key, iv=iv))
dec_data = decrypter.feed(data)
dec_data += decrypter.feed()
return dec_data
2 changes: 1 addition & 1 deletion jmbase/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
license='GPL',
packages=['jmbase'],
install_requires=['twisted==22.4.0', 'service-identity==21.1.0',
'chromalog==1.0.5'],
'chromalog==1.0.5', 'pyaes==1.6.1'],
python_requires='>=3.6',
zip_safe=False)
25 changes: 6 additions & 19 deletions jmbitcoin/jmbitcoin/secp256k1_ecies.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,22 @@
import base64
import hmac
import hashlib
import pyaes
import os
import jmbitcoin as btc
from jmbase import aes_cbc_encrypt, aes_cbc_decrypt
from bitcointx.core.key import CPubKey

ECIES_MAGIC_BYTES = b'BIE1'

class ECIESDecryptionError(Exception):
pass

# AES primitives. See BIP-SNICKER for specification.
def aes_encrypt(key, data, iv):
encrypter = pyaes.Encrypter(
pyaes.AESModeOfOperationCBC(key, iv=iv))
enc_data = encrypter.feed(data)
enc_data += encrypter.feed()

return enc_data

def aes_decrypt(key, data, iv):
decrypter = pyaes.Decrypter(
pyaes.AESModeOfOperationCBC(key, iv=iv))
def _ecies_aes_decrypt(key, data, iv):
try:
dec_data = decrypter.feed(data)
dec_data += decrypter.feed()
return aes_cbc_decrypt(key, data, iv)
except ValueError:
# note decryption errors can come from PKCS7 padding errors
raise ECIESDecryptionError()
return dec_data

def ecies_encrypt(message, pubkey):
""" Take a message in bytes and a secp256k1 public key
Expand All @@ -53,10 +40,10 @@ def ecies_encrypt(message, pubkey):
ecdh_key = btc.multiply(r, pubkey)
key = hashlib.sha512(ecdh_key).digest()
iv, key_e, key_m = key[0:16], key[16:32], key[32:]
ciphertext = aes_encrypt(key_e, message, iv=iv)
ciphertext = aes_cbc_encrypt(key_e, message, iv=iv)
encrypted = ECIES_MAGIC_BYTES + R + ciphertext
mac = hmac.new(key_m, encrypted, hashlib.sha256).digest()
return base64.b64encode(encrypted + mac)
return base64.b64encode(encrypted + mac)

def ecies_decrypt(privkey, encrypted):
if len(privkey) == 33 and privkey[-1] == 1:
Expand All @@ -78,5 +65,5 @@ def ecies_decrypt(privkey, encrypted):
iv, key_e, key_m = key[0:16], key[16:32], key[32:]
if mac != hmac.new(key_m, encrypted[:-32], hashlib.sha256).digest():
raise ECIESDecryptionError()
return aes_decrypt(key_e, ciphertext, iv=iv)
return _ecies_aes_decrypt(key_e, ciphertext, iv=iv)

2 changes: 1 addition & 1 deletion jmbitcoin/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
license='GPL',
packages=['jmbitcoin'],
python_requires='>=3.6',
install_requires=['python-bitcointx==1.1.3', 'pyaes==1.6.1'],
install_requires=['python-bitcointx==1.1.3'],
zip_safe=False)
19 changes: 6 additions & 13 deletions jmclient/jmclient/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import shutil
import atexit
import bencoder
import pyaes
from hashlib import sha256
from argon2 import low_level
from jmbase import aes_cbc_encrypt, aes_cbc_decrypt
from .support import get_random_bytes


Expand Down Expand Up @@ -252,20 +252,13 @@ def _decrypt_file(self, password, data):

return self._decrypt(container[b'data'], container[b'enc'][b'iv'])

def _encrypt(self, data, iv):
encrypter = pyaes.Encrypter(
pyaes.AESModeOfOperationCBC(self._hash.hash, iv=iv))
enc_data = encrypter.feed(self.MAGIC_DETECT_ENC + data)
enc_data += encrypter.feed()
def _encrypt(self, data: bytes, iv: bytes) -> bytes:
return aes_cbc_encrypt(self._hash.hash,
self.MAGIC_DETECT_ENC + data, iv)

return enc_data

def _decrypt(self, data, iv):
decrypter = pyaes.Decrypter(
pyaes.AESModeOfOperationCBC(self._hash.hash, iv=iv))
def _decrypt(self, data: bytes, iv: bytes) -> bytes:
try:
dec_data = decrypter.feed(data)
dec_data += decrypter.feed()
dec_data = aes_cbc_decrypt(self._hash.hash, data, iv)
except ValueError:
# in most "wrong password" cases the pkcs7 padding will be wrong
raise StoragePasswordError("Wrong password.")
Expand Down
2 changes: 1 addition & 1 deletion jmclient/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
packages=['jmclient'],
install_requires=['joinmarketbase==0.9.10dev', 'mnemonic==0.20',
'argon2_cffi==21.3.0', 'bencoder.pyx==3.0.1',
'pyaes==1.6.1', 'klein==20.6.0', 'pyjwt==2.4.0',
'klein==20.6.0', 'pyjwt==2.4.0',
'autobahn==20.12.3', 'werkzeug==2.2.3'],
python_requires='>=3.6',
zip_safe=False)

0 comments on commit 7731bcf

Please sign in to comment.