From 91495d75f2e2ea02cd195de95c77d25441eecaa6 Mon Sep 17 00:00:00 2001 From: Fabrice Bauzac Date: Tue, 26 Jan 2021 23:19:09 +0100 Subject: [PATCH] Prefer Cryptodome which is better maintained Prefer Cryptodome over Pycryptopp or Pycrypto. Cryptodome is more actively maintained at the moment. Use the specific "cryptodomex" interface of Cryptodome instead of the Pycrypto-compatible "cryptodome" interface, to avoid clashes with Pycrypto itself; in particular, for system-wide installation (such as Debian), it allows peaceful coexistence of both and smooth transition from Pycrypto to Cryptodome. --- beaker/crypto/pycrypto.py | 50 +++++++++++++++++++++++++++++++++------ setup.py | 4 ++-- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/beaker/crypto/pycrypto.py b/beaker/crypto/pycrypto.py index 55b319cc..9606f4fc 100644 --- a/beaker/crypto/pycrypto.py +++ b/beaker/crypto/pycrypto.py @@ -1,9 +1,44 @@ -"""Encryption module that uses pycryptopp or pycrypto""" +"""Encryption module that uses cryptodomex, pycryptopp, or pycrypto, whichever is +available first. + +cryptodomex is preferred over Pycryptopp because (as of 2021-01-26) it +is more actively maintained. + +""" + +try: + import Cryptodome + have_cryptodome = True +except ImportError: + have_cryptodome = False + try: - # Pycryptopp is preferred over Crypto because Crypto has had - # various periods of not being maintained, and pycryptopp uses - # the Crypto++ library which is generally considered the 'gold standard' - # of crypto implementations + import pycryptopp + have_pycryptopp = True +except ImportError: + have_pycryptopp = False + +try: + import Crypto + have_pycrypto = True +except ImportError: + have_pycrypto = False + +if have_cryptodome: + from Cryptodome.Cipher import AES + from Cryptodome.Util import Counter + + def aesEncrypt(data, key): + cipher = AES.new(key, AES.MODE_CTR, + counter=Counter.new(128, initial_value=0)) + + return cipher.encrypt(data) + + def aesDecrypt(data, key): + cipher = AES.new(key, AES.MODE_CTR, + counter=Counter.new(128, initial_value=0)) + return cipher.decrypt(data) +elif have_pycryptopp: from pycryptopp.cipher import aes def aesEncrypt(data, key): @@ -12,8 +47,7 @@ def aesEncrypt(data, key): # magic. aesDecrypt = aesEncrypt - -except ImportError: +elif have_pycrypto: from Crypto.Cipher import AES from Crypto.Util import Counter @@ -27,6 +61,8 @@ def aesDecrypt(data, key): cipher = AES.new(key, AES.MODE_CTR, counter=Counter.new(128, initial_value=0)) return cipher.decrypt(data) +else: + raise Exception("Could not find a suitable module to implement beaker.crypto.pycrypto") has_aes = True diff --git a/setup.py b/setup.py index efe063c0..fd26db33 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ INSTALL_REQUIRES.append('funcsigs') -TESTS_REQUIRE = ['pytest', 'Mock', 'pycryptodome'] +TESTS_REQUIRE = ['pytest', 'Mock', 'pycryptodomex'] if py_version == (2, 6): TESTS_REQUIRE.append('WebTest<2.0.24') @@ -90,7 +90,7 @@ extras_require={ 'crypto': ['pycryptopp>=0.5.12'], 'pycrypto': ['pycrypto'], - 'pycryptodome': ['pycryptodome'], + 'pycryptodome': ['pycryptodomex'], 'cryptography': ['cryptography'], 'testsuite': [TESTS_REQUIRE] },