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