Skip to content

Commit 4722918

Browse files
committed
implement minimal HMAC object interface
This commit adds the initial bits for a stateful HMAC object to provide streaming HMAC.
1 parent ac3b123 commit 4722918

File tree

1 file changed

+130
-1
lines changed

1 file changed

+130
-1
lines changed

Modules/hmacmodule.c

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#include "Python.h"
2020
#include "pycore_hashtable.h"
2121

22+
// Small mismatch between the variable names Python defines as part of configure
23+
// at the ones HACL* expects to be set in order to enable those headers.
24+
#define HACL_CAN_COMPILE_VEC128 HACL_CAN_COMPILE_SIMD128
25+
#define HACL_CAN_COMPILE_VEC256 HACL_CAN_COMPILE_SIMD256
26+
2227
#include "_hacl/Hacl_HMAC.h"
2328
#include "_hacl/Hacl_Streaming_HMAC.h" // Hacl_Agile_Hash_* identifiers
2429
#include "_hacl/Hacl_Streaming_Types.h" // Hacl_Streaming_Types_error_code
@@ -202,6 +207,8 @@ typedef struct py_hmac_hinfo {
202207
typedef struct hmacmodule_state {
203208
_Py_hashtable_t *hinfo_table;
204209
PyObject *unknown_hash_error;
210+
/* HMAC object type */
211+
PyTypeObject *hmac_type;
205212
/* interned strings */
206213
PyObject *str_lower;
207214
} hmacmodule_state;
@@ -214,17 +221,62 @@ get_hmacmodule_state(PyObject *module)
214221
return (hmacmodule_state *)state;
215222
}
216223

224+
static inline hmacmodule_state *
225+
get_hmacmodule_state_by_cls(PyTypeObject *cls)
226+
{
227+
void *state = PyType_GetModuleState(cls);
228+
assert(state != NULL);
229+
return (hmacmodule_state *)state;
230+
}
231+
232+
// --- HMAC Object ------------------------------------------------------------
233+
234+
typedef Hacl_Streaming_HMAC_agile_state HACL_HMAC_state;
235+
236+
typedef struct HMACObject {
237+
PyObject_HEAD
238+
239+
bool use_mutex;
240+
PyMutex mutex;
241+
242+
// Hash function information
243+
PyObject *name; // rendered name (exact unicode object)
244+
HMAC_Hash_Kind kind; // can be used for runtime dispatch (must be known)
245+
uint32_t block_size;
246+
uint32_t digest_size;
247+
py_hmac_hacl_api api;
248+
249+
// HMAC HACL* internal state.
250+
HACL_HMAC_state *state;
251+
} HMACObject;
252+
253+
#define HMACObject_CAST(op) ((HMACObject *)(op))
254+
217255
// --- HMAC module clinic configuration ---------------------------------------
218256

219257
/*[clinic input]
220258
module _hmac
259+
class _hmac.HMAC "HMACObject *" "clinic_state()->hmac_type"
221260
[clinic start generated code]*/
222-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=799f0f10157d561f]*/
261+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c8bab73fde49ba8a]*/
223262

263+
#define clinic_state() (get_hmacmodule_state_by_cls(Py_TYPE(self)))
224264
#include "clinic/hmacmodule.c.h"
265+
#undef clinic_state
225266

226267
// --- Helpers ----------------------------------------------------------------
227268

269+
/*
270+
* Free the HACL* internal state.
271+
*/
272+
static inline void
273+
_hacl_hmac_state_free(HACL_HMAC_state *state)
274+
{
275+
if (state != NULL) {
276+
Hacl_Streaming_HMAC_free(state);
277+
}
278+
}
279+
228280
/* Static information used to construct the hash table. */
229281
static const py_hmac_hinfo py_hmac_static_hinfo[] = {
230282
#define Py_HMAC_HINFO_HACL_API(HACL_HID) \
@@ -372,6 +424,63 @@ has_uint32_t_buffer_length(const Py_buffer *buffer)
372424
#endif
373425
}
374426

427+
// --- HMAC object ------------------------------------------------------------
428+
429+
static int
430+
HMACObject_clear(PyObject *self)
431+
{
432+
HMACObject *hmac = HMACObject_CAST(self);
433+
Py_CLEAR(hmac->name);
434+
_hacl_hmac_state_free(hmac->state);
435+
hmac->state = NULL;
436+
return 0;
437+
}
438+
439+
static void
440+
HMACObject_dealloc(PyObject *self)
441+
{
442+
PyTypeObject *type = Py_TYPE(self);
443+
PyObject_GC_UnTrack(self);
444+
(void)HMACObject_clear(self);
445+
type->tp_free(self);
446+
Py_DECREF(type);
447+
}
448+
449+
static int
450+
HMACObject_traverse(PyObject *self, visitproc visit, void *arg)
451+
{
452+
Py_VISIT(Py_TYPE(self));
453+
return 0;
454+
}
455+
456+
static PyMethodDef HMACObject_methods[] = {
457+
{NULL, NULL, 0, NULL} /* sentinel */
458+
};
459+
460+
static PyGetSetDef HMACObject_getsets[] = {
461+
{NULL, NULL, NULL, NULL, NULL} /* sentinel */
462+
};
463+
464+
static PyType_Slot HMACObject_Type_slots[] = {
465+
{Py_tp_methods, HMACObject_methods},
466+
{Py_tp_getset, HMACObject_getsets},
467+
{Py_tp_clear, HMACObject_clear},
468+
{Py_tp_dealloc, HMACObject_dealloc},
469+
{Py_tp_traverse, HMACObject_traverse},
470+
{0, NULL} /* sentinel */
471+
};
472+
473+
static PyType_Spec HMAC_Type_spec = {
474+
.name = "_hmac.HMAC",
475+
.basicsize = sizeof(HMACObject),
476+
.flags = Py_TPFLAGS_DEFAULT
477+
| Py_TPFLAGS_DISALLOW_INSTANTIATION
478+
| Py_TPFLAGS_HEAPTYPE
479+
| Py_TPFLAGS_IMMUTABLETYPE
480+
| Py_TPFLAGS_HAVE_GC,
481+
.slots = HMACObject_Type_slots,
482+
};
483+
375484
// --- One-shot HMAC-HASH interface -------------------------------------------
376485

377486
/*[clinic input]
@@ -794,6 +903,21 @@ hmacmodule_init_exceptions(PyObject *module, hmacmodule_state *state)
794903
return 0;
795904
}
796905

906+
static int
907+
hmacmodule_init_hmac_type(PyObject *module, hmacmodule_state *state)
908+
{
909+
state->hmac_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
910+
&HMAC_Type_spec,
911+
NULL);
912+
if (state->hmac_type == NULL) {
913+
return -1;
914+
}
915+
if (PyModule_AddType(module, state->hmac_type) < 0) {
916+
return -1;
917+
}
918+
return 0;
919+
}
920+
797921
static int
798922
hmacmodule_init_strings(hmacmodule_state *state)
799923
{
@@ -819,6 +943,9 @@ hmacmodule_exec(PyObject *module)
819943
if (hmacmodule_init_exceptions(module, state) < 0) {
820944
return -1;
821945
}
946+
if (hmacmodule_init_hmac_type(module, state) < 0) {
947+
return -1;
948+
}
822949
if (hmacmodule_init_strings(state) < 0) {
823950
return -1;
824951
}
@@ -831,6 +958,7 @@ hmacmodule_traverse(PyObject *mod, visitproc visit, void *arg)
831958
Py_VISIT(Py_TYPE(mod));
832959
hmacmodule_state *state = get_hmacmodule_state(mod);
833960
Py_VISIT(state->unknown_hash_error);
961+
Py_VISIT(state->hmac_type);
834962
Py_VISIT(state->str_lower);
835963
return 0;
836964
}
@@ -844,6 +972,7 @@ hmacmodule_clear(PyObject *mod)
844972
state->hinfo_table = NULL;
845973
}
846974
Py_CLEAR(state->unknown_hash_error);
975+
Py_CLEAR(state->hmac_type);
847976
Py_CLEAR(state->str_lower);
848977
return 0;
849978
}

0 commit comments

Comments
 (0)