diff options
author | Christian Heimes <christian@python.org> | 2018-01-27 09:53:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-27 09:53:43 +0100 |
commit | 2f050c7e1b36bf641e7023f7b28b451454c6b98a (patch) | |
tree | 01ee725ca174b0e7f1ba6f160916f891bebb5a38 /Modules/_hashopenssl.c | |
parent | a49ac9902903a798fab4970ccf563c531199c3f8 (diff) | |
download | cpython-git-2f050c7e1b36bf641e7023f7b28b451454c6b98a.tar.gz |
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 'Modules/_hashopenssl.c')
-rw-r--r-- | Modules/_hashopenssl.c | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index c8d175860b..50fe9d5a10 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -21,6 +21,7 @@ /* EVP is the preferred interface to hashing in OpenSSL */ #include <openssl/evp.h> +#include <openssl/hmac.h> /* We use the object interface to discover what hashes OpenSSL supports. */ #include <openssl/objects.h> #include "openssl/err.h" @@ -528,8 +529,6 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) return ret_obj; } - - #if (OPENSSL_VERSION_NUMBER >= 0x10000000 && !defined(OPENSSL_NO_HMAC) \ && !defined(OPENSSL_NO_SHA)) @@ -849,6 +848,61 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt, } #endif +/* Fast HMAC for hmac.digest() + */ + +/*[clinic input] +_hashlib.hmac_digest + + key: Py_buffer + msg: Py_buffer + digest: str + +Single-shot HMAC +[clinic start generated code]*/ + +static PyObject * +_hashlib_hmac_digest_impl(PyObject *module, Py_buffer *key, Py_buffer *msg, + const char *digest) +/*[clinic end generated code: output=75630e684cdd8762 input=10e964917921e2f2]*/ +{ + unsigned char md[EVP_MAX_MD_SIZE] = {0}; + unsigned int md_len = 0; + unsigned char *result; + const EVP_MD *evp; + + evp = EVP_get_digestbyname(digest); + if (evp == NULL) { + PyErr_SetString(PyExc_ValueError, "unsupported hash type"); + return NULL; + } + if (key->len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "key is too long."); + return NULL; + } + if (msg->len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "msg is too long."); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + result = HMAC( + evp, + (const void*)key->buf, (int)key->len, + (const unsigned char*)msg->buf, (int)msg->len, + md, &md_len + ); + Py_END_ALLOW_THREADS + + if (result == NULL) { + _setException(PyExc_ValueError); + return NULL; + } + return PyBytes_FromStringAndSize((const char*)md, md_len); +} + /* State for our callback function so that it can accumulate a result. */ typedef struct _internal_name_mapper_state { PyObject *set; @@ -982,6 +1036,7 @@ static struct PyMethodDef EVP_functions[] = { pbkdf2_hmac__doc__}, #endif _HASHLIB_SCRYPT_METHODDEF + _HASHLIB_HMAC_DIGEST_METHODDEF CONSTRUCTOR_METH_DEF(md5), CONSTRUCTOR_METH_DEF(sha1), CONSTRUCTOR_METH_DEF(sha224), |