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 /Modules | |
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 'Modules')
-rw-r--r-- | Modules/_hashopenssl.c | 59 | ||||
-rw-r--r-- | Modules/clinic/_hashopenssl.c.h | 44 |
2 files changed, 100 insertions, 3 deletions
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index c8d1758..50fe9d5 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), diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h index f08d7f3..cbc8638 100644 --- a/Modules/clinic/_hashopenssl.c.h +++ b/Modules/clinic/_hashopenssl.c.h @@ -54,7 +54,49 @@ exit: #endif /* (OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_SCRYPT) && !defined(LIBRESSL_VERSION_NUMBER)) */ +PyDoc_STRVAR(_hashlib_hmac_digest__doc__, +"hmac_digest($module, /, key, msg, digest)\n" +"--\n" +"\n" +"Single-shot HMAC"); + +#define _HASHLIB_HMAC_DIGEST_METHODDEF \ + {"hmac_digest", (PyCFunction)_hashlib_hmac_digest, METH_FASTCALL|METH_KEYWORDS, _hashlib_hmac_digest__doc__}, + +static PyObject * +_hashlib_hmac_digest_impl(PyObject *module, Py_buffer *key, Py_buffer *msg, + const char *digest); + +static PyObject * +_hashlib_hmac_digest(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"key", "msg", "digest", NULL}; + static _PyArg_Parser _parser = {"y*y*s:hmac_digest", _keywords, 0}; + Py_buffer key = {NULL, NULL}; + Py_buffer msg = {NULL, NULL}; + const char *digest; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &key, &msg, &digest)) { + goto exit; + } + return_value = _hashlib_hmac_digest_impl(module, &key, &msg, digest); + +exit: + /* Cleanup for key */ + if (key.obj) { + PyBuffer_Release(&key); + } + /* Cleanup for msg */ + if (msg.obj) { + PyBuffer_Release(&msg); + } + + return return_value; +} + #ifndef _HASHLIB_SCRYPT_METHODDEF #define _HASHLIB_SCRYPT_METHODDEF #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ -/*[clinic end generated code: output=1ea7d0397f38e2c2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b5b90821caf05391 input=a9049054013a1b77]*/ |