From eb2c0e6ca158d286eada3e99ccbfef39c0e5f930 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 1 Aug 2013 08:23:24 -0500 Subject: [PATCH] added better handling of missing library, thanks Michele --- VERSION | 2 +- gluon/contrib/pbkdf2_ctypes.py | 95 ++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/VERSION b/VERSION index 666e55b6..ca9652d7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.6.0-development+timestamp.2013.08.01.02.48.50 +Version 2.6.0-development+timestamp.2013.08.01.08.22.32 diff --git a/gluon/contrib/pbkdf2_ctypes.py b/gluon/contrib/pbkdf2_ctypes.py index cb220f6e..1e7d8a9d 100644 --- a/gluon/contrib/pbkdf2_ctypes.py +++ b/gluon/contrib/pbkdf2_ctypes.py @@ -23,7 +23,62 @@ import hashlib import platform import os.path -try: # check that we have proper OpenSSL on the system. +def commoncrypto_hashlib_to_crypto_map_get(hashfunc): + hashlib_to_crypto_map = {hashlib.sha1: 1, + hashlib.sha224: 2, + hashlib.sha256: 3, + hashlib.sha384: 4, + hashlib.sha512: 5} + crypto_hashfunc = hashlib_to_crypto_map.get(hashfunc) + if crypto_hashfunc is None: + raise ValueError('Unkwnown digest %s' % hashfunc) + return crypto_hashfunc + +def commoncrypto_pbkdf2(c_pass, c_passlen, + c_salt, c_saltlen, + c_iter, digest, c_keylen, c_buff): + """Common Crypto compatibile wrapper + """ + c_hashfunc = ctypes.c_int(commoncrypto_hashlib_to_crypto_map_get(digest)) + + return 1 - crypto.CCKeyDerivationPBKDF(2, # hardcoded 2-> PBKDF2 + c_pass, c_passlen, + c_salt, c_saltlen, + c_hashfunc, + c_iter, + c_buff, + c_keylen) + + +def openssl_hashlib_to_crypto_map_get(hashfunc): + 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} + crypto_hashfunc = hashlib_to_crypto_map.get(hashfunc) + if crypto_hashfunc is None: + raise ValueError('Unkwnown digest %s' % hashfunc) + crypto_hashfunc.restype = ctypes.c_void_p + return crypto_hashfunc() + + +def openssl_pbkdf2(c_pass, c_passlen, + c_salt, c_saltlen, + c_iter, digest, c_keylen, c_buff): + """OpenSSL compatibile wrapper + """ + c_hashfunc = ctypes.c_void_p(openssl_hashlib_to_crypto_map_get(digest)) + + return crypto.PKCS5_PBKDF2_HMAC(c_pass, c_passlen, + c_salt, c_saltlen, + c_iter, + c_hashfunc, + c_keylen, + c_buff) + +try: # check that we have proper OpenSSL or Common Crypto on the system. system = platform.system() if system == 'Windows': if platform.architecture()[0] == '64bit': @@ -32,18 +87,16 @@ try: # check that we have proper OpenSSL on the system. else: crypto = ctypes.CDLL(os.path.basename( ctypes.util.find_library('libeay32'))) + _pbkdf2_hmac = openssl_pbkdf2 + crypto.PKCS5_PBKDF2_HMAC # test compatibility + elif system == 'Darwin': # think different(TM)! i.e. break things! + raise ImportError('Not yet available on OS X') else: crypto = ctypes.CDLL(os.path.basename( ctypes.util.find_library('crypto'))) + _pbkdf2_hmac = openssl_pbkdf2 + crypto.PKCS5_PBKDF2_HMAC # test compatibility - 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), e: raise ImportError('Cannot find a compatible OpenSSL installation ' 'on your system') @@ -56,20 +109,11 @@ def pkcs5_pbkdf2_hmac(data, salt, iterations=1000, keylen=24, hashfunc=None): 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) - err = PKCS5_PBKDF2_HMAC(c_pass, c_passlen, + err = _pbkdf2_hmac(c_pass, c_passlen, c_salt, c_saltlen, c_iter, - c_digest, + hashfunc, c_keylen, c_buff) @@ -87,7 +131,12 @@ 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: + try: + crypto.SSLeay_version.restype = ctypes.c_char_p + print crypto.SSLeay_version(0) + except: + print "Not using OpenSSL" + + for h in [hashlib.sha1, hashlib.sha224, hashlib.sha256, + hashlib.sha384, hashlib.sha512]: pkcs5_pbkdf2_hmac('secret' * 11, 'salt', hashfunc=h)