1 /**
2  * Computes MD5 hashes of arbitrary data. MD5 hashes are 16 byte quantities that are like a
3  * checksum or CRC, but are more robust.
4  *
5 $(SCRIPT inhibitQuickIndex = 1;)
6 
7 $(DIVC quickindex,
8 $(BOOKTABLE ,
9 $(TR $(TH Category) $(TH Functions)
10 )
11 $(TR $(TDNW Template API) $(TD $(MYREF MD5)
12 )
13 )
14 $(TR $(TDNW OOP API) $(TD $(MYREF MD5Digest))
15 )
16 $(TR $(TDNW Helpers) $(TD $(MYREF md5Of))
17 )
18 )
19 )
20 
21  * This module conforms to the APIs defined in `std.digest`. To understand the
22  * differences between the template and the OOP API, see $(MREF std, digest).
23  *
24  * This module publicly imports $(MREF std, digest) and can be used as a stand-alone
25  * module.
26  *
27  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
28  *
29  * CTFE:
30  * Digests do not work in CTFE
31  *
32  * Authors:
33  * Piotr Szturmaj, Kai Nacke, Johannes Pfau $(BR)
34  * The routines and algorithms are derived from the $(I RSA Data Security, Inc. MD5 Message-Digest Algorithm).
35  *
36  * References:
37  *      $(LINK2 http://en.wikipedia.org/wiki/Md5, Wikipedia on MD5)
38  *
39  * Source: $(PHOBOSSRC std/digest/md.d)
40  *
41  */
42 
43 /* md5.d - RSA Data Security, Inc., MD5 message-digest algorithm
44  * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
45  */
46 module std.digest.md;
47 
48 public import std.digest;
49 
50 ///
51 @safe unittest
52 {
53     //Template API
54     import std.digest.md;
55 
56     //Feeding data
57     ubyte[1024] data;
58     MD5 md5;
59     md5.start();
60     md5.put(data[]);
61     md5.start(); //Start again
62     md5.put(data[]);
63     auto hash = md5.finish();
64 }
65 
66 ///
67 @safe unittest
68 {
69     //OOP API
70     import std.digest.md;
71 
72     auto md5 = new MD5Digest();
73     ubyte[] hash = md5.digest("abc");
74     assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72");
75 
76     //Feeding data
77     ubyte[1024] data;
78     md5.put(data[]);
79     md5.reset(); //Start again
80     md5.put(data[]);
81     hash = md5.finish();
82 }
83 
84 //rotateLeft rotates x left n bits
85 private uint rotateLeft(uint x, uint n) @safe pure nothrow @nogc
86 {
87     // With recently added optimization to DMD (commit 32ea0206 at 07/28/11), this is translated to rol.
88     // No assembler required.
89     return (x << n) | (x >> (32-n));
90 }
91 
92 /**
93  * Template API MD5 implementation.
94  * See `std.digest` for differences between template and OOP API.
95  */
96 struct MD5
97 {
98     private:
99         // magic initialization constants
100         uint[4] _state = [0x67452301,0xefcdab89,0x98badcfe,0x10325476]; // state (ABCD)
101         ulong _count; //number of bits, modulo 2^64
102         ubyte[64] _buffer; // input buffer
103 
104         static immutable ubyte[64] _padding =
105         [
106           0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
109         ];
110 
111         // F, G, H and I are basic MD5 functions
112         static @safe pure nothrow @nogc
113         {
114             uint F(uint x, uint y, uint z) { return (x & y) | (~x & z); }
115             uint G(uint x, uint y, uint z) { return (x & z) | (y & ~z); }
116             uint H(uint x, uint y, uint z) { return x ^ y ^ z; }
117             uint I(uint x, uint y, uint z) { return y ^ (x | ~z); }
118         }
119 
120 
121         /*
122          * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
123          * Rotation is separate from addition to prevent recomputation.
124          */
125         static void FF(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
126             @safe pure nothrow @nogc
127         {
128             a += F (b, c, d) + x + ac;
129             a = rotateLeft(a, s);
130             a += b;
131         }
132 
133         static void GG(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
134             @safe pure nothrow @nogc
135         {
136             a += G (b, c, d) + x + ac;
137             a = rotateLeft(a, s);
138             a += b;
139         }
140 
141         static void HH(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
142             @safe pure nothrow @nogc
143         {
144             a += H (b, c, d) + x + ac;
145             a = rotateLeft(a, s);
146             a += b;
147         }
148 
149         static void II(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
150             @safe pure nothrow @nogc
151         {
152             a += I (b, c, d) + x + ac;
153             a = rotateLeft(a, s);
154             a += b;
155         }
156 
157         /*
158          * MD5 basic transformation. Transforms state based on block.
159          */
160 
161         //Constants for MD5Transform routine.
162         enum
163         {
164             S11 = 7,
165             S12 = 12,
166             S13 = 17,
167             S14 = 22,
168             S21 = 5,
169             S22 = 9,
170             S23 = 14,
171             S24 = 20,
172             S31 = 4,
173             S32 = 11,
174             S33 = 16,
175             S34 = 23,
176             S41 = 6,
177             S42 = 10,
178             S43 = 15,
179             S44 = 21,
180         }
181 
182         private void transform(const(ubyte[64])* block) pure nothrow @nogc
183         {
184             uint a = _state[0],
185                  b = _state[1],
186                  c = _state[2],
187                  d = _state[3];
188 
189             uint[16] x = void;
190 
191             version (BigEndian)
192             {
193                 import std.bitmanip : littleEndianToNative;
194 
195                 for (size_t i = 0; i < 16; i++)
196                 {
197                     x[i] = littleEndianToNative!uint(*cast(ubyte[4]*)&(*block)[i*4]);
198                 }
199             }
200             else
201             {
202                 (cast(ubyte*) x.ptr)[0 .. 64] = (cast(ubyte*) block)[0 .. 64];
203             }
204 
205             //Round 1
206             FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
207             FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
208             FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
209             FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
210             FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
211             FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
212             FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
213             FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
214             FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
215             FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
216             FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
217             FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
218             FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
219             FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
220             FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
221             FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
222 
223             //Round 2
224             GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
225             GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
226             GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
227             GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
228             GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
229             GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
230             GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
231             GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
232             GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
233             GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
234             GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
235             GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
236             GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
237             GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
238             GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
239             GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
240 
241             //Round 3
242             HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
243             HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
244             HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
245             HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
246             HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
247             HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
248             HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
249             HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
250             HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
251             HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
252             HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
253             HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
254             HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
255             HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
256             HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
257             HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
258 
259             //Round 4
260             II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
261             II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
262             II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
263             II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
264             II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
265             II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
266             II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
267             II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
268             II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
269             II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
270             II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
271             II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
272             II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
273             II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
274             II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
275             II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
276 
277             _state[0] += a;
278             _state[1] += b;
279             _state[2] += c;
280             _state[3] += d;
281 
282             //Zeroize sensitive information.
283             x[] = 0;
284         }
285 
286     public:
287         enum blockSize = 512;
288 
289         /**
290          * Use this to feed the digest with data.
291          * Also implements the $(REF isOutputRange, std,range,primitives)
292          * interface for `ubyte` and `const(ubyte)[]`.
293          *
294          * Example:
295          * ----
296          * MD5 dig;
297          * dig.put(cast(ubyte) 0); //single ubyte
298          * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic
299          * ubyte[10] buf;
300          * dig.put(buf); //buffer
301          * ----
302          */
303         void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc
304         {
305             uint i, index, partLen;
306             auto inputLen = data.length;
307 
308             //Compute number of bytes mod 64
309             index = (cast(uint)_count >> 3) & (64 - 1);
310 
311             //Update number of bits
312             _count += inputLen * 8;
313 
314             partLen = 64 - index;
315 
316             //Transform as many times as possible
317             if (inputLen >= partLen)
318             {
319                 (&_buffer[index])[0 .. partLen] = data.ptr[0 .. partLen];
320                 transform(&_buffer);
321 
322                 for (i = partLen; i + 63 < inputLen; i += 64)
323                 {
324                     transform(cast(const(ubyte[64])*)(data[i .. i + 64].ptr));
325                 }
326 
327                 index = 0;
328             }
329             else
330             {
331                 i = 0;
332             }
333 
334             /* Buffer remaining input */
335             if (inputLen - i)
336                 (&_buffer[index])[0 .. inputLen-i] = (&data[i])[0 .. inputLen-i];
337         }
338 
339         /**
340          * Used to (re)initialize the MD5 digest.
341          *
342          * Note:
343          * For this MD5 Digest implementation calling start after default construction
344          * is not necessary. Calling start is only necessary to reset the Digest.
345          *
346          * Generic code which deals with different Digest types should always call start though.
347          *
348          * Example:
349          * --------
350          * MD5 digest;
351          * //digest.start(); //Not necessary
352          * digest.put(0);
353          * --------
354          */
355         void start() @safe pure nothrow @nogc
356         {
357             this = MD5.init;
358         }
359 
360         /**
361          * Returns the finished MD5 hash. This also calls $(LREF start) to
362          * reset the internal state.
363           */
364         ubyte[16] finish() @trusted pure nothrow @nogc
365         {
366             import std.bitmanip : nativeToLittleEndian;
367 
368             ubyte[16] data = void;
369             ubyte[8] bits = void;
370             uint index, padLen;
371 
372             //Save number of bits
373             bits[0 .. 8] = nativeToLittleEndian(_count)[];
374 
375             //Pad out to 56 mod 64
376             index = (cast(uint)_count >> 3) & (64 - 1);
377             padLen = (index < 56) ? (56 - index) : (120 - index);
378             put(_padding[0 .. padLen]);
379 
380             //Append length (before padding)
381             put(bits);
382 
383             //Store state in digest
384             data[0 .. 4]   = nativeToLittleEndian(_state[0])[];
385             data[4 .. 8]   = nativeToLittleEndian(_state[1])[];
386             data[8 .. 12]  = nativeToLittleEndian(_state[2])[];
387             data[12 .. 16] = nativeToLittleEndian(_state[3])[];
388 
389             /* Zeroize sensitive information. */
390             start();
391             return data;
392         }
393         ///
394         @safe unittest
395         {
396             //Simple example
397             MD5 hash;
398             hash.start();
399             hash.put(cast(ubyte) 0);
400             ubyte[16] result = hash.finish();
401         }
402 }
403 
404 ///
405 @safe unittest
406 {
407     //Simple example, hashing a string using md5Of helper function
408     ubyte[16] hash = md5Of("abc");
409     //Let's get a hash string
410     assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72");
411 }
412 
413 ///
414 @safe unittest
415 {
416     //Using the basic API
417     MD5 hash;
418     hash.start();
419     ubyte[1024] data;
420     //Initialize data here...
421     hash.put(data);
422     ubyte[16] result = hash.finish();
423 }
424 
425 ///
426 @safe unittest
427 {
428     //Let's use the template features:
429     void doSomething(T)(ref T hash)
430     if (isDigest!T)
431     {
432         hash.put(cast(ubyte) 0);
433     }
434     MD5 md5;
435     md5.start();
436     doSomething(md5);
437     assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71");
438 }
439 
440 @safe unittest
441 {
442     assert(isDigest!MD5);
443 }
444 
445 @system unittest
446 {
447     import std.range;
448     import std.conv : hexString;
449 
450     ubyte[16] digest;
451 
452     MD5 md5;
453     md5.put(cast(ubyte[])"abcdef");
454     md5.start();
455     md5.put(cast(ubyte[])"");
456     assert(md5.finish() == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e");
457 
458     digest = md5Of("");
459     assert(digest == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e");
460 
461     digest = md5Of("a");
462     assert(digest == cast(ubyte[]) hexString!"0cc175b9c0f1b6a831c399e269772661");
463 
464     digest = md5Of("abc");
465     assert(digest == cast(ubyte[]) hexString!"900150983cd24fb0d6963f7d28e17f72");
466 
467     digest = md5Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
468     assert(digest == cast(ubyte[]) hexString!"8215ef0796a20bcaaae116d3876c664a");
469 
470     digest = md5Of("message digest");
471     assert(digest == cast(ubyte[]) hexString!"f96b697d7cb7938d525a2f31aaf161d0");
472 
473     digest = md5Of("abcdefghijklmnopqrstuvwxyz");
474     assert(digest == cast(ubyte[]) hexString!"c3fcd3d76192e4007dfb496cca67e13b");
475 
476     digest = md5Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
477     assert(digest == cast(ubyte[]) hexString!"d174ab98d277d9f5a5611c2c9f419d9f");
478 
479     digest = md5Of("1234567890123456789012345678901234567890"~
480                     "1234567890123456789012345678901234567890");
481     assert(digest == cast(ubyte[]) hexString!"57edf4a22be3c955ac49da2e2107b67a");
482 
483     enum ubyte[16] input = cast(ubyte[16]) hexString!"c3fcd3d76192e4007dfb496cca67e13b";
484     assert(toHexString(input)
485         == "C3FCD3D76192E4007DFB496CCA67E13B");
486 
487     ubyte[] onemilliona = new ubyte[1000000];
488     onemilliona[] = 'a';
489     digest = md5Of(onemilliona);
490     assert(digest == cast(ubyte[]) hexString!"7707D6AE4E027C70EEA2A935C2296F21");
491 
492     auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
493     digest = md5Of(oneMillionRange);
494     assert(digest == cast(ubyte[]) hexString!"7707D6AE4E027C70EEA2A935C2296F21");
495 }
496 
497 /**
498  * This is a convenience alias for $(REF digest, std,digest) using the
499  * MD5 implementation.
500  */
501 //simple alias doesn't work here, hope this gets inlined...
502 auto md5Of(T...)(T data)
503 {
504     return digest!(MD5, T)(data);
505 }
506 
507 ///
508 @safe unittest
509 {
510     ubyte[16] hash = md5Of("abc");
511     assert(hash == digest!MD5("abc"));
512 }
513 
514 /**
515  * OOP API MD5 implementation.
516  * See `std.digest` for differences between template and OOP API.
517  *
518  * This is an alias for $(D $(REF WrapperDigest, std,digest)!MD5), see
519  * there for more information.
520  */
521 alias MD5Digest = WrapperDigest!MD5;
522 
523 ///
524 @safe unittest
525 {
526     //Simple example, hashing a string using Digest.digest helper function
527     auto md5 = new MD5Digest();
528     ubyte[] hash = md5.digest("abc");
529     //Let's get a hash string
530     assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72");
531 }
532 
533 ///
534 @system unittest
535 {
536      //Let's use the OOP features:
537     void test(Digest dig)
538     {
539       dig.put(cast(ubyte) 0);
540     }
541     auto md5 = new MD5Digest();
542     test(md5);
543 
544     //Let's use a custom buffer:
545     ubyte[16] buf;
546     ubyte[] result = md5.finish(buf[]);
547     assert(toHexString(result) == "93B885ADFE0DA089CDF634904FD59F71");
548 }
549 
550 @system unittest
551 {
552     import std.conv : hexString;
553     auto md5 = new MD5Digest();
554 
555     md5.put(cast(ubyte[])"abcdef");
556     md5.reset();
557     md5.put(cast(ubyte[])"");
558     assert(md5.finish() == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e");
559 
560     md5.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz");
561     ubyte[20] result;
562     auto result2 = md5.finish(result[]);
563     assert(result[0 .. 16] == result2 && result2 == cast(ubyte[]) hexString!"c3fcd3d76192e4007dfb496cca67e13b");
564 
565     debug
566     {
567         import std.exception;
568         assertThrown!Error(md5.finish(result[0 .. 15]));
569     }
570 
571     assert(md5.length == 16);
572 
573     assert(md5.digest("") == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e");
574 
575     assert(md5.digest("a") == cast(ubyte[]) hexString!"0cc175b9c0f1b6a831c399e269772661");
576 
577     assert(md5.digest("abc") == cast(ubyte[]) hexString!"900150983cd24fb0d6963f7d28e17f72");
578 
579     assert(md5.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
580            == cast(ubyte[]) hexString!"8215ef0796a20bcaaae116d3876c664a");
581 
582     assert(md5.digest("message digest") == cast(ubyte[]) hexString!"f96b697d7cb7938d525a2f31aaf161d0");
583 
584     assert(md5.digest("abcdefghijklmnopqrstuvwxyz")
585            == cast(ubyte[]) hexString!"c3fcd3d76192e4007dfb496cca67e13b");
586 
587     assert(md5.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
588            == cast(ubyte[]) hexString!"d174ab98d277d9f5a5611c2c9f419d9f");
589 
590     assert(md5.digest("1234567890123456789012345678901234567890",
591                                    "1234567890123456789012345678901234567890")
592            == cast(ubyte[]) hexString!"57edf4a22be3c955ac49da2e2107b67a");
593 }
Suggestion Box / Bug Report