update pbkdf2_ctypes.py to upstream

This commit is contained in:
Michele Comitini
2013-09-24 18:03:49 +02:00
parent d111f331ca
commit 7eb8a604bd
+34 -24
View File
@@ -3,13 +3,15 @@
pbkdf2_ctypes pbkdf2_ctypes
~~~~~~ ~~~~~~
Fast pbkdf2.
This module implements pbkdf2 for Python using crypto lib from This module implements pbkdf2 for Python using crypto lib from
openssl. openssl or commoncrypto.
Note: This module is intended as a plugin replacement of pbkdf2.py Note: This module is intended as a plugin replacement of pbkdf2.py
by Armin Ronacher. by Armin Ronacher.
Git repository: Git repository:
$ git clone https://github.com/michele-comitini/pbkdf2_ctypes.git $ git clone https://github.com/michele-comitini/pbkdf2_ctypes.git
:copyright: Copyright (c) 2013: Michele Comitini <mcm@glisco.it> :copyright: Copyright (c) 2013: Michele Comitini <mcm@glisco.it>
@@ -22,8 +24,12 @@ import ctypes.util
import hashlib import hashlib
import platform import platform
import os.path import os.path
import binascii
def commoncrypto_hashlib_to_crypto_map_get(hashfunc): __all__ = ['pkcs5_pbkdf2_hmac', 'pbkdf2_bin', 'pbkdf2_hex']
__version__ = '0.99.3'
def _commoncrypto_hashlib_to_crypto_map_get(hashfunc):
hashlib_to_crypto_map = {hashlib.sha1: 1, hashlib_to_crypto_map = {hashlib.sha1: 1,
hashlib.sha224: 2, hashlib.sha224: 2,
hashlib.sha256: 3, hashlib.sha256: 3,
@@ -34,10 +40,10 @@ def commoncrypto_hashlib_to_crypto_map_get(hashfunc):
raise ValueError('Unkwnown digest %s' % hashfunc) raise ValueError('Unkwnown digest %s' % hashfunc)
return crypto_hashfunc return crypto_hashfunc
def commoncrypto_pbkdf2(data, salt, iterations, digest, keylen): def _commoncrypto_pbkdf2(data, salt, iterations, digest, keylen):
"""Common Crypto compatibile wrapper """Common Crypto compatibile wrapper
""" """
c_hashfunc = ctypes.c_uint32(commoncrypto_hashlib_to_crypto_map_get(digest)) c_hashfunc = ctypes.c_uint32(_commoncrypto_hashlib_to_crypto_map_get(digest))
c_pass = ctypes.c_char_p(data) c_pass = ctypes.c_char_p(data)
c_passlen = ctypes.c_size_t(len(data)) c_passlen = ctypes.c_size_t(len(data))
c_salt = ctypes.c_char_p(salt) c_salt = ctypes.c_char_p(salt)
@@ -66,7 +72,7 @@ def commoncrypto_pbkdf2(data, salt, iterations, digest, keylen):
return (1 - ret, c_buff) return (1 - ret, c_buff)
def openssl_hashlib_to_crypto_map_get(hashfunc): def _openssl_hashlib_to_crypto_map_get(hashfunc):
hashlib_to_crypto_map = {hashlib.md5: crypto.EVP_md5, hashlib_to_crypto_map = {hashlib.md5: crypto.EVP_md5,
hashlib.sha1: crypto.EVP_sha1, hashlib.sha1: crypto.EVP_sha1,
hashlib.sha256: crypto.EVP_sha256, hashlib.sha256: crypto.EVP_sha256,
@@ -79,11 +85,11 @@ def openssl_hashlib_to_crypto_map_get(hashfunc):
crypto_hashfunc.restype = ctypes.c_void_p crypto_hashfunc.restype = ctypes.c_void_p
return crypto_hashfunc() return crypto_hashfunc()
def openssl_pbkdf2(data, salt, iterations, digest, keylen): def _openssl_pbkdf2(data, salt, iterations, digest, keylen):
"""OpenSSL compatibile wrapper """OpenSSL compatibile wrapper
""" """
c_hashfunc = ctypes.c_void_p(openssl_hashlib_to_crypto_map_get(digest)) c_hashfunc = ctypes.c_void_p(_openssl_hashlib_to_crypto_map_get(digest))
c_pass = ctypes.c_char_p(data) c_pass = ctypes.c_char_p(data)
c_passlen = ctypes.c_int(len(data)) c_passlen = ctypes.c_int(len(data))
@@ -92,7 +98,7 @@ def openssl_pbkdf2(data, salt, iterations, digest, keylen):
c_iter = ctypes.c_int(iterations) c_iter = ctypes.c_int(iterations)
c_keylen = ctypes.c_int(keylen) c_keylen = ctypes.c_int(keylen)
c_buff = ctypes.create_string_buffer(keylen) c_buff = ctypes.create_string_buffer(keylen)
# PKCS5_PBKDF2_HMAC(const char *pass, int passlen, # PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
# const unsigned char *salt, int saltlen, int iter, # const unsigned char *salt, int saltlen, int iter,
# const EVP_MD *digest, # const EVP_MD *digest,
@@ -102,7 +108,7 @@ def openssl_pbkdf2(data, salt, iterations, digest, keylen):
ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int,
ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p,
ctypes.c_int, ctypes.c_char_p] ctypes.c_int, ctypes.c_char_p]
crypto.PKCS5_PBKDF2_HMAC.restype = ctypes.c_int crypto.PKCS5_PBKDF2_HMAC.restype = ctypes.c_int
err = crypto.PKCS5_PBKDF2_HMAC(c_pass, c_passlen, err = crypto.PKCS5_PBKDF2_HMAC(c_pass, c_passlen,
c_salt, c_saltlen, c_salt, c_saltlen,
@@ -119,36 +125,40 @@ try: # check that we have proper OpenSSL or Common Crypto on the system.
libname = ctypes.util.find_library('libeay64') libname = ctypes.util.find_library('libeay64')
if not libname: if not libname:
raise OSError('Library not found') raise OSError('Library not found')
crypto = ctypes.CDLL(os.path.basename(libname)) crypto = ctypes.CDLL(libname)
else: else:
libname = ctypes.util.find_library('libeay32') libname = ctypes.util.find_library('libeay32')
if not libname: if not libname:
raise OSError('Library not found') raise OSError('Library libeay32 not found.')
crypto = ctypes.CDLL(os.path.basename(libname)) crypto = ctypes.CDLL(libname)
_pbkdf2_hmac = openssl_pbkdf2 _pbkdf2_hmac = _openssl_pbkdf2
crypto.PKCS5_PBKDF2_HMAC # test compatibility crypto.PKCS5_PBKDF2_HMAC # test compatibility
elif system == 'Darwin': # think different(TM)! i.e. break things! elif system == 'Darwin': # think different(TM)! i.e. break things!
if [int(x) for x in platform.mac_ver()[0].split('.')] < [10, 7, 0]:
raise OSError('OS X Version too old %s < 10.7.0' % platform.mac_ver()[0])
libname = ctypes.util.find_library('System') libname = ctypes.util.find_library('System')
if not libname: if not libname:
raise OSError('Library not found') raise OSError('Library not found')
crypto = ctypes.CDLL(os.path.basename(libname)) crypto = ctypes.CDLL(os.path.basename(libname))
_pbkdf2_hmac = commoncrypto_pbkdf2 _pbkdf2_hmac = _commoncrypto_pbkdf2
else: else:
libname = ctypes.util.find_library('crypto') libname = ctypes.util.find_library('crypto')
if not libname: if not libname:
raise OSError('not found') raise OSError('Library crypto not found.')
crypto = ctypes.CDLL(os.path.basename(libname)) crypto = ctypes.CDLL(os.path.basename(libname))
_pbkdf2_hmac = openssl_pbkdf2 _pbkdf2_hmac = _openssl_pbkdf2
crypto.PKCS5_PBKDF2_HMAC # test compatibility crypto.PKCS5_PBKDF2_HMAC # test compatibility
except (OSError, AttributeError), e: except (OSError, AttributeError) as e:
raise ImportError('Cannot find a compatible cryptographic library ' raise ImportError('Cannot find a compatible cryptographic library '
'on your system') 'on your system. %s' % e)
def pkcs5_pbkdf2_hmac(data, salt, iterations=1000, keylen=24, hashfunc=None): def pkcs5_pbkdf2_hmac(data, salt, iterations=1000, keylen=24, hashfunc=None):
if hashfunc is None:
hashfunc = hashlib.sha1
err, c_buff = _pbkdf2_hmac(data, salt, iterations, hashfunc, keylen) err, c_buff = _pbkdf2_hmac(data, salt, iterations, hashfunc, keylen)
if err == 0: if err == 0:
@@ -157,8 +167,7 @@ def pkcs5_pbkdf2_hmac(data, salt, iterations=1000, keylen=24, hashfunc=None):
def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None): def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None):
return pkcs5_pbkdf2_hmac(data, salt, iterations, keylen, hashfunc).\ return binascii.hexlify(pkcs5_pbkdf2_hmac(data, salt, iterations, keylen, hashfunc))
encode('hex')
def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None): def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
@@ -167,10 +176,11 @@ def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
if __name__ == '__main__': if __name__ == '__main__':
try: try:
crypto.SSLeay_version.restype = ctypes.c_char_p crypto.SSLeay_version.restype = ctypes.c_char_p
print crypto.SSLeay_version(0) print(crypto.SSLeay_version(0))
except: except:
pass pass
for h in [hashlib.sha1, hashlib.sha224, hashlib.sha256, for h in [hashlib.sha1, hashlib.sha224, hashlib.sha256,
hashlib.sha384, hashlib.sha512]: hashlib.sha384, hashlib.sha512]:
print pkcs5_pbkdf2_hmac('secret' * 11, 'salt', hashfunc=h).encode('hex') print(binascii.hexlify(pkcs5_pbkdf2_hmac(b'secret' * 11, b'salt',
hashfunc=h)))