summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorChristian Heimes <christian@cheimes.de>2013-10-12 22:52:43 (GMT)
committerChristian Heimes <christian@cheimes.de>2013-10-12 22:52:43 (GMT)
commite92ef13b0add24cff6b3eba2f0b52a7833195a8c (patch)
tree8ff77db5dc84b7b87ceafe5e5bc0da56e431315a /Modules
parent3892419a7a8321bef27262b0d8f0a22305830ce5 (diff)
downloadcpython-e92ef13b0add24cff6b3eba2f0b52a7833195a8c.zip
cpython-e92ef13b0add24cff6b3eba2f0b52a7833195a8c.tar.gz
cpython-e92ef13b0add24cff6b3eba2f0b52a7833195a8c.tar.bz2
Issue #18582: Add 'pbkdf2_hmac' to the hashlib module.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_hashopenssl.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index c8db5ed..bec84ce 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -22,6 +22,7 @@
#include <openssl/evp.h>
/* We use the object interface to discover what hashes OpenSSL supports. */
#include <openssl/objects.h>
+#include "openssl/err.h"
#define MUNCH_SIZE INT_MAX
@@ -61,6 +62,34 @@ DEFINE_CONSTS_FOR_NEW(sha384)
DEFINE_CONSTS_FOR_NEW(sha512)
#endif
+static PyObject *
+_setException(PyObject *exc)
+{
+ unsigned long errcode;
+ const char *lib, *func, *reason;
+
+ errcode = ERR_peek_last_error();
+ if (!errcode) {
+ PyErr_SetString(exc, "unknown reasons");
+ return NULL;
+ }
+ ERR_clear_error();
+
+ lib = ERR_lib_error_string(errcode);
+ func = ERR_func_error_string(errcode);
+ reason = ERR_reason_error_string(errcode);
+
+ if (lib && func) {
+ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason);
+ }
+ else if (lib) {
+ PyErr_Format(exc, "[%s] %s", lib, reason);
+ }
+ else {
+ PyErr_SetString(exc, reason);
+ }
+ return NULL;
+}
static EVPobject *
newEVPobject(PyObject *name)
@@ -466,6 +495,109 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)
return ret_obj;
}
+#if (OPENSSL_VERSION_NUMBER >= 0x10000000 && !defined(OPENSSL_NO_HMAC) \
+ && !defined(OPENSSL_NO_SHA))
+#define PY_PBKDF2_HMAC 1
+
+PyDoc_STRVAR(pbkdf2_hmac__doc__,
+"pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) -> key\n\
+\n\
+Password based key derivation function 2 (PKCS #5 v2.0) with HMAC as\n\
+pseudorandom function.");
+
+static PyObject *
+pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+ static char *kwlist[] = {"hash_name", "password", "salt", "iterations",
+ "dklen", NULL};
+ PyObject *key_obj = NULL, *dklen_obj = Py_None;
+ char *name, *key;
+ Py_buffer password, salt;
+ long iterations, dklen;
+ int retval;
+ const EVP_MD *digest;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "sy*y*l|O:pbkdf2_hmac",
+ kwlist, &name, &password, &salt,
+ &iterations, &dklen_obj)) {
+ return NULL;
+ }
+
+ digest = EVP_get_digestbyname(name);
+ if (digest == NULL) {
+ PyErr_SetString(PyExc_ValueError, "unsupported hash type");
+ goto end;
+ }
+
+ if (password.len > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "password is too long.");
+ goto end;
+ }
+
+ if (salt.len > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "salt is too long.");
+ goto end;
+ }
+
+ if (iterations < 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "iteration value must be greater than 0.");
+ goto end;
+ }
+ if (iterations > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "iteration value is too great.");
+ goto end;
+ }
+
+ if (dklen_obj == Py_None) {
+ dklen = EVP_MD_size(digest);
+ } else {
+ dklen = PyLong_AsLong(dklen_obj);
+ if ((dklen == -1) && PyErr_Occurred()) {
+ goto end;
+ }
+ }
+ if (dklen < 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "key length must be greater than 0.");
+ goto end;
+ }
+ if (dklen > INT_MAX) {
+ /* INT_MAX is always smaller than dkLen max (2^32 - 1) * hLen */
+ PyErr_SetString(PyExc_OverflowError,
+ "key length is too great.");
+ goto end;
+ }
+
+ key_obj = PyBytes_FromStringAndSize(NULL, dklen);
+ if (key_obj == NULL) {
+ goto end;
+ }
+ key = PyBytes_AS_STRING(key_obj);
+
+ Py_BEGIN_ALLOW_THREADS
+ retval = PKCS5_PBKDF2_HMAC((char*)password.buf, password.len,
+ (unsigned char *)salt.buf, salt.len,
+ iterations, digest, dklen,
+ (unsigned char *)key);
+ Py_END_ALLOW_THREADS
+
+ if (!retval) {
+ Py_CLEAR(key_obj);
+ _setException(PyExc_ValueError);
+ goto end;
+ }
+
+ end:
+ PyBuffer_Release(&password);
+ PyBuffer_Release(&salt);
+ return key_obj;
+}
+
+#endif
/* State for our callback function so that it can accumulate a result. */
typedef struct _internal_name_mapper_state {
@@ -588,6 +720,10 @@ GEN_CONSTRUCTOR(sha512)
static struct PyMethodDef EVP_functions[] = {
{"new", (PyCFunction)EVP_new, METH_VARARGS|METH_KEYWORDS, EVP_new__doc__},
+#ifdef PY_PBKDF2_HMAC
+ {"pbkdf2_hmac", (PyCFunction)pbkdf2_hmac, METH_VARARGS|METH_KEYWORDS,
+ pbkdf2_hmac__doc__},
+#endif
CONSTRUCTOR_METH_DEF(md5),
CONSTRUCTOR_METH_DEF(sha1),
#ifdef _OPENSSL_SUPPORTS_SHA2