diff options
author | Eli Collins <elic@assurancetechnologies.com> | 2020-10-06 15:56:15 -0400 |
---|---|---|
committer | Eli Collins <elic@assurancetechnologies.com> | 2020-10-06 15:56:15 -0400 |
commit | 73ab1733ebe4813063ecf96ba9fca028392db7ff (patch) | |
tree | ca37eb4fe3717cb72c5e50864804dcc0bc43da45 | |
parent | 49eb92ea545e69184bbea041d979325b2c715600 (diff) | |
download | passlib-73ab1733ebe4813063ecf96ba9fca028392db7ff.tar.gz |
passlib.hash.bcrypt: remove support for "py-bcrypt" backend
-rw-r--r-- | passlib/handlers/bcrypt.py | 73 | ||||
-rw-r--r-- | passlib/tests/test_handlers_bcrypt.py | 36 | ||||
-rw-r--r-- | tox.ini | 3 |
3 files changed, 1 insertions, 111 deletions
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py index c153dc4..7a57d47 100644 --- a/passlib/handlers/bcrypt.py +++ b/passlib/handlers/bcrypt.py @@ -19,7 +19,6 @@ import logging; log = logging.getLogger(__name__) from warnings import warn # site _bcrypt = None # dynamically imported by _load_backend_bcrypt() -_pybcrypt = None # dynamically imported by _load_backend_pybcrypt() # pkg _builtin_bcrypt = None # dynamically imported by _load_backend_builtin() from passlib.crypto.digest import compile_hmac @@ -651,75 +650,6 @@ class _BcryptBackend(_BcryptCommon): raise uh.exc.CryptBackendError(self, config, hash, source="`bcrypt` package") return hash[-31:].decode("ascii") -#----------------------------------------------------------------------- -# pybcrypt backend -#----------------------------------------------------------------------- -class _PyBcryptBackend(_BcryptCommon): - """ - backend which uses 'pybcrypt' package - """ - - #: classwide thread lock used for pybcrypt < 0.3 - _calc_lock = None - - @classmethod - def _load_backend_mixin(mixin_cls, name, dryrun): - # try to import pybcrypt - global _pybcrypt - if not _detect_pybcrypt(): - # not installed, or bcrypt installed instead - return False - try: - import bcrypt as _pybcrypt - except ImportError: # pragma: no cover - # XXX: should we raise AssertionError here? (if get here, _detect_pybcrypt() is broken) - return False - - # deprecated as of 1.7.2 - if not dryrun: - warn("Support for `py-bcrypt` is deprecated, and will be removed in Passlib 1.8; " - "Please use `pip install bcrypt` instead", DeprecationWarning) - - # determine pybcrypt version - try: - version = _pybcrypt._bcrypt.__version__ - except: - log.warning("(trapped) error reading pybcrypt version", exc_info=True) - version = "<unknown>" - log.debug("detected 'pybcrypt' backend, version %r", version) - - # return calc function based on version - vinfo = parse_version(version) or (0, 0) - if vinfo < (0, 3): - warn("py-bcrypt %s has a major security vulnerability, " - "you should upgrade to py-bcrypt 0.3 immediately." - % version, uh.exc.PasslibSecurityWarning) - if mixin_cls._calc_lock is None: - import threading - mixin_cls._calc_lock = threading.Lock() - mixin_cls._calc_checksum = mixin_cls._calc_checksum_threadsafe - - return mixin_cls._finalize_backend_mixin(name, dryrun) - - def _calc_checksum_threadsafe(self, secret): - # as workaround for pybcrypt < 0.3's concurrency issue, - # we wrap everything in a thread lock. as long as bcrypt is only - # used through passlib, this should be safe. - with self._calc_lock: - return self._calc_checksum_raw(secret) - - def _calc_checksum_raw(self, secret): - # py-bcrypt behavior: - # py3: unicode secret encoded as utf-8 bytes, - # hash encoded as ascii bytes, returns ascii unicode. - secret, ident = self._prepare_digest_args(secret) - config = self._get_config(ident) - hash = _pybcrypt.hashpw(secret, config) - if not hash.startswith(config) or len(hash) != len(config) + 31: - raise uh.exc.CryptBackendError(self, config, hash, source="pybcrypt library") - return hash[-31:] - - _calc_checksum = _calc_checksum_raw #----------------------------------------------------------------------- # os crypt backend @@ -898,7 +828,7 @@ class bcrypt(_NoBackend, _BcryptCommon): # in order to load the appropriate backend. #: list of potential backends - backends = ("bcrypt", "pybcrypt", "os_crypt", "builtin") + backends = ("bcrypt", "os_crypt", "builtin") #: flag that this class's bases should be modified by SubclassBackendMixin _backend_mixin_target = True @@ -907,7 +837,6 @@ class bcrypt(_NoBackend, _BcryptCommon): _backend_mixin_map = { None: _NoBackend, "bcrypt": _BcryptBackend, - "pybcrypt": _PyBcryptBackend, "os_crypt": _OsCryptBackend, "builtin": _BuiltinBackend, } diff --git a/passlib/tests/test_handlers_bcrypt.py b/passlib/tests/test_handlers_bcrypt.py index 54a3bc1..683b9ba 100644 --- a/passlib/tests/test_handlers_bcrypt.py +++ b/passlib/tests/test_handlers_bcrypt.py @@ -200,7 +200,6 @@ class _bcrypt_test(HandlerCase): fuzz_verifiers = HandlerCase.fuzz_verifiers + ( "fuzz_verifier_bcrypt", - "fuzz_verifier_pybcrypt", ) def fuzz_verifier_bcrypt(self): @@ -235,39 +234,6 @@ class _bcrypt_test(HandlerCase): raise ValueError("bcrypt rejected hash: %r (secret=%r)" % (hash, secret)) return check_bcrypt - def fuzz_verifier_pybcrypt(self): - # test against py-bcrypt, if available - from passlib.handlers.bcrypt import ( - IDENT_2, IDENT_2A, IDENT_2B, IDENT_2X, IDENT_2Y, - _PyBcryptBackend, - ) - from passlib.utils import to_native_str - - loaded = _PyBcryptBackend._load_backend_mixin("pybcrypt", False) - if not loaded: - return - - from passlib.handlers.bcrypt import _pybcrypt as bcrypt_mod - - lock = _PyBcryptBackend._calc_lock # reuse threadlock workaround for pybcrypt 0.2 - - def check_pybcrypt(secret, hash): - """pybcrypt""" - secret = to_native_str(secret, self.FuzzHashGenerator.password_encoding) - if len(secret) > 200: # vulnerable to wraparound bug - secret = secret[:200] - if hash.startswith((IDENT_2B, IDENT_2Y)): - hash = IDENT_2A + hash[4:] - try: - if lock: - with lock: - return bcrypt_mod.hashpw(secret, hash) == hash - else: - return bcrypt_mod.hashpw(secret, hash) == hash - except ValueError: - raise ValueError("py-bcrypt rejected hash: %r" % (hash,)) - return check_pybcrypt - class FuzzHashGenerator(HandlerCase.FuzzHashGenerator): @@ -400,7 +366,6 @@ class _bcrypt_test(HandlerCase): # create test cases for specific backends bcrypt_bcrypt_test = _bcrypt_test.create_backend_case("bcrypt") -bcrypt_pybcrypt_test = _bcrypt_test.create_backend_case("pybcrypt") class bcrypt_os_crypt_test(_bcrypt_test.create_backend_case("os_crypt")): @@ -645,7 +610,6 @@ class _bcrypt_sha256_test(HandlerCase): # create test cases for specific backends bcrypt_sha256_bcrypt_test = _bcrypt_sha256_test.create_backend_case("bcrypt") -bcrypt_sha256_pybcrypt_test = _bcrypt_sha256_test.create_backend_case("pybcrypt") class bcrypt_sha256_os_crypt_test(_bcrypt_sha256_test.create_backend_case("os_crypt")): @@ -58,9 +58,7 @@ envlist = pbkdf2-frombytes-py{3,py3}, # bcrypt backend testing (bcrypt cffi tested by default test) - # NOTE: 'other' checks bcryptor & py-bcrypt ## bcrypthash-bcrypt-py{2,3,py,py3}, # tested by default config - bcrypthash-other-py3 bcrypthash-{builtin,disabled}-py{3,py3} # scrypt backend testing (builtin backend tested by default test) @@ -156,7 +154,6 @@ deps = # NOTE: bcrypt10 env disabled, just used to check legacy issues ## bcrypthash-bcrypt10: bcrypt<1.1 default,bcrypthash-bcrypt: bcrypt - bcrypthash-other: py-bcrypt # scrypt backend tests # XXX: would test 'scrypt' under default, but not compatible w/ pypy, |