From c4ab11050d3efa7dd409a96d006435d282d5815e Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 20 Nov 2013 17:35:06 +0100 Subject: [PATCH] Issue #18775: Add name and block_size attribute to HMAC object. They now provide the same API elements as non-keyed cryptographic hash functions. --- Doc/library/hmac.rst | 19 +++++++++++++++++++ Lib/hmac.py | 8 ++++++++ Lib/test/test_hmac.py | 35 +++++++++++++++++++++++++++++------ Misc/NEWS | 3 +++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst index 8fa1435f881..2e9b0b26a57 100644 --- a/Doc/library/hmac.rst +++ b/Doc/library/hmac.rst @@ -79,6 +79,25 @@ An HMAC object has the following methods: compute the digests of strings that share a common initial substring. +A hash object has the following attributes: + +.. attribute:: HMAC.digest_size + + The size of the resulting HMAC digest in bytes. + +.. attribute:: HMAC.block_size + + The internal block size of the hash algorithm in bytes. + + .. versionadded:: 3.4 + +.. attribute:: HMAC.name + + The canonical name of this HMAC, always lowercase, e.g. ``hmac-md5``. + + .. versionadded:: 3.4 + + This module also provides the following helper function: .. function:: compare_digest(a, b) diff --git a/Lib/hmac.py b/Lib/hmac.py index 873327bf37c..77785a2d9b6 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -70,6 +70,10 @@ class HMAC: RuntimeWarning, 2) blocksize = self.blocksize + # self.blocksize is the default blocksize. self.block_size is + # effective block size as well as the public API attribute. + self.block_size = blocksize + if len(key) > blocksize: key = self.digest_cons(key).digest() @@ -79,6 +83,10 @@ class HMAC: if msg is not None: self.update(msg) + @property + def name(self): + return "hmac-" + self.inner.name + def update(self, msg): """Update this hashing object with the string msg. """ diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index eb23b26578c..52665bd47cb 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -12,8 +12,16 @@ class TestVectorsTestCase(unittest.TestCase): def md5test(key, data, digest): h = hmac.HMAC(key, data, digestmod=hashlib.md5) self.assertEqual(h.hexdigest().upper(), digest.upper()) + self.assertEqual(h.name, "hmac-md5") + self.assertEqual(h.digest_size, 16) + self.assertEqual(h.block_size, 64) + h = hmac.HMAC(key, data, digestmod='md5') self.assertEqual(h.hexdigest().upper(), digest.upper()) + self.assertEqual(h.name, "hmac-md5") + self.assertEqual(h.digest_size, 16) + self.assertEqual(h.block_size, 64) + md5test(b"\x0b" * 16, b"Hi There", @@ -48,8 +56,15 @@ class TestVectorsTestCase(unittest.TestCase): def shatest(key, data, digest): h = hmac.HMAC(key, data, digestmod=hashlib.sha1) self.assertEqual(h.hexdigest().upper(), digest.upper()) + self.assertEqual(h.name, "hmac-sha1") + self.assertEqual(h.digest_size, 20) + self.assertEqual(h.block_size, 64) + h = hmac.HMAC(key, data, digestmod='sha1') self.assertEqual(h.hexdigest().upper(), digest.upper()) + self.assertEqual(h.name, "hmac-sha1") + self.assertEqual(h.digest_size, 20) + self.assertEqual(h.block_size, 64) shatest(b"\x0b" * 20, @@ -81,12 +96,20 @@ class TestVectorsTestCase(unittest.TestCase): b"and Larger Than One Block-Size Data"), "e8e99d0f45237d786d6bbaa7965c7808bbff1a91") - def _rfc4231_test_cases(self, hashfunc, hashname): + def _rfc4231_test_cases(self, hashfunc, hash_name, digest_size, block_size): def hmactest(key, data, hexdigests): + hmac_name = "hmac-" + hash_name h = hmac.HMAC(key, data, digestmod=hashfunc) self.assertEqual(h.hexdigest().lower(), hexdigests[hashfunc]) - h = hmac.HMAC(key, data, digestmod=hashname) + self.assertEqual(h.name, hmac_name) + self.assertEqual(h.digest_size, digest_size) + self.assertEqual(h.block_size, block_size) + + h = hmac.HMAC(key, data, digestmod=hash_name) self.assertEqual(h.hexdigest().lower(), hexdigests[hashfunc]) + self.assertEqual(h.name, hmac_name) + self.assertEqual(h.digest_size, digest_size) + self.assertEqual(h.block_size, block_size) # 4.2. Test Case 1 @@ -197,16 +220,16 @@ class TestVectorsTestCase(unittest.TestCase): }) def test_sha224_rfc4231(self): - self._rfc4231_test_cases(hashlib.sha224, 'sha224') + self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64) def test_sha256_rfc4231(self): - self._rfc4231_test_cases(hashlib.sha256, 'sha256') + self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64) def test_sha384_rfc4231(self): - self._rfc4231_test_cases(hashlib.sha384, 'sha384') + self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128) def test_sha512_rfc4231(self): - self._rfc4231_test_cases(hashlib.sha512, 'sha512') + self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) def test_legacy_block_size_warnings(self): class MockCrazyHash(object): diff --git a/Misc/NEWS b/Misc/NEWS index 1aaf8c159bb..be6a1197c5a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,9 @@ Core and Builtins Library ------- +- Issue #18775: Add name and block_size attribute to HMAC object. They now + provide the same API elements as non-keyed cryptographic hash functions. + - Issue #17276: MD5 as default digestmod for HMAC is deprecated. The HMAC module supports digestmod names, e.g. hmac.HMAC('sha1').