An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
commit | author | age
f63228 1
CS 2 # HG changeset patch
3 # User Benjamin Peterson <benjamin@python.org>
4 # Date 1409233289 14400
5 # Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5
6 # Parent  97081a80f487841d81aeed55d398a1dba1faca00
7 PEP 466: backport hashlib algorithm constants (closes #21307)
8
9 diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst
10 --- a/Doc/library/hashlib.rst
11 +++ b/Doc/library/hashlib.rst
12 @@ -88,6 +88,24 @@ This module provides the following const
13  
14     .. versionadded:: 2.7
15  
16 +.. data:: algorithms_guaranteed
17 +
18 +   A set containing the names of the hash algorithms guaranteed to be supported
19 +   by this module on all platforms.
20 +
21 +   .. versionadded:: 2.7.9
22 +
23 +.. data:: algorithms_available
24 +
25 +   A set containing the names of the hash algorithms that are available in the
26 +   running Python interpreter.  These names will be recognized when passed to
27 +   :func:`new`.  :attr:`algorithms_guaranteed` will always be a subset.  The
28 +   same algorithm may appear multiple times in this set under different names
29 +   (thanks to OpenSSL).
30 +
31 +   .. versionadded:: 2.7.9
32 +
33 +
34  The following values are provided as constant attributes of the hash objects
35  returned by the constructors:
36  
37 diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py
38 --- Python-2.7.5/Lib/hashlib.py.hash    2015-03-04 17:05:57.496598686 +0100
39 +++ Python-2.7.5/Lib/hashlib.py    2015-03-04 17:11:34.872739103 +0100
40 @@ -18,8 +18,9 @@ than using new():
41  
42  md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
43  
44 -More algorithms may be available on your platform but the above are
45 -guaranteed to exist.
46 +More algorithms may be available on your platform but the above are guaranteed
47 +to exist.  See the algorithms_guaranteed and algorithms_available attributes
48 +to find out what algorithm names can be passed to new().
49  
50  NOTE: If you want the adler32 or crc32 hash functions they are available in
51  the zlib module.
52 @@ -75,9 +76,14 @@ More condensed:
53  # always available algorithm is added.
54  __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
55  
56 +algorithms_guaranteed = set(__always_supported)
57 +algorithms_available = set(__always_supported)
58 +
59  algorithms = __always_supported
60  
61 -__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac')
62 +__all__ = __always_supported + ('new', 'algorithms_guaranteed',
63 +                                'algorithms_available', 'algorithms',
64 +                                'pbkdf2_hmac')
65  
66  
67  def __get_openssl_constructor(name):
68 @@ -110,6 +116,8 @@ try:
69      import _hashlib
70      new = __hash_new
71      __get_hash = __get_openssl_constructor
72 +    algorithms_available = algorithms_available.union(
73 +        _hashlib.openssl_md_meth_names)
74  except ImportError:
75      # We don't build the legacy modules
76      raise
77 diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c
78 --- Python-2.7.5/Modules/_hashopenssl.c.hash    2015-03-04 17:06:18.246791837 +0100
79 +++ Python-2.7.5/Modules/_hashopenssl.c    2015-03-04 17:16:17.696369000 +0100
80 @@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar
81  
82  #endif
83  
84 +/* State for our callback function so that it can accumulate a result. */
85 +typedef struct _internal_name_mapper_state {
86 +    PyObject *set;
87 +    int error;
88 +} _InternalNameMapperState;
89 +
90 +
91 +/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
92 +static void
93 +_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg)
94 +{
95 +    _InternalNameMapperState *state = (_InternalNameMapperState *)arg;
96 +    PyObject *py_name;
97 +
98 +    assert(state != NULL);
99 +    if (openssl_obj_name == NULL)
100 +        return;
101 +    /* Ignore aliased names, they pollute the list and OpenSSL appears to
102 +     * have a its own definition of alias as the resulting list still
103 +     * contains duplicate and alternate names for several algorithms.     */
104 +    if (openssl_obj_name->alias)
105 +        return;
106 +
107 +    py_name = PyString_FromString(openssl_obj_name->name);
108 +    if (py_name == NULL) {
109 +        state->error = 1;
110 +    } else {
111 +        if (PySet_Add(state->set, py_name) != 0) {
112 +            state->error = 1;
113 +        }
114 +        Py_DECREF(py_name);
115 +    }
116 +}
117 +
118 +
119 +/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */
120 +static PyObject*
121 +generate_hash_name_list(void)
122 +{
123 +    _InternalNameMapperState state;
124 +    state.set = PyFrozenSet_New(NULL);
125 +    if (state.set == NULL)
126 +        return NULL;
127 +    state.error = 0;
128 +
129 +    OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state);
130 +
131 +    if (state.error) {
132 +        Py_DECREF(state.set);
133 +        return NULL;
134 +    }
135 +    return state.set;
136 +}
137 +
138 +
139  /*
140   *  This macro and function generates a family of constructor function
141   *  definitions for specific hash algorithms.  These constructors are much
142 @@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[
143  PyMODINIT_FUNC
144  init_hashlib(void)
145  {
146 -    PyObject *m;
147 +    PyObject *m, *openssl_md_meth_names;
148  
149      SSL_load_error_strings();
150      SSL_library_init();
151 -    OpenSSL_add_all_digests();
152 +    ERR_load_crypto_strings();
153  
154      Py_TYPE(&EVPtype) = &PyType_Type;
155      if (PyType_Ready(&EVPtype) < 0)
156 @@ -938,6 +993,14 @@ init_hashlib(void)
157      if (m == NULL)
158          return;
159  
160 +    openssl_md_meth_names = generate_hash_name_list();
161 +    if (openssl_md_meth_names == NULL) {
162 +        return;
163 +    }
164 +    if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) {
165 +        return;
166 +    }
167 +
168  #if HASH_OBJ_CONSTRUCTOR
169      Py_INCREF(&EVPtype);
170      PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
171 diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py
172 --- Python-2.7.5/Lib/test/test_hashlib.py.hash    2015-03-04 18:04:57.823553474 +0100
173 +++ Python-2.7.5/Lib/test/test_hashlib.py    2015-03-04 18:06:39.395499123 +0100
174 @@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase)
175              tuple([_algo for _algo in self.supported_hash_names if
176                                                  _algo.islower()]))
177  
178 +    def test_algorithms_guaranteed(self):
179 +        self.assertEqual(hashlib.algorithms_guaranteed,
180 +            set(_algo for _algo in self.supported_hash_names
181 +                  if _algo.islower()))
182 +
183 +    def test_algorithms_available(self):
184 +        self.assertTrue(set(hashlib.algorithms_guaranteed).
185 +                            issubset(hashlib.algorithms_available))
186 +
187      def test_unknown_hash(self):
188          self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
189          self.assertRaises(TypeError, hashlib.new, 1)