Skip to content

Commit af02eea

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 ace9296 commit af02eea

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
@@ -20,6 +20,11 @@
2020
#include "Python.h"
2121
#include "pycore_hashtable.h"
2222

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

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

220258
/*[clinic input]
221259
module _hmac
260+
class _hmac.HMAC "HMACObject *" "clinic_state()->hmac_type"
222261
[clinic start generated code]*/
223-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=799f0f10157d561f]*/
262+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c8bab73fde49ba8a]*/
224263

264+
#define clinic_state() (get_hmacmodule_state_by_cls(Py_TYPE(self)))
225265
#include "clinic/hmacmodule.c.h"
266+
#undef clinic_state
226267

227268
// --- Helpers ----------------------------------------------------------------
228269

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

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

380489
/*[clinic input]
@@ -802,6 +911,21 @@ hmacmodule_init_exceptions(PyObject *module, hmacmodule_state *state)
802911
return 0;
803912
}
804913

914+
static int
915+
hmacmodule_init_hmac_type(PyObject *module, hmacmodule_state *state)
916+
{
917+
state->hmac_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
918+
&HMAC_Type_spec,
919+
NULL);
920+
if (state->hmac_type == NULL) {
921+
return -1;
922+
}
923+
if (PyModule_AddType(module, state->hmac_type) < 0) {
924+
return -1;
925+
}
926+
return 0;
927+
}
928+
805929
static int
806930
hmacmodule_init_strings(hmacmodule_state *state)
807931
{
@@ -827,6 +951,9 @@ hmacmodule_exec(PyObject *module)
827951
if (hmacmodule_init_exceptions(module, state) < 0) {
828952
return -1;
829953
}
954+
if (hmacmodule_init_hmac_type(module, state) < 0) {
955+
return -1;
956+
}
830957
if (hmacmodule_init_strings(state) < 0) {
831958
return -1;
832959
}
@@ -839,6 +966,7 @@ hmacmodule_traverse(PyObject *mod, visitproc visit, void *arg)
839966
Py_VISIT(Py_TYPE(mod));
840967
hmacmodule_state *state = get_hmacmodule_state(mod);
841968
Py_VISIT(state->unknown_hash_error);
969+
Py_VISIT(state->hmac_type);
842970
Py_VISIT(state->str_lower);
843971
return 0;
844972
}
@@ -852,6 +980,7 @@ hmacmodule_clear(PyObject *mod)
852980
state->hinfo_table = NULL;
853981
}
854982
Py_CLEAR(state->unknown_hash_error);
983+
Py_CLEAR(state->hmac_type);
855984
Py_CLEAR(state->str_lower);
856985
return 0;
857986
}

0 commit comments

Comments
 (0)