Browse Source

dependencies: rm pyaes from requirements

Since #6014, pyaes is not really needed anymore.

As we currently require either one of pycryptodomex or cryptography,
even if pyaes is available, it will not be used.
We could strip it out completely from crypto.py...

In any case, pyaes is still pulled in by some hw wallet dependencies indirectly;
but the core library no longer depends on it.
patch-4
SomberNight 4 years ago
parent
commit
7e534f4865
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 1
      contrib/requirements/requirements.txt
  2. 18
      electrum/crypto.py
  3. 13
      electrum/tests/test_bitcoin.py
  4. 1
      run_electrum
  5. 2
      setup.py

1
contrib/requirements/requirements.txt

@ -1,4 +1,3 @@
pyaes>=0.1a1
ecdsa>=0.14 ecdsa>=0.14
qrcode qrcode
protobuf>=3.12 protobuf>=3.12

18
electrum/crypto.py

@ -30,12 +30,18 @@ import hashlib
import hmac import hmac
from typing import Union from typing import Union
import pyaes
from .util import assert_bytes, InvalidPassword, to_bytes, to_string, WalletFileException from .util import assert_bytes, InvalidPassword, to_bytes, to_string, WalletFileException
from .i18n import _ from .i18n import _
HAS_PYAES = False
try:
import pyaes
except:
pass
else:
HAS_PYAES = True
HAS_CRYPTODOME = False HAS_CRYPTODOME = False
try: try:
from Cryptodome.Cipher import ChaCha20_Poly1305 as CD_ChaCha20_Poly1305 from Cryptodome.Cipher import ChaCha20_Poly1305 as CD_ChaCha20_Poly1305
@ -97,10 +103,12 @@ def aes_encrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
cipher = CG_Cipher(CG_algorithms.AES(key), CG_modes.CBC(iv), backend=CG_default_backend()) cipher = CG_Cipher(CG_algorithms.AES(key), CG_modes.CBC(iv), backend=CG_default_backend())
encryptor = cipher.encryptor() encryptor = cipher.encryptor()
e = encryptor.update(data) + encryptor.finalize() e = encryptor.update(data) + encryptor.finalize()
else: elif HAS_PYAES:
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv) aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_NONE) aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_NONE)
e = aes.feed(data) + aes.feed() # empty aes.feed() flushes buffer e = aes.feed(data) + aes.feed() # empty aes.feed() flushes buffer
else:
raise Exception("no AES backend found")
return e return e
@ -113,10 +121,12 @@ def aes_decrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
cipher = CG_Cipher(CG_algorithms.AES(key), CG_modes.CBC(iv), backend=CG_default_backend()) cipher = CG_Cipher(CG_algorithms.AES(key), CG_modes.CBC(iv), backend=CG_default_backend())
decryptor = cipher.decryptor() decryptor = cipher.decryptor()
data = decryptor.update(data) + decryptor.finalize() data = decryptor.update(data) + decryptor.finalize()
else: elif HAS_PYAES:
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv) aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_NONE) aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_NONE)
data = aes.feed(data) + aes.feed() # empty aes.feed() flushes buffer data = aes.feed(data) + aes.feed() # empty aes.feed() flushes buffer
else:
raise Exception("no AES backend found")
try: try:
return strip_PKCS7_padding(data) return strip_PKCS7_padding(data)
except InvalidPadding: except InvalidPadding:

13
electrum/tests/test_bitcoin.py

@ -46,18 +46,21 @@ def needs_test_with_all_aes_implementations(func):
return return
has_cryptodome = crypto.HAS_CRYPTODOME has_cryptodome = crypto.HAS_CRYPTODOME
has_cryptography = crypto.HAS_CRYPTOGRAPHY has_cryptography = crypto.HAS_CRYPTOGRAPHY
has_pyaes = crypto.HAS_PYAES
try: try:
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = False, False if has_pyaes:
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY, crypto.HAS_PYAES) = False, False, True
func(*args, **kwargs) # pyaes func(*args, **kwargs) # pyaes
if has_cryptodome: if has_cryptodome:
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = True, False (crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY, crypto.HAS_PYAES) = True, False, False
func(*args, **kwargs) # cryptodome func(*args, **kwargs) # cryptodome
if has_cryptography: if has_cryptography:
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = False, True (crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY, crypto.HAS_PYAES) = False, True, False
func(*args, **kwargs) # cryptography func(*args, **kwargs) # cryptography
finally: finally:
crypto.HAS_CRYPTODOME = has_cryptodome crypto.HAS_CRYPTODOME = has_cryptodome
crypto.HAS_CRYPTOGRAPHY = has_cryptography crypto.HAS_CRYPTOGRAPHY = has_cryptography
crypto.HAS_PYAES = has_pyaes
return run_test return run_test
@ -101,6 +104,10 @@ class Test_bitcoin(ElectrumTestCase):
# we want the unit testing framework to test with cryptography available. # we want the unit testing framework to test with cryptography available.
self.assertTrue(bool(crypto.HAS_CRYPTOGRAPHY)) self.assertTrue(bool(crypto.HAS_CRYPTOGRAPHY))
def test_pyaes_is_available(self):
# we want the unit testing framework to test with pyaes available.
self.assertTrue(bool(crypto.HAS_PYAES))
@needs_test_with_all_aes_implementations @needs_test_with_all_aes_implementations
def test_crypto(self): def test_crypto(self):
for message in [b"Chancellor on brink of second bailout for banks", b'\xff'*512]: for message in [b"Chancellor on brink of second bailout for banks", b'\xff'*512]:

1
run_electrum

@ -60,7 +60,6 @@ def check_imports():
# pure-python dependencies need to be imported here for pyinstaller # pure-python dependencies need to be imported here for pyinstaller
try: try:
import dns import dns
import pyaes
import ecdsa import ecdsa
import certifi import certifi
import qrcode import qrcode

2
setup.py

@ -54,7 +54,7 @@ extras_require = {
'hardware': requirements_hw, 'hardware': requirements_hw,
'gui': ['pyqt5'], 'gui': ['pyqt5'],
'crypto': ['cryptography>=2.1'], 'crypto': ['cryptography>=2.1'],
'tests': ['pycryptodomex>=3.7', 'cryptography>=2.1'], 'tests': ['pycryptodomex>=3.7', 'cryptography>=2.1', 'pyaes>=0.1a1'],
} }
# 'full' extra that tries to grab everything an enduser would need (except for libsecp256k1...) # 'full' extra that tries to grab everything an enduser would need (except for libsecp256k1...)
extras_require['full'] = [pkg for sublist in extras_require['full'] = [pkg for sublist in

Loading…
Cancel
Save