Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ ENSUREPIP= @ENSUREPIP@
# Internal static libraries
LIBMPDEC_A= Modules/_decimal/libmpdec/libmpdec.a
LIBEXPAT_A= Modules/expat/libexpat.a
LIBHASHLIB_INTERNAL_A=Modules/_hashlib/libhashlib.a

# HACL* build configuration
LIBHACL_CFLAGS=@LIBHACL_CFLAGS@
Expand Down Expand Up @@ -761,6 +762,17 @@ LIBHACL_HMAC_HEADERS= \
$(LIBHACL_BLAKE2_HEADERS) \
$(LIBHACL_HEADERS)

##########################################################################
# Internal library for cryptographic primitives

LIBHASHLIB_INTERNAL_OBJS= \
Modules/_hashlib/hashlib_buffer.o

LIBHASHLIB_INTERNAL_HEADERS= \
Modules/_hashlib/hashlib_buffer.h \
Modules/_hashlib/hashlib_fetch.h \
Modules/_hashlib/hashlib_mutex.h

#########################################################################
# Rules

Expand Down Expand Up @@ -1511,6 +1523,17 @@ $(LIBEXPAT_A): $(LIBEXPAT_OBJS)
-rm -f $@
$(AR) $(ARFLAGS) $@ $(LIBEXPAT_OBJS)

##########################################################################
# '_hashlib', '_hmac' and HACL*-based modules helpers
LIBHASHLIB_INTERNAL_CFLAGS=@LIBHASHLIB_INTERNAL_CFLAGS@ $(PY_STDMODULE_CFLAGS) $(CCSHARED)

Modules/_hashlib/hashlib_buffer.o: Modules/_hashlib/hashlib_buffer.c $(LIBHASHLIB_INTERNAL_HEADERS) $(PYTHON_HEADERS)
$(CC) -I$(srcdir)/Modules/_hashlib -c $(LIBHASHLIB_INTERNAL_CFLAGS) -o $@ $(srcdir)/Modules/_hashlib/hashlib_buffer.c

$(LIBHASHLIB_INTERNAL_A): $(LIBHASHLIB_INTERNAL_OBJS)
-rm -f $@
$(AR) $(ARFLAGS) $@ $(LIBHASHLIB_INTERNAL_OBJS)

##########################################################################
# HACL* library build
#
Expand Down Expand Up @@ -3353,21 +3376,21 @@ MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h
MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@
MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h @LIBMPDEC_INTERNAL@
MODULE__ELEMENTTREE_DEPS=$(srcdir)/Modules/pyexpat.c @LIBEXPAT_INTERNAL@
MODULE__HASHLIB_DEPS=$(srcdir)/Modules/hashlib.h
MODULE__HASHLIB_DEPS=@LIBHASHLIB_INTERNAL@
MODULE__IO_DEPS=$(srcdir)/Modules/_io/_iomodule.h

# HACL*-based cryptographic primitives
MODULE__MD5_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_MD5_HEADERS) $(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__MD5_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_MD5_HEADERS) $(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__MD5_LDEPS=$(LIBHACL_MD5_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA1_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA1_HEADERS) $(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA1_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_SHA1_HEADERS) $(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA1_LDEPS=$(LIBHACL_SHA1_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA2_HEADERS) $(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA2_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_SHA2_HEADERS) $(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA2_LDEPS=$(LIBHACL_SHA2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA3_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA3_HEADERS) $(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA3_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_SHA3_HEADERS) $(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__SHA3_LDEPS=$(LIBHACL_SHA3_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__BLAKE2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_BLAKE2_HEADERS) $(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__BLAKE2_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_BLAKE2_HEADERS) $(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__BLAKE2_LDEPS=$(LIBHACL_BLAKE2_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__HMAC_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HMAC_HEADERS) $(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__HMAC_DEPS=$(MODULE__HASHLIB_DEPS) $(LIBHACL_HMAC_HEADERS) $(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)
MODULE__HMAC_LDEPS=$(LIBHACL_HMAC_LIB_@LIBHACL_LDEPS_LIBTYPE@)

MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c $(srcdir)/Modules/getnameinfo.c
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Remove :file:`!Modules/hashlib.h` and move its content into dedicated files
now located in ``Modules/_hashlib``. Patch by Bénédikt Tran.
40 changes: 40 additions & 0 deletions Modules/_hashlib/hashlib_buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "hashlib_buffer.h"

int
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)
{
if (data != NULL && string == NULL) {
// called as H(data) or H(data=...)
*res = data;
return 1;
}
else if (data == NULL && string != NULL) {
// called as H(string=...)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"the 'string' keyword parameter is deprecated since "
"Python 3.15 and slated for removal in Python 3.19; "
"use the 'data' keyword parameter or pass the data "
"to hash as a positional argument instead", 1) < 0)
{
*res = NULL;
return -1;
}
*res = string;
return 1;
}
else if (data == NULL && string == NULL) {
// fast path when no data is given
assert(!PyErr_Occurred());
*res = NULL;
return 0;
}
else {
// called as H(data=..., string)
*res = NULL;
PyErr_SetString(PyExc_TypeError,
"'data' and 'string' are mutually exclusive "
"and support for 'string' keyword parameter "
"is slated for removal in a future version.");
return -1;
}
}
60 changes: 60 additions & 0 deletions Modules/_hashlib/hashlib_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#ifndef _HASHLIB_HASHLIB_BUFFER_H
#define _HASHLIB_HASHLIB_BUFFER_H

#include "Python.h"

/*
* Given an buffer-like OBJ, fill in the buffer VIEW with the result
* of PyObject_GetBuffer.
*
* On error, set an exception and execute the ERRACTION statements,
* e.g. 'return NULL' or 'goto error'.
*
* Parameters
*
* OBJ An object supporting the buffer API.
* VIEW A Py_buffer pointer to fill.
* ERRACTION The statements to execute on error.
*/
#define GET_BUFFER_VIEW_OR_ERROR(OBJ, VIEW, ERRACTION) \
do { \
if (PyUnicode_Check((OBJ))) { \
PyErr_SetString(PyExc_TypeError, \
"strings must be encoded before hashing"); \
ERRACTION; \
} \
if (!PyObject_CheckBuffer((OBJ))) { \
PyErr_SetString(PyExc_TypeError, \
"object supporting the buffer API required"); \
ERRACTION; \
} \
if (PyObject_GetBuffer((OBJ), (VIEW), PyBUF_SIMPLE) == -1) { \
ERRACTION; \
} \
if ((VIEW)->ndim > 1) { \
PyErr_SetString(PyExc_BufferError, \
"buffer must be one-dimensional"); \
PyBuffer_Release((VIEW)); \
ERRACTION; \
} \
} while(0)

/* Specialization of GET_BUFFER_VIEW_OR_ERROR() returning NULL on error. */
#define GET_BUFFER_VIEW_OR_ERROUT(OBJ, VIEW) \
GET_BUFFER_VIEW_OR_ERROR(OBJ, VIEW, return NULL)

/*
* Allow to use the 'data' or 'string' keyword in hashlib.new()
* and other hash functions named constructors.
*
* - If 'data' and 'string' are both non-NULL, set an exception and return -1.
* - If 'data' and 'string' are both NULL, set '*res' to NULL and return 0.
* - Otherwise, set '*res' to 'data' or 'string' and return 1. A deprecation
* warning is set when 'string' is specified.
*
* The symbol is exported for '_hashlib' and HACL*-based extension modules.
*/
PyAPI_FUNC(int)
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string);

#endif // !_HASHLIB_HASHLIB_BUFFER_H
62 changes: 62 additions & 0 deletions Modules/_hashlib/hashlib_fetch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Interface for fetching a message digest from a digest-like identifier.
*
* The following table summaries the possible algorthms:
*
* +----------+--------------+--------------+---------------------------------+
* | Family | Algorithm | Python Name | Notes |
* +==========+==============+==============+=================================+
* | MD @ |
* | +--------------+--------------+---------------------------------+
* | | MD5 | "md5" | |
* +----------+--------------+--------------+---------------------------------+
* | SHA1 @ |
* | +--------------+--------------+---------------------------------+
* | | SHA1-160 | "sha1" | |
* +----------+--------------+--------------+---------------------------------+
* | SHA2 @ |
* | +--------------+--------------+---------------------------------+
* | | SHA2-224 | "sha224" | |
* | | SHA2-256 | "sha256" | |
* | | SHA2-384 | "sha384" | |
* | | SHA2-512 | "sha512" | |
* +----------+--------------+--------------+---------------------------------+
* | SHA2t @ Truncated SHA2-512 |
* | +--------------+--------------+---------------------------------+
* | | SHA2-512/224 | "sha512_224" | |
* | | SHA2-512/256 | "sha512_256" | |
* +----------+--------------+--------------+---------------------------------+
* | SHA3 @ |
* | +--------------+--------------+---------------------------------+
* | | SHA3-224 | "sha3_224" | |
* | | SHA3-256 | "sha3_256" | |
* | | SHA3-384 | "sha3_384" | |
* | | SHA3-512 | "sha3_512" | |
* +----------+--------------+--------------+---------------------------------+
* | SHA3-XOF @ Extensible Output Functions |
* | +--------------+--------------+---------------------------------+
* | | SHAKE-128 | "shake_128" | |
* | | SHAKE-256 | "shake_256" | |
* +----------+--------------+--------------+---------------------------------+
* | BLAKE2 @ |
* | +--------------+--------------+---------------------------------+
* | | BLAKE2b | "blake2b" | |
* | | BLAKE2s | "blake2s" | |
* +----------+--------------+--------------+---------------------------------+
*/

#ifndef _HASHLIB_HASHLIB_FETCH_H
#define _HASHLIB_HASHLIB_FETCH_H

#include "Python.h"

/*
* Internal error messages used for reporting an unsupported hash algorithm.
* The algorithm can be given by its name, a callable or a PEP-247 module.
* The same message is raised by Lib/hashlib.py::__get_builtin_constructor()
* and _hmacmodule.c::find_hash_info().
*/
#define _Py_HASHLIB_UNSUPPORTED_ALGORITHM "unsupported hash algorithm %S"
#define _Py_HASHLIB_UNSUPPORTED_STR_ALGORITHM "unsupported hash algorithm %s"

#endif // !_HASHLIB_HASHLIB_FETCH_H
90 changes: 8 additions & 82 deletions Modules/hashlib.h → Modules/_hashlib/hashlib_mutex.h
Original file line number Diff line number Diff line change
@@ -1,45 +1,14 @@
/* Common code for use by all hashlib related modules. */
#ifndef _HASHLIB_HASHLIB_MUTEX_H
#define _HASHLIB_HASHLIB_MUTEX_H

#include "pycore_lock.h" // PyMutex
#include "Python.h"
#include "pycore_lock.h" // PyMutex

/*
* Internal error messages used for reporting an unsupported hash algorithm.
* The algorithm can be given by its name, a callable or a PEP-247 module.
* The same message is raised by Lib/hashlib.py::__get_builtin_constructor()
* and _hmacmodule.c::find_hash_info().
*/
#define HASHLIB_UNSUPPORTED_ALGORITHM "unsupported hash algorithm %S"
#define HASHLIB_UNSUPPORTED_STR_ALGORITHM "unsupported hash algorithm %s"

/*
* Given a PyObject* obj, fill in the Py_buffer* viewp with the result
* of PyObject_GetBuffer. Sets an exception and issues the erraction
* on any errors, e.g. 'return NULL' or 'goto error'.
* Message length above which the GIL is to be released
* when performing hashing operations.
*/
#define GET_BUFFER_VIEW_OR_ERROR(obj, viewp, erraction) do { \
if (PyUnicode_Check((obj))) { \
PyErr_SetString(PyExc_TypeError, \
"Strings must be encoded before hashing");\
erraction; \
} \
if (!PyObject_CheckBuffer((obj))) { \
PyErr_SetString(PyExc_TypeError, \
"object supporting the buffer API required"); \
erraction; \
} \
if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \
erraction; \
} \
if ((viewp)->ndim > 1) { \
PyErr_SetString(PyExc_BufferError, \
"Buffer must be single dimension"); \
PyBuffer_Release((viewp)); \
erraction; \
} \
} while(0)

#define GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) \
GET_BUFFER_VIEW_OR_ERROR(obj, viewp, return NULL)
#define HASHLIB_GIL_MINSIZE 2048

/*
* Helper code to synchronize access to the hash object when the GIL is
Expand All @@ -64,12 +33,6 @@
#define HASHLIB_ACQUIRE_LOCK(OBJ) PyMutex_Lock(&(OBJ)->mutex)
#define HASHLIB_RELEASE_LOCK(OBJ) PyMutex_Unlock(&(OBJ)->mutex)

/*
* Message length above which the GIL is to be released
* when performing hashing operations.
*/
#define HASHLIB_GIL_MINSIZE 2048

// Macros for executing code while conditionally holding the GIL.
//
// These only drop the GIL if the lock acquisition itself is likely to
Expand Down Expand Up @@ -116,41 +79,4 @@
} \
} while (0)

static inline int
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)
{
if (data != NULL && string == NULL) {
// called as H(data) or H(data=...)
*res = data;
return 1;
}
else if (data == NULL && string != NULL) {
// called as H(string=...)
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"the 'string' keyword parameter is deprecated since "
"Python 3.15 and slated for removal in Python 3.19; "
"use the 'data' keyword parameter or pass the data "
"to hash as a positional argument instead", 1) < 0)
{
*res = NULL;
return -1;
}
*res = string;
return 1;
}
else if (data == NULL && string == NULL) {
// fast path when no data is given
assert(!PyErr_Occurred());
*res = NULL;
return 0;
}
else {
// called as H(data=..., string)
*res = NULL;
PyErr_SetString(PyExc_TypeError,
"'data' and 'string' are mutually exclusive "
"and support for 'string' keyword parameter "
"is slated for removal in a future version.");
return -1;
}
}
#endif // !_HASHLIB_HASHLIB_MUTEX_H
15 changes: 9 additions & 6 deletions Modules/_hashopenssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@

#include "Python.h"
#include "pycore_hashtable.h"
#include "pycore_strhex.h" // _Py_strhex()
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED
#include "hashlib.h"
#include "pycore_strhex.h" // _Py_strhex()
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED

#include "_hashlib/hashlib_buffer.h"
#include "_hashlib/hashlib_fetch.h"
#include "_hashlib/hashlib_mutex.h"

/* EVP is the preferred interface to hashing in OpenSSL */
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/crypto.h> // FIPS_mode()
#include <openssl/crypto.h> // FIPS_mode()
/* We use the object interface to discover what hashes OpenSSL supports. */
#include <openssl/objects.h>
#include <openssl/err.h>
Expand Down Expand Up @@ -532,7 +535,7 @@ raise_unsupported_algorithm_error(_hashlibstate *state, PyObject *digestmod)
{
raise_unsupported_algorithm_impl(
state->unsupported_digestmod_error,
HASHLIB_UNSUPPORTED_ALGORITHM,
_Py_HASHLIB_UNSUPPORTED_ALGORITHM,
digestmod
);
}
Expand All @@ -542,7 +545,7 @@ raise_unsupported_str_algorithm_error(_hashlibstate *state, const char *name)
{
raise_unsupported_algorithm_impl(
state->unsupported_digestmod_error,
HASHLIB_UNSUPPORTED_STR_ALGORITHM,
_Py_HASHLIB_UNSUPPORTED_STR_ALGORITHM,
name
);
}
Expand Down
Loading
Loading