1 /*
2  *
3  *  C++ Portable Types Library (PTypes)
4  *  Version 2.1.1  Released 27-Jun-2007
5  *
6  *  Copyright (C) 2001-2007 Hovik Melikyan
7  *
8  *  http://www.melikyan.com/ptypes/
9  *
10  */
11 
12 /*
13  *   Derived from L. Peter Deutsch's independent implementation
14  *   of MD5 (RFC1321). The original copyright notice follows.
15  *   This file is a concatenation of the original md5.h and
16  *   md5.c and contains PTypes' MD5 wrapper class at the bottom.
17  */
18 
19 /*
20   Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
21 
22   This software is provided 'as-is', without any express or implied
23   warranty.  In no event will the authors be held liable for any damages
24   arising from the use of this software.
25 
26   Permission is granted to anyone to use this software for any purpose,
27   including commercial applications, and to alter it and redistribute it
28   freely, subject to the following restrictions:
29 
30   1. The origin of this software must not be misrepresented; you must not
31      claim that you wrote the original software. If you use this software
32      in a product, an acknowledgment in the product documentation would be
33      appreciated but is not required.
34   2. Altered source versions must be plainly marked as such, and must not be
35      misrepresented as being the original software.
36   3. This notice may not be removed or altered from any source distribution.
37 
38   L. Peter Deutsch
39   ghost@aladdin.com
40 
41  */
42 
43 /*
44   Independent implementation of MD5 (RFC 1321).
45 
46   This code implements the MD5 Algorithm defined in RFC 1321, whose
47   text is available at
48 	http://www.ietf.org/rfc/rfc1321.txt
49   The code is derived from the text of the RFC, including the test suite
50   (section A.5) but excluding the rest of Appendix A.  It does not include
51   any code or documentation that is identified in the RFC as being
52   copyrighted.
53 
54   The original and principal author of md5.h is L. Peter Deutsch
55   <ghost@aladdin.com>.  Other authors are noted in the change history
56   that follows (in reverse chronological order):
57 
58   2002-04-13 lpd Removed support for non-ANSI compilers; removed
59 	references to Ghostscript; clarified derivation from RFC 1321;
60 	now handles byte order either statically or dynamically.
61   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
62   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
63 	added conditionalization for C++ compilation from Martin
64 	Purschke <purschke@bnl.gov>.
65   1999-05-03 lpd Original version.
66  */
67 
68 
69 #include <string.h>
70 
71 #include "pstreams.h"
72 
73 
74 PTYPES_BEGIN
75 
76 
77 //
78 // --- md5.h ---------------------------------------------------------------
79 //
80 
81 /*
82  * This package supports both compile-time and run-time determination of CPU
83  * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
84  * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
85  * defined as non-zero, the code will be compiled to run only on big-endian
86  * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
87  * run on either big- or little-endian CPUs, but will run slightly less
88  * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
89  */
90 
91 
92 //
93 // typedef unsigned char md5_byte_t; /* 8-bit byte */
94 // typedef unsigned int md5_word_t; /* 32-bit word */
95 //
96 // /* Define the state of the MD5 Algorithm. */
97 // typedef struct md5_state_s {
98 //     md5_word_t count[2];	/* message length in bits, lsw first */
99 //     md5_word_t abcd[4];		/* digest buffer */
100 //     md5_byte_t buf[64];		/* accumulate block */
101 // } md5_state_t;
102 //
103 
104 /* Initialize the algorithm. */
105 void md5_init(md5_state_t *pms);
106 
107 /* Append a string to the message. */
108 void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
109 
110 /* Finish the message and return the digest. */
111 void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
112 
113 
114 //
115 // --- md5.c ---------------------------------------------------------------
116 //
117 
118 
119 #undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
120 #ifdef ARCH_IS_BIG_ENDIAN
121 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
122 #else
123 #  define BYTE_ORDER 0
124 #endif
125 
126 #define T_MASK ((md5_word_t)~0)
127 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
128 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
129 #define T3    0x242070db
130 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
131 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
132 #define T6    0x4787c62a
133 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
134 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
135 #define T9    0x698098d8
136 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
137 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
138 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
139 #define T13    0x6b901122
140 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
141 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
142 #define T16    0x49b40821
143 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
144 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
145 #define T19    0x265e5a51
146 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
147 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
148 #define T22    0x02441453
149 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
150 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
151 #define T25    0x21e1cde6
152 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
153 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
154 #define T28    0x455a14ed
155 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
156 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
157 #define T31    0x676f02d9
158 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
159 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
160 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
161 #define T35    0x6d9d6122
162 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
163 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
164 #define T38    0x4bdecfa9
165 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
166 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
167 #define T41    0x289b7ec6
168 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
169 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
170 #define T44    0x04881d05
171 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
172 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
173 #define T47    0x1fa27cf8
174 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
175 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
176 #define T50    0x432aff97
177 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
178 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
179 #define T53    0x655b59c3
180 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
181 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
182 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
183 #define T57    0x6fa87e4f
184 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
185 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
186 #define T60    0x4e0811a1
187 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
188 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
189 #define T63    0x2ad7d2bb
190 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
191 
192 
193 static void
md5_process(md5_state_t * pms,const md5_byte_t * data)194 md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
195 {
196     md5_word_t
197 	a = pms->abcd[0], b = pms->abcd[1],
198 	c = pms->abcd[2], d = pms->abcd[3];
199     md5_word_t t;
200 #if BYTE_ORDER > 0
201     /* Define storage only for big-endian CPUs. */
202     md5_word_t X[16];
203 #else
204     /* Define storage for little-endian or both types of CPUs. */
205     md5_word_t xbuf[16];
206     const md5_word_t *X;
207 #endif
208 
209     {
210 #if BYTE_ORDER == 0
211 	/*
212 	 * Determine dynamically whether this is a big-endian or
213 	 * little-endian machine, since we can use a more efficient
214 	 * algorithm on the latter.
215 	 */
216 	static const int w = 1;
217 
218 	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
219 #endif
220 #if BYTE_ORDER <= 0		/* little-endian */
221 	{
222 	    /*
223 	     * On little-endian machines, we can process properly aligned
224 	     * data without copying it.
225 	     */
226 	    if (!((data - (const md5_byte_t *)0) & 3)) {
227 		/* data are properly aligned */
228 		X = (const md5_word_t *)data;
229 	    } else {
230 		/* not aligned */
231 		memcpy(xbuf, data, 64);
232 		X = xbuf;
233 	    }
234 	}
235 #endif
236 #if BYTE_ORDER == 0
237 	else			/* dynamic big-endian */
238 #endif
239 #if BYTE_ORDER >= 0		/* big-endian */
240 	{
241 	    /*
242 	     * On big-endian machines, we must arrange the bytes in the
243 	     * right order.
244 	     */
245 	    const md5_byte_t *xp = data;
246 	    int i;
247 
248 #  if BYTE_ORDER == 0
249 	    X = xbuf;		/* (dynamic only) */
250 #  else
251 #    define xbuf X		/* (static only) */
252 #  endif
253 	    for (i = 0; i < 16; ++i, xp += 4)
254 		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
255 	}
256 #endif
257     }
258 
259 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
260 
261     /* Round 1. */
262     /* Let [abcd k s i] denote the operation
263        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
264 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
265 #define SET(a, b, c, d, k, s, Ti)\
266   t = a + F(b,c,d) + X[k] + Ti;\
267   a = ROTATE_LEFT(t, s) + b
268     /* Do the following 16 operations. */
269     SET(a, b, c, d,  0,  7,  T1);
270     SET(d, a, b, c,  1, 12,  T2);
271     SET(c, d, a, b,  2, 17,  T3);
272     SET(b, c, d, a,  3, 22,  T4);
273     SET(a, b, c, d,  4,  7,  T5);
274     SET(d, a, b, c,  5, 12,  T6);
275     SET(c, d, a, b,  6, 17,  T7);
276     SET(b, c, d, a,  7, 22,  T8);
277     SET(a, b, c, d,  8,  7,  T9);
278     SET(d, a, b, c,  9, 12, T10);
279     SET(c, d, a, b, 10, 17, T11);
280     SET(b, c, d, a, 11, 22, T12);
281     SET(a, b, c, d, 12,  7, T13);
282     SET(d, a, b, c, 13, 12, T14);
283     SET(c, d, a, b, 14, 17, T15);
284     SET(b, c, d, a, 15, 22, T16);
285 #undef SET
286 
287      /* Round 2. */
288      /* Let [abcd k s i] denote the operation
289           a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
290 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
291 #define SET(a, b, c, d, k, s, Ti)\
292   t = a + G(b,c,d) + X[k] + Ti;\
293   a = ROTATE_LEFT(t, s) + b
294      /* Do the following 16 operations. */
295     SET(a, b, c, d,  1,  5, T17);
296     SET(d, a, b, c,  6,  9, T18);
297     SET(c, d, a, b, 11, 14, T19);
298     SET(b, c, d, a,  0, 20, T20);
299     SET(a, b, c, d,  5,  5, T21);
300     SET(d, a, b, c, 10,  9, T22);
301     SET(c, d, a, b, 15, 14, T23);
302     SET(b, c, d, a,  4, 20, T24);
303     SET(a, b, c, d,  9,  5, T25);
304     SET(d, a, b, c, 14,  9, T26);
305     SET(c, d, a, b,  3, 14, T27);
306     SET(b, c, d, a,  8, 20, T28);
307     SET(a, b, c, d, 13,  5, T29);
308     SET(d, a, b, c,  2,  9, T30);
309     SET(c, d, a, b,  7, 14, T31);
310     SET(b, c, d, a, 12, 20, T32);
311 #undef SET
312 
313      /* Round 3. */
314      /* Let [abcd k s t] denote the operation
315           a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
316 #define H(x, y, z) ((x) ^ (y) ^ (z))
317 #define SET(a, b, c, d, k, s, Ti)\
318   t = a + H(b,c,d) + X[k] + Ti;\
319   a = ROTATE_LEFT(t, s) + b
320      /* Do the following 16 operations. */
321     SET(a, b, c, d,  5,  4, T33);
322     SET(d, a, b, c,  8, 11, T34);
323     SET(c, d, a, b, 11, 16, T35);
324     SET(b, c, d, a, 14, 23, T36);
325     SET(a, b, c, d,  1,  4, T37);
326     SET(d, a, b, c,  4, 11, T38);
327     SET(c, d, a, b,  7, 16, T39);
328     SET(b, c, d, a, 10, 23, T40);
329     SET(a, b, c, d, 13,  4, T41);
330     SET(d, a, b, c,  0, 11, T42);
331     SET(c, d, a, b,  3, 16, T43);
332     SET(b, c, d, a,  6, 23, T44);
333     SET(a, b, c, d,  9,  4, T45);
334     SET(d, a, b, c, 12, 11, T46);
335     SET(c, d, a, b, 15, 16, T47);
336     SET(b, c, d, a,  2, 23, T48);
337 #undef SET
338 
339      /* Round 4. */
340      /* Let [abcd k s t] denote the operation
341           a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
342 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
343 #define SET(a, b, c, d, k, s, Ti)\
344   t = a + I(b,c,d) + X[k] + Ti;\
345   a = ROTATE_LEFT(t, s) + b
346      /* Do the following 16 operations. */
347     SET(a, b, c, d,  0,  6, T49);
348     SET(d, a, b, c,  7, 10, T50);
349     SET(c, d, a, b, 14, 15, T51);
350     SET(b, c, d, a,  5, 21, T52);
351     SET(a, b, c, d, 12,  6, T53);
352     SET(d, a, b, c,  3, 10, T54);
353     SET(c, d, a, b, 10, 15, T55);
354     SET(b, c, d, a,  1, 21, T56);
355     SET(a, b, c, d,  8,  6, T57);
356     SET(d, a, b, c, 15, 10, T58);
357     SET(c, d, a, b,  6, 15, T59);
358     SET(b, c, d, a, 13, 21, T60);
359     SET(a, b, c, d,  4,  6, T61);
360     SET(d, a, b, c, 11, 10, T62);
361     SET(c, d, a, b,  2, 15, T63);
362     SET(b, c, d, a,  9, 21, T64);
363 #undef SET
364 
365      /* Then perform the following additions. (That is increment each
366         of the four registers by the value it had before this block
367         was started.) */
368     pms->abcd[0] += a;
369     pms->abcd[1] += b;
370     pms->abcd[2] += c;
371     pms->abcd[3] += d;
372 }
373 
374 void
md5_init(md5_state_t * pms)375 md5_init(md5_state_t *pms)
376 {
377     pms->count[0] = pms->count[1] = 0;
378     pms->abcd[0] = 0x67452301;
379     pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
380     pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
381     pms->abcd[3] = 0x10325476;
382 }
383 
384 void
md5_append(md5_state_t * pms,const md5_byte_t * data,int nbytes)385 md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
386 {
387     const md5_byte_t *p = data;
388     int left = nbytes;
389     int offset = (pms->count[0] >> 3) & 63;
390     md5_word_t nbits = (md5_word_t)(nbytes << 3);
391 
392     if (nbytes <= 0)
393 	return;
394 
395     /* Update the message length. */
396     pms->count[1] += nbytes >> 29;
397     pms->count[0] += nbits;
398     if (pms->count[0] < nbits)
399 	pms->count[1]++;
400 
401     /* Process an initial partial block. */
402     if (offset) {
403 	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
404 
405 	memcpy(pms->buf + offset, p, copy);
406 	if (offset + copy < 64)
407 	    return;
408 	p += copy;
409 	left -= copy;
410 	md5_process(pms, pms->buf);
411     }
412 
413     /* Process full blocks. */
414     for (; left >= 64; p += 64, left -= 64)
415 	md5_process(pms, p);
416 
417     /* Process a final partial block. */
418     if (left)
419 	memcpy(pms->buf, p, left);
420 }
421 
422 void
md5_finish(md5_state_t * pms,md5_byte_t digest[16])423 md5_finish(md5_state_t *pms, md5_byte_t digest[16])
424 {
425     static const md5_byte_t pad[64] = {
426 	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
427 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
428 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
429 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
430     };
431     md5_byte_t data[8];
432     int i;
433 
434     /* Save the length before padding. */
435     for (i = 0; i < 8; ++i)
436 	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
437     /* Pad to 56 bytes mod 64. */
438     md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
439     /* Append the length. */
440     md5_append(pms, data, 8);
441     for (i = 0; i < 16; ++i)
442 	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
443 }
444 
445 
446 
447 //
448 // --- PTypes' wrapper class -----------------------------------------------
449 //
450 
451 
outmd5(outstm * istm)452 outmd5::outmd5(outstm* istm): outfilter(istm, 0)
453 {
454     memset(&ctx, 0, sizeof ctx);
455     memset(digest, 0, sizeof digest);
456 }
457 
458 
~outmd5()459 outmd5::~outmd5()
460 {
461     close();
462 }
463 
464 
doopen()465 void outmd5::doopen()
466 {
467     outfilter::doopen();
468     memset(digest, 0, sizeof digest);
469     md5_init(&ctx);
470 }
471 
472 
doclose()473 void outmd5::doclose()
474 {
475     md5_finish(&ctx, (unsigned char*)digest);
476     outfilter::doclose();
477 }
478 
479 
dorawwrite(const char * buf,int count)480 int outmd5::dorawwrite(const char* buf, int count)
481 {
482     if (count > 0)
483     {
484         md5_append(&ctx, (const unsigned char*)buf, (unsigned)count);
485         if (stm != nil)
486             stm->write(buf, count);
487         return count;
488     }
489     else
490         return 0;
491 }
492 
493 
get_streamname()494 string outmd5::get_streamname()
495 {
496     return "MD5";
497 }
498 
499 
get_digest()500 string outmd5::get_digest()
501 {
502     close();
503     string result;
504     // the first 120 bits are divided into 24-bit portions;
505     // each portion is represented with 4 characters from the base64 set
506     for (int i = 0; i <= 12; i += 3)
507     {
508         long v = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
509         result += itostring(large(v), 64, 4);
510     }
511     // the last byte is complemented with 4 zero bits to form
512     // the last two base64 characters
513     return result + itostring(large(digest[15] << 4), 64, 2);
514 }
515 
516 
517 PTYPES_END
518