@@ -498,6 +498,24 @@ _hacl_convert_errno(hacl_errno_t code, PyObject *algorithm)
498498 }
499499}
500500
501+ /*
502+ * Return a new HACL* internal state or return NULL on failure.
503+ *
504+ * An appropriate exception is set if the state cannot be created.
505+ */
506+ static HACL_HMAC_state *
507+ _hacl_hmac_state_new (HMAC_Hash_Kind kind , uint8_t * key , uint32_t len )
508+ {
509+ assert (kind != Py_hmac_kind_hash_unknown );
510+ HACL_HMAC_state * state = NULL ;
511+ hacl_errno_t retcode = Hacl_Streaming_HMAC_malloc_ (kind , key , len , & state );
512+ if (_hacl_convert_errno (retcode , NULL ) < 0 ) {
513+ assert (state == NULL );
514+ return NULL ;
515+ }
516+ return state ;
517+ }
518+
501519/*
502520 * Free the HACL* internal state.
503521 */
@@ -660,6 +678,165 @@ has_uint32_t_buffer_length(const Py_buffer *buffer)
660678
661679// --- HMAC object ------------------------------------------------------------
662680
681+ /*
682+ * Use the HMAC information 'info' to populate the corresponding fields.
683+ *
684+ * The real 'kind' for BLAKE-2 is obtained once and depends on both static
685+ * capabilities (supported compiler flags) and runtime CPUID features.
686+ */
687+ static void
688+ hmac_set_hinfo (hmacmodule_state * state ,
689+ HMACObject * self , const py_hmac_hinfo * info )
690+ {
691+ assert (info -> display_name != NULL );
692+ self -> name = Py_NewRef (info -> display_name );
693+ assert_is_static_hmac_hash_kind (info -> kind );
694+ self -> kind = narrow_hmac_hash_kind (state , info -> kind );
695+ assert (info -> block_size <= Py_hmac_hash_max_block_size );
696+ self -> block_size = info -> block_size ;
697+ assert (info -> digest_size <= Py_hmac_hash_max_digest_size );
698+ self -> digest_size = info -> digest_size ;
699+ assert (info -> api .compute != NULL );
700+ assert (info -> api .compute_py != NULL );
701+ self -> api = info -> api ;
702+ }
703+
704+ /*
705+ * Create initial HACL* internal state with the given key.
706+ *
707+ * This function MUST only be called by the HMAC object constructor
708+ * and after hmac_set_hinfo() has been called, lest the behaviour is
709+ * undefined.
710+ *
711+ * Return 0 on success and -1 on failure.
712+ */
713+ static int
714+ hmac_new_initial_state (HMACObject * self , uint8_t * key , Py_ssize_t len )
715+ {
716+ assert (key != NULL );
717+ #ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
718+ // Technically speaking, we could hash the key to make it small
719+ // but it would require to call the hash functions ourselves and
720+ // not rely on HACL* implementation anymore. As such, we explicitly
721+ // reject keys that do not fit on 32 bits until HACL* handles them.
722+ if (len > UINT32_MAX_AS_SSIZE_T ) {
723+ PyErr_SetString (PyExc_OverflowError , INVALID_KEY_LENGTH );
724+ return -1 ;
725+ }
726+ #endif
727+ assert (self -> kind != Py_hmac_kind_hash_unknown );
728+ // _hacl_hmac_state_new() may set an exception on error
729+ self -> state = _hacl_hmac_state_new (self -> kind , key , len );
730+ return self -> state == NULL ? -1 : 0 ;
731+ }
732+
733+ /*
734+ * Feed initial data.
735+ *
736+ * This function MUST only be called by the HMAC object constructor
737+ * and after hmac_set_hinfo() and hmac_new_initial_state() have been
738+ * called, lest the behaviour is undefined.
739+ *
740+ * Return 0 on success and -1 on failure.
741+ */
742+ static int
743+ hmac_feed_initial_data (HMACObject * self , uint8_t * msg , Py_ssize_t len )
744+ {
745+ assert (self -> name != NULL );
746+ assert (self -> state != NULL );
747+ if (len == 0 ) {
748+ // do nothing if the buffer is empty
749+ return 0 ;
750+ }
751+
752+ if (len < HASHLIB_GIL_MINSIZE ) {
753+ Py_HMAC_HACL_UPDATE (self -> state , msg , len , self -> name , return - 1 );
754+ return 0 ;
755+ }
756+
757+ int res = 0 ;
758+ Py_BEGIN_ALLOW_THREADS
759+ Py_HMAC_HACL_UPDATE (self -> state , msg , len , self -> name , goto error );
760+ goto done ;
761+ #ifndef NDEBUG
762+ error :
763+ res = -1 ;
764+ #else
765+ Py_UNREACHABLE ();
766+ #endif
767+ done :
768+ Py_END_ALLOW_THREADS
769+ return res ;
770+ }
771+
772+ /*[clinic input]
773+ _hmac.new
774+
775+ key as keyobj: object
776+ msg as msgobj: object(c_default="NULL") = None
777+ digestmod as hash_info_ref: object(c_default="NULL") = None
778+
779+ Return a new HMAC object.
780+ [clinic start generated code]*/
781+
782+ static PyObject *
783+ _hmac_new_impl (PyObject * module , PyObject * keyobj , PyObject * msgobj ,
784+ PyObject * hash_info_ref )
785+ /*[clinic end generated code: output=7c7573a427d58758 input=92fc7c0a00707d42]*/
786+ {
787+ hmacmodule_state * state = get_hmacmodule_state (module );
788+ if (hash_info_ref == NULL ) {
789+ PyErr_SetString (PyExc_TypeError ,
790+ "new() missing 1 required argument 'digestmod'" );
791+ return NULL ;
792+ }
793+
794+ const py_hmac_hinfo * info = find_hash_info (state , hash_info_ref );
795+ if (info == NULL ) {
796+ assert (PyErr_Occurred ());
797+ return NULL ;
798+ }
799+
800+ HMACObject * self = PyObject_GC_New (HMACObject , state -> hmac_type );
801+ if (self == NULL ) {
802+ return NULL ;
803+ }
804+ HASHLIB_INIT_MUTEX (self );
805+ hmac_set_hinfo (state , self , info );
806+ int rc ;
807+ // Create the HACL* internal state with the given key.
808+ Py_buffer key ;
809+ GET_BUFFER_VIEW_OR_ERROR (keyobj , & key , goto error_on_key );
810+ rc = hmac_new_initial_state (self , key .buf , key .len );
811+ PyBuffer_Release (& key );
812+ if (rc < 0 ) {
813+ goto error ;
814+ }
815+ // Feed the internal state the initial message if any.
816+ if (msgobj != NULL && msgobj != Py_None ) {
817+ Py_buffer msg ;
818+ GET_BUFFER_VIEW_OR_ERROR (msgobj , & msg , goto error );
819+ rc = hmac_feed_initial_data (self , msg .buf , msg .len );
820+ PyBuffer_Release (& msg );
821+ #ifndef NDEBUG
822+ if (rc < 0 ) {
823+ goto error ;
824+ }
825+ #else
826+ (void )rc ;
827+ #endif
828+ }
829+ assert (rc == 0 );
830+ PyObject_GC_Track (self );
831+ return (PyObject * )self ;
832+
833+ error_on_key :
834+ self -> state = NULL ;
835+ error :
836+ Py_DECREF (self );
837+ return NULL ;
838+ }
839+
663840/*
664841 * Copy HMAC hash information from 'src' to 'out'.
665842 */
@@ -1244,6 +1421,7 @@ _hmac_compute_blake2b_32_impl(PyObject *module, PyObject *key, PyObject *msg)
12441421// --- HMAC module methods ----------------------------------------------------
12451422
12461423static PyMethodDef hmacmodule_methods [] = {
1424+ _HMAC_NEW_METHODDEF
12471425 /* one-shot dispatcher */
12481426 _HMAC_COMPUTE_DIGEST_METHODDEF
12491427 /* one-shot methods */
0 commit comments