Statistics
| Revision:

root / libsylph / md5.c @ 3310

History | View | Annotate | Download (14.7 KB)

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

    
38
struct MD5Context {
39
        guint32 buf[4];
40
        guint32 bits[2];
41
        guchar  in[64];
42
        int     doByteReverse;
43
};
44

    
45
static void MD5Init(struct MD5Context *context);
46
static void MD5Update(struct MD5Context *context, guchar const *buf,
47
                      guint len);
48
static void MD5Final(guchar digest[16], struct MD5Context *context);
49
static 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
 */
54
typedef struct MD5Context MD5_CTX;
55

    
56

    
57

    
58

    
59
static void byteReverse(guint8 *buf, guint longs);
60

    
61
/*
62
 * Note: this code is harmless on little-endian machines.
63
 */
64
void 
65
byteReverse(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
 */
82
void 
83
MD5Init(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
 */
104
void 
105
MD5Update(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
 */
158
void 
159
MD5Final(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
 */
223
void 
224
MD5Transform(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

    
312
struct _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
 **/
329
SMD5*           
330
s_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
 **/
354
SMD5*                
355
s_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
 **/
417
SMD5*           
418
s_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
 **/
440
void
441
s_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
 **/
459
SMD5*                
460
s_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
 **/
481
void
482
s_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
 **/
498
void
499
s_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
 **/
519
gint
520
s_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
 **/
544
guint
545
s_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
 **/
568
gchar*                
569
s_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

    
577
static 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
 **/
593
gchar*          
594
s_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
 **/
624
void
625
s_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
}