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