From 61ad7f5ec78d4c80a99ac71820d9bc8b62c3fbae Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sat, 15 May 2021 22:48:13 -0700 Subject: [PATCH] Add BearSSL implementation of _hashlib --- Modules/_hashbearssl.c | 1126 +++++++++++++++++++++++++++++++ Modules/clinic/_hashbearssl.c.h | 1113 ++++++++++++++++++++++++++++++ 2 files changed, 2239 insertions(+) create mode 100644 Modules/_hashbearssl.c create mode 100644 Modules/clinic/_hashbearssl.c.h diff --git a/Modules/_hashbearssl.c b/Modules/_hashbearssl.c new file mode 100644 index 0000000000..2d1a76296d --- /dev/null +++ b/Modules/_hashbearssl.c @@ -0,0 +1,1126 @@ +/* Module that wraps all BearSSL hash algorithms */ +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "hashlib.h" +#include "pystrhex.h" + +#include + +static PyModuleDef _hashlibmodule; +static PyTypeObject Hash_Type; +static PyTypeObject SHAKE_Type; +static PyTypeObject HMAC_Type; + +typedef struct { + PyObject_HEAD + br_hash_compat_context ctx; + PyThread_type_lock lock; +} Hash; + +typedef struct { + PyObject_HEAD + br_hmac_context ctx; + br_hmac_key_context key; + PyThread_type_lock lock; +} HMAC; + +typedef struct { + PyObject_HEAD + br_shake_context ctx; + int bits; + PyThread_type_lock lock; +} SHAKE; + +#include "clinic/_hashbearssl.c.h" +/*[clinic input] +module _hashlib +class _hashlib.Hash "Hash *" "Hash_Type" +class _hashlib.HMAC "HMAC *" "HMAC_Type" +class _hashlib.SHAKE "SHAKE *" "SHAKE_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7a269412ec77c79a]*/ + +static const br_hash_class * +py_hash_by_name(const char *name) +{ + if (strcmp(name, "md5") == 0) + return &br_md5_vtable; + else if (strcmp(name, "sha1") == 0) + return &br_sha1_vtable; + else if (strcmp(name, "sha224") == 0) + return &br_sha224_vtable; + else if (strcmp(name, "sha256") == 0) + return &br_sha256_vtable; + else if (strcmp(name, "sha384") == 0) + return &br_sha384_vtable; + else if (strcmp(name, "sha512") == 0) + return &br_sha512_vtable; + return NULL; +} + +PyDoc_STRVAR(Hash_doc, +"Hash(name, string=b\'\')\n" +"--\n" +"\n" +"A hash is an object used to calculate a checksum of a string of information.\n" +"\n" +"Methods:\n" +"\n" +"update() -- updates the current digest with an additional string\n" +"digest() -- return the current digest value\n" +"hexdigest() -- return the current digest as a string of hexadecimal digits\n" +"copy() -- return a copy of the current hash object\n" +"\n" +"Attributes:\n" +"\n" +"name -- the hash algorithm being used by this object\n" +"digest_size -- number of bytes in this hashes output"); + +static void +Hash_dealloc(Hash *self) +{ + if (self->lock) + PyThread_free_lock(self->lock); + PyObject_Free(self); +} + +/*[clinic input] +_hashlib.Hash.update as Hash_update + + data: Py_buffer + / + +Update this hash object's state with the provided string. +[clinic start generated code]*/ + +static PyObject * +Hash_update_impl(Hash *self, Py_buffer *data) +/*[clinic end generated code: output=eed11f7503e289a3 input=0547d16ba3981abf]*/ +{ + if (!self->lock && data->len >= HASHLIB_GIL_MINSIZE) + self->lock = PyThread_allocate_lock(); + if (self->lock) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + self->ctx.vtable->update(&self->ctx.vtable, data->buf, data->len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + self->ctx.vtable->update(&self->ctx.vtable, data->buf, data->len); + } + Py_RETURN_NONE; +} + +/*[clinic input] +_hashlib.Hash.digest as Hash_digest + +Return the digest value as a bytes object. +[clinic start generated code]*/ + +static PyObject * +Hash_digest_impl(Hash *self) +/*[clinic end generated code: output=b3eafdc9f37cf341 input=6d4afcd832edc55a]*/ +{ + char digest[64]; + Py_ssize_t digest_size; + + ENTER_HASHLIB(self) + self->ctx.vtable->out(&self->ctx.vtable, digest); + LEAVE_HASHLIB(self) + digest_size = (self->ctx.vtable->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + + return PyBytes_FromStringAndSize(digest, digest_size); +} + +/*[clinic input] +_hashlib.Hash.hexdigest as Hash_hexdigest + +Return the digest value as a string of hexadecimal digits. +[clinic start generated code]*/ + +static PyObject * +Hash_hexdigest_impl(Hash *self) +/*[clinic end generated code: output=eff810494302910a input=6b224236fad6ff65]*/ +{ + char digest[64]; + Py_ssize_t digest_size; + + ENTER_HASHLIB(self) + self->ctx.vtable->out(&self->ctx.vtable, digest); + LEAVE_HASHLIB(self) + digest_size = (self->ctx.vtable->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; + + return _Py_strhex(digest, digest_size); +} + +/*[clinic input] +_hashlib.Hash.copy as Hash_copy + +Return a copy of the hash object. +[clinic start generated code]*/ + +static PyObject * +Hash_copy_impl(Hash *self) +/*[clinic end generated code: output=e97863340f55061b input=b830c9d949d08256]*/ +{ + Hash *newobj; + + newobj = PyObject_New(Hash, &Hash_Type); + if (!newobj) + return NULL; + newobj->lock = NULL; + ENTER_HASHLIB(self) + newobj->ctx = self->ctx; + LEAVE_HASHLIB(self) + + return (PyObject *)newobj; +} + +static PyMethodDef Hash_methods[] = { + HASH_UPDATE_METHODDEF + HASH_DIGEST_METHODDEF + HASH_HEXDIGEST_METHODDEF + HASH_COPY_METHODDEF + {0} +}; + +static PyObject * +Hash_get_digest_size(Hash *self, void *closure) +{ + long digest_size; + + digest_size = self->ctx.vtable->desc >> BR_HASHDESC_OUT_OFF & BR_HASHDESC_OUT_MASK; + return PyLong_FromLong(digest_size); +} + +static PyObject * +Hash_get_block_size(Hash *self, void *closure) +{ + long block_size; + + block_size = 1 << (self->ctx.vtable->desc >> BR_HASHDESC_LBLEN_OFF & BR_HASHDESC_LBLEN_MASK); + return PyLong_FromLong(block_size); +} + +static PyObject * +Hash_get_name(Hash *self, void *closure) +{ + const char *name = NULL; + + switch (self->ctx.vtable->desc >> BR_HASHDESC_ID_OFF & BR_HASHDESC_ID_MASK) { + case br_md5_ID: name = "md5"; break; + case br_sha1_ID: name = "sha1"; break; + case br_sha224_ID: name = "sha224"; break; + case br_sha256_ID: name = "sha256"; break; + case br_sha384_ID: name = "sha384"; break; + case br_sha512_ID: name = "sha512"; break; + } + + return PyUnicode_FromString(name); +} + +static PyGetSetDef Hash_getset[] = { + {"digest_size", (getter)Hash_get_digest_size, NULL, NULL, NULL}, + {"block_size", (getter)Hash_get_block_size, NULL, NULL, NULL}, + {"name", (getter)Hash_get_name, NULL, NULL, NULL}, + {0} +}; + +static PyTypeObject Hash_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_hashlib.Hash", + .tp_dealloc = (destructor)Hash_dealloc, + .tp_doc = Hash_doc, + .tp_basicsize = sizeof(Hash), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, + .tp_methods = Hash_methods, + .tp_getset = Hash_getset, +}; + +PyDoc_STRVAR(SHAKE_doc, +"SHAKE(name, string=b\'\')\n" +"--\n" +"\n" +"A hash is an object used to calculate a checksum of a string of information.\n" +"\n" +"Methods:\n" +"\n" +"update() -- updates the current digest with an additional string\n" +"digest(length) -- return the current digest value\n" +"hexdigest(length) -- return the current digest as a string of hexadecimal digits\n" +"copy() -- return a copy of the current hash object\n" +"\n" +"Attributes:\n" +"\n" +"name -- the hash algorithm being used by this object\n" +"digest_size -- number of bytes in this hashes output"); + +static void +SHAKE_dealloc(SHAKE *self) +{ + if (self->lock) + PyThread_free_lock(self->lock); + PyObject_Free(self); +} + +/*[clinic input] +_hashlib.SHAKE.update as SHAKE_update + + data: Py_buffer + / + +Update this hash object's state with the provided string. +[clinic start generated code]*/ + +static PyObject * +SHAKE_update_impl(SHAKE *self, Py_buffer *data) +/*[clinic end generated code: output=b7f5cd67459e2fb3 input=87a80642380b615f]*/ +{ + if (!self->lock && data->len >= HASHLIB_GIL_MINSIZE) + self->lock = PyThread_allocate_lock(); + if (self->lock) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + br_shake_inject(&self->ctx, data->buf, data->len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + br_shake_inject(&self->ctx, data->buf, data->len); + } + Py_RETURN_NONE; +} + +/*[clinic input] +_hashlib.SHAKE.digest as SHAKE_digest + + length: Py_ssize_t + +Return the digest value as a bytes object. +[clinic start generated code]*/ + +static PyObject * +SHAKE_digest_impl(SHAKE *self, Py_ssize_t length) +/*[clinic end generated code: output=4235ee593cba0b23 input=9e31587954f5e87a]*/ +{ + br_shake_context ctx; + PyObject *bytes; + + bytes = PyBytes_FromStringAndSize(NULL, length); + if (!bytes) + return NULL; + + ENTER_HASHLIB(self) + ctx = self->ctx; + LEAVE_HASHLIB(self) + br_shake_flip(&ctx); + br_shake_produce(&ctx, PyBytes_AS_STRING(bytes), length); + + return bytes; +} + +/*[clinic input] +_hashlib.SHAKE.hexdigest as SHAKE_hexdigest + + length: Py_ssize_t + +Return the digest value as a string of hexadecimal digits. +[clinic start generated code]*/ + +static PyObject * +SHAKE_hexdigest_impl(SHAKE *self, Py_ssize_t length) +/*[clinic end generated code: output=fd9a7905a89a1509 input=2c43a9638ca1db5e]*/ +{ + br_shake_context ctx; + char *bytes; + PyObject *str; + + bytes = PyMem_Malloc(length); + if (!bytes) { + PyErr_NoMemory(); + return NULL; + } + + ENTER_HASHLIB(self) + ctx = self->ctx; + LEAVE_HASHLIB(self) + br_shake_flip(&ctx); + br_shake_produce(&ctx, bytes, length); + + str = _Py_strhex(bytes, length); + PyMem_Free(bytes); + return str; +} + +/*[clinic input] +_hashlib.SHAKE.copy as SHAKE_copy + +Return a copy of the SHAKE object. +[clinic start generated code]*/ + +static PyObject * +SHAKE_copy_impl(SHAKE *self) +/*[clinic end generated code: output=19cff23538f29dc6 input=34c8368c5c9e910c]*/ +{ + SHAKE *newobj; + + newobj = PyObject_New(SHAKE, &SHAKE_Type); + if (!newobj) + return NULL; + newobj->lock = NULL; + ENTER_HASHLIB(self) + newobj->ctx = self->ctx; + newobj->bits = self->bits; + LEAVE_HASHLIB(self) + + return (PyObject *)newobj; +} + +static PyMethodDef SHAKE_methods[] = { + SHAKE_UPDATE_METHODDEF + SHAKE_DIGEST_METHODDEF + SHAKE_HEXDIGEST_METHODDEF + SHAKE_COPY_METHODDEF + {0} +}; + +static PyObject * +SHAKE_get_digest_size(SHAKE *self, void *closure) +{ + return PyLong_FromLong(0); +} + +static PyObject * +SHAKE_get_block_size(SHAKE *self, void *closure) +{ + return PyLong_FromLong(self->ctx.rate); +} + +static PyObject * +SHAKE_get_name(SHAKE *self, void *closure) +{ + const char *name = NULL; + + switch (self->bits) { + case 128: name = "shake_128"; break; + case 256: name = "shake_256"; break; + } + + return PyUnicode_FromString(name); +} + +static PyGetSetDef SHAKE_getset[] = { + {"digest_size", (getter)SHAKE_get_digest_size, NULL, NULL, NULL}, + {"block_size", (getter)SHAKE_get_block_size, NULL, NULL, NULL}, + {"name", (getter)SHAKE_get_name, NULL, NULL, NULL}, + {0} +}; + +static PyTypeObject SHAKE_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_hashlib.SHAKE", + .tp_dealloc = (destructor)SHAKE_dealloc, + .tp_doc = SHAKE_doc, + .tp_basicsize = sizeof(SHAKE), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, + .tp_methods = SHAKE_methods, + .tp_getset = SHAKE_getset, +}; + +PyDoc_STRVAR(HMAC_doc, +"The object used to calculate HMAC of a message.\n\ +\n\ +Methods:\n\ +\n\ +update() -- updates the current digest with an additional string\n\ +digest() -- return the current digest value\n\ +hexdigest() -- return the current digest as a string of hexadecimal digits\n\ +copy() -- return a copy of the current hash object\n\ +\n\ +Attributes:\n\ +\n\ +name -- the name, including the hash algorithm used by this object\n\ +digest_size -- number of bytes in digest() output\n"); + +static void +HMAC_dealloc(HMAC *self) +{ + if (self->lock) + PyThread_free_lock(self->lock); + PyObject_Free(self); +} +/*[clinic input] +_hashlib.HMAC.copy as HMAC_copy + +Return a copy of the HMAC object. +[clinic start generated code]*/ + +static PyObject * +HMAC_copy_impl(HMAC *self) +/*[clinic end generated code: output=6a3595133ec708a5 input=c471e903458ee9a7]*/ +{ + HMAC *newobj; + + newobj = PyObject_New(HMAC, &HMAC_Type); + if (!newobj) + return NULL; + newobj->lock = NULL; + ENTER_HASHLIB(self) + newobj->ctx = self->ctx; + newobj->key = self->key; + LEAVE_HASHLIB(self) + + return (PyObject *)newobj; +} + +/*[clinic input] +_hashlib.HMAC.update as HMAC_update + + data: Py_buffer + / + +Update the HMAC object with data. +[clinic start generated code]*/ + +static PyObject * +HMAC_update_impl(HMAC *self, Py_buffer *data) +/*[clinic end generated code: output=d3520ecffa6cc3ab input=827e77e990887267]*/ +{ + if (!self->lock && data->len >= HASHLIB_GIL_MINSIZE) + self->lock = PyThread_allocate_lock(); + if (self->lock) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + br_hmac_update(&self->ctx, data->buf, data->len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + br_hmac_update(&self->ctx, data->buf, data->len); + } + Py_RETURN_NONE; +} + +/*[clinic input] +_hashlib.HMAC.digest as HMAC_digest + +Return the digest of the bytes passed to the update() method so far. +[clinic start generated code]*/ + +static PyObject * +HMAC_digest_impl(HMAC *self) +/*[clinic end generated code: output=9853eeca2bdd96df input=d39cb2285b557318]*/ +{ + char digest[64]; + Py_ssize_t digest_size; + + ENTER_HASHLIB(self) + digest_size = br_hmac_out(&self->ctx, digest); + LEAVE_HASHLIB(self) + + return PyBytes_FromStringAndSize(digest, digest_size); +} + +/*[clinic input] +_hashlib.HMAC.hexdigest as HMAC_hexdigest + +Return hexadecimal digest of the bytes passed to the update() method so far. + +This may be used to exchange the value safely in email or other non-binary +environments. +[clinic start generated code]*/ + +static PyObject * +HMAC_hexdigest_impl(HMAC *self) +/*[clinic end generated code: output=9bb0c7abb6940bab input=2471f22b8dba7433]*/ +{ + char digest[64]; + Py_ssize_t digest_size; + + ENTER_HASHLIB(self) + digest_size = br_hmac_out(&self->ctx, digest); + LEAVE_HASHLIB(self) + + return _Py_strhex(digest, digest_size); +} + +static PyMethodDef HMAC_methods[] = { + HMAC_UPDATE_METHODDEF + HMAC_DIGEST_METHODDEF + HMAC_HEXDIGEST_METHODDEF + HMAC_COPY_METHODDEF + {0}, +}; + +static PyObject * +HMAC_get_digest_size(HMAC *self, void *closure) +{ + const br_hash_class *hc; + long digest_size; + + hc = br_hmac_get_digest(&self->ctx); + digest_size = hc->desc >> BR_HASHDESC_OUT_OFF & BR_HASHDESC_OUT_MASK; + return PyLong_FromLong(digest_size); +} + +static PyObject * +HMAC_get_block_size(HMAC *self, void *closure) +{ + const br_hash_class *hc; + long block_size; + + hc = br_hmac_get_digest(&self->ctx); + block_size = 1 << (hc->desc >> BR_HASHDESC_LBLEN_OFF & BR_HASHDESC_LBLEN_MASK); + return PyLong_FromLong(block_size); +} + +static PyObject * +HMAC_get_name(HMAC *self, void *closure) +{ + const br_hash_class *hc; + const char *name = NULL; + + hc = br_hmac_get_digest(&self->ctx); + switch (hc->desc >> BR_HASHDESC_ID_OFF & BR_HASHDESC_ID_MASK) { + case br_md5_ID: name = "hmac-md5"; break; + case br_sha1_ID: name = "hmac-sha1"; break; + case br_sha224_ID: name = "hmac-sha224"; break; + case br_sha256_ID: name = "hmac-sha256"; break; + case br_sha384_ID: name = "hmac-sha384"; break; + case br_sha512_ID: name = "hmac-sha512"; break; + } + + return PyUnicode_FromString(name); +} + +static PyGetSetDef HMAC_getset[] = { + {"digest_size", (getter)HMAC_get_digest_size, NULL, NULL, NULL}, + {"block_size", (getter)HMAC_get_block_size, NULL, NULL, NULL}, + {"name", (getter)HMAC_get_name, NULL, NULL, NULL}, + {0} +}; + +static PyTypeObject HMAC_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_hashlib.HMAC", + .tp_dealloc = (destructor)HMAC_dealloc, + .tp_doc = HMAC_doc, + .tp_basicsize = sizeof(HMAC), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE, + .tp_methods = HMAC_methods, + .tp_getset = HMAC_getset, +}; + +static PyObject * +Hash_new_vtable(PyObject *module, const br_hash_class *hc, + Py_buffer *string, int usedforsecurity) +{ + Hash *self; + + self = PyObject_New(Hash, &Hash_Type); + if (!self) + return NULL; + self->lock = NULL; + hc->init(&self->ctx.vtable); + + if (string->len >= HASHLIB_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS + hc->update(&self->ctx.vtable, string->buf, string->len); + Py_END_ALLOW_THREADS + } else { + hc->update(&self->ctx.vtable, string->buf, string->len); + } + + return (PyObject *)self; +} + +static PyObject * +SHAKE_new(PyObject *module, int bits, Py_buffer *string, int usedforsecurity) +{ + SHAKE *self; + + self = PyObject_New(SHAKE, &SHAKE_Type); + if (!self) + return NULL; + self->lock = NULL; + self->bits = bits; + br_shake_init(&self->ctx, bits); + + if (string->len >= HASHLIB_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS + br_shake_inject(&self->ctx, string->buf, string->len); + Py_END_ALLOW_THREADS + } else { + br_shake_inject(&self->ctx, string->buf, string->len); + } + + return (PyObject *)self; +} + +/*[clinic input] +_hashlib.new + + name: str + string: Py_buffer = None + * + usedforsecurity: bool = True + +Return a new hash object using the named algorithm. + +An optional string argument may be provided and will be +automatically hashed. + +The MD5 and SHA1 algorithms are always supported. +[clinic start generated code]*/ + +static PyObject * +_hashlib_new_impl(PyObject *module, const char *name, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=5459beb11946eb8d input=c7e3a9928c6af923]*/ +{ + const br_hash_class *hc = NULL; + int shake = 0; + + hc = py_hash_by_name(name); + if (hc) + ; + else if (strcmp(name, "shake_128") == 0) + shake = 128; + else if (strcmp(name, "shake_256") == 0) + shake = 256; + else { + PyErr_SetString(PyExc_ValueError, "unsupported hash type"); + return NULL; + } + + if (hc) + return Hash_new_vtable(module, hc, string, usedforsecurity); + if (shake) + return SHAKE_new(module, shake, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_md5 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a md5 hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_md5_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=bf0df21c3ecd9d85 input=75e59cc38a292e51]*/ +{ + return Hash_new_vtable(module, &br_md5_vtable, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_sha1 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a sha1 hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_sha1_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=9c468cf3cfdd2e57 input=0f8ad0fa5d988be8]*/ +{ + return Hash_new_vtable(module, &br_sha1_vtable, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_sha224 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a sha224 hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_sha224_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=9b3fea17aacc8dfe input=21aacab0e6949431]*/ +{ + return Hash_new_vtable(module, &br_sha224_vtable, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_sha256 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a sha256 hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_sha256_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=2c0585ccc6dfa22a input=81dd291675e0f6c9]*/ +{ + return Hash_new_vtable(module, &br_sha256_vtable, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_sha384 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a sha384 hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_sha384_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=196d8d7558cfd155 input=eed0b0128dd67969]*/ +{ + return Hash_new_vtable(module, &br_sha384_vtable, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_sha512 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a sha512 hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_sha512_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=7349b37b20ff6f75 input=da1228b585897043]*/ +{ + return Hash_new_vtable(module, &br_sha512_vtable, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_shake_128 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a shake-128 variable hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_shake_128_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=e51cc0e4bded887e input=fb6dce24fc91d53d]*/ +{ + return SHAKE_new(module, 128, string, usedforsecurity); +} + +/*[clinic input] +_hashlib.openssl_shake_256 + + string: Py_buffer = None + * + usedforsecurity: bool = True + +Returns a shake-256 variable hash object; optionally initialized with a string. +[clinic start generated code]*/ + +static PyObject * +_hashlib_openssl_shake_256_impl(PyObject *module, Py_buffer *string, + int usedforsecurity) +/*[clinic end generated code: output=983a76ff0796751b input=9eb2a133d11e34dc]*/ +{ + return SHAKE_new(module, 256, string, usedforsecurity); +} + +static int +_tscmp(const unsigned char *a, const unsigned char *b, + Py_ssize_t len_a, Py_ssize_t len_b) +{ + /* loop count depends on length of b. Might leak very little timing + * information if sizes are different. + */ + Py_ssize_t length = len_b; + unsigned result = 0; + size_t i; + + if (len_a != length) { + a = b; + result = 1; + } + + for (i = 0; i < length; i++) + result |= (unsigned)a[i] ^ (unsigned)b[i]; + + return ~(result | -result) >> CHAR_BIT * sizeof(result) - 1; +} + +/*[clinic input] +_hashlib.compare_digest + + a: object + b: object + / + +Return 'a == b'. + +This function uses an approach designed to prevent +timing analysis, making it appropriate for cryptography. + +a and b must both be of the same type: either str (ASCII only), +or any bytes-like object. + +Note: If a and b are of different lengths, or if an error occurs, +a timing attack could theoretically reveal information about the +types and lengths of a and b--but not their values. +[clinic start generated code]*/ + +static PyObject * +_hashlib_compare_digest_impl(PyObject *module, PyObject *a, PyObject *b) +/*[clinic end generated code: output=6f1c13927480aed9 input=f9cc6da970b1b1d5]*/ +{ + int rc; + + /* ASCII unicode string */ + if(PyUnicode_Check(a) && PyUnicode_Check(b)) { + if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) { + return NULL; + } + if (!PyUnicode_IS_ASCII(a) || !PyUnicode_IS_ASCII(b)) { + PyErr_SetString(PyExc_TypeError, + "comparing strings with non-ASCII characters is " + "not supported"); + return NULL; + } + + rc = _tscmp(PyUnicode_DATA(a), + PyUnicode_DATA(b), + PyUnicode_GET_LENGTH(a), + PyUnicode_GET_LENGTH(b)); + } + /* fallback to buffer interface for bytes, bytesarray and other */ + else { + Py_buffer view_a; + Py_buffer view_b; + + if (PyObject_CheckBuffer(a) == 0 && PyObject_CheckBuffer(b) == 0) { + PyErr_Format(PyExc_TypeError, + "unsupported operand types(s) or combination of types: " + "'%.100s' and '%.100s'", + Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); + return NULL; + } + + if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) { + return NULL; + } + if (view_a.ndim > 1) { + PyErr_SetString(PyExc_BufferError, + "Buffer must be single dimension"); + PyBuffer_Release(&view_a); + return NULL; + } + + if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) { + PyBuffer_Release(&view_a); + return NULL; + } + if (view_b.ndim > 1) { + PyErr_SetString(PyExc_BufferError, + "Buffer must be single dimension"); + PyBuffer_Release(&view_a); + PyBuffer_Release(&view_b); + return NULL; + } + + rc = _tscmp((const unsigned char*)view_a.buf, + (const unsigned char*)view_b.buf, + view_a.len, + view_b.len); + + PyBuffer_Release(&view_a); + PyBuffer_Release(&view_b); + } + + return PyBool_FromLong(rc); +} + +static struct PyMethodDef hashlib_methods[] = { + _HASHLIB_NEW_METHODDEF + _HASHLIB_HMAC_SINGLESHOT_METHODDEF + _HASHLIB_HMAC_NEW_METHODDEF + _HASHLIB_OPENSSL_MD5_METHODDEF + _HASHLIB_OPENSSL_SHA1_METHODDEF + _HASHLIB_OPENSSL_SHA224_METHODDEF + _HASHLIB_OPENSSL_SHA256_METHODDEF + _HASHLIB_OPENSSL_SHA384_METHODDEF + _HASHLIB_OPENSSL_SHA512_METHODDEF + _HASHLIB_OPENSSL_SHAKE_128_METHODDEF + _HASHLIB_OPENSSL_SHAKE_256_METHODDEF + _HASHLIB_COMPARE_DIGEST_METHODDEF + {0} +}; + +/* Fast HMAC for hmac.digest() */ + +/*[clinic input] +_hashlib.hmac_digest as _hashlib_hmac_singleshot + + key: Py_buffer + msg: Py_buffer + digest: str + +Single-shot HMAC. +[clinic start generated code]*/ + +static PyObject * +_hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, + Py_buffer *msg, const char *digest) +/*[clinic end generated code: output=15658ede5ab98185 input=019dffc571909a46]*/ +{ + char buf[64]; + Py_ssize_t buf_len; + br_hmac_context ctx; + br_hmac_key_context keyctx; + const br_hash_class *hc; + + hc = py_hash_by_name(digest); + if (!hc) { + PyErr_SetString(PyExc_ValueError, "unsupported hash type"); + return NULL; + } + if (msg->len >= HASHLIB_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS + br_hmac_key_init(&keyctx, hc, key->buf, key->len); + br_hmac_init(&ctx, &keyctx, 0); + br_hmac_update(&ctx, msg->buf, msg->len); + br_hmac_out(&ctx, buf); + Py_END_ALLOW_THREADS + } else { + br_hmac_key_init(&keyctx, hc, key->buf, key->len); + br_hmac_init(&ctx, &keyctx, 0); + br_hmac_update(&ctx, msg->buf, msg->len); + br_hmac_out(&ctx, buf); + } + buf_len = br_hmac_size(&ctx); + + return PyBytes_FromStringAndSize(buf, buf_len); +} + +/*[clinic input] +_hashlib.hmac_new + + key: Py_buffer + msg: Py_buffer = None + digestmod: str(c_default="NULL") = None + +Return a new hmac object. +[clinic start generated code]*/ + +static PyObject * +_hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, Py_buffer *msg, + const char *digestmod) +/*[clinic end generated code: output=5733a8600554bba2 input=b0125f4222a0d06d]*/ +{ + HMAC *self; + const br_hash_class *hc; + + printf("hmac new\n"); + + if (!digestmod || !digestmod[0]) { + PyErr_SetString( + PyExc_TypeError, "missing required parameter 'digestmod'"); + return NULL; + } + hc = py_hash_by_name(digestmod); + if (!hc) { + PyErr_SetString(PyExc_ValueError, "unknown hash function"); + return NULL; + } + self = PyObject_New(HMAC, &HMAC_Type); + if (!self) + return NULL; + self->lock = NULL; + br_hmac_key_init(&self->key, hc, key->buf, key->len); + br_hmac_init(&self->ctx, &self->key, 0); + + if (msg->len >= HASHLIB_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS + br_hmac_update(&self->ctx, msg->buf, msg->len); + Py_END_ALLOW_THREADS + } else { + br_hmac_update(&self->ctx, msg->buf, msg->len); + } + + return (PyObject *)self; +} + +static struct PyModuleDef _hashlibmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "_hashlib", + .m_doc = "BearSSL interface for hashlib module", + .m_methods = hashlib_methods, +}; + +PyMODINIT_FUNC +PyInit__hashlib(void) +{ + PyObject *m = NULL, *set = NULL, *name; + static const char *const names[] = { + "md5", + "sha1", + "sha224", + "sha256", + "sha384", + "sha512", + "shake_128", + "shake_256", + }; + int r; + + m = PyState_FindModule(&_hashlibmodule); + if (m) { + Py_INCREF(m); + return m; + } + m = PyModule_Create(&_hashlibmodule); + if (!m) + goto err; + if (PyModule_AddType(m, &Hash_Type) < 0) + goto err; + if (PyModule_AddType(m, &SHAKE_Type) < 0) + goto err; + if (PyModule_AddType(m, &HMAC_Type) < 0) + goto err; + set = PyFrozenSet_New(NULL); + if (!set) + goto err; + for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++) { + name = PyUnicode_FromString(names[i]); + if (!name) + goto err; + r = PySet_Add(set, name); + Py_DECREF(name); + if (r != 0) + goto err; + } + if (PyModule_AddObject(m, "openssl_md_meth_names", set) < 0) + goto err; + + return m; + + err: + if (set) + Py_DECREF(set); + if (m) + Py_DECREF(m); + return NULL; +} diff --git a/Modules/clinic/_hashbearssl.c.h b/Modules/clinic/_hashbearssl.c.h new file mode 100644 index 0000000000..49bf8f9287 --- /dev/null +++ b/Modules/clinic/_hashbearssl.c.h @@ -0,0 +1,1113 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(Hash_update__doc__, +"update($self, data, /)\n" +"--\n" +"\n" +"Update this hash object\'s state with the provided string."); + +#define HASH_UPDATE_METHODDEF \ + {"update", (PyCFunction)Hash_update, METH_O, Hash_update__doc__}, + +static PyObject * +Hash_update_impl(Hash *self, Py_buffer *data); + +static PyObject * +Hash_update(Hash *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&data, 'C')) { + _PyArg_BadArgument("update", "argument", "contiguous buffer", arg); + goto exit; + } + return_value = Hash_update_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) { + PyBuffer_Release(&data); + } + + return return_value; +} + +PyDoc_STRVAR(Hash_digest__doc__, +"digest($self, /)\n" +"--\n" +"\n" +"Return the digest value as a bytes object."); + +#define HASH_DIGEST_METHODDEF \ + {"digest", (PyCFunction)Hash_digest, METH_NOARGS, Hash_digest__doc__}, + +static PyObject * +Hash_digest_impl(Hash *self); + +static PyObject * +Hash_digest(Hash *self, PyObject *Py_UNUSED(ignored)) +{ + return Hash_digest_impl(self); +} + +PyDoc_STRVAR(Hash_hexdigest__doc__, +"hexdigest($self, /)\n" +"--\n" +"\n" +"Return the digest value as a string of hexadecimal digits."); + +#define HASH_HEXDIGEST_METHODDEF \ + {"hexdigest", (PyCFunction)Hash_hexdigest, METH_NOARGS, Hash_hexdigest__doc__}, + +static PyObject * +Hash_hexdigest_impl(Hash *self); + +static PyObject * +Hash_hexdigest(Hash *self, PyObject *Py_UNUSED(ignored)) +{ + return Hash_hexdigest_impl(self); +} + +PyDoc_STRVAR(Hash_copy__doc__, +"copy($self, /)\n" +"--\n" +"\n" +"Return a copy of the hash object."); + +#define HASH_COPY_METHODDEF \ + {"copy", (PyCFunction)Hash_copy, METH_NOARGS, Hash_copy__doc__}, + +static PyObject * +Hash_copy_impl(Hash *self); + +static PyObject * +Hash_copy(Hash *self, PyObject *Py_UNUSED(ignored)) +{ + return Hash_copy_impl(self); +} + +PyDoc_STRVAR(SHAKE_update__doc__, +"update($self, data, /)\n" +"--\n" +"\n" +"Update this hash object\'s state with the provided string."); + +#define SHAKE_UPDATE_METHODDEF \ + {"update", (PyCFunction)SHAKE_update, METH_O, SHAKE_update__doc__}, + +static PyObject * +SHAKE_update_impl(SHAKE *self, Py_buffer *data); + +static PyObject * +SHAKE_update(SHAKE *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&data, 'C')) { + _PyArg_BadArgument("update", "argument", "contiguous buffer", arg); + goto exit; + } + return_value = SHAKE_update_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) { + PyBuffer_Release(&data); + } + + return return_value; +} + +PyDoc_STRVAR(SHAKE_digest__doc__, +"digest($self, /, length)\n" +"--\n" +"\n" +"Return the digest value as a bytes object."); + +#define SHAKE_DIGEST_METHODDEF \ + {"digest", (PyCFunction)(void(*)(void))SHAKE_digest, METH_FASTCALL|METH_KEYWORDS, SHAKE_digest__doc__}, + +static PyObject * +SHAKE_digest_impl(SHAKE *self, Py_ssize_t length); + +static PyObject * +SHAKE_digest(SHAKE *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"length", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "digest", 0}; + PyObject *argsbuf[1]; + Py_ssize_t length; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + 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 = SHAKE_digest_impl(self, length); + +exit: + return return_value; +} + +PyDoc_STRVAR(SHAKE_hexdigest__doc__, +"hexdigest($self, /, length)\n" +"--\n" +"\n" +"Return the digest value as a string of hexadecimal digits."); + +#define SHAKE_HEXDIGEST_METHODDEF \ + {"hexdigest", (PyCFunction)(void(*)(void))SHAKE_hexdigest, METH_FASTCALL|METH_KEYWORDS, SHAKE_hexdigest__doc__}, + +static PyObject * +SHAKE_hexdigest_impl(SHAKE *self, Py_ssize_t length); + +static PyObject * +SHAKE_hexdigest(SHAKE *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"length", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "hexdigest", 0}; + PyObject *argsbuf[1]; + Py_ssize_t length; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + 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 = SHAKE_hexdigest_impl(self, length); + +exit: + return return_value; +} + +PyDoc_STRVAR(SHAKE_copy__doc__, +"copy($self, /)\n" +"--\n" +"\n" +"Return a copy of the SHAKE object."); + +#define SHAKE_COPY_METHODDEF \ + {"copy", (PyCFunction)SHAKE_copy, METH_NOARGS, SHAKE_copy__doc__}, + +static PyObject * +SHAKE_copy_impl(SHAKE *self); + +static PyObject * +SHAKE_copy(SHAKE *self, PyObject *Py_UNUSED(ignored)) +{ + return SHAKE_copy_impl(self); +} + +PyDoc_STRVAR(HMAC_copy__doc__, +"copy($self, /)\n" +"--\n" +"\n" +"Return a copy of the HMAC object."); + +#define HMAC_COPY_METHODDEF \ + {"copy", (PyCFunction)HMAC_copy, METH_NOARGS, HMAC_copy__doc__}, + +static PyObject * +HMAC_copy_impl(HMAC *self); + +static PyObject * +HMAC_copy(HMAC *self, PyObject *Py_UNUSED(ignored)) +{ + return HMAC_copy_impl(self); +} + +PyDoc_STRVAR(HMAC_update__doc__, +"update($self, data, /)\n" +"--\n" +"\n" +"Update the HMAC object with data."); + +#define HMAC_UPDATE_METHODDEF \ + {"update", (PyCFunction)HMAC_update, METH_O, HMAC_update__doc__}, + +static PyObject * +HMAC_update_impl(HMAC *self, Py_buffer *data); + +static PyObject * +HMAC_update(HMAC *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&data, 'C')) { + _PyArg_BadArgument("update", "argument", "contiguous buffer", arg); + goto exit; + } + return_value = HMAC_update_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) { + PyBuffer_Release(&data); + } + + return return_value; +} + +PyDoc_STRVAR(HMAC_digest__doc__, +"digest($self, /)\n" +"--\n" +"\n" +"Return the digest of the bytes passed to the update() method so far."); + +#define HMAC_DIGEST_METHODDEF \ + {"digest", (PyCFunction)HMAC_digest, METH_NOARGS, HMAC_digest__doc__}, + +static PyObject * +HMAC_digest_impl(HMAC *self); + +static PyObject * +HMAC_digest(HMAC *self, PyObject *Py_UNUSED(ignored)) +{ + return HMAC_digest_impl(self); +} + +PyDoc_STRVAR(HMAC_hexdigest__doc__, +"hexdigest($self, /)\n" +"--\n" +"\n" +"Return hexadecimal digest of the bytes passed to the update() method so far.\n" +"\n" +"This may be used to exchange the value safely in email or other non-binary\n" +"environments."); + +#define HMAC_HEXDIGEST_METHODDEF \ + {"hexdigest", (PyCFunction)HMAC_hexdigest, METH_NOARGS, HMAC_hexdigest__doc__}, + +static PyObject * +HMAC_hexdigest_impl(HMAC *self); + +static PyObject * +HMAC_hexdigest(HMAC *self, PyObject *Py_UNUSED(ignored)) +{ + return HMAC_hexdigest_impl(self); +} + +PyDoc_STRVAR(_hashlib_new__doc__, +"new($module, /, name, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Return a new hash object using the named algorithm.\n" +"\n" +"An optional string argument may be provided and will be\n" +"automatically hashed.\n" +"\n" +"The MD5 and SHA1 algorithms are always supported."); + +#define _HASHLIB_NEW_METHODDEF \ + {"new", (PyCFunction)(void(*)(void))_hashlib_new, METH_FASTCALL|METH_KEYWORDS, _hashlib_new__doc__}, + +static PyObject * +_hashlib_new_impl(PyObject *module, const char *name, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"name", "string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "new", 0}; + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + const char *name; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("new", "argument 'name'", "str", args[0]); + goto exit; + } + Py_ssize_t name_length; + name = PyUnicode_AsUTF8AndSize(args[0], &name_length); + if (name == NULL) { + goto exit; + } + if (strlen(name) != (size_t)name_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + if (PyObject_GetBuffer(args[1], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("new", "argument 'string'", "contiguous buffer", args[1]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[2]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_new_impl(module, name, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_md5__doc__, +"openssl_md5($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a md5 hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_MD5_METHODDEF \ + {"openssl_md5", (PyCFunction)(void(*)(void))_hashlib_openssl_md5, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_md5__doc__}, + +static PyObject * +_hashlib_openssl_md5_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_md5(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_md5", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_md5", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_md5_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_sha1__doc__, +"openssl_sha1($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a sha1 hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHA1_METHODDEF \ + {"openssl_sha1", (PyCFunction)(void(*)(void))_hashlib_openssl_sha1, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha1__doc__}, + +static PyObject * +_hashlib_openssl_sha1_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_sha1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha1", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_sha1", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_sha1_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_sha224__doc__, +"openssl_sha224($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a sha224 hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHA224_METHODDEF \ + {"openssl_sha224", (PyCFunction)(void(*)(void))_hashlib_openssl_sha224, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha224__doc__}, + +static PyObject * +_hashlib_openssl_sha224_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_sha224(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha224", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_sha224", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_sha224_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_sha256__doc__, +"openssl_sha256($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a sha256 hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHA256_METHODDEF \ + {"openssl_sha256", (PyCFunction)(void(*)(void))_hashlib_openssl_sha256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha256__doc__}, + +static PyObject * +_hashlib_openssl_sha256_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_sha256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha256", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_sha256", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_sha256_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_sha384__doc__, +"openssl_sha384($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a sha384 hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHA384_METHODDEF \ + {"openssl_sha384", (PyCFunction)(void(*)(void))_hashlib_openssl_sha384, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha384__doc__}, + +static PyObject * +_hashlib_openssl_sha384_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_sha384(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha384", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_sha384", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_sha384_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_sha512__doc__, +"openssl_sha512($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a sha512 hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHA512_METHODDEF \ + {"openssl_sha512", (PyCFunction)(void(*)(void))_hashlib_openssl_sha512, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_sha512__doc__}, + +static PyObject * +_hashlib_openssl_sha512_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_sha512(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_sha512", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_sha512", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_sha512_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_shake_128__doc__, +"openssl_shake_128($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a shake-128 variable hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHAKE_128_METHODDEF \ + {"openssl_shake_128", (PyCFunction)(void(*)(void))_hashlib_openssl_shake_128, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_128__doc__}, + +static PyObject * +_hashlib_openssl_shake_128_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_shake_128(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_shake_128", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_shake_128", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_shake_128_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_openssl_shake_256__doc__, +"openssl_shake_256($module, /, string=None, *, usedforsecurity=True)\n" +"--\n" +"\n" +"Returns a shake-256 variable hash object; optionally initialized with a string."); + +#define _HASHLIB_OPENSSL_SHAKE_256_METHODDEF \ + {"openssl_shake_256", (PyCFunction)(void(*)(void))_hashlib_openssl_shake_256, METH_FASTCALL|METH_KEYWORDS, _hashlib_openssl_shake_256__doc__}, + +static PyObject * +_hashlib_openssl_shake_256_impl(PyObject *module, Py_buffer *string, + int usedforsecurity); + +static PyObject * +_hashlib_openssl_shake_256(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"string", "usedforsecurity", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "openssl_shake_256", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + Py_buffer string = {NULL, NULL}; + int usedforsecurity = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + if (PyObject_GetBuffer(args[0], &string, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&string, 'C')) { + _PyArg_BadArgument("openssl_shake_256", "argument 'string'", "contiguous buffer", args[0]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } + usedforsecurity = PyObject_IsTrue(args[1]); + if (usedforsecurity < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = _hashlib_openssl_shake_256_impl(module, &string, usedforsecurity); + +exit: + /* Cleanup for string */ + if (string.obj) { + PyBuffer_Release(&string); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_compare_digest__doc__, +"compare_digest($module, a, b, /)\n" +"--\n" +"\n" +"Return \'a == b\'.\n" +"\n" +"This function uses an approach designed to prevent\n" +"timing analysis, making it appropriate for cryptography.\n" +"\n" +"a and b must both be of the same type: either str (ASCII only),\n" +"or any bytes-like object.\n" +"\n" +"Note: If a and b are of different lengths, or if an error occurs,\n" +"a timing attack could theoretically reveal information about the\n" +"types and lengths of a and b--but not their values."); + +#define _HASHLIB_COMPARE_DIGEST_METHODDEF \ + {"compare_digest", (PyCFunction)(void(*)(void))_hashlib_compare_digest, METH_FASTCALL, _hashlib_compare_digest__doc__}, + +static PyObject * +_hashlib_compare_digest_impl(PyObject *module, PyObject *a, PyObject *b); + +static PyObject * +_hashlib_compare_digest(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + + if (!_PyArg_CheckPositional("compare_digest", nargs, 2, 2)) { + goto exit; + } + a = args[0]; + b = args[1]; + return_value = _hashlib_compare_digest_impl(module, a, b); + +exit: + return return_value; +} + +PyDoc_STRVAR(_hashlib_hmac_singleshot__doc__, +"hmac_digest($module, /, key, msg, digest)\n" +"--\n" +"\n" +"Single-shot HMAC."); + +#define _HASHLIB_HMAC_SINGLESHOT_METHODDEF \ + {"hmac_digest", (PyCFunction)(void(*)(void))_hashlib_hmac_singleshot, METH_FASTCALL|METH_KEYWORDS, _hashlib_hmac_singleshot__doc__}, + +static PyObject * +_hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key, + Py_buffer *msg, const char *digest); + +static PyObject * +_hashlib_hmac_singleshot(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"key", "msg", "digest", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "hmac_digest", 0}; + PyObject *argsbuf[3]; + Py_buffer key = {NULL, NULL}; + Py_buffer msg = {NULL, NULL}; + const char *digest; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &key, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&key, 'C')) { + _PyArg_BadArgument("hmac_digest", "argument 'key'", "contiguous buffer", args[0]); + goto exit; + } + if (PyObject_GetBuffer(args[1], &msg, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&msg, 'C')) { + _PyArg_BadArgument("hmac_digest", "argument 'msg'", "contiguous buffer", args[1]); + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("hmac_digest", "argument 'digest'", "str", args[2]); + goto exit; + } + Py_ssize_t digest_length; + digest = PyUnicode_AsUTF8AndSize(args[2], &digest_length); + if (digest == NULL) { + goto exit; + } + if (strlen(digest) != (size_t)digest_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + return_value = _hashlib_hmac_singleshot_impl(module, &key, &msg, digest); + +exit: + /* Cleanup for key */ + if (key.obj) { + PyBuffer_Release(&key); + } + /* Cleanup for msg */ + if (msg.obj) { + PyBuffer_Release(&msg); + } + + return return_value; +} + +PyDoc_STRVAR(_hashlib_hmac_new__doc__, +"hmac_new($module, /, key, msg=None, digestmod=None)\n" +"--\n" +"\n" +"Return a new hmac object."); + +#define _HASHLIB_HMAC_NEW_METHODDEF \ + {"hmac_new", (PyCFunction)(void(*)(void))_hashlib_hmac_new, METH_FASTCALL|METH_KEYWORDS, _hashlib_hmac_new__doc__}, + +static PyObject * +_hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, Py_buffer *msg, + const char *digestmod); + +static PyObject * +_hashlib_hmac_new(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"key", "msg", "digestmod", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "hmac_new", 0}; + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + Py_buffer key = {NULL, NULL}; + Py_buffer msg = {NULL, NULL}; + const char *digestmod = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &key, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&key, 'C')) { + _PyArg_BadArgument("hmac_new", "argument 'key'", "contiguous buffer", args[0]); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + if (PyObject_GetBuffer(args[1], &msg, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&msg, 'C')) { + _PyArg_BadArgument("hmac_new", "argument 'msg'", "contiguous buffer", args[1]); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("hmac_new", "argument 'digestmod'", "str", args[2]); + goto exit; + } + Py_ssize_t digestmod_length; + digestmod = PyUnicode_AsUTF8AndSize(args[2], &digestmod_length); + if (digestmod == NULL) { + goto exit; + } + if (strlen(digestmod) != (size_t)digestmod_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = _hashlib_hmac_new_impl(module, &key, &msg, digestmod); + +exit: + /* Cleanup for key */ + if (key.obj) { + PyBuffer_Release(&key); + } + /* Cleanup for msg */ + if (msg.obj) { + PyBuffer_Release(&msg); + } + + return return_value; +} +/*[clinic end generated code: output=b4705bad5ece43e9 input=a9049054013a1b77]*/ -- 2.32.0