Author: Stefano Rivera <[email protected]>
Branch: openssl-1.1
Changeset: r87983:a10a0e16df19
Date: 2016-10-28 15:39 -0700
http://bitbucket.org/pypy/pypy/changeset/a10a0e16df19/

Log:    OpenSSL 1.1 has a fast implementation of PKCS5_PBKDF2_HMAC

        Use it

diff --git a/pypy/module/_hashlib/__init__.py b/pypy/module/_hashlib/__init__.py
--- a/pypy/module/_hashlib/__init__.py
+++ b/pypy/module/_hashlib/__init__.py
@@ -1,5 +1,6 @@
 from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module._hashlib.interp_hashlib import algorithms, fetch_names
+from pypy.module._hashlib.interp_hashlib import (
+    algorithms, fetch_names, HAS_FAST_PKCS5_PBKDF2_HMAC)
 
 
 class Module(MixedModule):
@@ -13,6 +14,9 @@
     for name in algorithms:
         interpleveldefs['openssl_' + name] = 'interp_hashlib.new_' + name
 
+    if HAS_FAST_PKCS5_PBKDF2_HMAC:
+        interpleveldefs['pbkdf2_hmac'] = 'interp_hashlib.pbkdf2_hmac'
+
     def startup(self, space):
         w_meth_names = fetch_names(space)
         space.setattr(self, space.wrap('openssl_md_meth_names'), w_meth_names)
diff --git a/pypy/module/_hashlib/interp_hashlib.py 
b/pypy/module/_hashlib/interp_hashlib.py
--- a/pypy/module/_hashlib/interp_hashlib.py
+++ b/pypy/module/_hashlib/interp_hashlib.py
@@ -8,7 +8,7 @@
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.gateway import unwrap_spec, interp2app
+from pypy.interpreter.gateway import unwrap_spec, interp2app, WrappedDefault
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.module.thread.os_lock import Lock
 
@@ -184,3 +184,27 @@
 for _name in algorithms:
     _newname = 'new_%s' % (_name,)
     globals()[_newname] = make_new_hash(_name, _newname)
+
+
+HAS_FAST_PKCS5_PBKDF2_HMAC = ropenssl.PKCS5_PBKDF2_HMAC is not None
+if HAS_FAST_PKCS5_PBKDF2_HMAC:
+    @unwrap_spec(name=str, password=str, salt=str, rounds=int,
+                 w_dklen=WrappedDefault(None))
+    def pbkdf2_hmac(space, name, password, salt, rounds, w_dklen):
+        digest = ropenssl.EVP_get_digestbyname(name)
+        if not digest:
+            raise oefmt(space.w_ValueError, "unknown hash function")
+        if space.is_w(w_dklen, space.w_None):
+            dklen = ropenssl.EVP_MD_size(digest)
+        else:
+            dklen = space.int_w(w_dklen)
+        if dklen < 1:
+            raise oefmt(space.w_ValueError,
+                        "key length must be greater than 0.")
+        with rffi.scoped_alloc_buffer(dklen) as buf:
+            r = ropenssl.PKCS5_PBKDF2_HMAC(
+                password, len(password), salt, len(salt), rounds, digest,
+                dklen, buf.raw)
+            if not r:
+                raise ValueError
+            return space.wrap(buf.str(dklen))
diff --git a/pypy/module/_hashlib/test/test_hashlib.py 
b/pypy/module/_hashlib/test/test_hashlib.py
--- a/pypy/module/_hashlib/test/test_hashlib.py
+++ b/pypy/module/_hashlib/test/test_hashlib.py
@@ -111,3 +111,13 @@
             got.decode('hex')
             if expected is not None:
                 assert got == expected
+
+    def test_pbkdf2(self):
+        try:
+            from _hashlib import pbkdf2_hmac
+        except ImportError:
+            skip("Requires OpenSSL >= 1.1")
+        out = pbkdf2_hmac('sha1', 'password', 'salt', 1)
+        assert out == '0c60c80f961f0e71f3a9b524af6012062fe037a6'.decode('hex')
+        out = pbkdf2_hmac('sha1', 'password', 'salt', 2, None)
+        assert out == 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'.decode('hex')
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -592,6 +592,13 @@
     'EVP_MD_CTX_free', [EVP_MD_CTX], lltype.Void, releasegil=False,
     macro=bool(OPENSSL_VERSION_NUMBER < 0x10100000) or None)
 
+if OPENSSL_VERSION_NUMBER >= 0x10100000 and not LIBRESSL:
+    PKCS5_PBKDF2_HMAC = external('PKCS5_PBKDF2_HMAC', [
+        rffi.CCHARP, rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT, EVP_MD,
+        rffi.INT, rffi.CCHARP], rffi.INT)
+else:
+    PKCS5_PBKDF2_HMAC = None
+
 OBJ_NAME_CALLBACK = lltype.Ptr(lltype.FuncType(
         [OBJ_NAME, rffi.VOIDP], lltype.Void))
 OBJ_NAME_do_all = external(
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to