Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6fe2a75

Browse files
committed
Issue #16113: Add SHA-3 and SHAKE support to hashlib module.
1 parent dfb9ef1 commit 6fe2a75

26 files changed

Lines changed: 6495 additions & 19 deletions

Doc/library/hashlib.rst

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,13 @@ Constructors for hash algorithms that are always present in this module are
6969
:func:`md5` is normally available as well, though it
7070
may be missing if you are using a rare "FIPS compliant" build of Python.
7171
Additional algorithms may also be available depending upon the OpenSSL
72-
library that Python uses on your platform.
72+
library that Python uses on your platform. On most platforms the
73+
:func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, :func:`sha3_512`,
74+
:func:`shake_128`, :func:`shake_256` are also available.
75+
76+
.. versionadded:: 3.6
77+
SHA3 (Keccak) and SHAKE constructors :func:`sha3_224`, :func:`sha3_256`,
78+
:func:`sha3_384`, :func:`sha3_512`, :func:`shake_128`, :func:`shake_256`.
7379

7480
.. versionadded:: 3.6
7581
:func:`blake2b` and :func:`blake2s` were added.
@@ -189,6 +195,28 @@ A hash object has the following methods:
189195
compute the digests of data sharing a common initial substring.
190196

191197

198+
SHAKE variable length digests
199+
-----------------------------
200+
201+
The :func:`shake_128` and :func:`shake_256` algorithms provide variable
202+
length digests with length_in_bits//2 up to 128 or 256 bits of security.
203+
As such, their digest methods require a length. Maximum length is not limited
204+
by the SHAKE algorithm.
205+
206+
.. method:: shake.digest(length)
207+
208+
Return the digest of the data passed to the :meth:`update` method so far.
209+
This is a bytes object of size ``length`` which may contain bytes in
210+
the whole range from 0 to 255.
211+
212+
213+
.. method:: shake.hexdigest(length)
214+
215+
Like :meth:`digest` except the digest is returned as a string object of
216+
double length, containing only hexadecimal digits. This may be used to
217+
exchange the value safely in email or other non-binary environments.
218+
219+
192220
Key derivation
193221
--------------
194222

Lib/hashlib.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
Named constructor functions are also available, these are faster
1212
than using new(name):
1313
14-
md5(), sha1(), sha224(), sha256(), sha384(), sha512(), blake2b(), and blake2s()
14+
md5(), sha1(), sha224(), sha256(), sha384(), sha512(), blake2b(), blake2s(),
15+
sha3_224, sha3_256, sha3_384, sha3_512, shake_128, and shake_256.
1516
1617
More algorithms may be available on your platform but the above are guaranteed
1718
to exist. See the algorithms_guaranteed and algorithms_available attributes
@@ -55,7 +56,10 @@
5556
# This tuple and __get_builtin_constructor() must be modified if a new
5657
# always available algorithm is added.
5758
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
58-
'blake2b', 'blake2s')
59+
'blake2b', 'blake2s',
60+
'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
61+
'shake_128', 'shake_256')
62+
5963

6064
algorithms_guaranteed = set(__always_supported)
6165
algorithms_available = set(__always_supported)
@@ -90,6 +94,15 @@ def __get_builtin_constructor(name):
9094
import _blake2
9195
cache['blake2b'] = _blake2.blake2b
9296
cache['blake2s'] = _blake2.blake2s
97+
elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
98+
'shake_128', 'shake_256'}:
99+
import _sha3
100+
cache['sha3_224'] = _sha3.sha3_224
101+
cache['sha3_256'] = _sha3.sha3_256
102+
cache['sha3_384'] = _sha3.sha3_384
103+
cache['sha3_512'] = _sha3.sha3_512
104+
cache['shake_128'] = _sha3.shake_128
105+
cache['shake_256'] = _sha3.shake_256
93106
except ImportError:
94107
pass # no extension module, this hash is unsupported.
95108

Lib/test/test_hashlib.py

Lines changed: 141 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434

3535
requires_blake2 = unittest.skipUnless(_blake2, 'requires _blake2')
3636

37+
try:
38+
import _sha3
39+
except ImportError:
40+
_sha3 = None
41+
42+
requires_sha3 = unittest.skipUnless(_sha3, 'requires _sha3')
43+
3744

3845
def hexstr(s):
3946
assert isinstance(s, bytes), repr(s)
@@ -61,7 +68,11 @@ class HashLibTestCase(unittest.TestCase):
6168
supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
6269
'sha224', 'SHA224', 'sha256', 'SHA256',
6370
'sha384', 'SHA384', 'sha512', 'SHA512',
64-
'blake2b', 'blake2s')
71+
'blake2b', 'blake2s',
72+
'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
73+
'shake_128', 'shake_256')
74+
75+
shakes = {'shake_128', 'shake_256'}
6576

6677
# Issue #14693: fallback modules are always compiled under POSIX
6778
_warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG
@@ -131,6 +142,15 @@ def add_builtin_constructor(name):
131142
add_builtin_constructor('blake2s')
132143
add_builtin_constructor('blake2b')
133144

145+
_sha3 = self._conditional_import_module('_sha3')
146+
if _sha3:
147+
add_builtin_constructor('sha3_224')
148+
add_builtin_constructor('sha3_256')
149+
add_builtin_constructor('sha3_384')
150+
add_builtin_constructor('sha3_512')
151+
add_builtin_constructor('shake_128')
152+
add_builtin_constructor('shake_256')
153+
134154
super(HashLibTestCase, self).__init__(*args, **kwargs)
135155

136156
@property
@@ -142,7 +162,10 @@ def test_hash_array(self):
142162
a = array.array("b", range(10))
143163
for cons in self.hash_constructors:
144164
c = cons(a)
145-
c.hexdigest()
165+
if c.name in self.shakes:
166+
c.hexdigest(16)
167+
else:
168+
c.hexdigest()
146169

147170
def test_algorithms_guaranteed(self):
148171
self.assertEqual(hashlib.algorithms_guaranteed,
@@ -186,14 +209,21 @@ def test_get_builtin_constructor(self):
186209
def test_hexdigest(self):
187210
for cons in self.hash_constructors:
188211
h = cons()
189-
self.assertIsInstance(h.digest(), bytes)
190-
self.assertEqual(hexstr(h.digest()), h.hexdigest())
212+
if h.name in self.shakes:
213+
self.assertIsInstance(h.digest(16), bytes)
214+
self.assertEqual(hexstr(h.digest(16)), h.hexdigest(16))
215+
else:
216+
self.assertIsInstance(h.digest(), bytes)
217+
self.assertEqual(hexstr(h.digest()), h.hexdigest())
191218

192219
def test_name_attribute(self):
193220
for cons in self.hash_constructors:
194221
h = cons()
195222
self.assertIsInstance(h.name, str)
196-
self.assertIn(h.name, self.supported_hash_names)
223+
if h.name in self.supported_hash_names:
224+
self.assertIn(h.name, self.supported_hash_names)
225+
else:
226+
self.assertNotIn(h.name, self.supported_hash_names)
197227
self.assertEqual(h.name, hashlib.new(h.name).name)
198228

199229
def test_large_update(self):
@@ -208,40 +238,46 @@ def test_large_update(self):
208238
m1.update(bees)
209239
m1.update(cees)
210240
m1.update(dees)
241+
if m1.name in self.shakes:
242+
args = (16,)
243+
else:
244+
args = ()
211245

212246
m2 = cons()
213247
m2.update(aas + bees + cees + dees)
214-
self.assertEqual(m1.digest(), m2.digest())
248+
self.assertEqual(m1.digest(*args), m2.digest(*args))
215249

216250
m3 = cons(aas + bees + cees + dees)
217-
self.assertEqual(m1.digest(), m3.digest())
251+
self.assertEqual(m1.digest(*args), m3.digest(*args))
218252

219253
# verify copy() doesn't touch original
220254
m4 = cons(aas + bees + cees)
221-
m4_digest = m4.digest()
255+
m4_digest = m4.digest(*args)
222256
m4_copy = m4.copy()
223257
m4_copy.update(dees)
224-
self.assertEqual(m1.digest(), m4_copy.digest())
225-
self.assertEqual(m4.digest(), m4_digest)
258+
self.assertEqual(m1.digest(*args), m4_copy.digest(*args))
259+
self.assertEqual(m4.digest(*args), m4_digest)
226260

227-
def check(self, name, data, hexdigest, **kwargs):
261+
def check(self, name, data, hexdigest, shake=False, **kwargs):
262+
length = len(hexdigest)//2
228263
hexdigest = hexdigest.lower()
229264
constructors = self.constructors_to_test[name]
230265
# 2 is for hashlib.name(...) and hashlib.new(name, ...)
231266
self.assertGreaterEqual(len(constructors), 2)
232267
for hash_object_constructor in constructors:
233268
m = hash_object_constructor(data, **kwargs)
234-
computed = m.hexdigest()
269+
computed = m.hexdigest() if not shake else m.hexdigest(length)
235270
self.assertEqual(
236271
computed, hexdigest,
237272
"Hash algorithm %s constructed using %s returned hexdigest"
238273
" %r for %d byte input data that should have hashed to %r."
239274
% (name, hash_object_constructor,
240275
computed, len(data), hexdigest))
241-
computed = m.digest()
276+
computed = m.digest() if not shake else m.digest(length)
242277
digest = bytes.fromhex(hexdigest)
243278
self.assertEqual(computed, digest)
244-
self.assertEqual(len(digest), m.digest_size)
279+
if not shake:
280+
self.assertEqual(len(digest), m.digest_size)
245281

246282
def check_no_unicode(self, algorithm_name):
247283
# Unicode objects are not allowed as input.
@@ -262,13 +298,30 @@ def test_no_unicode_blake2(self):
262298
self.check_no_unicode('blake2b')
263299
self.check_no_unicode('blake2s')
264300

265-
def check_blocksize_name(self, name, block_size=0, digest_size=0):
301+
@requires_sha3
302+
def test_no_unicode_sha3(self):
303+
self.check_no_unicode('sha3_224')
304+
self.check_no_unicode('sha3_256')
305+
self.check_no_unicode('sha3_384')
306+
self.check_no_unicode('sha3_512')
307+
self.check_no_unicode('shake_128')
308+
self.check_no_unicode('shake_256')
309+
310+
def check_blocksize_name(self, name, block_size=0, digest_size=0,
311+
digest_length=None):
266312
constructors = self.constructors_to_test[name]
267313
for hash_object_constructor in constructors:
268314
m = hash_object_constructor()
269315
self.assertEqual(m.block_size, block_size)
270316
self.assertEqual(m.digest_size, digest_size)
271-
self.assertEqual(len(m.digest()), digest_size)
317+
if digest_length:
318+
self.assertEqual(len(m.digest(digest_length)),
319+
digest_length)
320+
self.assertEqual(len(m.hexdigest(digest_length)),
321+
2*digest_length)
322+
else:
323+
self.assertEqual(len(m.digest()), digest_size)
324+
self.assertEqual(len(m.hexdigest()), 2*digest_size)
272325
self.assertEqual(m.name, name)
273326
# split for sha3_512 / _sha3.sha3 object
274327
self.assertIn(name.split("_")[0], repr(m))
@@ -280,6 +333,12 @@ def test_blocksize_name(self):
280333
self.check_blocksize_name('sha256', 64, 32)
281334
self.check_blocksize_name('sha384', 128, 48)
282335
self.check_blocksize_name('sha512', 128, 64)
336+
self.check_blocksize_name('sha3_224', 144, 28)
337+
self.check_blocksize_name('sha3_256', 136, 32)
338+
self.check_blocksize_name('sha3_384', 104, 48)
339+
self.check_blocksize_name('sha3_512', 72, 64)
340+
self.check_blocksize_name('shake_128', 168, 0, 32)
341+
self.check_blocksize_name('shake_256', 136, 0, 64)
283342

284343
@requires_blake2
285344
def test_blocksize_name_blake2(self):
@@ -563,6 +622,72 @@ def test_blake2s_vectors(self):
563622
key = bytes.fromhex(key)
564623
self.check('blake2s', msg, md, key=key)
565624

625+
@requires_sha3
626+
def test_case_sha3_224_0(self):
627+
self.check('sha3_224', b"",
628+
"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7")
629+
630+
@requires_sha3
631+
def test_case_sha3_224_vector(self):
632+
for msg, md in read_vectors('sha3_224'):
633+
self.check('sha3_224', msg, md)
634+
635+
@requires_sha3
636+
def test_case_sha3_256_0(self):
637+
self.check('sha3_256', b"",
638+
"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a")
639+
640+
@requires_sha3
641+
def test_case_sha3_256_vector(self):
642+
for msg, md in read_vectors('sha3_256'):
643+
self.check('sha3_256', msg, md)
644+
645+
@requires_sha3
646+
def test_case_sha3_384_0(self):
647+
self.check('sha3_384', b"",
648+
"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a"+
649+
"c3713831264adb47fb6bd1e058d5f004")
650+
651+
@requires_sha3
652+
def test_case_sha3_384_vector(self):
653+
for msg, md in read_vectors('sha3_384'):
654+
self.check('sha3_384', msg, md)
655+
656+
@requires_sha3
657+
def test_case_sha3_512_0(self):
658+
self.check('sha3_512', b"",
659+
"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6"+
660+
"15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26")
661+
662+
@requires_sha3
663+
def test_case_sha3_512_vector(self):
664+
for msg, md in read_vectors('sha3_512'):
665+
self.check('sha3_512', msg, md)
666+
667+
@requires_sha3
668+
def test_case_shake_128_0(self):
669+
self.check('shake_128', b"",
670+
"7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26",
671+
True)
672+
self.check('shake_128', b"", "7f9c", True)
673+
674+
@requires_sha3
675+
def test_case_shake128_vector(self):
676+
for msg, md in read_vectors('shake_128'):
677+
self.check('shake_128', msg, md, True)
678+
679+
@requires_sha3
680+
def test_case_shake_256_0(self):
681+
self.check('shake_256', b"",
682+
"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f",
683+
True)
684+
self.check('shake_256', b"", "46b9", True)
685+
686+
@requires_sha3
687+
def test_case_shake256_vector(self):
688+
for msg, md in read_vectors('shake_256'):
689+
self.check('shake_256', msg, md, True)
690+
566691
def test_gil(self):
567692
# Check things work fine with an input larger than the size required
568693
# for multithreaded operation (which is hardwired to 2048).

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ Core and Builtins
9191
Library
9292
-------
9393

94+
- Issue #16113: Add SHA-3 and SHAKE support to hashlib module.
95+
9496
- Issue #27776: The :func:`os.urandom` function does now block on Linux 3.17
9597
and newer until the system urandom entropy pool is initialized to increase
9698
the security. This change is part of the :pep:`524`.

Modules/_sha3/README.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Keccak Code Package
2+
===================
3+
4+
The files in kcp are taken from the Keccak Code Package. They have been
5+
slightly to be C89 compatible. The architecture specific header file
6+
KeccakP-1600-SnP.h ha been renamed to KeccakP-1600-SnP-opt32.h or
7+
KeccakP-1600-SnP-opt64.h.
8+
9+
The 64bit files were generated with generic64lc/libkeccak.a.pack target, the
10+
32bit files with generic32lc/libkeccak.a.pack.
11+

0 commit comments

Comments
 (0)