Issue #27928: Add scrypt (password-based key derivation function) to hashlib module (requires OpenSSL 1.1.0).
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
index 316cece..348ea14 100644
--- a/Lib/hashlib.py
+++ b/Lib/hashlib.py
@@ -202,6 +202,12 @@
 
         return dkey[:dklen]
 
+try:
+    # OpenSSL's scrypt requires OpenSSL 1.1+
+    from _hashlib import scrypt
+except ImportError:
+    pass
+
 
 for __func_name in __always_supported:
     # try them all, some may not work due to the OpenSSL
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index c9b113e..b010a74 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -7,6 +7,7 @@
 #
 
 import array
+from binascii import unhexlify
 import hashlib
 import itertools
 import os
@@ -447,6 +448,12 @@
         (b'pass\0word', b'sa\0lt', 4096, 16),
     ]
 
+    scrypt_test_vectors = [
+        (b'', b'', 16, 1, 1, unhexlify('77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906')),
+        (b'password', b'NaCl', 1024, 8, 16, unhexlify('fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640')),
+        (b'pleaseletmein', b'SodiumChloride', 16384, 8, 1, unhexlify('7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887')),
+   ]
+
     pbkdf2_results = {
         "sha1": [
             # official test vectors from RFC 6070
@@ -526,5 +533,45 @@
         self._test_pbkdf2_hmac(c_hashlib.pbkdf2_hmac)
 
 
+    @unittest.skipUnless(hasattr(c_hashlib, 'scrypt'),
+                     '   test requires OpenSSL > 1.1')
+    def test_scrypt(self):
+        for password, salt, n, r, p, expected in self.scrypt_test_vectors:
+            result = hashlib.scrypt(password, salt=salt, n=n, r=r, p=p)
+            self.assertEqual(result, expected)
+
+        # this values should work
+        hashlib.scrypt(b'password', salt=b'salt', n=2, r=8, p=1)
+        # password and salt must be bytes-like
+        with self.assertRaises(TypeError):
+            hashlib.scrypt('password', salt=b'salt', n=2, r=8, p=1)
+        with self.assertRaises(TypeError):
+            hashlib.scrypt(b'password', salt='salt', n=2, r=8, p=1)
+        # require keyword args
+        with self.assertRaises(TypeError):
+            hashlib.scrypt(b'password')
+        with self.assertRaises(TypeError):
+            hashlib.scrypt(b'password', b'salt')
+        with self.assertRaises(TypeError):
+            hashlib.scrypt(b'password', 2, 8, 1, salt=b'salt')
+        for n in [-1, 0, 1, None]:
+            with self.assertRaises((ValueError, OverflowError, TypeError)):
+                hashlib.scrypt(b'password', salt=b'salt', n=n, r=8, p=1)
+        for r in [-1, 0, None]:
+            with self.assertRaises((ValueError, OverflowError, TypeError)):
+                hashlib.scrypt(b'password', salt=b'salt', n=2, r=r, p=1)
+        for p in [-1, 0, None]:
+            with self.assertRaises((ValueError, OverflowError, TypeError)):
+                hashlib.scrypt(b'password', salt=b'salt', n=2, r=8, p=p)
+        for maxmem in [-1, None]:
+            with self.assertRaises((ValueError, OverflowError, TypeError)):
+                hashlib.scrypt(b'password', salt=b'salt', n=2, r=8, p=1,
+                               maxmem=maxmem)
+        for dklen in [-1, None]:
+            with self.assertRaises((ValueError, OverflowError, TypeError)):
+                hashlib.scrypt(b'password', salt=b'salt', n=2, r=8, p=1,
+                               dklen=dklen)
+
+
 if __name__ == "__main__":
     unittest.main()