Remove commented out code.
[geeqie.git] / src / md5-util.c
1 /*
2  * This code implements the MD5 message-digest algorithm.
3  * The algorithm is due to Ron Rivest.  This code was
4  * written by Colin Plumb in 1993, no copyright is claimed.
5  * This code is in the public domain; do with it what you wish.
6  *
7  * Equivalent code is available from RSA Data Security, Inc.
8  * This code has been tested against that, and is equivalent,
9  * except that you don't need to include two pages of legalese
10  * with every copy.
11  *
12  * To compute the message digest of a chunk of bytes, declare an
13  * MD5Context structure, pass it to md5_init, call md5_update as
14  * needed on buffers full of bytes, and then call md5_Final, which
15  * will fill a supplied 16-byte array with the digest.
16  */
17
18 /* parts of this file are :
19  * Written March 1993 by Branko Lankester
20  * Modified June 1993 by Colin Plumb for altered md5.c.
21  * Modified October 1995 by Erik Troan for RPM
22  */
23
24 /*
25  * Pulled from evolution for use in Geeqie, their version is nicely glib'ed
26  * GNOME CVS HEAD evolution/e-util/md5-utils.[ch] September 8, 2004
27  */
28
29
30 #include <stdio.h>
31 #include <string.h>
32 #include "md5-util.h"
33
34
35 static void md5_transform(guint32 buf[4], const guint32 in[16]);
36
37 static gint _ie = 0x44332211;
38 static union _endian { gint i; gchar b[4]; } *_endian = (union _endian *)&_ie;
39 #define IS_BIG_ENDIAN()         (_endian->b[0] == '\x44')
40 #define IS_LITTLE_ENDIAN()      (_endian->b[0] == '\x11')
41
42
43 /*
44  * Note: this code is harmless on little-endian machines.
45  */
46 static void
47 _byte_reverse(guchar *buf, guint32 longs)
48 {
49         guint32 t;
50         do {
51                 t = (guint32) ((guint32) buf[3] << 8 | buf[2]) << 16 |
52                         ((guint32) buf[1] << 8 | buf[0]);
53                 *(guint32 *) buf = t;
54                 buf += 4;
55         } while (--longs);
56 }
57
58 /**
59  * md5_init: Initialise an md5 context object
60  * @ctx: md5 context
61  *
62  * Initialise an md5 buffer.
63  *
64  **/
65 void
66 md5_init(MD5Context *ctx)
67 {
68         ctx->buf[0] = 0x67452301;
69         ctx->buf[1] = 0xefcdab89;
70         ctx->buf[2] = 0x98badcfe;
71         ctx->buf[3] = 0x10325476;
72
73         ctx->bits[0] = 0;
74         ctx->bits[1] = 0;
75
76         if (IS_BIG_ENDIAN())
77                 ctx->doByteReverse = 1;
78         else
79                 ctx->doByteReverse = 0;
80 }
81
82
83
84 /**
85  * md5_update: add a buffer to md5 hash computation
86  * @ctx: context object used for md5 computaion
87  * @buf: buffer to add
88  * @len: buffer length
89  *
90  * Update context to reflect the concatenation of another buffer full
91  * of bytes. Use this to progressively construct an md5 hash.
92  **/
93 void
94 md5_update(MD5Context *ctx, const guchar *buf, guint32 len)
95 {
96         guint32 t;
97
98         /* Update bitcount */
99
100         t = ctx->bits[0];
101         if ((ctx->bits[0] = t + ((guint32) len << 3)) < t)
102                 ctx->bits[1]++;         /* Carry from low to high */
103         ctx->bits[1] += len >> 29;
104
105         t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
106
107         /* Handle any leading odd-sized chunks */
108
109         if (t) {
110                 guchar *p = (guchar *) ctx->in + t;
111
112                 t = 64 - t;
113                 if (len < t) {
114                         memcpy(p, buf, len);
115                         return;
116                 }
117                 memcpy(p, buf, t);
118                 if (ctx->doByteReverse)
119                         _byte_reverse(ctx->in, 16);
120                 md5_transform(ctx->buf, (guint32 *) ctx->in);
121                 buf += t;
122                 len -= t;
123         }
124         /* Process data in 64-byte chunks */
125
126         while (len >= 64) {
127                 memcpy(ctx->in, buf, 64);
128                 if (ctx->doByteReverse)
129                         _byte_reverse(ctx->in, 16);
130                 md5_transform(ctx->buf, (guint32 *) ctx->in);
131                 buf += 64;
132                 len -= 64;
133         }
134
135         /* Handle any remaining bytes of data. */
136
137         memcpy(ctx->in, buf, len);
138 }
139
140
141 /*
142  * Final wrapup - pad to 64-byte boundary with the bit pattern
143  * 1 0* (64-bit count of bits processed, MSB-first)
144  */
145 /**
146  * md5_final: copy the final md5 hash to a bufer
147  * @digest: 16 bytes buffer
148  * @ctx: context containing the calculated md5
149  *
150  * copy the final md5 hash to a bufer
151  **/
152 void
153 md5_final(MD5Context *ctx, guchar digest[16])
154 {
155         guint32 count;
156         guchar *p;
157
158         /* Compute number of bytes mod 64 */
159         count = (ctx->bits[0] >> 3) & 0x3F;
160
161         /* Set the first char of padding to 0x80.  This is safe since there is
162            always at least one byte free */
163         p = ctx->in + count;
164         *p++ = 0x80;
165
166         /* Bytes of padding needed to make 64 bytes */
167         count = 64 - 1 - count;
168
169         /* Pad out to 56 mod 64 */
170         if (count < 8) {
171                 /* Two lots of padding:  Pad the first block to 64 bytes */
172                 memset(p, 0, count);
173                 if (ctx->doByteReverse)
174                         _byte_reverse(ctx->in, 16);
175                 md5_transform(ctx->buf, (guint32 *) ctx->in);
176
177                 /* Now fill the next block with 56 bytes */
178                 memset(ctx->in, 0, 56);
179         } else {
180                 /* Pad block to 56 bytes */
181                 memset(p, 0, count - 8);
182         }
183         if (ctx->doByteReverse)
184                 _byte_reverse(ctx->in, 14);
185
186         /* Append length in bits and transform */
187         ((guint32 *) ctx->in)[14] = ctx->bits[0];
188         ((guint32 *) ctx->in)[15] = ctx->bits[1];
189
190         md5_transform(ctx->buf, (guint32 *) ctx->in);
191         if (ctx->doByteReverse)
192                 _byte_reverse((guchar *) ctx->buf, 4);
193         memcpy(digest, ctx->buf, 16);
194 }
195
196
197
198
199 /* The four core functions - F1 is optimized somewhat */
200
201 /* #define F1(x, y, z) (x & y | ~x & z) */
202 #define F1(x, y, z) (z ^ (x & (y ^ z)))
203 #define F2(x, y, z) F1(z, x, y)
204 #define F3(x, y, z) (x ^ y ^ z)
205 #define F4(x, y, z) (y ^ (x | ~z))
206
207 /* This is the central step in the MD5 algorithm. */
208 #define MD5STEP(f, w, x, y, z, data, s) \
209         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
210
211 /*
212  * The core of the MD5 algorithm, this alters an existing MD5 hash to
213  * reflect the addition of 16 longwords of new data.  md5_Update blocks
214  * the data and converts bytes into longwords for this routine.
215  */
216 static void
217 md5_transform(guint32 buf[4], const guint32 in[16])
218 {
219         register guint32 a, b, c, d;
220
221         a = buf[0];
222         b = buf[1];
223         c = buf[2];
224         d = buf[3];
225
226         MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
227         MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
228         MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
229         MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
230         MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
231         MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
232         MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
233         MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
234         MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
235         MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
236         MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
237         MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
238         MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
239         MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
240         MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
241         MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
242
243         MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
244         MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
245         MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
246         MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
247         MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
248         MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
249         MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
250         MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
251         MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
252         MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
253         MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
254         MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
255         MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
256         MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
257         MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
258         MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
259
260         MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
261         MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
262         MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
263         MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
264         MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
265         MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
266         MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
267         MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
268         MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
269         MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
270         MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
271         MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
272         MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
273         MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
274         MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
275         MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
276
277         MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
278         MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
279         MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
280         MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
281         MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
282         MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
283         MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
284         MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
285         MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
286         MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
287         MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
288         MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
289         MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
290         MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
291         MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
292         MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
293
294         buf[0] += a;
295         buf[1] += b;
296         buf[2] += c;
297         buf[3] += d;
298 }
299
300
301
302
303 /**
304  * md5_get_digest: get the md5 hash of a buffer
305  * @buffer: byte buffer
306  * @buffer_size: buffer size (in bytes)
307  * @digest: 16 bytes buffer receiving the hash code.
308  *
309  * Get the md5 hash of a buffer. The result is put in
310  * the 16 bytes buffer @digest .
311  **/
312 void
313 md5_get_digest(const guchar *buffer, gint buffer_size, guchar digest[16])
314 {
315         MD5Context ctx;
316
317         md5_init(&ctx);
318         md5_update(&ctx, buffer, buffer_size);
319         md5_final(&ctx, digest);
320
321 }
322
323 /* modified for GQView, starting here */
324
325 /**
326  * md5_get_digest_from_file: get the md5 hash of a file
327  * @filename: file name
328  * @digest: 16 bytes buffer receiving the hash code.
329  * @return: TRUE on success
330  *
331  * Get the md5 hash of a file. The result is put in
332  * the 16 bytes buffer @digest .
333  **/
334 gboolean md5_get_digest_from_file(const gchar *path, guchar digest[16])
335 {
336         MD5Context ctx;
337         guchar tmp_buf[1024];
338         gint nb_bytes_read;
339         FILE *fp;
340         gint success;
341
342         fp = fopen(path, "r");
343         if (!fp) return FALSE;
344
345         md5_init(&ctx);
346
347         while ((nb_bytes_read = fread(tmp_buf, sizeof (guchar), sizeof(tmp_buf), fp)) > 0)
348                 {
349                 md5_update(&ctx, tmp_buf, nb_bytes_read);
350                 }
351
352         success = (ferror(fp) == 0);
353         fclose(fp);
354         if (!success) return FALSE;
355
356         md5_final(&ctx, digest);
357         return TRUE;
358 }
359
360 /* these to and from text string converters were borrowed from
361  * the libgnomeui library, where they are name thumb_digest_to/from_ascii
362  *
363  * this version of the from text util does buffer length checking,
364  * and assumes a NULL terminated string.
365  */
366
367 gchar *md5_digest_to_text(guchar digest[16])
368 {
369         static gchar hex_digits[] = "0123456789abcdef";
370         gchar *result;
371         gint i;
372
373         result = g_malloc(33);
374         for (i = 0; i < 16; i++)
375                 {
376                 result[2*i] = hex_digits[digest[i] >> 4];
377                 result[2*i+1] = hex_digits[digest[i] & 0xf];
378                 }
379         result[32] = '\0';
380
381         return result;
382 }
383
384 gboolean md5_digest_from_text(const gchar *text, guchar digest[16])
385 {
386         gint i;
387
388         for (i = 0; i < 16; i++)
389                 {
390                 if (text[2*i] == '\0' || text[2*i+1] == '\0') return FALSE;
391                 digest[i] = g_ascii_xdigit_value(text[2*i]) << 4 |
392                             g_ascii_xdigit_value(text[2*i + 1]);
393         }
394
395         return TRUE;
396 }
397
398 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */