Skip to content

Commit c615db6

Browse files
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. (cherry picked from commit f33c57d) Co-authored-by: Gregory P. Smith <[email protected]>
1 parent 7773d39 commit c615db6

File tree

4 files changed

+43
-28
lines changed

4 files changed

+43
-28
lines changed

Doc/library/hmac.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
This module implements the HMAC algorithm as described by :rfc:`2104`.
1515

1616

17-
.. function:: new(key, msg=None, digestmod=None)
17+
.. function:: new(key, msg=None, digestmod='')
1818

1919
Return a new hmac object. *key* is a bytes or bytearray object giving the
2020
secret key. If *msg* is present, the method call ``update(msg)`` is made.
2121
*digestmod* is the digest name, digest constructor or module for the HMAC
22-
object to use. It supports any name suitable to :func:`hashlib.new`.
22+
object to use. It may be any name suitable to :func:`hashlib.new`.
23+
Despite its argument position, it is required.
2324

2425
.. versionchanged:: 3.4
2526
Parameter *key* can be a bytes or bytearray object.
@@ -28,6 +29,8 @@ This module implements the HMAC algorithm as described by :rfc:`2104`.
2829

2930
.. deprecated-removed:: 3.4 3.8
3031
MD5 as implicit default digest for *digestmod* is deprecated.
32+
The digestmod parameter is now required. Pass it as a keyword
33+
argument to avoid awkwardness when you do not have an initial msg.
3134

3235

3336
.. function:: digest(key, msg, digest)
@@ -127,7 +130,6 @@ This module also provides the following helper function:
127130
a timing attack could theoretically reveal information about the
128131
types and lengths of *a* and *b*—but not their values.
129132

130-
131133
.. versionadded:: 3.3
132134

133135

Lib/hmac.py

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""HMAC (Keyed-Hashing for Message Authentication) Python module.
1+
"""HMAC (Keyed-Hashing for Message Authentication) module.
22
33
Implements the HMAC algorithm as described by RFC 2104.
44
"""
@@ -30,23 +30,25 @@ class HMAC:
3030
"""
3131
blocksize = 64 # 512-bit HMAC; can be changed in subclasses.
3232

33-
def __init__(self, key, msg = None, digestmod = None):
33+
def __init__(self, key, msg=None, digestmod=''):
3434
"""Create a new HMAC object.
3535
36-
key: key for the keyed hash object.
37-
msg: Initial input for the hash, if provided.
38-
digestmod: Required. A module supporting PEP 247. *OR*
39-
A hashlib constructor returning a new hash object. *OR*
40-
A hash name suitable for hashlib.new().
36+
key: bytes or buffer, key for the keyed hash object.
37+
msg: bytes or buffer, Initial input for the hash or None.
38+
digestmod: A hash name suitable for hashlib.new(). *OR*
39+
A hashlib constructor returning a new hash object. *OR*
40+
A module supporting PEP 247.
4141
42-
Note: key and msg must be a bytes or bytearray objects.
42+
Required as of 3.8, despite its position after the optional
43+
msg argument. Passing it as a keyword argument is
44+
recommended, though not required for legacy API reasons.
4345
"""
4446

4547
if not isinstance(key, (bytes, bytearray)):
4648
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
4749

48-
if digestmod is None:
49-
raise ValueError('`digestmod` is required.')
50+
if not digestmod:
51+
raise TypeError("Missing required parameter 'digestmod'.")
5052

5153
if callable(digestmod):
5254
self.digest_cons = digestmod
@@ -90,8 +92,7 @@ def name(self):
9092
return "hmac-" + self.inner.name
9193

9294
def update(self, msg):
93-
"""Update this hashing object with the string msg.
94-
"""
95+
"""Feed data from msg into this hashing object."""
9596
self.inner.update(msg)
9697

9798
def copy(self):
@@ -119,7 +120,7 @@ def _current(self):
119120
def digest(self):
120121
"""Return the hash value of this hashing object.
121122
122-
This returns a string containing 8-bit data. The object is
123+
This returns the hmac value as bytes. The object is
123124
not altered in any way by this function; you can continue
124125
updating the object after calling this function.
125126
"""
@@ -132,30 +133,34 @@ def hexdigest(self):
132133
h = self._current()
133134
return h.hexdigest()
134135

135-
def new(key, msg = None, digestmod = None):
136+
def new(key, msg=None, digestmod=''):
136137
"""Create a new hashing object and return it.
137138
138-
key: The starting key for the hash.
139-
msg: if available, will immediately be hashed into the object's starting
140-
state.
139+
key: bytes or buffer, The starting key for the hash.
140+
msg: bytes or buffer, Initial input for the hash, or None.
141+
digestmod: A hash name suitable for hashlib.new(). *OR*
142+
A hashlib constructor returning a new hash object. *OR*
143+
A module supporting PEP 247.
144+
145+
Required as of 3.8, despite its position after the optional
146+
msg argument. Passing it as a keyword argument is
147+
recommended, though not required for legacy API reasons.
141148
142-
You can now feed arbitrary strings into the object using its update()
149+
You can now feed arbitrary bytes into the object using its update()
143150
method, and can ask for the hash value at any time by calling its digest()
144-
method.
151+
or hexdigest() methods.
145152
"""
146153
return HMAC(key, msg, digestmod)
147154

148155

149156
def digest(key, msg, digest):
150-
"""Fast inline implementation of HMAC
157+
"""Fast inline implementation of HMAC.
151158
152-
key: key for the keyed hash object.
153-
msg: input message
159+
key: bytes or buffer, The key for the keyed hash object.
160+
msg: bytes or buffer, Input message.
154161
digest: A hash name suitable for hashlib.new() for best performance. *OR*
155162
A hashlib constructor returning a new hash object. *OR*
156163
A module supporting PEP 247.
157-
158-
Note: key and msg must be a bytes or bytearray objects.
159164
"""
160165
if (_hashopenssl is not None and
161166
isinstance(digest, str) and digest in _openssl_md_meths):

Lib/test/test_hmac.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,15 @@ def digest(self):
312312
self.fail('Expected warning about small block_size')
313313

314314
def test_with_digestmod_no_default(self):
315-
with self.assertRaises(ValueError):
315+
"""The digestmod parameter is required as of Python 3.8."""
316+
with self.assertRaisesRegex(TypeError, r'required.*digestmod'):
316317
key = b"\x0b" * 16
317318
data = b"Hi There"
318319
hmac.HMAC(key, data, digestmod=None)
320+
with self.assertRaisesRegex(TypeError, r'required.*digestmod'):
321+
hmac.new(key, data)
322+
with self.assertRaisesRegex(TypeError, r'required.*digestmod'):
323+
hmac.HMAC(key, msg=data, digestmod='')
319324

320325

321326
class ConstructorTestCase(unittest.TestCase):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed `hmac.new` and `hmac.HMAC` to raise TypeError instead of ValueError
2+
when the digestmod parameter, now required in 3.8, is omitted. Also
3+
clarified the hmac module documentation and docstrings.

0 commit comments

Comments
 (0)