|
1 |
|
2 /* MD5 module */ |
|
3 |
|
4 /* This module provides an interface to the RSA Data Security, |
|
5 Inc. MD5 Message-Digest Algorithm, described in RFC 1321. |
|
6 It requires the files md5c.c and md5.h (which are slightly changed |
|
7 from the versions in the RFC to avoid the "global.h" file.) */ |
|
8 |
|
9 |
|
10 /* MD5 objects */ |
|
11 |
|
12 #include "Python.h" |
|
13 #include "structmember.h" |
|
14 #include "md5.h" |
|
15 |
|
16 typedef struct { |
|
17 PyObject_HEAD |
|
18 md5_state_t md5; /* the context holder */ |
|
19 } md5object; |
|
20 |
|
21 static PyTypeObject MD5type; |
|
22 |
|
23 #define is_md5object(v) ((v)->ob_type == &MD5type) |
|
24 |
|
25 static md5object * |
|
26 newmd5object(void) |
|
27 { |
|
28 md5object *md5p; |
|
29 |
|
30 md5p = PyObject_New(md5object, &MD5type); |
|
31 if (md5p == NULL) |
|
32 return NULL; |
|
33 |
|
34 md5_init(&md5p->md5); /* actual initialisation */ |
|
35 return md5p; |
|
36 } |
|
37 |
|
38 |
|
39 /* MD5 methods */ |
|
40 |
|
41 static void |
|
42 md5_dealloc(md5object *md5p) |
|
43 { |
|
44 PyObject_Del(md5p); |
|
45 } |
|
46 |
|
47 |
|
48 /* MD5 methods-as-attributes */ |
|
49 |
|
50 static PyObject * |
|
51 md5_update(md5object *self, PyObject *args) |
|
52 { |
|
53 unsigned char *cp; |
|
54 int len; |
|
55 |
|
56 if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) |
|
57 return NULL; |
|
58 |
|
59 md5_append(&self->md5, cp, len); |
|
60 |
|
61 Py_INCREF(Py_None); |
|
62 return Py_None; |
|
63 } |
|
64 |
|
65 PyDoc_STRVAR(update_doc, |
|
66 "update (arg)\n\ |
|
67 \n\ |
|
68 Update the md5 object with the string arg. Repeated calls are\n\ |
|
69 equivalent to a single call with the concatenation of all the\n\ |
|
70 arguments."); |
|
71 |
|
72 |
|
73 static PyObject * |
|
74 md5_digest(md5object *self) |
|
75 { |
|
76 md5_state_t mdContext; |
|
77 unsigned char aDigest[16]; |
|
78 |
|
79 /* make a temporary copy, and perform the final */ |
|
80 mdContext = self->md5; |
|
81 md5_finish(&mdContext, aDigest); |
|
82 |
|
83 return PyString_FromStringAndSize((char *)aDigest, 16); |
|
84 } |
|
85 |
|
86 PyDoc_STRVAR(digest_doc, |
|
87 "digest() -> string\n\ |
|
88 \n\ |
|
89 Return the digest of the strings passed to the update() method so\n\ |
|
90 far. This is a 16-byte string which may contain non-ASCII characters,\n\ |
|
91 including null bytes."); |
|
92 |
|
93 |
|
94 static PyObject * |
|
95 md5_hexdigest(md5object *self) |
|
96 { |
|
97 md5_state_t mdContext; |
|
98 unsigned char digest[16]; |
|
99 unsigned char hexdigest[32]; |
|
100 int i, j; |
|
101 |
|
102 /* make a temporary copy, and perform the final */ |
|
103 mdContext = self->md5; |
|
104 md5_finish(&mdContext, digest); |
|
105 |
|
106 /* Make hex version of the digest */ |
|
107 for(i=j=0; i<16; i++) { |
|
108 char c; |
|
109 c = (digest[i] >> 4) & 0xf; |
|
110 c = (c>9) ? c+'a'-10 : c + '0'; |
|
111 hexdigest[j++] = c; |
|
112 c = (digest[i] & 0xf); |
|
113 c = (c>9) ? c+'a'-10 : c + '0'; |
|
114 hexdigest[j++] = c; |
|
115 } |
|
116 return PyString_FromStringAndSize((char*)hexdigest, 32); |
|
117 } |
|
118 |
|
119 |
|
120 PyDoc_STRVAR(hexdigest_doc, |
|
121 "hexdigest() -> string\n\ |
|
122 \n\ |
|
123 Like digest(), but returns the digest as a string of hexadecimal digits."); |
|
124 |
|
125 |
|
126 static PyObject * |
|
127 md5_copy(md5object *self) |
|
128 { |
|
129 md5object *md5p; |
|
130 |
|
131 if ((md5p = newmd5object()) == NULL) |
|
132 return NULL; |
|
133 |
|
134 md5p->md5 = self->md5; |
|
135 |
|
136 return (PyObject *)md5p; |
|
137 } |
|
138 |
|
139 PyDoc_STRVAR(copy_doc, |
|
140 "copy() -> md5 object\n\ |
|
141 \n\ |
|
142 Return a copy (``clone'') of the md5 object."); |
|
143 |
|
144 |
|
145 static PyMethodDef md5_methods[] = { |
|
146 {"update", (PyCFunction)md5_update, METH_VARARGS, update_doc}, |
|
147 {"digest", (PyCFunction)md5_digest, METH_NOARGS, digest_doc}, |
|
148 {"hexdigest", (PyCFunction)md5_hexdigest, METH_NOARGS, hexdigest_doc}, |
|
149 {"copy", (PyCFunction)md5_copy, METH_NOARGS, copy_doc}, |
|
150 {NULL, NULL} /* sentinel */ |
|
151 }; |
|
152 |
|
153 static PyObject * |
|
154 md5_get_block_size(PyObject *self, void *closure) |
|
155 { |
|
156 return PyInt_FromLong(64); |
|
157 } |
|
158 |
|
159 static PyObject * |
|
160 md5_get_digest_size(PyObject *self, void *closure) |
|
161 { |
|
162 return PyInt_FromLong(16); |
|
163 } |
|
164 |
|
165 static PyObject * |
|
166 md5_get_name(PyObject *self, void *closure) |
|
167 { |
|
168 return PyString_FromStringAndSize("MD5", 3); |
|
169 } |
|
170 |
|
171 static PyGetSetDef md5_getseters[] = { |
|
172 {"digest_size", |
|
173 (getter)md5_get_digest_size, NULL, |
|
174 NULL, |
|
175 NULL}, |
|
176 {"block_size", |
|
177 (getter)md5_get_block_size, NULL, |
|
178 NULL, |
|
179 NULL}, |
|
180 {"name", |
|
181 (getter)md5_get_name, NULL, |
|
182 NULL, |
|
183 NULL}, |
|
184 /* the old md5 and sha modules support 'digest_size' as in PEP 247. |
|
185 * the old sha module also supported 'digestsize'. ugh. */ |
|
186 {"digestsize", |
|
187 (getter)md5_get_digest_size, NULL, |
|
188 NULL, |
|
189 NULL}, |
|
190 {NULL} /* Sentinel */ |
|
191 }; |
|
192 |
|
193 |
|
194 PyDoc_STRVAR(module_doc, |
|
195 "This module implements the interface to RSA's MD5 message digest\n\ |
|
196 algorithm (see also Internet RFC 1321). Its use is quite\n\ |
|
197 straightforward: use the new() to create an md5 object. You can now\n\ |
|
198 feed this object with arbitrary strings using the update() method, and\n\ |
|
199 at any point you can ask it for the digest (a strong kind of 128-bit\n\ |
|
200 checksum, a.k.a. ``fingerprint'') of the concatenation of the strings\n\ |
|
201 fed to it so far using the digest() method.\n\ |
|
202 \n\ |
|
203 Functions:\n\ |
|
204 \n\ |
|
205 new([arg]) -- return a new md5 object, initialized with arg if provided\n\ |
|
206 md5([arg]) -- DEPRECATED, same as new, but for compatibility\n\ |
|
207 \n\ |
|
208 Special Objects:\n\ |
|
209 \n\ |
|
210 MD5Type -- type object for md5 objects"); |
|
211 |
|
212 PyDoc_STRVAR(md5type_doc, |
|
213 "An md5 represents the object used to calculate the MD5 checksum of a\n\ |
|
214 string of information.\n\ |
|
215 \n\ |
|
216 Methods:\n\ |
|
217 \n\ |
|
218 update() -- updates the current digest with an additional string\n\ |
|
219 digest() -- return the current digest value\n\ |
|
220 hexdigest() -- return the current digest as a string of hexadecimal digits\n\ |
|
221 copy() -- return a copy of the current md5 object"); |
|
222 |
|
223 static PyTypeObject MD5type = { |
|
224 PyVarObject_HEAD_INIT(NULL, 0) |
|
225 "_md5.md5", /*tp_name*/ |
|
226 sizeof(md5object), /*tp_size*/ |
|
227 0, /*tp_itemsize*/ |
|
228 /* methods */ |
|
229 (destructor)md5_dealloc, /*tp_dealloc*/ |
|
230 0, /*tp_print*/ |
|
231 0, /*tp_getattr*/ |
|
232 0, /*tp_setattr*/ |
|
233 0, /*tp_compare*/ |
|
234 0, /*tp_repr*/ |
|
235 0, /*tp_as_number*/ |
|
236 0, /*tp_as_sequence*/ |
|
237 0, /*tp_as_mapping*/ |
|
238 0, /*tp_hash*/ |
|
239 0, /*tp_call*/ |
|
240 0, /*tp_str*/ |
|
241 0, /*tp_getattro*/ |
|
242 0, /*tp_setattro*/ |
|
243 0, /*tp_as_buffer*/ |
|
244 Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
|
245 md5type_doc, /*tp_doc*/ |
|
246 0, /*tp_traverse*/ |
|
247 0, /*tp_clear*/ |
|
248 0, /*tp_richcompare*/ |
|
249 0, /*tp_weaklistoffset*/ |
|
250 0, /*tp_iter*/ |
|
251 0, /*tp_iternext*/ |
|
252 md5_methods, /*tp_methods*/ |
|
253 0, /*tp_members*/ |
|
254 md5_getseters, /*tp_getset*/ |
|
255 }; |
|
256 |
|
257 |
|
258 /* MD5 functions */ |
|
259 |
|
260 static PyObject * |
|
261 MD5_new(PyObject *self, PyObject *args) |
|
262 { |
|
263 md5object *md5p; |
|
264 unsigned char *cp = NULL; |
|
265 int len = 0; |
|
266 |
|
267 if (!PyArg_ParseTuple(args, "|s#:new", &cp, &len)) |
|
268 return NULL; |
|
269 |
|
270 if ((md5p = newmd5object()) == NULL) |
|
271 return NULL; |
|
272 |
|
273 if (cp) |
|
274 md5_append(&md5p->md5, cp, len); |
|
275 |
|
276 return (PyObject *)md5p; |
|
277 } |
|
278 |
|
279 PyDoc_STRVAR(new_doc, |
|
280 "new([arg]) -> md5 object\n\ |
|
281 \n\ |
|
282 Return a new md5 object. If arg is present, the method call update(arg)\n\ |
|
283 is made."); |
|
284 |
|
285 |
|
286 /* List of functions exported by this module */ |
|
287 |
|
288 static PyMethodDef md5_functions[] = { |
|
289 {"new", (PyCFunction)MD5_new, METH_VARARGS, new_doc}, |
|
290 {NULL, NULL} /* Sentinel */ |
|
291 }; |
|
292 |
|
293 |
|
294 /* Initialize this module. */ |
|
295 |
|
296 PyMODINIT_FUNC |
|
297 init_md5(void) |
|
298 { |
|
299 PyObject *m, *d; |
|
300 |
|
301 Py_TYPE(&MD5type) = &PyType_Type; |
|
302 if (PyType_Ready(&MD5type) < 0) |
|
303 return; |
|
304 m = Py_InitModule3("_md5", md5_functions, module_doc); |
|
305 if (m == NULL) |
|
306 return; |
|
307 d = PyModule_GetDict(m); |
|
308 PyDict_SetItemString(d, "MD5Type", (PyObject *)&MD5type); |
|
309 PyModule_AddIntConstant(m, "digest_size", 16); |
|
310 /* No need to check the error here, the caller will do that */ |
|
311 } |