OILS / opy / _regtest / src / hashlib.py View on Github | oilshell.org

221 lines, 110 significant
1# $Id$
2#
3# Copyright (C) 2005 Gregory P. Smith (greg@krypto.org)
4# Licensed to PSF under a Contributor Agreement.
5#
6
7__doc__ = """hashlib module - A common interface to many hash functions.
8
9new(name, string='') - returns a new hash object implementing the
10 given hash function; initializing the hash
11 using the given string data.
12
13Named constructor functions are also available, these are much faster
14than using new():
15
16md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
17
18More algorithms may be available on your platform but the above are guaranteed
19to exist. See the algorithms_guaranteed and algorithms_available attributes
20to find out what algorithm names can be passed to new().
21
22NOTE: If you want the adler32 or crc32 hash functions they are available in
23the zlib module.
24
25Choose your hash function wisely. Some have known collision weaknesses.
26sha384 and sha512 will be slow on 32 bit platforms.
27
28Hash objects have these methods:
29 - update(arg): Update the hash object with the string arg. Repeated calls
30 are equivalent to a single call with the concatenation of all
31 the arguments.
32 - digest(): Return the digest of the strings passed to the update() method
33 so far. This may contain non-ASCII characters, including
34 NUL bytes.
35 - hexdigest(): Like digest() except the digest is returned as a string of
36 double length, containing only hexadecimal digits.
37 - copy(): Return a copy (clone) of the hash object. This can be used to
38 efficiently compute the digests of strings that share a common
39 initial substring.
40
41For example, to obtain the digest of the string 'Nobody inspects the
42spammish repetition':
43
44 >>> import hashlib
45 >>> m = hashlib.md5()
46 >>> m.update("Nobody inspects")
47 >>> m.update(" the spammish repetition")
48 >>> m.digest()
49 '\\xbbd\\x9c\\x83\\xdd\\x1e\\xa5\\xc9\\xd9\\xde\\xc9\\xa1\\x8d\\xf0\\xff\\xe9'
50
51More condensed:
52
53 >>> hashlib.sha224("Nobody inspects the spammish repetition").hexdigest()
54 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
55
56"""
57
58# This tuple and __get_builtin_constructor() must be modified if a new
59# always available algorithm is added.
60__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
61
62algorithms_guaranteed = set(__always_supported)
63algorithms_available = set(__always_supported)
64
65algorithms = __always_supported
66
67__all__ = __always_supported + ('new', 'algorithms_guaranteed',
68 'algorithms_available', 'algorithms',
69 'pbkdf2_hmac')
70
71
72def __get_builtin_constructor(name):
73 try:
74 if name in ('SHA1', 'sha1'):
75 import _sha
76 return _sha.new
77 elif name in ('MD5', 'md5'):
78 import _md5
79 return _md5.new
80 elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'):
81 import _sha256
82 bs = name[3:]
83 if bs == '256':
84 return _sha256.sha256
85 elif bs == '224':
86 return _sha256.sha224
87 elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'):
88 import _sha512
89 bs = name[3:]
90 if bs == '512':
91 return _sha512.sha512
92 elif bs == '384':
93 return _sha512.sha384
94 except ImportError:
95 pass # no extension module, this hash is unsupported.
96
97 raise ValueError('unsupported hash type ' + name)
98
99
100def __get_openssl_constructor(name):
101 try:
102 f = getattr(_hashlib, 'openssl_' + name)
103 # Allow the C module to raise ValueError. The function will be
104 # defined but the hash not actually available thanks to OpenSSL.
105 f()
106 # Use the C function directly (very fast)
107 return f
108 except (AttributeError, ValueError):
109 return __get_builtin_constructor(name)
110
111
112def __py_new(name, string=''):
113 """new(name, string='') - Return a new hashing object using the named algorithm;
114 optionally initialized with a string.
115 """
116 return __get_builtin_constructor(name)(string)
117
118
119def __hash_new(name, string=''):
120 """new(name, string='') - Return a new hashing object using the named algorithm;
121 optionally initialized with a string.
122 """
123 try:
124 return _hashlib.new(name, string)
125 except ValueError:
126 # If the _hashlib module (OpenSSL) doesn't support the named
127 # hash, try using our builtin implementations.
128 # This allows for SHA224/256 and SHA384/512 support even though
129 # the OpenSSL library prior to 0.9.8 doesn't provide them.
130 return __get_builtin_constructor(name)(string)
131
132
133try:
134 import _hashlib
135 new = __hash_new
136 __get_hash = __get_openssl_constructor
137 algorithms_available = algorithms_available.union(
138 _hashlib.openssl_md_meth_names)
139except ImportError:
140 new = __py_new
141 __get_hash = __get_builtin_constructor
142
143for __func_name in __always_supported:
144 # try them all, some may not work due to the OpenSSL
145 # version not supporting that algorithm.
146 try:
147 globals()[__func_name] = __get_hash(__func_name)
148 except ValueError:
149 import logging
150 logging.exception('code for hash %s was not found.', __func_name)
151
152
153try:
154 # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
155 from _hashlib import pbkdf2_hmac
156except ImportError:
157 import binascii
158 import struct
159
160 _trans_5C = b"".join(chr(x ^ 0x5C) for x in range(256))
161 _trans_36 = b"".join(chr(x ^ 0x36) for x in range(256))
162
163 def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
164 """Password based key derivation function 2 (PKCS #5 v2.0)
165
166 This Python implementations based on the hmac module about as fast
167 as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
168 for long passwords.
169 """
170 if not isinstance(hash_name, str):
171 raise TypeError(hash_name)
172
173 if not isinstance(password, (bytes, bytearray)):
174 password = bytes(buffer(password))
175 if not isinstance(salt, (bytes, bytearray)):
176 salt = bytes(buffer(salt))
177
178 # Fast inline HMAC implementation
179 inner = new(hash_name)
180 outer = new(hash_name)
181 blocksize = getattr(inner, 'block_size', 64)
182 if len(password) > blocksize:
183 password = new(hash_name, password).digest()
184 password = password + b'\x00' * (blocksize - len(password))
185 inner.update(password.translate(_trans_36))
186 outer.update(password.translate(_trans_5C))
187
188 def prf(msg, inner=inner, outer=outer):
189 # PBKDF2_HMAC uses the password as key. We can re-use the same
190 # digest objects and just update copies to skip initialization.
191 icpy = inner.copy()
192 ocpy = outer.copy()
193 icpy.update(msg)
194 ocpy.update(icpy.digest())
195 return ocpy.digest()
196
197 if iterations < 1:
198 raise ValueError(iterations)
199 if dklen is None:
200 dklen = outer.digest_size
201 if dklen < 1:
202 raise ValueError(dklen)
203
204 hex_format_string = "%%0%ix" % (new(hash_name).digest_size * 2)
205
206 dkey = b''
207 loop = 1
208 while len(dkey) < dklen:
209 prev = prf(salt + struct.pack(b'>I', loop))
210 rkey = int(binascii.hexlify(prev), 16)
211 for i in xrange(iterations - 1):
212 prev = prf(prev)
213 rkey ^= int(binascii.hexlify(prev), 16)
214 loop += 1
215 dkey += binascii.unhexlify(hex_format_string % rkey)
216
217 return dkey[:dklen]
218
219# Cleanup locals()
220del __always_supported, __func_name, __get_hash
221del __py_new, __hash_new, __get_openssl_constructor