From 52660b078016e4e4789e340f406fe8bea26eea9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 9 Aug 2026 14:29:08 +0200 Subject: [PATCH] gh-155428: align `hmac.digest` and `hmac.HMAC.digest` outputs when using small block sizes --- Lib/hmac.py | 39 +++++++++++-------- ...-08-09-14-26-48.gh-issue-155428.wi0_fI.rst | 3 ++ 2 files changed, 26 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-09-14-26-48.gh-issue-155428.wi0_fI.rst diff --git a/Lib/hmac.py b/Lib/hmac.py index e0c040bcd5fe3d2..89c600950783136 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -49,6 +49,27 @@ def digest_wrapper(d=b''): return digest_wrapper +def _select_blocksize(obj, default, stacklevel=3): + if hasattr(obj, 'block_size'): + blocksize = obj.block_size + if blocksize < 16: + import warnings + + warnings.warn(f"block_size of {blocksize} seems too small; " + f"using our default of {default}.", + RuntimeWarning, stacklevel=stacklevel) + blocksize = default + else: + import warnings + + warnings.warn("No block_size attribute on given digest object; " + f"Assuming {default}.", + RuntimeWarning, stacklevel=stacklevel) + blocksize = default + return blocksize + + + class HMAC: """RFC 2104 HMAC class. Also complies with RFC 4231. @@ -116,8 +137,6 @@ def _init_builtin_hmac(self, key, msg, digestmod): self.block_size = self._hmac.block_size def _init_old(self, key, msg, digestmod): - import warnings - digest_cons = _get_digest_constructor(digestmod) if _is_shake_constructor(digest_cons): raise ValueError(f"unsupported hash algorithm {digestmod}") @@ -127,19 +146,7 @@ def _init_old(self, key, msg, digestmod): self._inner = digest_cons() self.digest_size = self._inner.digest_size - if hasattr(self._inner, 'block_size'): - blocksize = self._inner.block_size - if blocksize < 16: - warnings.warn(f"block_size of {blocksize} seems too small; " - f"using our default of {self.blocksize}.", - RuntimeWarning, 2) - blocksize = self.blocksize # pragma: no cover - else: - warnings.warn("No block_size attribute on given digest object; " - f"Assuming {self.blocksize}.", - RuntimeWarning, 2) - blocksize = self.blocksize # pragma: no cover - + blocksize = _select_blocksize(self._inner, self.blocksize) if len(key) > blocksize: key = digest_cons(key).digest() @@ -272,7 +279,7 @@ def _compute_digest_fallback(key, msg, digest): raise ValueError(f"unsupported hash algorithm {digest}") inner = digest_cons() outer = digest_cons() - blocksize = getattr(inner, 'block_size', 64) + blocksize = _select_blocksize(inner, HMAC.blocksize) if len(key) > blocksize: key = digest_cons(key).digest() key = key.ljust(blocksize, b'\0') diff --git a/Misc/NEWS.d/next/Library/2026-08-09-14-26-48.gh-issue-155428.wi0_fI.rst b/Misc/NEWS.d/next/Library/2026-08-09-14-26-48.gh-issue-155428.wi0_fI.rst new file mode 100644 index 000000000000000..f0c6201cbe592ee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-09-14-26-48.gh-issue-155428.wi0_fI.rst @@ -0,0 +1,3 @@ +Ensure that :func:`hmac.digest` and :meth:`hmac.HMAC.digest` output +identical values when using a digest's block size smaller than 16. Patch by +Bénédikt Tran.