Branch data Line data Source code
1 : : /* MD5 module */
2 : :
3 : : /* This module provides an interface to the MD5 algorithm */
4 : :
5 : : /* See below for information about the original code this module was
6 : : based upon. Additional work performed by:
7 : :
8 : : Andrew Kuchling (amk@amk.ca)
9 : : Greg Stein (gstein@lyra.org)
10 : : Trevor Perrin (trevp@trevp.net)
11 : :
12 : : Copyright (C) 2005-2007 Gregory P. Smith (greg@krypto.org)
13 : : Licensed to PSF under a Contributor Agreement.
14 : :
15 : : */
16 : :
17 : : /* MD5 objects */
18 : : #ifndef Py_BUILD_CORE_BUILTIN
19 : : # define Py_BUILD_CORE_MODULE 1
20 : : #endif
21 : :
22 : : #include "Python.h"
23 : : #include "hashlib.h"
24 : : #include "pycore_strhex.h" // _Py_strhex()
25 : : #include "pycore_typeobject.h" // _PyType_GetModuleState()
26 : :
27 : : /*[clinic input]
28 : : module _md5
29 : : class MD5Type "MD5object *" "&PyType_Type"
30 : : [clinic start generated code]*/
31 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=6e5261719957a912]*/
32 : :
33 : : /* Some useful types */
34 : :
35 : : #if SIZEOF_INT == 4
36 : : typedef unsigned int MD5_INT32; /* 32-bit integer */
37 : : typedef long long MD5_INT64; /* 64-bit integer */
38 : : #else
39 : : /* not defined. compilation will die. */
40 : : #endif
41 : :
42 : : /* The MD5 block size and message digest sizes, in bytes */
43 : :
44 : : #define MD5_BLOCKSIZE 64
45 : : #define MD5_DIGESTSIZE 16
46 : :
47 : : #include "_hacl/Hacl_Hash_MD5.h"
48 : :
49 : :
50 : : typedef struct {
51 : : PyObject_HEAD
52 : :
53 : : Hacl_Streaming_MD5_state *hash_state;
54 : : } MD5object;
55 : :
56 : : #include "clinic/md5module.c.h"
57 : :
58 : :
59 : : typedef struct {
60 : : PyTypeObject* md5_type;
61 : : } MD5State;
62 : :
63 : : static inline MD5State*
64 : 11 : md5_get_state(PyObject *module)
65 : : {
66 : 11 : void *state = PyModule_GetState(module);
67 : : assert(state != NULL);
68 : 11 : return (MD5State *)state;
69 : : }
70 : :
71 : : static MD5object *
72 : 0 : newMD5object(MD5State * st)
73 : : {
74 : 0 : MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type);
75 : 0 : PyObject_GC_Track(md5);
76 : 0 : return md5;
77 : : }
78 : :
79 : : /* Internal methods for a hash object */
80 : : static int
81 : 0 : MD5_traverse(PyObject *ptr, visitproc visit, void *arg)
82 : : {
83 [ # # # # ]: 0 : Py_VISIT(Py_TYPE(ptr));
84 : 0 : return 0;
85 : : }
86 : :
87 : : static void
88 : 0 : MD5_dealloc(MD5object *ptr)
89 : : {
90 : 0 : Hacl_Streaming_MD5_legacy_free(ptr->hash_state);
91 : 0 : PyTypeObject *tp = Py_TYPE(ptr);
92 : 0 : PyObject_GC_UnTrack(ptr);
93 : 0 : PyObject_GC_Del(ptr);
94 : 0 : Py_DECREF(tp);
95 : 0 : }
96 : :
97 : :
98 : : /* External methods for a hash object */
99 : :
100 : : /*[clinic input]
101 : : MD5Type.copy
102 : :
103 : : cls: defining_class
104 : :
105 : : Return a copy of the hash object.
106 : : [clinic start generated code]*/
107 : :
108 : : static PyObject *
109 : 0 : MD5Type_copy_impl(MD5object *self, PyTypeObject *cls)
110 : : /*[clinic end generated code: output=bf055e08244bf5ee input=d89087dcfb2a8620]*/
111 : : {
112 : 0 : MD5State *st = _PyType_GetModuleState(cls);
113 : :
114 : : MD5object *newobj;
115 [ # # ]: 0 : if ((newobj = newMD5object(st))==NULL)
116 : 0 : return NULL;
117 : :
118 : 0 : newobj->hash_state = Hacl_Streaming_MD5_legacy_copy(self->hash_state);
119 : 0 : return (PyObject *)newobj;
120 : : }
121 : :
122 : : /*[clinic input]
123 : : MD5Type.digest
124 : :
125 : : Return the digest value as a bytes object.
126 : : [clinic start generated code]*/
127 : :
128 : : static PyObject *
129 : 0 : MD5Type_digest_impl(MD5object *self)
130 : : /*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/
131 : : {
132 : : unsigned char digest[MD5_DIGESTSIZE];
133 : 0 : Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest);
134 : 0 : return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE);
135 : : }
136 : :
137 : : /*[clinic input]
138 : : MD5Type.hexdigest
139 : :
140 : : Return the digest value as a string of hexadecimal digits.
141 : : [clinic start generated code]*/
142 : :
143 : : static PyObject *
144 : 0 : MD5Type_hexdigest_impl(MD5object *self)
145 : : /*[clinic end generated code: output=17badced1f3ac932 input=b60b19de644798dd]*/
146 : : {
147 : : unsigned char digest[MD5_DIGESTSIZE];
148 : 0 : Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest);
149 : 0 : return _Py_strhex((const char*)digest, MD5_DIGESTSIZE);
150 : : }
151 : :
152 : 0 : static void update(Hacl_Streaming_MD5_state *state, uint8_t *buf, Py_ssize_t len) {
153 : : #if PY_SSIZE_T_MAX > UINT32_MAX
154 [ # # ]: 0 : while (len > UINT32_MAX) {
155 : 0 : Hacl_Streaming_MD5_legacy_update(state, buf, UINT32_MAX);
156 : 0 : len -= UINT32_MAX;
157 : 0 : buf += UINT32_MAX;
158 : : }
159 : : #endif
160 : 0 : Hacl_Streaming_MD5_legacy_update(state, buf, (uint32_t) len);
161 : 0 : }
162 : :
163 : : /*[clinic input]
164 : : MD5Type.update
165 : :
166 : : obj: object
167 : : /
168 : :
169 : : Update this hash object's state with the provided string.
170 : : [clinic start generated code]*/
171 : :
172 : : static PyObject *
173 : 0 : MD5Type_update(MD5object *self, PyObject *obj)
174 : : /*[clinic end generated code: output=f6ad168416338423 input=6e1efcd9ecf17032]*/
175 : : {
176 : : Py_buffer buf;
177 : :
178 [ # # # # : 0 : GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
# # # # ]
179 : :
180 : 0 : update(self->hash_state, buf.buf, buf.len);
181 : :
182 : 0 : PyBuffer_Release(&buf);
183 : 0 : Py_RETURN_NONE;
184 : : }
185 : :
186 : : static PyMethodDef MD5_methods[] = {
187 : : MD5TYPE_COPY_METHODDEF
188 : : MD5TYPE_DIGEST_METHODDEF
189 : : MD5TYPE_HEXDIGEST_METHODDEF
190 : : MD5TYPE_UPDATE_METHODDEF
191 : : {NULL, NULL} /* sentinel */
192 : : };
193 : :
194 : : static PyObject *
195 : 0 : MD5_get_block_size(PyObject *self, void *closure)
196 : : {
197 : 0 : return PyLong_FromLong(MD5_BLOCKSIZE);
198 : : }
199 : :
200 : : static PyObject *
201 : 0 : MD5_get_name(PyObject *self, void *closure)
202 : : {
203 : 0 : return PyUnicode_FromStringAndSize("md5", 3);
204 : : }
205 : :
206 : : static PyObject *
207 : 0 : md5_get_digest_size(PyObject *self, void *closure)
208 : : {
209 : 0 : return PyLong_FromLong(MD5_DIGESTSIZE);
210 : : }
211 : :
212 : : static PyGetSetDef MD5_getseters[] = {
213 : : {"block_size",
214 : : (getter)MD5_get_block_size, NULL,
215 : : NULL,
216 : : NULL},
217 : : {"name",
218 : : (getter)MD5_get_name, NULL,
219 : : NULL,
220 : : NULL},
221 : : {"digest_size",
222 : : (getter)md5_get_digest_size, NULL,
223 : : NULL,
224 : : NULL},
225 : : {NULL} /* Sentinel */
226 : : };
227 : :
228 : : static PyType_Slot md5_type_slots[] = {
229 : : {Py_tp_dealloc, MD5_dealloc},
230 : : {Py_tp_methods, MD5_methods},
231 : : {Py_tp_getset, MD5_getseters},
232 : : {Py_tp_traverse, MD5_traverse},
233 : : {0,0}
234 : : };
235 : :
236 : : static PyType_Spec md5_type_spec = {
237 : : .name = "_md5.md5",
238 : : .basicsize = sizeof(MD5object),
239 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
240 : : Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC),
241 : : .slots = md5_type_slots
242 : : };
243 : :
244 : : /* The single module-level function: new() */
245 : :
246 : : /*[clinic input]
247 : : _md5.md5
248 : :
249 : : string: object(c_default="NULL") = b''
250 : : *
251 : : usedforsecurity: bool = True
252 : :
253 : : Return a new MD5 hash object; optionally initialized with a string.
254 : : [clinic start generated code]*/
255 : :
256 : : static PyObject *
257 : 0 : _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity)
258 : : /*[clinic end generated code: output=587071f76254a4ac input=7a144a1905636985]*/
259 : : {
260 : : MD5object *new;
261 : : Py_buffer buf;
262 : :
263 [ # # ]: 0 : if (string)
264 [ # # # # : 0 : GET_BUFFER_VIEW_OR_ERROUT(string, &buf);
# # # # ]
265 : :
266 : 0 : MD5State *st = md5_get_state(module);
267 [ # # ]: 0 : if ((new = newMD5object(st)) == NULL) {
268 [ # # ]: 0 : if (string)
269 : 0 : PyBuffer_Release(&buf);
270 : 0 : return NULL;
271 : : }
272 : :
273 : 0 : new->hash_state = Hacl_Streaming_MD5_legacy_create_in();
274 : :
275 [ # # ]: 0 : if (PyErr_Occurred()) {
276 : 0 : Py_DECREF(new);
277 [ # # ]: 0 : if (string)
278 : 0 : PyBuffer_Release(&buf);
279 : 0 : return NULL;
280 : : }
281 [ # # ]: 0 : if (string) {
282 : 0 : update(new->hash_state, buf.buf, buf.len);
283 : 0 : PyBuffer_Release(&buf);
284 : : }
285 : :
286 : 0 : return (PyObject *)new;
287 : : }
288 : :
289 : :
290 : : /* List of functions exported by this module */
291 : :
292 : : static struct PyMethodDef MD5_functions[] = {
293 : : _MD5_MD5_METHODDEF
294 : : {NULL, NULL} /* Sentinel */
295 : : };
296 : :
297 : : static int
298 : 8 : _md5_traverse(PyObject *module, visitproc visit, void *arg)
299 : : {
300 : 8 : MD5State *state = md5_get_state(module);
301 [ + - - + ]: 8 : Py_VISIT(state->md5_type);
302 : 8 : return 0;
303 : : }
304 : :
305 : : static int
306 : 2 : _md5_clear(PyObject *module)
307 : : {
308 : 2 : MD5State *state = md5_get_state(module);
309 [ + + ]: 2 : Py_CLEAR(state->md5_type);
310 : 2 : return 0;
311 : : }
312 : :
313 : : static void
314 : 1 : _md5_free(void *module)
315 : : {
316 : 1 : _md5_clear((PyObject *)module);
317 : 1 : }
318 : :
319 : : /* Initialize this module. */
320 : : static int
321 : 1 : md5_exec(PyObject *m)
322 : : {
323 : 1 : MD5State *st = md5_get_state(m);
324 : :
325 : 1 : st->md5_type = (PyTypeObject *)PyType_FromModuleAndSpec(
326 : : m, &md5_type_spec, NULL);
327 : :
328 [ - + ]: 1 : if (st->md5_type == NULL) {
329 : 0 : return -1;
330 : : }
331 : :
332 : 1 : Py_INCREF((PyObject *)st->md5_type);
333 [ - + ]: 1 : if (PyModule_AddObject(m, "MD5Type", (PyObject *)st->md5_type) < 0) {
334 : 0 : Py_DECREF(st->md5_type);
335 : 0 : return -1;
336 : : }
337 : :
338 : 1 : return 0;
339 : : }
340 : :
341 : : static PyModuleDef_Slot _md5_slots[] = {
342 : : {Py_mod_exec, md5_exec},
343 : : {0, NULL}
344 : : };
345 : :
346 : :
347 : : static struct PyModuleDef _md5module = {
348 : : PyModuleDef_HEAD_INIT,
349 : : .m_name = "_md5",
350 : : .m_size = sizeof(MD5State),
351 : : .m_methods = MD5_functions,
352 : : .m_slots = _md5_slots,
353 : : .m_traverse = _md5_traverse,
354 : : .m_clear = _md5_clear,
355 : : .m_free = _md5_free,
356 : : };
357 : :
358 : : PyMODINIT_FUNC
359 : 1 : PyInit__md5(void)
360 : : {
361 : 1 : return PyModuleDef_Init(&_md5module);
362 : : }
|