Skip to content

Commit dfd4826

Browse files
committed
implement HMAC.{digest,hexdigest}() methods
The HMAC-HASH digest can be extracted using the internal HACL* state. Stated otherwise, this adds a thin (thread-safe) wrapper around `Hacl_Streaming_HMAC_digest`.
1 parent a8b074a commit dfd4826

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

Modules/clinic/hmacmodule.c.h

Lines changed: 40 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: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "Python.h"
2121
#include "pycore_hashtable.h"
22+
#include "pycore_strhex.h" // _Py_strhex()
2223

2324
// Small mismatch between the variable names Python defines as part of configure
2425
// at the ones HACL* expects to be set in order to enable those headers.
@@ -685,6 +686,56 @@ _hmac_HMAC_update_impl(HMACObject *self, PyObject *msgobj)
685686
return rc < 0 ? NULL : Py_None;
686687
}
687688

689+
/*
690+
* Compute the HMAC-HASH digest from the internal HACL* state.
691+
*
692+
* At least 'self->digest_size' bytes should be available
693+
* in the 'digest' pointed memory area.
694+
*/
695+
static inline void
696+
hmac_digest_compute_cond_lock(HMACObject *self, uint8_t *digest)
697+
{
698+
assert(digest != NULL);
699+
ENTER_HASHLIB(self); // conditionally acquire a lock
700+
Hacl_Streaming_HMAC_digest(self->state, digest, self->digest_size);
701+
LEAVE_HASHLIB(self);
702+
}
703+
704+
/*[clinic input]
705+
_hmac.HMAC.digest
706+
707+
Return the digest of the bytes passed to the update() method so far.
708+
[clinic start generated code]*/
709+
710+
static PyObject *
711+
_hmac_HMAC_digest_impl(HMACObject *self)
712+
/*[clinic end generated code: output=5bf3cc5862d26ada input=46ada2d337ddcc85]*/
713+
{
714+
assert(self->digest_size <= Py_hmac_hash_max_digest_size);
715+
uint8_t digest[Py_hmac_hash_max_digest_size];
716+
hmac_digest_compute_cond_lock(self, digest);
717+
return PyBytes_FromStringAndSize((const char *)digest, self->digest_size);
718+
}
719+
720+
/*[clinic input]
721+
_hmac.HMAC.hexdigest
722+
723+
Return hexadecimal digest of the bytes passed to the update() method so far.
724+
725+
This may be used to exchange the value safely in email or other non-binary
726+
environments.
727+
[clinic start generated code]*/
728+
729+
static PyObject *
730+
_hmac_HMAC_hexdigest_impl(HMACObject *self)
731+
/*[clinic end generated code: output=6659807a09ae14ec input=a7460247846b4c15]*/
732+
{
733+
assert(self->digest_size <= Py_hmac_hash_max_digest_size);
734+
uint8_t digest[Py_hmac_hash_max_digest_size];
735+
hmac_digest_compute_cond_lock(self, digest);
736+
return _Py_strhex((const char *)digest, self->digest_size);
737+
}
738+
688739
/*[clinic input]
689740
@getter
690741
_hmac.HMAC.name
@@ -759,6 +810,8 @@ HMACObject_traverse(PyObject *self, visitproc visit, void *arg)
759810

760811
static PyMethodDef HMACObject_methods[] = {
761812
_HMAC_HMAC_UPDATE_METHODDEF
813+
_HMAC_HMAC_DIGEST_METHODDEF
814+
_HMAC_HMAC_HEXDIGEST_METHODDEF
762815
{NULL, NULL, 0, NULL} /* sentinel */
763816
};
764817

0 commit comments

Comments
 (0)