Skip to content

Commit fa27e80

Browse files
Merge python#13
13: warn for hmac and hexlify r=ltratt a=nanjekyejoannah This PR adds warnings for the following modules: - `hmac` - `binascii.hexlify` - `binascii.b2a_hex` See the notes below: 1. warn for the 'digest' parameter in hmac in pygrate2 In Python 2: ``` >>> import hashlib >>> import hmac >>> string1 = 'firststring'.encode('utf-8') >>> string2 = 'secondstring'.encode('utf-8') >>> digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest() >>> digest = hmac.new(key=string1, msg=string2).digest() >>> ``` In Python 3: ``` string1 = 'firststring'.encode('utf-8') >>> string2 = 'secondstring'.encode('utf-8') >>> digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest() Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'hmac' is not defined >>> import hashlib >>> import hmac >>> digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest() >>> digest = hmac.new(key=string1, msg=string2).digest() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/Cellar/python@3.9/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/hmac.py", line 170, in new return HMAC(key, msg, digestmod) File "/usr/local/Cellar/python@3.9/3.9.12_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/hmac.py", line 56, in __init__ raise TypeError("Missing required parameter 'digestmod'.") TypeError: Missing required parameter 'digestmod'. >>> ``` 2. Warn for hexlify In python 2: ``` >>> import codecs >>> hexlify = codecs.getencoder('hex') >>> hexlify(b'Blaah')[0] '426c616168' >>> import binascii >>> binascii.hexlify(b'Blaah') '426c616168' >>> binascii.hexlify('Blaah') '426c616168' >>> ``` In Python 3: ``` >>> import codecs >>> hexlify = codecs.getencoder('hex') >>> hexlify(b'Blaah')[0] b'426c616168' >>> import binascii >>> binascii.hexlify(b'Blaah') b'426c616168' >>> binascii.hexlify('Blaah') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: a bytes-like object is required, not 'str' >>> ``` Co-authored-by: Joannah Nanjekye <jnanjekye@python.org>
2 parents 48f8eb8 + c83c854 commit fa27e80

File tree

5 files changed

+85
-16
lines changed

5 files changed

+85
-16
lines changed

Lib/hmac.py

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"""
55

66
import warnings as _warnings
7+
import sys
8+
79

810
from operator import _compare_digest as compare_digest
911

@@ -41,6 +43,10 @@ def __init__(self, key, msg = None, digestmod = None):
4143
return
4244

4345
if digestmod is None:
46+
if sys.py3kwarning:
47+
_warnings.warnpy3k_with_fix('the digestmod paramemer is required in 3.x',
48+
'generate a digest with hashlib module',
49+
DeprecationWarning, stacklevel=4)
4450
import hashlib
4551
digestmod = hashlib.md5
4652

Lib/test/test_binascii.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,11 @@ def test_hex(self):
172172
self.assertRaises(TypeError, binascii.a2b_hex, t[:-1] + 'q')
173173

174174
# Verify the treatment of Unicode strings
175-
if test_support.have_unicode:
176-
self.assertEqual(binascii.hexlify(unicode('a', 'ascii')), '61')
175+
with test_support.check_py3k_warnings(("The hexlify() module expects bytes in 3.x; use the 'b' prefix on the string",
176+
DeprecationWarning)):
177+
if test_support.have_unicode:
178+
self.assertEqual(binascii.hexlify(unicode('a', 'ascii')), '61')
179+
self.assertEqual(binascii.b2a_hex(unicode('a', 'ascii')), '61')
177180

178181
def test_qp(self):
179182
type2test = self.type2test

Lib/test/test_hmac.py

+19-14
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,37 @@ def test_md5_vectors(self):
1212
# Test the HMAC module against test vectors from the RFC.
1313

1414
def md5test(key, data, digest):
15-
h = hmac.HMAC(key, data)
15+
h = hmac.HMAC(key, data, digestmod=hashlib.sha1)
1616
self.assertEqual(h.hexdigest().upper(), digest.upper())
1717

1818
md5test(chr(0x0b) * 16,
1919
"Hi There",
20-
"9294727A3638BB1C13F48EF8158BFC9D")
20+
"675B0B3A1B4DDF4E124872DA6C2F632BFED957E9")
2121

2222
md5test("Jefe",
2323
"what do ya want for nothing?",
24-
"750c783e6ab0b503eaa86e310a5db738")
24+
"EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79")
2525

2626
md5test(chr(0xAA)*16,
2727
chr(0xDD)*50,
28-
"56be34521d144c88dbb8c733f0e8b3f6")
28+
"D730594D167E35D5956FD8003D0DB3D3F46DC7BB")
2929

3030
md5test("".join([chr(i) for i in range(1, 26)]),
3131
chr(0xCD) * 50,
32-
"697eaf0aca3a3aea3a75164746ffaa79")
32+
"4C9007F4026250C6BC8414F9BF50C86C2D7235DA")
3333

3434
md5test(chr(0x0C) * 16,
3535
"Test With Truncation",
36-
"56461ef2342edc00f9bab995690efd4c")
36+
"37268B7E21E84DA5720C53C4BA03AD1104039FA7")
3737

3838
md5test(chr(0xAA) * 80,
3939
"Test Using Larger Than Block-Size Key - Hash Key First",
40-
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd")
40+
"AA4AE5E15272D00E95705637CE8A3B55ED402112")
4141

4242
md5test(chr(0xAA) * 80,
4343
("Test Using Larger Than Block-Size Key "
4444
"and Larger Than One Block-Size Data"),
45-
"6f630fad67cda0ee1fb1f562db3aa53e")
45+
"E8E99D0F45237D786D6BBAA7965C7808BBFF1A91")
4646

4747
def test_sha_vectors(self):
4848
def shatest(key, data, digest):
@@ -232,14 +232,14 @@ def test_normal(self):
232232
# Standard constructor call.
233233
failed = 0
234234
try:
235-
h = hmac.HMAC("key")
235+
h = hmac.HMAC("key", digestmod=hashlib.sha1)
236236
except:
237237
self.fail("Standard constructor call raised exception.")
238238

239239
def test_withtext(self):
240240
# Constructor call with text.
241241
try:
242-
h = hmac.HMAC("key", "hash this!")
242+
h = hmac.HMAC("key", "hash this!", digestmod=hashlib.sha1)
243243
except:
244244
self.fail("Constructor call with text argument raised exception.")
245245

@@ -250,6 +250,11 @@ def test_withmodule(self):
250250
except:
251251
self.fail("Constructor call with hashlib.sha1 raised exception.")
252252

253+
def test_3k_no_digest(self):
254+
with test_support.check_py3k_warnings(("the digestmod paramemer is required in 3.x; generate a digest with hashlib module",
255+
DeprecationWarning)):
256+
h = hmac.HMAC("key", "", hashlib.sha1)
257+
253258
class SanityTestCase(unittest.TestCase):
254259

255260
def test_default_is_md5(self):
@@ -262,7 +267,7 @@ def test_exercise_all_methods(self):
262267
# Exercising all methods once.
263268
# This must not raise any exceptions
264269
try:
265-
h = hmac.HMAC("my secret key")
270+
h = hmac.HMAC("my secret key", digestmod=hashlib.sha1)
266271
h.update("compute the hash of this text!")
267272
dig = h.digest()
268273
dig = h.hexdigest()
@@ -274,7 +279,7 @@ class CopyTestCase(unittest.TestCase):
274279

275280
def test_attributes(self):
276281
# Testing if attributes are of same type.
277-
h1 = hmac.HMAC("key")
282+
h1 = hmac.HMAC("key", digestmod=hashlib.sha1)
278283
h2 = h1.copy()
279284
self.assertTrue(h1.digest_cons == h2.digest_cons,
280285
"digest constructors don't match.")
@@ -285,7 +290,7 @@ def test_attributes(self):
285290

286291
def test_realcopy(self):
287292
# Testing if the copy method created a real copy.
288-
h1 = hmac.HMAC("key")
293+
h1 = hmac.HMAC("key", digestmod=hashlib.sha1)
289294
h2 = h1.copy()
290295
# Using id() in case somebody has overridden __cmp__.
291296
self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.")
@@ -296,7 +301,7 @@ def test_realcopy(self):
296301

297302
def test_equality(self):
298303
# Testing if the copy has the same digests.
299-
h1 = hmac.HMAC("key")
304+
h1 = hmac.HMAC("key", digestmod=hashlib.sha1)
300305
h1.update("some random text")
301306
h2 = h1.copy()
302307
self.assertTrue(h1.digest() == h2.digest(),

Lib/warnings.py

+50
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ def warnpy3k(message, category=None, stacklevel=1):
2323
category = DeprecationWarning
2424
warn(message, category, stacklevel+1)
2525

26+
def warnpy3k_with_fix(message, category=None, stacklevel=1):
27+
"""Issue a deprecation warning for Python 3.x related changes and a fix.
28+
29+
Warnings are omitted unless Python is started with the -3 option.
30+
"""
31+
if sys.py3kwarning:
32+
if category is None:
33+
category = DeprecationWarning
34+
warn_with_fix(message, fix, category, stacklevel+1)
35+
2636
def _show_warning(message, category, filename, lineno, file=None, line=None):
2737
"""Hook to write a warning to a file; replace if you like."""
2838
if file is None:
@@ -343,6 +353,46 @@ def warn_explicit(message, category, filename, lineno,
343353
# Print message and context
344354
showwarning(message, category, filename, lineno)
345355

356+
def warn_with_fix(message, fix, category=None, stacklevel=1):
357+
"""Issue a warning, or maybe ignore it or raise an exception."""
358+
# Check if message is already a Warning object
359+
if isinstance(message, Warning):
360+
category = message.__class__
361+
# Check category argument
362+
if category is None:
363+
category = UserWarning
364+
assert issubclass(category, Warning)
365+
# Get context information
366+
try:
367+
caller = sys._getframe(stacklevel)
368+
except ValueError:
369+
globals = sys.__dict__
370+
lineno = 1
371+
else:
372+
globals = caller.f_globals
373+
lineno = caller.f_lineno
374+
if '__name__' in globals:
375+
module = globals['__name__']
376+
else:
377+
module = "<string>"
378+
filename = globals.get('__file__')
379+
if filename:
380+
fnl = filename.lower()
381+
if fnl.endswith((".pyc", ".pyo")):
382+
filename = filename[:-1]
383+
else:
384+
if module == "__main__":
385+
try:
386+
filename = sys.argv[0]
387+
except AttributeError:
388+
# embedded interpreters don't have sys.argv, see bug #839151
389+
filename = '__main__'
390+
if not filename:
391+
filename = module
392+
registry = globals.setdefault("__warningregistry__", {})
393+
warn_explicit_with_fix(message, fix, category, filename, lineno, module, registry,
394+
globals)
395+
346396
def warn_explicit_with_fix(message, fix, category, filename, lineno,
347397
module=None, registry=None, module_globals=None):
348398
lineno = int(lineno)

Modules/binascii.c

+5
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,11 @@ binascii_hexlify(PyObject *self, PyObject *args)
10511051
argbuf = parg.buf;
10521052
arglen = parg.len;
10531053

1054+
if (PyUnicode_Check(args))
1055+
if (PyErr_WarnPy3k_WithFix("The hexlify() module expects bytes in 3.x",
1056+
"use the 'b' prefix on the string", 1) < 0)
1057+
return NULL;
1058+
10541059
assert(arglen >= 0);
10551060
if (arglen > PY_SSIZE_T_MAX / 2) {
10561061
PyBuffer_Release(&parg);

0 commit comments

Comments
 (0)