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