summaryrefslogtreecommitdiff
path: root/libsylph/md5.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsylph/md5.c')
-rw-r--r--libsylph/md5.c637
1 files changed, 637 insertions, 0 deletions
diff --git a/libsylph/md5.c b/libsylph/md5.c
new file mode 100644
index 0000000..a047471
--- /dev/null
+++ b/libsylph/md5.c
@@ -0,0 +1,637 @@
1/*
2
3 GNet API added by David Helder <dhelder@umich.edu> 2000-6-11. All
4 additions and changes placed in the public domain.
5
6 Files originally from: http://www.gxsnmp.org/CVS/gxsnmp/
7
8 Modified the prefix of functions to prevent conflict with original GNet.
9
10 */
11/*
12 * This code implements the MD5 message-digest algorithm.
13 * The algorithm is due to Ron Rivest. This code was
14 * written by Colin Plumb in 1993, no copyright is claimed.
15 * This code is in the public domain; do with it what you wish.
16 *
17 * Equivalent code is available from RSA Data Security, Inc.
18 * This code has been tested against that, and is equivalent,
19 * except that you don't need to include two pages of legalese
20 * with every copy.
21 *
22 * To compute the message digest of a chunk of bytes, declare an
23 * MD5Context structure, pass it to MD5Init, call MD5Update as
24 * needed on buffers full of bytes, and then call MD5Final, which
25 * will fill a supplied 16-byte array with the digest.
26 */
27
28#include "md5.h"
29#include <glib.h>
30#include <string.h>
31
32
33/* ************************************************************ */
34/* Code below is from Colin Plumb implementation */
35
36
37
38struct MD5Context {
39 guint32 buf[4];
40 guint32 bits[2];
41 guchar in[64];
42 int doByteReverse;
43};
44
45static void MD5Init(struct MD5Context *context);
46static void MD5Update(struct MD5Context *context, guchar const *buf,
47 guint len);
48static void MD5Final(guchar digest[16], struct MD5Context *context);
49static void MD5Transform(guint32 buf[4], guint32 const in[16]);
50
51/*
52 * This is needed to make RSAREF happy on some MS-DOS compilers.
53 */
54typedef struct MD5Context MD5_CTX;
55
56
57
58
59static void byteReverse(guint8 *buf, guint longs);
60
61/*
62 * Note: this code is harmless on little-endian machines.
63 */
64void
65byteReverse(guint8 *buf, guint longs)
66{
67 guint32 t;
68 do
69 {
70 t = (guint32) ((guint) buf[3] << 8 | buf[2]) << 16 |
71 ((guint) buf[1] << 8 | buf[0]);
72 *(guint32 *) buf = t;
73 buf += 4;
74 }
75 while (--longs);
76}
77
78/*
79 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
80 * initialization constants.
81 */
82void
83MD5Init(struct MD5Context *ctx)
84{
85 ctx->buf[0] = 0x67452301;
86 ctx->buf[1] = 0xefcdab89;
87 ctx->buf[2] = 0x98badcfe;
88 ctx->buf[3] = 0x10325476;
89
90 ctx->bits[0] = 0;
91 ctx->bits[1] = 0;
92
93#if (G_BYTE_ORDER == G_BIG_ENDIAN)
94 ctx->doByteReverse = 1;
95#else
96 ctx->doByteReverse = 0;
97#endif
98}
99
100/*
101 * Update context to reflect the concatenation of another buffer full
102 * of bytes.
103 */
104void
105MD5Update(struct MD5Context *ctx, guint8 const *buf, guint len)
106{
107 guint32 t;
108
109 /* Update bitcount */
110
111 t = ctx->bits[0];
112 if ((ctx->bits[0] = t + ((guint32) len << 3)) < t)
113 ctx->bits[1]++; /* Carry from low to high */
114 ctx->bits[1] += len >> 29;
115
116 t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
117
118 /* Handle any leading odd-sized chunks */
119
120 if (t)
121 {
122 guint8 *p = (guint8 *) ctx->in + t;
123
124 t = 64 - t;
125 if (len < t)
126 {
127 g_memmove(p, buf, len);
128 return;
129 }
130 g_memmove(p, buf, t);
131 if (ctx->doByteReverse)
132 byteReverse(ctx->in, 16);
133 MD5Transform(ctx->buf, (guint32 *) ctx->in);
134 buf += t;
135 len -= t;
136 }
137 /* Process data in 64-byte chunks */
138
139 while (len >= 64)
140 {
141 g_memmove(ctx->in, buf, 64);
142 if (ctx->doByteReverse)
143 byteReverse(ctx->in, 16);
144 MD5Transform(ctx->buf, (guint32 *) ctx->in);
145 buf += 64;
146 len -= 64;
147 }
148
149 /* Handle any remaining bytes of data. */
150
151 g_memmove(ctx->in, buf, len);
152}
153
154/*
155 * Final wrapup - pad to 64-byte boundary with the bit pattern
156 * 1 0* (64-bit count of bits processed, MSB-first)
157 */
158void
159MD5Final(guint8 digest[16], struct MD5Context *ctx)
160{
161 guint count;
162 guint8 *p;
163
164 /* Compute number of bytes mod 64 */
165 count = (ctx->bits[0] >> 3) & 0x3F;
166
167 /* Set the first char of padding to 0x80. This is safe since there is
168 always at least one byte free */
169 p = ctx->in + count;
170 *p++ = 0x80;
171
172 /* Bytes of padding needed to make 64 bytes */
173 count = 64 - 1 - count;
174
175 /* Pad out to 56 mod 64 */
176 if (count < 8)
177 {
178 /* Two lots of padding: Pad the first block to 64 bytes */
179 memset(p, 0, count);
180 if (ctx->doByteReverse)
181 byteReverse(ctx->in, 16);
182 MD5Transform(ctx->buf, (guint32 *) ctx->in);
183
184 /* Now fill the next block with 56 bytes */
185 memset(ctx->in, 0, 56);
186 }
187 else
188 {
189 /* Pad block to 56 bytes */
190 memset(p, 0, count - 8);
191 }
192 if (ctx->doByteReverse)
193 byteReverse(ctx->in, 14);
194
195 /* Append length in bits and transform */
196 ((guint32 *) ctx->in)[14] = ctx->bits[0];
197 ((guint32 *) ctx->in)[15] = ctx->bits[1];
198
199 MD5Transform(ctx->buf, (guint32 *) ctx->in);
200 if (ctx->doByteReverse)
201 byteReverse((guint8 *) ctx->buf, 4);
202 g_memmove(digest, ctx->buf, 16);
203 memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
204}
205
206/* The four core functions - F1 is optimized somewhat */
207
208/* #define F1(x, y, z) (x & y | ~x & z) */
209#define F1(x, y, z) (z ^ (x & (y ^ z)))
210#define F2(x, y, z) F1(z, x, y)
211#define F3(x, y, z) (x ^ y ^ z)
212#define F4(x, y, z) (y ^ (x | ~z))
213
214/* This is the central step in the MD5 algorithm. */
215#define MD5STEP(f, w, x, y, z, data, s) \
216 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
217
218/*
219 * The core of the MD5 algorithm, this alters an existing MD5 hash to
220 * reflect the addition of 16 longwords of new data. MD5Update blocks
221 * the data and converts bytes into longwords for this routine.
222 */
223void
224MD5Transform(guint32 buf[4], guint32 const in[16])
225{
226 register guint32 a, b, c, d;
227
228 a = buf[0];
229 b = buf[1];
230 c = buf[2];
231 d = buf[3];
232
233 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
234 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
235 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
236 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
237 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
238 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
239 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
240 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
241 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
242 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
243 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
244 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
245 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
246 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
247 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
248 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
249
250 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
251 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
252 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
253 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
254 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
255 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
256 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
257 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
258 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
259 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
260 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
261 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
262 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
263 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
264 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
265 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
266
267 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
268 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
269 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
270 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
271 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
272 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
273 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
274 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
275 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
276 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
277 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
278 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
279 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
280 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
281 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
282 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
283
284 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
285 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
286 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
287 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
288 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
289 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
290 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
291 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
292 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
293 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
294 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
295 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
296 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
297 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
298 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
299 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
300
301 buf[0] += a;
302 buf[1] += b;
303 buf[2] += c;
304 buf[3] += d;
305}
306
307
308
309/* ************************************************************ */
310/* Code below is David Helder's API for GNet */
311
312struct _SMD5
313{
314 struct MD5Context ctx;
315 gchar digest[S_GNET_MD5_HASH_LENGTH];
316};
317
318
319/**
320 * s_gnet_md5_new:
321 * @buffer: buffer to hash
322 * @length: length of @buffer
323 *
324 * Creates a #SMD5 from @buffer.
325 *
326 * Returns: a new #SMD5.
327 *
328 **/
329SMD5*
330s_gnet_md5_new (const guchar* buffer, guint length)
331{
332 SMD5* md5;
333
334 md5 = g_new0 (SMD5, 1);
335 MD5Init (&md5->ctx);
336 MD5Update (&md5->ctx, buffer, length);
337 MD5Final ((gpointer) &md5->digest, &md5->ctx);
338
339 return md5;
340}
341
342
343
344/**
345 * s_gnet_md5_new_string:
346 * @str: hexidecimal string
347 *
348 * Creates a #SMD5 from @str. @str is a hexidecimal string
349 * representing the digest.
350 *
351 * Returns: a new #SMD5.
352 *
353 **/
354SMD5*
355s_gnet_md5_new_string (const gchar* str)
356{
357 SMD5* md5;
358 guint i;
359
360 g_return_val_if_fail (str, NULL);
361 g_return_val_if_fail (strlen(str) >= (S_GNET_MD5_HASH_LENGTH * 2), NULL);
362
363 md5 = g_new0 (SMD5, 1);
364
365 for (i = 0; i < (S_GNET_MD5_HASH_LENGTH * 2); ++i)
366 {
367 guint val = 0;
368
369 switch (str[i])
370 {
371 case '0': val = 0; break;
372 case '1': val = 1; break;
373 case '2': val = 2; break;
374 case '3': val = 3; break;
375 case '4': val = 4; break;
376 case '5': val = 5; break;
377 case '6': val = 6; break;
378 case '7': val = 7; break;
379 case '8': val = 8; break;
380 case '9': val = 9; break;
381 case 'A':
382 case 'a': val = 10; break;
383 case 'B':
384 case 'b': val = 11; break;
385 case 'C':
386 case 'c': val = 12; break;
387 case 'D':
388 case 'd': val = 13; break;
389 case 'E':
390 case 'e': val = 14; break;
391 case 'F':
392 case 'f': val = 15; break;
393 default:
394 g_return_val_if_fail (FALSE, NULL);
395 }
396
397 if (i % 2)
398 md5->digest[i / 2] |= val;
399 else
400 md5->digest[i / 2] = val << 4;
401 }
402
403 return md5;
404}
405
406
407
408/**
409 * s_gnet_md5_clone
410 * @md5: a #SMD5
411 *
412 * Copies a #SMD5.
413 *
414 * Returns: a copy of @md5.
415 *
416 **/
417SMD5*
418s_gnet_md5_clone (const SMD5* md5)
419{
420 SMD5* md52;
421
422 g_return_val_if_fail (md5, NULL);
423
424 md52 = g_new0 (SMD5, 1);
425 md52->ctx = md5->ctx;
426 memcpy (md52->digest, md5->digest, sizeof(md5->digest));
427
428 return md52;
429}
430
431
432
433/**
434 * s_gnet_md5_delete
435 * @md5: a #SMD5
436 *
437 * Deletes a #SMD5.
438 *
439 **/
440void
441s_gnet_md5_delete (SMD5* md5)
442{
443 if (md5)
444 g_free (md5);
445}
446
447
448
449/**
450 * s_gnet_md5_new_incremental
451 *
452 * Creates a #SMD5 incrementally. After creating a #SMD5, call
453 * s_gnet_md5_update() one or more times to hash data. Finally, call
454 * s_gnet_md5_final() to compute the final hash value.
455 *
456 * Returns: a new #SMD5.
457 *
458 **/
459SMD5*
460s_gnet_md5_new_incremental (void)
461{
462 SMD5* md5;
463
464 md5 = g_new0 (SMD5, 1);
465 MD5Init (&md5->ctx);
466 return md5;
467}
468
469
470/**
471 * s_gnet_md5_update
472 * @md5: a #SMD5
473 * @buffer: buffer to add
474 * @length: length of @buffer
475 *
476 * Updates the hash with @buffer. This may be called several times
477 * on a hash created by s_gnet_md5_new_incremental() before being
478 * finalized by calling s_gnet_md5_final().
479 *
480 **/
481void
482s_gnet_md5_update (SMD5* md5, const guchar* buffer, guint length)
483{
484 g_return_if_fail (md5);
485
486 MD5Update (&md5->ctx, buffer, length);
487}
488
489
490/**
491 * s_gnet_md5_final
492 * @md5: a #SMD5
493 *
494 * Calcuates the final hash value of a #SMD5. This should only be
495 * called on an #SMD5 created by s_gnet_md5_new_incremental().
496 *
497 **/
498void
499s_gnet_md5_final (SMD5* md5)
500{
501 g_return_if_fail (md5);
502
503 MD5Final ((gpointer) &md5->digest, &md5->ctx);
504}
505
506
507/* **************************************** */
508
509/**
510 * s_gnet_md5_equal
511 * @p1: first #SMD5.
512 * @p2: second #SMD5.
513 *
514 * Compares two #SMD5's for equality.
515 *
516 * Returns: TRUE if they are equal; FALSE otherwise.
517 *
518 **/
519gint
520s_gnet_md5_equal (gconstpointer p1, gconstpointer p2)
521{
522 SMD5* md5a = (SMD5*) p1;
523 SMD5* md5b = (SMD5*) p2;
524 guint i;
525
526 for (i = 0; i < S_GNET_MD5_HASH_LENGTH; ++i)
527 if (md5a->digest[i] != md5b->digest[i])
528 return FALSE;
529
530 return TRUE;
531}
532
533
534/**
535 * s_gnet_md5_hash
536 * @p: a #SMD5
537 *
538 * Creates a hash code for a #SMD5 for use with GHashTable. This
539 * hash value is not the same as the MD5 digest.
540 *
541 * Returns: the hash code for @p.
542 *
543 **/
544guint
545s_gnet_md5_hash (gconstpointer p)
546{
547 const SMD5* md5 = (const SMD5*) p;
548 const guint* q;
549
550 g_return_val_if_fail (md5, 0);
551
552 q = (const guint*) md5->digest;
553
554 return (q[0] ^ q[1] ^ q[2] ^ q[3]);
555}
556
557
558/**
559 * s_gnet_md5_get_digest
560 * @md5: a #SMD5
561 *
562 * Gets the raw MD5 digest.
563 *
564 * Returns: a callee-owned buffer containing the MD5 hash digest.
565 * The buffer is %S_GNET_MD5_HASH_LENGTH bytes long.
566 *
567 **/
568gchar*
569s_gnet_md5_get_digest (const SMD5* md5)
570{
571 g_return_val_if_fail (md5, NULL);
572
573 return (gchar*) md5->digest;
574}
575
576
577static gchar bits2hex[16] = { '0', '1', '2', '3',
578 '4', '5', '6', '7',
579 '8', '9', 'a', 'b',
580 'c', 'd', 'e', 'f' };
581
582/**
583 * s_gnet_md5_get_string
584 * @md5: a #SMD5
585 *
586 * Gets the digest represented a human-readable string.
587 *
588 * Returns: a hexadecimal string representing the digest. The string
589 * is 2 * %S_GNET_MD5_HASH_LENGTH bytes long and NULL terminated. The
590 * string is caller owned.
591 *
592 **/
593gchar*
594s_gnet_md5_get_string (const SMD5* md5)
595{
596 gchar* str;
597 guint i;
598
599 g_return_val_if_fail (md5, NULL);
600
601 str = g_new (gchar, S_GNET_MD5_HASH_LENGTH * 2 + 1);
602 str[S_GNET_MD5_HASH_LENGTH * 2] = '\0';
603
604 for (i = 0; i < S_GNET_MD5_HASH_LENGTH; ++i)
605 {
606 str[i * 2] = bits2hex[(md5->digest[i] & 0xF0) >> 4];
607 str[(i * 2) + 1] = bits2hex[(md5->digest[i] & 0x0F) ];
608 }
609
610 return str;
611}
612
613
614
615/**
616 * s_gnet_md5_copy_string
617 * @md5: a #SMD5
618 * @buffer: buffer at least 2 * %S_GNET_MD5_HASH_LENGTH bytes long
619 *
620 * Copies the digest, represented as a string, into @buffer. The
621 * string is not NULL terminated.
622 *
623 **/
624void
625s_gnet_md5_copy_string (const SMD5* md5, gchar* buffer)
626{
627 guint i;
628
629 g_return_if_fail (md5);
630 g_return_if_fail (buffer);
631
632 for (i = 0; i < S_GNET_MD5_HASH_LENGTH; ++i)
633 {
634 buffer[i * 2] = bits2hex[(md5->digest[i] & 0xF0) >> 4];
635 buffer[(i * 2) + 1] = bits2hex[(md5->digest[i] & 0x0F) ];
636 }
637}