pbkdf2 implemented ctypes wrapper around OpenSSL native implementation: 6x speedup
This commit is contained in:
@@ -0,0 +1,86 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
pbkdf2_ctypes
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
This module implements pbkdf2 for Python using crypto lib from
|
||||||
|
openssl.
|
||||||
|
|
||||||
|
Note: This module is intended as a plugin replacement of pbkdf2.py
|
||||||
|
by Armin Ronacher.
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright (c) 2013: Michele Comitini <mcm@glisco.it>
|
||||||
|
:license: LGPLv3
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
import hashlib
|
||||||
|
import platform
|
||||||
|
|
||||||
|
|
||||||
|
try: # check that we have proper OpenSSL on the system.
|
||||||
|
if platform.system()=='Windows':
|
||||||
|
if platform.architecture()[0] == '64bit':
|
||||||
|
crypto = ctypes.CDLL('libeay64.dll')
|
||||||
|
else:
|
||||||
|
crypto = ctypes.CDLL('libeay32.dll')
|
||||||
|
else: # should work on most unix os'.
|
||||||
|
crypto = ctypes.CDLL('libcrypto.so')
|
||||||
|
|
||||||
|
PKCS5_PBKDF2_HMAC = crypto.PKCS5_PBKDF2_HMAC
|
||||||
|
|
||||||
|
hashlib_to_crypto_map = {hashlib.md5: crypto.EVP_md5,
|
||||||
|
hashlib.sha1: crypto.EVP_sha1,
|
||||||
|
hashlib.sha256: crypto.EVP_sha256,
|
||||||
|
hashlib.sha224: crypto.EVP_sha224,
|
||||||
|
hashlib.sha384: crypto.EVP_sha384,
|
||||||
|
hashlib.sha512: crypto.EVP_sha512
|
||||||
|
}
|
||||||
|
except OSError, AttributeError:
|
||||||
|
raise ImportError('Cannot find a compatible OpenSSL installation on your system')
|
||||||
|
|
||||||
|
|
||||||
|
def pkcs5_pbkdf2_hmac(data, salt, iterations=1000, keylen=24, hashfunc=None):
|
||||||
|
c_pass = ctypes.c_char_p(data)
|
||||||
|
c_passlen = ctypes.c_int(len(data))
|
||||||
|
c_salt = ctypes.c_char_p(salt)
|
||||||
|
c_saltlen = ctypes.c_int(len(salt))
|
||||||
|
c_iter = ctypes.c_int(iterations)
|
||||||
|
c_keylen = ctypes.c_int(keylen)
|
||||||
|
if hashfunc:
|
||||||
|
crypto_hashfunc = hashlib_to_crypto_map.get(hashfunc)
|
||||||
|
crypto_hashfunc.restype = ctypes.c_void_p
|
||||||
|
if crypto_hashfunc is None:
|
||||||
|
raise ValueError('Unknown digest' + str(hashfunc))
|
||||||
|
c_digest = ctypes.c_void_p(crypto_hashfunc())
|
||||||
|
else:
|
||||||
|
crypto.EVP_sha1.restype = ctypes.c_void_p
|
||||||
|
c_digest = ctypes.c_void_p(crypto.EVP_sha1())
|
||||||
|
c_buff = ctypes.create_string_buffer('\000' * (keylen + 1))
|
||||||
|
err = PKCS5_PBKDF2_HMAC(c_pass, c_passlen,
|
||||||
|
c_salt, c_saltlen,
|
||||||
|
c_iter,
|
||||||
|
c_digest,
|
||||||
|
c_keylen,
|
||||||
|
c_buff)
|
||||||
|
|
||||||
|
if err == 0:
|
||||||
|
raise ValueError('wrong parameters')
|
||||||
|
return c_buff.raw[:keylen]
|
||||||
|
|
||||||
|
def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None):
|
||||||
|
return pkcs5_pbkdf2_hmac(data, salt, iterations, keylen, hashfunc).encode('hex')
|
||||||
|
|
||||||
|
def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
|
||||||
|
return pkcs5_pbkdf2_hmac(data, salt, iterations, keylen, hashfunc)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
crypto.SSLeay_version.restype = ctypes.c_char_p
|
||||||
|
print crypto.SSLeay_version(0)
|
||||||
|
for h in hashlib_to_crypto_map:
|
||||||
|
pkcs5_pbkdf2_hmac('secret' * 11, 'salt', hashfunc=h)
|
||||||
+4
-1
@@ -44,7 +44,10 @@ except ImportError:
|
|||||||
import hmac
|
import hmac
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from contrib.pbkdf2 import pbkdf2_hex
|
try:
|
||||||
|
from contrib.pbkdf2_ctypes import pbkdf2_hex
|
||||||
|
except ImportError:
|
||||||
|
from contrib.pbkdf2 import pbkdf2_hex
|
||||||
HAVE_PBKDF2 = True
|
HAVE_PBKDF2 = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user