diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/hashlib.py | 17 | ||||
-rw-r--r-- | Lib/test/test_hashlib.py | 157 |
2 files changed, 156 insertions, 18 deletions
diff --git a/Lib/hashlib.py b/Lib/hashlib.py index 2d5e92e..053a7ad 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -11,7 +11,8 @@ new(name, data=b'', **kwargs) - returns a new hash object implementing the Named constructor functions are also available, these are faster than using new(name): -md5(), sha1(), sha224(), sha256(), sha384(), sha512(), blake2b(), and blake2s() +md5(), sha1(), sha224(), sha256(), sha384(), sha512(), blake2b(), blake2s(), +sha3_224, sha3_256, sha3_384, sha3_512, shake_128, and shake_256. More algorithms may be available on your platform but the above are guaranteed to exist. See the algorithms_guaranteed and algorithms_available attributes @@ -55,7 +56,10 @@ More condensed: # This tuple and __get_builtin_constructor() must be modified if a new # always available algorithm is added. __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', - 'blake2b', 'blake2s') + 'blake2b', 'blake2s', + 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', + 'shake_128', 'shake_256') + algorithms_guaranteed = set(__always_supported) algorithms_available = set(__always_supported) @@ -90,6 +94,15 @@ def __get_builtin_constructor(name): import _blake2 cache['blake2b'] = _blake2.blake2b cache['blake2s'] = _blake2.blake2s + elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', + 'shake_128', 'shake_256'}: + import _sha3 + cache['sha3_224'] = _sha3.sha3_224 + cache['sha3_256'] = _sha3.sha3_256 + cache['sha3_384'] = _sha3.sha3_384 + cache['sha3_512'] = _sha3.sha3_512 + cache['shake_128'] = _sha3.shake_128 + cache['shake_256'] = _sha3.shake_256 except ImportError: pass # no extension module, this hash is unsupported. diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index e94fc3f..21260f6 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -34,6 +34,13 @@ except ImportError: requires_blake2 = unittest.skipUnless(_blake2, 'requires _blake2') +try: + import _sha3 +except ImportError: + _sha3 = None + +requires_sha3 = unittest.skipUnless(_sha3, 'requires _sha3') + def hexstr(s): assert isinstance(s, bytes), repr(s) @@ -61,7 +68,11 @@ class HashLibTestCase(unittest.TestCase): supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', 'sha224', 'SHA224', 'sha256', 'SHA256', 'sha384', 'SHA384', 'sha512', 'SHA512', - 'blake2b', 'blake2s') + 'blake2b', 'blake2s', + 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', + 'shake_128', 'shake_256') + + shakes = {'shake_128', 'shake_256'} # Issue #14693: fallback modules are always compiled under POSIX _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG @@ -131,6 +142,15 @@ class HashLibTestCase(unittest.TestCase): add_builtin_constructor('blake2s') add_builtin_constructor('blake2b') + _sha3 = self._conditional_import_module('_sha3') + if _sha3: + add_builtin_constructor('sha3_224') + add_builtin_constructor('sha3_256') + add_builtin_constructor('sha3_384') + add_builtin_constructor('sha3_512') + add_builtin_constructor('shake_128') + add_builtin_constructor('shake_256') + super(HashLibTestCase, self).__init__(*args, **kwargs) @property @@ -142,7 +162,10 @@ class HashLibTestCase(unittest.TestCase): a = array.array("b", range(10)) for cons in self.hash_constructors: c = cons(a) - c.hexdigest() + if c.name in self.shakes: + c.hexdigest(16) + else: + c.hexdigest() def test_algorithms_guaranteed(self): self.assertEqual(hashlib.algorithms_guaranteed, @@ -186,14 +209,21 @@ class HashLibTestCase(unittest.TestCase): def test_hexdigest(self): for cons in self.hash_constructors: h = cons() - self.assertIsInstance(h.digest(), bytes) - self.assertEqual(hexstr(h.digest()), h.hexdigest()) + if h.name in self.shakes: + self.assertIsInstance(h.digest(16), bytes) + self.assertEqual(hexstr(h.digest(16)), h.hexdigest(16)) + else: + self.assertIsInstance(h.digest(), bytes) + self.assertEqual(hexstr(h.digest()), h.hexdigest()) def test_name_attribute(self): for cons in self.hash_constructors: h = cons() self.assertIsInstance(h.name, str) - self.assertIn(h.name, self.supported_hash_names) + if h.name in self.supported_hash_names: + self.assertIn(h.name, self.supported_hash_names) + else: + self.assertNotIn(h.name, self.supported_hash_names) self.assertEqual(h.name, hashlib.new(h.name).name) def test_large_update(self): @@ -208,40 +238,46 @@ class HashLibTestCase(unittest.TestCase): m1.update(bees) m1.update(cees) m1.update(dees) + if m1.name in self.shakes: + args = (16,) + else: + args = () m2 = cons() m2.update(aas + bees + cees + dees) - self.assertEqual(m1.digest(), m2.digest()) + self.assertEqual(m1.digest(*args), m2.digest(*args)) m3 = cons(aas + bees + cees + dees) - self.assertEqual(m1.digest(), m3.digest()) + self.assertEqual(m1.digest(*args), m3.digest(*args)) # verify copy() doesn't touch original m4 = cons(aas + bees + cees) - m4_digest = m4.digest() + m4_digest = m4.digest(*args) m4_copy = m4.copy() m4_copy.update(dees) - self.assertEqual(m1.digest(), m4_copy.digest()) - self.assertEqual(m4.digest(), m4_digest) + self.assertEqual(m1.digest(*args), m4_copy.digest(*args)) + self.assertEqual(m4.digest(*args), m4_digest) - def check(self, name, data, hexdigest, **kwargs): + def check(self, name, data, hexdigest, shake=False, **kwargs): + length = len(hexdigest)//2 hexdigest = hexdigest.lower() 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: m = hash_object_constructor(data, **kwargs) - computed = m.hexdigest() + computed = m.hexdigest() if not shake else m.hexdigest(length) self.assertEqual( computed, hexdigest, "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), hexdigest)) - computed = m.digest() + computed = m.digest() if not shake else m.digest(length) digest = bytes.fromhex(hexdigest) self.assertEqual(computed, digest) - self.assertEqual(len(digest), m.digest_size) + if not shake: + self.assertEqual(len(digest), m.digest_size) def check_no_unicode(self, algorithm_name): # Unicode objects are not allowed as input. @@ -262,13 +298,30 @@ class HashLibTestCase(unittest.TestCase): self.check_no_unicode('blake2b') self.check_no_unicode('blake2s') - def check_blocksize_name(self, name, block_size=0, digest_size=0): + @requires_sha3 + def test_no_unicode_sha3(self): + self.check_no_unicode('sha3_224') + self.check_no_unicode('sha3_256') + self.check_no_unicode('sha3_384') + self.check_no_unicode('sha3_512') + self.check_no_unicode('shake_128') + self.check_no_unicode('shake_256') + + def check_blocksize_name(self, name, block_size=0, digest_size=0, + digest_length=None): constructors = self.constructors_to_test[name] for hash_object_constructor in constructors: m = hash_object_constructor() self.assertEqual(m.block_size, block_size) self.assertEqual(m.digest_size, digest_size) - self.assertEqual(len(m.digest()), digest_size) + if digest_length: + self.assertEqual(len(m.digest(digest_length)), + digest_length) + self.assertEqual(len(m.hexdigest(digest_length)), + 2*digest_length) + else: + self.assertEqual(len(m.digest()), digest_size) + self.assertEqual(len(m.hexdigest()), 2*digest_size) self.assertEqual(m.name, name) # split for sha3_512 / _sha3.sha3 object self.assertIn(name.split("_")[0], repr(m)) @@ -280,6 +333,12 @@ class HashLibTestCase(unittest.TestCase): self.check_blocksize_name('sha256', 64, 32) self.check_blocksize_name('sha384', 128, 48) self.check_blocksize_name('sha512', 128, 64) + self.check_blocksize_name('sha3_224', 144, 28) + self.check_blocksize_name('sha3_256', 136, 32) + self.check_blocksize_name('sha3_384', 104, 48) + self.check_blocksize_name('sha3_512', 72, 64) + self.check_blocksize_name('shake_128', 168, 0, 32) + self.check_blocksize_name('shake_256', 136, 0, 64) @requires_blake2 def test_blocksize_name_blake2(self): @@ -563,6 +622,72 @@ class HashLibTestCase(unittest.TestCase): key = bytes.fromhex(key) self.check('blake2s', msg, md, key=key) + @requires_sha3 + def test_case_sha3_224_0(self): + self.check('sha3_224', b"", + "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7") + + @requires_sha3 + def test_case_sha3_224_vector(self): + for msg, md in read_vectors('sha3_224'): + self.check('sha3_224', msg, md) + + @requires_sha3 + def test_case_sha3_256_0(self): + self.check('sha3_256', b"", + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a") + + @requires_sha3 + def test_case_sha3_256_vector(self): + for msg, md in read_vectors('sha3_256'): + self.check('sha3_256', msg, md) + + @requires_sha3 + def test_case_sha3_384_0(self): + self.check('sha3_384', b"", + "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a"+ + "c3713831264adb47fb6bd1e058d5f004") + + @requires_sha3 + def test_case_sha3_384_vector(self): + for msg, md in read_vectors('sha3_384'): + self.check('sha3_384', msg, md) + + @requires_sha3 + def test_case_sha3_512_0(self): + self.check('sha3_512', b"", + "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6"+ + "15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26") + + @requires_sha3 + def test_case_sha3_512_vector(self): + for msg, md in read_vectors('sha3_512'): + self.check('sha3_512', msg, md) + + @requires_sha3 + def test_case_shake_128_0(self): + self.check('shake_128', b"", + "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26", + True) + self.check('shake_128', b"", "7f9c", True) + + @requires_sha3 + def test_case_shake128_vector(self): + for msg, md in read_vectors('shake_128'): + self.check('shake_128', msg, md, True) + + @requires_sha3 + def test_case_shake_256_0(self): + self.check('shake_256', b"", + "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", + True) + self.check('shake_256', b"", "46b9", True) + + @requires_sha3 + def test_case_shake256_vector(self): + for msg, md in read_vectors('shake_256'): + self.check('shake_256', msg, md, True) + def test_gil(self): # Check things work fine with an input larger than the size required # for multithreaded operation (which is hardwired to 2048). |