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 {
202207typedef 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]
220258module _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. */
229281static 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+
797921static int
798922hmacmodule_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