aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules/sha3module.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/sha3module.c')
-rw-r--r--Modules/sha3module.c202
1 files changed, 115 insertions, 87 deletions
diff --git a/Modules/sha3module.c b/Modules/sha3module.c
index cfbf0cbcc04..5764556bb68 100644
--- a/Modules/sha3module.c
+++ b/Modules/sha3module.c
@@ -9,6 +9,7 @@
* Greg Stein (gstein@lyra.org)
* Trevor Perrin (trevp@trevp.net)
* Gregory P. Smith (greg@krypto.org)
+ * Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
*
* Copyright (C) 2012-2022 Christian Heimes (christian@python.org)
* Licensed to PSF under a Contributor Agreement.
@@ -24,8 +25,23 @@
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "hashlib.h"
+#include "_hacl/Hacl_Hash_SHA3.h"
+
+/*
+ * Assert that 'LEN' can be safely casted to uint32_t.
+ *
+ * The 'LEN' parameter should be convertible to Py_ssize_t.
+ */
+#if !defined(NDEBUG) && (PY_SSIZE_T_MAX > UINT32_MAX)
+#define CHECK_HACL_UINT32_T_LENGTH(LEN) assert((LEN) < (Py_ssize_t)UINT32_MAX)
+#else
+#define CHECK_HACL_UINT32_T_LENGTH(LEN)
+#endif
+
#define SHA3_MAX_DIGESTSIZE 64 /* 64 Bytes (512 Bits) for 224 to 512 */
+// --- Module state -----------------------------------------------------------
+
typedef struct {
PyTypeObject *sha3_224_type;
PyTypeObject *sha3_256_type;
@@ -43,33 +59,34 @@ sha3_get_state(PyObject *module)
return (SHA3State *)state;
}
-/*[clinic input]
-module _sha3
-class _sha3.sha3_224 "SHA3object *" "&SHA3_224typ"
-class _sha3.sha3_256 "SHA3object *" "&SHA3_256typ"
-class _sha3.sha3_384 "SHA3object *" "&SHA3_384typ"
-class _sha3.sha3_512 "SHA3object *" "&SHA3_512typ"
-class _sha3.shake_128 "SHA3object *" "&SHAKE128type"
-class _sha3.shake_256 "SHA3object *" "&SHAKE256type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b8a53680f370285a]*/
+// --- Module objects ---------------------------------------------------------
/* The structure for storing SHA3 info */
-#include "_hacl/Hacl_Hash_SHA3.h"
-
typedef struct {
- PyObject_HEAD
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
+ HASHLIB_OBJECT_HEAD
Hacl_Hash_SHA3_state_t *hash_state;
} SHA3object;
#define _SHA3object_CAST(op) ((SHA3object *)(op))
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _sha3
+class _sha3.sha3_224 "SHA3object *" "&PyType_Type"
+class _sha3.sha3_256 "SHA3object *" "&PyType_Type"
+class _sha3.sha3_384 "SHA3object *" "&PyType_Type"
+class _sha3.sha3_512 "SHA3object *" "&PyType_Type"
+class _sha3.shake_128 "SHA3object *" "&PyType_Type"
+class _sha3.shake_256 "SHA3object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ccd22550c7fb99bf]*/
+
#include "clinic/sha3module.c.h"
+// --- SHA-3 object interface -------------------------------------------------
+
static SHA3object *
newSHA3object(PyTypeObject *type)
{
@@ -163,16 +180,12 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data_obj, int usedforsecurity,
if (data) {
GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- /* We do not initialize self->lock here as this is the constructor
- * where it is not yet possible to have concurrent access. */
- Py_BEGIN_ALLOW_THREADS
- sha3_update(self->hash_state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- sha3_update(self->hash_state, buf.buf, buf.len);
- }
+ /* Do not use self->mutex here as this is the constructor
+ * where it is not yet possible to have concurrent access. */
+ HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(
+ buf.len,
+ sha3_update(self->hash_state, buf.buf, buf.len)
+ );
}
PyBuffer_Release(&buf);
@@ -226,21 +239,22 @@ SHA3_traverse(PyObject *self, visitproc visit, void *arg)
/*[clinic input]
_sha3.sha3_224.copy
+ cls: defining_class
+
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
-_sha3_sha3_224_copy_impl(SHA3object *self)
-/*[clinic end generated code: output=6c537411ecdcda4c input=93a44aaebea51ba8]*/
+_sha3_sha3_224_copy_impl(SHA3object *self, PyTypeObject *cls)
+/*[clinic end generated code: output=13958b44c244013e input=7134b4dc0a2fbcac]*/
{
SHA3object *newobj;
-
- if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) {
+ if ((newobj = newSHA3object(cls)) == NULL) {
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
newobj->hash_state = Hacl_Hash_SHA3_copy(self->hash_state);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (newobj->hash_state == NULL) {
Py_DECREF(newobj);
return PyErr_NoMemory();
@@ -262,9 +276,9 @@ _sha3_sha3_224_digest_impl(SHA3object *self)
unsigned char digest[SHA3_MAX_DIGESTSIZE];
// This function errors out if the algorithm is SHAKE. Here, we know this
// not to be the case, and therefore do not perform error checking.
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
(void)Hacl_Hash_SHA3_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest,
Hacl_Hash_SHA3_hash_len(self->hash_state));
}
@@ -281,9 +295,9 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self)
/*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/
{
unsigned char digest[SHA3_MAX_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
(void)Hacl_Hash_SHA3_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest,
Hacl_Hash_SHA3_hash_len(self->hash_state));
}
@@ -303,22 +317,11 @@ _sha3_sha3_224_update_impl(SHA3object *self, PyObject *data)
/*[clinic end generated code: output=390b7abf7c9795a5 input=a887f54dcc4ae227]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
-
- if (!self->use_mutex && buf.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- sha3_update(self->hash_state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- sha3_update(self->hash_state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ sha3_update(self->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -472,69 +475,94 @@ SHA3_TYPE_SPEC(sha3_384_spec, "sha3_384", sha3_384_slots);
SHA3_TYPE_SLOTS(sha3_512_slots, sha3_512__doc__, SHA3_methods, SHA3_getseters);
SHA3_TYPE_SPEC(sha3_512_spec, "sha3_512", sha3_512_slots);
-static PyObject *
-_SHAKE_digest(PyObject *op, unsigned long digestlen, int hex)
+static int
+sha3_shake_check_digest_length(Py_ssize_t length)
{
- unsigned char *digest = NULL;
- PyObject *result = NULL;
- SHA3object *self = _SHA3object_CAST(op);
-
- if (digestlen >= (1 << 29)) {
- PyErr_SetString(PyExc_ValueError, "length is too large");
- return NULL;
- }
- digest = (unsigned char*)PyMem_Malloc(digestlen);
- if (digest == NULL) {
- return PyErr_NoMemory();
- }
-
- /* Get the raw (binary) digest value. The HACL functions errors out if:
- * - the algorithm is not shake -- not the case here
- * - the output length is zero -- we follow the existing behavior and return
- * an empty digest, without raising an error */
- if (digestlen > 0) {
- (void)Hacl_Hash_SHA3_squeeze(self->hash_state, digest, digestlen);
- }
- if (hex) {
- result = _Py_strhex((const char *)digest, digestlen);
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative digest length");
+ return -1;
}
- else {
- result = PyBytes_FromStringAndSize((const char *)digest, digestlen);
+ if ((size_t)length >= (1 << 29)) {
+ /*
+ * Raise OverflowError to match the semantics of OpenSSL SHAKE
+ * when the digest length exceeds the range of a 'Py_ssize_t';
+ * the exception message will however be different in this case.
+ */
+ PyErr_SetString(PyExc_OverflowError, "digest length is too large");
+ return -1;
}
- PyMem_Free(digest);
- return result;
+ return 0;
}
/*[clinic input]
_sha3.shake_128.digest
- length: unsigned_long
+ length: Py_ssize_t
Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
-_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length)
-/*[clinic end generated code: output=2313605e2f87bb8f input=93d6d6ff32904f18]*/
+_sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length)
+/*[clinic end generated code: output=6c53fb71a6cff0a0 input=be03ade4b31dd54c]*/
{
- return _SHAKE_digest((PyObject *)self, length, 0);
+ if (sha3_shake_check_digest_length(length) < 0) {
+ return NULL;
+ }
+
+ /*
+ * Hacl_Hash_SHA3_squeeze() fails if the algorithm is not SHAKE,
+ * or if the length is 0. In the latter case, we follow OpenSSL's
+ * behavior and return an empty digest, without raising an error.
+ */
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+
+ CHECK_HACL_UINT32_T_LENGTH(length);
+ PyObject *digest = PyBytes_FromStringAndSize(NULL, length);
+ uint8_t *buffer = (uint8_t *)PyBytes_AS_STRING(digest);
+ HASHLIB_ACQUIRE_LOCK(self);
+ (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length);
+ HASHLIB_RELEASE_LOCK(self);
+ return digest;
}
/*[clinic input]
_sha3.shake_128.hexdigest
- length: unsigned_long
+ length: Py_ssize_t
Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
-_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length)
-/*[clinic end generated code: output=bf8e2f1e490944a8 input=562d74e7060b56ab]*/
+_sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length)
+/*[clinic end generated code: output=a27412d404f64512 input=0d84d05d7a8ccd37]*/
{
- return _SHAKE_digest((PyObject *)self, length, 1);
+ if (sha3_shake_check_digest_length(length) < 0) {
+ return NULL;
+ }
+
+ /* See _sha3_shake_128_digest_impl() for the fast path rationale. */
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
+ }
+
+ CHECK_HACL_UINT32_T_LENGTH(length);
+ uint8_t *buffer = PyMem_Malloc(length);
+ if (buffer == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ HASHLIB_ACQUIRE_LOCK(self);
+ (void)Hacl_Hash_SHA3_squeeze(self->hash_state, buffer, (uint32_t)length);
+ HASHLIB_RELEASE_LOCK(self);
+ PyObject *digest = _Py_strhex((const char *)buffer, length);
+ PyMem_Free(buffer);
+ return digest;
}
static PyObject *