mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Always use an individual lock on hash objects when in free-threaded builds. Fixes #111916
		
			
				
	
	
		
			417 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			417 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Written in 2013 by Dmitry Chestnykh <dmitry@codingrobots.com>
 | 
						|
 * Modified for CPython by Christian Heimes <christian@python.org>
 | 
						|
 *
 | 
						|
 * To the extent possible under law, the author have dedicated all
 | 
						|
 * copyright and related and neighboring rights to this software to
 | 
						|
 * the public domain worldwide. This software is distributed without
 | 
						|
 * any warranty. http://creativecommons.org/publicdomain/zero/1.0/
 | 
						|
 */
 | 
						|
 | 
						|
/* WARNING: autogenerated file!
 | 
						|
 *
 | 
						|
 * The blake2s_impl.c is autogenerated from blake2b_impl.c.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef Py_BUILD_CORE_BUILTIN
 | 
						|
#  define Py_BUILD_CORE_MODULE 1
 | 
						|
#endif
 | 
						|
 | 
						|
#include <stdbool.h>
 | 
						|
#include "Python.h"
 | 
						|
#include "pycore_strhex.h"       // _Py_strhex()
 | 
						|
 | 
						|
#include "../hashlib.h"
 | 
						|
#include "blake2module.h"
 | 
						|
 | 
						|
#ifndef HAVE_LIBB2
 | 
						|
/* pure SSE2 implementation is very slow, so only use the more optimized SSSE3+
 | 
						|
 * https://bugs.python.org/issue31834 */
 | 
						|
#if defined(__SSSE3__) || defined(__SSE4_1__) || defined(__AVX__) || defined(__XOP__)
 | 
						|
#include "impl/blake2b.c"
 | 
						|
#else
 | 
						|
#include "impl/blake2b-ref.c"
 | 
						|
#endif
 | 
						|
#endif // !HAVE_LIBB2
 | 
						|
 | 
						|
#define HAVE_BLAKE2B 1
 | 
						|
 | 
						|
extern PyType_Spec blake2b_type_spec;
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    PyObject_HEAD
 | 
						|
    blake2b_param    param;
 | 
						|
    blake2b_state    state;
 | 
						|
    bool use_mutex;
 | 
						|
    PyMutex mutex;
 | 
						|
} BLAKE2bObject;
 | 
						|
 | 
						|
#include "clinic/blake2b_impl.c.h"
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
module _blake2
 | 
						|
class _blake2.blake2b "BLAKE2bObject *" "&PyBlake2_BLAKE2bType"
 | 
						|
[clinic start generated code]*/
 | 
						|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d47b0527b39c673f]*/
 | 
						|
 | 
						|
 | 
						|
static BLAKE2bObject *
 | 
						|
new_BLAKE2bObject(PyTypeObject *type)
 | 
						|
{
 | 
						|
    BLAKE2bObject *self;
 | 
						|
    self = (BLAKE2bObject *)type->tp_alloc(type, 0);
 | 
						|
    if (self == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    HASHLIB_INIT_MUTEX(self);
 | 
						|
 | 
						|
    return self;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
@classmethod
 | 
						|
_blake2.blake2b.__new__ as py_blake2b_new
 | 
						|
    data: object(c_default="NULL") = b''
 | 
						|
    /
 | 
						|
    *
 | 
						|
    digest_size: int(c_default="BLAKE2B_OUTBYTES") = _blake2.blake2b.MAX_DIGEST_SIZE
 | 
						|
    key: Py_buffer(c_default="NULL", py_default="b''") = None
 | 
						|
    salt: Py_buffer(c_default="NULL", py_default="b''") = None
 | 
						|
    person: Py_buffer(c_default="NULL", py_default="b''") = None
 | 
						|
    fanout: int = 1
 | 
						|
    depth: int = 1
 | 
						|
    leaf_size: unsigned_long = 0
 | 
						|
    node_offset: unsigned_long_long = 0
 | 
						|
    node_depth: int = 0
 | 
						|
    inner_size: int = 0
 | 
						|
    last_node: bool = False
 | 
						|
    usedforsecurity: bool = True
 | 
						|
 | 
						|
Return a new BLAKE2b hash object.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
 | 
						|
                    Py_buffer *key, Py_buffer *salt, Py_buffer *person,
 | 
						|
                    int fanout, int depth, unsigned long leaf_size,
 | 
						|
                    unsigned long long node_offset, int node_depth,
 | 
						|
                    int inner_size, int last_node, int usedforsecurity)
 | 
						|
/*[clinic end generated code: output=32bfd8f043c6896f input=b947312abff46977]*/
 | 
						|
{
 | 
						|
    BLAKE2bObject *self = NULL;
 | 
						|
    Py_buffer buf;
 | 
						|
 | 
						|
    self = new_BLAKE2bObject(type);
 | 
						|
    if (self == NULL) {
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Zero parameter block. */
 | 
						|
    memset(&self->param, 0, sizeof(self->param));
 | 
						|
 | 
						|
    /* Set digest size. */
 | 
						|
    if (digest_size <= 0 || digest_size > BLAKE2B_OUTBYTES) {
 | 
						|
        PyErr_Format(PyExc_ValueError,
 | 
						|
                "digest_size must be between 1 and %d bytes",
 | 
						|
                BLAKE2B_OUTBYTES);
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    self->param.digest_length = digest_size;
 | 
						|
 | 
						|
    /* Set salt parameter. */
 | 
						|
    if ((salt->obj != NULL) && salt->len) {
 | 
						|
        if (salt->len > BLAKE2B_SALTBYTES) {
 | 
						|
            PyErr_Format(PyExc_ValueError,
 | 
						|
                "maximum salt length is %d bytes",
 | 
						|
                BLAKE2B_SALTBYTES);
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
        memcpy(self->param.salt, salt->buf, salt->len);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Set personalization parameter. */
 | 
						|
    if ((person->obj != NULL) && person->len) {
 | 
						|
        if (person->len > BLAKE2B_PERSONALBYTES) {
 | 
						|
            PyErr_Format(PyExc_ValueError,
 | 
						|
                "maximum person length is %d bytes",
 | 
						|
                BLAKE2B_PERSONALBYTES);
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
        memcpy(self->param.personal, person->buf, person->len);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Set tree parameters. */
 | 
						|
    if (fanout < 0 || fanout > 255) {
 | 
						|
        PyErr_SetString(PyExc_ValueError,
 | 
						|
                "fanout must be between 0 and 255");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    self->param.fanout = (uint8_t)fanout;
 | 
						|
 | 
						|
    if (depth <= 0 || depth > 255) {
 | 
						|
        PyErr_SetString(PyExc_ValueError,
 | 
						|
                "depth must be between 1 and 255");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    self->param.depth = (uint8_t)depth;
 | 
						|
 | 
						|
    if (leaf_size > 0xFFFFFFFFU) {
 | 
						|
        PyErr_SetString(PyExc_OverflowError, "leaf_size is too large");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    // NB: Simple assignment here would be incorrect on big endian platforms.
 | 
						|
    store32(&(self->param.leaf_length), leaf_size);
 | 
						|
 | 
						|
#ifdef HAVE_BLAKE2S
 | 
						|
    if (node_offset > 0xFFFFFFFFFFFFULL) {
 | 
						|
        /* maximum 2**48 - 1 */
 | 
						|
         PyErr_SetString(PyExc_OverflowError, "node_offset is too large");
 | 
						|
         goto error;
 | 
						|
     }
 | 
						|
    store48(&(self->param.node_offset), node_offset);
 | 
						|
#else
 | 
						|
    // NB: Simple assignment here would be incorrect on big endian platforms.
 | 
						|
    store64(&(self->param.node_offset), node_offset);
 | 
						|
#endif
 | 
						|
 | 
						|
    if (node_depth < 0 || node_depth > 255) {
 | 
						|
        PyErr_SetString(PyExc_ValueError,
 | 
						|
                "node_depth must be between 0 and 255");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    self->param.node_depth = node_depth;
 | 
						|
 | 
						|
    if (inner_size < 0 || inner_size > BLAKE2B_OUTBYTES) {
 | 
						|
        PyErr_Format(PyExc_ValueError,
 | 
						|
                "inner_size must be between 0 and is %d",
 | 
						|
                BLAKE2B_OUTBYTES);
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    self->param.inner_length = inner_size;
 | 
						|
 | 
						|
    /* Set key length. */
 | 
						|
    if ((key->obj != NULL) && key->len) {
 | 
						|
        if (key->len > BLAKE2B_KEYBYTES) {
 | 
						|
            PyErr_Format(PyExc_ValueError,
 | 
						|
                "maximum key length is %d bytes",
 | 
						|
                BLAKE2B_KEYBYTES);
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
        self->param.key_length = (uint8_t)key->len;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Initialize hash state. */
 | 
						|
    if (blake2b_init_param(&self->state, &self->param) < 0) {
 | 
						|
        PyErr_SetString(PyExc_RuntimeError,
 | 
						|
                "error initializing hash state");
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Set last node flag (must come after initialization). */
 | 
						|
    self->state.last_node = last_node;
 | 
						|
 | 
						|
    /* Process key block if any. */
 | 
						|
    if (self->param.key_length) {
 | 
						|
        uint8_t block[BLAKE2B_BLOCKBYTES];
 | 
						|
        memset(block, 0, sizeof(block));
 | 
						|
        memcpy(block, key->buf, key->len);
 | 
						|
        blake2b_update(&self->state, block, sizeof(block));
 | 
						|
        secure_zero_memory(block, sizeof(block));
 | 
						|
    }
 | 
						|
 | 
						|
    /* Process initial data if any. */
 | 
						|
    if (data != NULL) {
 | 
						|
        GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
 | 
						|
 | 
						|
        if (buf.len >= HASHLIB_GIL_MINSIZE) {
 | 
						|
            Py_BEGIN_ALLOW_THREADS
 | 
						|
            blake2b_update(&self->state, buf.buf, buf.len);
 | 
						|
            Py_END_ALLOW_THREADS
 | 
						|
        } else {
 | 
						|
            blake2b_update(&self->state, buf.buf, buf.len);
 | 
						|
        }
 | 
						|
        PyBuffer_Release(&buf);
 | 
						|
    }
 | 
						|
 | 
						|
    return (PyObject *)self;
 | 
						|
 | 
						|
  error:
 | 
						|
    if (self != NULL) {
 | 
						|
        Py_DECREF(self);
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_blake2.blake2b.copy
 | 
						|
 | 
						|
Return a copy of the hash object.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_blake2_blake2b_copy_impl(BLAKE2bObject *self)
 | 
						|
/*[clinic end generated code: output=ff6acee5f93656ae input=e383c2d199fd8a2e]*/
 | 
						|
{
 | 
						|
    BLAKE2bObject *cpy;
 | 
						|
 | 
						|
    if ((cpy = new_BLAKE2bObject(Py_TYPE(self))) == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    ENTER_HASHLIB(self);
 | 
						|
    cpy->param = self->param;
 | 
						|
    cpy->state = self->state;
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
    return (PyObject *)cpy;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_blake2.blake2b.update
 | 
						|
 | 
						|
    data: object
 | 
						|
    /
 | 
						|
 | 
						|
Update this hash object's state with the provided bytes-like object.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_blake2_blake2b_update(BLAKE2bObject *self, PyObject *data)
 | 
						|
/*[clinic end generated code: output=010dfcbe22654359 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);
 | 
						|
        blake2b_update(&self->state, buf.buf, buf.len);
 | 
						|
        PyMutex_Unlock(&self->mutex);
 | 
						|
        Py_END_ALLOW_THREADS
 | 
						|
    } else {
 | 
						|
        blake2b_update(&self->state, buf.buf, buf.len);
 | 
						|
    }
 | 
						|
 | 
						|
    PyBuffer_Release(&buf);
 | 
						|
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_blake2.blake2b.digest
 | 
						|
 | 
						|
Return the digest value as a bytes object.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_blake2_blake2b_digest_impl(BLAKE2bObject *self)
 | 
						|
/*[clinic end generated code: output=a5864660f4bfc61a input=7d21659e9c5fff02]*/
 | 
						|
{
 | 
						|
    uint8_t digest[BLAKE2B_OUTBYTES];
 | 
						|
    blake2b_state state_cpy;
 | 
						|
 | 
						|
    ENTER_HASHLIB(self);
 | 
						|
    state_cpy = self->state;
 | 
						|
    blake2b_final(&state_cpy, digest, self->param.digest_length);
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
    return PyBytes_FromStringAndSize((const char *)digest,
 | 
						|
            self->param.digest_length);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_blake2.blake2b.hexdigest
 | 
						|
 | 
						|
Return the digest value as a string of hexadecimal digits.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_blake2_blake2b_hexdigest_impl(BLAKE2bObject *self)
 | 
						|
/*[clinic end generated code: output=b5598a87d8794a60 input=76930f6946351f56]*/
 | 
						|
{
 | 
						|
    uint8_t digest[BLAKE2B_OUTBYTES];
 | 
						|
    blake2b_state state_cpy;
 | 
						|
 | 
						|
    ENTER_HASHLIB(self);
 | 
						|
    state_cpy = self->state;
 | 
						|
    blake2b_final(&state_cpy, digest, self->param.digest_length);
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
    return _Py_strhex((const char *)digest, self->param.digest_length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static PyMethodDef py_blake2b_methods[] = {
 | 
						|
    _BLAKE2_BLAKE2B_COPY_METHODDEF
 | 
						|
    _BLAKE2_BLAKE2B_DIGEST_METHODDEF
 | 
						|
    _BLAKE2_BLAKE2B_HEXDIGEST_METHODDEF
 | 
						|
    _BLAKE2_BLAKE2B_UPDATE_METHODDEF
 | 
						|
    {NULL, NULL}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static PyObject *
 | 
						|
py_blake2b_get_name(BLAKE2bObject *self, void *closure)
 | 
						|
{
 | 
						|
    return PyUnicode_FromString("blake2b");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static PyObject *
 | 
						|
py_blake2b_get_block_size(BLAKE2bObject *self, void *closure)
 | 
						|
{
 | 
						|
    return PyLong_FromLong(BLAKE2B_BLOCKBYTES);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static PyObject *
 | 
						|
py_blake2b_get_digest_size(BLAKE2bObject *self, void *closure)
 | 
						|
{
 | 
						|
    return PyLong_FromLong(self->param.digest_length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static PyGetSetDef py_blake2b_getsetters[] = {
 | 
						|
    {"name", (getter)py_blake2b_get_name,
 | 
						|
        NULL, NULL, NULL},
 | 
						|
    {"block_size", (getter)py_blake2b_get_block_size,
 | 
						|
        NULL, NULL, NULL},
 | 
						|
    {"digest_size", (getter)py_blake2b_get_digest_size,
 | 
						|
        NULL, NULL, NULL},
 | 
						|
    {NULL}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
py_blake2b_dealloc(PyObject *self)
 | 
						|
{
 | 
						|
    BLAKE2bObject *obj = (BLAKE2bObject *)self;
 | 
						|
 | 
						|
    /* Try not to leave state in memory. */
 | 
						|
    secure_zero_memory(&obj->param, sizeof(obj->param));
 | 
						|
    secure_zero_memory(&obj->state, sizeof(obj->state));
 | 
						|
 | 
						|
    PyTypeObject *type = Py_TYPE(self);
 | 
						|
    PyObject_Free(self);
 | 
						|
    Py_DECREF(type);
 | 
						|
}
 | 
						|
 | 
						|
static PyType_Slot blake2b_type_slots[] = {
 | 
						|
    {Py_tp_dealloc, py_blake2b_dealloc},
 | 
						|
    {Py_tp_doc, (char *)py_blake2b_new__doc__},
 | 
						|
    {Py_tp_methods, py_blake2b_methods},
 | 
						|
    {Py_tp_getset, py_blake2b_getsetters},
 | 
						|
    {Py_tp_new, py_blake2b_new},
 | 
						|
    {0,0}
 | 
						|
};
 | 
						|
 | 
						|
PyType_Spec blake2b_type_spec = {
 | 
						|
    .name = "_blake2.blake2b",
 | 
						|
    .basicsize =  sizeof(BLAKE2bObject),
 | 
						|
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
 | 
						|
    .slots = blake2b_type_slots
 | 
						|
};
 |