Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(32152)

Delta Between Two Patch Sets: Lib/hashlib.py

Issue 16113: Add SHA-3 (Keccak) support
Left Patch Set: Created 7 years ago
Right Patch Set: Created 3 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Doc/library/hashlib.rst ('k') | Lib/test/test_hashlib.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org) 1 #. Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org)
2 # Licensed to PSF under a Contributor Agreement. 2 # Licensed to PSF under a Contributor Agreement.
3 # 3 #
4 4
5 __doc__ = """hashlib module - A common interface to many hash functions. 5 __doc__ = """hashlib module - A common interface to many hash functions.
6 6
7 new(name, data=b'') - returns a new hash object implementing the 7 new(name, data=b'') - returns a new hash object implementing the
8 given hash function; initializing the hash 8 given hash function; initializing the hash
9 using the given binary data. 9 using the given binary data.
10 10
11 Named constructor functions are also available, these are faster 11 Named constructor functions are also available, these are faster
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 More condensed: 48 More condensed:
49 49
50 >>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest() 50 >>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
51 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2' 51 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
52 52
53 """ 53 """
54 54
55 # This tuple and __get_builtin_constructor() must be modified if a new 55 # This tuple and __get_builtin_constructor() must be modified if a new
56 # always available algorithm is added. 56 # always available algorithm is added.
57 __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 57 __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
58 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512') 58 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
59 'shake_128', 'shake_256')
60
59 61
60 algorithms_guaranteed = set(__always_supported) 62 algorithms_guaranteed = set(__always_supported)
61 algorithms_available = set(__always_supported) 63 algorithms_available = set(__always_supported)
62 64
63 __all__ = __always_supported + ('new', 'algorithms_guaranteed', 65 __all__ = __always_supported + ('new', 'algorithms_guaranteed',
64 'algorithms_available') 66 'algorithms_available', 'pbkdf2_hmac')
65 67
68
69 __builtin_constructor_cache = {}
66 70
67 def __get_builtin_constructor(name): 71 def __get_builtin_constructor(name):
72 cache = __builtin_constructor_cache
73 constructor = cache.get(name)
74 if constructor is not None:
75 return constructor
68 try: 76 try:
69 if name in ('SHA1', 'sha1'): 77 if name in ('SHA1', 'sha1'):
70 import _sha1 78 import _sha1
71 return _sha1.sha1 79 cache['SHA1'] = cache['sha1'] = _sha1.sha1
72 elif name in ('MD5', 'md5'): 80 elif name in ('MD5', 'md5'):
73 import _md5 81 import _md5
74 return _md5.md5 82 cache['MD5'] = cache['md5'] = _md5.md5
75 elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): 83 elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'):
76 import _sha256 84 import _sha256
77 bs = name[3:] 85 cache['SHA224'] = cache['sha224'] = _sha256.sha224
78 if bs == '256': 86 cache['SHA256'] = cache['sha256'] = _sha256.sha256
79 return _sha256.sha256
80 elif bs == '224':
81 return _sha256.sha224
82 elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): 87 elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'):
83 import _sha512 88 import _sha512
84 bs = name[3:] 89 cache['SHA384'] = cache['sha384'] = _sha512.sha384
85 if bs == '512': 90 cache['SHA512'] = cache['sha512'] = _sha512.sha512
86 return _sha512.sha512
87 elif bs == '384':
88 return _sha512.sha384
89 elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', 91 elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
90 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512'}: 92 'shake_128', 'shake_256'}:
91 import _sha3 93 import _sha3
92 bs = name[5:] 94 cache['sha3_224'] = _sha3.sha3_224
93 if bs == '224': 95 cache['sha3_256'] = _sha3.sha3_256
94 return _sha3.sha3_224 96 cache['sha3_384'] = _sha3.sha3_384
95 elif bs == '256': 97 cache['sha3_512'] = _sha3.sha3_512
96 return _sha3.sha3_256 98 cache['shake_128'] = _sha3.shake_128
97 elif bs == '384': 99 cache['shake_256'] = _sha3.shake_256
98 return _sha3.sha3_384
99 elif bs == '512':
100 return _sha3.sha3_512
101 except ImportError: 100 except ImportError:
102 pass # no extension module, this hash is unsupported. 101 pass # no extension module, this hash is unsupported.
102
103 constructor = cache.get(name)
104 if constructor is not None:
105 return constructor
103 106
104 raise ValueError('unsupported hash type ' + name) 107 raise ValueError('unsupported hash type ' + name)
105 108
106 109
107 def __get_openssl_constructor(name): 110 def __get_openssl_constructor(name):
108 try: 111 try:
109 f = getattr(_hashlib, 'openssl_' + name) 112 f = getattr(_hashlib, 'openssl_' + name)
110 # Allow the C module to raise ValueError. The function will be 113 # Allow the C module to raise ValueError. The function will be
111 # defined but the hash not actually available thanks to OpenSSL. 114 # defined but the hash not actually available thanks to OpenSSL.
112 f() 115 f()
(...skipping 27 matching lines...) Expand all
140 try: 143 try:
141 import _hashlib 144 import _hashlib
142 new = __hash_new 145 new = __hash_new
143 __get_hash = __get_openssl_constructor 146 __get_hash = __get_openssl_constructor
144 algorithms_available = algorithms_available.union( 147 algorithms_available = algorithms_available.union(
145 _hashlib.openssl_md_meth_names) 148 _hashlib.openssl_md_meth_names)
146 except ImportError: 149 except ImportError:
147 new = __py_new 150 new = __py_new
148 __get_hash = __get_builtin_constructor 151 __get_hash = __get_builtin_constructor
149 152
153 try:
154 # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
155 from _hashlib import pbkdf2_hmac
156 except ImportError:
157 _trans_5C = bytes((x ^ 0x5C) for x in range(256))
158 _trans_36 = bytes((x ^ 0x36) for x in range(256))
159
160 def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
161 """Password based key derivation function 2 (PKCS #5 v2.0)
162
163 This Python implementations based on the hmac module about as fast
164 as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
165 for long passwords.
166 """
167 if not isinstance(hash_name, str):
168 raise TypeError(hash_name)
169
170 if not isinstance(password, (bytes, bytearray)):
171 password = bytes(memoryview(password))
172 if not isinstance(salt, (bytes, bytearray)):
173 salt = bytes(memoryview(salt))
174
175 # Fast inline HMAC implementation
176 inner = new(hash_name)
177 outer = new(hash_name)
178 blocksize = getattr(inner, 'block_size', 64)
179 if len(password) > blocksize:
180 password = new(hash_name, password).digest()
181 password = password + b'\x00' * (blocksize - len(password))
182 inner.update(password.translate(_trans_36))
183 outer.update(password.translate(_trans_5C))
184
185 def prf(msg, inner=inner, outer=outer):
186 # PBKDF2_HMAC uses the password as key. We can re-use the same
187 # digest objects and just update copies to skip initialization.
188 icpy = inner.copy()
189 ocpy = outer.copy()
190 icpy.update(msg)
191 ocpy.update(icpy.digest())
192 return ocpy.digest()
193
194 if iterations < 1:
195 raise ValueError(iterations)
196 if dklen is None:
197 dklen = outer.digest_size
198 if dklen < 1:
199 raise ValueError(dklen)
200
201 dkey = b''
202 loop = 1
203 from_bytes = int.from_bytes
204 while len(dkey) < dklen:
205 prev = prf(salt + loop.to_bytes(4, 'big'))
206 # endianess doesn't matter here as long to / from use the same
207 rkey = int.from_bytes(prev, 'big')
208 for i in range(iterations - 1):
209 prev = prf(prev)
210 # rkey = rkey ^ prev
211 rkey ^= from_bytes(prev, 'big')
212 loop += 1
213 dkey += rkey.to_bytes(inner.digest_size, 'big')
214
215 return dkey[:dklen]
216
217
150 for __func_name in __always_supported: 218 for __func_name in __always_supported:
151 # try them all, some may not work due to the OpenSSL 219 # try them all, some may not work due to the OpenSSL
152 # version not supporting that algorithm. 220 # version not supporting that algorithm.
153 try: 221 try:
154 globals()[__func_name] = __get_hash(__func_name) 222 globals()[__func_name] = __get_hash(__func_name)
155 except ValueError: 223 except ValueError:
156 import logging 224 import logging
157 logging.exception('code for hash %s was not found.', __func_name) 225 logging.exception('code for hash %s was not found.', __func_name)
158 226
227
159 # Cleanup locals() 228 # Cleanup locals()
160 del __always_supported, __func_name, __get_hash 229 del __always_supported, __func_name, __get_hash
161 del __py_new, __hash_new, __get_openssl_constructor 230 del __py_new, __hash_new, __get_openssl_constructor
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+