summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/hmac.rst19
-rw-r--r--Lib/hmac.py8
-rw-r--r--Lib/test/test_hmac.py35
-rw-r--r--Misc/NEWS3
4 files changed, 59 insertions, 6 deletions
diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst
index 8fa1435..2e9b0b2 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 873327b..77785a2 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 eb23b26..52665bd 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 1aaf8c1..be6a119 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').