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 :
19 : #include "Python.h"
20 : #include "hashlib.h"
21 :
22 :
23 : /* Some useful types */
24 :
25 : #if SIZEOF_INT == 4
26 : typedef unsigned int MD5_INT32; /* 32-bit integer */
27 : typedef PY_LONG_LONG MD5_INT64; /* 64-bit integer */
28 : #else
29 : /* not defined. compilation will die. */
30 : #endif
31 :
32 : /* The MD5 block size and message digest sizes, in bytes */
33 :
34 : #define MD5_BLOCKSIZE 64
35 : #define MD5_DIGESTSIZE 16
36 :
37 : /* The structure for storing MD5 info */
38 :
39 : struct md5_state {
40 : MD5_INT64 length;
41 : MD5_INT32 state[4], curlen;
42 : unsigned char buf[MD5_BLOCKSIZE];
43 : };
44 :
45 : typedef struct {
46 : PyObject_HEAD
47 :
48 : struct md5_state hash_state;
49 : } MD5object;
50 :
51 :
52 : /* ------------------------------------------------------------------------
53 : *
54 : * This code for the MD5 algorithm was noted as public domain. The
55 : * original headers are pasted below.
56 : *
57 : * Several changes have been made to make it more compatible with the
58 : * Python environment and desired interface.
59 : *
60 : */
61 :
62 : /* LibTomCrypt, modular cryptographic library -- Tom St Denis
63 : *
64 : * LibTomCrypt is a library that provides various cryptographic
65 : * algorithms in a highly modular and flexible manner.
66 : *
67 : * The library is free for all purposes without any express
68 : * guarantee it works.
69 : *
70 : * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
71 : */
72 :
73 : /* rotate the hard way (platform optimizations could be done) */
74 : #define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
75 :
76 : /* Endian Neutral macros that work on all platforms */
77 :
78 : #define STORE32L(x, y) \
79 : { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
80 : (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
81 :
82 : #define LOAD32L(x, y) \
83 : { x = ((unsigned long)((y)[3] & 255)<<24) | \
84 : ((unsigned long)((y)[2] & 255)<<16) | \
85 : ((unsigned long)((y)[1] & 255)<<8) | \
86 : ((unsigned long)((y)[0] & 255)); }
87 :
88 : #define STORE64L(x, y) \
89 : { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
90 : (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
91 : (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
92 : (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
93 :
94 : #ifndef MIN
95 : #define MIN(x, y) ( ((x)<(y))?(x):(y) )
96 : #endif
97 :
98 :
99 : /* MD5 macros */
100 :
101 : #define F(x,y,z) (z ^ (x & (y ^ z)))
102 : #define G(x,y,z) (y ^ (z & (y ^ x)))
103 : #define H(x,y,z) (x^y^z)
104 : #define I(x,y,z) (y^(x|(~z)))
105 :
106 : #define FF(a,b,c,d,M,s,t) \
107 : a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b;
108 :
109 : #define GG(a,b,c,d,M,s,t) \
110 : a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b;
111 :
112 : #define HH(a,b,c,d,M,s,t) \
113 : a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b;
114 :
115 : #define II(a,b,c,d,M,s,t) \
116 : a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b;
117 :
118 :
119 0 : static void md5_compress(struct md5_state *md5, unsigned char *buf)
120 : {
121 : MD5_INT32 i, W[16], a, b, c, d;
122 :
123 : assert(md5 != NULL);
124 : assert(buf != NULL);
125 :
126 : /* copy the state into 512-bits into W[0..15] */
127 0 : for (i = 0; i < 16; i++) {
128 0 : LOAD32L(W[i], buf + (4*i));
129 : }
130 :
131 : /* copy state */
132 0 : a = md5->state[0];
133 0 : b = md5->state[1];
134 0 : c = md5->state[2];
135 0 : d = md5->state[3];
136 :
137 0 : FF(a,b,c,d,W[0],7,0xd76aa478UL)
138 0 : FF(d,a,b,c,W[1],12,0xe8c7b756UL)
139 0 : FF(c,d,a,b,W[2],17,0x242070dbUL)
140 0 : FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
141 0 : FF(a,b,c,d,W[4],7,0xf57c0fafUL)
142 0 : FF(d,a,b,c,W[5],12,0x4787c62aUL)
143 0 : FF(c,d,a,b,W[6],17,0xa8304613UL)
144 0 : FF(b,c,d,a,W[7],22,0xfd469501UL)
145 0 : FF(a,b,c,d,W[8],7,0x698098d8UL)
146 0 : FF(d,a,b,c,W[9],12,0x8b44f7afUL)
147 0 : FF(c,d,a,b,W[10],17,0xffff5bb1UL)
148 0 : FF(b,c,d,a,W[11],22,0x895cd7beUL)
149 0 : FF(a,b,c,d,W[12],7,0x6b901122UL)
150 0 : FF(d,a,b,c,W[13],12,0xfd987193UL)
151 0 : FF(c,d,a,b,W[14],17,0xa679438eUL)
152 0 : FF(b,c,d,a,W[15],22,0x49b40821UL)
153 0 : GG(a,b,c,d,W[1],5,0xf61e2562UL)
154 0 : GG(d,a,b,c,W[6],9,0xc040b340UL)
155 0 : GG(c,d,a,b,W[11],14,0x265e5a51UL)
156 0 : GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
157 0 : GG(a,b,c,d,W[5],5,0xd62f105dUL)
158 0 : GG(d,a,b,c,W[10],9,0x02441453UL)
159 0 : GG(c,d,a,b,W[15],14,0xd8a1e681UL)
160 0 : GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
161 0 : GG(a,b,c,d,W[9],5,0x21e1cde6UL)
162 0 : GG(d,a,b,c,W[14],9,0xc33707d6UL)
163 0 : GG(c,d,a,b,W[3],14,0xf4d50d87UL)
164 0 : GG(b,c,d,a,W[8],20,0x455a14edUL)
165 0 : GG(a,b,c,d,W[13],5,0xa9e3e905UL)
166 0 : GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
167 0 : GG(c,d,a,b,W[7],14,0x676f02d9UL)
168 0 : GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
169 0 : HH(a,b,c,d,W[5],4,0xfffa3942UL)
170 0 : HH(d,a,b,c,W[8],11,0x8771f681UL)
171 0 : HH(c,d,a,b,W[11],16,0x6d9d6122UL)
172 0 : HH(b,c,d,a,W[14],23,0xfde5380cUL)
173 0 : HH(a,b,c,d,W[1],4,0xa4beea44UL)
174 0 : HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
175 0 : HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
176 0 : HH(b,c,d,a,W[10],23,0xbebfbc70UL)
177 0 : HH(a,b,c,d,W[13],4,0x289b7ec6UL)
178 0 : HH(d,a,b,c,W[0],11,0xeaa127faUL)
179 0 : HH(c,d,a,b,W[3],16,0xd4ef3085UL)
180 0 : HH(b,c,d,a,W[6],23,0x04881d05UL)
181 0 : HH(a,b,c,d,W[9],4,0xd9d4d039UL)
182 0 : HH(d,a,b,c,W[12],11,0xe6db99e5UL)
183 0 : HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
184 0 : HH(b,c,d,a,W[2],23,0xc4ac5665UL)
185 0 : II(a,b,c,d,W[0],6,0xf4292244UL)
186 0 : II(d,a,b,c,W[7],10,0x432aff97UL)
187 0 : II(c,d,a,b,W[14],15,0xab9423a7UL)
188 0 : II(b,c,d,a,W[5],21,0xfc93a039UL)
189 0 : II(a,b,c,d,W[12],6,0x655b59c3UL)
190 0 : II(d,a,b,c,W[3],10,0x8f0ccc92UL)
191 0 : II(c,d,a,b,W[10],15,0xffeff47dUL)
192 0 : II(b,c,d,a,W[1],21,0x85845dd1UL)
193 0 : II(a,b,c,d,W[8],6,0x6fa87e4fUL)
194 0 : II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
195 0 : II(c,d,a,b,W[6],15,0xa3014314UL)
196 0 : II(b,c,d,a,W[13],21,0x4e0811a1UL)
197 0 : II(a,b,c,d,W[4],6,0xf7537e82UL)
198 0 : II(d,a,b,c,W[11],10,0xbd3af235UL)
199 0 : II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
200 0 : II(b,c,d,a,W[9],21,0xeb86d391UL)
201 :
202 0 : md5->state[0] = md5->state[0] + a;
203 0 : md5->state[1] = md5->state[1] + b;
204 0 : md5->state[2] = md5->state[2] + c;
205 0 : md5->state[3] = md5->state[3] + d;
206 0 : }
207 :
208 :
209 : /**
210 : Initialize the hash state
211 : @param sha1 The hash state you wish to initialize
212 : */
213 : static void
214 0 : md5_init(struct md5_state *md5)
215 : {
216 : assert(md5 != NULL);
217 0 : md5->state[0] = 0x67452301UL;
218 0 : md5->state[1] = 0xefcdab89UL;
219 0 : md5->state[2] = 0x98badcfeUL;
220 0 : md5->state[3] = 0x10325476UL;
221 0 : md5->curlen = 0;
222 0 : md5->length = 0;
223 0 : }
224 :
225 : /**
226 : Process a block of memory though the hash
227 : @param sha1 The hash state
228 : @param in The data to hash
229 : @param inlen The length of the data (octets)
230 : */
231 : static void
232 0 : md5_process(struct md5_state *md5, const unsigned char *in, Py_ssize_t inlen)
233 : {
234 : Py_ssize_t n;
235 :
236 : assert(md5 != NULL);
237 : assert(in != NULL);
238 : assert(md5->curlen <= sizeof(md5->buf));
239 :
240 0 : while (inlen > 0) {
241 0 : if (md5->curlen == 0 && inlen >= MD5_BLOCKSIZE) {
242 0 : md5_compress(md5, (unsigned char *)in);
243 0 : md5->length += MD5_BLOCKSIZE * 8;
244 0 : in += MD5_BLOCKSIZE;
245 0 : inlen -= MD5_BLOCKSIZE;
246 : } else {
247 0 : n = MIN(inlen, (Py_ssize_t)(MD5_BLOCKSIZE - md5->curlen));
248 0 : memcpy(md5->buf + md5->curlen, in, (size_t)n);
249 0 : md5->curlen += n;
250 0 : in += n;
251 0 : inlen -= n;
252 0 : if (md5->curlen == MD5_BLOCKSIZE) {
253 0 : md5_compress(md5, md5->buf);
254 0 : md5->length += 8*MD5_BLOCKSIZE;
255 0 : md5->curlen = 0;
256 : }
257 : }
258 : }
259 0 : }
260 :
261 : /**
262 : Terminate the hash to get the digest
263 : @param sha1 The hash state
264 : @param out [out] The destination of the hash (16 bytes)
265 : */
266 : static void
267 0 : md5_done(struct md5_state *md5, unsigned char *out)
268 : {
269 : int i;
270 :
271 : assert(md5 != NULL);
272 : assert(out != NULL);
273 : assert(md5->curlen < sizeof(md5->buf));
274 :
275 : /* increase the length of the message */
276 0 : md5->length += md5->curlen * 8;
277 :
278 : /* append the '1' bit */
279 0 : md5->buf[md5->curlen++] = (unsigned char)0x80;
280 :
281 : /* if the length is currently above 56 bytes we append zeros
282 : * then compress. Then we can fall back to padding zeros and length
283 : * encoding like normal.
284 : */
285 0 : if (md5->curlen > 56) {
286 0 : while (md5->curlen < 64) {
287 0 : md5->buf[md5->curlen++] = (unsigned char)0;
288 : }
289 0 : md5_compress(md5, md5->buf);
290 0 : md5->curlen = 0;
291 : }
292 :
293 : /* pad upto 56 bytes of zeroes */
294 0 : while (md5->curlen < 56) {
295 0 : md5->buf[md5->curlen++] = (unsigned char)0;
296 : }
297 :
298 : /* store length */
299 0 : STORE64L(md5->length, md5->buf+56);
300 0 : md5_compress(md5, md5->buf);
301 :
302 : /* copy output */
303 0 : for (i = 0; i < 4; i++) {
304 0 : STORE32L(md5->state[i], out+(4*i));
305 : }
306 0 : }
307 :
308 : /* .Source: /cvs/libtom/libtomcrypt/src/hashes/md5.c,v $ */
309 : /* .Revision: 1.10 $ */
310 : /* .Date: 2007/05/12 14:25:28 $ */
311 :
312 : /*
313 : * End of copied MD5 code.
314 : *
315 : * ------------------------------------------------------------------------
316 : */
317 :
318 : static PyTypeObject MD5type;
319 :
320 :
321 : static MD5object *
322 0 : newMD5object(void)
323 : {
324 0 : return (MD5object *)PyObject_New(MD5object, &MD5type);
325 : }
326 :
327 :
328 : /* Internal methods for a hash object */
329 :
330 : static void
331 0 : MD5_dealloc(PyObject *ptr)
332 : {
333 0 : PyObject_Del(ptr);
334 0 : }
335 :
336 :
337 : /* External methods for a hash object */
338 :
339 : PyDoc_STRVAR(MD5_copy__doc__, "Return a copy of the hash object.");
340 :
341 : static PyObject *
342 0 : MD5_copy(MD5object *self, PyObject *unused)
343 : {
344 : MD5object *newobj;
345 :
346 0 : if (Py_TYPE(self) == &MD5type) {
347 0 : if ( (newobj = newMD5object())==NULL)
348 0 : return NULL;
349 : } else {
350 0 : if ( (newobj = newMD5object())==NULL)
351 0 : return NULL;
352 : }
353 :
354 0 : newobj->hash_state = self->hash_state;
355 0 : return (PyObject *)newobj;
356 : }
357 :
358 : PyDoc_STRVAR(MD5_digest__doc__,
359 : "Return the digest value as a string of binary data.");
360 :
361 : static PyObject *
362 0 : MD5_digest(MD5object *self, PyObject *unused)
363 : {
364 : unsigned char digest[MD5_DIGESTSIZE];
365 : struct md5_state temp;
366 :
367 0 : temp = self->hash_state;
368 0 : md5_done(&temp, digest);
369 0 : return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE);
370 : }
371 :
372 : PyDoc_STRVAR(MD5_hexdigest__doc__,
373 : "Return the digest value as a string of hexadecimal digits.");
374 :
375 : static PyObject *
376 0 : MD5_hexdigest(MD5object *self, PyObject *unused)
377 : {
378 : unsigned char digest[MD5_DIGESTSIZE];
379 : struct md5_state temp;
380 : PyObject *retval;
381 : Py_UCS1 *hex_digest;
382 : int i, j;
383 :
384 : /* Get the raw (binary) digest value */
385 0 : temp = self->hash_state;
386 0 : md5_done(&temp, digest);
387 :
388 : /* Create a new string */
389 0 : retval = PyUnicode_New(MD5_DIGESTSIZE * 2, 127);
390 0 : if (!retval)
391 0 : return NULL;
392 0 : hex_digest = PyUnicode_1BYTE_DATA(retval);
393 :
394 : /* Make hex version of the digest */
395 0 : for(i=j=0; i<MD5_DIGESTSIZE; i++) {
396 : unsigned char c;
397 0 : c = (digest[i] >> 4) & 0xf;
398 0 : hex_digest[j++] = Py_hexdigits[c];
399 0 : c = (digest[i] & 0xf);
400 0 : hex_digest[j++] = Py_hexdigits[c];
401 : }
402 : assert(_PyUnicode_CheckConsistency(retval, 1));
403 0 : return retval;
404 : }
405 :
406 : PyDoc_STRVAR(MD5_update__doc__,
407 : "Update this hash object's state with the provided string.");
408 :
409 : static PyObject *
410 0 : MD5_update(MD5object *self, PyObject *args)
411 : {
412 : PyObject *obj;
413 : Py_buffer buf;
414 :
415 0 : if (!PyArg_ParseTuple(args, "O:update", &obj))
416 0 : return NULL;
417 :
418 0 : GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
419 :
420 0 : md5_process(&self->hash_state, buf.buf, buf.len);
421 :
422 0 : PyBuffer_Release(&buf);
423 0 : Py_INCREF(Py_None);
424 0 : return Py_None;
425 : }
426 :
427 : static PyMethodDef MD5_methods[] = {
428 : {"copy", (PyCFunction)MD5_copy, METH_NOARGS, MD5_copy__doc__},
429 : {"digest", (PyCFunction)MD5_digest, METH_NOARGS, MD5_digest__doc__},
430 : {"hexdigest", (PyCFunction)MD5_hexdigest, METH_NOARGS, MD5_hexdigest__doc__},
431 : {"update", (PyCFunction)MD5_update, METH_VARARGS, MD5_update__doc__},
432 : {NULL, NULL} /* sentinel */
433 : };
434 :
435 : static PyObject *
436 0 : MD5_get_block_size(PyObject *self, void *closure)
437 : {
438 0 : return PyLong_FromLong(MD5_BLOCKSIZE);
439 : }
440 :
441 : static PyObject *
442 0 : MD5_get_name(PyObject *self, void *closure)
443 : {
444 0 : return PyUnicode_FromStringAndSize("MD5", 3);
445 : }
446 :
447 : static PyObject *
448 0 : md5_get_digest_size(PyObject *self, void *closure)
449 : {
450 0 : return PyLong_FromLong(MD5_DIGESTSIZE);
451 : }
452 :
453 :
454 : static PyGetSetDef MD5_getseters[] = {
455 : {"block_size",
456 : (getter)MD5_get_block_size, NULL,
457 : NULL,
458 : NULL},
459 : {"name",
460 : (getter)MD5_get_name, NULL,
461 : NULL,
462 : NULL},
463 : {"digest_size",
464 : (getter)md5_get_digest_size, NULL,
465 : NULL,
466 : NULL},
467 : {NULL} /* Sentinel */
468 : };
469 :
470 : static PyTypeObject MD5type = {
471 : PyVarObject_HEAD_INIT(NULL, 0)
472 : "_md5.md5", /*tp_name*/
473 : sizeof(MD5object), /*tp_size*/
474 : 0, /*tp_itemsize*/
475 : /* methods */
476 : MD5_dealloc, /*tp_dealloc*/
477 : 0, /*tp_print*/
478 : 0, /*tp_getattr*/
479 : 0, /*tp_setattr*/
480 : 0, /*tp_reserved*/
481 : 0, /*tp_repr*/
482 : 0, /*tp_as_number*/
483 : 0, /*tp_as_sequence*/
484 : 0, /*tp_as_mapping*/
485 : 0, /*tp_hash*/
486 : 0, /*tp_call*/
487 : 0, /*tp_str*/
488 : 0, /*tp_getattro*/
489 : 0, /*tp_setattro*/
490 : 0, /*tp_as_buffer*/
491 : Py_TPFLAGS_DEFAULT, /*tp_flags*/
492 : 0, /*tp_doc*/
493 : 0, /*tp_traverse*/
494 : 0, /*tp_clear*/
495 : 0, /*tp_richcompare*/
496 : 0, /*tp_weaklistoffset*/
497 : 0, /*tp_iter*/
498 : 0, /*tp_iternext*/
499 : MD5_methods, /* tp_methods */
500 : NULL, /* tp_members */
501 : MD5_getseters, /* tp_getset */
502 : };
503 :
504 :
505 : /* The single module-level function: new() */
506 :
507 : PyDoc_STRVAR(MD5_new__doc__,
508 : "Return a new MD5 hash object; optionally initialized with a string.");
509 :
510 : static PyObject *
511 0 : MD5_new(PyObject *self, PyObject *args, PyObject *kwdict)
512 : {
513 : static char *kwlist[] = {"string", NULL};
514 : MD5object *new;
515 0 : PyObject *data_obj = NULL;
516 : Py_buffer buf;
517 :
518 0 : if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist,
519 : &data_obj)) {
520 0 : return NULL;
521 : }
522 :
523 0 : if (data_obj)
524 0 : GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf);
525 :
526 0 : if ((new = newMD5object()) == NULL) {
527 0 : if (data_obj)
528 0 : PyBuffer_Release(&buf);
529 0 : return NULL;
530 : }
531 :
532 0 : md5_init(&new->hash_state);
533 :
534 0 : if (PyErr_Occurred()) {
535 0 : Py_DECREF(new);
536 0 : if (data_obj)
537 0 : PyBuffer_Release(&buf);
538 0 : return NULL;
539 : }
540 0 : if (data_obj) {
541 0 : md5_process(&new->hash_state, buf.buf, buf.len);
542 0 : PyBuffer_Release(&buf);
543 : }
544 :
545 0 : return (PyObject *)new;
546 : }
547 :
548 :
549 : /* List of functions exported by this module */
550 :
551 : static struct PyMethodDef MD5_functions[] = {
552 : {"md5", (PyCFunction)MD5_new, METH_VARARGS|METH_KEYWORDS, MD5_new__doc__},
553 : {NULL, NULL} /* Sentinel */
554 : };
555 :
556 :
557 : /* Initialize this module. */
558 :
559 : #define insint(n,v) { PyModule_AddIntConstant(m,n,v); }
560 :
561 :
562 : static struct PyModuleDef _md5module = {
563 : PyModuleDef_HEAD_INIT,
564 : "_md5",
565 : NULL,
566 : -1,
567 : MD5_functions,
568 : NULL,
569 : NULL,
570 : NULL,
571 : NULL
572 : };
573 :
574 : PyMODINIT_FUNC
575 0 : PyInit__md5(void)
576 : {
577 0 : Py_TYPE(&MD5type) = &PyType_Type;
578 0 : if (PyType_Ready(&MD5type) < 0)
579 0 : return NULL;
580 0 : return PyModule_Create(&_md5module);
581 : }
|