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 { 107 uint F(uint x, uint y, uint z) { return (x & y) | (~x & z); } 108 uint G(uint x, uint y, uint z) { return (x & z) | (y & ~z); } 109 uint H(uint x, uint y, uint z) { return x ^ y ^ z; } 110 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 */ 118 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 126 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 134 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 142 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 175 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 */ 296 void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc 297 { 298 size_t i; 299 uint index, partLen; 300 auto inputLen = data.length; 301 302 //Compute number of bytes mod 64 303 index = (cast(uint)_count >> 3) & (64 - 1); 304 305 //Update number of bits 306 _count += inputLen * 8; 307 308 partLen = 64 - index; 309 310 //Transform as many times as possible 311 if (inputLen >= partLen) 312 { 313 (&_buffer[index])[0 .. partLen] = data.ptr[0 .. partLen]; 314 transform(&_buffer); 315 316 for (i = partLen; i + 63 < inputLen; i += 64) 317 { 318 transform(cast(const(ubyte[64])*)(data[i .. i + 64].ptr)); 319 } 320 321 index = 0; 322 } 323 else 324 { 325 i = 0; 326 } 327 328 /* Buffer remaining input */ 329 if (inputLen - i) 330 (&_buffer[index])[0 .. inputLen-i] = (&data[i])[0 .. inputLen-i]; 331 } 332 333 /** 334 * Used to (re)initialize the MD5 digest. 335 * 336 * Note: 337 * For this MD5 Digest implementation calling start after default construction 338 * is not necessary. Calling start is only necessary to reset the Digest. 339 * 340 * Generic code which deals with different Digest types should always call start though. 341 * 342 * Example: 343 * -------- 344 * MD5 digest; 345 * //digest.start(); //Not necessary 346 * digest.put(0); 347 * -------- 348 */ 349 void start() @safe pure nothrow @nogc 350 { 351 this = MD5.init; 352 } 353 354 /** 355 * Returns the finished MD5 hash. This also calls $(LREF start) to 356 * reset the internal state. 357 */ 358 ubyte[16] finish() @trusted pure nothrow @nogc 359 { 360 import std.bitmanip : nativeToLittleEndian; 361 362 ubyte[16] data = void; 363 ubyte[8] bits = void; 364 uint index, padLen; 365 366 //Save number of bits 367 bits[0 .. 8] = nativeToLittleEndian(_count)[]; 368 369 //Pad out to 56 mod 64 370 index = (cast(uint)_count >> 3) & (64 - 1); 371 padLen = (index < 56) ? (56 - index) : (120 - index); 372 put(_padding[0 .. padLen]); 373 374 //Append length (before padding) 375 put(bits); 376 377 //Store state in digest 378 data[0 .. 4] = nativeToLittleEndian(_state[0])[]; 379 data[4 .. 8] = nativeToLittleEndian(_state[1])[]; 380 data[8 .. 12] = nativeToLittleEndian(_state[2])[]; 381 data[12 .. 16] = nativeToLittleEndian(_state[3])[]; 382 383 /* Zeroize sensitive information. */ 384 start(); 385 return data; 386 } 387 /// 388 @safe unittest 389 { 390 //Simple example 391 MD5 hash; 392 hash.start(); 393 hash.put(cast(ubyte) 0); 394 ubyte[16] result = hash.finish(); 395 } 396 } 397 398 /// 399 @safe unittest 400 { 401 //Simple example, hashing a string using md5Of helper function 402 ubyte[16] hash = md5Of("abc"); 403 //Let's get a hash string 404 assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); 405 } 406 407 /// 408 @safe unittest 409 { 410 //Using the basic API 411 MD5 hash; 412 hash.start(); 413 ubyte[1024] data; 414 //Initialize data here... 415 hash.put(data); 416 ubyte[16] result = hash.finish(); 417 } 418 419 /// 420 @safe unittest 421 { 422 //Let's use the template features: 423 void doSomething(T)(ref T hash) 424 if (isDigest!T) 425 { 426 hash.put(cast(ubyte) 0); 427 } 428 MD5 md5; 429 md5.start(); 430 doSomething(md5); 431 assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); 432 } 433 434 @safe unittest 435 { 436 assert(isDigest!MD5); 437 } 438 439 @system unittest 440 { 441 import std.range; 442 import std.conv : hexString; 443 444 ubyte[16] digest; 445 446 MD5 md5; 447 md5.put(cast(ubyte[])"abcdef"); 448 md5.start(); 449 md5.put(cast(ubyte[])""); 450 assert(md5.finish() == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e"); 451 452 digest = md5Of(""); 453 assert(digest == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e"); 454 455 digest = md5Of("a"); 456 assert(digest == cast(ubyte[]) hexString!"0cc175b9c0f1b6a831c399e269772661"); 457 458 digest = md5Of("abc"); 459 assert(digest == cast(ubyte[]) hexString!"900150983cd24fb0d6963f7d28e17f72"); 460 461 digest = md5Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 462 assert(digest == cast(ubyte[]) hexString!"8215ef0796a20bcaaae116d3876c664a"); 463 464 digest = md5Of("message digest"); 465 assert(digest == cast(ubyte[]) hexString!"f96b697d7cb7938d525a2f31aaf161d0"); 466 467 digest = md5Of("abcdefghijklmnopqrstuvwxyz"); 468 assert(digest == cast(ubyte[]) hexString!"c3fcd3d76192e4007dfb496cca67e13b"); 469 470 digest = md5Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 471 assert(digest == cast(ubyte[]) hexString!"d174ab98d277d9f5a5611c2c9f419d9f"); 472 473 digest = md5Of("1234567890123456789012345678901234567890"~ 474 "1234567890123456789012345678901234567890"); 475 assert(digest == cast(ubyte[]) hexString!"57edf4a22be3c955ac49da2e2107b67a"); 476 477 enum ubyte[16] input = cast(ubyte[16]) hexString!"c3fcd3d76192e4007dfb496cca67e13b"; 478 assert(toHexString(input) 479 == "C3FCD3D76192E4007DFB496CCA67E13B"); 480 481 ubyte[] onemilliona = new ubyte[1000000]; 482 onemilliona[] = 'a'; 483 digest = md5Of(onemilliona); 484 assert(digest == cast(ubyte[]) hexString!"7707D6AE4E027C70EEA2A935C2296F21"); 485 486 auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); 487 digest = md5Of(oneMillionRange); 488 assert(digest == cast(ubyte[]) hexString!"7707D6AE4E027C70EEA2A935C2296F21"); 489 } 490 491 /** 492 * This is a convenience alias for $(REF digest, std,digest) using the 493 * MD5 implementation. 494 */ 495 //simple alias doesn't work here, hope this gets inlined... 496 auto md5Of(T...)(T data) 497 { 498 return digest!(MD5, T)(data); 499 } 500 501 /// 502 @safe unittest 503 { 504 ubyte[16] hash = md5Of("abc"); 505 assert(hash == digest!MD5("abc")); 506 } 507 508 /** 509 * OOP API MD5 implementation. 510 * See `std.digest` for differences between template and OOP API. 511 * 512 * This is an alias for $(D $(REF WrapperDigest, std,digest)!MD5), see 513 * there for more information. 514 */ 515 alias MD5Digest = WrapperDigest!MD5; 516 517 /// 518 @safe unittest 519 { 520 //Simple example, hashing a string using Digest.digest helper function 521 auto md5 = new MD5Digest(); 522 ubyte[] hash = md5.digest("abc"); 523 //Let's get a hash string 524 assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); 525 } 526 527 /// 528 @system unittest 529 { 530 //Let's use the OOP features: 531 void test(Digest dig) 532 { 533 dig.put(cast(ubyte) 0); 534 } 535 auto md5 = new MD5Digest(); 536 test(md5); 537 538 //Let's use a custom buffer: 539 ubyte[16] buf; 540 ubyte[] result = md5.finish(buf[]); 541 assert(toHexString(result) == "93B885ADFE0DA089CDF634904FD59F71"); 542 } 543 544 @system unittest 545 { 546 import std.conv : hexString; 547 auto md5 = new MD5Digest(); 548 549 md5.put(cast(ubyte[])"abcdef"); 550 md5.reset(); 551 md5.put(cast(ubyte[])""); 552 assert(md5.finish() == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e"); 553 554 md5.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); 555 ubyte[20] result; 556 auto result2 = md5.finish(result[]); 557 assert(result[0 .. 16] == result2 && result2 == cast(ubyte[]) hexString!"c3fcd3d76192e4007dfb496cca67e13b"); 558 559 debug 560 { 561 import std.exception; 562 assertThrown!Error(md5.finish(result[0 .. 15])); 563 } 564 565 assert(md5.length == 16); 566 567 assert(md5.digest("") == cast(ubyte[]) hexString!"d41d8cd98f00b204e9800998ecf8427e"); 568 569 assert(md5.digest("a") == cast(ubyte[]) hexString!"0cc175b9c0f1b6a831c399e269772661"); 570 571 assert(md5.digest("abc") == cast(ubyte[]) hexString!"900150983cd24fb0d6963f7d28e17f72"); 572 573 assert(md5.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") 574 == cast(ubyte[]) hexString!"8215ef0796a20bcaaae116d3876c664a"); 575 576 assert(md5.digest("message digest") == cast(ubyte[]) hexString!"f96b697d7cb7938d525a2f31aaf161d0"); 577 578 assert(md5.digest("abcdefghijklmnopqrstuvwxyz") 579 == cast(ubyte[]) hexString!"c3fcd3d76192e4007dfb496cca67e13b"); 580 581 assert(md5.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") 582 == cast(ubyte[]) hexString!"d174ab98d277d9f5a5611c2c9f419d9f"); 583 584 assert(md5.digest("1234567890123456789012345678901234567890", 585 "1234567890123456789012345678901234567890") 586 == cast(ubyte[]) hexString!"57edf4a22be3c955ac49da2e2107b67a"); 587 }