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