aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_hashopenssl.c121
-rw-r--r--Modules/_heapqmodule.c37
-rw-r--r--Modules/blake2module.c69
-rw-r--r--Modules/clinic/sha3module.c.h38
-rw-r--r--Modules/hashlib.h99
-rw-r--r--Modules/hmacmodule.c288
-rw-r--r--Modules/md5module.c78
-rw-r--r--Modules/sha1module.c78
-rw-r--r--Modules/sha2module.c166
-rw-r--r--Modules/sha3module.c193
10 files changed, 501 insertions, 666 deletions
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index ce9603d5db8..90a7391ebb0 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -255,7 +255,8 @@ py_hashentry_table_new(void) {
return NULL;
}
-/* Module state */
+// --- Module state -----------------------------------------------------------
+
static PyModuleDef _hashlibmodule;
typedef struct {
@@ -277,35 +278,33 @@ get_hashlib_state(PyObject *module)
return (_hashlibstate *)state;
}
+// --- Module objects ---------------------------------------------------------
+
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
EVP_MD_CTX *ctx; /* OpenSSL message digest context */
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex; /* OpenSSL context lock */
} HASHobject;
#define HASHobject_CAST(op) ((HASHobject *)(op))
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
HMAC_CTX *ctx; /* OpenSSL hmac context */
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex; /* HMAC context lock */
} HMACobject;
#define HMACobject_CAST(op) ((HMACobject *)(op))
-#include "clinic/_hashopenssl.c.h"
+// --- Module clinic configuration --------------------------------------------
+
/*[clinic input]
module _hashlib
-class _hashlib.HASH "HASHobject *" "((_hashlibstate *)PyModule_GetState(module))->HASH_type"
-class _hashlib.HASHXOF "HASHobject *" "((_hashlibstate *)PyModule_GetState(module))->HASHXOF_type"
-class _hashlib.HMAC "HMACobject *" "((_hashlibstate *)PyModule_GetState(module))->HMAC_type"
+class _hashlib.HASH "HASHobject *" "&PyType_Type"
+class _hashlib.HASHXOF "HASHobject *" "&PyType_Type"
+class _hashlib.HMAC "HMACobject *" "&PyType_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=eb805ce4b90b1b31]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6b5c9ce5c28bdc58]*/
+#include "clinic/_hashopenssl.c.h"
/* LCOV_EXCL_START */
@@ -700,9 +699,9 @@ static int
_hashlib_HASH_copy_locked(HASHobject *self, EVP_MD_CTX *new_ctx_p)
{
int result;
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
result = EVP_MD_CTX_copy(new_ctx_p, self->ctx);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (result == 0) {
notify_smart_ssl_error_occurred_in(Py_STRINGIFY(EVP_MD_CTX_copy));
return -1;
@@ -802,27 +801,13 @@ _hashlib_HASH_update_impl(HASHobject *self, PyObject *obj)
{
int result;
Py_buffer view;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
-
- if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- result = _hashlib_HASH_hash(self, view.buf, view.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- result = _hashlib_HASH_hash(self, view.buf, view.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, view.len,
+ result = _hashlib_HASH_hash(self, view.buf, view.len)
+ );
PyBuffer_Release(&view);
-
- if (result == -1)
- return NULL;
- Py_RETURN_NONE;
+ return result < 0 ? NULL : Py_None;
}
static PyMethodDef HASH_methods[] = {
@@ -938,8 +923,18 @@ _hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length)
/*[clinic end generated code: output=dcb09335dd2fe908 input=3eb034ce03c55b21]*/
{
EVP_MD_CTX *temp_ctx;
- PyObject *retval = PyBytes_FromStringAndSize(NULL, length);
+ PyObject *retval;
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative digest length");
+ return NULL;
+ }
+
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+ }
+
+ retval = PyBytes_FromStringAndSize(NULL, length);
if (retval == NULL) {
return NULL;
}
@@ -986,9 +981,18 @@ _hashlib_HASHXOF_hexdigest_impl(HASHobject *self, Py_ssize_t length)
EVP_MD_CTX *temp_ctx;
PyObject *retval;
+ if (length < 0) {
+ PyErr_SetString(PyExc_ValueError, "negative digest length");
+ return NULL;
+ }
+
+ if (length == 0) {
+ return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
+ }
+
digest = (unsigned char*)PyMem_Malloc(length);
if (digest == NULL) {
- PyErr_NoMemory();
+ (void)PyErr_NoMemory();
return NULL;
}
@@ -1125,15 +1129,12 @@ _hashlib_HASH(PyObject *module, const char *digestname, PyObject *data_obj,
}
if (view.buf && view.len) {
- if (view.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
- result = _hashlib_HASH_hash(self, view.buf, view.len);
- Py_END_ALLOW_THREADS
- } else {
- result = _hashlib_HASH_hash(self, view.buf, view.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(
+ view.len,
+ result = _hashlib_HASH_hash(self, view.buf, view.len)
+ );
if (result == -1) {
assert(PyErr_Occurred());
Py_CLEAR(self);
@@ -1794,9 +1795,9 @@ static int
locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
{
int result;
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
result = HMAC_CTX_copy(new_ctx_p, self->ctx);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (result == 0) {
notify_smart_ssl_error_occurred_in(Py_STRINGIFY(HMAC_CTX_copy));
return -1;
@@ -1827,24 +1828,12 @@ _hmac_update(HMACobject *self, PyObject *obj)
Py_buffer view = {0};
GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0);
-
- if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
- self->use_mutex = true;
- }
- if (self->use_mutex) {
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex);
- r = HMAC_Update(self->ctx,
- (const unsigned char *)view.buf,
- (size_t)view.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- r = HMAC_Update(self->ctx,
- (const unsigned char *)view.buf,
- (size_t)view.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, view.len,
+ r = HMAC_Update(
+ self->ctx, (const unsigned char *)view.buf, (size_t)view.len
+ )
+ );
PyBuffer_Release(&view);
if (r == 0) {
diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c
index 7784cdcd9ff..560fe431fca 100644
--- a/Modules/_heapqmodule.c
+++ b/Modules/_heapqmodule.c
@@ -12,6 +12,7 @@ annotated by François Pinard, and converted to C by Raymond Hettinger.
#include "Python.h"
#include "pycore_list.h" // _PyList_ITEMS(), _PyList_AppendTakeRef()
+#include "pycore_pyatomic_ft_wrappers.h"
#include "clinic/_heapqmodule.c.h"
@@ -59,8 +60,8 @@ siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
arr = _PyList_ITEMS(heap);
parent = arr[parentpos];
newitem = arr[pos];
- arr[parentpos] = newitem;
- arr[pos] = parent;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[parentpos], newitem);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], parent);
pos = parentpos;
}
return 0;
@@ -108,8 +109,8 @@ siftup(PyListObject *heap, Py_ssize_t pos)
/* Move the smaller child up. */
tmp1 = arr[childpos];
tmp2 = arr[pos];
- arr[childpos] = tmp2;
- arr[pos] = tmp1;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[childpos], tmp2);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], tmp1);
pos = childpos;
}
/* Bubble it up to its final resting place (by sifting its parents down). */
@@ -172,8 +173,9 @@ heappop_internal(PyObject *heap, int siftup_func(PyListObject *, Py_ssize_t))
if (!n)
return lastelt;
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, lastelt);
- if (siftup_func((PyListObject *)heap, 0)) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], lastelt);
+ if (siftup_func(list, 0)) {
Py_DECREF(returnitem);
return NULL;
}
@@ -208,8 +210,9 @@ heapreplace_internal(PyObject *heap, PyObject *item, int siftup_func(PyListObjec
}
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, Py_NewRef(item));
- if (siftup_func((PyListObject *)heap, 0)) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], Py_NewRef(item));
+ if (siftup_func(list, 0)) {
Py_DECREF(returnitem);
return NULL;
}
@@ -284,8 +287,9 @@ _heapq_heappushpop_impl(PyObject *module, PyObject *heap, PyObject *item)
}
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, Py_NewRef(item));
- if (siftup((PyListObject *)heap, 0)) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], Py_NewRef(item));
+ if (siftup(list, 0)) {
Py_DECREF(returnitem);
return NULL;
}
@@ -437,8 +441,8 @@ siftdown_max(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos)
arr = _PyList_ITEMS(heap);
parent = arr[parentpos];
newitem = arr[pos];
- arr[parentpos] = newitem;
- arr[pos] = parent;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[parentpos], newitem);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], parent);
pos = parentpos;
}
return 0;
@@ -486,8 +490,8 @@ siftup_max(PyListObject *heap, Py_ssize_t pos)
/* Move the smaller child up. */
tmp1 = arr[childpos];
tmp2 = arr[pos];
- arr[childpos] = tmp2;
- arr[pos] = tmp1;
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[childpos], tmp2);
+ FT_ATOMIC_STORE_PTR_RELAXED(arr[pos], tmp1);
pos = childpos;
}
/* Bubble it up to its final resting place (by sifting its parents down). */
@@ -621,8 +625,9 @@ _heapq_heappushpop_max_impl(PyObject *module, PyObject *heap, PyObject *item)
}
returnitem = PyList_GET_ITEM(heap, 0);
- PyList_SET_ITEM(heap, 0, Py_NewRef(item));
- if (siftup_max((PyListObject *)heap, 0) < 0) {
+ PyListObject *list = _PyList_CAST(heap);
+ FT_ATOMIC_STORE_PTR_RELAXED(list->ob_item[0], Py_NewRef(item));
+ if (siftup_max(list, 0) < 0) {
Py_DECREF(returnitem);
return NULL;
}
diff --git a/Modules/blake2module.c b/Modules/blake2module.c
index 2ce8c0cd3d7..6c4349ac06b 100644
--- a/Modules/blake2module.c
+++ b/Modules/blake2module.c
@@ -2,6 +2,7 @@
* Written in 2013 by Dmitry Chestnykh <dmitry@codingrobots.com>
* Modified for CPython by Christian Heimes <christian@python.org>
* Updated to use HACL* by Jonathan Protzenko <jonathan@protzenko.fr>
+ * Additional work by Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
*
* To the extent possible under law, the author have dedicated all
* copyright and related and neighboring rights to this software to
@@ -352,7 +353,7 @@ type_to_impl(PyTypeObject *type)
}
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
union {
Hacl_Hash_Blake2s_state_t *blake2s_state;
Hacl_Hash_Blake2b_state_t *blake2b_state;
@@ -364,21 +365,22 @@ typedef struct {
#endif
};
blake2_impl impl;
- bool use_mutex;
- PyMutex mutex;
} Blake2Object;
#define _Blake2Object_CAST(op) ((Blake2Object *)(op))
-#include "clinic/blake2module.c.h"
+// --- Module clinic configuration --------------------------------------------
/*[clinic input]
module _blake2
-class _blake2.blake2b "Blake2Object *" "&PyBlake2_BLAKE2bType"
-class _blake2.blake2s "Blake2Object *" "&PyBlake2_BLAKE2sType"
+class _blake2.blake2b "Blake2Object *" "&PyType_Type"
+class _blake2.blake2s "Blake2Object *" "&PyType_Type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b7526666bd18af83]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=86b0972b0c41b3d0]*/
+
+#include "clinic/blake2module.c.h"
+// --- BLAKE-2 object interface -----------------------------------------------
static Blake2Object *
new_Blake2Object(PyTypeObject *type)
@@ -422,7 +424,7 @@ new_Blake2Object(PyTypeObject *type)
} while (0)
static void
-update(Blake2Object *self, uint8_t *buf, Py_ssize_t len)
+blake2_update_unlocked(Blake2Object *self, uint8_t *buf, Py_ssize_t len)
{
switch (self->impl) {
// blake2b_256_state and blake2s_128_state must be if'd since
@@ -646,14 +648,12 @@ py_blake2_new(PyTypeObject *type, PyObject *data, int digest_size,
if (data != NULL) {
Py_buffer buf;
GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
- if (buf.len >= HASHLIB_GIL_MINSIZE) {
- Py_BEGIN_ALLOW_THREADS
- update(self, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update(self, 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,
+ blake2_update_unlocked(self, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -744,7 +744,7 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data_obj, int digest_size,
}
static int
-blake2_blake2b_copy_locked(Blake2Object *self, Blake2Object *cpy)
+blake2_blake2b_copy_unlocked(Blake2Object *self, Blake2Object *cpy)
{
assert(cpy != NULL);
#define BLAKE2_COPY(TYPE, STATE_ATTR) \
@@ -801,9 +801,9 @@ _blake2_blake2b_copy_impl(Blake2Object *self)
return NULL;
}
- ENTER_HASHLIB(self);
- rc = blake2_blake2b_copy_locked(self, cpy);
- LEAVE_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
+ rc = blake2_blake2b_copy_unlocked(self, cpy);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(cpy);
return NULL;
@@ -825,25 +825,12 @@ _blake2_blake2b_update_impl(Blake2Object *self, PyObject *data)
/*[clinic end generated code: output=99330230068e8c99 input=ffc4aa6a6a225d31]*/
{
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);
- update(self, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- }
- else {
- update(self, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ blake2_update_unlocked(self, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
-
Py_RETURN_NONE;
}
@@ -881,9 +868,9 @@ _blake2_blake2b_digest_impl(Blake2Object *self)
/*[clinic end generated code: output=31ab8ad477f4a2f7 input=7d21659e9c5fff02]*/
{
uint8_t digest_length = 0, digest[HACL_HASH_BLAKE2B_OUT_BYTES];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
digest_length = blake2_blake2b_compute_digest(self, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, digest_length);
}
@@ -898,9 +885,9 @@ _blake2_blake2b_hexdigest_impl(Blake2Object *self)
/*[clinic end generated code: output=5ef54b138db6610a input=76930f6946351f56]*/
{
uint8_t digest_length = 0, digest[HACL_HASH_BLAKE2B_OUT_BYTES];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
digest_length = blake2_blake2b_compute_digest(self, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, digest_length);
}
diff --git a/Modules/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h
index 121be2c0758..d6d44bf4c51 100644
--- a/Modules/clinic/sha3module.c.h
+++ b/Modules/clinic/sha3module.c.h
@@ -6,7 +6,7 @@ preserve
# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
-#include "pycore_long.h" // _PyLong_UnsignedLong_Converter()
+#include "pycore_abstract.h" // _PyNumber_Index()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(py_sha3_new__doc__,
@@ -179,7 +179,7 @@ PyDoc_STRVAR(_sha3_shake_128_digest__doc__,
{"digest", _PyCFunction_CAST(_sha3_shake_128_digest), METH_FASTCALL|METH_KEYWORDS, _sha3_shake_128_digest__doc__},
static PyObject *
-_sha3_shake_128_digest_impl(SHA3object *self, unsigned long length);
+_sha3_shake_128_digest_impl(SHA3object *self, Py_ssize_t length);
static PyObject *
_sha3_shake_128_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -213,15 +213,24 @@ _sha3_shake_128_digest(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
};
#undef KWTUPLE
PyObject *argsbuf[1];
- unsigned long length;
+ Py_ssize_t length;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
- if (!_PyLong_UnsignedLong_Converter(args[0], &length)) {
- goto exit;
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[0]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ length = ival;
}
return_value = _sha3_shake_128_digest_impl((SHA3object *)self, length);
@@ -239,7 +248,7 @@ PyDoc_STRVAR(_sha3_shake_128_hexdigest__doc__,
{"hexdigest", _PyCFunction_CAST(_sha3_shake_128_hexdigest), METH_FASTCALL|METH_KEYWORDS, _sha3_shake_128_hexdigest__doc__},
static PyObject *
-_sha3_shake_128_hexdigest_impl(SHA3object *self, unsigned long length);
+_sha3_shake_128_hexdigest_impl(SHA3object *self, Py_ssize_t length);
static PyObject *
_sha3_shake_128_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -273,19 +282,28 @@ _sha3_shake_128_hexdigest(PyObject *self, PyObject *const *args, Py_ssize_t narg
};
#undef KWTUPLE
PyObject *argsbuf[1];
- unsigned long length;
+ Py_ssize_t length;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
- if (!_PyLong_UnsignedLong_Converter(args[0], &length)) {
- goto exit;
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[0]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ length = ival;
}
return_value = _sha3_shake_128_hexdigest_impl((SHA3object *)self, length);
exit:
return return_value;
}
-/*[clinic end generated code: output=65e437799472b89f input=a9049054013a1b77]*/
+/*[clinic end generated code: output=c17e3ec670afe253 input=a9049054013a1b77]*/
diff --git a/Modules/hashlib.h b/Modules/hashlib.h
index e82ec92be25..9a7e72f34a7 100644
--- a/Modules/hashlib.h
+++ b/Modules/hashlib.h
@@ -34,47 +34,78 @@
/*
* Helper code to synchronize access to the hash object when the GIL is
- * released around a CPU consuming hashlib operation. All code paths that
- * access a mutable part of obj must be enclosed in an ENTER_HASHLIB /
- * LEAVE_HASHLIB block or explicitly acquire and release the lock inside
- * a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for
- * an operation.
+ * released around a CPU consuming hashlib operation.
*
- * These only drop the GIL if the lock acquisition itself is likely to
- * block. Thus the non-blocking acquire gating the GIL release for a
- * blocking lock acquisition. The intent of these macros is to surround
- * the assumed always "fast" operations that you aren't releasing the
- * GIL around. Otherwise use code similar to what you see in hash
- * function update() methods.
+ * Code accessing a mutable part of the hash object must be enclosed in
+ * an HASHLIB_{ACQUIRE,RELEASE}_LOCK block or explicitly acquire and release
+ * the mutex inside a Py_BEGIN_ALLOW_THREADS -- Py_END_ALLOW_THREADS block if
+ * they wish to release the GIL for an operation.
*/
-#include "pythread.h"
-#define ENTER_HASHLIB(obj) \
- if ((obj)->use_mutex) { \
- PyMutex_Lock(&(obj)->mutex); \
- }
-#define LEAVE_HASHLIB(obj) \
- if ((obj)->use_mutex) { \
- PyMutex_Unlock(&(obj)->mutex); \
- }
+#define HASHLIB_OBJECT_HEAD \
+ PyObject_HEAD \
+ /* Guard against race conditions during incremental update(). */ \
+ PyMutex mutex;
-#ifdef Py_GIL_DISABLED
-#define HASHLIB_INIT_MUTEX(obj) \
- do { \
- (obj)->mutex = (PyMutex){0}; \
- (obj)->use_mutex = true; \
+#define HASHLIB_INIT_MUTEX(OBJ) \
+ do { \
+ (OBJ)->mutex = (PyMutex){0}; \
} while (0)
-#else
-#define HASHLIB_INIT_MUTEX(obj) \
- do { \
- (obj)->mutex = (PyMutex){0}; \
- (obj)->use_mutex = false; \
+
+#define HASHLIB_ACQUIRE_LOCK(OBJ) PyMutex_Lock(&(OBJ)->mutex)
+#define HASHLIB_RELEASE_LOCK(OBJ) PyMutex_Unlock(&(OBJ)->mutex)
+
+/*
+ * Message length above which the GIL is to be released
+ * when performing hashing operations.
+ */
+#define HASHLIB_GIL_MINSIZE 2048
+
+// Macros for executing code while conditionally holding the GIL.
+//
+// These only drop the GIL if the lock acquisition itself is likely to
+// block. Thus the non-blocking acquire gating the GIL release for a
+// blocking lock acquisition. The intent of these macros is to surround
+// the assumed always "fast" operations that you aren't releasing the
+// GIL around.
+
+/*
+ * Execute a suite of C statements 'STATEMENTS'.
+ *
+ * The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold.
+ */
+#define HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(SIZE, STATEMENTS) \
+ do { \
+ if ((SIZE) > HASHLIB_GIL_MINSIZE) { \
+ Py_BEGIN_ALLOW_THREADS \
+ STATEMENTS; \
+ Py_END_ALLOW_THREADS \
+ } \
+ else { \
+ STATEMENTS; \
+ } \
} while (0)
-#endif
-/* TODO(gpshead): We should make this a module or class attribute
- * to allow the user to optimize based on the platform they're using. */
-#define HASHLIB_GIL_MINSIZE 2048
+/*
+ * Lock 'OBJ' and execute a suite of C statements 'STATEMENTS'.
+ *
+ * The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold.
+ */
+#define HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(OBJ, SIZE, STATEMENTS) \
+ do { \
+ if ((SIZE) > HASHLIB_GIL_MINSIZE) { \
+ Py_BEGIN_ALLOW_THREADS \
+ HASHLIB_ACQUIRE_LOCK(OBJ); \
+ STATEMENTS; \
+ HASHLIB_RELEASE_LOCK(OBJ); \
+ Py_END_ALLOW_THREADS \
+ } \
+ else { \
+ HASHLIB_ACQUIRE_LOCK(OBJ); \
+ STATEMENTS; \
+ HASHLIB_RELEASE_LOCK(OBJ); \
+ } \
+ } while (0)
static inline int
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)
diff --git a/Modules/hmacmodule.c b/Modules/hmacmodule.c
index f6ed35ae742..e7a5ccbb19b 100644
--- a/Modules/hmacmodule.c
+++ b/Modules/hmacmodule.c
@@ -216,105 +216,6 @@ typedef struct py_hmac_hacl_api {
#endif
/*
- * Call the HACL* HMAC-HASH update function on the given data.
- *
- * The magnitude of 'LEN' is not checked and thus 'LEN' must be
- * safely convertible to a uint32_t value.
- */
-#define Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, LEN) \
- Hacl_Streaming_HMAC_update(HACL_STATE, BUF, (uint32_t)(LEN))
-
-/*
- * Call the HACL* HMAC-HASH update function on the given data.
- *
- * On DEBUG builds, the 'ERRACTION' statements are executed if
- * the update() call returned a non-successful HACL* exit code.
- *
- * The buffer 'BUF' and its length 'LEN' are left untouched.
- *
- * The formal signature of this macro is:
- *
- * (HACL_HMAC_state *, uint8_t *, uint32_t, (C statements))
- */
-#ifndef NDEBUG
-#define Py_HMAC_HACL_UPDATE_ONCE( \
- HACL_STATE, BUF, LEN, \
- ERRACTION \
-) \
- do { \
- Py_CHECK_HACL_UINT32_T_LENGTH(LEN); \
- hacl_errno_t code = Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, LEN); \
- if (_hacl_convert_errno(code) < 0) { \
- ERRACTION; \
- } \
- } while (0)
-#else
-#define Py_HMAC_HACL_UPDATE_ONCE( \
- HACL_STATE, BUF, LEN, \
- _ERRACTION \
-) \
- do { \
- (void)Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, (LEN)); \
- } while (0)
-#endif
-
-/*
- * Repetivively call the HACL* HMAC-HASH update function on the given
- * data until the buffer length 'LEN' is strictly less than UINT32_MAX.
- *
- * On builds with PY_SSIZE_T_MAX <= UINT32_MAX, this is a no-op.
- *
- * The buffer 'BUF' (resp. 'LEN') is advanced (resp. decremented)
- * by UINT32_MAX after each update. On DEBUG builds, each update()
- * call is verified and the 'ERRACTION' statements are executed if
- * a non-successful HACL* exit code is being returned.
- *
- * In particular, 'BUF' and 'LEN' must be variable names and not
- * expressions on their own.
- *
- * The formal signature of this macro is:
- *
- * (HACL_HMAC_state *, uint8_t *, C integer, (C statements))
- */
-#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
-#define Py_HMAC_HACL_UPDATE_LOOP( \
- HACL_STATE, BUF, LEN, \
- ERRACTION \
-) \
- do { \
- while ((Py_ssize_t)LEN > UINT32_MAX_AS_SSIZE_T) { \
- Py_HMAC_HACL_UPDATE_ONCE(HACL_STATE, BUF, UINT32_MAX, \
- ERRACTION); \
- BUF += UINT32_MAX; \
- LEN -= UINT32_MAX; \
- } \
- } while (0)
-#else
-#define Py_HMAC_HACL_UPDATE_LOOP( \
- HACL_STATE, BUF, LEN, \
- _ERRACTION \
-)
-#endif
-
-/*
- * Perform the HMAC-HASH update() operation in a streaming fashion.
- *
- * The formal signature of this macro is:
- *
- * (HACL_HMAC_state *, uint8_t *, C integer, (C statements))
- */
-#define Py_HMAC_HACL_UPDATE( \
- HACL_STATE, BUF, LEN, \
- ERRACTION \
-) \
- do { \
- Py_HMAC_HACL_UPDATE_LOOP(HACL_STATE, BUF, LEN, \
- ERRACTION); \
- Py_HMAC_HACL_UPDATE_ONCE(HACL_STATE, BUF, LEN, \
- ERRACTION); \
- } while (0)
-
-/*
* HMAC underlying hash function static information.
*/
typedef struct py_hmac_hinfo {
@@ -382,11 +283,7 @@ get_hmacmodule_state_by_cls(PyTypeObject *cls)
typedef Hacl_Streaming_HMAC_agile_state HACL_HMAC_state;
typedef struct HMACObject {
- PyObject_HEAD
-
- bool use_mutex;
- PyMutex mutex;
-
+ HASHLIB_OBJECT_HEAD
// Hash function information
PyObject *name; // rendered name (exact unicode object)
HMAC_Hash_Kind kind; // can be used for runtime dispatch (must be known)
@@ -556,6 +453,51 @@ _hacl_hmac_state_free(HACL_HMAC_state *state)
}
}
+/*
+ * Call the HACL* HMAC-HASH update function on the given data.
+ *
+ * On DEBUG builds, the update() call is verified.
+ *
+ * Return 0 on success; otherwise, set an exception and return -1 on failure.
+*/
+static int
+_hacl_hmac_state_update_once(HACL_HMAC_state *state,
+ uint8_t *buf, uint32_t len)
+{
+#ifndef NDEBUG
+ hacl_errno_t code = Hacl_Streaming_HMAC_update(state, buf, len);
+ return _hacl_convert_errno(code);
+#else
+ (void)Hacl_Streaming_HMAC_update(state, buf, len);
+ return 0;
+#endif
+}
+
+/*
+ * Perform the HMAC-HASH update() operation in a streaming fashion.
+ *
+ * On DEBUG builds, each update() call is verified.
+ *
+ * Return 0 on success; otherwise, set an exception and return -1 on failure.
+ */
+static int
+_hacl_hmac_state_update(HACL_HMAC_state *state, uint8_t *buf, Py_ssize_t len)
+{
+ assert(len >= 0);
+#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
+ while (len > UINT32_MAX_AS_SSIZE_T) {
+ if (_hacl_hmac_state_update_once(state, buf, UINT32_MAX) < 0) {
+ assert(PyErr_Occurred());
+ return -1;
+ }
+ buf += UINT32_MAX;
+ len -= UINT32_MAX;
+ }
+#endif
+ Py_CHECK_HACL_UINT32_T_LENGTH(len);
+ return _hacl_hmac_state_update_once(state, buf, (uint32_t)len);
+}
+
/* Static information used to construct the hash table. */
static const py_hmac_hinfo py_hmac_static_hinfo[] = {
#define Py_HMAC_HINFO_HACL_API(HACL_HID) \
@@ -786,45 +728,6 @@ hmac_new_initial_state(HMACObject *self, uint8_t *key, Py_ssize_t len)
return self->state == NULL ? -1 : 0;
}
-/*
- * Feed initial data.
- *
- * This function MUST only be called by the HMAC object constructor
- * and after hmac_set_hinfo() and hmac_new_initial_state() have been
- * called, lest the behaviour is undefined.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static int
-hmac_feed_initial_data(HMACObject *self, uint8_t *msg, Py_ssize_t len)
-{
- assert(self->name != NULL);
- assert(self->state != NULL);
- if (len == 0) {
- // do nothing if the buffer is empty
- return 0;
- }
-
- if (len < HASHLIB_GIL_MINSIZE) {
- Py_HMAC_HACL_UPDATE(self->state, msg, len, return -1);
- return 0;
- }
-
- int res = 0;
- Py_BEGIN_ALLOW_THREADS
- Py_HMAC_HACL_UPDATE(self->state, msg, len, goto error);
- goto done;
-#ifndef NDEBUG
-error:
- res = -1;
-#else
- Py_UNREACHABLE();
-#endif
-done:
- Py_END_ALLOW_THREADS
- return res;
-}
-
/*[clinic input]
_hmac.new
@@ -871,7 +774,12 @@ _hmac_new_impl(PyObject *module, PyObject *keyobj, PyObject *msgobj,
if (msgobj != NULL && msgobj != Py_None) {
Py_buffer msg;
GET_BUFFER_VIEW_OR_ERROR(msgobj, &msg, goto error);
- rc = hmac_feed_initial_data(self, msg.buf, msg.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(
+ msg.len,
+ rc = _hacl_hmac_state_update(self->state, msg.buf, msg.len)
+ );
PyBuffer_Release(&msg);
#ifndef NDEBUG
if (rc < 0) {
@@ -948,12 +856,12 @@ _hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls)
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
/* copy hash information */
hmac_copy_hinfo(copy, self);
/* copy internal state */
int rc = hmac_copy_state(copy, self);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(copy);
@@ -965,78 +873,6 @@ _hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls)
return (PyObject *)copy;
}
-/*
- * Update the HMAC object with the given buffer.
- *
- * This unconditionally acquires the lock on the HMAC object.
- *
- * On DEBUG builds, each update() call is verified.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static int
-hmac_update_state_with_lock(HMACObject *self, uint8_t *buf, Py_ssize_t len)
-{
- int res = 0;
- Py_BEGIN_ALLOW_THREADS
- PyMutex_Lock(&self->mutex); // unconditionally acquire a lock
- Py_HMAC_HACL_UPDATE(self->state, buf, len, goto error);
- goto done;
-#ifndef NDEBUG
-error:
- res = -1;
-#else
- Py_UNREACHABLE();
-#endif
-done:
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- return res;
-}
-
-/*
- * Update the HMAC object with the given buffer.
- *
- * This conditionally acquires the lock on the HMAC object.
- *
- * On DEBUG builds, each update() call is verified.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static int
-hmac_update_state_cond_lock(HMACObject *self, uint8_t *buf, Py_ssize_t len)
-{
- ENTER_HASHLIB(self); // conditionally acquire a lock
- Py_HMAC_HACL_UPDATE(self->state, buf, len, goto error);
- LEAVE_HASHLIB(self);
- return 0;
-
-#ifndef NDEBUG
-error:
- LEAVE_HASHLIB(self);
- return -1;
-#else
- Py_UNREACHABLE();
-#endif
-}
-
-/*
- * Update the internal HMAC state with the given buffer.
- *
- * Return 0 on success; otherwise, set an exception and return -1 on failure.
- */
-static inline int
-hmac_update_state(HMACObject *self, uint8_t *buf, Py_ssize_t len)
-{
- assert(buf != 0);
- assert(len >= 0);
- return len == 0
- ? 0 /* nothing to do */
- : len < HASHLIB_GIL_MINSIZE
- ? hmac_update_state_cond_lock(self, buf, len)
- : hmac_update_state_with_lock(self, buf, len);
-}
-
/*[clinic input]
_hmac.HMAC.update
@@ -1049,9 +885,13 @@ static PyObject *
_hmac_HMAC_update_impl(HMACObject *self, PyObject *msgobj)
/*[clinic end generated code: output=962134ada5e55985 input=7c0ea830efb03367]*/
{
+ int rc = 0;
Py_buffer msg;
GET_BUFFER_VIEW_OR_ERROUT(msgobj, &msg);
- int rc = hmac_update_state(self, msg.buf, msg.len);
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, msg.len,
+ rc = _hacl_hmac_state_update(self->state, msg.buf, msg.len)
+ );
PyBuffer_Release(&msg);
return rc < 0 ? NULL : Py_None;
}
@@ -1067,13 +907,13 @@ _hmac_HMAC_update_impl(HMACObject *self, PyObject *msgobj)
* Note: this function may raise a MemoryError.
*/
static int
-hmac_digest_compute_cond_lock(HMACObject *self, uint8_t *digest)
+hmac_digest_compute_locked(HMACObject *self, uint8_t *digest)
{
assert(digest != NULL);
hacl_errno_t rc;
- ENTER_HASHLIB(self); // conditionally acquire a lock
+ HASHLIB_ACQUIRE_LOCK(self);
rc = Hacl_Streaming_HMAC_digest(self->state, digest, self->digest_size);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
assert(
rc == Hacl_Streaming_Types_Success ||
rc == Hacl_Streaming_Types_OutOfMemory
@@ -1095,7 +935,7 @@ _hmac_HMAC_digest_impl(HMACObject *self)
{
assert(self->digest_size <= Py_hmac_hash_max_digest_size);
uint8_t digest[Py_hmac_hash_max_digest_size];
- if (hmac_digest_compute_cond_lock(self, digest) < 0) {
+ if (hmac_digest_compute_locked(self, digest) < 0) {
return NULL;
}
return PyBytes_FromStringAndSize((const char *)digest, self->digest_size);
@@ -1118,7 +958,7 @@ _hmac_HMAC_hexdigest_impl(HMACObject *self)
{
assert(self->digest_size <= Py_hmac_hash_max_digest_size);
uint8_t digest[Py_hmac_hash_max_digest_size];
- if (hmac_digest_compute_cond_lock(self, digest) < 0) {
+ if (hmac_digest_compute_locked(self, digest) < 0) {
return NULL;
}
return _Py_strhex((const char *)digest, self->digest_size);
diff --git a/Modules/md5module.c b/Modules/md5module.c
index 6ec0ee87a2f..8b6dd4a8195 100644
--- a/Modules/md5module.c
+++ b/Modules/md5module.c
@@ -8,6 +8,7 @@
Andrew Kuchling (amk@amk.ca)
Greg Stein (gstein@lyra.org)
Trevor Perrin (trevp@trevp.net)
+ Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
Licensed to PSF under a Contributor Agreement.
@@ -25,32 +26,23 @@
#include "hashlib.h"
-/*[clinic input]
-module _md5
-class MD5Type "MD5object *" "&PyType_Type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6e5261719957a912]*/
+#include "_hacl/Hacl_Hash_MD5.h"
/* The MD5 block size and message digest sizes, in bytes */
#define MD5_BLOCKSIZE 64
#define MD5_DIGESTSIZE 16
-#include "_hacl/Hacl_Hash_MD5.h"
-
+// --- Module objects ---------------------------------------------------------
typedef struct {
- PyObject_HEAD
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
+ HASHLIB_OBJECT_HEAD
Hacl_Hash_MD5_state_t *hash_state;
} MD5object;
#define _MD5object_CAST(op) ((MD5object *)(op))
-#include "clinic/md5module.c.h"
-
+// --- Module state -----------------------------------------------------------
typedef struct {
PyTypeObject* md5_type;
@@ -64,6 +56,18 @@ md5_get_state(PyObject *module)
return (MD5State *)state;
}
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _md5
+class MD5Type "MD5object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6e5261719957a912]*/
+
+#include "clinic/md5module.c.h"
+
+// --- MD5 object interface ---------------------------------------------------
+
static MD5object *
newMD5object(MD5State * st)
{
@@ -118,9 +122,9 @@ MD5Type_copy_impl(MD5object *self, PyTypeObject *cls)
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
newobj->hash_state = Hacl_Hash_MD5_copy(self->hash_state);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (newobj->hash_state == NULL) {
Py_DECREF(newobj);
return PyErr_NoMemory();
@@ -139,9 +143,9 @@ MD5Type_digest_impl(MD5object *self)
/*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/
{
uint8_t digest[MD5_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_MD5_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE);
}
@@ -156,9 +160,9 @@ MD5Type_hexdigest_impl(MD5object *self)
/*[clinic end generated code: output=17badced1f3ac932 input=b60b19de644798dd]*/
{
uint8_t digest[MD5_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_MD5_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, MD5_DIGESTSIZE);
}
@@ -170,6 +174,7 @@ update(Hacl_Hash_MD5_state_t *state, uint8_t *buf, Py_ssize_t len)
* take more than 1 billion years to overflow the maximum admissible length
* for MD5 (2^61 - 1).
*/
+ assert(len >= 0);
#if PY_SSIZE_T_MAX > UINT32_MAX
while (len > UINT32_MAX) {
(void)Hacl_Hash_MD5_update(state, buf, UINT32_MAX);
@@ -195,22 +200,11 @@ MD5Type_update_impl(MD5object *self, PyObject *obj)
/*[clinic end generated code: output=b0fed9a7ce7ad253 input=6e1efcd9ecf17032]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &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);
- update(self->hash_state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update(self->hash_state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update(self->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -312,16 +306,12 @@ _md5_md5_impl(PyObject *module, PyObject *data, int usedforsecurity,
}
if (string) {
- 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
- update(new->hash_state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update(new->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,
+ update(new->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
diff --git a/Modules/sha1module.c b/Modules/sha1module.c
index a746bf74f8d..faa9dcccc57 100644
--- a/Modules/sha1module.c
+++ b/Modules/sha1module.c
@@ -8,13 +8,13 @@
Andrew Kuchling (amk@amk.ca)
Greg Stein (gstein@lyra.org)
Trevor Perrin (trevp@trevp.net)
+ Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
Licensed to PSF under a Contributor Agreement.
*/
-/* SHA1 objects */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
@@ -24,32 +24,23 @@
#include "pycore_strhex.h" // _Py_strhex()
#include "pycore_typeobject.h" // _PyType_GetModuleState()
-/*[clinic input]
-module _sha1
-class SHA1Type "SHA1object *" "&PyType_Type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3dc9a20d1becb759]*/
+#include "_hacl/Hacl_Hash_SHA1.h"
/* The SHA1 block size and message digest sizes, in bytes */
#define SHA1_BLOCKSIZE 64
#define SHA1_DIGESTSIZE 20
-#include "_hacl/Hacl_Hash_SHA1.h"
+// --- Module objects ---------------------------------------------------------
typedef struct {
- PyObject_HEAD
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
- PyThread_type_lock lock;
+ HASHLIB_OBJECT_HEAD
Hacl_Hash_SHA1_state_t *hash_state;
} SHA1object;
#define _SHA1object_CAST(op) ((SHA1object *)(op))
-#include "clinic/sha1module.c.h"
-
+// --- Module state -----------------------------------------------------------
typedef struct {
PyTypeObject* sha1_type;
@@ -63,6 +54,18 @@ sha1_get_state(PyObject *module)
return (SHA1State *)state;
}
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _sha1
+class SHA1Type "SHA1object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3dc9a20d1becb759]*/
+
+#include "clinic/sha1module.c.h"
+
+// --- SHA-1 object interface configuration -----------------------------------
+
static SHA1object *
newSHA1object(SHA1State *st)
{
@@ -121,9 +124,9 @@ SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls)
return NULL;
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
newobj->hash_state = Hacl_Hash_SHA1_copy(self->hash_state);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (newobj->hash_state == NULL) {
Py_DECREF(newobj);
return PyErr_NoMemory();
@@ -142,9 +145,9 @@ SHA1Type_digest_impl(SHA1object *self)
/*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA1_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE);
}
@@ -159,9 +162,9 @@ SHA1Type_hexdigest_impl(SHA1object *self)
/*[clinic end generated code: output=4161fd71e68c6659 input=97691055c0c74ab0]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA1_digest(self->hash_state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, SHA1_DIGESTSIZE);
}
@@ -198,22 +201,11 @@ SHA1Type_update_impl(SHA1object *self, PyObject *obj)
/*[clinic end generated code: output=cdc8e0e106dbec5f input=aad8e07812edbba3]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &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);
- update(self->hash_state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update(self->hash_state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update(self->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -314,16 +306,12 @@ _sha1_sha1_impl(PyObject *module, PyObject *data, int usedforsecurity,
return PyErr_NoMemory();
}
if (string) {
- 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
- update(new->hash_state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update(new->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,
+ update(new->hash_state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
diff --git a/Modules/sha2module.c b/Modules/sha2module.c
index 72931910c5d..36300ba899f 100644
--- a/Modules/sha2module.c
+++ b/Modules/sha2module.c
@@ -9,32 +9,25 @@
Greg Stein (gstein@lyra.org)
Trevor Perrin (trevp@trevp.net)
Jonathan Protzenko (jonathan@protzenko.fr)
+ Bénédikt Tran (10796600+picnixz@users.noreply.github.com)
Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
Licensed to PSF under a Contributor Agreement.
*/
-/* SHA objects */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
-#include "pycore_bitutils.h" // _Py_bswap32()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "pycore_strhex.h" // _Py_strhex()
#include "hashlib.h"
-/*[clinic input]
-module _sha2
-class SHA256Type "SHA256object *" "&PyType_Type"
-class SHA512Type "SHA512object *" "&PyType_Type"
-[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b5315a7b611c9afc]*/
-
+#include "_hacl/Hacl_Hash_SHA2.h"
/* The SHA block sizes and maximum message digest sizes, in bytes */
@@ -43,34 +36,26 @@ class SHA512Type "SHA512object *" "&PyType_Type"
#define SHA512_BLOCKSIZE 128
#define SHA512_DIGESTSIZE 64
-/* Our SHA2 implementations defer to the HACL* verified library. */
-
-#include "_hacl/Hacl_Hash_SHA2.h"
+// --- Module objects ---------------------------------------------------------
// TODO: Get rid of int digestsize in favor of Hacl state info?
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
int digestsize;
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
Hacl_Hash_SHA2_state_t_256 *state;
} SHA256object;
typedef struct {
- PyObject_HEAD
+ HASHLIB_OBJECT_HEAD
int digestsize;
- // Prevents undefined behavior via multiple threads entering the C API.
- bool use_mutex;
- PyMutex mutex;
Hacl_Hash_SHA2_state_t_512 *state;
} SHA512object;
#define _SHA256object_CAST(op) ((SHA256object *)(op))
#define _SHA512object_CAST(op) ((SHA512object *)(op))
-#include "clinic/sha2module.c.h"
+// --- Module state -----------------------------------------------------------
/* We shall use run-time type information in the remainder of this module to
* tell apart SHA2-224 and SHA2-256 */
@@ -89,6 +74,19 @@ sha2_get_state(PyObject *module)
return (sha2_state *)state;
}
+// --- Module clinic configuration --------------------------------------------
+
+/*[clinic input]
+module _sha2
+class SHA256Type "SHA256object *" "&PyType_Type"
+class SHA512Type "SHA512object *" "&PyType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b5315a7b611c9afc]*/
+
+#include "clinic/sha2module.c.h"
+
+// --- SHA-2 object interface -------------------------------------------------
+
static int
SHA256copy(SHA256object *src, SHA256object *dest)
{
@@ -272,9 +270,9 @@ SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls)
}
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
rc = SHA256copy(self, newobj);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(newobj);
return NULL;
@@ -309,9 +307,9 @@ SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls)
}
}
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
rc = SHA512copy(self, newobj);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
if (rc < 0) {
Py_DECREF(newobj);
return NULL;
@@ -331,11 +329,11 @@ SHA256Type_digest_impl(SHA256object *self)
{
uint8_t digest[SHA256_DIGESTSIZE];
assert(self->digestsize <= SHA256_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
// HACL* performs copies under the hood so that self->state remains valid
// after this call.
Hacl_Hash_SHA2_digest_256(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, self->digestsize);
}
@@ -351,11 +349,11 @@ SHA512Type_digest_impl(SHA512object *self)
{
uint8_t digest[SHA512_DIGESTSIZE];
assert(self->digestsize <= SHA512_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
// HACL* performs copies under the hood so that self->state remains valid
// after this call.
Hacl_Hash_SHA2_digest_512(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return PyBytes_FromStringAndSize((const char *)digest, self->digestsize);
}
@@ -371,9 +369,9 @@ SHA256Type_hexdigest_impl(SHA256object *self)
{
uint8_t digest[SHA256_DIGESTSIZE];
assert(self->digestsize <= SHA256_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA2_digest_256(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, self->digestsize);
}
@@ -389,9 +387,9 @@ SHA512Type_hexdigest_impl(SHA512object *self)
{
uint8_t digest[SHA512_DIGESTSIZE];
assert(self->digestsize <= SHA512_DIGESTSIZE);
- ENTER_HASHLIB(self);
+ HASHLIB_ACQUIRE_LOCK(self);
Hacl_Hash_SHA2_digest_512(self->state, digest);
- LEAVE_HASHLIB(self);
+ HASHLIB_RELEASE_LOCK(self);
return _Py_strhex((const char *)digest, self->digestsize);
}
@@ -409,22 +407,11 @@ SHA256Type_update_impl(SHA256object *self, PyObject *obj)
/*[clinic end generated code: output=dc58a580cf8905a5 input=b2d449d5b30f0f5a]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &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);
- update_256(self->state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update_256(self->state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update_256(self->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -443,22 +430,11 @@ SHA512Type_update_impl(SHA512object *self, PyObject *obj)
/*[clinic end generated code: output=9af211766c0b7365 input=ded2b46656566283]*/
{
Py_buffer buf;
-
GET_BUFFER_VIEW_OR_ERROUT(obj, &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);
- update_512(self->state, buf.buf, buf.len);
- PyMutex_Unlock(&self->mutex);
- Py_END_ALLOW_THREADS
- } else {
- update_512(self->state, buf.buf, buf.len);
- }
-
+ HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(
+ self, buf.len,
+ update_512(self->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
@@ -638,16 +614,12 @@ _sha2_sha256_impl(PyObject *module, PyObject *data, int usedforsecurity,
return PyErr_NoMemory();
}
if (string) {
- 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
- update_256(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_256(new->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,
+ update_256(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -700,16 +672,12 @@ _sha2_sha224_impl(PyObject *module, PyObject *data, int usedforsecurity,
return PyErr_NoMemory();
}
if (string) {
- 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
- update_256(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_256(new->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,
+ update_256(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -763,16 +731,12 @@ _sha2_sha512_impl(PyObject *module, PyObject *data, int usedforsecurity,
return PyErr_NoMemory();
}
if (string) {
- 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
- update_512(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_512(new->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,
+ update_512(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
@@ -826,16 +790,12 @@ _sha2_sha384_impl(PyObject *module, PyObject *data, int usedforsecurity,
return PyErr_NoMemory();
}
if (string) {
- 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
- update_512(new->state, buf.buf, buf.len);
- Py_END_ALLOW_THREADS
- }
- else {
- update_512(new->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,
+ update_512(new->state, buf.buf, buf.len)
+ );
PyBuffer_Release(&buf);
}
diff --git a/Modules/sha3module.c b/Modules/sha3module.c
index cfbf0cbcc04..face90a6094 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);
@@ -238,9 +251,9 @@ _sha3_sha3_224_copy_impl(SHA3object *self)
if ((newobj = newSHA3object(Py_TYPE(self))) == 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 +275,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 +294,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 +316,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 +474,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 *