summaryrefslogtreecommitdiffstats
path: root/Modules/_hashopenssl.c
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2020-05-16 20:27:06 (GMT)
committerGitHub <noreply@github.com>2020-05-16 20:27:06 (GMT)
commitd5b3f6b7f9fc74438009af63f1de01bd77be9385 (patch)
tree32fed153b988a3dbb9c691ba924d989de5d17578 /Modules/_hashopenssl.c
parentb17e49e0def23238b9e7f48c8a02e2d7bbf1f653 (diff)
downloadcpython-d5b3f6b7f9fc74438009af63f1de01bd77be9385.zip
cpython-d5b3f6b7f9fc74438009af63f1de01bd77be9385.tar.gz
cpython-d5b3f6b7f9fc74438009af63f1de01bd77be9385.tar.bz2
bpo-37630: Use SHA3 and SHAKE XOF from OpenSSL (GH-16049)
OpenSSL 1.1.1 comes with SHA3 and SHAKE builtin. Signed-off-by: Christian Heimes <christian@python.org> Automerge-Triggered-By: @tiran
Diffstat (limited to 'Modules/_hashopenssl.c')
-rw-r--r--Modules/_hashopenssl.c366
1 files changed, 349 insertions, 17 deletions
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index b55ac93..936b515 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -55,6 +55,9 @@ static PyModuleDef _hashlibmodule;
typedef struct {
PyTypeObject *EVPtype;
+#ifdef PY_OPENSSL_HAS_SHAKE
+ PyTypeObject *EVPXOFtype;
+#endif
} _hashlibstate;
static inline _hashlibstate*
@@ -79,8 +82,9 @@ typedef struct {
/*[clinic input]
module _hashlib
class _hashlib.HASH "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPtype"
+class _hashlib.HASHXOF "EVPobject *" "((_hashlibstate *)PyModule_GetState(module))->EVPXOFtype"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1adf85e8eb2ab979]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=813acc7b2d8f322c]*/
/* LCOV_EXCL_START */
@@ -114,6 +118,15 @@ _setException(PyObject *exc)
}
/* LCOV_EXCL_STOP */
+/* {Py_tp_new, NULL} doesn't block __new__ */
+static PyObject *
+_disabled_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyErr_Format(PyExc_TypeError,
+ "cannot create '%.100s' instances", _PyType_Name(type));
+ return NULL;
+}
+
static PyObject*
py_digest_name(const EVP_MD *md)
{
@@ -249,11 +262,9 @@ py_digest_by_name(const char *name)
}
static EVPobject *
-newEVPobject(void)
+newEVPobject(PyTypeObject *type)
{
- EVPobject *retval = (EVPobject *)PyObject_New(
- EVPobject, _hashlibstate_global->EVPtype
- );
+ EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, type);
if (retval == NULL) {
return NULL;
}
@@ -327,7 +338,7 @@ EVP_copy_impl(EVPobject *self)
{
EVPobject *newobj;
- if ( (newobj = newEVPobject())==NULL)
+ if ((newobj = newEVPobject(Py_TYPE(self))) == NULL)
return NULL;
if (!locked_EVP_MD_CTX_copy(newobj->ctx, self)) {
@@ -502,7 +513,8 @@ EVP_repr(EVPobject *self)
if (!name_obj) {
return NULL;
}
- repr = PyUnicode_FromFormat("<%U HASH object @ %p>", name_obj, self);
+ repr = PyUnicode_FromFormat("<%U %s object @ %p>",
+ name_obj, Py_TYPE(self)->tp_name, self);
Py_DECREF(name_obj);
return repr;
}
@@ -531,6 +543,7 @@ static PyType_Slot EVPtype_slots[] = {
{Py_tp_doc, (char *)hashtype_doc},
{Py_tp_methods, EVP_methods},
{Py_tp_getset, EVP_getseters},
+ {Py_tp_new, _disabled_new},
{0, 0},
};
@@ -542,19 +555,179 @@ static PyType_Spec EVPtype_spec = {
EVPtype_slots
};
+#ifdef PY_OPENSSL_HAS_SHAKE
+
+/*[clinic input]
+_hashlib.HASHXOF.digest as EVPXOF_digest
+
+ length: Py_ssize_t
+
+Return the digest value as a bytes object.
+[clinic start generated code]*/
+
+static PyObject *
+EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
+/*[clinic end generated code: output=ef9320c23280efad input=816a6537cea3d1db]*/
+{
+ EVP_MD_CTX *temp_ctx;
+ PyObject *retval = PyBytes_FromStringAndSize(NULL, length);
+
+ if (retval == NULL) {
+ return NULL;
+ }
+
+ temp_ctx = EVP_MD_CTX_new();
+ if (temp_ctx == NULL) {
+ Py_DECREF(retval);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
+ Py_DECREF(retval);
+ EVP_MD_CTX_free(temp_ctx);
+ return _setException(PyExc_ValueError);
+ }
+ if (!EVP_DigestFinalXOF(temp_ctx,
+ (unsigned char*)PyBytes_AS_STRING(retval),
+ length)) {
+ Py_DECREF(retval);
+ EVP_MD_CTX_free(temp_ctx);
+ _setException(PyExc_ValueError);
+ return NULL;
+ }
+
+ EVP_MD_CTX_free(temp_ctx);
+ return retval;
+}
+
+/*[clinic input]
+_hashlib.HASHXOF.hexdigest as EVPXOF_hexdigest
+
+ length: Py_ssize_t
+
+Return the digest value as a string of hexadecimal digits.
+[clinic start generated code]*/
+
+static PyObject *
+EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
+/*[clinic end generated code: output=eb3e6ee7788bf5b2 input=5f9d6a8f269e34df]*/
+{
+ unsigned char *digest;
+ EVP_MD_CTX *temp_ctx;
+ PyObject *retval;
+
+ digest = (unsigned char*)PyMem_Malloc(length);
+ if (digest == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ temp_ctx = EVP_MD_CTX_new();
+ if (temp_ctx == NULL) {
+ PyMem_Free(digest);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ /* Get the raw (binary) digest value */
+ if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
+ PyMem_Free(digest);
+ EVP_MD_CTX_free(temp_ctx);
+ return _setException(PyExc_ValueError);
+ }
+ if (!EVP_DigestFinalXOF(temp_ctx, digest, length)) {
+ PyMem_Free(digest);
+ EVP_MD_CTX_free(temp_ctx);
+ _setException(PyExc_ValueError);
+ return NULL;
+ }
+
+ EVP_MD_CTX_free(temp_ctx);
+
+ retval = _Py_strhex((const char *)digest, length);
+ PyMem_Free(digest);
+ return retval;
+}
+
+static PyMethodDef EVPXOF_methods[] = {
+ EVPXOF_DIGEST_METHODDEF
+ EVPXOF_HEXDIGEST_METHODDEF
+ {NULL, NULL} /* sentinel */
+};
+
+
+static PyObject *
+EVPXOF_get_digest_size(EVPobject *self, void *closure)
+{
+ return PyLong_FromLong(0);
+}
+
+static PyGetSetDef EVPXOF_getseters[] = {
+ {"digest_size",
+ (getter)EVPXOF_get_digest_size, NULL,
+ NULL,
+ NULL},
+ {NULL} /* Sentinel */
+};
+
+PyDoc_STRVAR(hashxoftype_doc,
+"HASHXOF(name, string=b\'\')\n"
+"--\n"
+"\n"
+"A hash is an object used to calculate a checksum of a string of information.\n"
+"\n"
+"Methods:\n"
+"\n"
+"update() -- updates the current digest with an additional string\n"
+"digest(length) -- return the current digest value\n"
+"hexdigest(length) -- return the current digest as a string of hexadecimal digits\n"
+"copy() -- return a copy of the current hash object\n"
+"\n"
+"Attributes:\n"
+"\n"
+"name -- the hash algorithm being used by this object\n"
+"digest_size -- number of bytes in this hashes output");
+
+static PyType_Slot EVPXOFtype_slots[] = {
+ {Py_tp_doc, (char *)hashxoftype_doc},
+ {Py_tp_methods, EVPXOF_methods},
+ {Py_tp_getset, EVPXOF_getseters},
+ {Py_tp_new, _disabled_new},
+ {0, 0},
+};
+
+static PyType_Spec EVPXOFtype_spec = {
+ "_hashlib.HASHXOF", /*tp_name*/
+ sizeof(EVPobject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ EVPXOFtype_slots
+};
+
+
+#endif
+
static PyObject *
-EVPnew(const EVP_MD *digest,
+EVPnew(PyObject *module, const EVP_MD *digest,
const unsigned char *cp, Py_ssize_t len, int usedforsecurity)
{
int result = 0;
EVPobject *self;
+ PyTypeObject *type = get_hashlib_state(module)->EVPtype;
if (!digest) {
PyErr_SetString(PyExc_ValueError, "unsupported hash type");
return NULL;
}
- if ((self = newEVPobject()) == NULL)
+#ifdef PY_OPENSSL_HAS_SHAKE
+ if ((EVP_MD_flags(digest) & EVP_MD_FLAG_XOF) == EVP_MD_FLAG_XOF) {
+ type = get_hashlib_state(module)->EVPXOFtype;
+ }
+#endif
+
+ if ((self = newEVPobject(type)) == NULL)
return NULL;
if (!usedforsecurity) {
@@ -614,7 +787,7 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj,
Py_buffer view = { 0 };
PyObject *ret_obj;
char *name;
- const EVP_MD *digest;
+ const EVP_MD *digest = NULL;
if (!PyArg_Parse(name_obj, "s", &name)) {
PyErr_SetString(PyExc_TypeError, "name must be a string");
@@ -626,7 +799,7 @@ EVP_new_impl(PyObject *module, PyObject *name_obj, PyObject *data_obj,
digest = py_digest_by_name(name);
- ret_obj = EVPnew(digest,
+ ret_obj = EVPnew(module, digest,
(unsigned char*)view.buf, view.len,
usedforsecurity);
@@ -645,7 +818,7 @@ EVP_fast_new(PyObject *module, PyObject *data_obj, const EVP_MD *digest,
if (data_obj)
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
- ret_obj = EVPnew(digest,
+ ret_obj = EVPnew(module, digest,
(unsigned char*)view.buf, view.len,
usedforsecurity);
@@ -775,6 +948,125 @@ _hashlib_openssl_sha512_impl(PyObject *module, PyObject *data_obj,
}
+#ifdef PY_OPENSSL_HAS_SHA3
+
+/*[clinic input]
+_hashlib.openssl_sha3_224
+
+ string as data_obj: object(py_default="b''") = NULL
+ *
+ usedforsecurity: bool = True
+
+Returns a sha3-224 hash object; optionally initialized with a string
+
+[clinic start generated code]*/
+
+static PyObject *
+_hashlib_openssl_sha3_224_impl(PyObject *module, PyObject *data_obj,
+ int usedforsecurity)
+/*[clinic end generated code: output=144641c1d144b974 input=e3a01b2888916157]*/
+{
+ return EVP_fast_new(module, data_obj, EVP_sha3_224(), usedforsecurity);
+}
+
+/*[clinic input]
+_hashlib.openssl_sha3_256
+
+ string as data_obj: object(py_default="b''") = NULL
+ *
+ usedforsecurity: bool = True
+
+Returns a sha3-256 hash object; optionally initialized with a string
+
+[clinic start generated code]*/
+
+static PyObject *
+_hashlib_openssl_sha3_256_impl(PyObject *module, PyObject *data_obj,
+ int usedforsecurity)
+/*[clinic end generated code: output=c61f1ab772d06668 input=e2908126c1b6deed]*/
+{
+ return EVP_fast_new(module, data_obj, EVP_sha3_256(), usedforsecurity);
+}
+
+/*[clinic input]
+_hashlib.openssl_sha3_384
+
+ string as data_obj: object(py_default="b''") = NULL
+ *
+ usedforsecurity: bool = True
+
+Returns a sha3-384 hash object; optionally initialized with a string
+
+[clinic start generated code]*/
+
+static PyObject *
+_hashlib_openssl_sha3_384_impl(PyObject *module, PyObject *data_obj,
+ int usedforsecurity)
+/*[clinic end generated code: output=f68e4846858cf0ee input=ec0edf5c792f8252]*/
+{
+ return EVP_fast_new(module, data_obj, EVP_sha3_384(), usedforsecurity);
+}
+
+/*[clinic input]
+_hashlib.openssl_sha3_512
+
+ string as data_obj: object(py_default="b''") = NULL
+ *
+ usedforsecurity: bool = True
+
+Returns a sha3-512 hash object; optionally initialized with a string
+
+[clinic start generated code]*/
+
+static PyObject *
+_hashlib_openssl_sha3_512_impl(PyObject *module, PyObject *data_obj,
+ int usedforsecurity)
+/*[clinic end generated code: output=2eede478c159354a input=64e2cc0c094d56f4]*/
+{
+ return EVP_fast_new(module, data_obj, EVP_sha3_512(), usedforsecurity);
+}
+#endif /* PY_OPENSSL_HAS_SHA3 */
+
+#ifdef PY_OPENSSL_HAS_SHAKE
+/*[clinic input]
+_hashlib.openssl_shake128
+
+ string as data_obj: object(py_default="b''") = NULL
+ *
+ usedforsecurity: bool = True
+
+Returns a shake128 variable hash object; optionally initialized with a string
+
+[clinic start generated code]*/
+
+static PyObject *
+_hashlib_openssl_shake128_impl(PyObject *module, PyObject *data_obj,
+ int usedforsecurity)
+/*[clinic end generated code: output=c68a0e30b4c09e1a input=b6d1e9566bacbb64]*/
+{
+ return EVP_fast_new(module, data_obj, EVP_shake128(), usedforsecurity);
+}
+
+/*[clinic input]
+_hashlib.openssl_shake256
+
+ string as data_obj: object(py_default="b''") = NULL
+ *
+ usedforsecurity: bool = True
+
+Returns a shake256 variable hash object; optionally initialized with a string
+
+[clinic start generated code]*/
+
+static PyObject *
+_hashlib_openssl_shake256_impl(PyObject *module, PyObject *data_obj,
+ int usedforsecurity)
+/*[clinic end generated code: output=d56387762dcad516 input=591b9b78c0498116]*/
+{
+ return EVP_fast_new(module, data_obj, EVP_shake256(), usedforsecurity);
+}
+#endif /* PY_OPENSSL_HAS_SHAKE */
+
/*[clinic input]
_hashlib.pbkdf2_hmac as pbkdf2_hmac
@@ -1163,6 +1455,12 @@ static struct PyMethodDef EVP_functions[] = {
_HASHLIB_OPENSSL_SHA256_METHODDEF
_HASHLIB_OPENSSL_SHA384_METHODDEF
_HASHLIB_OPENSSL_SHA512_METHODDEF
+ _HASHLIB_OPENSSL_SHA3_224_METHODDEF
+ _HASHLIB_OPENSSL_SHA3_256_METHODDEF
+ _HASHLIB_OPENSSL_SHA3_384_METHODDEF
+ _HASHLIB_OPENSSL_SHA3_512_METHODDEF
+ _HASHLIB_OPENSSL_SHAKE128_METHODDEF
+ _HASHLIB_OPENSSL_SHAKE256_METHODDEF
{NULL, NULL} /* Sentinel */
};
@@ -1174,6 +1472,9 @@ hashlib_traverse(PyObject *m, visitproc visit, void *arg)
{
_hashlibstate *state = get_hashlib_state(m);
Py_VISIT(state->EVPtype);
+#ifdef PY_OPENSSL_HAS_SHAKE
+ Py_VISIT(state->EVPXOFtype);
+#endif
return 0;
}
@@ -1182,6 +1483,9 @@ hashlib_clear(PyObject *m)
{
_hashlibstate *state = get_hashlib_state(m);
Py_CLEAR(state->EVPtype);
+#ifdef PY_OPENSSL_HAS_SHAKE
+ Py_CLEAR(state->EVPXOFtype);
+#endif
return 0;
}
@@ -1208,6 +1512,10 @@ PyMODINIT_FUNC
PyInit__hashlib(void)
{
PyObject *m, *openssl_md_meth_names;
+ _hashlibstate *state = NULL;
+#ifdef PY_OPENSSL_HAS_SHAKE
+ PyObject *bases;
+#endif
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
/* Load all digest algorithms and initialize cpuid */
@@ -1225,10 +1533,37 @@ PyInit__hashlib(void)
if (m == NULL)
return NULL;
+ state = get_hashlib_state(m);
+
PyTypeObject *EVPtype = (PyTypeObject *)PyType_FromSpec(&EVPtype_spec);
- if (EVPtype == NULL)
+ if (EVPtype == NULL) {
+ Py_DECREF(m);
return NULL;
- get_hashlib_state(m)->EVPtype = EVPtype;
+ }
+ state->EVPtype = EVPtype;
+
+ Py_INCREF((PyObject *)state->EVPtype);
+ PyModule_AddObject(m, "HASH", (PyObject *)state->EVPtype);
+
+#ifdef PY_OPENSSL_HAS_SHAKE
+ bases = PyTuple_Pack(1, (PyObject *)EVPtype);
+ if (bases == NULL) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ PyTypeObject *EVPXOFtype = (PyTypeObject *)PyType_FromSpecWithBases(
+ &EVPXOFtype_spec, bases
+ );
+ Py_DECREF(bases);
+ if (EVPXOFtype == NULL) {
+ Py_DECREF(m);
+ return NULL;
+ }
+ state->EVPXOFtype = EVPXOFtype;
+
+ Py_INCREF((PyObject *)state->EVPXOFtype);
+ PyModule_AddObject(m, "HASHXOF", (PyObject *)state->EVPXOFtype);
+#endif
openssl_md_meth_names = generate_hash_name_list();
if (openssl_md_meth_names == NULL) {
@@ -1240,9 +1575,6 @@ PyInit__hashlib(void)
return NULL;
}
- Py_INCREF((PyObject *)get_hashlib_state(m)->EVPtype);
- PyModule_AddObject(m, "HASH", (PyObject *)get_hashlib_state(m)->EVPtype);
-
PyState_AddModule(m, &_hashlibmodule);
return m;
}