Issue #1515: Enable use of deepcopy() with instance methods. Patch by Robert Collins.
[python.git] / Modules / md5module.c
blob7081706ba3ce42e31c156bb3f5b5eee14455e0c1
2 /* MD5 module */
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.) */
10 /* MD5 objects */
12 #include "Python.h"
13 #include "structmember.h"
14 #include "md5.h"
15 #include "hashlib.h"
17 typedef struct {
18 PyObject_HEAD
19 md5_state_t md5; /* the context holder */
20 } md5object;
22 static PyTypeObject MD5type;
24 #define is_md5object(v) ((v)->ob_type == &MD5type)
26 static md5object *
27 newmd5object(void)
29 md5object *md5p;
31 md5p = PyObject_New(md5object, &MD5type);
32 if (md5p == NULL)
33 return NULL;
35 md5_init(&md5p->md5); /* actual initialisation */
36 return md5p;
40 /* MD5 methods */
42 static void
43 md5_dealloc(md5object *md5p)
45 PyObject_Del(md5p);
49 /* MD5 methods-as-attributes */
51 static PyObject *
52 md5_update(md5object *self, PyObject *args)
54 PyObject *data_obj;
55 Py_buffer view;
57 if (!PyArg_ParseTuple(args, "O:update", &data_obj))
58 return NULL;
60 GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view, NULL);
62 md5_append(&self->md5, (unsigned char*)view.buf,
63 Py_SAFE_DOWNCAST(view.len, Py_ssize_t, unsigned int));
65 PyBuffer_Release(&view);
66 Py_INCREF(Py_None);
67 return Py_None;
70 PyDoc_STRVAR(update_doc,
71 "update (arg)\n\
72 \n\
73 Update the md5 object with the string arg. Repeated calls are\n\
74 equivalent to a single call with the concatenation of all the\n\
75 arguments.");
78 static PyObject *
79 md5_digest(md5object *self)
81 md5_state_t mdContext;
82 unsigned char aDigest[16];
84 /* make a temporary copy, and perform the final */
85 mdContext = self->md5;
86 md5_finish(&mdContext, aDigest);
88 return PyString_FromStringAndSize((char *)aDigest, 16);
91 PyDoc_STRVAR(digest_doc,
92 "digest() -> string\n\
93 \n\
94 Return the digest of the strings passed to the update() method so\n\
95 far. This is a 16-byte string which may contain non-ASCII characters,\n\
96 including null bytes.");
99 static PyObject *
100 md5_hexdigest(md5object *self)
102 md5_state_t mdContext;
103 unsigned char digest[16];
104 unsigned char hexdigest[32];
105 int i, j;
107 /* make a temporary copy, and perform the final */
108 mdContext = self->md5;
109 md5_finish(&mdContext, digest);
111 /* Make hex version of the digest */
112 for(i=j=0; i<16; i++) {
113 char c;
114 c = (digest[i] >> 4) & 0xf;
115 c = (c>9) ? c+'a'-10 : c + '0';
116 hexdigest[j++] = c;
117 c = (digest[i] & 0xf);
118 c = (c>9) ? c+'a'-10 : c + '0';
119 hexdigest[j++] = c;
121 return PyString_FromStringAndSize((char*)hexdigest, 32);
125 PyDoc_STRVAR(hexdigest_doc,
126 "hexdigest() -> string\n\
128 Like digest(), but returns the digest as a string of hexadecimal digits.");
131 static PyObject *
132 md5_copy(md5object *self)
134 md5object *md5p;
136 if ((md5p = newmd5object()) == NULL)
137 return NULL;
139 md5p->md5 = self->md5;
141 return (PyObject *)md5p;
144 PyDoc_STRVAR(copy_doc,
145 "copy() -> md5 object\n\
147 Return a copy (``clone'') of the md5 object.");
150 static PyMethodDef md5_methods[] = {
151 {"update", (PyCFunction)md5_update, METH_VARARGS, update_doc},
152 {"digest", (PyCFunction)md5_digest, METH_NOARGS, digest_doc},
153 {"hexdigest", (PyCFunction)md5_hexdigest, METH_NOARGS, hexdigest_doc},
154 {"copy", (PyCFunction)md5_copy, METH_NOARGS, copy_doc},
155 {NULL, NULL} /* sentinel */
158 static PyObject *
159 md5_get_block_size(PyObject *self, void *closure)
161 return PyInt_FromLong(64);
164 static PyObject *
165 md5_get_digest_size(PyObject *self, void *closure)
167 return PyInt_FromLong(16);
170 static PyObject *
171 md5_get_name(PyObject *self, void *closure)
173 return PyString_FromStringAndSize("MD5", 3);
176 static PyGetSetDef md5_getseters[] = {
177 {"digest_size",
178 (getter)md5_get_digest_size, NULL,
179 NULL,
180 NULL},
181 {"block_size",
182 (getter)md5_get_block_size, NULL,
183 NULL,
184 NULL},
185 {"name",
186 (getter)md5_get_name, NULL,
187 NULL,
188 NULL},
189 /* the old md5 and sha modules support 'digest_size' as in PEP 247.
190 * the old sha module also supported 'digestsize'. ugh. */
191 {"digestsize",
192 (getter)md5_get_digest_size, NULL,
193 NULL,
194 NULL},
195 {NULL} /* Sentinel */
199 PyDoc_STRVAR(module_doc,
200 "This module implements the interface to RSA's MD5 message digest\n\
201 algorithm (see also Internet RFC 1321). Its use is quite\n\
202 straightforward: use the new() to create an md5 object. You can now\n\
203 feed this object with arbitrary strings using the update() method, and\n\
204 at any point you can ask it for the digest (a strong kind of 128-bit\n\
205 checksum, a.k.a. ``fingerprint'') of the concatenation of the strings\n\
206 fed to it so far using the digest() method.\n\
208 Functions:\n\
210 new([arg]) -- return a new md5 object, initialized with arg if provided\n\
211 md5([arg]) -- DEPRECATED, same as new, but for compatibility\n\
213 Special Objects:\n\
215 MD5Type -- type object for md5 objects");
217 PyDoc_STRVAR(md5type_doc,
218 "An md5 represents the object used to calculate the MD5 checksum of a\n\
219 string of information.\n\
221 Methods:\n\
223 update() -- updates the current digest with an additional string\n\
224 digest() -- return the current digest value\n\
225 hexdigest() -- return the current digest as a string of hexadecimal digits\n\
226 copy() -- return a copy of the current md5 object");
228 static PyTypeObject MD5type = {
229 PyVarObject_HEAD_INIT(NULL, 0)
230 "_md5.md5", /*tp_name*/
231 sizeof(md5object), /*tp_size*/
232 0, /*tp_itemsize*/
233 /* methods */
234 (destructor)md5_dealloc, /*tp_dealloc*/
235 0, /*tp_print*/
236 0, /*tp_getattr*/
237 0, /*tp_setattr*/
238 0, /*tp_compare*/
239 0, /*tp_repr*/
240 0, /*tp_as_number*/
241 0, /*tp_as_sequence*/
242 0, /*tp_as_mapping*/
243 0, /*tp_hash*/
244 0, /*tp_call*/
245 0, /*tp_str*/
246 0, /*tp_getattro*/
247 0, /*tp_setattro*/
248 0, /*tp_as_buffer*/
249 Py_TPFLAGS_DEFAULT, /*tp_flags*/
250 md5type_doc, /*tp_doc*/
251 0, /*tp_traverse*/
252 0, /*tp_clear*/
253 0, /*tp_richcompare*/
254 0, /*tp_weaklistoffset*/
255 0, /*tp_iter*/
256 0, /*tp_iternext*/
257 md5_methods, /*tp_methods*/
258 0, /*tp_members*/
259 md5_getseters, /*tp_getset*/
263 /* MD5 functions */
265 static PyObject *
266 MD5_new(PyObject *self, PyObject *args)
268 md5object *md5p;
269 PyObject *data_obj = NULL;
270 Py_buffer view;
272 if (!PyArg_ParseTuple(args, "|O:new", &data_obj))
273 return NULL;
275 if (data_obj)
276 GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view, NULL);
278 if ((md5p = newmd5object()) == NULL) {
279 if (data_obj)
280 PyBuffer_Release(&view);
281 return NULL;
284 if (data_obj) {
285 md5_append(&md5p->md5, (unsigned char*)view.buf,
286 Py_SAFE_DOWNCAST(view.len, Py_ssize_t, unsigned int));
287 PyBuffer_Release(&view);
290 return (PyObject *)md5p;
293 PyDoc_STRVAR(new_doc,
294 "new([arg]) -> md5 object\n\
296 Return a new md5 object. If arg is present, the method call update(arg)\n\
297 is made.");
300 /* List of functions exported by this module */
302 static PyMethodDef md5_functions[] = {
303 {"new", (PyCFunction)MD5_new, METH_VARARGS, new_doc},
304 {NULL, NULL} /* Sentinel */
308 /* Initialize this module. */
310 PyMODINIT_FUNC
311 init_md5(void)
313 PyObject *m, *d;
315 Py_TYPE(&MD5type) = &PyType_Type;
316 if (PyType_Ready(&MD5type) < 0)
317 return;
318 m = Py_InitModule3("_md5", md5_functions, module_doc);
319 if (m == NULL)
320 return;
321 d = PyModule_GetDict(m);
322 PyDict_SetItemString(d, "MD5Type", (PyObject *)&MD5type);
323 PyModule_AddIntConstant(m, "digest_size", 16);
324 /* No need to check the error here, the caller will do that */