Skip to content

Commit 35b53f6

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 01c9f4a commit 35b53f6

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
@@ -590,6 +590,79 @@ has_uint32_t_buffer_length(const Py_buffer *buffer)
590590

591591
// --- HMAC object ------------------------------------------------------------
592592

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

808881
static PyMethodDef HMACObject_methods[] = {
882+
_HMAC_HMAC_COPY_METHODDEF
809883
_HMAC_HMAC_UPDATE_METHODDEF
810884
_HMAC_HMAC_DIGEST_METHODDEF
811885
_HMAC_HMAC_HEXDIGEST_METHODDEF

0 commit comments

Comments
 (0)