From c83c8548dbc9e0a11aa0589b72060a2f8521a5ea Mon Sep 17 00:00:00 2001 From: Joannah Nanjekye Date: Fri, 25 Nov 2022 03:39:16 -0500 Subject: [PATCH] warn for hmac and hexlify --- Lib/hmac.py | 6 +++++ Lib/test/test_binascii.py | 7 ++++-- Lib/test/test_hmac.py | 33 +++++++++++++++----------- Lib/warnings.py | 50 +++++++++++++++++++++++++++++++++++++++ Modules/binascii.c | 5 ++++ 5 files changed, 85 insertions(+), 16 deletions(-) diff --git a/Lib/hmac.py b/Lib/hmac.py index 9cd1a9fd913f6b..eaea55f5529a0d 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -4,6 +4,8 @@ """ import warnings as _warnings +import sys + from operator import _compare_digest as compare_digest @@ -41,6 +43,10 @@ def __init__(self, key, msg = None, digestmod = None): return if digestmod is None: + if sys.py3kwarning: + _warnings.warnpy3k_with_fix('the digestmod paramemer is required in 3.x', + 'generate a digest with hashlib module', + DeprecationWarning, stacklevel=4) import hashlib digestmod = hashlib.md5 diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py index 209126b255fd0b..62ce475cfc6143 100644 --- a/Lib/test/test_binascii.py +++ b/Lib/test/test_binascii.py @@ -172,8 +172,11 @@ def test_hex(self): self.assertRaises(TypeError, binascii.a2b_hex, t[:-1] + 'q') # Verify the treatment of Unicode strings - if test_support.have_unicode: - self.assertEqual(binascii.hexlify(unicode('a', 'ascii')), '61') + with test_support.check_py3k_warnings(("The hexlify() module expects bytes in 3.x; use the 'b' prefix on the string", + DeprecationWarning)): + if test_support.have_unicode: + self.assertEqual(binascii.hexlify(unicode('a', 'ascii')), '61') + self.assertEqual(binascii.b2a_hex(unicode('a', 'ascii')), '61') def test_qp(self): type2test = self.type2test diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index 8f639a383e176c..fdc4baa322e749 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -12,37 +12,37 @@ def test_md5_vectors(self): # Test the HMAC module against test vectors from the RFC. def md5test(key, data, digest): - h = hmac.HMAC(key, data) + h = hmac.HMAC(key, data, digestmod=hashlib.sha1) self.assertEqual(h.hexdigest().upper(), digest.upper()) md5test(chr(0x0b) * 16, "Hi There", - "9294727A3638BB1C13F48EF8158BFC9D") + "675B0B3A1B4DDF4E124872DA6C2F632BFED957E9") md5test("Jefe", "what do ya want for nothing?", - "750c783e6ab0b503eaa86e310a5db738") + "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79") md5test(chr(0xAA)*16, chr(0xDD)*50, - "56be34521d144c88dbb8c733f0e8b3f6") + "D730594D167E35D5956FD8003D0DB3D3F46DC7BB") md5test("".join([chr(i) for i in range(1, 26)]), chr(0xCD) * 50, - "697eaf0aca3a3aea3a75164746ffaa79") + "4C9007F4026250C6BC8414F9BF50C86C2D7235DA") md5test(chr(0x0C) * 16, "Test With Truncation", - "56461ef2342edc00f9bab995690efd4c") + "37268B7E21E84DA5720C53C4BA03AD1104039FA7") md5test(chr(0xAA) * 80, "Test Using Larger Than Block-Size Key - Hash Key First", - "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd") + "AA4AE5E15272D00E95705637CE8A3B55ED402112") md5test(chr(0xAA) * 80, ("Test Using Larger Than Block-Size Key " "and Larger Than One Block-Size Data"), - "6f630fad67cda0ee1fb1f562db3aa53e") + "E8E99D0F45237D786D6BBAA7965C7808BBFF1A91") def test_sha_vectors(self): def shatest(key, data, digest): @@ -232,14 +232,14 @@ def test_normal(self): # Standard constructor call. failed = 0 try: - h = hmac.HMAC("key") + h = hmac.HMAC("key", digestmod=hashlib.sha1) except: self.fail("Standard constructor call raised exception.") def test_withtext(self): # Constructor call with text. try: - h = hmac.HMAC("key", "hash this!") + h = hmac.HMAC("key", "hash this!", digestmod=hashlib.sha1) except: self.fail("Constructor call with text argument raised exception.") @@ -250,6 +250,11 @@ def test_withmodule(self): except: self.fail("Constructor call with hashlib.sha1 raised exception.") + def test_3k_no_digest(self): + with test_support.check_py3k_warnings(("the digestmod paramemer is required in 3.x; generate a digest with hashlib module", + DeprecationWarning)): + h = hmac.HMAC("key", "", hashlib.sha1) + class SanityTestCase(unittest.TestCase): def test_default_is_md5(self): @@ -262,7 +267,7 @@ def test_exercise_all_methods(self): # Exercising all methods once. # This must not raise any exceptions try: - h = hmac.HMAC("my secret key") + h = hmac.HMAC("my secret key", digestmod=hashlib.sha1) h.update("compute the hash of this text!") dig = h.digest() dig = h.hexdigest() @@ -274,7 +279,7 @@ class CopyTestCase(unittest.TestCase): def test_attributes(self): # Testing if attributes are of same type. - h1 = hmac.HMAC("key") + h1 = hmac.HMAC("key", digestmod=hashlib.sha1) h2 = h1.copy() self.assertTrue(h1.digest_cons == h2.digest_cons, "digest constructors don't match.") @@ -285,7 +290,7 @@ def test_attributes(self): def test_realcopy(self): # Testing if the copy method created a real copy. - h1 = hmac.HMAC("key") + h1 = hmac.HMAC("key", digestmod=hashlib.sha1) h2 = h1.copy() # Using id() in case somebody has overridden __cmp__. self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.") @@ -296,7 +301,7 @@ def test_realcopy(self): def test_equality(self): # Testing if the copy has the same digests. - h1 = hmac.HMAC("key") + h1 = hmac.HMAC("key", digestmod=hashlib.sha1) h1.update("some random text") h2 = h1.copy() self.assertTrue(h1.digest() == h2.digest(), diff --git a/Lib/warnings.py b/Lib/warnings.py index 3af0c1ed60cfde..41bd2501d32891 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -23,6 +23,16 @@ def warnpy3k(message, category=None, stacklevel=1): category = DeprecationWarning warn(message, category, stacklevel+1) +def warnpy3k_with_fix(message, category=None, stacklevel=1): + """Issue a deprecation warning for Python 3.x related changes and a fix. + + Warnings are omitted unless Python is started with the -3 option. + """ + if sys.py3kwarning: + if category is None: + category = DeprecationWarning + warn_with_fix(message, fix, category, stacklevel+1) + def _show_warning(message, category, filename, lineno, file=None, line=None): """Hook to write a warning to a file; replace if you like.""" if file is None: @@ -343,6 +353,46 @@ def warn_explicit(message, category, filename, lineno, # Print message and context showwarning(message, category, filename, lineno) +def warn_with_fix(message, fix, category=None, stacklevel=1): + """Issue a warning, or maybe ignore it or raise an exception.""" + # Check if message is already a Warning object + if isinstance(message, Warning): + category = message.__class__ + # Check category argument + if category is None: + category = UserWarning + assert issubclass(category, Warning) + # Get context information + try: + caller = sys._getframe(stacklevel) + except ValueError: + globals = sys.__dict__ + lineno = 1 + else: + globals = caller.f_globals + lineno = caller.f_lineno + if '__name__' in globals: + module = globals['__name__'] + else: + module = "" + filename = globals.get('__file__') + if filename: + fnl = filename.lower() + if fnl.endswith((".pyc", ".pyo")): + filename = filename[:-1] + else: + if module == "__main__": + try: + filename = sys.argv[0] + except AttributeError: + # embedded interpreters don't have sys.argv, see bug #839151 + filename = '__main__' + if not filename: + filename = module + registry = globals.setdefault("__warningregistry__", {}) + warn_explicit_with_fix(message, fix, category, filename, lineno, module, registry, + globals) + def warn_explicit_with_fix(message, fix, category, filename, lineno, module=None, registry=None, module_globals=None): lineno = int(lineno) diff --git a/Modules/binascii.c b/Modules/binascii.c index 1e785fa8faaa5f..16838114ae178c 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -1051,6 +1051,11 @@ binascii_hexlify(PyObject *self, PyObject *args) argbuf = parg.buf; arglen = parg.len; + if (PyUnicode_Check(args)) + if (PyErr_WarnPy3k_WithFix("The hexlify() module expects bytes in 3.x", + "use the 'b' prefix on the string", 1) < 0) + return NULL; + assert(arglen >= 0); if (arglen > PY_SSIZE_T_MAX / 2) { PyBuffer_Release(&parg);