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.) */
13 #include "structmember.h"
19 md5_state_t md5
; /* the context holder */
22 static PyTypeObject MD5type
;
24 #define is_md5object(v) ((v)->ob_type == &MD5type)
31 md5p
= PyObject_New(md5object
, &MD5type
);
35 md5_init(&md5p
->md5
); /* actual initialisation */
43 md5_dealloc(md5object
*md5p
)
49 /* MD5 methods-as-attributes */
52 md5_update(md5object
*self
, PyObject
*args
)
57 if (!PyArg_ParseTuple(args
, "O:update", &data_obj
))
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
);
70 PyDoc_STRVAR(update_doc
,
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\
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\
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.");
100 md5_hexdigest(md5object
*self
)
102 md5_state_t mdContext
;
103 unsigned char digest
[16];
104 unsigned char hexdigest
[32];
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
++) {
114 c
= (digest
[i
] >> 4) & 0xf;
115 c
= (c
>9) ? c
+'a'-10 : c
+ '0';
117 c
= (digest
[i
] & 0xf);
118 c
= (c
>9) ? c
+'a'-10 : c
+ '0';
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.");
132 md5_copy(md5object
*self
)
136 if ((md5p
= newmd5object()) == 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 */
159 md5_get_block_size(PyObject
*self
, void *closure
)
161 return PyInt_FromLong(64);
165 md5_get_digest_size(PyObject
*self
, void *closure
)
167 return PyInt_FromLong(16);
171 md5_get_name(PyObject
*self
, void *closure
)
173 return PyString_FromStringAndSize("MD5", 3);
176 static PyGetSetDef md5_getseters
[] = {
178 (getter
)md5_get_digest_size
, NULL
,
182 (getter
)md5_get_block_size
, NULL
,
186 (getter
)md5_get_name
, NULL
,
189 /* the old md5 and sha modules support 'digest_size' as in PEP 247.
190 * the old sha module also supported 'digestsize'. ugh. */
192 (getter
)md5_get_digest_size
, 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\
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\
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\
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*/
234 (destructor
)md5_dealloc
, /*tp_dealloc*/
241 0, /*tp_as_sequence*/
249 Py_TPFLAGS_DEFAULT
, /*tp_flags*/
250 md5type_doc
, /*tp_doc*/
253 0, /*tp_richcompare*/
254 0, /*tp_weaklistoffset*/
257 md5_methods
, /*tp_methods*/
259 md5_getseters
, /*tp_getset*/
266 MD5_new(PyObject
*self
, PyObject
*args
)
269 PyObject
*data_obj
= NULL
;
272 if (!PyArg_ParseTuple(args
, "|O:new", &data_obj
))
276 GET_BUFFER_VIEW_OR_ERROUT(data_obj
, &view
, NULL
);
278 if ((md5p
= newmd5object()) == NULL
) {
280 PyBuffer_Release(&view
);
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\
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. */
315 Py_TYPE(&MD5type
) = &PyType_Type
;
316 if (PyType_Ready(&MD5type
) < 0)
318 m
= Py_InitModule3("_md5", md5_functions
, module_doc
);
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 */