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 (in 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 }
Suggestion Box / Bug Report