cpython/Modules/_blake2/blake2s_impl.c

453 lines
13 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 blake2s_impl.c.
*/
#include "Python.h"
#include "pystrhex.h"
#include "pythread.h"
#include "../hashlib.h"
#include "blake2ns.h"
#define HAVE_BLAKE2S 1
#define BLAKE2_LOCAL_INLINE(type) Py_LOCAL_INLINE(type)
#include "impl/blake2.h"
#include "impl/blake2-impl.h" /* for secure_zero_memory() and store48() */
/* 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/blake2s.c"
#else
#include "impl/blake2s-ref.c"
#endif
extern PyTypeObject PyBlake2_BLAKE2sType;
typedef struct {
PyObject_HEAD
blake2s_param param;
blake2s_state state;
PyThread_type_lock lock;
} BLAKE2sObject;
#include "clinic/blake2s_impl.c.h"
/*[clinic input]
module _blake2
class _blake2.blake2s "BLAKE2sObject *" "&PyBlake2_BLAKE2sType"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b79d7ffe07286ce]*/
static BLAKE2sObject *
new_BLAKE2sObject(PyTypeObject *type)
{
BLAKE2sObject *self;
self = (BLAKE2sObject *)type->tp_alloc(type, 0);
if (self != NULL) {
self->lock = NULL;
}
return self;
}
/*[clinic input]
@classmethod
_blake2.blake2s.__new__ as py_blake2s_new
data: object(c_default="NULL") = b''
/
*
digest_size: int(c_default="BLAKE2S_OUTBYTES") = _blake2.blake2s.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 as leaf_size_obj: object(c_default="NULL") = 0
node_offset as node_offset_obj: object(c_default="NULL") = 0
node_depth: int = 0
inner_size: int = 0
last_node: bool = False
Return a new BLAKE2s hash object.
[clinic start generated code]*/
static PyObject *
py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
Py_buffer *key, Py_buffer *salt, Py_buffer *person,
int fanout, int depth, PyObject *leaf_size_obj,
PyObject *node_offset_obj, int node_depth,
int inner_size, int last_node)
/*[clinic end generated code: output=fe060b258a8cbfc6 input=3abfaabe7f5f62cc]*/
{
BLAKE2sObject *self = NULL;
Py_buffer buf;
unsigned long leaf_size = 0;
unsigned long long node_offset = 0;
self = new_BLAKE2sObject(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 > BLAKE2S_OUTBYTES) {
PyErr_Format(PyExc_ValueError,
"digest_size must be between 1 and %d bytes",
BLAKE2S_OUTBYTES);
goto error;
}
self->param.digest_length = digest_size;
/* Set salt parameter. */
if ((salt->obj != NULL) && salt->len) {
if (salt->len > BLAKE2S_SALTBYTES) {
PyErr_Format(PyExc_ValueError,
"maximum salt length is %d bytes",
BLAKE2S_SALTBYTES);
goto error;
}
memcpy(self->param.salt, salt->buf, salt->len);
}
/* Set personalization parameter. */
if ((person->obj != NULL) && person->len) {
if (person->len > BLAKE2S_PERSONALBYTES) {
PyErr_Format(PyExc_ValueError,
"maximum person length is %d bytes",
BLAKE2S_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_obj != NULL) {
leaf_size = PyLong_AsUnsignedLong(leaf_size_obj);
if (leaf_size == (unsigned long) -1 && PyErr_Occurred()) {
goto error;
}
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);
if (node_offset_obj != NULL) {
node_offset = PyLong_AsUnsignedLongLong(node_offset_obj);
if (node_offset == (unsigned long long) -1 && PyErr_Occurred()) {
goto error;
}
}
#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 > BLAKE2S_OUTBYTES) {
PyErr_Format(PyExc_ValueError,
"inner_size must be between 0 and is %d",
BLAKE2S_OUTBYTES);
goto error;
}
self->param.inner_length = inner_size;
/* Set key length. */
if ((key->obj != NULL) && key->len) {
if (key->len > BLAKE2S_KEYBYTES) {
PyErr_Format(PyExc_ValueError,
"maximum key length is %d bytes",
BLAKE2S_KEYBYTES);
goto error;
}
self->param.key_length = (uint8_t)key->len;
}
/* Initialize hash state. */
if (blake2s_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[BLAKE2S_BLOCKBYTES];
memset(block, 0, sizeof(block));
memcpy(block, key->buf, key->len);
blake2s_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
blake2s_update(&self->state, buf.buf, buf.len);
Py_END_ALLOW_THREADS
} else {
blake2s_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.blake2s.copy
Return a copy of the hash object.
[clinic start generated code]*/
static PyObject *
_blake2_blake2s_copy_impl(BLAKE2sObject *self)
/*[clinic end generated code: output=5b90131c4eae275e input=0b9d44942f0fe4b2]*/
{
BLAKE2sObject *cpy;
if ((cpy = new_BLAKE2sObject(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.blake2s.update
data: object
/
Update this hash object's state with the provided bytes-like object.
[clinic start generated code]*/
static PyObject *
_blake2_blake2s_update(BLAKE2sObject *self, PyObject *data)
/*[clinic end generated code: output=757dc087fec37815 input=97500db2f9de4aaa]*/
{
Py_buffer buf;
GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE)
self->lock = PyThread_allocate_lock();
if (self->lock != NULL) {
Py_BEGIN_ALLOW_THREADS
PyThread_acquire_lock(self->lock, 1);
blake2s_update(&self->state, buf.buf, buf.len);
PyThread_release_lock(self->lock);
Py_END_ALLOW_THREADS
} else {
blake2s_update(&self->state, buf.buf, buf.len);
}
PyBuffer_Release(&buf);
Py_RETURN_NONE;
}
/*[clinic input]
_blake2.blake2s.digest
Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
_blake2_blake2s_digest_impl(BLAKE2sObject *self)
/*[clinic end generated code: output=40c566ca4bc6bc51 input=f41e0b8d6d937454]*/
{
uint8_t digest[BLAKE2S_OUTBYTES];
blake2s_state state_cpy;
ENTER_HASHLIB(self);
state_cpy = self->state;
blake2s_final(&state_cpy, digest, self->param.digest_length);
LEAVE_HASHLIB(self);
return PyBytes_FromStringAndSize((const char *)digest,
self->param.digest_length);
}
/*[clinic input]
_blake2.blake2s.hexdigest
Return the digest value as a string of hexadecimal digits.
[clinic start generated code]*/
static PyObject *
_blake2_blake2s_hexdigest_impl(BLAKE2sObject *self)
/*[clinic end generated code: output=15153eb5e59c52eb input=c77a1321567e8952]*/
{
uint8_t digest[BLAKE2S_OUTBYTES];
blake2s_state state_cpy;
ENTER_HASHLIB(self);
state_cpy = self->state;
blake2s_final(&state_cpy, digest, self->param.digest_length);
LEAVE_HASHLIB(self);
return _Py_strhex((const char *)digest, self->param.digest_length);
}
static PyMethodDef py_blake2s_methods[] = {
_BLAKE2_BLAKE2S_COPY_METHODDEF
_BLAKE2_BLAKE2S_DIGEST_METHODDEF
_BLAKE2_BLAKE2S_HEXDIGEST_METHODDEF
_BLAKE2_BLAKE2S_UPDATE_METHODDEF
{NULL, NULL}
};
static PyObject *
py_blake2s_get_name(BLAKE2sObject *self, void *closure)
{
return PyUnicode_FromString("blake2s");
}
static PyObject *
py_blake2s_get_block_size(BLAKE2sObject *self, void *closure)
{
return PyLong_FromLong(BLAKE2S_BLOCKBYTES);
}
static PyObject *
py_blake2s_get_digest_size(BLAKE2sObject *self, void *closure)
{
return PyLong_FromLong(self->param.digest_length);
}
static PyGetSetDef py_blake2s_getsetters[] = {
{"name", (getter)py_blake2s_get_name,
NULL, NULL, NULL},
{"block_size", (getter)py_blake2s_get_block_size,
NULL, NULL, NULL},
{"digest_size", (getter)py_blake2s_get_digest_size,
NULL, NULL, NULL},
{NULL}
};
static void
py_blake2s_dealloc(PyObject *self)
{
BLAKE2sObject *obj = (BLAKE2sObject *)self;
/* Try not to leave state in memory. */
secure_zero_memory(&obj->param, sizeof(obj->param));
secure_zero_memory(&obj->state, sizeof(obj->state));
if (obj->lock) {
PyThread_free_lock(obj->lock);
obj->lock = NULL;
}
PyObject_Del(self);
}
PyTypeObject PyBlake2_BLAKE2sType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_blake2.blake2s", /* tp_name */
sizeof(BLAKE2sObject), /* tp_basicsize */
0, /* tp_itemsize */
py_blake2s_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
py_blake2s_new__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
py_blake2s_methods, /* tp_methods */
0, /* tp_members */
py_blake2s_getsetters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
py_blake2s_new, /* tp_new */
};