mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1859 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1859 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * @author Bénédikt Tran
 | 
						|
 *
 | 
						|
 * Implement the HMAC algorithm as described by RFC 2104 using HACL*.
 | 
						|
 *
 | 
						|
 * Using HACL* implementation implicitly assumes that the caller wants
 | 
						|
 * a formally verified implementation. In particular, only algorithms
 | 
						|
 * given by their names will be recognized.
 | 
						|
 *
 | 
						|
 * Some algorithms exposed by `_hashlib` such as truncated SHA-2-512-224/256
 | 
						|
 * are not yet implemented by the HACL* project. Nonetheless, the supported
 | 
						|
 * HMAC algorithms form a subset of those supported by '_hashlib'.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef Py_BUILD_CORE_BUILTIN
 | 
						|
#  define Py_BUILD_CORE_MODULE 1
 | 
						|
#endif
 | 
						|
 | 
						|
#include "Python.h"
 | 
						|
#include "pycore_hashtable.h"
 | 
						|
#include "pycore_strhex.h"              // _Py_strhex()
 | 
						|
 | 
						|
/*
 | 
						|
 * Taken from blake2module.c. In the future, detection of SIMD support
 | 
						|
 * should be delegated to https://github.com/python/cpython/pull/125011.
 | 
						|
 */
 | 
						|
#if defined(__x86_64__) && defined(__GNUC__)
 | 
						|
#  include <cpuid.h>
 | 
						|
#elif defined(_M_X64)
 | 
						|
#  include <intrin.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(__APPLE__) && defined(__arm64__)
 | 
						|
#  undef HACL_CAN_COMPILE_SIMD128
 | 
						|
#  undef HACL_CAN_COMPILE_SIMD256
 | 
						|
#endif
 | 
						|
 | 
						|
// Small mismatch between the variable names Python defines as part of configure
 | 
						|
// at the ones HACL* expects to be set in order to enable those headers.
 | 
						|
#define HACL_CAN_COMPILE_VEC128 HACL_CAN_COMPILE_SIMD128
 | 
						|
#define HACL_CAN_COMPILE_VEC256 HACL_CAN_COMPILE_SIMD256
 | 
						|
 | 
						|
#include "_hacl/Hacl_HMAC.h"
 | 
						|
#include "_hacl/Hacl_Streaming_HMAC.h"  // Hacl_Agile_Hash_* identifiers
 | 
						|
#include "_hacl/Hacl_Streaming_Types.h" // Hacl_Streaming_Types_error_code
 | 
						|
 | 
						|
#include <stdbool.h>
 | 
						|
 | 
						|
#include "hashlib.h"
 | 
						|
 | 
						|
// --- Reusable error messages ------------------------------------------------
 | 
						|
 | 
						|
static inline void
 | 
						|
set_invalid_key_length_error(void)
 | 
						|
{
 | 
						|
    (void)PyErr_Format(PyExc_OverflowError,
 | 
						|
                       "key length exceeds %u",
 | 
						|
                       UINT32_MAX);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
set_invalid_msg_length_error(void)
 | 
						|
{
 | 
						|
    (void)PyErr_Format(PyExc_OverflowError,
 | 
						|
                       "message length exceeds %u",
 | 
						|
                       UINT32_MAX);
 | 
						|
}
 | 
						|
 | 
						|
// --- HMAC underlying hash function static information -----------------------
 | 
						|
 | 
						|
#define UINT32_MAX_AS_SSIZE_T                   ((Py_ssize_t)UINT32_MAX)
 | 
						|
 | 
						|
#define Py_hmac_hash_max_block_size             144
 | 
						|
#define Py_hmac_hash_max_digest_size            64
 | 
						|
 | 
						|
/* MD-5 */
 | 
						|
// HACL_HID = md5
 | 
						|
#define Py_hmac_md5_block_size                  64
 | 
						|
#define Py_hmac_md5_digest_size                 16
 | 
						|
 | 
						|
#define Py_hmac_md5_compute_func                Hacl_HMAC_compute_md5
 | 
						|
 | 
						|
/* SHA-1 family */
 | 
						|
// HACL_HID = sha1
 | 
						|
#define Py_hmac_sha1_block_size                 64
 | 
						|
#define Py_hmac_sha1_digest_size                20
 | 
						|
 | 
						|
#define Py_hmac_sha1_compute_func               Hacl_HMAC_compute_sha1
 | 
						|
 | 
						|
/* SHA-2 family */
 | 
						|
// HACL_HID = sha2_224
 | 
						|
#define Py_hmac_sha2_224_block_size             64
 | 
						|
#define Py_hmac_sha2_224_digest_size            28
 | 
						|
 | 
						|
#define Py_hmac_sha2_224_compute_func           Hacl_HMAC_compute_sha2_224
 | 
						|
 | 
						|
// HACL_HID = sha2_256
 | 
						|
#define Py_hmac_sha2_256_block_size             64
 | 
						|
#define Py_hmac_sha2_256_digest_size            32
 | 
						|
 | 
						|
#define Py_hmac_sha2_256_compute_func           Hacl_HMAC_compute_sha2_256
 | 
						|
 | 
						|
// HACL_HID = sha2_384
 | 
						|
#define Py_hmac_sha2_384_block_size             128
 | 
						|
#define Py_hmac_sha2_384_digest_size            48
 | 
						|
 | 
						|
#define Py_hmac_sha2_384_compute_func           Hacl_HMAC_compute_sha2_384
 | 
						|
 | 
						|
// HACL_HID = sha2_512
 | 
						|
#define Py_hmac_sha2_512_block_size             128
 | 
						|
#define Py_hmac_sha2_512_digest_size            64
 | 
						|
 | 
						|
#define Py_hmac_sha2_512_compute_func           Hacl_HMAC_compute_sha2_512
 | 
						|
 | 
						|
/* SHA-3 family */
 | 
						|
// HACL_HID = sha3_224
 | 
						|
#define Py_hmac_sha3_224_block_size             144
 | 
						|
#define Py_hmac_sha3_224_digest_size            28
 | 
						|
 | 
						|
#define Py_hmac_sha3_224_compute_func           Hacl_HMAC_compute_sha3_224
 | 
						|
 | 
						|
// HACL_HID = sha3_256
 | 
						|
#define Py_hmac_sha3_256_block_size             136
 | 
						|
#define Py_hmac_sha3_256_digest_size            32
 | 
						|
 | 
						|
#define Py_hmac_sha3_256_compute_func           Hacl_HMAC_compute_sha3_256
 | 
						|
 | 
						|
// HACL_HID = sha3_384
 | 
						|
#define Py_hmac_sha3_384_block_size             104
 | 
						|
#define Py_hmac_sha3_384_digest_size            48
 | 
						|
 | 
						|
#define Py_hmac_sha3_384_compute_func           Hacl_HMAC_compute_sha3_384
 | 
						|
 | 
						|
// HACL_HID = sha3_512
 | 
						|
#define Py_hmac_sha3_512_block_size             72
 | 
						|
#define Py_hmac_sha3_512_digest_size            64
 | 
						|
 | 
						|
#define Py_hmac_sha3_512_compute_func           Hacl_HMAC_compute_sha3_512
 | 
						|
 | 
						|
/* Blake2 family */
 | 
						|
// HACL_HID = blake2s_32
 | 
						|
#define Py_hmac_blake2s_32_block_size           64
 | 
						|
#define Py_hmac_blake2s_32_digest_size          32
 | 
						|
 | 
						|
#define Py_hmac_blake2s_32_compute_func         Hacl_HMAC_compute_blake2s_32
 | 
						|
 | 
						|
// HACL_HID = blake2b_32
 | 
						|
#define Py_hmac_blake2b_32_block_size           128
 | 
						|
#define Py_hmac_blake2b_32_digest_size          64
 | 
						|
 | 
						|
#define Py_hmac_blake2b_32_compute_func         Hacl_HMAC_compute_blake2b_32
 | 
						|
 | 
						|
/* Enumeration indicating the underlying hash function used by HMAC. */
 | 
						|
typedef enum HMAC_Hash_Kind {
 | 
						|
    Py_hmac_kind_hash_unknown = -1,
 | 
						|
#define DECL_HACL_HMAC_HASH_KIND(NAME, HACL_NAME)  \
 | 
						|
    Py_hmac_kind_hmac_ ## NAME = Hacl_Agile_Hash_ ## HACL_NAME,
 | 
						|
    /* MD5 */
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(md5, MD5)
 | 
						|
    /* SHA-1 */
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha1, SHA1)
 | 
						|
    /* SHA-2 family */
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha2_224, SHA2_224)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha2_256, SHA2_256)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha2_384, SHA2_384)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha2_512, SHA2_512)
 | 
						|
    /* SHA-3 family */
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha3_224, SHA3_224)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha3_256, SHA3_256)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha3_384, SHA3_384)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(sha3_512, SHA3_512)
 | 
						|
    /* Blake family */
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(blake2s_32, Blake2S_32)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(blake2b_32, Blake2B_32)
 | 
						|
    /* Blake runtime family (should not be used statically) */
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(vectorized_blake2s_32, Blake2S_128)
 | 
						|
    DECL_HACL_HMAC_HASH_KIND(vectorized_blake2b_32, Blake2B_256)
 | 
						|
#undef DECL_HACL_HMAC_HASH_KIND
 | 
						|
} HMAC_Hash_Kind;
 | 
						|
 | 
						|
typedef Hacl_Streaming_Types_error_code hacl_errno_t;
 | 
						|
 | 
						|
/* Function pointer type for 1-shot HACL* HMAC functions. */
 | 
						|
typedef void
 | 
						|
(*HACL_HMAC_compute_func)(uint8_t *out,
 | 
						|
                          uint8_t *key, uint32_t keylen,
 | 
						|
                          uint8_t *msg, uint32_t msglen);
 | 
						|
/* Function pointer type for 1-shot HACL* HMAC CPython AC functions. */
 | 
						|
typedef PyObject *
 | 
						|
(*PyAC_HMAC_compute_func)(PyObject *module, PyObject *key, PyObject *msg);
 | 
						|
 | 
						|
/*
 | 
						|
 * HACL* HMAC minimal interface.
 | 
						|
 */
 | 
						|
typedef struct py_hmac_hacl_api {
 | 
						|
    HACL_HMAC_compute_func compute;
 | 
						|
    PyAC_HMAC_compute_func compute_py;
 | 
						|
} py_hmac_hacl_api;
 | 
						|
 | 
						|
#if PY_SSIZE_T_MAX > UINT32_MAX
 | 
						|
#define Py_HMAC_SSIZE_LARGER_THAN_UINT32
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Assert that 'LEN' can be safely casted to uint32_t.
 | 
						|
 *
 | 
						|
 * The 'LEN' parameter should be convertible to Py_ssize_t.
 | 
						|
 */
 | 
						|
#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
 | 
						|
#define Py_CHECK_HACL_UINT32_T_LENGTH(LEN)                  \
 | 
						|
    do {                                                    \
 | 
						|
        assert((Py_ssize_t)(LEN) <= UINT32_MAX_AS_SSIZE_T); \
 | 
						|
    } while (0)
 | 
						|
#else
 | 
						|
#define Py_CHECK_HACL_UINT32_T_LENGTH(LEN)
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Call the HACL* HMAC-HASH update function on the given data.
 | 
						|
 *
 | 
						|
 * The magnitude of 'LEN' is not checked and thus 'LEN' must be
 | 
						|
 * safely convertible to a uint32_t value.
 | 
						|
 */
 | 
						|
#define Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, LEN)          \
 | 
						|
    Hacl_Streaming_HMAC_update(HACL_STATE, BUF, (uint32_t)(LEN))
 | 
						|
 | 
						|
/*
 | 
						|
 * Call the HACL* HMAC-HASH update function on the given data.
 | 
						|
 *
 | 
						|
 * On DEBUG builds, the 'ERRACTION' statements are executed if
 | 
						|
 * the update() call returned a non-successful HACL* exit code.
 | 
						|
 *
 | 
						|
 * The buffer 'BUF' and its length 'LEN' are left untouched.
 | 
						|
 *
 | 
						|
 * The formal signature of this macro is:
 | 
						|
 *
 | 
						|
 *     (HACL_HMAC_state *, uint8_t *, uint32_t, PyObject *, (C statements))
 | 
						|
 */
 | 
						|
#ifndef NDEBUG
 | 
						|
#define Py_HMAC_HACL_UPDATE_ONCE(                                           \
 | 
						|
    HACL_STATE, BUF, LEN,                                                   \
 | 
						|
    ALGORITHM, ERRACTION                                                    \
 | 
						|
)                                                                           \
 | 
						|
    do {                                                                    \
 | 
						|
        Py_CHECK_HACL_UINT32_T_LENGTH(LEN);                                 \
 | 
						|
        hacl_errno_t code = Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, LEN); \
 | 
						|
        if (_hacl_convert_errno(code, (ALGORITHM)) < 0) {                   \
 | 
						|
            ERRACTION;                                                      \
 | 
						|
        }                                                                   \
 | 
						|
    } while (0)
 | 
						|
#else
 | 
						|
#define Py_HMAC_HACL_UPDATE_ONCE(                                   \
 | 
						|
    HACL_STATE, BUF, LEN,                                           \
 | 
						|
    _ALGORITHM, _ERRACTION                                          \
 | 
						|
)                                                                   \
 | 
						|
    do {                                                            \
 | 
						|
        (void)Py_HMAC_HACL_UPDATE_CALL(HACL_STATE, BUF, (LEN));     \
 | 
						|
    } while (0)
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Repetivively call the HACL* HMAC-HASH update function on the given
 | 
						|
 * data until the buffer length 'LEN' is strictly less than UINT32_MAX.
 | 
						|
 *
 | 
						|
 * On builds with PY_SSIZE_T_MAX <= UINT32_MAX, this is a no-op.
 | 
						|
 *
 | 
						|
 * The buffer 'BUF' (resp. 'LEN') is advanced (resp. decremented)
 | 
						|
 * by UINT32_MAX after each update. On DEBUG builds, each update()
 | 
						|
 * call is verified and the 'ERRACTION' statements are executed if
 | 
						|
 * a non-successful HACL* exit code is being returned.
 | 
						|
 *
 | 
						|
 * In particular, 'BUF' and 'LEN' must be variable names and not
 | 
						|
 * expressions on their own.
 | 
						|
 *
 | 
						|
 * The formal signature of this macro is:
 | 
						|
 *
 | 
						|
 *     (HACL_HMAC_state *, uint8_t *, C integer, PyObject *, (C statements))
 | 
						|
 */
 | 
						|
#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
 | 
						|
#define Py_HMAC_HACL_UPDATE_LOOP(                                   \
 | 
						|
    HACL_STATE, BUF, LEN,                                           \
 | 
						|
    ALGORITHM, ERRACTION                                            \
 | 
						|
)                                                                   \
 | 
						|
    do {                                                            \
 | 
						|
        while ((Py_ssize_t)LEN > UINT32_MAX_AS_SSIZE_T) {           \
 | 
						|
            Py_HMAC_HACL_UPDATE_ONCE(HACL_STATE, BUF, UINT32_MAX,   \
 | 
						|
                                     ALGORITHM, ERRACTION);         \
 | 
						|
            BUF += UINT32_MAX;                                      \
 | 
						|
            LEN -= UINT32_MAX;                                      \
 | 
						|
        }                                                           \
 | 
						|
    } while (0)
 | 
						|
#else
 | 
						|
#define Py_HMAC_HACL_UPDATE_LOOP(   \
 | 
						|
    HACL_STATE, BUF, LEN,           \
 | 
						|
    _ALGORITHM, _ERRACTION          \
 | 
						|
)
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Perform the HMAC-HASH update() operation in a streaming fashion.
 | 
						|
 *
 | 
						|
 * The formal signature of this macro is:
 | 
						|
 *
 | 
						|
 *     (HACL_HMAC_state *, uint8_t *, C integer, PyObject *, (C statements))
 | 
						|
 */
 | 
						|
#define Py_HMAC_HACL_UPDATE(                            \
 | 
						|
    HACL_STATE, BUF, LEN,                               \
 | 
						|
    ALGORITHM, ERRACTION                                \
 | 
						|
)                                                       \
 | 
						|
    do {                                                \
 | 
						|
        Py_HMAC_HACL_UPDATE_LOOP(HACL_STATE, BUF, LEN,  \
 | 
						|
                                 ALGORITHM, ERRACTION); \
 | 
						|
        Py_HMAC_HACL_UPDATE_ONCE(HACL_STATE, BUF, LEN,  \
 | 
						|
                                 ALGORITHM, ERRACTION); \
 | 
						|
    } while (0)
 | 
						|
 | 
						|
/*
 | 
						|
 * HMAC underlying hash function static information.
 | 
						|
 */
 | 
						|
typedef struct py_hmac_hinfo {
 | 
						|
    /*
 | 
						|
     * Name of the hash function used by the HACL* HMAC module.
 | 
						|
     *
 | 
						|
     * This name may differ from the hashlib names. For instance,
 | 
						|
     * SHA-2/224 is named "sha2_224" instead of "sha224" as it is
 | 
						|
     * done by 'hashlib'.
 | 
						|
     */
 | 
						|
    const char *name;
 | 
						|
 | 
						|
    /* hash function information */
 | 
						|
    HMAC_Hash_Kind kind;
 | 
						|
    uint32_t block_size;
 | 
						|
    uint32_t digest_size;
 | 
						|
 | 
						|
    /* HACL* HMAC API */
 | 
						|
    py_hmac_hacl_api api;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Cached field storing the 'hashlib_name' field as a Python string.
 | 
						|
     *
 | 
						|
     * This field is NULL by default in the items of "py_hmac_static_hinfo"
 | 
						|
     * but will be populated when creating the module's state "hinfo_table".
 | 
						|
     */
 | 
						|
    PyObject *display_name;
 | 
						|
    const char *hashlib_name;   /* hashlib preferred name (default: name) */
 | 
						|
 | 
						|
    Py_ssize_t refcnt;
 | 
						|
} py_hmac_hinfo;
 | 
						|
 | 
						|
// --- HMAC module state ------------------------------------------------------
 | 
						|
 | 
						|
typedef struct hmacmodule_state {
 | 
						|
    _Py_hashtable_t *hinfo_table;
 | 
						|
    PyObject *unknown_hash_error;
 | 
						|
    /* HMAC object type */
 | 
						|
    PyTypeObject *hmac_type;
 | 
						|
    /* interned strings */
 | 
						|
    PyObject *str_lower;
 | 
						|
 | 
						|
    bool can_run_simd128;
 | 
						|
    bool can_run_simd256;
 | 
						|
} hmacmodule_state;
 | 
						|
 | 
						|
static inline hmacmodule_state *
 | 
						|
get_hmacmodule_state(PyObject *module)
 | 
						|
{
 | 
						|
    void *state = PyModule_GetState(module);
 | 
						|
    assert(state != NULL);
 | 
						|
    return (hmacmodule_state *)state;
 | 
						|
}
 | 
						|
 | 
						|
static inline hmacmodule_state *
 | 
						|
get_hmacmodule_state_by_cls(PyTypeObject *cls)
 | 
						|
{
 | 
						|
    void *state = PyType_GetModuleState(cls);
 | 
						|
    assert(state != NULL);
 | 
						|
    return (hmacmodule_state *)state;
 | 
						|
}
 | 
						|
 | 
						|
// --- HMAC Object ------------------------------------------------------------
 | 
						|
 | 
						|
typedef Hacl_Streaming_HMAC_agile_state HACL_HMAC_state;
 | 
						|
 | 
						|
typedef struct HMACObject {
 | 
						|
    PyObject_HEAD
 | 
						|
 | 
						|
    bool use_mutex;
 | 
						|
    PyMutex mutex;
 | 
						|
 | 
						|
    // Hash function information
 | 
						|
    PyObject *name;         // rendered name (exact unicode object)
 | 
						|
    HMAC_Hash_Kind kind;    // can be used for runtime dispatch (must be known)
 | 
						|
    uint32_t block_size;
 | 
						|
    uint32_t digest_size;
 | 
						|
    py_hmac_hacl_api api;
 | 
						|
 | 
						|
    // HMAC HACL* internal state.
 | 
						|
    HACL_HMAC_state *state;
 | 
						|
} HMACObject;
 | 
						|
 | 
						|
#define HMACObject_CAST(op) ((HMACObject *)(op))
 | 
						|
 | 
						|
// --- HMAC module clinic configuration ---------------------------------------
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
module _hmac
 | 
						|
class _hmac.HMAC "HMACObject *" "clinic_state()->hmac_type"
 | 
						|
[clinic start generated code]*/
 | 
						|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c8bab73fde49ba8a]*/
 | 
						|
 | 
						|
#define clinic_state()  (get_hmacmodule_state_by_cls(Py_TYPE(self)))
 | 
						|
#include "clinic/hmacmodule.c.h"
 | 
						|
#undef clinic_state
 | 
						|
 | 
						|
// --- Helpers ----------------------------------------------------------------
 | 
						|
//
 | 
						|
// The helpers have the following naming conventions:
 | 
						|
//
 | 
						|
// - Helpers with the "_hacl" prefix are thin wrappers around HACL* functions.
 | 
						|
//   Buffer lengths given as inputs should fit on 32-bit integers.
 | 
						|
//
 | 
						|
// - Helpers with the "hmac_" prefix act on HMAC objects and accept buffers
 | 
						|
//   whose length fits on 32-bit or 64-bit integers (depending on the host
 | 
						|
//   machine).
 | 
						|
 | 
						|
/*
 | 
						|
 * Assert that a HMAC hash kind is a static kind.
 | 
						|
 *
 | 
						|
 * A "static" kind is specified in the 'py_hmac_static_hinfo'
 | 
						|
 * table and is always independent of the host CPUID features.
 | 
						|
 */
 | 
						|
#ifndef NDEBUG
 | 
						|
static void
 | 
						|
assert_is_static_hmac_hash_kind(HMAC_Hash_Kind kind)
 | 
						|
{
 | 
						|
    switch (kind) {
 | 
						|
        case Py_hmac_kind_hash_unknown: {
 | 
						|
            Py_FatalError("HMAC hash kind must be a known kind");
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        case Py_hmac_kind_hmac_vectorized_blake2s_32:
 | 
						|
        case Py_hmac_kind_hmac_vectorized_blake2b_32: {
 | 
						|
            Py_FatalError("HMAC hash kind must not be a vectorized kind");
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        default:
 | 
						|
            return;
 | 
						|
    }
 | 
						|
}
 | 
						|
#else
 | 
						|
static inline void
 | 
						|
assert_is_static_hmac_hash_kind(HMAC_Hash_Kind Py_UNUSED(kind)) {}
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Convert a HMAC hash static kind into a runtime kind.
 | 
						|
 *
 | 
						|
 * A "runtime" kind is derived from a static kind and depends
 | 
						|
 * on the host CPUID features. In particular, this is the kind
 | 
						|
 * that a HMAC object internally stores.
 | 
						|
 */
 | 
						|
static HMAC_Hash_Kind
 | 
						|
narrow_hmac_hash_kind(hmacmodule_state *state, HMAC_Hash_Kind kind)
 | 
						|
{
 | 
						|
    switch (kind) {
 | 
						|
        case Py_hmac_kind_hmac_blake2s_32: {
 | 
						|
#if HACL_CAN_COMPILE_SIMD128
 | 
						|
            if (state->can_run_simd128) {
 | 
						|
                return Py_hmac_kind_hmac_vectorized_blake2s_32;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            return kind;
 | 
						|
        }
 | 
						|
        case Py_hmac_kind_hmac_blake2b_32: {
 | 
						|
#if HACL_CAN_COMPILE_SIMD256
 | 
						|
            if (state->can_run_simd256) {
 | 
						|
                return Py_hmac_kind_hmac_vectorized_blake2b_32;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            return kind;
 | 
						|
        }
 | 
						|
        default:
 | 
						|
            return kind;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Handle the HACL* exit code.
 | 
						|
 *
 | 
						|
 * If 'code' represents a successful operation, this returns 0.
 | 
						|
 * Otherwise, this sets an appropriate exception and returns -1.
 | 
						|
 */
 | 
						|
static int
 | 
						|
_hacl_convert_errno(hacl_errno_t code, PyObject *algorithm)
 | 
						|
{
 | 
						|
    switch (code) {
 | 
						|
        case Hacl_Streaming_Types_Success: {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        case Hacl_Streaming_Types_InvalidAlgorithm: {
 | 
						|
            // only makes sense if an algorithm is known at call time
 | 
						|
            assert(algorithm != NULL);
 | 
						|
            assert(PyUnicode_CheckExact(algorithm));
 | 
						|
            PyErr_Format(PyExc_ValueError, "invalid algorithm: %U", algorithm);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        case Hacl_Streaming_Types_InvalidLength: {
 | 
						|
            PyErr_SetString(PyExc_ValueError, "invalid length");
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        case Hacl_Streaming_Types_MaximumLengthExceeded: {
 | 
						|
            PyErr_SetString(PyExc_OverflowError, "maximum length exceeded");
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        case Hacl_Streaming_Types_OutOfMemory: {
 | 
						|
            PyErr_NoMemory();
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
        default: {
 | 
						|
            PyErr_Format(PyExc_RuntimeError,
 | 
						|
                         "HACL* internal routine failed with error code: %d",
 | 
						|
                         code);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Return a new HACL* internal state or return NULL on failure.
 | 
						|
 *
 | 
						|
 * An appropriate exception is set if the state cannot be created.
 | 
						|
 */
 | 
						|
static HACL_HMAC_state *
 | 
						|
_hacl_hmac_state_new(HMAC_Hash_Kind kind, uint8_t *key, uint32_t len)
 | 
						|
{
 | 
						|
    assert(kind != Py_hmac_kind_hash_unknown);
 | 
						|
    HACL_HMAC_state *state = NULL;
 | 
						|
    hacl_errno_t retcode = Hacl_Streaming_HMAC_malloc_(kind, key, len, &state);
 | 
						|
    if (_hacl_convert_errno(retcode, NULL) < 0) {
 | 
						|
        assert(state == NULL);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    return state;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Free the HACL* internal state.
 | 
						|
 */
 | 
						|
static inline void
 | 
						|
_hacl_hmac_state_free(HACL_HMAC_state *state)
 | 
						|
{
 | 
						|
    if (state != NULL) {
 | 
						|
        Hacl_Streaming_HMAC_free(state);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Static information used to construct the hash table. */
 | 
						|
static const py_hmac_hinfo py_hmac_static_hinfo[] = {
 | 
						|
#define Py_HMAC_HINFO_HACL_API(HACL_HID)                                \
 | 
						|
    {                                                                   \
 | 
						|
        /* one-shot helpers */                                          \
 | 
						|
        .compute = &Py_hmac_## HACL_HID ##_compute_func,                \
 | 
						|
        .compute_py = &_hmac_compute_## HACL_HID ##_impl,               \
 | 
						|
    }
 | 
						|
 | 
						|
#define Py_HMAC_HINFO_ENTRY(HACL_HID, HLIB_NAME)            \
 | 
						|
    {                                                       \
 | 
						|
        .name = Py_STRINGIFY(HACL_HID),                     \
 | 
						|
        .kind = Py_hmac_kind_hmac_ ## HACL_HID,             \
 | 
						|
        .block_size = Py_hmac_## HACL_HID ##_block_size,    \
 | 
						|
        .digest_size = Py_hmac_## HACL_HID ##_digest_size,  \
 | 
						|
        .api = Py_HMAC_HINFO_HACL_API(HACL_HID),            \
 | 
						|
        .display_name = NULL,                               \
 | 
						|
        .hashlib_name = HLIB_NAME,                          \
 | 
						|
        .refcnt = 0,                                        \
 | 
						|
    }
 | 
						|
    /* MD5 */
 | 
						|
    Py_HMAC_HINFO_ENTRY(md5, NULL),
 | 
						|
    /* SHA-1 */
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha1, NULL),
 | 
						|
    /* SHA-2 family */
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha2_224, "sha224"),
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha2_256, "sha256"),
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha2_384, "sha384"),
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha2_512, "sha512"),
 | 
						|
    /* SHA-3 family */
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha3_224, NULL),
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha3_256, NULL),
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha3_384, NULL),
 | 
						|
    Py_HMAC_HINFO_ENTRY(sha3_512, NULL),
 | 
						|
    /* Blake family */
 | 
						|
    Py_HMAC_HINFO_ENTRY(blake2s_32, "blake2s"),
 | 
						|
    Py_HMAC_HINFO_ENTRY(blake2b_32, "blake2b"),
 | 
						|
#undef Py_HMAC_HINFO_ENTRY
 | 
						|
#undef Py_HMAC_HINFO_HACL_API
 | 
						|
    /* sentinel */
 | 
						|
    {
 | 
						|
        NULL, Py_hmac_kind_hash_unknown, 0, 0,
 | 
						|
        {NULL, NULL},
 | 
						|
        NULL, NULL,
 | 
						|
        0,
 | 
						|
    },
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * Check whether 'name' is a known HMAC hash function name,
 | 
						|
 * storing the corresponding static information in 'info'.
 | 
						|
 *
 | 
						|
 * This function always succeeds and never set an exception.
 | 
						|
 */
 | 
						|
static inline bool
 | 
						|
find_hash_info_by_utf8name(hmacmodule_state *state,
 | 
						|
                           const char *name,
 | 
						|
                           const py_hmac_hinfo **info)
 | 
						|
{
 | 
						|
    assert(name != NULL);
 | 
						|
    *info = _Py_hashtable_get(state->hinfo_table, name);
 | 
						|
    return *info != NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Find the corresponding HMAC hash function static information by its name.
 | 
						|
 *
 | 
						|
 * On error, propagate the exception, set 'info' to NULL and return -1.
 | 
						|
 *
 | 
						|
 * If no correspondence exists, set 'info' to NULL and return 0.
 | 
						|
 * Otherwise, set 'info' to the deduced information and return 1.
 | 
						|
 *
 | 
						|
 * Parameters
 | 
						|
 *
 | 
						|
 *      state           The HMAC module state.
 | 
						|
 *      name            The hash function name.
 | 
						|
 *      info            The deduced information, if any.
 | 
						|
 */
 | 
						|
static int
 | 
						|
find_hash_info_by_name(hmacmodule_state *state,
 | 
						|
                       PyObject *name,
 | 
						|
                       const py_hmac_hinfo **info)
 | 
						|
{
 | 
						|
    const char *utf8name = PyUnicode_AsUTF8(name);
 | 
						|
    if (utf8name == NULL) {
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    if (find_hash_info_by_utf8name(state, utf8name, info)) {
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    // try to find an alternative using the lowercase name
 | 
						|
    PyObject *lower = PyObject_CallMethodNoArgs(name, state->str_lower);
 | 
						|
    if (lower == NULL) {
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    const char *utf8lower = PyUnicode_AsUTF8(lower);
 | 
						|
    if (utf8lower == NULL) {
 | 
						|
        Py_DECREF(lower);
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    int found = find_hash_info_by_utf8name(state, utf8lower, info);
 | 
						|
    Py_DECREF(lower);
 | 
						|
    return found;
 | 
						|
 | 
						|
error:
 | 
						|
    *info = NULL;
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Find the corresponding HMAC hash function static information.
 | 
						|
 *
 | 
						|
 * On error, propagate the exception, set 'info' to NULL and return -1.
 | 
						|
 *
 | 
						|
 * If no correspondence exists, set 'info' to NULL and return 0.
 | 
						|
 * Otherwise, set 'info' to the deduced information and return 1.
 | 
						|
 *
 | 
						|
 * Parameters
 | 
						|
 *
 | 
						|
 *      state           The HMAC module state.
 | 
						|
 *      hash_info_ref   An input to hashlib.new().
 | 
						|
 *      info            The deduced information, if any.
 | 
						|
 */
 | 
						|
static int
 | 
						|
find_hash_info_impl(hmacmodule_state *state,
 | 
						|
                    PyObject *hash_info_ref,
 | 
						|
                    const py_hmac_hinfo **info)
 | 
						|
{
 | 
						|
    if (PyUnicode_Check(hash_info_ref)) {
 | 
						|
        return find_hash_info_by_name(state, hash_info_ref, info);
 | 
						|
    }
 | 
						|
    // NOTE(picnixz): For now, we only support named algorithms.
 | 
						|
    // In the future, we need to decide whether 'hashlib.openssl_md5'
 | 
						|
    // would make sense as an alias to 'md5' and how to remove OpenSSL.
 | 
						|
    *info = NULL;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Find the corresponding HMAC hash function static information.
 | 
						|
 *
 | 
						|
 * If nothing can be found or if an error occurred, return NULL
 | 
						|
 * with an exception set. Otherwise return a non-NULL object.
 | 
						|
 */
 | 
						|
static const py_hmac_hinfo *
 | 
						|
find_hash_info(hmacmodule_state *state, PyObject *hash_info_ref)
 | 
						|
{
 | 
						|
    const py_hmac_hinfo *info = NULL;
 | 
						|
    int rc = find_hash_info_impl(state, hash_info_ref, &info);
 | 
						|
    // The code below could be simplfied with only 'rc == 0' case,
 | 
						|
    // but we are deliberately verbose to ease future improvements.
 | 
						|
    if (rc < 0) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    if (rc == 0) {
 | 
						|
        PyErr_Format(state->unknown_hash_error,
 | 
						|
                     "unsupported hash type: %R", hash_info_ref);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    assert(info != NULL);
 | 
						|
    return info;
 | 
						|
}
 | 
						|
 | 
						|
/* Check that the buffer length fits on a uint32_t. */
 | 
						|
static inline int
 | 
						|
has_uint32_t_buffer_length(const Py_buffer *buffer)
 | 
						|
{
 | 
						|
#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
 | 
						|
    return buffer->len <= UINT32_MAX_AS_SSIZE_T;
 | 
						|
#else
 | 
						|
    return 1;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
// --- HMAC object ------------------------------------------------------------
 | 
						|
 | 
						|
/*
 | 
						|
 * Use the HMAC information 'info' to populate the corresponding fields.
 | 
						|
 *
 | 
						|
 * The real 'kind' for BLAKE-2 is obtained once and depends on both static
 | 
						|
 * capabilities (supported compiler flags) and runtime CPUID features.
 | 
						|
 */
 | 
						|
static void
 | 
						|
hmac_set_hinfo(hmacmodule_state *state,
 | 
						|
               HMACObject *self, const py_hmac_hinfo *info)
 | 
						|
{
 | 
						|
    assert(info->display_name != NULL);
 | 
						|
    self->name = Py_NewRef(info->display_name);
 | 
						|
    assert_is_static_hmac_hash_kind(info->kind);
 | 
						|
    self->kind = narrow_hmac_hash_kind(state, info->kind);
 | 
						|
    assert(info->block_size <= Py_hmac_hash_max_block_size);
 | 
						|
    self->block_size = info->block_size;
 | 
						|
    assert(info->digest_size <= Py_hmac_hash_max_digest_size);
 | 
						|
    self->digest_size = info->digest_size;
 | 
						|
    assert(info->api.compute != NULL);
 | 
						|
    assert(info->api.compute_py != NULL);
 | 
						|
    self->api = info->api;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Create initial HACL* internal state with the given key.
 | 
						|
 *
 | 
						|
 * This function MUST only be called by the HMAC object constructor
 | 
						|
 * and after hmac_set_hinfo() has been called, lest the behaviour is
 | 
						|
 * undefined.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 */
 | 
						|
static int
 | 
						|
hmac_new_initial_state(HMACObject *self, uint8_t *key, Py_ssize_t len)
 | 
						|
{
 | 
						|
    assert(key != NULL);
 | 
						|
#ifdef Py_HMAC_SSIZE_LARGER_THAN_UINT32
 | 
						|
    // Technically speaking, we could hash the key to make it small
 | 
						|
    // but it would require to call the hash functions ourselves and
 | 
						|
    // not rely on HACL* implementation anymore. As such, we explicitly
 | 
						|
    // reject keys that do not fit on 32 bits until HACL* handles them.
 | 
						|
    if (len > UINT32_MAX_AS_SSIZE_T) {
 | 
						|
        set_invalid_key_length_error();
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    assert(self->kind != Py_hmac_kind_hash_unknown);
 | 
						|
    // cast to uint32_t is now safe even on 32-bit platforms
 | 
						|
    self->state = _hacl_hmac_state_new(self->kind, key, (uint32_t)len);
 | 
						|
    // _hacl_hmac_state_new() may set an exception on error
 | 
						|
    return self->state == NULL ? -1 : 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Feed initial data.
 | 
						|
 *
 | 
						|
 * This function MUST only be called by the HMAC object constructor
 | 
						|
 * and after hmac_set_hinfo() and hmac_new_initial_state() have been
 | 
						|
 * called, lest the behaviour is undefined.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 */
 | 
						|
static int
 | 
						|
hmac_feed_initial_data(HMACObject *self, uint8_t *msg, Py_ssize_t len)
 | 
						|
{
 | 
						|
    assert(self->name != NULL);
 | 
						|
    assert(self->state != NULL);
 | 
						|
    if (len == 0) {
 | 
						|
        // do nothing if the buffer is empty
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (len < HASHLIB_GIL_MINSIZE) {
 | 
						|
        Py_HMAC_HACL_UPDATE(self->state, msg, len, self->name, return -1);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    int res = 0;
 | 
						|
    Py_BEGIN_ALLOW_THREADS
 | 
						|
        Py_HMAC_HACL_UPDATE(self->state, msg, len, self->name, goto error);
 | 
						|
        goto done;
 | 
						|
#ifndef NDEBUG
 | 
						|
error:
 | 
						|
        res = -1;
 | 
						|
#else
 | 
						|
        Py_UNREACHABLE();
 | 
						|
#endif
 | 
						|
done:
 | 
						|
    Py_END_ALLOW_THREADS
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.new
 | 
						|
 | 
						|
    key as keyobj: object
 | 
						|
    msg as msgobj: object(c_default="NULL") = None
 | 
						|
    digestmod as hash_info_ref: object(c_default="NULL") = None
 | 
						|
 | 
						|
Return a new HMAC object.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_new_impl(PyObject *module, PyObject *keyobj, PyObject *msgobj,
 | 
						|
               PyObject *hash_info_ref)
 | 
						|
/*[clinic end generated code: output=7c7573a427d58758 input=92fc7c0a00707d42]*/
 | 
						|
{
 | 
						|
    hmacmodule_state *state = get_hmacmodule_state(module);
 | 
						|
    if (hash_info_ref == NULL) {
 | 
						|
        PyErr_SetString(PyExc_TypeError,
 | 
						|
                        "new() missing 1 required argument 'digestmod'");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    const py_hmac_hinfo *info = find_hash_info(state, hash_info_ref);
 | 
						|
    if (info == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    HMACObject *self = PyObject_GC_New(HMACObject, state->hmac_type);
 | 
						|
    if (self == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    HASHLIB_INIT_MUTEX(self);
 | 
						|
    hmac_set_hinfo(state, self, info);
 | 
						|
    int rc;
 | 
						|
    // Create the HACL* internal state with the given key.
 | 
						|
    Py_buffer key;
 | 
						|
    GET_BUFFER_VIEW_OR_ERROR(keyobj, &key, goto error_on_key);
 | 
						|
    rc = hmac_new_initial_state(self, key.buf, key.len);
 | 
						|
    PyBuffer_Release(&key);
 | 
						|
    if (rc < 0) {
 | 
						|
        goto error;
 | 
						|
    }
 | 
						|
    // Feed the internal state the initial message if any.
 | 
						|
    if (msgobj != NULL && msgobj != Py_None) {
 | 
						|
        Py_buffer msg;
 | 
						|
        GET_BUFFER_VIEW_OR_ERROR(msgobj, &msg, goto error);
 | 
						|
        rc = hmac_feed_initial_data(self, msg.buf, msg.len);
 | 
						|
        PyBuffer_Release(&msg);
 | 
						|
#ifndef NDEBUG
 | 
						|
        if (rc < 0) {
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
#else
 | 
						|
        (void)rc;
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    assert(rc == 0);
 | 
						|
    PyObject_GC_Track(self);
 | 
						|
    return (PyObject *)self;
 | 
						|
 | 
						|
error_on_key:
 | 
						|
    self->state = NULL;
 | 
						|
error:
 | 
						|
    Py_DECREF(self);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Copy HMAC hash information from 'src' to 'out'.
 | 
						|
 */
 | 
						|
static void
 | 
						|
hmac_copy_hinfo(HMACObject *out, const HMACObject *src)
 | 
						|
{
 | 
						|
    assert(src->name != NULL);
 | 
						|
    out->name = Py_NewRef(src->name);
 | 
						|
    assert(src->kind != Py_hmac_kind_hash_unknown);
 | 
						|
    out->kind = src->kind;
 | 
						|
    assert(src->block_size <= Py_hmac_hash_max_block_size);
 | 
						|
    out->block_size = src->block_size;
 | 
						|
    assert(src->digest_size <= Py_hmac_hash_max_digest_size);
 | 
						|
    out->digest_size = src->digest_size;
 | 
						|
    assert(src->api.compute != NULL);
 | 
						|
    assert(src->api.compute_py != NULL);
 | 
						|
    out->api = src->api;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Copy the HMAC internal state from 'src' to 'out'.
 | 
						|
 *
 | 
						|
 * The internal state of 'out' must not already exist.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 */
 | 
						|
static int
 | 
						|
hmac_copy_state(HMACObject *out, const HMACObject *src)
 | 
						|
{
 | 
						|
    assert(src->state != NULL);
 | 
						|
    out->state = Hacl_Streaming_HMAC_copy(src->state);
 | 
						|
    if (out->state == NULL) {
 | 
						|
        PyErr_NoMemory();
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.HMAC.copy
 | 
						|
 | 
						|
    cls: defining_class
 | 
						|
 | 
						|
Return a copy ("clone") of the HMAC object.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_copy_impl(HMACObject *self, PyTypeObject *cls)
 | 
						|
/*[clinic end generated code: output=a955bfa55b65b215 input=17b2c0ad0b147e36]*/
 | 
						|
{
 | 
						|
    hmacmodule_state *state = get_hmacmodule_state_by_cls(cls);
 | 
						|
    HMACObject *copy = PyObject_GC_New(HMACObject, state->hmac_type);
 | 
						|
    if (copy == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    ENTER_HASHLIB(self);
 | 
						|
    /* copy hash information */
 | 
						|
    hmac_copy_hinfo(copy, self);
 | 
						|
    /* copy internal state */
 | 
						|
    int rc = hmac_copy_state(copy, self);
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
 | 
						|
    if (rc < 0) {
 | 
						|
        Py_DECREF(copy);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    HASHLIB_INIT_MUTEX(copy);
 | 
						|
    PyObject_GC_Track(copy);
 | 
						|
    return (PyObject *)copy;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Update the HMAC object with the given buffer.
 | 
						|
 *
 | 
						|
 * This unconditionally acquires the lock on the HMAC object.
 | 
						|
 *
 | 
						|
 * On DEBUG builds, each update() call is verified.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 */
 | 
						|
static int
 | 
						|
hmac_update_state_with_lock(HMACObject *self, uint8_t *buf, Py_ssize_t len)
 | 
						|
{
 | 
						|
    int res = 0;
 | 
						|
    Py_BEGIN_ALLOW_THREADS
 | 
						|
        PyMutex_Lock(&self->mutex);  // unconditionally acquire a lock
 | 
						|
        Py_HMAC_HACL_UPDATE(self->state, buf, len, self->name, goto error);
 | 
						|
        goto done;
 | 
						|
#ifndef NDEBUG
 | 
						|
error:
 | 
						|
        res = -1;
 | 
						|
#else
 | 
						|
        Py_UNREACHABLE();
 | 
						|
#endif
 | 
						|
done:
 | 
						|
        PyMutex_Unlock(&self->mutex);
 | 
						|
    Py_END_ALLOW_THREADS
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Update the HMAC object with the given buffer.
 | 
						|
 *
 | 
						|
 * This conditionally acquires the lock on the HMAC object.
 | 
						|
 *
 | 
						|
 * On DEBUG builds, each update() call is verified.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 */
 | 
						|
static int
 | 
						|
hmac_update_state_cond_lock(HMACObject *self, uint8_t *buf, Py_ssize_t len)
 | 
						|
{
 | 
						|
    ENTER_HASHLIB(self);  // conditionally acquire a lock
 | 
						|
    Py_HMAC_HACL_UPDATE(self->state, buf, len, self->name, goto error);
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
    return 0;
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
error:
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
    return -1;
 | 
						|
#else
 | 
						|
    Py_UNREACHABLE();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Update the internal HMAC state with the given buffer.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 */
 | 
						|
static inline int
 | 
						|
hmac_update_state(HMACObject *self, uint8_t *buf, Py_ssize_t len)
 | 
						|
{
 | 
						|
    assert(buf != 0);
 | 
						|
    assert(len >= 0);
 | 
						|
    return len == 0
 | 
						|
               ? 0 /* nothing to do */
 | 
						|
               : len < HASHLIB_GIL_MINSIZE
 | 
						|
                     ? hmac_update_state_cond_lock(self, buf, len)
 | 
						|
                     : hmac_update_state_with_lock(self, buf, len);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.HMAC.update
 | 
						|
 | 
						|
    msg as msgobj: object
 | 
						|
 | 
						|
Update the HMAC object with the given message.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_update_impl(HMACObject *self, PyObject *msgobj)
 | 
						|
/*[clinic end generated code: output=962134ada5e55985 input=7c0ea830efb03367]*/
 | 
						|
{
 | 
						|
    Py_buffer msg;
 | 
						|
    GET_BUFFER_VIEW_OR_ERROUT(msgobj, &msg);
 | 
						|
    int rc = hmac_update_state(self, msg.buf, msg.len);
 | 
						|
    PyBuffer_Release(&msg);
 | 
						|
    return rc < 0 ? NULL : Py_None;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Compute the HMAC-HASH digest from the internal HACL* state.
 | 
						|
 *
 | 
						|
 * At least 'self->digest_size' bytes should be available
 | 
						|
 * in the 'digest' pointed memory area.
 | 
						|
 *
 | 
						|
 * Return 0 on success; otherwise, set an exception and return -1 on failure.
 | 
						|
 *
 | 
						|
 * Note: this function may raise a MemoryError.
 | 
						|
 */
 | 
						|
static int
 | 
						|
hmac_digest_compute_cond_lock(HMACObject *self, uint8_t *digest)
 | 
						|
{
 | 
						|
    assert(digest != NULL);
 | 
						|
    hacl_errno_t rc;
 | 
						|
    ENTER_HASHLIB(self);  // conditionally acquire a lock
 | 
						|
    rc = Hacl_Streaming_HMAC_digest(self->state, digest, self->digest_size);
 | 
						|
    LEAVE_HASHLIB(self);
 | 
						|
    assert(
 | 
						|
        rc == Hacl_Streaming_Types_Success ||
 | 
						|
        rc == Hacl_Streaming_Types_OutOfMemory
 | 
						|
    );
 | 
						|
    return _hacl_convert_errno(rc, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.HMAC.digest
 | 
						|
 | 
						|
Return the digest of the bytes passed to the update() method so far.
 | 
						|
 | 
						|
This method may raise a MemoryError.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_digest_impl(HMACObject *self)
 | 
						|
/*[clinic end generated code: output=5bf3cc5862d26ada input=a70feb0b8e2bbe7d]*/
 | 
						|
{
 | 
						|
    assert(self->digest_size <= Py_hmac_hash_max_digest_size);
 | 
						|
    uint8_t digest[Py_hmac_hash_max_digest_size];
 | 
						|
    if (hmac_digest_compute_cond_lock(self, digest) < 0) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    return PyBytes_FromStringAndSize((const char *)digest, self->digest_size);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.HMAC.hexdigest
 | 
						|
 | 
						|
Return hexadecimal digest of the bytes passed to the update() method so far.
 | 
						|
 | 
						|
This may be used to exchange the value safely in email or other non-binary
 | 
						|
environments.
 | 
						|
 | 
						|
This method may raise a MemoryError.
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_hexdigest_impl(HMACObject *self)
 | 
						|
/*[clinic end generated code: output=6659807a09ae14ec input=493b2db8013982b9]*/
 | 
						|
{
 | 
						|
    assert(self->digest_size <= Py_hmac_hash_max_digest_size);
 | 
						|
    uint8_t digest[Py_hmac_hash_max_digest_size];
 | 
						|
    if (hmac_digest_compute_cond_lock(self, digest) < 0) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    return _Py_strhex((const char *)digest, self->digest_size);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
@getter
 | 
						|
_hmac.HMAC.name
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_name_get_impl(HMACObject *self)
 | 
						|
/*[clinic end generated code: output=ae693f09778d96d9 input=41c2c5dd1cf47fbc]*/
 | 
						|
{
 | 
						|
    assert(self->name != NULL);
 | 
						|
    return PyUnicode_FromFormat("hmac-%U", self->name);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
@getter
 | 
						|
_hmac.HMAC.block_size
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_block_size_get_impl(HMACObject *self)
 | 
						|
/*[clinic end generated code: output=52cb11dee4e80cae input=9dda6b8d43e995b4]*/
 | 
						|
{
 | 
						|
    return PyLong_FromUInt32(self->block_size);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
@getter
 | 
						|
_hmac.HMAC.digest_size
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_HMAC_digest_size_get_impl(HMACObject *self)
 | 
						|
/*[clinic end generated code: output=22eeca1010ac6255 input=5622bb2840025b5a]*/
 | 
						|
{
 | 
						|
    return PyLong_FromUInt32(self->digest_size);
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
HMACObject_repr(PyObject *op)
 | 
						|
{
 | 
						|
    HMACObject *self = HMACObject_CAST(op);
 | 
						|
    assert(self->name != NULL);
 | 
						|
    return PyUnicode_FromFormat("<%U HMAC object @ %p>", self->name, self);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
HMACObject_clear(PyObject *op)
 | 
						|
{
 | 
						|
    HMACObject *self = HMACObject_CAST(op);
 | 
						|
    Py_CLEAR(self->name);
 | 
						|
    _hacl_hmac_state_free(self->state);
 | 
						|
    self->state = NULL;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
HMACObject_dealloc(PyObject *op)
 | 
						|
{
 | 
						|
    PyTypeObject *type = Py_TYPE(op);
 | 
						|
    PyObject_GC_UnTrack(op);
 | 
						|
    (void)HMACObject_clear(op);
 | 
						|
    type->tp_free(op);
 | 
						|
    Py_DECREF(type);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
HMACObject_traverse(PyObject *op, visitproc visit, void *arg)
 | 
						|
{
 | 
						|
    Py_VISIT(Py_TYPE(op));
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static PyMethodDef HMACObject_methods[] = {
 | 
						|
    _HMAC_HMAC_COPY_METHODDEF
 | 
						|
    _HMAC_HMAC_UPDATE_METHODDEF
 | 
						|
    _HMAC_HMAC_DIGEST_METHODDEF
 | 
						|
    _HMAC_HMAC_HEXDIGEST_METHODDEF
 | 
						|
    {NULL, NULL, 0, NULL} /* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
static PyGetSetDef HMACObject_getsets[] = {
 | 
						|
    _HMAC_HMAC_NAME_GETSETDEF
 | 
						|
    _HMAC_HMAC_BLOCK_SIZE_GETSETDEF
 | 
						|
    _HMAC_HMAC_DIGEST_SIZE_GETSETDEF
 | 
						|
    {NULL, NULL, NULL, NULL, NULL} /* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
static PyType_Slot HMACObject_Type_slots[] = {
 | 
						|
    {Py_tp_repr, HMACObject_repr},
 | 
						|
    {Py_tp_methods, HMACObject_methods},
 | 
						|
    {Py_tp_getset, HMACObject_getsets},
 | 
						|
    {Py_tp_clear, HMACObject_clear},
 | 
						|
    {Py_tp_dealloc, HMACObject_dealloc},
 | 
						|
    {Py_tp_traverse, HMACObject_traverse},
 | 
						|
    {0, NULL} /* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
static PyType_Spec HMAC_Type_spec = {
 | 
						|
    .name = "_hmac.HMAC",
 | 
						|
    .basicsize = sizeof(HMACObject),
 | 
						|
    .flags = Py_TPFLAGS_DEFAULT
 | 
						|
             | Py_TPFLAGS_DISALLOW_INSTANTIATION
 | 
						|
             | Py_TPFLAGS_HEAPTYPE
 | 
						|
             | Py_TPFLAGS_IMMUTABLETYPE
 | 
						|
             | Py_TPFLAGS_HAVE_GC,
 | 
						|
    .slots = HMACObject_Type_slots,
 | 
						|
};
 | 
						|
 | 
						|
// --- One-shot HMAC-HASH interface -------------------------------------------
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_digest
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    digest: object
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_digest_impl(PyObject *module, PyObject *key, PyObject *msg,
 | 
						|
                          PyObject *digest)
 | 
						|
/*[clinic end generated code: output=c519b7c4c9f57333 input=1c2bfc2cd8598574]*/
 | 
						|
{
 | 
						|
    hmacmodule_state *state = get_hmacmodule_state(module);
 | 
						|
    const py_hmac_hinfo *info = find_hash_info(state, digest);
 | 
						|
    if (info == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    assert(info->api.compute_py != NULL);
 | 
						|
    return info->api.compute_py(module, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * One-shot HMAC-HASH using the given HACL_HID.
 | 
						|
 *
 | 
						|
 * The length of the key and message buffers must not exceed UINT32_MAX,
 | 
						|
 * lest an OverflowError is raised. The Python implementation takes care
 | 
						|
 * of dispatching to the OpenSSL implementation in this case.
 | 
						|
 */
 | 
						|
#define Py_HMAC_HACL_ONESHOT(HACL_HID, KEY, MSG)                \
 | 
						|
    do {                                                        \
 | 
						|
        Py_buffer keyview, msgview;                             \
 | 
						|
        GET_BUFFER_VIEW_OR_ERROUT((KEY), &keyview);             \
 | 
						|
        if (!has_uint32_t_buffer_length(&keyview)) {            \
 | 
						|
            PyBuffer_Release(&keyview);                         \
 | 
						|
            set_invalid_key_length_error();                     \
 | 
						|
            return NULL;                                        \
 | 
						|
        }                                                       \
 | 
						|
        GET_BUFFER_VIEW_OR_ERROR((MSG), &msgview,               \
 | 
						|
                                 PyBuffer_Release(&keyview);    \
 | 
						|
                                 return NULL);                  \
 | 
						|
        if (!has_uint32_t_buffer_length(&msgview)) {            \
 | 
						|
            PyBuffer_Release(&msgview);                         \
 | 
						|
            PyBuffer_Release(&keyview);                         \
 | 
						|
            set_invalid_msg_length_error();                     \
 | 
						|
            return NULL;                                        \
 | 
						|
        }                                                       \
 | 
						|
        uint8_t out[Py_hmac_## HACL_HID ##_digest_size];        \
 | 
						|
        Py_hmac_## HACL_HID ##_compute_func(                    \
 | 
						|
            out,                                                \
 | 
						|
            (uint8_t *)keyview.buf, (uint32_t)keyview.len,      \
 | 
						|
            (uint8_t *)msgview.buf, (uint32_t)msgview.len       \
 | 
						|
        );                                                      \
 | 
						|
        PyBuffer_Release(&msgview);                             \
 | 
						|
        PyBuffer_Release(&keyview);                             \
 | 
						|
        return PyBytes_FromStringAndSize(                       \
 | 
						|
            (const char *)out,                                  \
 | 
						|
            Py_hmac_## HACL_HID ##_digest_size                  \
 | 
						|
        );                                                      \
 | 
						|
    } while (0)
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_md5
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_md5_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=7837a4ceccbbf636 input=77a4b774c7d61218]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(md5, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha1
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha1_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=79fd7689c83691d8 input=3b64dccc6bdbe4ba]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha1, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha224 as _hmac_compute_sha2_224
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha2_224_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=7f21f1613e53979e input=a1a75f25f23449af]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha2_224, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha256 as _hmac_compute_sha2_256
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha2_256_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=d4a291f7d9a82459 input=5c9ccf2df048ace3]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha2_256, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha384 as _hmac_compute_sha2_384
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha2_384_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=f211fa26e3700c27 input=2fee2c14766af231]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha2_384, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha512 as _hmac_compute_sha2_512
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha2_512_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=d5c20373762cecca input=3371eaac315c7864]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha2_512, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha3_224
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha3_224_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=a242ccac9ad9c22b input=d0ab0c7d189c3d87]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha3_224, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha3_256
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha3_256_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=b539dbb61af2fe0b input=f05d7b6364b35d02]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha3_256, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha3_384
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha3_384_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=5eb372fb5c4ffd3a input=d842d393e7aa05ae]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha3_384, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_sha3_512
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_sha3_512_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=154bcbf8c2eacac1 input=166fe5baaeaabfde]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(sha3_512, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_blake2s_32
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_blake2s_32_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=cfc730791bc62361 input=d22c36e7fe31a985]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(blake2s_32, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
/*[clinic input]
 | 
						|
_hmac.compute_blake2b_32
 | 
						|
 | 
						|
    key: object
 | 
						|
    msg: object
 | 
						|
    /
 | 
						|
 | 
						|
[clinic start generated code]*/
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_hmac_compute_blake2b_32_impl(PyObject *module, PyObject *key, PyObject *msg)
 | 
						|
/*[clinic end generated code: output=765c5c4fb9124636 input=4a35ee058d172f4b]*/
 | 
						|
{
 | 
						|
    Py_HMAC_HACL_ONESHOT(blake2b_32, key, msg);
 | 
						|
}
 | 
						|
 | 
						|
// --- HMAC module methods ----------------------------------------------------
 | 
						|
 | 
						|
static PyMethodDef hmacmodule_methods[] = {
 | 
						|
    _HMAC_NEW_METHODDEF
 | 
						|
    /* one-shot dispatcher */
 | 
						|
    _HMAC_COMPUTE_DIGEST_METHODDEF
 | 
						|
    /* one-shot methods */
 | 
						|
    _HMAC_COMPUTE_MD5_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA1_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA2_224_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA2_256_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA2_384_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA2_512_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA3_224_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA3_256_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA3_384_METHODDEF
 | 
						|
    _HMAC_COMPUTE_SHA3_512_METHODDEF
 | 
						|
    _HMAC_COMPUTE_BLAKE2S_32_METHODDEF
 | 
						|
    _HMAC_COMPUTE_BLAKE2B_32_METHODDEF
 | 
						|
    {NULL, NULL, 0, NULL} /* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
// --- HMAC static information table ------------------------------------------
 | 
						|
 | 
						|
static inline Py_uhash_t
 | 
						|
py_hmac_hinfo_ht_hash(const void *name)
 | 
						|
{
 | 
						|
    return Py_HashBuffer(name, strlen((const char *)name));
 | 
						|
}
 | 
						|
 | 
						|
static inline int
 | 
						|
py_hmac_hinfo_ht_comp(const void *a, const void *b)
 | 
						|
{
 | 
						|
    return strcmp((const char *)a, (const char *)b) == 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
py_hmac_hinfo_ht_free(void *hinfo)
 | 
						|
{
 | 
						|
    py_hmac_hinfo *entry = (py_hmac_hinfo *)hinfo;
 | 
						|
    assert(entry->display_name != NULL);
 | 
						|
    if (--(entry->refcnt) == 0) {
 | 
						|
        Py_CLEAR(entry->display_name);
 | 
						|
        PyMem_Free(hinfo);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Equivalent to table.setdefault(key, info).
 | 
						|
 *
 | 
						|
 * Return 1 if a new item has been created, 0 if 'key' is NULL or
 | 
						|
 * an entry 'table[key]' existed, and -1 if a memory error occurs.
 | 
						|
 *
 | 
						|
 * To reduce memory footprint, 'info' may be a borrowed reference,
 | 
						|
 * namely, multiple keys can be associated with the same 'info'.
 | 
						|
 *
 | 
						|
 * In particular, resources owned by 'info' must only be released
 | 
						|
 * when a single key associated with 'info' remains.
 | 
						|
 */
 | 
						|
static int
 | 
						|
py_hmac_hinfo_ht_add(_Py_hashtable_t *table, const void *key, void *info)
 | 
						|
{
 | 
						|
    if (key == NULL || _Py_hashtable_get_entry(table, key) != NULL) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    if (_Py_hashtable_set(table, key, info) < 0) {
 | 
						|
        assert(!PyErr_Occurred());
 | 
						|
        PyErr_NoMemory();
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Create a new hashtable from the static 'py_hmac_static_hinfo' object,
 | 
						|
 * or set an exception and return NULL if an error occurs.
 | 
						|
 */
 | 
						|
static _Py_hashtable_t *
 | 
						|
py_hmac_hinfo_ht_new(void)
 | 
						|
{
 | 
						|
    _Py_hashtable_t *table = _Py_hashtable_new_full(
 | 
						|
        py_hmac_hinfo_ht_hash,
 | 
						|
        py_hmac_hinfo_ht_comp,
 | 
						|
        NULL,
 | 
						|
        py_hmac_hinfo_ht_free,
 | 
						|
        NULL
 | 
						|
    );
 | 
						|
 | 
						|
    if (table == NULL) {
 | 
						|
        assert(!PyErr_Occurred());
 | 
						|
        PyErr_NoMemory();
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    for (const py_hmac_hinfo *e = py_hmac_static_hinfo; e->name != NULL; e++) {
 | 
						|
        /*
 | 
						|
         * The real kind of a HMAC object is obtained only once and is
 | 
						|
         * derived from the kind of the 'py_hmac_hinfo' that could be
 | 
						|
         * found by its name.
 | 
						|
         *
 | 
						|
         * Since 'vectorized_blake2{s,b}_32' depend on the runtime CPUID
 | 
						|
         * features, we should not create 'py_hmac_hinfo' entries for them.
 | 
						|
         */
 | 
						|
        assert_is_static_hmac_hash_kind(e->kind);
 | 
						|
 | 
						|
        py_hmac_hinfo *value = PyMem_Malloc(sizeof(py_hmac_hinfo));
 | 
						|
        if (value == NULL) {
 | 
						|
            PyErr_NoMemory();
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
 | 
						|
        memcpy(value, e, sizeof(py_hmac_hinfo));
 | 
						|
        assert(value->display_name == NULL);
 | 
						|
        value->refcnt = 0;
 | 
						|
 | 
						|
#define Py_HMAC_HINFO_LINK(KEY)                                 \
 | 
						|
        do {                                                    \
 | 
						|
            int rc = py_hmac_hinfo_ht_add(table, KEY, value);   \
 | 
						|
            if (rc < 0) {                                       \
 | 
						|
                PyMem_Free(value);                              \
 | 
						|
                goto error;                                     \
 | 
						|
            }                                                   \
 | 
						|
            else if (rc == 1) {                                 \
 | 
						|
                value->refcnt++;                                \
 | 
						|
            }                                                   \
 | 
						|
        } while (0)
 | 
						|
        Py_HMAC_HINFO_LINK(e->name);
 | 
						|
        Py_HMAC_HINFO_LINK(e->hashlib_name);
 | 
						|
#undef Py_HMAC_HINFO_LINK
 | 
						|
        assert(value->refcnt > 0);
 | 
						|
        assert(value->display_name == NULL);
 | 
						|
        value->display_name = PyUnicode_FromString(
 | 
						|
            /* display name is synchronized with hashlib's name */
 | 
						|
            e->hashlib_name == NULL ? e->name : e->hashlib_name
 | 
						|
        );
 | 
						|
        if (value->display_name == NULL) {
 | 
						|
            PyMem_Free(value);
 | 
						|
            goto error;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return table;
 | 
						|
 | 
						|
error:
 | 
						|
    _Py_hashtable_destroy(table);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
// --- HMAC module initialization and finalization functions ------------------
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_init_hash_info_table(hmacmodule_state *state)
 | 
						|
{
 | 
						|
    // py_hmac_hinfo_ht_new() sets an exception on error
 | 
						|
    state->hinfo_table = py_hmac_hinfo_ht_new();
 | 
						|
    return state->hinfo_table == NULL ? -1 : 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_init_exceptions(PyObject *module, hmacmodule_state *state)
 | 
						|
{
 | 
						|
#define ADD_EXC(ATTR, NAME, BASE)                                       \
 | 
						|
    do {                                                                \
 | 
						|
        state->ATTR = PyErr_NewException("_hmac." NAME, BASE, NULL);    \
 | 
						|
        if (state->ATTR == NULL) {                                      \
 | 
						|
            return -1;                                                  \
 | 
						|
        }                                                               \
 | 
						|
        if (PyModule_AddObjectRef(module, NAME, state->ATTR) < 0) {     \
 | 
						|
            return -1;                                                  \
 | 
						|
        }                                                               \
 | 
						|
    } while (0)
 | 
						|
    ADD_EXC(unknown_hash_error, "UnknownHashError", PyExc_ValueError);
 | 
						|
#undef ADD_EXC
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_init_hmac_type(PyObject *module, hmacmodule_state *state)
 | 
						|
{
 | 
						|
    state->hmac_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
 | 
						|
                                                                &HMAC_Type_spec,
 | 
						|
                                                                NULL);
 | 
						|
    if (state->hmac_type == NULL) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (PyModule_AddType(module, state->hmac_type) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_init_strings(hmacmodule_state *state)
 | 
						|
{
 | 
						|
#define ADD_STR(ATTR, STRING)                       \
 | 
						|
    do {                                            \
 | 
						|
        state->ATTR = PyUnicode_FromString(STRING); \
 | 
						|
        if (state->ATTR == NULL) {                  \
 | 
						|
            return -1;                              \
 | 
						|
        }                                           \
 | 
						|
    } while (0)
 | 
						|
    ADD_STR(str_lower, "lower");
 | 
						|
#undef ADD_STR
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_init_globals(PyObject *module, hmacmodule_state *state)
 | 
						|
{
 | 
						|
#define ADD_INT_CONST(NAME, VALUE)                                  \
 | 
						|
    do {                                                            \
 | 
						|
        if (PyModule_AddIntConstant(module, (NAME), (VALUE)) < 0) { \
 | 
						|
            return -1;                                              \
 | 
						|
        }                                                           \
 | 
						|
    } while (0)
 | 
						|
    ADD_INT_CONST("_GIL_MINSIZE", HASHLIB_GIL_MINSIZE);
 | 
						|
#undef ADD_INT_CONST
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
hmacmodule_init_cpu_features(hmacmodule_state *state)
 | 
						|
{
 | 
						|
    int eax1 = 0, ebx1 = 0, ecx1 = 0, edx1 = 0;
 | 
						|
    int eax7 = 0, ebx7 = 0, ecx7 = 0, edx7 = 0;
 | 
						|
#if defined(__x86_64__) && defined(__GNUC__)
 | 
						|
    __cpuid_count(1, 0, eax1, ebx1, ecx1, edx1);
 | 
						|
    __cpuid_count(7, 0, eax7, ebx7, ecx7, edx7);
 | 
						|
#elif defined(_M_X64)
 | 
						|
    int info1[4] = { 0 };
 | 
						|
    __cpuidex(info1, 1, 0);
 | 
						|
    eax1 = info1[0], ebx1 = info1[1], ecx1 = info1[2], edx1 = info1[3];
 | 
						|
 | 
						|
    int info7[4] = { 0 };
 | 
						|
    __cpuidex(info7, 7, 0);
 | 
						|
    eax7 = info7[0], ebx7 = info7[1], ecx7 = info7[2], edx7 = info7[3];
 | 
						|
#endif
 | 
						|
    // fmt: off
 | 
						|
    (void)eax1; (void)ebx1; (void)ecx1; (void)edx1;
 | 
						|
    (void)eax7; (void)ebx7; (void)ecx7; (void)edx7;
 | 
						|
    // fmt: on
 | 
						|
 | 
						|
#define EBX_AVX2 (1 << 5)
 | 
						|
#define ECX_SSE3 (1 << 0)
 | 
						|
#define ECX_SSSE3 (1 << 9)
 | 
						|
#define ECX_SSE4_1 (1 << 19)
 | 
						|
#define ECX_SSE4_2 (1 << 20)
 | 
						|
#define ECX_AVX (1 << 28)
 | 
						|
#define EDX_SSE (1 << 25)
 | 
						|
#define EDX_SSE2 (1 << 26)
 | 
						|
#define EDX_CMOV (1 << 15)
 | 
						|
 | 
						|
    bool avx = (ecx1 & ECX_AVX) != 0;
 | 
						|
    bool avx2 = (ebx7 & EBX_AVX2) != 0;
 | 
						|
 | 
						|
    bool sse = (edx1 & EDX_SSE) != 0;
 | 
						|
    bool sse2 = (edx1 & EDX_SSE2) != 0;
 | 
						|
    bool cmov = (edx1 & EDX_CMOV) != 0;
 | 
						|
 | 
						|
    bool sse3 = (ecx1 & ECX_SSE3) != 0;
 | 
						|
    bool sse41 = (ecx1 & ECX_SSE4_1) != 0;
 | 
						|
    bool sse42 = (ecx1 & ECX_SSE4_2) != 0;
 | 
						|
 | 
						|
#undef EDX_CMOV
 | 
						|
#undef EDX_SSE2
 | 
						|
#undef EDX_SSE
 | 
						|
#undef ECX_AVX
 | 
						|
#undef ECX_SSE4_2
 | 
						|
#undef ECX_SSE4_1
 | 
						|
#undef ECX_SSSE3
 | 
						|
#undef ECX_SSE3
 | 
						|
#undef EBX_AVX2
 | 
						|
 | 
						|
#if HACL_CAN_COMPILE_SIMD128
 | 
						|
    // TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection
 | 
						|
    state->can_run_simd128 = sse && sse2 && sse3 && sse41 && sse42 && cmov;
 | 
						|
#else
 | 
						|
    // fmt: off
 | 
						|
    (void)sse; (void)sse2; (void)sse3; (void)sse41; (void)sse42; (void)cmov;
 | 
						|
    // fmt: on
 | 
						|
    state->can_run_simd128 = false;
 | 
						|
#endif
 | 
						|
 | 
						|
#if HACL_CAN_COMPILE_SIMD256
 | 
						|
    // TODO(picnixz): use py_cpuid_features (gh-125022) to improve detection
 | 
						|
    state->can_run_simd256 = state->can_run_simd128 && avx && avx2;
 | 
						|
#else
 | 
						|
    // fmt: off
 | 
						|
    (void)avx; (void)avx2;
 | 
						|
    // fmt: on
 | 
						|
    state->can_run_simd256 = false;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_exec(PyObject *module)
 | 
						|
{
 | 
						|
    hmacmodule_state *state = get_hmacmodule_state(module);
 | 
						|
    if (hmacmodule_init_hash_info_table(state) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (hmacmodule_init_exceptions(module, state) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (hmacmodule_init_hmac_type(module, state) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (hmacmodule_init_strings(state) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (hmacmodule_init_globals(module, state) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    hmacmodule_init_cpu_features(state);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_traverse(PyObject *mod, visitproc visit, void *arg)
 | 
						|
{
 | 
						|
    Py_VISIT(Py_TYPE(mod));
 | 
						|
    hmacmodule_state *state = get_hmacmodule_state(mod);
 | 
						|
    Py_VISIT(state->unknown_hash_error);
 | 
						|
    Py_VISIT(state->hmac_type);
 | 
						|
    Py_VISIT(state->str_lower);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
hmacmodule_clear(PyObject *mod)
 | 
						|
{
 | 
						|
    hmacmodule_state *state = get_hmacmodule_state(mod);
 | 
						|
    if (state->hinfo_table != NULL) {
 | 
						|
        _Py_hashtable_destroy(state->hinfo_table);
 | 
						|
        state->hinfo_table = NULL;
 | 
						|
    }
 | 
						|
    Py_CLEAR(state->unknown_hash_error);
 | 
						|
    Py_CLEAR(state->hmac_type);
 | 
						|
    Py_CLEAR(state->str_lower);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
hmacmodule_free(void *mod)
 | 
						|
{
 | 
						|
    (void)hmacmodule_clear((PyObject *)mod);
 | 
						|
}
 | 
						|
 | 
						|
static struct PyModuleDef_Slot hmacmodule_slots[] = {
 | 
						|
    {Py_mod_exec, hmacmodule_exec},
 | 
						|
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
 | 
						|
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
 | 
						|
    {0, NULL} /* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
static struct PyModuleDef _hmacmodule = {
 | 
						|
    PyModuleDef_HEAD_INIT,
 | 
						|
    .m_name = "_hmac",
 | 
						|
    .m_size = sizeof(hmacmodule_state),
 | 
						|
    .m_methods = hmacmodule_methods,
 | 
						|
    .m_slots = hmacmodule_slots,
 | 
						|
    .m_traverse = hmacmodule_traverse,
 | 
						|
    .m_clear = hmacmodule_clear,
 | 
						|
    .m_free = hmacmodule_free,
 | 
						|
};
 | 
						|
 | 
						|
PyMODINIT_FUNC
 | 
						|
PyInit__hmac(void)
 | 
						|
{
 | 
						|
    return PyModuleDef_Init(&_hmacmodule);
 | 
						|
}
 |