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) $(MYREF secureEqual)) 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 `MD5` <--> `MD5Digest`, 32 * `CRC32` <--> `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 `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 `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 `ubyte` and `const(ubyte)[]`. 212 * The following usages of `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 * `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 `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 `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 `InputRange` with `ElementType` `ubyte`, `ubyte[]` or `ubyte[num]` 431 */ 432 DigestType!Hash digest(Hash, Range)(auto ref Range range) 433 if (!isArray!Range 434 && isDigestibleRange!Range) 435 { 436 Hash hash; 437 hash.start(); 438 alias E = ElementType!Range; // Not necessarily ubyte. Could be ubyte[N] or ubyte[] or something w/alias this. 439 static if (!(__traits(isScalar, E) && E.sizeof == 1)) 440 { 441 foreach (e; range) 442 hash.put(e); 443 return hash.finish(); 444 } 445 else 446 { 447 static if (hasBlockSize!Hash) 448 enum bufferBytes = Hash.blockSize >= (8192 * 8) ? 8192 : Hash.blockSize <= 64 ? 8 : (Hash.blockSize / 8); 449 else 450 enum bufferBytes = 8; 451 ubyte[bufferBytes] buffer = void; 452 static if (isRandomAccessRange!Range && hasLength!Range) 453 { 454 const end = range.length; 455 size_t i = 0; 456 while (end - i >= buffer.length) 457 { 458 foreach (ref e; buffer) 459 e = range[i++]; 460 hash.put(buffer); 461 } 462 if (const remaining = end - i) 463 { 464 foreach (ref e; buffer[0 .. remaining]) 465 e = range[i++]; 466 hash.put(buffer[0 .. remaining]); 467 } 468 return hash.finish(); 469 } 470 else 471 { 472 for (;;) 473 { 474 size_t n = buffer.length; 475 foreach (i, ref e; buffer) 476 { 477 if (range.empty) 478 { 479 n = i; 480 break; 481 } 482 e = range.front; 483 range.popFront(); 484 } 485 if (n) 486 hash.put(buffer[0 .. n]); 487 if (n != buffer.length) 488 return hash.finish(); 489 } 490 } 491 } 492 } 493 494 /// 495 @system unittest 496 { 497 import std.digest.md; 498 import std.range : repeat; 499 auto testRange = repeat!ubyte(cast(ubyte)'a', 100); 500 auto md5 = digest!MD5(testRange); 501 } 502 503 /** 504 * This overload of the digest function handles arrays. 505 * 506 * Params: 507 * data= one or more arrays of any type 508 */ 509 DigestType!Hash digest(Hash, T...)(scope const T data) 510 if (allSatisfy!(isArray, typeof(data))) 511 { 512 Hash hash; 513 hash.start(); 514 foreach (datum; data) 515 hash.put(cast(const(ubyte[]))datum); 516 return hash.finish(); 517 } 518 519 /// 520 @system unittest 521 { 522 import std.digest.crc, std.digest.md, std.digest.sha; 523 auto md5 = digest!MD5( "The quick brown fox jumps over the lazy dog"); 524 auto sha1 = digest!SHA1( "The quick brown fox jumps over the lazy dog"); 525 auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); 526 assert(toHexString(crc32) == "39A34F41"); 527 } 528 529 /// 530 @system unittest 531 { 532 import std.digest.crc; 533 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); 534 assert(toHexString(crc32) == "39A34F41"); 535 } 536 537 /** 538 * This is a convenience function similar to $(LREF digest), but it returns the string 539 * representation of the hash. Every digest passing the $(LREF isDigest) test can be used with this 540 * function. 541 * 542 * Params: 543 * order= the order in which the bytes are processed (see $(LREF toHexString)) 544 * range= an `InputRange` with `ElementType` `ubyte`, `ubyte[]` or `ubyte[num]` 545 */ 546 char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range) 547 if (!isArray!Range && isDigestibleRange!Range) 548 { 549 return toHexString!order(digest!Hash(range)); 550 } 551 552 /// 553 @system unittest 554 { 555 import std.digest.md; 556 import std.range : repeat; 557 auto testRange = repeat!ubyte(cast(ubyte)'a', 100); 558 assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF"); 559 } 560 561 /** 562 * This overload of the hexDigest function handles arrays. 563 * 564 * Params: 565 * order= the order in which the bytes are processed (see $(LREF toHexString)) 566 * data= one or more arrays of any type 567 */ 568 char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data) 569 if (allSatisfy!(isArray, typeof(data))) 570 { 571 return toHexString!order(digest!Hash(data)); 572 } 573 574 /// 575 @system unittest 576 { 577 import std.digest.crc; 578 assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339"); 579 } 580 /// 581 @system unittest 582 { 583 import std.digest.crc; 584 assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339"); 585 } 586 587 /** 588 * This is a convenience function which returns an initialized digest, so it's not necessary to call 589 * start manually. 590 */ 591 Hash makeDigest(Hash)() 592 { 593 Hash hash; 594 hash.start(); 595 return hash; 596 } 597 598 /// 599 @system unittest 600 { 601 import std.digest.md; 602 auto md5 = makeDigest!MD5(); 603 md5.put(0); 604 assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); 605 } 606 607 /*+*************************** End of template part, welcome to OOP land **************************/ 608 609 /** 610 * This describes the OOP API. To understand when to use the template API and when to use the OOP API, 611 * see the module documentation at the top of this page. 612 * 613 * The Digest interface is the base interface which is implemented by all digests. 614 * 615 * Note: 616 * A Digest implementation is always an `OutputRange` 617 */ 618 interface Digest 619 { 620 public: 621 /** 622 * Use this to feed the digest with data. 623 * Also implements the $(REF isOutputRange, std,range,primitives) 624 * interface for `ubyte` and `const(ubyte)[]`. 625 * 626 * Example: 627 * ---- 628 * void test(Digest dig) 629 * { 630 * dig.put(cast(ubyte) 0); //single ubyte 631 * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic 632 * ubyte[10] buf; 633 * dig.put(buf); //buffer 634 * } 635 * ---- 636 */ 637 @trusted nothrow void put(scope const(ubyte)[] data...); 638 639 /** 640 * Resets the internal state of the digest. 641 * Note: 642 * $(LREF finish) calls this internally, so it's not necessary to call 643 * `reset` manually after a call to $(LREF finish). 644 */ 645 @trusted nothrow void reset(); 646 647 /** 648 * This is the length in bytes of the hash value which is returned by $(LREF finish). 649 * It's also the required size of a buffer passed to $(LREF finish). 650 */ 651 @trusted nothrow @property size_t length() const; 652 653 /** 654 * The finish function returns the hash value. It takes an optional buffer to copy the data 655 * into. If a buffer is passed, it must be at least $(LREF length) bytes big. 656 */ 657 @trusted nothrow ubyte[] finish(); 658 ///ditto 659 nothrow ubyte[] finish(ubyte[] buf); 660 // https://issues.dlang.org/show_bug.cgi?id=6549 661 /*in 662 { 663 assert(buf.length >= this.length); 664 }*/ 665 666 /** 667 * This is a convenience function to calculate the hash of a value using the OOP API. 668 */ 669 final @trusted nothrow ubyte[] digest(scope const(void[])[] data...) 670 { 671 this.reset(); 672 foreach (datum; data) 673 this.put(cast(ubyte[]) datum); 674 return this.finish(); 675 } 676 } 677 678 /// 679 @system unittest 680 { 681 //Using the OutputRange feature 682 import std.algorithm.mutation : copy; 683 import std.digest.md; 684 import std.range : repeat; 685 686 auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); 687 auto ctx = new MD5Digest(); 688 copy(oneMillionRange, ctx); 689 assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); 690 } 691 692 /// 693 @system unittest 694 { 695 import std.digest.crc, std.digest.md, std.digest.sha; 696 ubyte[] md5 = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); 697 ubyte[] sha1 = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); 698 ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); 699 assert(crcHexString(crc32) == "414FA339"); 700 } 701 702 /// 703 @system unittest 704 { 705 import std.digest.crc; 706 ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); 707 assert(crcHexString(crc32) == "414FA339"); 708 } 709 710 @system unittest 711 { 712 import std.range : isOutputRange; 713 assert(!isDigest!(Digest)); 714 assert(isOutputRange!(Digest, ubyte)); 715 } 716 717 /// 718 @system unittest 719 { 720 void test(Digest dig) 721 { 722 dig.put(cast(ubyte) 0); //single ubyte 723 dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic 724 ubyte[10] buf; 725 dig.put(buf); //buffer 726 } 727 } 728 729 /*+*************************** End of OOP part, helper functions follow ***************************/ 730 731 /** 732 * See $(LREF toHexString) 733 */ 734 enum Order : bool 735 { 736 increasing, /// 737 decreasing /// 738 } 739 740 /// 741 @safe unittest 742 { 743 import std.digest.crc : CRC32; 744 745 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); 746 assert(crc32.toHexString!(Order.decreasing) == "414FA339"); 747 assert(crc32.toHexString!(LetterCase.lower, Order.decreasing) == "414fa339"); 748 } 749 750 751 /** 752 * Used to convert a hash value (a static or dynamic array of ubytes) to a string. 753 * Can be used with the OOP and with the template API. 754 * 755 * The additional order parameter can be used to specify the order of the input data. 756 * By default the data is processed in increasing order, starting at index 0. To process it in the 757 * opposite order, pass Order.decreasing as a parameter. 758 * 759 * The additional letterCase parameter can be used to specify the case of the output data. 760 * By default the output is in upper case. To change it to the lower case 761 * pass LetterCase.lower as a parameter. 762 * 763 * Note: 764 * The function overloads returning a string allocate their return values 765 * using the GC. The versions returning static arrays use pass-by-value for 766 * the return value, effectively avoiding dynamic allocation. 767 */ 768 char[num*2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper) 769 (const ubyte[num] digest) 770 { 771 772 char[num*2] result; 773 size_t i; 774 toHexStringImpl!(order, letterCase)(digest, result); 775 return result; 776 } 777 778 ///ditto 779 char[num*2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest) 780 { 781 return toHexString!(order, num, letterCase)(digest); 782 } 783 784 ///ditto 785 string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper) 786 (in ubyte[] digest) 787 { 788 auto result = new char[digest.length*2]; 789 toHexStringImpl!(order, letterCase)(digest, result); 790 import std.exception : assumeUnique; 791 // memory was just created, so casting to immutable is safe 792 return () @trusted { return assumeUnique(result); }(); 793 } 794 795 ///ditto 796 string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest) 797 { 798 return toHexString!(order, letterCase)(digest); 799 } 800 801 //For more example unittests, see Digest.digest, digest 802 803 /// 804 @safe unittest 805 { 806 import std.digest.crc; 807 //Test with template API: 808 auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); 809 //Lower case variant: 810 assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41"); 811 //Usually CRCs are printed in this order, though: 812 assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); 813 assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339"); 814 } 815 816 /// 817 @safe unittest 818 { 819 import std.digest.crc; 820 // With OOP API 821 auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); 822 //Usually CRCs are printed in this order, though: 823 assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); 824 } 825 826 @safe unittest 827 { 828 ubyte[16] data; 829 assert(toHexString(data) == "00000000000000000000000000000000"); 830 831 assert(toHexString(cast(ubyte[4])[42, 43, 44, 45]) == "2A2B2C2D"); 832 assert(toHexString(cast(ubyte[])[42, 43, 44, 45]) == "2A2B2C2D"); 833 assert(toHexString!(Order.decreasing)(cast(ubyte[4])[42, 43, 44, 45]) == "2D2C2B2A"); 834 assert(toHexString!(Order.decreasing, LetterCase.lower)(cast(ubyte[4])[42, 43, 44, 45]) == "2d2c2b2a"); 835 assert(toHexString!(Order.decreasing)(cast(ubyte[])[42, 43, 44, 45]) == "2D2C2B2A"); 836 } 837 838 /*+*********************** End of public helper part, private helpers follow ***********************/ 839 840 /* 841 * Used to convert from a ubyte[] slice to a ref ubyte[N]. 842 * This helper is used internally in the WrapperDigest template to wrap the template API's 843 * finish function. 844 */ 845 ref T[N] asArray(size_t N, T)(ref T[] source, string errorMsg = "") 846 { 847 assert(source.length >= N, errorMsg); 848 return *cast(T[N]*) source.ptr; 849 } 850 851 /* 852 * Fill in a preallocated buffer with the ASCII hex representation from a byte buffer 853 */ 854 private void toHexStringImpl(Order order, LetterCase letterCase, BB, HB) 855 (scope const ref BB byteBuffer, ref HB hexBuffer){ 856 static if (letterCase == LetterCase.upper) 857 { 858 import std.ascii : hexDigits = hexDigits; 859 } 860 else 861 { 862 import std.ascii : hexDigits = lowerHexDigits; 863 } 864 865 size_t i; 866 static if (order == Order.increasing) 867 { 868 foreach (u; byteBuffer) 869 { 870 hexBuffer[i++] = hexDigits[u >> 4]; 871 hexBuffer[i++] = hexDigits[u & 15]; 872 } 873 } 874 else 875 { 876 size_t j = byteBuffer.length -1; 877 while (i < byteBuffer.length*2) 878 { 879 hexBuffer[i++] = hexDigits[byteBuffer[j] >> 4]; 880 hexBuffer[i++] = hexDigits[byteBuffer[j] & 15]; 881 j--; 882 } 883 } 884 } 885 886 887 /* 888 * Returns the length (in bytes) of the hash value produced by T. 889 */ 890 template digestLength(T) 891 if (isDigest!T) 892 { 893 enum size_t digestLength = (ReturnType!(T.finish)).length; 894 } 895 896 @safe pure nothrow @nogc 897 unittest 898 { 899 import std.digest.md : MD5; 900 import std.digest.sha : SHA1, SHA256, SHA512; 901 assert(digestLength!MD5 == 16); 902 assert(digestLength!SHA1 == 20); 903 assert(digestLength!SHA256 == 32); 904 assert(digestLength!SHA512 == 64); 905 } 906 907 /** 908 * Wraps a template API hash struct into a Digest interface. 909 * Modules providing digest implementations will usually provide 910 * an alias for this template (e.g. MD5Digest, SHA1Digest, ...). 911 */ 912 class WrapperDigest(T) 913 if (isDigest!T) : Digest 914 { 915 protected: 916 T _digest; 917 918 public final: 919 /** 920 * Initializes the digest. 921 */ 922 this() 923 { 924 _digest.start(); 925 } 926 927 /** 928 * Use this to feed the digest with data. 929 * Also implements the $(REF isOutputRange, std,range,primitives) 930 * interface for `ubyte` and `const(ubyte)[]`. 931 */ 932 @trusted nothrow void put(scope const(ubyte)[] data...) 933 { 934 _digest.put(data); 935 } 936 937 /** 938 * Resets the internal state of the digest. 939 * Note: 940 * $(LREF finish) calls this internally, so it's not necessary to call 941 * `reset` manually after a call to $(LREF finish). 942 */ 943 @trusted nothrow void reset() 944 { 945 _digest.start(); 946 } 947 948 /** 949 * This is the length in bytes of the hash value which is returned by $(LREF finish). 950 * It's also the required size of a buffer passed to $(LREF finish). 951 */ 952 @trusted nothrow @property size_t length() const pure 953 { 954 return digestLength!T; 955 } 956 957 /** 958 * The finish function returns the hash value. It takes an optional buffer to copy the data 959 * into. If a buffer is passed, it must have a length at least $(LREF length) bytes. 960 * 961 * Example: 962 * -------- 963 * 964 * import std.digest.md; 965 * ubyte[16] buf; 966 * auto hash = new WrapperDigest!MD5(); 967 * hash.put(cast(ubyte) 0); 968 * auto result = hash.finish(buf[]); 969 * //The result is now in result (and in buf). If you pass a buffer which is bigger than 970 * //necessary, result will have the correct length, but buf will still have it's original 971 * //length 972 * -------- 973 */ 974 nothrow ubyte[] finish(ubyte[] buf) 975 in 976 { 977 assert(buf.length >= this.length, "Given buffer is smaller than the local buffer."); 978 } 979 do 980 { 981 enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ 982 "big, check " ~ typeof(this).stringof ~ ".length!"; 983 asArray!(digestLength!T)(buf, msg) = _digest.finish(); 984 return buf[0 .. digestLength!T]; 985 } 986 987 ///ditto 988 @trusted nothrow ubyte[] finish() 989 { 990 enum len = digestLength!T; 991 auto buf = new ubyte[len]; 992 asArray!(digestLength!T)(buf) = _digest.finish(); 993 return buf; 994 } 995 996 version (StdDdoc) 997 { 998 /** 999 * Works like `finish` but does not reset the internal state, so it's possible 1000 * to continue putting data into this WrapperDigest after a call to peek. 1001 * 1002 * These functions are only available if `hasPeek!T` is true. 1003 */ 1004 @trusted ubyte[] peek(ubyte[] buf) const; 1005 ///ditto 1006 @trusted ubyte[] peek() const; 1007 } 1008 else static if (hasPeek!T) 1009 { 1010 @trusted ubyte[] peek(ubyte[] buf) const 1011 in 1012 { 1013 assert(buf.length >= this.length, "Given buffer is smaller than the local buffer."); 1014 } 1015 do 1016 { 1017 enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ 1018 "big, check " ~ typeof(this).stringof ~ ".length!"; 1019 asArray!(digestLength!T)(buf, msg) = _digest.peek(); 1020 return buf[0 .. digestLength!T]; 1021 } 1022 1023 @trusted ubyte[] peek() const 1024 { 1025 enum len = digestLength!T; 1026 auto buf = new ubyte[len]; 1027 asArray!(digestLength!T)(buf) = _digest.peek(); 1028 return buf; 1029 } 1030 } 1031 } 1032 1033 /// 1034 @system unittest 1035 { 1036 import std.digest.md; 1037 //Simple example 1038 auto hash = new WrapperDigest!MD5(); 1039 hash.put(cast(ubyte) 0); 1040 auto result = hash.finish(); 1041 } 1042 1043 /// 1044 @system unittest 1045 { 1046 //using a supplied buffer 1047 import std.digest.md; 1048 ubyte[16] buf; 1049 auto hash = new WrapperDigest!MD5(); 1050 hash.put(cast(ubyte) 0); 1051 auto result = hash.finish(buf[]); 1052 //The result is now in result (and in buf). If you pass a buffer which is bigger than 1053 //necessary, result will have the correct length, but buf will still have it's original 1054 //length 1055 } 1056 1057 @safe unittest 1058 { 1059 // Test peek & length 1060 import std.digest.crc; 1061 auto hash = new WrapperDigest!CRC32(); 1062 assert(hash.length == 4); 1063 hash.put(cast(const(ubyte[]))"The quick brown fox jumps over the lazy dog"); 1064 assert(hash.peek().toHexString() == "39A34F41"); 1065 ubyte[5] buf; 1066 assert(hash.peek(buf).toHexString() == "39A34F41"); 1067 } 1068 1069 /** 1070 * Securely compares two digest representations while protecting against timing 1071 * attacks. Do not use `==` to compare digest representations. 1072 * 1073 * The attack happens as follows: 1074 * 1075 * $(OL 1076 * $(LI An attacker wants to send harmful data to your server, which 1077 * requires a integrity HMAC SHA1 token signed with a secret.) 1078 * $(LI The length of the token is known to be 40 characters long due to its format, 1079 * so the attacker first sends `"0000000000000000000000000000000000000000"`, 1080 * then `"1000000000000000000000000000000000000000"`, and so on.) 1081 * $(LI The given HMAC token is compared with the expected token using the 1082 * `==` string comparison, which returns `false` as soon as the first wrong 1083 * element is found. If a wrong element is found, then a rejection is sent 1084 * back to the sender.) 1085 * $(LI Eventually, the attacker is able to determine the first character in 1086 * the correct token because the sever takes slightly longer to return a 1087 * rejection. This is due to the comparison moving on to second item in 1088 * the two arrays, seeing they are different, and then sending the rejection.) 1089 * $(LI It may seem like too small of a difference in time for the attacker 1090 * to notice, but security researchers have shown that differences as 1091 * small as $(LINK2 http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf, 1092 * 20µs can be reliably distinguished) even with network inconsistencies.) 1093 * $(LI Repeat the process for each character until the attacker has the whole 1094 * correct token and the server accepts the harmful data. This can be done 1095 * in a week with the attacker pacing the attack to 10 requests per second 1096 * with only one client.) 1097 * ) 1098 * 1099 * This function defends against this attack by always comparing every single 1100 * item in the array if the two arrays are the same length. Therefore, this 1101 * function is always $(BIGOH n) for ranges of the same length. 1102 * 1103 * This attack can also be mitigated via rate limiting and banning IPs which have too 1104 * many rejected requests. However, this does not completely solve the problem, 1105 * as the attacker could be in control of a bot net. To fully defend against 1106 * the timing attack, rate limiting, banning IPs, and using this function 1107 * should be used together. 1108 * 1109 * Params: 1110 * r1 = A digest representation 1111 * r2 = A digest representation 1112 * Returns: 1113 * `true` if both representations are equal, `false` otherwise 1114 * See_Also: 1115 * $(LINK2 https://en.wikipedia.org/wiki/Timing_attack, The Wikipedia article 1116 * on timing attacks). 1117 */ 1118 bool secureEqual(R1, R2)(R1 r1, R2 r2) 1119 if (isInputRange!R1 && isInputRange!R2 && !isInfinite!R1 && !isInfinite!R2 && 1120 (isIntegral!(ElementEncodingType!R1) || isSomeChar!(ElementEncodingType!R1)) && 1121 !is(CommonType!(ElementEncodingType!R1, ElementEncodingType!R2) == void)) 1122 { 1123 static if (hasLength!R1 && hasLength!R2) 1124 if (r1.length != r2.length) 1125 return false; 1126 1127 int result; 1128 1129 static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && 1130 hasLength!R1 && hasLength!R2) 1131 { 1132 foreach (i; 0 .. r1.length) 1133 result |= r1[i] ^ r2[i]; 1134 } 1135 else static if (hasLength!R1 && hasLength!R2) 1136 { 1137 // Lengths are the same so we can squeeze out a bit of performance 1138 // by not checking if r2 is empty 1139 for (; !r1.empty; r1.popFront(), r2.popFront()) 1140 { 1141 result |= r1.front ^ r2.front; 1142 } 1143 } 1144 else 1145 { 1146 // Generic case, walk both ranges 1147 for (; !r1.empty; r1.popFront(), r2.popFront()) 1148 { 1149 if (r2.empty) return false; 1150 result |= r1.front ^ r2.front; 1151 } 1152 if (!r2.empty) return false; 1153 } 1154 1155 return result == 0; 1156 } 1157 1158 /// 1159 @system pure unittest 1160 { 1161 import std.digest.hmac : hmac; 1162 import std.digest.sha : SHA1; 1163 import std.string : representation; 1164 1165 // a typical HMAC data integrity verification 1166 auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation; 1167 auto data = "data".representation; 1168 1169 auto hex1 = data.hmac!SHA1(secret).toHexString; 1170 auto hex2 = data.hmac!SHA1(secret).toHexString; 1171 auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString; 1172 1173 assert( secureEqual(hex1[], hex2[])); 1174 assert(!secureEqual(hex1[], hex3[])); 1175 } 1176 1177 @system pure unittest 1178 { 1179 import std.internal.test.dummyrange : ReferenceInputRange; 1180 import std.range : takeExactly; 1181 import std.string : representation; 1182 import std.utf : byWchar, byDchar; 1183 1184 { 1185 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".representation; 1186 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".representation; 1187 assert(!secureEqual(hex1, hex2)); 1188 } 1189 { 1190 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018"w.representation; 1191 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018"d.representation; 1192 assert(secureEqual(hex1, hex2)); 1193 } 1194 { 1195 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byWchar; 1196 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar; 1197 assert(secureEqual(hex1, hex2)); 1198 } 1199 { 1200 auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".byWchar; 1201 auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar; 1202 assert(!secureEqual(hex1, hex2)); 1203 } 1204 { 1205 auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); 1206 auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); 1207 assert(secureEqual(hex1, hex2)); 1208 } 1209 { 1210 auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); 1211 auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 9]).takeExactly(9); 1212 assert(!secureEqual(hex1, hex2)); 1213 } 1214 }