chiark / gitweb /
242e14ca68fd6eacb5e5a59d8aa0cb7f34712749
[become] / src / md5.c
1 /* -*-c-*-
2  *
3  * $Id: md5.c,v 1.3 1998/01/12 16:46:11 mdw Exp $
4  *
5  * MD-5 secure hash routines
6  *  Based on RSA MD-5 code
7  *
8  * (c) 1996-1998 Mark Wooding
9  */
10
11 /*----- Licensing notice --------------------------------------------------*
12  *
13  * This file is part of `become'
14  *
15  * `Become' is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * `Become' is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with `become'; if not, write to the Free Software Foundation,
27  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------*
31  *
32  * $Log: md5.c,v $
33  * Revision 1.3  1998/01/12 16:46:11  mdw
34  * Fix copyright date.
35  *
36  * Revision 1.2  1997/08/04 10:24:23  mdw
37  * Sources placed under CVS control.
38  *
39  * Revision 1.1  1997/07/21  13:47:47  mdw
40  * Initial revision
41  *
42  */
43
44 /*----- Header files ------------------------------------------------------*/
45
46 #include <stdio.h>
47 #include <string.h>
48
49 #include "config.h"
50 #include "md5.h"
51 #include "utils.h"
52
53 /*----- Define MD-5 transform ---------------------------------------------*/
54
55 /* --- Low-level nonlinear functions --- */
56
57 #define f(x,y,z) (((x) & (y)) | ((~x) & (z)))
58 #define g(x,y,z) (((x) & (z)) | ((y) & (~z)))
59 #define h(x,y,z) ((x) ^ (y) ^ (z))
60 #define i(x,y,z) ((y) ^ ((x) | (~z)))
61
62 #define rol(x,b) (((x) << (b)) | ((x) >> (32-(b))))
63
64 /* --- Rotations applied at various stages --- */
65
66 #define S11 7u
67 #define S12 12u
68 #define S13 17
69 #define S14 22u
70 #define S21 5u
71 #define S22 9u
72 #define S23 14u
73 #define S24 20u
74 #define S31 4u
75 #define S32 11u
76 #define S33 16u
77 #define S34 23u
78 #define S41 6u
79 #define S42 10u
80 #define S43 15u
81 #define S44 21u
82
83 /* --- Higher level nonlinear functions --- */
84
85 #define ff(a, b, c, d, x, s, m) ( a += f(b, c, d) + x + m,              \
86                                   a = rol(a, s), a += b )
87
88 #define gg(a, b, c, d, x, s, m) ( a += g(b, c, d) + x + m,              \
89                                   a = rol(a, s), a += b )
90
91 #define hh(a, b, c, d, x, s, m) ( a += h(b, c, d) + x + m,              \
92                                   a = rol(a, s), a += b )
93
94 #define ii(a, b, c, d, x, s, m) ( a += i(b, c, d) + x + m,              \
95                                   a = rol(a, s), a += b )
96
97 /*----- Main code ---------------------------------------------------------*/
98
99 /* --- @md5__trans@ --- *
100  *
101  * Arguments:   @uint_32 *v@ = pointer to chaining variables (updated)
102  *              @const unsigned char *buf@ = pointer to a 64-byte block
103  *
104  * Returns:     ---
105  *
106  * Use:         Performs the main MD5 transform on a block of data.
107  */
108
109 static void md5__trans(uint_32 *v, const unsigned char *buf)
110 {
111   uint_32 a, b, c, d;
112   uint_32 ib[16];
113   size_t i;
114
115   /* --- Initialise my internal registers --- */
116
117   a = v[0], b = v[1], c = v[2], d = v[3];
118
119   /* --- Turn the buffer into 32-bit words --- */
120
121   for (i = 0; i < 16; i++)
122     ib[i] = load32_l(buf + (i << 2));
123
124   /* --- Round one --- */
125
126   ff(a, b, c, d, ib[ 0], S11, 0xd76aa478);      /* 1 */
127   ff(d, a, b, c, ib[ 1], S12, 0xe8c7b756);      /* 2 */
128   ff(c, d, a, b, ib[ 2], S13, 0x242070db);      /* 3 */
129   ff(b, c, d, a, ib[ 3], S14, 0xc1bdceee);      /* 4 */
130   ff(a, b, c, d, ib[ 4], S11, 0xf57c0faf);      /* 5 */
131   ff(d, a, b, c, ib[ 5], S12, 0x4787c62a);      /* 6 */
132   ff(c, d, a, b, ib[ 6], S13, 0xa8304613);      /* 7 */
133   ff(b, c, d, a, ib[ 7], S14, 0xfd469501);      /* 8 */
134   ff(a, b, c, d, ib[ 8], S11, 0x698098d8);      /* 9 */
135   ff(d, a, b, c, ib[ 9], S12, 0x8b44f7af);      /* 10 */
136   ff(c, d, a, b, ib[10], S13, 0xffff5bb1);      /* 11 */
137   ff(b, c, d, a, ib[11], S14, 0x895cd7be);      /* 12 */
138   ff(a, b, c, d, ib[12], S11, 0x6b901122);      /* 13 */
139   ff(d, a, b, c, ib[13], S12, 0xfd987193);      /* 14 */
140   ff(c, d, a, b, ib[14], S13, 0xa679438e);      /* 15 */
141   ff(b, c, d, a, ib[15], S14, 0x49b40821);      /* 16 */
142
143   /* --- Round two --- */
144
145   gg(a, b, c, d, ib[ 1], S21, 0xf61e2562);      /* 17 */
146   gg(d, a, b, c, ib[ 6], S22, 0xc040b340);      /* 18 */
147   gg(c, d, a, b, ib[11], S23, 0x265e5a51);      /* 19 */
148   gg(b, c, d, a, ib[ 0], S24, 0xe9b6c7aa);      /* 20 */
149   gg(a, b, c, d, ib[ 5], S21, 0xd62f105d);      /* 21 */
150   gg(d, a, b, c, ib[10], S22, 0x02441453);      /* 22 */
151   gg(c, d, a, b, ib[15], S23, 0xd8a1e681);      /* 23 */
152   gg(b, c, d, a, ib[ 4], S24, 0xe7d3fbc8);      /* 24 */
153   gg(a, b, c, d, ib[ 9], S21, 0x21e1cde6);      /* 25 */
154   gg(d, a, b, c, ib[14], S22, 0xc33707d6);      /* 26 */
155   gg(c, d, a, b, ib[ 3], S23, 0xf4d50d87);      /* 27 */
156   gg(b, c, d, a, ib[ 8], S24, 0x455a14ed);      /* 28 */
157   gg(a, b, c, d, ib[13], S21, 0xa9e3e905);      /* 29 */
158   gg(d, a, b, c, ib[ 2], S22, 0xfcefa3f8);      /* 30 */
159   gg(c, d, a, b, ib[ 7], S23, 0x676f02d9);      /* 31 */
160   gg(b, c, d, a, ib[12], S24, 0x8d2a4c8a);      /* 32 */
161
162   /* --- Round three --- */
163
164   hh(a, b, c, d, ib[ 5], S31, 0xfffa3942);      /* 33 */
165   hh(d, a, b, c, ib[ 8], S32, 0x8771f681);      /* 34 */
166   hh(c, d, a, b, ib[11], S33, 0x6d9d6122);      /* 35 */
167   hh(b, c, d, a, ib[14], S34, 0xfde5380c);      /* 36 */
168   hh(a, b, c, d, ib[ 1], S31, 0xa4beea44);      /* 37 */
169   hh(d, a, b, c, ib[ 4], S32, 0x4bdecfa9);      /* 38 */
170   hh(c, d, a, b, ib[ 7], S33, 0xf6bb4b60);      /* 39 */
171   hh(b, c, d, a, ib[10], S34, 0xbebfbc70);      /* 40 */
172   hh(a, b, c, d, ib[13], S31, 0x289b7ec6);      /* 41 */
173   hh(d, a, b, c, ib[ 0], S32, 0xeaa127fa);      /* 42 */
174   hh(c, d, a, b, ib[ 3], S33, 0xd4ef3085);      /* 43 */
175   hh(b, c, d, a, ib[ 6], S34, 0x04881d05);      /* 44 */
176   hh(a, b, c, d, ib[ 9], S31, 0xd9d4d039);      /* 45 */
177   hh(d, a, b, c, ib[12], S32, 0xe6db99e5);      /* 46 */
178   hh(c, d, a, b, ib[15], S33, 0x1fa27cf8);      /* 47 */
179   hh(b, c, d, a, ib[ 2], S34, 0xc4ac5665);      /* 48 */
180
181   /* --- Round four --- */
182
183   ii(a, b, c, d, ib[ 0], S41, 0xf4292244);      /* 49 */
184   ii(d, a, b, c, ib[ 7], S42, 0x432aff97);      /* 50 */
185   ii(c, d, a, b, ib[14], S43, 0xab9423a7);      /* 51 */
186   ii(b, c, d, a, ib[ 5], S44, 0xfc93a039);      /* 52 */
187   ii(a, b, c, d, ib[12], S41, 0x655b59c3);      /* 53 */
188   ii(d, a, b, c, ib[ 3], S42, 0x8f0ccc92);      /* 54 */
189   ii(c, d, a, b, ib[10], S43, 0xffeff47d);      /* 55 */
190   ii(b, c, d, a, ib[ 1], S44, 0x85845dd1);      /* 56 */
191   ii(a, b, c, d, ib[ 8], S41, 0x6fa87e4f);      /* 57 */
192   ii(d, a, b, c, ib[15], S42, 0xfe2ce6e0);      /* 58 */
193   ii(c, d, a, b, ib[ 6], S43, 0xa3014314);      /* 59 */
194   ii(b, c, d, a, ib[13], S44, 0x4e0811a1);      /* 60 */
195   ii(a, b, c, d, ib[ 4], S41, 0xf7537e82);      /* 61 */
196   ii(d, a, b, c, ib[11], S42, 0xbd3af235);      /* 62 */
197   ii(c, d, a, b, ib[ 2], S43, 0x2ad7d2bb);      /* 63 */
198   ii(b, c, d, a, ib[ 9], S44, 0xeb86d391);      /* 64 */
199
200   /* --- Update the context --- */
201
202   v[0] += a, v[1] += b, v[2] += c, v[3] += d;
203 }
204
205 /* --- @md5_trans@ --- *
206  *
207  * Arguments:   @unsigned char *v@ = pointer to chaining block (updated)
208  *              @const unsigned char *buf@ = pointer to input buffer
209  *
210  * Returns:     ---
211  *
212  * Use:         Performs the MD5 transformation on a chunk of data.  This may
213  *              be useful for using MD5 in MDC-type cipher constructions.
214  */
215
216 void md5_trans(unsigned char *v, const unsigned char *buf)
217 {
218   uint_32 vv[4];
219
220   vv[0] = load32_l(v +  0);
221   vv[1] = load32_l(v +  4);
222   vv[2] = load32_l(v +  8);
223   vv[3] = load32_l(v + 12);
224   md5__trans(vv, buf);
225   store32_l(v +  0, vv[0]);
226   store32_l(v +  4, vv[1]);
227   store32_l(v +  8, vv[2]);
228   store32_l(v + 12, vv[3]);
229 }
230
231 /* --- @md5_buffer@ --- *
232  *
233  * Arguments:   @md5 *m@ = pointer to an MD5 context
234  *              @const void *buff@ = pointer to buffer of data
235  *              @size_t size@ = size of buffer
236  *
237  * Returns:     ---
238  *
239  * Use:         Hashes the buffer of data.  You can call @md5_buffer@
240  *              lots of times during an MD5 job, to allow big files to be
241  *              split into little ones.
242  */
243
244 void md5_buffer(md5 *m, const void *buff, size_t size)
245 {
246   long int s = size;
247   const unsigned char *b = buff;
248   unsigned long x, y;
249
250   /* --- Maybe there's some data already in the buffer --- */
251
252   if (x = m->size & 63, x) {
253     y = 64 - x;
254     if (y > s) {
255       memcpy(x + m->buf, b, s);
256       m->size += s;
257       return;
258     }
259     memcpy(x + m->buf, b, y);
260     md5__trans(m->val, m->buf);
261     s -= y, b += y;
262   }
263
264   /* --- Now do whole buffers-full --- */
265
266   while (s >= 64) {
267     md5__trans(m->val, b);
268     s -= 64, b += 64;
269   }
270
271   /* --- Tidy up the tail end --- */
272
273   if (s)
274     memcpy(m->buf, b, s);
275   m->size += size;
276 }
277
278 /* --- @md5_key@ --- *
279  *
280  * Arguments:   @md5 *m@ = pointer to an MD5 context
281  *              @const unsigned char *k@ = pointer to a 4-word `key'
282  *
283  * Returns:     ---
284  *
285  * Use:         Initialises a context buffer, with a chosen initialisation
286  *              string (instead of the standard MD5 value).  This allows you
287  *              to use NMAC message authentication, should the urge take you.
288  */
289
290 void md5_key(md5 *m, const unsigned char *k)
291 {
292   m->size = 0;
293   m->val[0] = load32_l(k +  0);
294   m->val[0] = load32_l(k +  4);
295   m->val[0] = load32_l(k +  8);
296   m->val[0] = load32_l(k + 12);
297 }
298
299 /* --- @md5_init@ --- *
300  *
301  * Arguments:   @md5 *m@ = pointer to an MD5 context
302  *
303  * Returns:     ---
304  *
305  * Use:         Initialises the context buffer, so that you can do an
306  *              MD5 job.
307  */
308
309 void md5_init(md5 *m)
310 {
311   m->size = 0;
312   m->val[0] = 0x67452301;
313   m->val[1] = 0xefcdab89;
314   m->val[2] = 0x98badcfe;
315   m->val[3] = 0x10325476;
316 }
317
318 /* --- @md5_final@ --- *
319  *
320  * Arguments:   @md5 *m@ = pointer to context buffer
321  *              @unsigned char *v@ = where to store the value
322  *
323  * Returns:     ---
324  *
325  * Use:         Finalises an MD5 buffer, so that you can use the result.
326  */
327
328 void md5_final(md5 *m, unsigned char *v)
329 {
330   int s = m->size;
331
332   /* --- Pad out the block --- */
333
334   {
335     const static unsigned char pad[64] = { 0x80 };
336     int p = m->size & 63;
337     p = (p < 56) ? (p = 56 - p) : (p = 120 - p);
338     md5_buffer(m, pad, p);
339   }
340
341   /* --- Append the length --- */
342
343   {
344     unsigned char b[8];
345
346     store32_l(b + 0, s << 3);
347     store32_l(b + 4, s >> 29);
348     md5_buffer(m, b, 8);
349   }
350
351   /* --- Write out the value --- */
352
353   if (v) {
354     store32_l(v +  0, m->val[0]);
355     store32_l(v +  4, m->val[1]);
356     store32_l(v +  8, m->val[2]);
357     store32_l(v + 12, m->val[3]);
358   }
359 }
360
361 /*----- Test driver -------------------------------------------------------*/
362
363 #ifdef TEST_RIG
364
365 int main(int argc, char *argv[])
366 {
367   if (argc > 1 && strcmp(argv[1], "-x") == 0) {
368
369     static struct {
370       const char *string;
371       uint_32 md[4];
372     } table[] = {
373       "",               { 0xd98c1dd4, 0x04b2008f, 0x980980e9, 0x7e42f8ec },
374       "a",              { 0xb975c10c, 0xa8b6f1c0, 0xe299c331, 0x61267769 },
375       "abc",            { 0x98500190, 0xb04fd23c, 0x7d3f96d6, 0x727fe128 },
376       "message digest", { 0x7d696bf9, 0x8d93b77c, 0x312f5a52, 0xd061f1aa },
377       "abcdefghijklmnopqrstuvwxyz",
378                         { 0xd7d3fcc3, 0x00e49261, 0x6c49fb7d, 0x3be167ca },
379       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
380                         { 0x98ab74d1, 0xf5d977d2, 0x2c1c61a5, 0x9f9d419f },
381       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
382       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
383       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
384       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
385       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
386       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
387       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
388       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
389       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
390       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
391       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
392       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
393       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
394       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
395       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
396       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
397       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
398       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
399       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
400       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
401       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
402       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"
403       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n",
404                         { 0xbaa7652b, 0x5e10cd4a, 0xde9acbf2, 0xfa0b9fbd }
405     };
406     int steptbl[] = { 3, 18, 32, 37, 63, 64, 65, 256, 1024, -1 };
407
408     md5 m;
409     int i, j;
410     const char *p;
411     size_t sz, a, d;
412     int f = 1;
413
414     for (i = 0; i < sizeof(table) / sizeof(table[0]); i++) {
415       sz = strlen(table[i].string);
416       for (j = 0; steptbl[j] < sz && steptbl[j] != -1; j++) {
417         p = table[i].string;
418         d = steptbl[j];
419         md5_init(&m);
420         for (a = sz; a > d; a -= d) {
421           md5_buffer(&m, p, d);
422           p += d;
423         }
424         md5_buffer(&m, p, a);
425         md5_final(&m, 0);
426         if (m.val[0] != table[i].md[0] ||
427             m.val[1] != table[i].md[1] ||
428             m.val[2] != table[i].md[2] ||
429             m.val[3] != table[i].md[3]) {
430           printf("!!! bad value, string == `%s', step size == %i\n"
431                  "!!! expected %08lx-%08lx-%08lx-%08lx, found "
432                  "%08lx-%08lx-%08lx-%08lx\n\n",
433                  table[i].string, d,
434                  (unsigned long)table[i].md[0],
435                  (unsigned long)table[i].md[1],
436                  (unsigned long)table[i].md[2],
437                  (unsigned long)table[i].md[3],
438                  (unsigned long)m.val[0],
439                  (unsigned long)m.val[1],
440                  (unsigned long)m.val[2],
441                  (unsigned long)m.val[3]);
442           f = 0;
443         }
444       }
445       md5_init(&m);
446       md5_buffer(&m, table[i].string, sz);
447       md5_final(&m, 0);
448       if (m.val[0] != table[i].md[0] ||
449           m.val[1] != table[i].md[1] ||
450           m.val[2] != table[i].md[2] ||
451           m.val[3] != table[i].md[3]) {
452         printf("!!! bad value, string == `%s', step size == entire string\n"
453                "!!! expected %08lx-%08lx-%08lx-%08lx, found "
454                "%08lx-%08lx-%08lx-%08lx\n\n",
455                table[i].string,
456                (unsigned long)table[i].md[0],
457                (unsigned long)table[i].md[1],
458                (unsigned long)table[i].md[2],
459                (unsigned long)table[i].md[3],
460                (unsigned long)m.val[0],
461                (unsigned long)m.val[1],
462                (unsigned long)m.val[2],
463                (unsigned long)m.val[3]);
464         f = 0;
465       } else {
466         printf("`%s' => %08lx-%08lx-%08lx-%08lx\n",
467                table[i].string,
468                (unsigned long)m.val[0],
469                (unsigned long)m.val[1],
470                (unsigned long)m.val[2],
471                (unsigned long)m.val[3]);
472       }
473     }
474     
475   } else {
476
477     char buff[4096];
478     md5 m;
479     int i;
480     int read;
481
482     md5_init(&m);
483     while (read = fread(buff, 1, 4096, stdin), read)
484       md5_buffer(&m, buff, read);
485     md5_final(&m, 0);
486
487     for (i = 0; i < 4; i++)
488       printf("%02lx%02lx%02lx%02lx",
489              (unsigned long)( (m.val[i] & 0x000000FF) >>  0 ),
490              (unsigned long)( (m.val[i] & 0x0000FF00) >>  8 ),
491              (unsigned long)( (m.val[i] & 0x00FF0000) >> 16 ),
492              (unsigned long)( (m.val[i] & 0xFF000000) >> 24 ));
493     putc('\n', stdout);
494
495   }
496
497   return (0);
498 }
499
500 #endif
501
502 /*----- That's all, folks -------------------------------------------------*/