PEP 466: backport hashlib algorithm constants (closes #21307)
This commit is contained in:
parent
876473eba3
commit
0062d1e7f4
|
@ -88,6 +88,24 @@ This module provides the following constant attribute:
|
|||
|
||||
.. versionadded:: 2.7
|
||||
|
||||
.. data:: algorithms_guaranteed
|
||||
|
||||
A set containing the names of the hash algorithms guaranteed to be supported
|
||||
by this module on all platforms.
|
||||
|
||||
.. versionadded:: 2.7.9
|
||||
|
||||
.. data:: algorithms_available
|
||||
|
||||
A set containing the names of the hash algorithms that are available in the
|
||||
running Python interpreter. These names will be recognized when passed to
|
||||
:func:`new`. :attr:`algorithms_guaranteed` will always be a subset. The
|
||||
same algorithm may appear multiple times in this set under different names
|
||||
(thanks to OpenSSL).
|
||||
|
||||
.. versionadded:: 2.7.9
|
||||
|
||||
|
||||
The following values are provided as constant attributes of the hash objects
|
||||
returned by the constructors:
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ than using new():
|
|||
|
||||
md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
|
||||
|
||||
More algorithms may be available on your platform but the above are
|
||||
guaranteed to exist.
|
||||
More algorithms may be available on your platform but the above are guaranteed
|
||||
to exist. See the algorithms_guaranteed and algorithms_available attributes
|
||||
to find out what algorithm names can be passed to new().
|
||||
|
||||
NOTE: If you want the adler32 or crc32 hash functions they are available in
|
||||
the zlib module.
|
||||
|
@ -58,9 +59,14 @@ More condensed:
|
|||
# always available algorithm is added.
|
||||
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
|
||||
|
||||
algorithms_guaranteed = set(__always_supported)
|
||||
algorithms_available = set(__always_supported)
|
||||
|
||||
algorithms = __always_supported
|
||||
|
||||
__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac')
|
||||
__all__ = __always_supported + ('new', 'algorithms_guaranteed',
|
||||
'algorithms_available', 'algorithms',
|
||||
'pbkdf2_hmac')
|
||||
|
||||
|
||||
def __get_builtin_constructor(name):
|
||||
|
@ -128,6 +134,8 @@ try:
|
|||
import _hashlib
|
||||
new = __hash_new
|
||||
__get_hash = __get_openssl_constructor
|
||||
algorithms_available = algorithms_available.union(
|
||||
_hashlib.openssl_md_meth_names)
|
||||
except ImportError:
|
||||
new = __py_new
|
||||
__get_hash = __get_builtin_constructor
|
||||
|
|
|
@ -109,6 +109,15 @@ class HashLibTestCase(unittest.TestCase):
|
|||
tuple([_algo for _algo in self.supported_hash_names if
|
||||
_algo.islower()]))
|
||||
|
||||
def test_algorithms_guaranteed(self):
|
||||
self.assertEqual(hashlib.algorithms_guaranteed,
|
||||
set(_algo for _algo in self.supported_hash_names
|
||||
if _algo.islower()))
|
||||
|
||||
def test_algorithms_available(self):
|
||||
self.assertTrue(set(hashlib.algorithms_guaranteed).
|
||||
issubset(hashlib.algorithms_available))
|
||||
|
||||
def test_unknown_hash(self):
|
||||
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
|
||||
self.assertRaises(TypeError, hashlib.new, 1)
|
||||
|
|
|
@ -19,6 +19,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #21307: As part of PEP 466, backport hashlib.algorithms_guaranteed and
|
||||
hashlib.algorithms_available.
|
||||
|
||||
- Issue #22259: Fix segfault when attempting to fopen a file descriptor
|
||||
corresponding to a directory.
|
||||
|
||||
|
|
|
@ -712,6 +712,61 @@ pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)
|
|||
|
||||
#endif
|
||||
|
||||
/* State for our callback function so that it can accumulate a result. */
|
||||
typedef struct _internal_name_mapper_state {
|
||||
PyObject *set;
|
||||
int error;
|
||||
} _InternalNameMapperState;
|
||||
|
||||
|
||||
/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
|
||||
static void
|
||||
_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg)
|
||||
{
|
||||
_InternalNameMapperState *state = (_InternalNameMapperState *)arg;
|
||||
PyObject *py_name;
|
||||
|
||||
assert(state != NULL);
|
||||
if (openssl_obj_name == NULL)
|
||||
return;
|
||||
/* Ignore aliased names, they pollute the list and OpenSSL appears to
|
||||
* have a its own definition of alias as the resulting list still
|
||||
* contains duplicate and alternate names for several algorithms. */
|
||||
if (openssl_obj_name->alias)
|
||||
return;
|
||||
|
||||
py_name = PyString_FromString(openssl_obj_name->name);
|
||||
if (py_name == NULL) {
|
||||
state->error = 1;
|
||||
} else {
|
||||
if (PySet_Add(state->set, py_name) != 0) {
|
||||
state->error = 1;
|
||||
}
|
||||
Py_DECREF(py_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */
|
||||
static PyObject*
|
||||
generate_hash_name_list(void)
|
||||
{
|
||||
_InternalNameMapperState state;
|
||||
state.set = PyFrozenSet_New(NULL);
|
||||
if (state.set == NULL)
|
||||
return NULL;
|
||||
state.error = 0;
|
||||
|
||||
OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state);
|
||||
|
||||
if (state.error) {
|
||||
Py_DECREF(state.set);
|
||||
return NULL;
|
||||
}
|
||||
return state.set;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This macro generates constructor function definitions for specific
|
||||
* hash algorithms. These constructors are much faster than calling
|
||||
|
@ -792,9 +847,10 @@ static struct PyMethodDef EVP_functions[] = {
|
|||
PyMODINIT_FUNC
|
||||
init_hashlib(void)
|
||||
{
|
||||
PyObject *m;
|
||||
PyObject *m, *openssl_md_meth_names;
|
||||
|
||||
OpenSSL_add_all_digests();
|
||||
ERR_load_crypto_strings();
|
||||
|
||||
/* TODO build EVP_functions openssl_* entries dynamically based
|
||||
* on what hashes are supported rather than listing many
|
||||
|
@ -809,6 +865,14 @@ init_hashlib(void)
|
|||
if (m == NULL)
|
||||
return;
|
||||
|
||||
openssl_md_meth_names = generate_hash_name_list();
|
||||
if (openssl_md_meth_names == NULL) {
|
||||
return;
|
||||
}
|
||||
if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if HASH_OBJ_CONSTRUCTOR
|
||||
Py_INCREF(&EVPtype);
|
||||
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
|
||||
|
|
Loading…
Reference in New Issue