5454
5555"""
5656
57+ # This tuple and __get_builtin_constructor() must be modified if a new
58+ # always available algorithm is added.
59+ __always_supported = ('md5' , 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512' )
60+
61+ __all__ = __always_supported + ('new' ,)
62+
5763
5864def __get_builtin_constructor (name ):
5965 if name in ('SHA1' , 'sha1' ):
@@ -77,7 +83,19 @@ def __get_builtin_constructor(name):
7783 elif bs == '384' :
7884 return _sha512 .sha384
7985
80- raise ValueError , "unsupported hash type"
86+ raise ValueError ('unsupported hash type %s' % name )
87+
88+
89+ def __get_openssl_constructor (name ):
90+ try :
91+ f = getattr (_hashlib , 'openssl_' + name )
92+ # Allow the C module to raise ValueError. The function will be
93+ # defined but the hash not actually available thanks to OpenSSL.
94+ f ()
95+ # Use the C function directly (very fast)
96+ return f
97+ except (AttributeError , ValueError ):
98+ return __get_builtin_constructor (name )
8199
82100
83101def __py_new (name , string = '' ):
@@ -103,39 +121,21 @@ def __hash_new(name, string=''):
103121
104122try :
105123 import _hashlib
106- # use the wrapper of the C implementation
107124 new = __hash_new
108-
109- for opensslFuncName in filter (lambda n : n .startswith ('openssl_' ), dir (_hashlib )):
110- funcName = opensslFuncName [len ('openssl_' ):]
111- try :
112- # try them all, some may not work due to the OpenSSL
113- # version not supporting that algorithm.
114- f = getattr (_hashlib , opensslFuncName )
115- f ()
116- # Use the C function directly (very fast)
117- exec funcName + ' = f'
118- except ValueError :
119- try :
120- # Use the builtin implementation directly (fast)
121- exec funcName + ' = __get_builtin_constructor(funcName)'
122- except ValueError :
123- # this one has no builtin implementation, don't define it
124- pass
125- # clean up our locals
126- del f
127- del opensslFuncName
128- del funcName
129-
125+ __get_hash = __get_openssl_constructor
130126except ImportError :
131- # We don't have the _hashlib OpenSSL module?
132- # use the built in legacy interfaces via a wrapper function
133127 new = __py_new
128+ __get_hash = __get_builtin_constructor
129+
130+ for __func_name in __always_supported :
131+ # try them all, some may not work due to the OpenSSL
132+ # version not supporting that algorithm.
133+ try :
134+ globals ()[__func_name ] = __get_hash (__func_name )
135+ except ValueError :
136+ import logging
137+ logging .exception ('code for hash %s was not found.' , __func_name )
134138
135- # lookup the C function to use directly for the named constructors
136- md5 = __get_builtin_constructor ('md5' )
137- sha1 = __get_builtin_constructor ('sha1' )
138- sha224 = __get_builtin_constructor ('sha224' )
139- sha256 = __get_builtin_constructor ('sha256' )
140- sha384 = __get_builtin_constructor ('sha384' )
141- sha512 = __get_builtin_constructor ('sha512' )
139+ # Cleanup locals()
140+ del __always_supported , __func_name , __get_hash
141+ del __py_new , __hash_new , __get_openssl_constructor
0 commit comments