Skip to content

Commit 2c52720

Browse files
committed
implement HMAC.copy() interface
The internal HACL* state can be agilely copied. Stated otherwise, this only adds a thin wrapper around `Hacl_Streaming_HMAC_copy`
1 parent 06a316f commit 2c52720

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

Modules/clinic/hmacmodule.c.h

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/hmacmodule.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,79 @@ has_uint32_t_buffer_length(const Py_buffer *buffer)
593593

594594
// --- HMAC object ------------------------------------------------------------
595595

596+
/*
597+
* Copy HMAC hash information from 'src' to 'out'.
598+
*/
599+
static void
600+
hmac_copy_hinfo(HMACObject *out, const HMACObject *src)
601+
{
602+
assert(src->name != NULL);
603+
out->name = Py_NewRef(src->name);
604+
assert(src->kind != Py_hmac_kind_hash_unknown);
605+
out->kind = src->kind;
606+
assert(src->block_size <= Py_hmac_hash_max_block_size);
607+
out->block_size = src->block_size;
608+
assert(src->digest_size <= Py_hmac_hash_max_digest_size);
609+
out->digest_size = src->digest_size;
610+
assert(src->api.compute != NULL);
611+
assert(src->api.compute_py != NULL);
612+
out->api = src->api;
613+
}
614+
615+
/*
616+
* Copy the HMAC internal state from 'src' to 'out'.
617+
*
618+
* The internal state of 'out' must not already exist.
619+
*
620+
* Return 0 on success and -1 on failure.
621+
*/
622+
static int
623+
hmac_copy_state(HMACObject *out, const HMACObject *src)
624+
{
625+
assert(src->state != NULL);
626+
out->state = Hacl_Streaming_HMAC_copy(src->state);
627+
if (out->state == NULL) {
628+
PyErr_NoMemory();
629+
return -1;
630+
}
631+
return 0;
632+
}
633+
634+
/*[clinic input]
635+
_hmac.HMAC.copy
636+
637+
cls: defining_class
638+
639+
Return a copy ("clone") of the HMAC object.
640+
[clinic start generated code]*/
641+
642+
static PyObject *
643+
_hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls)
644+
/*[clinic end generated code: output=a955bfa55b65b215 input=17b2c0ad0b147e36]*/
645+
{
646+
hmacmodule_state *state = get_hmacmodule_state_by_cls(cls);
647+
HMACObject *copy = PyObject_GC_New(HMACObject, state->hmac_type);
648+
if (copy == NULL) {
649+
return NULL;
650+
}
651+
652+
ENTER_HASHLIB(self);
653+
/* copy hash information */
654+
hmac_copy_hinfo(copy, self);
655+
/* copy internal state */
656+
int rc = hmac_copy_state(copy, self);
657+
LEAVE_HASHLIB(self);
658+
659+
if (rc < 0) {
660+
Py_DECREF(copy);
661+
return NULL;
662+
}
663+
664+
HASHLIB_INIT_MUTEX(copy);
665+
PyObject_GC_Track(copy);
666+
return (PyObject *)copy;
667+
}
668+
596669
/*
597670
* Update the HMAC object with the given buffer.
598671
*
@@ -809,6 +882,7 @@ HMACObject_traverse(PyObject *self, visitproc visit, void *arg)
809882
}
810883

811884
static PyMethodDef HMACObject_methods[] = {
885+
_HMAC_HMAC_COPY_METHODDEF
812886
_HMAC_HMAC_UPDATE_METHODDEF
813887
_HMAC_HMAC_DIGEST_METHODDEF
814888
_HMAC_HMAC_HEXDIGEST_METHODDEF

0 commit comments

Comments
 (0)