summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/hashlib.rst18
-rw-r--r--Doc/whatsnew/3.12.rst6
-rw-r--r--Lib/hashlib.py70
-rw-r--r--Lib/test/test_hashlib.py10
-rw-r--r--Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst5
5 files changed, 22 insertions, 87 deletions
diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst
index 0906ce7..386541a 100644
--- a/Doc/library/hashlib.rst
+++ b/Doc/library/hashlib.rst
@@ -300,23 +300,17 @@ include a `salt <https://en.wikipedia.org/wiki/Salt_%28cryptography%29>`_.
>>> from hashlib import pbkdf2_hmac
>>> our_app_iters = 500_000 # Application specific, read above.
- >>> dk = pbkdf2_hmac('sha256', b'password', b'bad salt'*2, our_app_iters)
+ >>> dk = pbkdf2_hmac('sha256', b'password', b'bad salt' * 2, our_app_iters)
>>> dk.hex()
'15530bba69924174860db778f2c6f8104d3aaf9d26241840c8c4a641c8d000a9'
- .. versionadded:: 3.4
-
- .. note::
+ Function only available when Python is compiled with OpenSSL.
- A fast implementation of *pbkdf2_hmac* is available with OpenSSL. The
- Python implementation uses an inline version of :mod:`hmac`. It is about
- three times slower and doesn't release the GIL.
-
- .. deprecated:: 3.10
+ .. versionadded:: 3.4
- Slow Python implementation of *pbkdf2_hmac* is deprecated. In the
- future the function will only be available when Python is compiled
- with OpenSSL.
+ .. versionchanged:: 3.12
+ Function now only available when Python is built with OpenSSL. The slow
+ pure Python implementation has been removed.
.. function:: scrypt(password, *, salt, n, r, p, maxmem=0, dklen=64)
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index e0b9599..0a4d498 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -273,6 +273,12 @@ Removed
use :func:`locale.format_string` instead.
(Contributed by Victor Stinner in :gh:`94226`.)
+* :mod:`hashlib`: Remove the pure Python implementation of
+ :func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and
+ newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides
+ a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster.
+ (Contributed by Victor Stinner in :gh:`94199`.)
+
Porting to Python 3.12
======================
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
index b546a3f..21b5e91 100644
--- a/Lib/hashlib.py
+++ b/Lib/hashlib.py
@@ -65,7 +65,7 @@ algorithms_guaranteed = set(__always_supported)
algorithms_available = set(__always_supported)
__all__ = __always_supported + ('new', 'algorithms_guaranteed',
- 'algorithms_available', 'pbkdf2_hmac', 'file_digest')
+ 'algorithms_available', 'file_digest')
__builtin_constructor_cache = {}
@@ -180,72 +180,10 @@ except ImportError:
try:
# OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
from _hashlib import pbkdf2_hmac
+ __all__ += ('pbkdf2_hmac',)
except ImportError:
- from warnings import warn as _warn
- _trans_5C = bytes((x ^ 0x5C) for x in range(256))
- _trans_36 = bytes((x ^ 0x36) for x in range(256))
-
- def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
- """Password based key derivation function 2 (PKCS #5 v2.0)
-
- This Python implementations based on the hmac module about as fast
- as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
- for long passwords.
- """
- _warn(
- "Python implementation of pbkdf2_hmac() is deprecated.",
- category=DeprecationWarning,
- stacklevel=2
- )
- if not isinstance(hash_name, str):
- raise TypeError(hash_name)
-
- if not isinstance(password, (bytes, bytearray)):
- password = bytes(memoryview(password))
- if not isinstance(salt, (bytes, bytearray)):
- salt = bytes(memoryview(salt))
-
- # Fast inline HMAC implementation
- inner = new(hash_name)
- outer = new(hash_name)
- blocksize = getattr(inner, 'block_size', 64)
- if len(password) > blocksize:
- password = new(hash_name, password).digest()
- password = password + b'\x00' * (blocksize - len(password))
- inner.update(password.translate(_trans_36))
- outer.update(password.translate(_trans_5C))
-
- def prf(msg, inner=inner, outer=outer):
- # PBKDF2_HMAC uses the password as key. We can re-use the same
- # digest objects and just update copies to skip initialization.
- icpy = inner.copy()
- ocpy = outer.copy()
- icpy.update(msg)
- ocpy.update(icpy.digest())
- return ocpy.digest()
-
- if iterations < 1:
- raise ValueError(iterations)
- if dklen is None:
- dklen = outer.digest_size
- if dklen < 1:
- raise ValueError(dklen)
-
- dkey = b''
- loop = 1
- from_bytes = int.from_bytes
- while len(dkey) < dklen:
- prev = prf(salt + loop.to_bytes(4))
- # endianness doesn't matter here as long to / from use the same
- rkey = from_bytes(prev)
- for i in range(iterations - 1):
- prev = prf(prev)
- # rkey = rkey ^ prev
- rkey ^= from_bytes(prev)
- loop += 1
- dkey += rkey.to_bytes(inner.digest_size)
-
- return dkey[:dklen]
+ pass
+
try:
# OpenSSL's scrypt requires OpenSSL 1.1+
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index bc9407d..450dc49 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -1096,15 +1096,7 @@ class KDFTests(unittest.TestCase):
iterations=1, dklen=None)
self.assertEqual(out, self.pbkdf2_results['sha1'][0][0])
- @unittest.skipIf(builtin_hashlib is None, "test requires builtin_hashlib")
- def test_pbkdf2_hmac_py(self):
- with warnings_helper.check_warnings():
- self._test_pbkdf2_hmac(
- builtin_hashlib.pbkdf2_hmac, builtin_hashes
- )
-
- @unittest.skipUnless(hasattr(openssl_hashlib, 'pbkdf2_hmac'),
- ' test requires OpenSSL > 1.0')
+ @unittest.skipIf(openssl_hashlib is None, "requires OpenSSL bindings")
def test_pbkdf2_hmac_c(self):
self._test_pbkdf2_hmac(openssl_hashlib.pbkdf2_hmac, openssl_md_meth_names)
diff --git a/Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst b/Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst
new file mode 100644
index 0000000..f3a9a35
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-06-24-10-18-59.gh-issue-94199.kYOo8g.rst
@@ -0,0 +1,5 @@
+:mod:`hashlib`: Remove the pure Python implementation of
+:func:`hashlib.pbkdf2_hmac()`, deprecated in Python 3.10. Python 3.10 and
+newer requires OpenSSL 1.1.1 (:pep:`644`): this OpenSSL version provides
+a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. Patch
+by Victor Stinner.