|
|
f63228 |
|
|
|
f63228 |
# HG changeset patch
|
|
|
f63228 |
# User Benjamin Peterson <benjamin@python.org>
|
|
|
f63228 |
# Date 1409233289 14400
|
|
|
f63228 |
# Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5
|
|
|
f63228 |
# Parent 97081a80f487841d81aeed55d398a1dba1faca00
|
|
|
f63228 |
PEP 466: backport hashlib algorithm constants (closes #21307)
|
|
|
f63228 |
|
|
|
f63228 |
diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst
|
|
|
f63228 |
--- a/Doc/library/hashlib.rst
|
|
|
f63228 |
+++ b/Doc/library/hashlib.rst
|
|
|
f63228 |
@@ -88,6 +88,24 @@ This module provides the following const
|
|
|
f63228 |
|
|
|
f63228 |
.. versionadded:: 2.7
|
|
|
f63228 |
|
|
|
f63228 |
+.. data:: algorithms_guaranteed
|
|
|
f63228 |
+
|
|
|
f63228 |
+ A set containing the names of the hash algorithms guaranteed to be supported
|
|
|
f63228 |
+ by this module on all platforms.
|
|
|
f63228 |
+
|
|
|
f63228 |
+ .. versionadded:: 2.7.9
|
|
|
f63228 |
+
|
|
|
f63228 |
+.. data:: algorithms_available
|
|
|
f63228 |
+
|
|
|
f63228 |
+ A set containing the names of the hash algorithms that are available in the
|
|
|
f63228 |
+ running Python interpreter. These names will be recognized when passed to
|
|
|
f63228 |
+ :func:`new`. :attr:`algorithms_guaranteed` will always be a subset. The
|
|
|
f63228 |
+ same algorithm may appear multiple times in this set under different names
|
|
|
f63228 |
+ (thanks to OpenSSL).
|
|
|
f63228 |
+
|
|
|
f63228 |
+ .. versionadded:: 2.7.9
|
|
|
f63228 |
+
|
|
|
f63228 |
+
|
|
|
f63228 |
The following values are provided as constant attributes of the hash objects
|
|
|
f63228 |
returned by the constructors:
|
|
|
f63228 |
|
|
|
f63228 |
diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py
|
|
|
f63228 |
--- Python-2.7.5/Lib/hashlib.py.hash 2015-03-04 17:05:57.496598686 +0100
|
|
|
f63228 |
+++ Python-2.7.5/Lib/hashlib.py 2015-03-04 17:11:34.872739103 +0100
|
|
|
f63228 |
@@ -18,8 +18,9 @@ than using new():
|
|
|
f63228 |
|
|
|
f63228 |
md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
|
|
|
f63228 |
|
|
|
f63228 |
-More algorithms may be available on your platform but the above are
|
|
|
f63228 |
-guaranteed to exist.
|
|
|
f63228 |
+More algorithms may be available on your platform but the above are guaranteed
|
|
|
f63228 |
+to exist. See the algorithms_guaranteed and algorithms_available attributes
|
|
|
f63228 |
+to find out what algorithm names can be passed to new().
|
|
|
f63228 |
|
|
|
f63228 |
NOTE: If you want the adler32 or crc32 hash functions they are available in
|
|
|
f63228 |
the zlib module.
|
|
|
f63228 |
@@ -75,9 +76,14 @@ More condensed:
|
|
|
f63228 |
# always available algorithm is added.
|
|
|
f63228 |
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
|
|
|
f63228 |
|
|
|
f63228 |
+algorithms_guaranteed = set(__always_supported)
|
|
|
f63228 |
+algorithms_available = set(__always_supported)
|
|
|
f63228 |
+
|
|
|
f63228 |
algorithms = __always_supported
|
|
|
f63228 |
|
|
|
f63228 |
-__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac')
|
|
|
f63228 |
+__all__ = __always_supported + ('new', 'algorithms_guaranteed',
|
|
|
f63228 |
+ 'algorithms_available', 'algorithms',
|
|
|
f63228 |
+ 'pbkdf2_hmac')
|
|
|
f63228 |
|
|
|
f63228 |
|
|
|
f63228 |
def __get_openssl_constructor(name):
|
|
|
f63228 |
@@ -110,6 +116,8 @@ try:
|
|
|
f63228 |
import _hashlib
|
|
|
f63228 |
new = __hash_new
|
|
|
f63228 |
__get_hash = __get_openssl_constructor
|
|
|
f63228 |
+ algorithms_available = algorithms_available.union(
|
|
|
f63228 |
+ _hashlib.openssl_md_meth_names)
|
|
|
f63228 |
except ImportError:
|
|
|
f63228 |
# We don't build the legacy modules
|
|
|
f63228 |
raise
|
|
|
f63228 |
diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c
|
|
|
f63228 |
--- Python-2.7.5/Modules/_hashopenssl.c.hash 2015-03-04 17:06:18.246791837 +0100
|
|
|
f63228 |
+++ Python-2.7.5/Modules/_hashopenssl.c 2015-03-04 17:16:17.696369000 +0100
|
|
|
f63228 |
@@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar
|
|
|
f63228 |
|
|
|
f63228 |
#endif
|
|
|
f63228 |
|
|
|
f63228 |
+/* State for our callback function so that it can accumulate a result. */
|
|
|
f63228 |
+typedef struct _internal_name_mapper_state {
|
|
|
f63228 |
+ PyObject *set;
|
|
|
f63228 |
+ int error;
|
|
|
f63228 |
+} _InternalNameMapperState;
|
|
|
f63228 |
+
|
|
|
f63228 |
+
|
|
|
f63228 |
+/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
|
|
|
f63228 |
+static void
|
|
|
f63228 |
+_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg)
|
|
|
f63228 |
+{
|
|
|
f63228 |
+ _InternalNameMapperState *state = (_InternalNameMapperState *)arg;
|
|
|
f63228 |
+ PyObject *py_name;
|
|
|
f63228 |
+
|
|
|
f63228 |
+ assert(state != NULL);
|
|
|
f63228 |
+ if (openssl_obj_name == NULL)
|
|
|
f63228 |
+ return;
|
|
|
f63228 |
+ /* Ignore aliased names, they pollute the list and OpenSSL appears to
|
|
|
f63228 |
+ * have a its own definition of alias as the resulting list still
|
|
|
f63228 |
+ * contains duplicate and alternate names for several algorithms. */
|
|
|
f63228 |
+ if (openssl_obj_name->alias)
|
|
|
f63228 |
+ return;
|
|
|
f63228 |
+
|
|
|
f63228 |
+ py_name = PyString_FromString(openssl_obj_name->name);
|
|
|
f63228 |
+ if (py_name == NULL) {
|
|
|
f63228 |
+ state->error = 1;
|
|
|
f63228 |
+ } else {
|
|
|
f63228 |
+ if (PySet_Add(state->set, py_name) != 0) {
|
|
|
f63228 |
+ state->error = 1;
|
|
|
f63228 |
+ }
|
|
|
f63228 |
+ Py_DECREF(py_name);
|
|
|
f63228 |
+ }
|
|
|
f63228 |
+}
|
|
|
f63228 |
+
|
|
|
f63228 |
+
|
|
|
f63228 |
+/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */
|
|
|
f63228 |
+static PyObject*
|
|
|
f63228 |
+generate_hash_name_list(void)
|
|
|
f63228 |
+{
|
|
|
f63228 |
+ _InternalNameMapperState state;
|
|
|
f63228 |
+ state.set = PyFrozenSet_New(NULL);
|
|
|
f63228 |
+ if (state.set == NULL)
|
|
|
f63228 |
+ return NULL;
|
|
|
f63228 |
+ state.error = 0;
|
|
|
f63228 |
+
|
|
|
f63228 |
+ OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state);
|
|
|
f63228 |
+
|
|
|
f63228 |
+ if (state.error) {
|
|
|
f63228 |
+ Py_DECREF(state.set);
|
|
|
f63228 |
+ return NULL;
|
|
|
f63228 |
+ }
|
|
|
f63228 |
+ return state.set;
|
|
|
f63228 |
+}
|
|
|
f63228 |
+
|
|
|
f63228 |
+
|
|
|
f63228 |
/*
|
|
|
f63228 |
* This macro and function generates a family of constructor function
|
|
|
f63228 |
* definitions for specific hash algorithms. These constructors are much
|
|
|
f63228 |
@@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[
|
|
|
f63228 |
PyMODINIT_FUNC
|
|
|
f63228 |
init_hashlib(void)
|
|
|
f63228 |
{
|
|
|
f63228 |
- PyObject *m;
|
|
|
f63228 |
+ PyObject *m, *openssl_md_meth_names;
|
|
|
f63228 |
|
|
|
f63228 |
SSL_load_error_strings();
|
|
|
f63228 |
SSL_library_init();
|
|
|
f63228 |
- OpenSSL_add_all_digests();
|
|
|
f63228 |
+ ERR_load_crypto_strings();
|
|
|
f63228 |
|
|
|
f63228 |
Py_TYPE(&EVPtype) = &PyType_Type;
|
|
|
f63228 |
if (PyType_Ready(&EVPtype) < 0)
|
|
|
f63228 |
@@ -938,6 +993,14 @@ init_hashlib(void)
|
|
|
f63228 |
if (m == NULL)
|
|
|
f63228 |
return;
|
|
|
f63228 |
|
|
|
f63228 |
+ openssl_md_meth_names = generate_hash_name_list();
|
|
|
f63228 |
+ if (openssl_md_meth_names == NULL) {
|
|
|
f63228 |
+ return;
|
|
|
f63228 |
+ }
|
|
|
f63228 |
+ if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) {
|
|
|
f63228 |
+ return;
|
|
|
f63228 |
+ }
|
|
|
f63228 |
+
|
|
|
f63228 |
#if HASH_OBJ_CONSTRUCTOR
|
|
|
f63228 |
Py_INCREF(&EVPtype);
|
|
|
f63228 |
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
|
|
|
f63228 |
diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py
|
|
|
f63228 |
--- Python-2.7.5/Lib/test/test_hashlib.py.hash 2015-03-04 18:04:57.823553474 +0100
|
|
|
f63228 |
+++ Python-2.7.5/Lib/test/test_hashlib.py 2015-03-04 18:06:39.395499123 +0100
|
|
|
f63228 |
@@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase)
|
|
|
f63228 |
tuple([_algo for _algo in self.supported_hash_names if
|
|
|
f63228 |
_algo.islower()]))
|
|
|
f63228 |
|
|
|
f63228 |
+ def test_algorithms_guaranteed(self):
|
|
|
f63228 |
+ self.assertEqual(hashlib.algorithms_guaranteed,
|
|
|
f63228 |
+ set(_algo for _algo in self.supported_hash_names
|
|
|
f63228 |
+ if _algo.islower()))
|
|
|
f63228 |
+
|
|
|
f63228 |
+ def test_algorithms_available(self):
|
|
|
f63228 |
+ self.assertTrue(set(hashlib.algorithms_guaranteed).
|
|
|
f63228 |
+ issubset(hashlib.algorithms_available))
|
|
|
f63228 |
+
|
|
|
f63228 |
def test_unknown_hash(self):
|
|
|
f63228 |
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
|
|
|
f63228 |
self.assertRaises(TypeError, hashlib.new, 1)
|