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 {
203208typedef 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]
221259module _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. */
230282static 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+
805929static int
806930hmacmodule_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