Commit f33c57d5 authored by Gregory P. Smith's avatar Gregory P. Smith Committed by GitHub

bpo-33604: Raise TypeError on missing hmac arg. (GH-16805)

Also updates the documentation to clarify the situation surrounding
the digestmod parameter that is required despite its position in the
argument list as of 3.8.0 as well as removing old python2 era
references to "binary strings".

We indavertently had this raise ValueError in 3.8.0 for the missing
arg.  This is not considered an API change as no reasonable code would
be catching this missing argument error in order to handle it.
parent d8ca2354
...@@ -14,12 +14,13 @@ ...@@ -14,12 +14,13 @@
This module implements the HMAC algorithm as described by :rfc:`2104`. This module implements the HMAC algorithm as described by :rfc:`2104`.
.. function:: new(key, msg=None, digestmod=None) .. function:: new(key, msg=None, digestmod='')
Return a new hmac object. *key* is a bytes or bytearray object giving the Return a new hmac object. *key* is a bytes or bytearray object giving the
secret key. If *msg* is present, the method call ``update(msg)`` is made. secret key. If *msg* is present, the method call ``update(msg)`` is made.
*digestmod* is the digest name, digest constructor or module for the HMAC *digestmod* is the digest name, digest constructor or module for the HMAC
object to use. It supports any name suitable to :func:`hashlib.new`. object to use. It may be any name suitable to :func:`hashlib.new`.
Despite its argument position, it is required.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Parameter *key* can be a bytes or bytearray object. Parameter *key* can be a bytes or bytearray object.
...@@ -28,6 +29,8 @@ This module implements the HMAC algorithm as described by :rfc:`2104`. ...@@ -28,6 +29,8 @@ This module implements the HMAC algorithm as described by :rfc:`2104`.
.. deprecated-removed:: 3.4 3.8 .. deprecated-removed:: 3.4 3.8
MD5 as implicit default digest for *digestmod* is deprecated. MD5 as implicit default digest for *digestmod* is deprecated.
The digestmod parameter is now required. Pass it as a keyword
argument to avoid awkwardness when you do not have an initial msg.
.. function:: digest(key, msg, digest) .. function:: digest(key, msg, digest)
...@@ -127,7 +130,6 @@ This module also provides the following helper function: ...@@ -127,7 +130,6 @@ This module also provides the following helper function:
a timing attack could theoretically reveal information about the a timing attack could theoretically reveal information about the
types and lengths of *a* and *b*—but not their values. types and lengths of *a* and *b*—but not their values.
.. versionadded:: 3.3 .. versionadded:: 3.3
......
"""HMAC (Keyed-Hashing for Message Authentication) Python module. """HMAC (Keyed-Hashing for Message Authentication) module.
Implements the HMAC algorithm as described by RFC 2104. Implements the HMAC algorithm as described by RFC 2104.
""" """
...@@ -30,23 +30,25 @@ class HMAC: ...@@ -30,23 +30,25 @@ class HMAC:
""" """
blocksize = 64 # 512-bit HMAC; can be changed in subclasses. blocksize = 64 # 512-bit HMAC; can be changed in subclasses.
def __init__(self, key, msg = None, digestmod = None): def __init__(self, key, msg=None, digestmod=''):
"""Create a new HMAC object. """Create a new HMAC object.
key: key for the keyed hash object. key: bytes or buffer, key for the keyed hash object.
msg: Initial input for the hash, if provided. msg: bytes or buffer, Initial input for the hash or None.
digestmod: Required. A module supporting PEP 247. *OR* digestmod: A hash name suitable for hashlib.new(). *OR*
A hashlib constructor returning a new hash object. *OR* A hashlib constructor returning a new hash object. *OR*
A hash name suitable for hashlib.new(). A module supporting PEP 247.
Note: key and msg must be a bytes or bytearray objects. Required as of 3.8, despite its position after the optional
msg argument. Passing it as a keyword argument is
recommended, though not required for legacy API reasons.
""" """
if not isinstance(key, (bytes, bytearray)): if not isinstance(key, (bytes, bytearray)):
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
if digestmod is None: if not digestmod:
raise ValueError('`digestmod` is required.') raise TypeError("Missing required parameter 'digestmod'.")
if callable(digestmod): if callable(digestmod):
self.digest_cons = digestmod self.digest_cons = digestmod
...@@ -90,8 +92,7 @@ class HMAC: ...@@ -90,8 +92,7 @@ class HMAC:
return "hmac-" + self.inner.name return "hmac-" + self.inner.name
def update(self, msg): def update(self, msg):
"""Update this hashing object with the string msg. """Feed data from msg into this hashing object."""
"""
self.inner.update(msg) self.inner.update(msg)
def copy(self): def copy(self):
...@@ -119,7 +120,7 @@ class HMAC: ...@@ -119,7 +120,7 @@ class HMAC:
def digest(self): def digest(self):
"""Return the hash value of this hashing object. """Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is This returns the hmac value as bytes. The object is
not altered in any way by this function; you can continue not altered in any way by this function; you can continue
updating the object after calling this function. updating the object after calling this function.
""" """
...@@ -132,30 +133,34 @@ class HMAC: ...@@ -132,30 +133,34 @@ class HMAC:
h = self._current() h = self._current()
return h.hexdigest() return h.hexdigest()
def new(key, msg = None, digestmod = None): def new(key, msg=None, digestmod=''):
"""Create a new hashing object and return it. """Create a new hashing object and return it.
key: The starting key for the hash. key: bytes or buffer, The starting key for the hash.
msg: if available, will immediately be hashed into the object's starting msg: bytes or buffer, Initial input for the hash, or None.
state. digestmod: A hash name suitable for hashlib.new(). *OR*
A hashlib constructor returning a new hash object. *OR*
A module supporting PEP 247.
Required as of 3.8, despite its position after the optional
msg argument. Passing it as a keyword argument is
recommended, though not required for legacy API reasons.
You can now feed arbitrary strings into the object using its update() You can now feed arbitrary bytes into the object using its update()
method, and can ask for the hash value at any time by calling its digest() method, and can ask for the hash value at any time by calling its digest()
method. or hexdigest() methods.
""" """
return HMAC(key, msg, digestmod) return HMAC(key, msg, digestmod)
def digest(key, msg, digest): def digest(key, msg, digest):
"""Fast inline implementation of HMAC """Fast inline implementation of HMAC.
key: key for the keyed hash object. key: bytes or buffer, The key for the keyed hash object.
msg: input message msg: bytes or buffer, Input message.
digest: A hash name suitable for hashlib.new() for best performance. *OR* digest: A hash name suitable for hashlib.new() for best performance. *OR*
A hashlib constructor returning a new hash object. *OR* A hashlib constructor returning a new hash object. *OR*
A module supporting PEP 247. A module supporting PEP 247.
Note: key and msg must be a bytes or bytearray objects.
""" """
if (_hashopenssl is not None and if (_hashopenssl is not None and
isinstance(digest, str) and digest in _openssl_md_meths): isinstance(digest, str) and digest in _openssl_md_meths):
......
...@@ -312,10 +312,15 @@ class TestVectorsTestCase(unittest.TestCase): ...@@ -312,10 +312,15 @@ class TestVectorsTestCase(unittest.TestCase):
self.fail('Expected warning about small block_size') self.fail('Expected warning about small block_size')
def test_with_digestmod_no_default(self): def test_with_digestmod_no_default(self):
with self.assertRaises(ValueError): """The digestmod parameter is required as of Python 3.8."""
with self.assertRaisesRegex(TypeError, r'required.*digestmod'):
key = b"\x0b" * 16 key = b"\x0b" * 16
data = b"Hi There" data = b"Hi There"
hmac.HMAC(key, data, digestmod=None) hmac.HMAC(key, data, digestmod=None)
with self.assertRaisesRegex(TypeError, r'required.*digestmod'):
hmac.new(key, data)
with self.assertRaisesRegex(TypeError, r'required.*digestmod'):
hmac.HMAC(key, msg=data, digestmod='')
class ConstructorTestCase(unittest.TestCase): class ConstructorTestCase(unittest.TestCase):
......
Fixed `hmac.new` and `hmac.HMAC` to raise TypeError instead of ValueError
when the digestmod parameter, now required in 3.8, is omitted. Also
clarified the hmac module documentation and docstrings.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment