@@ -383,6 +383,10 @@ class _hmac.HMAC "HMACObject *" "clinic_state()->hmac_type"
383383//
384384// - Helpers with the "_hacl" prefix are thin wrappers around HACL* functions.
385385// Buffer lengths given as inputs should fit on 32-bit integers.
386+ //
387+ // - Helpers with the "hmac_" prefix act on HMAC objects and accept buffers
388+ // whose length fits on 32-bit or 64-bit integers (depending on the host
389+ // machine).
386390
387391/*
388392 * Handle the HACL* exit code.
@@ -585,6 +589,99 @@ has_uint32_t_buffer_length(const Py_buffer *buffer)
585589
586590// --- HMAC object ------------------------------------------------------------
587591
592+ /*
593+ * Update the HMAC object with the given buffer.
594+ *
595+ * This unconditionally acquires the lock on the HMAC object.
596+ *
597+ * On DEBUG builds, each update() call is verified.
598+ * On other builds, only the last update() call is verified.
599+ *
600+ * Return 0 on success and -1 on failure.
601+ */
602+ static int
603+ hmac_update_state_with_lock (HMACObject * self , uint8_t * buf , Py_ssize_t len )
604+ {
605+ int res = 0 ;
606+ Py_BEGIN_ALLOW_THREADS
607+ PyMutex_Lock (& self -> mutex ); // unconditionally acquire a lock
608+ Py_HMAC_HACL_UPDATE (self -> state , buf , len , self -> name , goto error );
609+ goto done ;
610+ #ifndef NDEBUG
611+ error :
612+ res = -1 ;
613+ #else
614+ Py_UNREACHABLE ();
615+ #endif
616+ done :
617+ PyMutex_Unlock (& self -> mutex );
618+ Py_END_ALLOW_THREADS
619+ return res ;
620+ }
621+
622+ /*
623+ * Update the HMAC object with the given buffer.
624+ *
625+ * This conditionally acquires the lock on the HMAC object.
626+ *
627+ * On DEBUG builds, each update() call is verified.
628+ * On other builds, only the last update() call is verified.
629+ *
630+ * Return 0 on success and -1 on failure.
631+ */
632+ static int
633+ hmac_update_state_cond_lock (HMACObject * self , uint8_t * buf , Py_ssize_t len )
634+ {
635+ ENTER_HASHLIB (self ); // conditionally acquire a lock
636+ Py_HMAC_HACL_UPDATE (self -> state , buf , len , self -> name , goto error );
637+ LEAVE_HASHLIB (self );
638+ return 0 ;
639+
640+ #ifndef NDEBUG
641+ error :
642+ LEAVE_HASHLIB (self );
643+ return -1 ;
644+ #else
645+ Py_UNREACHABLE ();
646+ #endif
647+ }
648+
649+ /*
650+ * Update the internal HMAC state with the given buffer.
651+ *
652+ * Return 0 on success and -1 on failure.
653+ */
654+ static inline int
655+ hmac_update_state (HMACObject * self , uint8_t * buf , Py_ssize_t len )
656+ {
657+ assert (buf != 0 );
658+ assert (len >= 0 );
659+ return len == 0
660+ ? 0 /* nothing to do */
661+ : len < HASHLIB_GIL_MINSIZE
662+ ? hmac_update_state_cond_lock (self , buf , len )
663+ : hmac_update_state_with_lock (self , buf , len );
664+ }
665+
666+ /*[clinic input]
667+ _hmac.HMAC.update
668+
669+ msg as msgobj: object
670+
671+ Update the HMAC object with the given message.
672+ [clinic start generated code]*/
673+
674+ static PyObject *
675+ _hmac_HMAC_update_impl (HMACObject * self , PyObject * msgobj )
676+ /*[clinic end generated code: output=962134ada5e55985 input=7c0ea830efb03367]*/
677+ {
678+ Py_buffer msg ;
679+ GET_BUFFER_VIEW_OR_ERROUT (msgobj , & msg );
680+ int rc = hmac_update_state (self , msg .buf , msg .len );
681+ PyBuffer_Release (& msg );
682+ return rc < 0 ? NULL : Py_None ;
683+ }
684+
588685/*[clinic input]
589686@getter
590687_hmac.HMAC.name
@@ -658,6 +755,7 @@ HMACObject_traverse(PyObject *op, visitproc visit, void *arg)
658755}
659756
660757static PyMethodDef HMACObject_methods [] = {
758+ _HMAC_HMAC_UPDATE_METHODDEF
661759 {NULL , NULL , 0 , NULL } /* sentinel */
662760};
663761
0 commit comments