Skip to content

Commit 2b010ef

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 2d02577 commit 2b010ef

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
@@ -18,6 +18,7 @@
1818

1919
#include "Python.h"
2020
#include "pycore_hashtable.h"
21+
#include "pycore_strhex.h" // _Py_strhex()
2122

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

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

757808
static PyMethodDef HMACObject_methods[] = {
758809
_HMAC_HMAC_UPDATE_METHODDEF
810+
_HMAC_HMAC_DIGEST_METHODDEF
811+
_HMAC_HMAC_HEXDIGEST_METHODDEF
759812
{NULL, NULL, 0, NULL} /* sentinel */
760813
};
761814

0 commit comments

Comments
 (0)