test_hashlib.py 13.2 KB
Newer Older
1 2 3 4
# Test hashlib module
#
# $Id$
#
5
#  Copyright (C) 2005-2010   Gregory P. Smith (greg@krypto.org)
6 7 8
#  Licensed to PSF under a Contributor Agreement.
#

9
import array
10
import hashlib
11
import itertools
12
import sys
13 14 15 16
try:
    import threading
except ImportError:
    threading = None
17
import unittest
18
import warnings
19
from test import support
20
from test.support import _4G, precisionbigmemtest
21

22 23 24 25
# Were we compiled --with-pydebug or with #define Py_DEBUG?
COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount')


26
def hexstr(s):
27
    assert isinstance(s, bytes), repr(s)
28 29
    h = "0123456789abcdef"
    r = ''
30
    for i in s:
31
        r += h[(i >> 4) & 0xF] + h[i & 0xF]
32 33 34 35 36 37 38 39
    return r


class HashLibTestCase(unittest.TestCase):
    supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
                             'sha224', 'SHA224', 'sha256', 'SHA256',
                             'sha384', 'SHA384', 'sha512', 'SHA512' )

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    _warn_on_extension_import = COMPILED_WITH_PYDEBUG

    def _conditional_import_module(self, module_name):
        """Import a module and return a reference to it or None on failure."""
        try:
            exec('import '+module_name)
        except ImportError as error:
            if self._warn_on_extension_import:
                warnings.warn('Did a C extension fail to compile? %s' % error)
        return locals().get(module_name)

    def __init__(self, *args, **kwargs):
        algorithms = set()
        for algorithm in self.supported_hash_names:
            algorithms.add(algorithm.lower())
        self.constructors_to_test = {}
        for algorithm in algorithms:
            self.constructors_to_test[algorithm] = set()

        # For each algorithm, test the direct constructor and the use
        # of hashlib.new given the algorithm name.
        for algorithm, constructors in self.constructors_to_test.items():
            constructors.add(getattr(hashlib, algorithm))
            def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm):
                if data is None:
                    return hashlib.new(_alg)
                return hashlib.new(_alg, data)
            constructors.add(_test_algorithm_via_hashlib_new)

        _hashlib = self._conditional_import_module('_hashlib')
        if _hashlib:
            # These two algorithms should always be present when this module
            # is compiled.  If not, something was compiled wrong.
            assert hasattr(_hashlib, 'openssl_md5')
            assert hasattr(_hashlib, 'openssl_sha1')
            for algorithm, constructors in self.constructors_to_test.items():
                constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
                if constructor:
                    constructors.add(constructor)

        _md5 = self._conditional_import_module('_md5')
        if _md5:
82 83 84 85
            self.constructors_to_test['md5'].add(_md5.md5)
        _sha1 = self._conditional_import_module('_sha1')
        if _sha1:
            self.constructors_to_test['sha1'].add(_sha1.sha1)
86 87 88 89 90 91 92 93 94 95 96
        _sha256 = self._conditional_import_module('_sha256')
        if _sha256:
            self.constructors_to_test['sha224'].add(_sha256.sha224)
            self.constructors_to_test['sha256'].add(_sha256.sha256)
        _sha512 = self._conditional_import_module('_sha512')
        if _sha512:
            self.constructors_to_test['sha384'].add(_sha512.sha384)
            self.constructors_to_test['sha512'].add(_sha512.sha512)

        super(HashLibTestCase, self).__init__(*args, **kwargs)

97 98 99 100 101 102 103
    def test_hash_array(self):
        a = array.array("b", range(10))
        constructors = self.constructors_to_test.values()
        for cons in itertools.chain.from_iterable(constructors):
            c = cons(a)
            c.hexdigest()

104 105
    def test_algorithms_guaranteed(self):
        self.assertEqual(hashlib.algorithms_guaranteed,
106
            set(_algo for _algo in self.supported_hash_names
107 108
                  if _algo.islower()))

109 110 111 112
    def test_algorithms_available(self):
        self.assertTrue(set(hashlib.algorithms_guaranteed).
                            issubset(hashlib.algorithms_available))

113 114 115 116 117 118
    def test_unknown_hash(self):
        try:
            hashlib.new('spam spam spam spam spam')
        except ValueError:
            pass
        else:
119
            self.assertTrue(0 == "hashlib didn't reject bogus hash name")
120 121 122 123

    def test_hexdigest(self):
        for name in self.supported_hash_names:
            h = hashlib.new(name)
124 125
            assert isinstance(h.digest(), bytes), name
            self.assertEqual(hexstr(h.digest()), h.hexdigest())
126 127 128


    def test_large_update(self):
129 130 131
        aas = b'a' * 128
        bees = b'b' * 127
        cees = b'c' * 126
132 133 134 135 136 137 138 139 140 141 142 143

        for name in self.supported_hash_names:
            m1 = hashlib.new(name)
            m1.update(aas)
            m1.update(bees)
            m1.update(cees)

            m2 = hashlib.new(name)
            m2.update(aas + bees + cees)
            self.assertEqual(m1.digest(), m2.digest())

    def check(self, name, data, digest):
144 145 146 147 148 149 150 151 152 153 154
        constructors = self.constructors_to_test[name]
        # 2 is for hashlib.name(...) and hashlib.new(name, ...)
        self.assertGreaterEqual(len(constructors), 2)
        for hash_object_constructor in constructors:
            computed = hash_object_constructor(data).hexdigest()
            self.assertEqual(
                    computed, digest,
                    "Hash algorithm %s constructed using %s returned hexdigest"
                    " %r for %d byte input data that should have hashed to %r."
                    % (name, hash_object_constructor,
                       computed, len(data), digest))
155

156 157
    def check_no_unicode(self, algorithm_name):
        # Unicode objects are not allowed as input.
158 159 160
        constructors = self.constructors_to_test[algorithm_name]
        for hash_object_constructor in constructors:
            self.assertRaises(TypeError, hash_object_constructor, 'spam')
161 162 163 164 165 166 167 168

    def test_no_unicode(self):
        self.check_no_unicode('md5')
        self.check_no_unicode('sha1')
        self.check_no_unicode('sha224')
        self.check_no_unicode('sha256')
        self.check_no_unicode('sha384')
        self.check_no_unicode('sha512')
169 170

    def test_case_md5_0(self):
171
        self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e')
172 173

    def test_case_md5_1(self):
174
        self.check('md5', b'abc', '900150983cd24fb0d6963f7d28e17f72')
175 176

    def test_case_md5_2(self):
177 178
        self.check('md5',
                   b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
179
                   'd174ab98d277d9f5a5611c2c9f419d9f')
180

181 182 183 184
    @precisionbigmemtest(size=_4G + 5, memuse=1)
    def test_case_md5_huge(self, size):
        if size == _4G + 5:
            try:
185
                self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d')
186 187 188 189 190 191 192
            except OverflowError:
                pass # 32-bit arch

    @precisionbigmemtest(size=_4G - 1, memuse=1)
    def test_case_md5_uintmax(self, size):
        if size == _4G - 1:
            try:
193
                self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3')
194 195
            except OverflowError:
                pass # 32-bit arch
196 197 198 199 200 201

    # use the three examples from Federal Information Processing Standards
    # Publication 180-1, Secure Hash Standard,  1995 April 17
    # http://www.itl.nist.gov/div897/pubs/fip180-1.htm

    def test_case_sha1_0(self):
202
        self.check('sha1', b"",
203
                   "da39a3ee5e6b4b0d3255bfef95601890afd80709")
204 205

    def test_case_sha1_1(self):
206
        self.check('sha1', b"abc",
207
                   "a9993e364706816aba3e25717850c26c9cd0d89d")
208 209

    def test_case_sha1_2(self):
210 211
        self.check('sha1',
                   b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
212
                   "84983e441c3bd26ebaae4aa1f95129e5e54670f1")
213 214

    def test_case_sha1_3(self):
215
        self.check('sha1', b"a" * 1000000,
216
                   "34aa973cd4c4daa4f61eeb2bdbad27316534016f")
217 218 219 220 221 222 223


    # use the examples from Federal Information Processing Standards
    # Publication 180-2, Secure Hash Standard,  2002 August 1
    # http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf

    def test_case_sha224_0(self):
224
        self.check('sha224', b"",
225 226 227
          "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f")

    def test_case_sha224_1(self):
228
        self.check('sha224', b"abc",
229 230 231 232
          "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7")

    def test_case_sha224_2(self):
        self.check('sha224',
233
          b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
234 235 236
          "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525")

    def test_case_sha224_3(self):
237
        self.check('sha224', b"a" * 1000000,
238 239 240 241
          "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67")


    def test_case_sha256_0(self):
242
        self.check('sha256', b"",
243 244 245
          "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")

    def test_case_sha256_1(self):
246
        self.check('sha256', b"abc",
247 248 249 250
          "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")

    def test_case_sha256_2(self):
        self.check('sha256',
251
          b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
252 253 254
          "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1")

    def test_case_sha256_3(self):
255
        self.check('sha256', b"a" * 1000000,
256 257 258 259
          "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")


    def test_case_sha384_0(self):
260
        self.check('sha384', b"",
261 262 263 264
          "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da"+
          "274edebfe76f65fbd51ad2f14898b95b")

    def test_case_sha384_1(self):
265
        self.check('sha384', b"abc",
266 267 268 269 270
          "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"+
          "8086072ba1e7cc2358baeca134c825a7")

    def test_case_sha384_2(self):
        self.check('sha384',
271 272
                   b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+
                   b"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
273 274 275 276
          "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"+
          "fcc7c71a557e2db966c3e9fa91746039")

    def test_case_sha384_3(self):
277
        self.check('sha384', b"a" * 1000000,
278 279 280 281 282
          "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"+
          "07b8b3dc38ecc4ebae97ddd87f3d8985")


    def test_case_sha512_0(self):
283
        self.check('sha512', b"",
284 285 286 287
          "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"+
          "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")

    def test_case_sha512_1(self):
288
        self.check('sha512', b"abc",
289 290 291 292 293
          "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"+
          "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")

    def test_case_sha512_2(self):
        self.check('sha512',
294 295
                   b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+
                   b"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
296 297 298 299
          "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"+
          "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909")

    def test_case_sha512_3(self):
300
        self.check('sha512', b"a" * 1000000,
301 302 303
          "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+
          "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")

304 305 306 307 308 309 310 311 312
    def test_gil(self):
        # Check things work fine with an input larger than the size required
        # for multithreaded operation (which is hardwired to 2048).
        gil_minsize = 2048

        m = hashlib.md5()
        m.update(b'1')
        m.update(b'#' * gil_minsize)
        m.update(b'1')
313
        self.assertEqual(m.hexdigest(), 'cb1e1a2cbc80be75e19935d621fb9b21')
314 315

        m = hashlib.md5(b'x' * gil_minsize)
316
        self.assertEqual(m.hexdigest(), 'cfb767f225d58469c5de3632a8803958')
317

318 319
    @unittest.skipUnless(threading, 'Threading required for this test.')
    @support.reap_threads
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
    def test_threaded_hashing(self):
        # Updating the same hash object from several threads at once
        # using data chunk sizes containing the same byte sequences.
        #
        # If the internal locks are working to prevent multiple
        # updates on the same object from running at once, the resulting
        # hash will be the same as doing it single threaded upfront.
        hasher = hashlib.sha1()
        num_threads = 5
        smallest_data = b'swineflu'
        data = smallest_data*200000
        expected_hash = hashlib.sha1(data*num_threads).hexdigest()

        def hash_in_chunks(chunk_size, event):
            index = 0
            while index < len(data):
                hasher.update(data[index:index+chunk_size])
                index += chunk_size
            event.set()

        events = []
        for threadnum in range(num_threads):
            chunk_size = len(data) // (10**threadnum)
            assert chunk_size > 0
            assert chunk_size % len(smallest_data) == 0
            event = threading.Event()
            events.append(event)
            threading.Thread(target=hash_in_chunks,
                             args=(chunk_size, event)).start()

        for event in events:
            event.wait()

        self.assertEqual(expected_hash, hasher.hexdigest())

355
def test_main():
356
    support.run_unittest(HashLibTestCase)
357 358 359

if __name__ == "__main__":
    test_main()