diff options
author | Christian Heimes <christian@python.org> | 2018-01-27 08:53:43 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-27 08:53:43 (GMT) |
commit | 2f050c7e1b36bf641e7023f7b28b451454c6b98a (patch) | |
tree | 01ee725ca174b0e7f1ba6f160916f891bebb5a38 /Lib/hmac.py | |
parent | a49ac9902903a798fab4970ccf563c531199c3f8 (diff) | |
download | cpython-2f050c7e1b36bf641e7023f7b28b451454c6b98a.zip cpython-2f050c7e1b36bf641e7023f7b28b451454c6b98a.tar.gz cpython-2f050c7e1b36bf641e7023f7b28b451454c6b98a.tar.bz2 |
bpo-32433: Optimized HMAC digest (#5023)
The hmac module now has hmac.digest(), which provides an optimized HMAC
digest for short messages. hmac.digest() is up to three times faster
than hmac.HMAC().digest().
Signed-off-by: Christian Heimes <christian@python.org>
Diffstat (limited to 'Lib/hmac.py')
-rw-r--r-- | Lib/hmac.py | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/Lib/hmac.py b/Lib/hmac.py index 121029a..93c084e 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -5,6 +5,13 @@ Implements the HMAC algorithm as described by RFC 2104. import warnings as _warnings from _operator import _compare_digest as compare_digest +try: + import _hashlib as _hashopenssl +except ImportError: + _hashopenssl = None + _openssl_md_meths = None +else: + _openssl_md_meths = frozenset(_hashopenssl.openssl_md_meth_names) import hashlib as _hashlib trans_5C = bytes((x ^ 0x5C) for x in range(256)) @@ -142,3 +149,38 @@ def new(key, msg = None, digestmod = None): method. """ return HMAC(key, msg, digestmod) + + +def digest(key, msg, digest): + """Fast inline implementation of HMAC + + key: key for the keyed hash object. + msg: input message + digest: A hash name suitable for hashlib.new() for best performance. *OR* + A hashlib constructor returning a new hash object. *OR* + A module supporting PEP 247. + + Note: key and msg must be a bytes or bytearray objects. + """ + if (_hashopenssl is not None and + isinstance(digest, str) and digest in _openssl_md_meths): + return _hashopenssl.hmac_digest(key, msg, digest) + + if callable(digest): + digest_cons = digest + elif isinstance(digest, str): + digest_cons = lambda d=b'': _hashlib.new(digest, d) + else: + digest_cons = lambda d=b'': digest.new(d) + + inner = digest_cons() + outer = digest_cons() + blocksize = getattr(inner, 'block_size', 64) + if len(key) > blocksize: + key = digest_cons(key).digest() + key = key + b'\x00' * (blocksize - len(key)) + inner.update(key.translate(trans_36)) + outer.update(key.translate(trans_5C)) + inner.update(msg) + outer.update(inner.digest()) + return outer.digest() |