1 | # Test hashlib module
|
---|
2 | #
|
---|
3 | # $Id$
|
---|
4 | #
|
---|
5 | # Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org)
|
---|
6 | # Licensed to PSF under a Contributor Agreement.
|
---|
7 | #
|
---|
8 |
|
---|
9 | import array
|
---|
10 | import hashlib
|
---|
11 | import itertools
|
---|
12 | import sys
|
---|
13 | try:
|
---|
14 | import threading
|
---|
15 | except ImportError:
|
---|
16 | threading = None
|
---|
17 | import unittest
|
---|
18 | import warnings
|
---|
19 | from test import test_support
|
---|
20 | from test.test_support import _4G, precisionbigmemtest
|
---|
21 |
|
---|
22 | # Were we compiled --with-pydebug or with #define Py_DEBUG?
|
---|
23 | COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount')
|
---|
24 |
|
---|
25 |
|
---|
26 | def hexstr(s):
|
---|
27 | import string
|
---|
28 | h = string.hexdigits
|
---|
29 | r = ''
|
---|
30 | for c in s:
|
---|
31 | i = ord(c)
|
---|
32 | r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
|
---|
33 | return r
|
---|
34 |
|
---|
35 |
|
---|
36 | class HashLibTestCase(unittest.TestCase):
|
---|
37 | supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
|
---|
38 | 'sha224', 'SHA224', 'sha256', 'SHA256',
|
---|
39 | 'sha384', 'SHA384', 'sha512', 'SHA512' )
|
---|
40 |
|
---|
41 | _warn_on_extension_import = COMPILED_WITH_PYDEBUG
|
---|
42 |
|
---|
43 | def _conditional_import_module(self, module_name):
|
---|
44 | """Import a module and return a reference to it or None on failure."""
|
---|
45 | try:
|
---|
46 | exec('import '+module_name)
|
---|
47 | except ImportError, error:
|
---|
48 | if self._warn_on_extension_import:
|
---|
49 | warnings.warn('Did a C extension fail to compile? %s' % error)
|
---|
50 | return locals().get(module_name)
|
---|
51 |
|
---|
52 | def __init__(self, *args, **kwargs):
|
---|
53 | algorithms = set()
|
---|
54 | for algorithm in self.supported_hash_names:
|
---|
55 | algorithms.add(algorithm.lower())
|
---|
56 | self.constructors_to_test = {}
|
---|
57 | for algorithm in algorithms:
|
---|
58 | self.constructors_to_test[algorithm] = set()
|
---|
59 |
|
---|
60 | # For each algorithm, test the direct constructor and the use
|
---|
61 | # of hashlib.new given the algorithm name.
|
---|
62 | for algorithm, constructors in self.constructors_to_test.items():
|
---|
63 | constructors.add(getattr(hashlib, algorithm))
|
---|
64 | def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm):
|
---|
65 | if data is None:
|
---|
66 | return hashlib.new(_alg)
|
---|
67 | return hashlib.new(_alg, data)
|
---|
68 | constructors.add(_test_algorithm_via_hashlib_new)
|
---|
69 |
|
---|
70 | _hashlib = self._conditional_import_module('_hashlib')
|
---|
71 | if _hashlib:
|
---|
72 | # These two algorithms should always be present when this module
|
---|
73 | # is compiled. If not, something was compiled wrong.
|
---|
74 | assert hasattr(_hashlib, 'openssl_md5')
|
---|
75 | assert hasattr(_hashlib, 'openssl_sha1')
|
---|
76 | for algorithm, constructors in self.constructors_to_test.items():
|
---|
77 | constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
|
---|
78 | if constructor:
|
---|
79 | constructors.add(constructor)
|
---|
80 |
|
---|
81 | _md5 = self._conditional_import_module('_md5')
|
---|
82 | if _md5:
|
---|
83 | self.constructors_to_test['md5'].add(_md5.new)
|
---|
84 | _sha = self._conditional_import_module('_sha')
|
---|
85 | if _sha:
|
---|
86 | self.constructors_to_test['sha1'].add(_sha.new)
|
---|
87 | _sha256 = self._conditional_import_module('_sha256')
|
---|
88 | if _sha256:
|
---|
89 | self.constructors_to_test['sha224'].add(_sha256.sha224)
|
---|
90 | self.constructors_to_test['sha256'].add(_sha256.sha256)
|
---|
91 | _sha512 = self._conditional_import_module('_sha512')
|
---|
92 | if _sha512:
|
---|
93 | self.constructors_to_test['sha384'].add(_sha512.sha384)
|
---|
94 | self.constructors_to_test['sha512'].add(_sha512.sha512)
|
---|
95 |
|
---|
96 | super(HashLibTestCase, self).__init__(*args, **kwargs)
|
---|
97 |
|
---|
98 | def test_hash_array(self):
|
---|
99 | a = array.array("b", range(10))
|
---|
100 | constructors = self.constructors_to_test.itervalues()
|
---|
101 | for cons in itertools.chain.from_iterable(constructors):
|
---|
102 | c = cons(a)
|
---|
103 | c.hexdigest()
|
---|
104 |
|
---|
105 | def test_algorithms_attribute(self):
|
---|
106 | self.assertEqual(hashlib.algorithms,
|
---|
107 | tuple([_algo for _algo in self.supported_hash_names if
|
---|
108 | _algo.islower()]))
|
---|
109 |
|
---|
110 | def test_unknown_hash(self):
|
---|
111 | self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
|
---|
112 | self.assertRaises(TypeError, hashlib.new, 1)
|
---|
113 |
|
---|
114 | def test_get_builtin_constructor(self):
|
---|
115 | get_builtin_constructor = hashlib.__dict__[
|
---|
116 | '__get_builtin_constructor']
|
---|
117 | self.assertRaises(ValueError, get_builtin_constructor, 'test')
|
---|
118 | try:
|
---|
119 | import _md5
|
---|
120 | except ImportError:
|
---|
121 | pass
|
---|
122 | # This forces an ImportError for "import _md5" statements
|
---|
123 | sys.modules['_md5'] = None
|
---|
124 | try:
|
---|
125 | self.assertRaises(ValueError, get_builtin_constructor, 'md5')
|
---|
126 | finally:
|
---|
127 | if '_md5' in locals():
|
---|
128 | sys.modules['_md5'] = _md5
|
---|
129 | else:
|
---|
130 | del sys.modules['_md5']
|
---|
131 | self.assertRaises(TypeError, get_builtin_constructor, 3)
|
---|
132 |
|
---|
133 | def test_hexdigest(self):
|
---|
134 | for name in self.supported_hash_names:
|
---|
135 | h = hashlib.new(name)
|
---|
136 | self.assertTrue(hexstr(h.digest()) == h.hexdigest())
|
---|
137 |
|
---|
138 | def test_large_update(self):
|
---|
139 | aas = 'a' * 128
|
---|
140 | bees = 'b' * 127
|
---|
141 | cees = 'c' * 126
|
---|
142 | abcs = aas + bees + cees
|
---|
143 |
|
---|
144 | for name in self.supported_hash_names:
|
---|
145 | m1 = hashlib.new(name)
|
---|
146 | m1.update(aas)
|
---|
147 | m1.update(bees)
|
---|
148 | m1.update(cees)
|
---|
149 |
|
---|
150 | m2 = hashlib.new(name)
|
---|
151 | m2.update(abcs)
|
---|
152 | self.assertEqual(m1.digest(), m2.digest(), name+' update problem.')
|
---|
153 |
|
---|
154 | m3 = hashlib.new(name, abcs)
|
---|
155 | self.assertEqual(m1.digest(), m3.digest(), name+' new problem.')
|
---|
156 |
|
---|
157 | def check(self, name, data, digest):
|
---|
158 | constructors = self.constructors_to_test[name]
|
---|
159 | # 2 is for hashlib.name(...) and hashlib.new(name, ...)
|
---|
160 | self.assertGreaterEqual(len(constructors), 2)
|
---|
161 | for hash_object_constructor in constructors:
|
---|
162 | computed = hash_object_constructor(data).hexdigest()
|
---|
163 | self.assertEqual(
|
---|
164 | computed, digest,
|
---|
165 | "Hash algorithm %s constructed using %s returned hexdigest"
|
---|
166 | " %r for %d byte input data that should have hashed to %r."
|
---|
167 | % (name, hash_object_constructor,
|
---|
168 | computed, len(data), digest))
|
---|
169 |
|
---|
170 | def check_update(self, name, data, digest):
|
---|
171 | constructors = self.constructors_to_test[name]
|
---|
172 | # 2 is for hashlib.name(...) and hashlib.new(name, ...)
|
---|
173 | self.assertGreaterEqual(len(constructors), 2)
|
---|
174 | for hash_object_constructor in constructors:
|
---|
175 | h = hash_object_constructor()
|
---|
176 | h.update(data)
|
---|
177 | computed = h.hexdigest()
|
---|
178 | self.assertEqual(
|
---|
179 | computed, digest,
|
---|
180 | "Hash algorithm %s using %s when updated returned hexdigest"
|
---|
181 | " %r for %d byte input data that should have hashed to %r."
|
---|
182 | % (name, hash_object_constructor,
|
---|
183 | computed, len(data), digest))
|
---|
184 |
|
---|
185 | def check_unicode(self, algorithm_name):
|
---|
186 | # Unicode objects are not allowed as input.
|
---|
187 | expected = hashlib.new(algorithm_name, str(u'spam')).hexdigest()
|
---|
188 | self.check(algorithm_name, u'spam', expected)
|
---|
189 |
|
---|
190 | def test_unicode(self):
|
---|
191 | # In python 2.x unicode is auto-encoded to the system default encoding
|
---|
192 | # when passed to hashlib functions.
|
---|
193 | self.check_unicode('md5')
|
---|
194 | self.check_unicode('sha1')
|
---|
195 | self.check_unicode('sha224')
|
---|
196 | self.check_unicode('sha256')
|
---|
197 | self.check_unicode('sha384')
|
---|
198 | self.check_unicode('sha512')
|
---|
199 |
|
---|
200 | def test_case_md5_0(self):
|
---|
201 | self.check('md5', '', 'd41d8cd98f00b204e9800998ecf8427e')
|
---|
202 |
|
---|
203 | def test_case_md5_1(self):
|
---|
204 | self.check('md5', 'abc', '900150983cd24fb0d6963f7d28e17f72')
|
---|
205 |
|
---|
206 | def test_case_md5_2(self):
|
---|
207 | self.check('md5', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
---|
208 | 'd174ab98d277d9f5a5611c2c9f419d9f')
|
---|
209 |
|
---|
210 | @precisionbigmemtest(size=_4G + 5, memuse=1)
|
---|
211 | def test_case_md5_huge(self, size):
|
---|
212 | if size == _4G + 5:
|
---|
213 | try:
|
---|
214 | self.check('md5', 'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d')
|
---|
215 | except OverflowError:
|
---|
216 | pass # 32-bit arch
|
---|
217 |
|
---|
218 | @precisionbigmemtest(size=_4G + 5, memuse=1)
|
---|
219 | def test_case_md5_huge_update(self, size):
|
---|
220 | if size == _4G + 5:
|
---|
221 | try:
|
---|
222 | self.check_update('md5', 'A'*size,
|
---|
223 | 'c9af2dff37468ce5dfee8f2cfc0a9c6d')
|
---|
224 | except OverflowError:
|
---|
225 | pass # 32-bit arch
|
---|
226 |
|
---|
227 | @precisionbigmemtest(size=_4G - 1, memuse=1)
|
---|
228 | def test_case_md5_uintmax(self, size):
|
---|
229 | if size == _4G - 1:
|
---|
230 | try:
|
---|
231 | self.check('md5', 'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3')
|
---|
232 | except OverflowError:
|
---|
233 | pass # 32-bit arch
|
---|
234 |
|
---|
235 | # use the three examples from Federal Information Processing Standards
|
---|
236 | # Publication 180-1, Secure Hash Standard, 1995 April 17
|
---|
237 | # http://www.itl.nist.gov/div897/pubs/fip180-1.htm
|
---|
238 |
|
---|
239 | def test_case_sha1_0(self):
|
---|
240 | self.check('sha1', "",
|
---|
241 | "da39a3ee5e6b4b0d3255bfef95601890afd80709")
|
---|
242 |
|
---|
243 | def test_case_sha1_1(self):
|
---|
244 | self.check('sha1', "abc",
|
---|
245 | "a9993e364706816aba3e25717850c26c9cd0d89d")
|
---|
246 |
|
---|
247 | def test_case_sha1_2(self):
|
---|
248 | self.check('sha1', "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
---|
249 | "84983e441c3bd26ebaae4aa1f95129e5e54670f1")
|
---|
250 |
|
---|
251 | def test_case_sha1_3(self):
|
---|
252 | self.check('sha1', "a" * 1000000,
|
---|
253 | "34aa973cd4c4daa4f61eeb2bdbad27316534016f")
|
---|
254 |
|
---|
255 | @precisionbigmemtest(size=_4G + 5, memuse=1)
|
---|
256 | def test_case_sha1_huge(self, size):
|
---|
257 | if size == _4G + 5:
|
---|
258 | try:
|
---|
259 | self.check('sha1', 'A'*size,
|
---|
260 | '87d745c50e6b2879ffa0fb2c930e9fbfe0dc9a5b')
|
---|
261 | except OverflowError:
|
---|
262 | pass # 32-bit arch
|
---|
263 |
|
---|
264 | @precisionbigmemtest(size=_4G + 5, memuse=1)
|
---|
265 | def test_case_sha1_huge_update(self, size):
|
---|
266 | if size == _4G + 5:
|
---|
267 | try:
|
---|
268 | self.check_update('sha1', 'A'*size,
|
---|
269 | '87d745c50e6b2879ffa0fb2c930e9fbfe0dc9a5b')
|
---|
270 | except OverflowError:
|
---|
271 | pass # 32-bit arch
|
---|
272 |
|
---|
273 | # use the examples from Federal Information Processing Standards
|
---|
274 | # Publication 180-2, Secure Hash Standard, 2002 August 1
|
---|
275 | # http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
---|
276 |
|
---|
277 | def test_case_sha224_0(self):
|
---|
278 | self.check('sha224', "",
|
---|
279 | "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f")
|
---|
280 |
|
---|
281 | def test_case_sha224_1(self):
|
---|
282 | self.check('sha224', "abc",
|
---|
283 | "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7")
|
---|
284 |
|
---|
285 | def test_case_sha224_2(self):
|
---|
286 | self.check('sha224',
|
---|
287 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
---|
288 | "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525")
|
---|
289 |
|
---|
290 | def test_case_sha224_3(self):
|
---|
291 | self.check('sha224', "a" * 1000000,
|
---|
292 | "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67")
|
---|
293 |
|
---|
294 |
|
---|
295 | def test_case_sha256_0(self):
|
---|
296 | self.check('sha256', "",
|
---|
297 | "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
|
---|
298 |
|
---|
299 | def test_case_sha256_1(self):
|
---|
300 | self.check('sha256', "abc",
|
---|
301 | "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
|
---|
302 |
|
---|
303 | def test_case_sha256_2(self):
|
---|
304 | self.check('sha256',
|
---|
305 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
---|
306 | "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1")
|
---|
307 |
|
---|
308 | def test_case_sha256_3(self):
|
---|
309 | self.check('sha256', "a" * 1000000,
|
---|
310 | "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")
|
---|
311 |
|
---|
312 |
|
---|
313 | def test_case_sha384_0(self):
|
---|
314 | self.check('sha384', "",
|
---|
315 | "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da"+
|
---|
316 | "274edebfe76f65fbd51ad2f14898b95b")
|
---|
317 |
|
---|
318 | def test_case_sha384_1(self):
|
---|
319 | self.check('sha384', "abc",
|
---|
320 | "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"+
|
---|
321 | "8086072ba1e7cc2358baeca134c825a7")
|
---|
322 |
|
---|
323 | def test_case_sha384_2(self):
|
---|
324 | self.check('sha384',
|
---|
325 | "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+
|
---|
326 | "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
|
---|
327 | "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"+
|
---|
328 | "fcc7c71a557e2db966c3e9fa91746039")
|
---|
329 |
|
---|
330 | def test_case_sha384_3(self):
|
---|
331 | self.check('sha384', "a" * 1000000,
|
---|
332 | "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"+
|
---|
333 | "07b8b3dc38ecc4ebae97ddd87f3d8985")
|
---|
334 |
|
---|
335 |
|
---|
336 | def test_case_sha512_0(self):
|
---|
337 | self.check('sha512', "",
|
---|
338 | "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"+
|
---|
339 | "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
|
---|
340 |
|
---|
341 | def test_case_sha512_1(self):
|
---|
342 | self.check('sha512', "abc",
|
---|
343 | "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"+
|
---|
344 | "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")
|
---|
345 |
|
---|
346 | def test_case_sha512_2(self):
|
---|
347 | self.check('sha512',
|
---|
348 | "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+
|
---|
349 | "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
|
---|
350 | "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"+
|
---|
351 | "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909")
|
---|
352 |
|
---|
353 | def test_case_sha512_3(self):
|
---|
354 | self.check('sha512', "a" * 1000000,
|
---|
355 | "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+
|
---|
356 | "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")
|
---|
357 |
|
---|
358 | @unittest.skipUnless(threading, 'Threading required for this test.')
|
---|
359 | @test_support.reap_threads
|
---|
360 | def test_threaded_hashing(self):
|
---|
361 | # Updating the same hash object from several threads at once
|
---|
362 | # using data chunk sizes containing the same byte sequences.
|
---|
363 | #
|
---|
364 | # If the internal locks are working to prevent multiple
|
---|
365 | # updates on the same object from running at once, the resulting
|
---|
366 | # hash will be the same as doing it single threaded upfront.
|
---|
367 | hasher = hashlib.sha1()
|
---|
368 | num_threads = 5
|
---|
369 | smallest_data = 'swineflu'
|
---|
370 | data = smallest_data*200000
|
---|
371 | expected_hash = hashlib.sha1(data*num_threads).hexdigest()
|
---|
372 |
|
---|
373 | def hash_in_chunks(chunk_size, event):
|
---|
374 | index = 0
|
---|
375 | while index < len(data):
|
---|
376 | hasher.update(data[index:index+chunk_size])
|
---|
377 | index += chunk_size
|
---|
378 | event.set()
|
---|
379 |
|
---|
380 | events = []
|
---|
381 | for threadnum in xrange(num_threads):
|
---|
382 | chunk_size = len(data) // (10**threadnum)
|
---|
383 | assert chunk_size > 0
|
---|
384 | assert chunk_size % len(smallest_data) == 0
|
---|
385 | event = threading.Event()
|
---|
386 | events.append(event)
|
---|
387 | threading.Thread(target=hash_in_chunks,
|
---|
388 | args=(chunk_size, event)).start()
|
---|
389 |
|
---|
390 | for event in events:
|
---|
391 | event.wait()
|
---|
392 |
|
---|
393 | self.assertEqual(expected_hash, hasher.hexdigest())
|
---|
394 |
|
---|
395 | def test_main():
|
---|
396 | test_support.run_unittest(HashLibTestCase)
|
---|
397 |
|
---|
398 | if __name__ == "__main__":
|
---|
399 | test_main()
|
---|