comparison lphobos/std/md5.d @ 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents
children
comparison
equal deleted inserted replaced
472:15c804b6ce77 473:373489eeaf90
1 /* md5.d - RSA Data Security, Inc., MD5 message-digest algorithm
2 * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
3 */
4
5 /**
6 * Computes MD5 digests of arbitrary data. MD5 digests are 16 byte quantities that are like a checksum or crc, but are more robust.
7 *
8 * There are two ways to do this. The first does it all in one function call to
9 * sum(). The second is for when the data is buffered.
10 *
11 * Bugs:
12 * MD5 digests have been demonstrated to not be unique.
13 *
14 * Author:
15 * The routines and algorithms are derived from the
16 * $(I RSA Data Security, Inc. MD5 Message-Digest Algorithm).
17 *
18 * References:
19 * $(LINK2 http://en.wikipedia.org/wiki/Md5, Wikipedia on MD5)
20 *
21 * Macros:
22 * WIKI = Phobos/StdMd5
23 */
24
25 /++++++++++++++++++++++++++++++++
26 Example:
27
28 --------------------
29 // This code is derived from the
30 // RSA Data Security, Inc. MD5 Message-Digest Algorithm.
31
32 import std.md5;
33
34 private import std.stdio;
35 private import std.string;
36 private import std.c.stdio;
37 private import std.c.string;
38
39 int main(char[][] args)
40 {
41 foreach (char[] arg; args)
42 MDFile(arg);
43 return 0;
44 }
45
46 /* Digests a file and prints the result. */
47 void MDFile(char[] filename)
48 {
49 FILE* file;
50 MD5_CTX context;
51 int len;
52 ubyte[4 * 1024] buffer;
53 ubyte digest[16];
54
55 if ((file = fopen(std.string.toStringz(filename), "rb")) == null)
56 writefln("%s can't be opened", filename);
57 else
58 {
59 context.start();
60 while ((len = fread(buffer, 1, buffer.sizeof, file)) != 0)
61 context.update(buffer[0 .. len]);
62 context.finish(digest);
63 fclose(file);
64
65 writefln("MD5 (%s) = %s", filename, digestToString(digest));
66 }
67 }
68 --------------------
69 +/
70
71 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
72 rights reserved.
73
74 License to copy and use this software is granted provided that it
75 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
76 Algorithm" in all material mentioning or referencing this software
77 or this function.
78
79 License is also granted to make and use derivative works provided
80 that such works are identified as "derived from the RSA Data
81 Security, Inc. MD5 Message-Digest Algorithm" in all material
82 mentioning or referencing the derived work.
83
84 RSA Data Security, Inc. makes no representations concerning either
85 the merchantability of this software or the suitability of this
86 software for any particular purpose. It is provided "as is"
87 without express or implied warranty of any kind.
88 These notices must be retained in any copies of any part of this
89 documentation and/or software.
90 */
91
92 /* NOTE: This file has been patched from the original DMD distribution to
93 work with the GDC compiler.
94
95 Modified by David Friedman, September 2004
96 */
97
98 module std.md5;
99
100 //debug=md5; // uncomment to turn on debugging printf's
101
102 import std.string;
103
104 version(D_InlineAsm)
105 version(X86)
106 version = Asm86;
107
108 /***************************************
109 * Computes MD5 digest of array of data.
110 */
111
112 void sum(ubyte[16] digest, void[] data)
113 {
114 MD5_CTX context;
115
116 context.start();
117 context.update(data);
118 context.finish(digest);
119 }
120
121 /******************
122 * Prints a message digest in hexadecimal to stdout.
123 */
124 void printDigest(ubyte digest[16])
125 {
126 foreach (ubyte u; digest)
127 printf("%02x", u);
128 }
129
130 /****************************************
131 * Converts MD5 digest to a string.
132 */
133
134 char[] digestToString(ubyte[16] digest)
135 {
136 char[] result = new char[32];
137 int i;
138
139 foreach (ubyte u; digest)
140 {
141 result[i] = std.string.hexdigits[u >> 4];
142 result[i + 1] = std.string.hexdigits[u & 15];
143 i += 2;
144 }
145 return result;
146 }
147
148 /**
149 * Holds context of MD5 computation.
150 *
151 * Used when data to be digested is buffered.
152 */
153 struct MD5_CTX
154 {
155 uint state[4] = /* state (ABCD) */
156 /* magic initialization constants */
157 [0x67452301,0xefcdab89,0x98badcfe,0x10325476];
158
159 ulong count; /* number of bits, modulo 2^64 */
160 ubyte buffer[64]; /* input buffer */
161
162 static ubyte[64] PADDING =
163 [
164 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
167 ];
168
169 /* F, G, H and I are basic MD5 functions.
170 */
171 private static
172 {
173 uint F(uint x, uint y, uint z) { return (x & y) | (~x & z); }
174 uint G(uint x, uint y, uint z) { return (x & z) | (y & ~z); }
175 uint H(uint x, uint y, uint z) { return x ^ y ^ z; }
176 uint I(uint x, uint y, uint z) { return y ^ (x | ~z); }
177 }
178
179 /* ROTATE_LEFT rotates x left n bits.
180 */
181 static uint ROTATE_LEFT(uint x, uint n)
182 {
183 version (Asm86)
184 {
185 version (GNU)
186 {
187 asm
188 {
189 naked ;
190 mov ECX, n ;
191 mov EAX, x ;
192 rol EAX, CL ;
193 ret ;
194 }
195 }
196 else
197 {
198 asm
199 { naked ;
200 mov ECX,EAX ;
201 mov EAX,4[ESP] ;
202 rol EAX,CL ;
203 ret 4 ;
204 }
205 }
206 }
207 else
208 {
209 return (x << n) | (x >> (32-n));
210 }
211 }
212
213 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
214 * Rotation is separate from addition to prevent recomputation.
215 */
216 static void FF(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
217 {
218 a += F (b, c, d) + x + cast(uint)(ac);
219 a = ROTATE_LEFT (a, s);
220 a += b;
221 }
222
223 static void GG(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
224 {
225 a += G (b, c, d) + x + cast(uint)(ac);
226 a = ROTATE_LEFT (a, s);
227 a += b;
228 }
229
230 static void HH(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
231 {
232 a += H (b, c, d) + x + cast(uint)(ac);
233 a = ROTATE_LEFT (a, s);
234 a += b;
235 }
236
237 static void II(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
238 {
239 a += I (b, c, d) + x + cast(uint)(ac);
240 a = ROTATE_LEFT (a, s);
241 a += b;
242 }
243
244 /**
245 * MD5 initialization. Begins an MD5 operation, writing a new context.
246 */
247 void start()
248 {
249 *this = MD5_CTX.init;
250 }
251
252 /** MD5 block update operation. Continues an MD5 message-digest
253 operation, processing another message block, and updating the
254 context.
255 */
256 void update(void[] input)
257 {
258 uint index, partLen;
259 size_t i;
260 size_t inputLen = input.length;
261
262 /* Compute number of bytes mod 64 */
263 index = (cast(uint)count >> 3) & (64 - 1);
264
265 /* Update number of bits */
266 count += inputLen * 8;
267
268 partLen = 64 - index;
269
270 /* Transform as many times as possible. */
271 if (inputLen >= partLen)
272 {
273 std.c.string.memcpy(&buffer[index], input.ptr, partLen);
274 transform (buffer.ptr);
275
276 for (i = partLen; i + 63 < inputLen; i += 64)
277 transform ((cast(ubyte[])input)[i .. i + 64].ptr);
278
279 index = 0;
280 }
281 else
282 i = 0;
283
284 /* Buffer remaining input */
285 if (inputLen - i)
286 std.c.string.memcpy(&buffer[index], &input[i], inputLen-i);
287 }
288
289 /** MD5 finalization. Ends an MD5 message-digest operation, writing the
290 * the message to digest and zeroing the context.
291 */
292 void finish(ubyte[16] digest) /* message digest */
293 {
294 ubyte bits[8];
295 uint index, padLen;
296 uint[2] cnt;
297
298 /* Save number of bits */
299 cnt[0] = cast(uint)count;
300 cnt[1] = cast(uint)(count >> 32);
301 Encode (bits.ptr, cnt.ptr, 8);
302
303 /* Pad out to 56 mod 64. */
304 index = (cast(uint)count >> 3) & (64 - 1);
305 padLen = (index < 56) ? (56 - index) : (120 - index);
306 update (PADDING[0 .. padLen]);
307
308 /* Append length (before padding) */
309 update (bits);
310
311 /* Store state in digest */
312 Encode (digest.ptr, state.ptr, 16);
313
314 /* Zeroize sensitive information. */
315 std.c.string.memset (this, 0, MD5_CTX.sizeof);
316 }
317
318 /* MD5 basic transformation. Transforms state based on block.
319 */
320
321 /* Constants for MD5Transform routine. */
322 enum
323 {
324 S11 = 7,
325 S12 = 12,
326 S13 = 17,
327 S14 = 22,
328 S21 = 5,
329 S22 = 9,
330 S23 = 14,
331 S24 = 20,
332 S31 = 4,
333 S32 = 11,
334 S33 = 16,
335 S34 = 23,
336 S41 = 6,
337 S42 = 10,
338 S43 = 15,
339 S44 = 21,
340 }
341
342 private void transform (ubyte* /*[64]*/ block)
343 {
344 uint a = state[0],
345 b = state[1],
346 c = state[2],
347 d = state[3];
348 uint[16] x;
349
350 Decode (x.ptr, block, 64);
351
352 /* Round 1 */
353 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
354 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
355 FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
356 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
357 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
358 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
359 FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
360 FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
361 FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
362 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
363 FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
364 FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
365 FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
366 FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
367 FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
368 FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
369
370 /* Round 2 */
371 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
372 GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
373 GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
374 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
375 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
376 GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
377 GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
378 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
379 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
380 GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
381 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
382 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
383 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
384 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
385 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
386 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
387
388 /* Round 3 */
389 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
390 HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
391 HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
392 HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
393 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
394 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
395 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
396 HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
397 HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
398 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
399 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
400 HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
401 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
402 HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
403 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
404 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
405
406 /* Round 4 */
407 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
408 II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
409 II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
410 II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
411 II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
412 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
413 II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
414 II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
415 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
416 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
417 II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
418 II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
419 II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
420 II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
421 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
422 II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
423
424 state[0] += a;
425 state[1] += b;
426 state[2] += c;
427 state[3] += d;
428
429 /* Zeroize sensitive information. */
430 x[] = 0;
431 }
432
433 /* Encodes input (uint) into output (ubyte). Assumes len is
434 a multiple of 4.
435 */
436 private static void Encode (ubyte *output, uint *input, uint len)
437 {
438 uint i, j;
439
440 for (i = 0, j = 0; j < len; i++, j += 4)
441 {
442 uint u = input[i];
443 output[j] = cast(ubyte)(u);
444 output[j+1] = cast(ubyte)(u >> 8);
445 output[j+2] = cast(ubyte)(u >> 16);
446 output[j+3] = cast(ubyte)(u >> 24);
447 }
448 }
449
450 /* Decodes input (ubyte) into output (uint). Assumes len is
451 a multiple of 4.
452 */
453 private static void Decode (uint *output, ubyte *input, uint len)
454 {
455 uint i, j;
456
457 for (i = 0, j = 0; j < len; i++, j += 4)
458 {
459 version (LittleEndian)
460 {
461 output[i] = *cast(uint*)&input[j];
462 }
463 else
464 {
465 output[i] = (cast(uint)input[j]) | ((cast(uint)input[j+1]) << 8) |
466 ((cast(uint)input[j+2]) << 16) | ((cast(uint)input[j+3]) << 24);
467 }
468 }
469 }
470 }
471
472 unittest
473 {
474 debug(md5) printf("std.md5.unittest\n");
475
476 ubyte[16] digest;
477
478 sum (digest, "");
479 assert(digest == cast(ubyte[])x"d41d8cd98f00b204e9800998ecf8427e");
480
481 sum (digest, "a");
482 assert(digest == cast(ubyte[])x"0cc175b9c0f1b6a831c399e269772661");
483
484 sum (digest, "abc");
485 assert(digest == cast(ubyte[])x"900150983cd24fb0d6963f7d28e17f72");
486
487 sum (digest, "message digest");
488 assert(digest == cast(ubyte[])x"f96b697d7cb7938d525a2f31aaf161d0");
489
490 sum (digest, "abcdefghijklmnopqrstuvwxyz");
491 assert(digest == cast(ubyte[])x"c3fcd3d76192e4007dfb496cca67e13b");
492
493 sum (digest, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
494 assert(digest == cast(ubyte[])x"d174ab98d277d9f5a5611c2c9f419d9f");
495
496 sum (digest,
497 "1234567890123456789012345678901234567890"
498 "1234567890123456789012345678901234567890");
499 assert(digest == cast(ubyte[])x"57edf4a22be3c955ac49da2e2107b67a");
500
501 assert(digestToString(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b")
502 == "C3FCD3D76192E4007DFB496CCA67E13B");
503 }
504