1 /** 2 * This module describes the _digest APIs used in Phobos. All digests follow 3 * these APIs. Additionally, this module contains useful helper methods which 4 * can be used with every _digest type. 5 * 6 $(SCRIPT inhibitQuickIndex = 1;) 7 8 $(DIVC quickindex, 9 $(BOOKTABLE , 10 $(TR $(TH Category) $(TH Functions) 11 ) 12 $(TR $(TDNW Template API) $(TD $(MYREF isDigest) $(MYREF DigestType) $(MYREF hasPeek) 13 $(MYREF hasBlockSize) 14 $(MYREF ExampleDigest) $(MYREF _digest) $(MYREF hexDigest) $(MYREF makeDigest) 15 ) 16 ) 17 $(TR $(TDNW OOP API) $(TD $(MYREF Digest) 18 ) 19 ) 20 $(TR $(TDNW Helper functions) $(TD $(MYREF toHexString)) 21 ) 22 $(TR $(TDNW Implementation helpers) $(TD $(MYREF digestLength) $(MYREF WrapperDigest)) 23 ) 24 ) 25 ) 26 27 * APIs: 28 * There are two APIs for digests: The template API and the OOP API. The template API uses structs 29 * and template helpers like $(LREF isDigest). The OOP API implements digests as classes inheriting 30 * the $(LREF Digest) interface. All digests are named so that the template API struct is called "$(B x)" 31 * and the OOP API class is called "$(B x)Digest". For example we have $(D MD5) <--> $(D MD5Digest), 32 * $(D CRC32) <--> $(D CRC32Digest), etc. 33 * 34 * The template API is slightly more efficient. It does not have to allocate memory dynamically, 35 * all memory is allocated on the stack. The OOP API has to allocate in the finish method if no 36 * buffer was provided. If you provide a buffer to the OOP APIs finish function, it doesn't allocate, 37 * but the $(LREF Digest) classes still have to be created using $(D new) which allocates them using the GC. 38 * 39 * The OOP API is useful to change the _digest function and/or _digest backend at 'runtime'. The benefit here 40 * is that switching e.g. Phobos MD5Digest and an OpenSSLMD5Digest implementation is ABI compatible. 41 * 42 * If just one specific _digest type and backend is needed, the template API is usually a good fit. 43 * In this simplest case, the template API can even be used without templates: Just use the "$(B x)" structs 44 * directly. 45 * 46 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 47 * Authors: 48 * Johannes Pfau 49 * 50 * Source: $(PHOBOSSRC std/_digest/_package.d) 51 * 52 * CTFE: 53 * Digests do not work in CTFE 54 * 55 * TODO: 56 * Digesting single bits (as opposed to bytes) is not implemented. This will be done as another 57 * template constraint helper (hasBitDigesting!T) and an additional interface (BitDigest) 58 */ 59 /* Copyright Johannes Pfau 2012. 60 * Distributed under the Boost Software License, Version 1.0. 61 * (See accompanying file LICENSE_1_0.txt or copy at 62 * http://www.boost.org/LICENSE_1_0.txt) 63 */ 64 module std.digest; 65 66 public import std.ascii : LetterCase; 67 import std.meta : allSatisfy; 68 import std.range.primitives; 69 import std.traits; 70 71 72 /// 73 @system unittest 74 { 75 import std.digest.crc; 76 77 //Simple example 78 char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog"); 79 assert(hexHash == "39A34F41"); 80 81 //Simple example, using the API manually 82 CRC32 context = makeDigest!CRC32(); 83 context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog"); 84 ubyte[4] hash = context.finish(); 85 assert(toHexString(hash) == "39A34F41"); 86 } 87 88 /// 89 @system unittest 90 { 91 //Generating the hashes of a file, idiomatic D way 92 import std.digest.crc, std.digest.md, std.digest.sha; 93 import std.stdio; 94 95 // Digests a file and prints the result. 96 void digestFile(Hash)(string filename) 97 if (isDigest!Hash) 98 { 99 auto file = File(filename); 100 auto result = digest!Hash(file.byChunk(4096 * 1024)); 101 writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); 102 } 103 104 void main(string[] args) 105 { 106 foreach (name; args[1 .. $]) 107 { 108 digestFile!MD5(name); 109 digestFile!SHA1(name); 110 digestFile!CRC32(name); 111 } 112 } 113 } 114 /// 115 @system unittest 116 { 117 //Generating the hashes of a file using the template API 118 import std.digest.crc, std.digest.md, std.digest.sha; 119 import std.stdio; 120 // Digests a file and prints the result. 121 void digestFile(Hash)(ref Hash hash, string filename) 122 if (isDigest!Hash) 123 { 124 File file = File(filename); 125 126 //As digests imlement OutputRange, we could use std.algorithm.copy 127 //Let's do it manually for now 128 foreach (buffer; file.byChunk(4096 * 1024)) 129 hash.put(buffer); 130 131 auto result = hash.finish(); 132 writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); 133 } 134 135 void uMain(string[] args) 136 { 137 MD5 md5; 138 SHA1 sha1; 139 CRC32 crc32; 140 141 md5.start(); 142 sha1.start(); 143 crc32.start(); 144 145 foreach (arg; args[1 .. $]) 146 { 147 digestFile(md5, arg); 148 digestFile(sha1, arg); 149 digestFile(crc32, arg); 150 } 151 } 152 } 153 154 /// 155 @system unittest 156 { 157 import std.digest.crc, std.digest.md, std.digest.sha; 158 import std.stdio; 159 160 // Digests a file and prints the result. 161 void digestFile(Digest hash, string filename) 162 { 163 File file = File(filename); 164 165 //As digests implement OutputRange, we could use std.algorithm.copy 166 //Let's do it manually for now 167 foreach (buffer; file.byChunk(4096 * 1024)) 168 hash.put(buffer); 169 170 ubyte[] result = hash.finish(); 171 writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result)); 172 } 173 174 void umain(string[] args) 175 { 176 auto md5 = new MD5Digest(); 177 auto sha1 = new SHA1Digest(); 178 auto crc32 = new CRC32Digest(); 179 180 foreach (arg; args[1 .. $]) 181 { 182 digestFile(md5, arg); 183 digestFile(sha1, arg); 184 digestFile(crc32, arg); 185 } 186 } 187 } 188 189 version (StdDdoc) 190 version = ExampleDigest; 191 192 version (ExampleDigest) 193 { 194 /** 195 * This documents the general structure of a Digest in the template API. 196 * All digest implementations should implement the following members and therefore pass 197 * the $(LREF isDigest) test. 198 * 199 * Note: 200 * $(UL 201 * $(LI A digest must be a struct (value type) to pass the $(LREF isDigest) test.) 202 * $(LI A digest passing the $(LREF isDigest) test is always an $(D OutputRange)) 203 * ) 204 */ 205 struct ExampleDigest 206 { 207 public: 208 /** 209 * Use this to feed the digest with data. 210 * Also implements the $(REF isOutputRange, std,range,primitives) 211 * interface for $(D ubyte) and $(D const(ubyte)[]). 212 * The following usages of $(D put) must work for any type which 213 * passes $(LREF isDigest): 214 * Example: 215 * ---- 216 * ExampleDigest dig; 217 * dig.put(cast(ubyte) 0); //single ubyte 218 * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic 219 * ubyte[10] buf; 220 * dig.put(buf); //buffer 221 * ---- 222 */ 223 @trusted void put(scope const(ubyte)[] data...) 224 { 225 226 } 227 228 /** 229 * This function is used to (re)initialize the digest. 230 * It must be called before using the digest and it also works as a 'reset' function 231 * if the digest has already processed data. 232 */ 233 @trusted void start() 234 { 235 236 } 237 238 /** 239 * The finish function returns the final hash sum and resets the Digest. 240 * 241 * Note: 242 * The actual type returned by finish depends on the digest implementation. 243 * $(D ubyte[16]) is just used as an example. It is guaranteed that the type is a 244 * static array of ubytes. 245 * 246 * $(UL 247 * $(LI Use $(LREF DigestType) to obtain the actual return type.) 248 * $(LI Use $(LREF digestLength) to obtain the length of the ubyte array.) 249 * ) 250 */ 251 @trusted ubyte[16] finish() 252 { 253 return (ubyte[16]).init; 254 } 255 } 256 } 257 258 /// 259 @system unittest 260 { 261 //Using the OutputRange feature 262 import std.algorithm.mutation : copy; 263 import std.digest.md; 264 import std.range : repeat; 265 266 auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); 267 auto ctx = makeDigest!MD5(); 268 copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy! 269 assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); 270 } 271 272 /** 273 * Use this to check if a type is a digest. See $(LREF ExampleDigest) to see what 274 * a type must provide to pass this check. 275 * 276 * Note: 277 * This is very useful as a template constraint (see examples) 278 * 279 * BUGS: 280 * $(UL 281 * $(LI Does not yet verify that put takes scope parameters.) 282 * $(LI Should check that finish() returns a ubyte[num] array) 283 * ) 284 */ 285 template isDigest(T) 286 { 287 import std.range : isOutputRange; 288 enum bool isDigest = isOutputRange!(T, const(ubyte)[]) && isOutputRange!(T, ubyte) && 289 is(T == struct) && 290 is(typeof( 291 { 292 T dig = void; //Can define 293 dig.put(cast(ubyte) 0, cast(ubyte) 0); //varags 294 dig.start(); //has start 295 auto value = dig.finish(); //has finish 296 })); 297 } 298 299 /// 300 @system unittest 301 { 302 import std.digest.crc; 303 static assert(isDigest!CRC32); 304 } 305 /// 306 @system unittest 307 { 308 import std.digest.crc; 309 void myFunction(T)() 310 if (isDigest!T) 311 { 312 T dig; 313 dig.start(); 314 auto result = dig.finish(); 315 } 316 myFunction!CRC32(); 317 } 318 319 /** 320 * Use this template to get the type which is returned by a digest's $(LREF finish) method. 321 */ 322 template DigestType(T) 323 { 324 static if (isDigest!T) 325 { 326 alias DigestType = 327 ReturnType!(typeof( 328 { 329 T dig = void; 330 return dig.finish(); 331 })); 332 } 333 else 334 static assert(false, T.stringof ~ " is not a digest! (fails isDigest!T)"); 335 } 336 337 /// 338 @system unittest 339 { 340 import std.digest.crc; 341 assert(is(DigestType!(CRC32) == ubyte[4])); 342 } 343 /// 344 @system unittest 345 { 346 import std.digest.crc; 347 CRC32 dig; 348 dig.start(); 349 DigestType!CRC32 result = dig.finish(); 350 } 351 352 /** 353 * Used to check if a digest supports the $(D peek) method. 354 * Peek has exactly the same function signatures as finish, but it doesn't reset 355 * the digest's internal state. 356 * 357 * Note: 358 * $(UL 359 * $(LI This is very useful as a template constraint (see examples)) 360 * $(LI This also checks if T passes $(LREF isDigest)) 361 * ) 362 */ 363 template hasPeek(T) 364 { 365 enum bool hasPeek = isDigest!T && 366 is(typeof( 367 { 368 T dig = void; //Can define 369 DigestType!T val = dig.peek(); 370 })); 371 } 372 373 /// 374 @system unittest 375 { 376 import std.digest.crc, std.digest.md; 377 assert(!hasPeek!(MD5)); 378 assert(hasPeek!CRC32); 379 } 380 /// 381 @system unittest 382 { 383 import std.digest.crc; 384 void myFunction(T)() 385 if (hasPeek!T) 386 { 387 T dig; 388 dig.start(); 389 auto result = dig.peek(); 390 } 391 myFunction!CRC32(); 392 } 393 394 /** 395 * Checks whether the digest has a $(D blockSize) member, which contains the 396 * digest's internal block size in bits. It is primarily used by $(REF HMAC, std,digest,hmac). 397 */ 398 399 template hasBlockSize(T) 400 if (isDigest!T) 401 { 402 enum bool hasBlockSize = __traits(compiles, { size_t blockSize = T.blockSize; }); 403 } 404 405 /// 406 @system unittest 407 { 408 import std.digest.hmac, std.digest.md; 409 static assert(hasBlockSize!MD5 && MD5.blockSize == 512); 410 static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512); 411 } 412 413 package template isDigestibleRange(Range) 414 { 415 import std.digest.md; 416 import std.range : isInputRange, ElementType; 417 enum bool isDigestibleRange = isInputRange!Range && is(typeof( 418 { 419 MD5 ha; //Could use any conformant hash 420 ElementType!Range val; 421 ha.put(val); 422 })); 423 } 424 425 /** 426 * This is a convenience function to calculate a hash using the template API. 427 * Every digest passing the $(LREF isDigest) test can be used with this function. 428 * 429 * Params: 430 * range= an $(D InputRange) with $(D ElementType) $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) 431 */ 432 DigestType!Hash digest(Hash, Range)(auto ref Range range) 433 if (!isArray!Range 434 && isDigestibleRange!Range) 435 { 436 import std.algorithm.mutation : copy; 437 Hash hash; 438 hash.start(); 439 copy(range, &hash); 440 return hash.finish(); 441 } 442 443 /// 444 @system unittest 445 { 446 import std.digest.md; 447 import std.range : repeat; 448 auto testRange = repeat!ubyte(cast(ubyte)'a', 100); 449 auto md5 = digest!MD5(testRange); 450 } 451 452 /** 453 * This overload of the digest function handles arrays. 454 * 455 * Params: 456 * data= one or more arrays of any type 457 */ 458 DigestType!Hash digest(Hash, T...)(scope const T data) 459 if (allSatisfy!(isArray, typeof(data))) 460 { 461 Hash hash; 462 hash.start(); 463 foreach (datum; data) 464 hash.put(cast(const(ubyte[]))datum); 465 return hash.finish(); 466 } 467 468 /// 469 @system unittest 470 { 471 import std.digest.crc, std.digest.md, std.digest.sha; 472 auto md5 = digest!MD5( "The quick brown fox jumps over the lazy dog"); 473 auto sha1 = digest!SHA1( "The quick brown fox jumps over the lazy dog"); 474 auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); 475 assert(toHexString(crc32) == "39A34F41"); 476 } 477 478 /// 479 @system unittest 480 { 481 import std.digest.crc; 482 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); 483 assert(toHexString(crc32) == "39A34F41"); 484 } 485 486 /** 487 * This is a convenience function similar to $(LREF digest), but it returns the string 488 * representation of the hash. Every digest passing the $(LREF isDigest) test can be used with this 489 * function. 490 * 491 * Params: 492 * order= the order in which the bytes are processed (see $(LREF toHexString)) 493 * range= an $(D InputRange) with $(D ElementType) $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) 494 */ 495 char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range) 496 if (!isArray!Range && isDigestibleRange!Range) 497 { 498 return toHexString!order(digest!Hash(range)); 499 } 500 501 /// 502 @system unittest 503 { 504 import std.digest.md; 505 import std.range : repeat; 506 auto testRange = repeat!ubyte(cast(ubyte)'a', 100); 507 assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF"); 508 } 509 510 /** 511 * This overload of the hexDigest function handles arrays. 512 * 513 * Params: 514 * order= the order in which the bytes are processed (see $(LREF toHexString)) 515 * data= one or more arrays of any type 516 */ 517 char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data) 518 if (allSatisfy!(isArray, typeof(data))) 519 { 520 return toHexString!order(digest!Hash(data)); 521 } 522 523 /// 524 @system unittest 525 { 526 import std.digest.crc; 527 assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339"); 528 } 529 /// 530 @system unittest 531 { 532 import std.digest.crc; 533 assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339"); 534 } 535 536 /** 537 * This is a convenience function which returns an initialized digest, so it's not necessary to call 538 * start manually. 539 */ 540 Hash makeDigest(Hash)() 541 { 542 Hash hash; 543 hash.start(); 544 return hash; 545 } 546 547 /// 548 @system unittest 549 { 550 import std.digest.md; 551 auto md5 = makeDigest!MD5(); 552 md5.put(0); 553 assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); 554 } 555 556 /*+*************************** End of template part, welcome to OOP land **************************/ 557 558 /** 559 * This describes the OOP API. To understand when to use the template API and when to use the OOP API, 560 * see the module documentation at the top of this page. 561 * 562 * The Digest interface is the base interface which is implemented by all digests. 563 * 564 * Note: 565 * A Digest implementation is always an $(D OutputRange) 566 */ 567 interface Digest 568 { 569 public: 570 /** 571 * Use this to feed the digest with data. 572 * Also implements the $(REF isOutputRange, std,range,primitives) 573 * interface for $(D ubyte) and $(D const(ubyte)[]). 574 * 575 * Example: 576 * ---- 577 * void test(Digest dig) 578 * { 579 * dig.put(cast(ubyte) 0); //single ubyte 580 * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic 581 * ubyte[10] buf; 582 * dig.put(buf); //buffer 583 * } 584 * ---- 585 */ 586 @trusted nothrow void put(scope const(ubyte)[] data...); 587 588 /** 589 * Resets the internal state of the digest. 590 * Note: 591 * $(LREF finish) calls this internally, so it's not necessary to call 592 * $(D reset) manually after a call to $(LREF finish). 593 */ 594 @trusted nothrow void reset(); 595 596 /** 597 * This is the length in bytes of the hash value which is returned by $(LREF finish). 598 * It's also the required size of a buffer passed to $(LREF finish). 599 */ 600 @trusted nothrow @property size_t length() const; 601 602 /** 603 * The finish function returns the hash value. It takes an optional buffer to copy the data 604 * into. If a buffer is passed, it must be at least $(LREF length) bytes big. 605 */ 606 @trusted nothrow ubyte[] finish(); 607 ///ditto 608 nothrow ubyte[] finish(ubyte[] buf); 609 //@@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=6549 610 /*in 611 { 612 assert(buf.length >= this.length); 613 }*/ 614 615 /** 616 * This is a convenience function to calculate the hash of a value using the OOP API. 617 */ 618 final @trusted nothrow ubyte[] digest(scope const(void[])[] data...) 619 { 620 this.reset(); 621 foreach (datum; data) 622 this.put(cast(ubyte[]) datum); 623 return this.finish(); 624 } 625 } 626 627 /// 628 @system unittest 629 { 630 //Using the OutputRange feature 631 import std.algorithm.mutation : copy; 632 import std.digest.md; 633 import std.range : repeat; 634 635 auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); 636 auto ctx = new MD5Digest(); 637 copy(oneMillionRange, ctx); 638 assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); 639 } 640 641 /// 642 @system unittest 643 { 644 import std.digest.crc, std.digest.md, std.digest.sha; 645 ubyte[] md5 = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); 646 ubyte[] sha1 = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); 647 ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); 648 assert(crcHexString(crc32) == "414FA339"); 649 } 650 651 /// 652 @system unittest 653 { 654 import std.digest.crc; 655 ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); 656 assert(crcHexString(crc32) == "414FA339"); 657 } 658 659 @system unittest 660 { 661 import std.range : isOutputRange; 662 assert(!isDigest!(Digest)); 663 assert(isOutputRange!(Digest, ubyte)); 664 } 665 666 /// 667 @system unittest 668 { 669 void test(Digest dig) 670 { 671 dig.put(cast(ubyte) 0); //single ubyte 672 dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic 673 ubyte[10] buf; 674 dig.put(buf); //buffer 675 } 676 } 677 678 /*+*************************** End of OOP part, helper functions follow ***************************/ 679 680 /** 681 * See $(LREF toHexString) 682 */ 683 enum Order : bool 684 { 685 increasing, /// 686 decreasing /// 687 } 688 689 690 /** 691 * Used to convert a hash value (a static or dynamic array of ubytes) to a string. 692 * Can be used with the OOP and with the template API. 693 * 694 * The additional order parameter can be used to specify the order of the input data. 695 * By default the data is processed in increasing order, starting at index 0. To process it in the 696 * opposite order, pass Order.decreasing as a parameter. 697 * 698 * The additional letterCase parameter can be used to specify the case of the output data. 699 * By default the output is in upper case. To change it to the lower case 700 * pass LetterCase.lower as a parameter. 701 * 702 * Note: 703 * The function overloads returning a string allocate their return values 704 * using the GC. The versions returning static arrays use pass-by-value for 705 * the return value, effectively avoiding dynamic allocation. 706 */ 707 char[num*2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper) 708 (in ubyte[num] digest) 709 { 710 static if (letterCase == LetterCase.upper) 711 { 712 import std.ascii : hexDigits = hexDigits; 713 } 714 else 715 { 716 import std.ascii : hexDigits = lowerHexDigits; 717 } 718 719 720 char[num*2] result; 721 size_t i; 722 723 static if (order == Order.increasing) 724 { 725 foreach (u; digest) 726 { 727 result[i++] = hexDigits[u >> 4]; 728 result[i++] = hexDigits[u & 15]; 729 } 730 } 731 else 732 { 733 size_t j = num - 1; 734 while (i < num*2) 735 { 736 result[i++] = hexDigits[digest[j] >> 4]; 737 result[i++] = hexDigits[digest[j] & 15]; 738 j--; 739 } 740 } 741 return result; 742 } 743 744 ///ditto 745 char[num*2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest) 746 { 747 return toHexString!(order, num, letterCase)(digest); 748 } 749 750 ///ditto 751 string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper) 752 (in ubyte[] digest) 753 { 754 static if (letterCase == LetterCase.upper) 755 { 756 import std.ascii : hexDigits = hexDigits; 757 } 758 else 759 { 760 import std.ascii : hexDigits = lowerHexDigits; 761 } 762 763 auto result = new char[digest.length*2]; 764 size_t i; 765 766 static if (order == Order.increasing) 767 { 768 foreach (u; digest) 769 { 770 result[i++] = hexDigits[u >> 4]; 771 result[i++] = hexDigits[u & 15]; 772 } 773 } 774 else 775 { 776 import std.range : retro; 777 foreach (u; retro(digest)) 778 { 779 result[i++] = hexDigits[u >> 4]; 780 result[i++] = hexDigits[u & 15]; 781 } 782 } 783 import std.exception : assumeUnique; 784 // memory was just created, so casting to immutable is safe 785 return () @trusted { return assumeUnique(result); }(); 786 } 787 788 ///ditto 789 string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest) 790 { 791 return toHexString!(order, letterCase)(digest); 792 } 793 794 //For more example unittests, see Digest.digest, digest 795 796 /// 797 @safe unittest 798 { 799 import std.digest.crc; 800 //Test with template API: 801 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); 802 //Lower case variant: 803 assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41"); 804 //Usually CRCs are printed in this order, though: 805 assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); 806 assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339"); 807 } 808 809 /// 810 @safe unittest 811 { 812 import std.digest.crc; 813 // With OOP API 814 auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); 815 //Usually CRCs are printed in this order, though: 816 assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); 817 } 818 819 @safe unittest 820 { 821 ubyte[16] data; 822 assert(toHexString(data) == "00000000000000000000000000000000"); 823 824 assert(toHexString(cast(ubyte[4])[42, 43, 44, 45]) == "2A2B2C2D"); 825 assert(toHexString(cast(ubyte[])[42, 43, 44, 45]) == "2A2B2C2D"); 826 assert(toHexString!(Order.decreasing)(cast(ubyte[4])[42, 43, 44, 45]) == "2D2C2B2A"); 827 assert(toHexString!(Order.decreasing, LetterCase.lower)(cast(ubyte[4])[42, 43, 44, 45]) == "2d2c2b2a"); 828 assert(toHexString!(Order.decreasing)(cast(ubyte[])[42, 43, 44, 45]) == "2D2C2B2A"); 829 } 830 831 /*+*********************** End of public helper part, private helpers follow ***********************/ 832 833 /* 834 * Used to convert from a ubyte[] slice to a ref ubyte[N]. 835 * This helper is used internally in the WrapperDigest template to wrap the template API's 836 * finish function. 837 */ 838 ref T[N] asArray(size_t N, T)(ref T[] source, string errorMsg = "") 839 { 840 assert(source.length >= N, errorMsg); 841 return *cast(T[N]*) source.ptr; 842 } 843 844 /* 845 * Returns the length (in bytes) of the hash value produced by T. 846 */ 847 template digestLength(T) 848 if (isDigest!T) 849 { 850 enum size_t digestLength = (ReturnType!(T.finish)).length; 851 } 852 853 @safe pure nothrow @nogc 854 unittest 855 { 856 import std.digest.md : MD5; 857 import std.digest.sha : SHA1, SHA256, SHA512; 858 assert(digestLength!MD5 == 16); 859 assert(digestLength!SHA1 == 20); 860 assert(digestLength!SHA256 == 32); 861 assert(digestLength!SHA512 == 64); 862 } 863 864 /** 865 * Wraps a template API hash struct into a Digest interface. 866 * Modules providing digest implementations will usually provide 867 * an alias for this template (e.g. MD5Digest, SHA1Digest, ...). 868 */ 869 class WrapperDigest(T) 870 if (isDigest!T) : Digest 871 { 872 protected: 873 T _digest; 874 875 public final: 876 /** 877 * Initializes the digest. 878 */ 879 this() 880 { 881 _digest.start(); 882 } 883 884 /** 885 * Use this to feed the digest with data. 886 * Also implements the $(REF isOutputRange, std,range,primitives) 887 * interface for $(D ubyte) and $(D const(ubyte)[]). 888 */ 889 @trusted nothrow void put(scope const(ubyte)[] data...) 890 { 891 _digest.put(data); 892 } 893 894 /** 895 * Resets the internal state of the digest. 896 * Note: 897 * $(LREF finish) calls this internally, so it's not necessary to call 898 * $(D reset) manually after a call to $(LREF finish). 899 */ 900 @trusted nothrow void reset() 901 { 902 _digest.start(); 903 } 904 905 /** 906 * This is the length in bytes of the hash value which is returned by $(LREF finish). 907 * It's also the required size of a buffer passed to $(LREF finish). 908 */ 909 @trusted nothrow @property size_t length() const pure 910 { 911 return digestLength!T; 912 } 913 914 /** 915 * The finish function returns the hash value. It takes an optional buffer to copy the data 916 * into. If a buffer is passed, it must have a length at least $(LREF length) bytes. 917 * 918 * Example: 919 * -------- 920 * 921 * import std.digest.md; 922 * ubyte[16] buf; 923 * auto hash = new WrapperDigest!MD5(); 924 * hash.put(cast(ubyte) 0); 925 * auto result = hash.finish(buf[]); 926 * //The result is now in result (and in buf). If you pass a buffer which is bigger than 927 * //necessary, result will have the correct length, but buf will still have it's original 928 * //length 929 * -------- 930 */ 931 nothrow ubyte[] finish(ubyte[] buf) 932 in 933 { 934 assert(buf.length >= this.length); 935 } 936 body 937 { 938 enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ 939 "big, check " ~ typeof(this).stringof ~ ".length!"; 940 asArray!(digestLength!T)(buf, msg) = _digest.finish(); 941 return buf[0 .. digestLength!T]; 942 } 943 944 ///ditto 945 @trusted nothrow ubyte[] finish() 946 { 947 enum len = digestLength!T; 948 auto buf = new ubyte[len]; 949 asArray!(digestLength!T)(buf) = _digest.finish(); 950 return buf; 951 } 952 953 version (StdDdoc) 954 { 955 /** 956 * Works like $(D finish) but does not reset the internal state, so it's possible 957 * to continue putting data into this WrapperDigest after a call to peek. 958 * 959 * These functions are only available if $(D hasPeek!T) is true. 960 */ 961 @trusted ubyte[] peek(ubyte[] buf) const; 962 ///ditto 963 @trusted ubyte[] peek() const; 964 } 965 else static if (hasPeek!T) 966 { 967 @trusted ubyte[] peek(ubyte[] buf) const 968 in 969 { 970 assert(buf.length >= this.length); 971 } 972 body 973 { 974 enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ 975 "big, check " ~ typeof(this).stringof ~ ".length!"; 976 asArray!(digestLength!T)(buf, msg) = _digest.peek(); 977 return buf[0 .. digestLength!T]; 978 } 979 980 @trusted ubyte[] peek() const 981 { 982 enum len = digestLength!T; 983 auto buf = new ubyte[len]; 984 asArray!(digestLength!T)(buf) = _digest.peek(); 985 return buf; 986 } 987 } 988 } 989 990 /// 991 @system unittest 992 { 993 import std.digest.md; 994 //Simple example 995 auto hash = new WrapperDigest!MD5(); 996 hash.put(cast(ubyte) 0); 997 auto result = hash.finish(); 998 } 999 1000 /// 1001 @system unittest 1002 { 1003 //using a supplied buffer 1004 import std.digest.md; 1005 ubyte[16] buf; 1006 auto hash = new WrapperDigest!MD5(); 1007 hash.put(cast(ubyte) 0); 1008 auto result = hash.finish(buf[]); 1009 //The result is now in result (and in buf). If you pass a buffer which is bigger than 1010 //necessary, result will have the correct length, but buf will still have it's original 1011 //length 1012 } 1013 1014 @safe unittest 1015 { 1016 // Test peek & length 1017 import std.digest.crc; 1018 auto hash = new WrapperDigest!CRC32(); 1019 assert(hash.length == 4); 1020 hash.put(cast(const(ubyte[]))"The quick brown fox jumps over the lazy dog"); 1021 assert(hash.peek().toHexString() == "39A34F41"); 1022 ubyte[5] buf; 1023 assert(hash.peek(buf).toHexString() == "39A34F41"); 1024 } 1025 1026 /** 1027 * Securely compares two digest representations while protecting against timing 1028 * attacks. Do not use `==` to compare digest representations. 1029 * 1030 * The attack happens as follows: 1031 * 1032 * $(OL 1033 * $(LI An attacker wants to send harmful data to your server, which 1034 * requires a integrity HMAC SHA1 token signed with a secret.) 1035 * $(LI The length of the token is known to be 40 characters long due to its format, 1036 * so the attacker first sends `"0000000000000000000000000000000000000000"`, 1037 * then `"1000000000000000000000000000000000000000"`, and so on.) 1038 * $(LI The given HMAC token is compared with the expected token using the 1039 * `==` string comparison, which returns `false` as soon as the first wrong 1040 * element is found. If a wrong element is found, then a rejection is sent 1041 * back to the sender.) 1042 * $(LI Eventually, the attacker is able to determine the first character in 1043 * the correct token because the sever takes slightly longer to return a 1044 * rejection. This is due to the comparison moving on to second item in 1045 * the two arrays, seeing they are different, and then sending the rejection.) 1046 * $(LI It may seem like too small of a difference in time for the attacker 1047 * to notice, but security researchers have shown that differences as 1048 * small as $(LINK2 http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf, 1049 * 20µs can be reliably distinguished) even with network inconsistencies.) 1050 * $(LI Repeat the process for each character until the attacker has the whole 1051 * correct token and the server accepts the harmful data. This can be done 1052 * in a week with the attacker pacing the attack to 10 requests per second 1053 * with only one client.) 1054 * ) 1055 * 1056 * This function defends against this attack by always comparing every single 1057 * item in the array if the two arrays are the same length. Therefore, this 1058 * function is always $(BIGOH n) for ranges of the same length. 1059 * 1060 * This attack can also be mitigated via rate limiting and banning IPs which have too 1061 * many rejected requests. However, this does not completely solve the problem, 1062 * as the attacker could be in control of a bot net. To fully defend against 1063 * the timing attack, rate limiting, banning IPs, and using this function 1064 * should be used together. 1065 * 1066 * Params: 1067 * r1 = A digest representation 1068 * r2 = A digest representation 1069 * Returns: 1070 * `true` if both representations are equal, `false` otherwise 1071 * See_Also: 1072 * $(LINK2 https://en.wikipedia.org/wiki/Timing_attack, The Wikipedia article 1073 * on timing attacks). 1074 */ 1075 bool secureEqual(R1, R2)(R1 r1, R2 r2) 1076 if (isInputRange!R1 && isInputRange!R2 && !isInfinite!R1 && !isInfinite!R2 && 1077 (isIntegral!(ElementEncodingType!R1) || isSomeChar!(ElementEncodingType!R1)) && 1078 !is(CommonType!(ElementEncodingType!R1, ElementEncodingType!R2) == void)) 1079 { 1080 static if (hasLength!R1 && hasLength!R2) 1081 if (r1.length != r2.length) 1082 return false; 1083 1084 int result; 1085 1086 static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && 1087 hasLength!R1 && hasLength!R2) 1088 { 1089 foreach (i; 0 .. r1.length) 1090 result |= r1[i] ^ r2[i]; 1091 } 1092 else static if (hasLength!R1 && hasLength!R2) 1093 { 1094 // Lengths are the same so we can squeeze out a bit of performance 1095 // by not checking if r2 is empty 1096 for (; !r1.empty; r1.popFront(), r2.popFront()) 1097 { 1098 result |= r1.front ^ r2.front; 1099 } 1100 } 1101 else 1102 { 1103 // Generic case, walk both ranges 1104 for (; !r1.empty; r1.popFront(), r2.popFront()) 1105 { 1106 if (r2.empty) return false; 1107 result |= r1.front ^ r2.front; 1108 } 1109 if (!r2.empty) return false; 1110 } 1111 1112 return result == 0; 1113 } 1114 1115 /// 1116 @system pure unittest 1117 { 1118 import std.digest.hmac : hmac; 1119 import std.digest.sha : SHA1; 1120 import std.string : representation; 1121 1122 // a typical HMAC data integrity verification 1123 auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation; 1124 auto data = "data".representation; 1125 1126 string hex1 = data.hmac!SHA1(secret).toHexString; 1127 string hex2 = data.hmac!SHA1(secret).toHexString; 1128 string hex3 = "data1".representation.hmac!SHA1(secret).toHexString; 1129 1130 assert( secureEqual(hex1, hex2)); 1131 assert(!secureEqual(hex1, hex3)); 1132 } 1133 1134 @system pure unittest 1135 { 1136 import std.internal.test.dummyrange : ReferenceInputRange; 1137 import std.range : takeExactly; 1138 import std.string : representation; 1139 import std.utf : byWchar, byDchar; 1140 1141 { 1142 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".representation; 1143 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".representation; 1144 assert(!secureEqual(hex1, hex2)); 1145 } 1146 { 1147 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018"w.representation; 1148 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018"d.representation; 1149 assert(secureEqual(hex1, hex2)); 1150 } 1151 { 1152 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byWchar; 1153 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar; 1154 assert(secureEqual(hex1, hex2)); 1155 } 1156 { 1157 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".byWchar; 1158 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar; 1159 assert(!secureEqual(hex1, hex2)); 1160 } 1161 { 1162 auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); 1163 auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); 1164 assert(secureEqual(hex1, hex2)); 1165 } 1166 { 1167 auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); 1168 auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 9]).takeExactly(9); 1169 assert(!secureEqual(hex1, hex2)); 1170 } 1171 } 1172