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
main(string[]args)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
uMain(string[]args)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.
digestFile(Digest hash,string filename)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
umain(string[]args)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
version(ExampleDigest)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 }
1215