xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/src/std/digest/package.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg /**
2*b1e83836Smrg  * This module describes the digest APIs used in Phobos. All digests follow
3181254a7Smrg  * these APIs. Additionally, this module contains useful helper methods which
4*b1e83836Smrg  * can be used with every digest type.
5181254a7Smrg  *
6181254a7Smrg $(SCRIPT inhibitQuickIndex = 1;)
7181254a7Smrg 
8181254a7Smrg $(DIVC quickindex,
9181254a7Smrg $(BOOKTABLE ,
10181254a7Smrg $(TR $(TH Category) $(TH Functions)
11181254a7Smrg )
12181254a7Smrg $(TR $(TDNW Template API) $(TD $(MYREF isDigest) $(MYREF DigestType) $(MYREF hasPeek)
13181254a7Smrg   $(MYREF hasBlockSize)
14*b1e83836Smrg   $(MYREF ExampleDigest) $(MYREF digest) $(MYREF hexDigest) $(MYREF makeDigest)
15181254a7Smrg )
16181254a7Smrg )
17181254a7Smrg $(TR $(TDNW OOP API) $(TD $(MYREF Digest)
18181254a7Smrg )
19181254a7Smrg )
20*b1e83836Smrg $(TR $(TDNW Helper functions) $(TD $(MYREF toHexString) $(MYREF secureEqual))
21181254a7Smrg )
22181254a7Smrg $(TR $(TDNW Implementation helpers) $(TD $(MYREF digestLength) $(MYREF WrapperDigest))
23181254a7Smrg )
24181254a7Smrg )
25181254a7Smrg )
26181254a7Smrg 
27181254a7Smrg  * APIs:
28181254a7Smrg  * There are two APIs for digests: The template API and the OOP API. The template API uses structs
29181254a7Smrg  * and template helpers like $(LREF isDigest). The OOP API implements digests as classes inheriting
30181254a7Smrg  * the $(LREF Digest) interface. All digests are named so that the template API struct is called "$(B x)"
31*b1e83836Smrg  * and the OOP API class is called "$(B x)Digest". For example we have `MD5` <--> `MD5Digest`,
32*b1e83836Smrg  * `CRC32` <--> `CRC32Digest`, etc.
33181254a7Smrg  *
34181254a7Smrg  * The template API is slightly more efficient. It does not have to allocate memory dynamically,
35181254a7Smrg  * all memory is allocated on the stack. The OOP API has to allocate in the finish method if no
36181254a7Smrg  * buffer was provided. If you provide a buffer to the OOP APIs finish function, it doesn't allocate,
37*b1e83836Smrg  * but the $(LREF Digest) classes still have to be created using `new` which allocates them using the GC.
38181254a7Smrg  *
39*b1e83836Smrg  * The OOP API is useful to change the digest function and/or digest backend at 'runtime'. The benefit here
40181254a7Smrg  * is that switching e.g. Phobos MD5Digest and an OpenSSLMD5Digest implementation is ABI compatible.
41181254a7Smrg  *
42*b1e83836Smrg  * If just one specific digest type and backend is needed, the template API is usually a good fit.
43181254a7Smrg  * In this simplest case, the template API can even be used without templates: Just use the "$(B x)" structs
44181254a7Smrg  * directly.
45181254a7Smrg  *
46181254a7Smrg  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
47181254a7Smrg  * Authors:
48181254a7Smrg  * Johannes Pfau
49181254a7Smrg  *
50*b1e83836Smrg  * Source:    $(PHOBOSSRC std/digest/package.d)
51181254a7Smrg  *
52181254a7Smrg  * CTFE:
53181254a7Smrg  * Digests do not work in CTFE
54181254a7Smrg  *
55181254a7Smrg  * TODO:
56181254a7Smrg  * Digesting single bits (as opposed to bytes) is not implemented. This will be done as another
57181254a7Smrg  * template constraint helper (hasBitDigesting!T) and an additional interface (BitDigest)
58181254a7Smrg  */
59181254a7Smrg /*          Copyright Johannes Pfau 2012.
60181254a7Smrg  * Distributed under the Boost Software License, Version 1.0.
61181254a7Smrg  *    (See accompanying file LICENSE_1_0.txt or copy at
62181254a7Smrg  *          http://www.boost.org/LICENSE_1_0.txt)
63181254a7Smrg  */
64181254a7Smrg module std.digest;
65181254a7Smrg 
66181254a7Smrg public import std.ascii : LetterCase;
67181254a7Smrg import std.meta : allSatisfy;
68181254a7Smrg import std.range.primitives;
69181254a7Smrg import std.traits;
70181254a7Smrg 
71181254a7Smrg 
72181254a7Smrg ///
73181254a7Smrg @system unittest
74181254a7Smrg {
75181254a7Smrg     import std.digest.crc;
76181254a7Smrg 
77181254a7Smrg     //Simple example
78181254a7Smrg     char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog");
79181254a7Smrg     assert(hexHash == "39A34F41");
80181254a7Smrg 
81181254a7Smrg     //Simple example, using the API manually
82181254a7Smrg     CRC32 context = makeDigest!CRC32();
83181254a7Smrg     context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog");
84181254a7Smrg     ubyte[4] hash = context.finish();
85181254a7Smrg     assert(toHexString(hash) == "39A34F41");
86181254a7Smrg }
87181254a7Smrg 
88181254a7Smrg ///
89181254a7Smrg @system unittest
90181254a7Smrg {
91181254a7Smrg     //Generating the hashes of a file, idiomatic D way
92181254a7Smrg     import std.digest.crc, std.digest.md, std.digest.sha;
93181254a7Smrg     import std.stdio;
94181254a7Smrg 
95181254a7Smrg     // Digests a file and prints the result.
96181254a7Smrg     void digestFile(Hash)(string filename)
97181254a7Smrg     if (isDigest!Hash)
98181254a7Smrg     {
99181254a7Smrg         auto file = File(filename);
100181254a7Smrg         auto result = digest!Hash(file.byChunk(4096 * 1024));
101181254a7Smrg         writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result));
102181254a7Smrg     }
103181254a7Smrg 
main(string[]args)104181254a7Smrg     void main(string[] args)
105181254a7Smrg     {
106181254a7Smrg         foreach (name; args[1 .. $])
107181254a7Smrg         {
108181254a7Smrg             digestFile!MD5(name);
109181254a7Smrg             digestFile!SHA1(name);
110181254a7Smrg             digestFile!CRC32(name);
111181254a7Smrg         }
112181254a7Smrg     }
113181254a7Smrg }
114181254a7Smrg ///
115181254a7Smrg @system unittest
116181254a7Smrg {
117181254a7Smrg     //Generating the hashes of a file using the template API
118181254a7Smrg     import std.digest.crc, std.digest.md, std.digest.sha;
119181254a7Smrg     import std.stdio;
120181254a7Smrg     // Digests a file and prints the result.
121181254a7Smrg     void digestFile(Hash)(ref Hash hash, string filename)
122181254a7Smrg     if (isDigest!Hash)
123181254a7Smrg     {
124181254a7Smrg         File file = File(filename);
125181254a7Smrg 
126181254a7Smrg         //As digests imlement OutputRange, we could use std.algorithm.copy
127181254a7Smrg         //Let's do it manually for now
128181254a7Smrg         foreach (buffer; file.byChunk(4096 * 1024))
129181254a7Smrg             hash.put(buffer);
130181254a7Smrg 
131181254a7Smrg         auto result = hash.finish();
132181254a7Smrg         writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result));
133181254a7Smrg     }
134181254a7Smrg 
uMain(string[]args)135181254a7Smrg     void uMain(string[] args)
136181254a7Smrg     {
137181254a7Smrg         MD5 md5;
138181254a7Smrg         SHA1 sha1;
139181254a7Smrg         CRC32 crc32;
140181254a7Smrg 
141181254a7Smrg         md5.start();
142181254a7Smrg         sha1.start();
143181254a7Smrg         crc32.start();
144181254a7Smrg 
145181254a7Smrg         foreach (arg; args[1 .. $])
146181254a7Smrg         {
147181254a7Smrg             digestFile(md5, arg);
148181254a7Smrg             digestFile(sha1, arg);
149181254a7Smrg             digestFile(crc32, arg);
150181254a7Smrg         }
151181254a7Smrg     }
152181254a7Smrg }
153181254a7Smrg 
154181254a7Smrg ///
155181254a7Smrg @system unittest
156181254a7Smrg {
157181254a7Smrg     import std.digest.crc, std.digest.md, std.digest.sha;
158181254a7Smrg     import std.stdio;
159181254a7Smrg 
160181254a7Smrg     // Digests a file and prints the result.
digestFile(Digest hash,string filename)161181254a7Smrg     void digestFile(Digest hash, string filename)
162181254a7Smrg     {
163181254a7Smrg         File file = File(filename);
164181254a7Smrg 
165181254a7Smrg         //As digests implement OutputRange, we could use std.algorithm.copy
166181254a7Smrg         //Let's do it manually for now
167181254a7Smrg         foreach (buffer; file.byChunk(4096 * 1024))
168181254a7Smrg           hash.put(buffer);
169181254a7Smrg 
170181254a7Smrg         ubyte[] result = hash.finish();
171181254a7Smrg         writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result));
172181254a7Smrg     }
173181254a7Smrg 
umain(string[]args)174181254a7Smrg     void umain(string[] args)
175181254a7Smrg     {
176181254a7Smrg         auto md5 = new MD5Digest();
177181254a7Smrg         auto sha1 = new SHA1Digest();
178181254a7Smrg         auto crc32 = new CRC32Digest();
179181254a7Smrg 
180181254a7Smrg         foreach (arg; args[1 .. $])
181181254a7Smrg         {
182181254a7Smrg           digestFile(md5, arg);
183181254a7Smrg           digestFile(sha1, arg);
184181254a7Smrg           digestFile(crc32, arg);
185181254a7Smrg         }
186181254a7Smrg     }
187181254a7Smrg }
188181254a7Smrg 
189181254a7Smrg version (StdDdoc)
190181254a7Smrg     version = ExampleDigest;
191181254a7Smrg 
version(ExampleDigest)192181254a7Smrg version (ExampleDigest)
193181254a7Smrg {
194181254a7Smrg     /**
195181254a7Smrg      * This documents the general structure of a Digest in the template API.
196181254a7Smrg      * All digest implementations should implement the following members and therefore pass
197181254a7Smrg      * the $(LREF isDigest) test.
198181254a7Smrg      *
199181254a7Smrg      * Note:
200181254a7Smrg      * $(UL
201181254a7Smrg      * $(LI A digest must be a struct (value type) to pass the $(LREF isDigest) test.)
202*b1e83836Smrg      * $(LI A digest passing the $(LREF isDigest) test is always an `OutputRange`)
203181254a7Smrg      * )
204181254a7Smrg      */
205181254a7Smrg     struct ExampleDigest
206181254a7Smrg     {
207181254a7Smrg         public:
208181254a7Smrg             /**
209181254a7Smrg              * Use this to feed the digest with data.
210181254a7Smrg              * Also implements the $(REF isOutputRange, std,range,primitives)
211*b1e83836Smrg              * interface for `ubyte` and `const(ubyte)[]`.
212*b1e83836Smrg              * The following usages of `put` must work for any type which
213181254a7Smrg              * passes $(LREF isDigest):
214181254a7Smrg              * Example:
215181254a7Smrg              * ----
216181254a7Smrg              * ExampleDigest dig;
217181254a7Smrg              * dig.put(cast(ubyte) 0); //single ubyte
218181254a7Smrg              * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic
219181254a7Smrg              * ubyte[10] buf;
220181254a7Smrg              * dig.put(buf); //buffer
221181254a7Smrg              * ----
222181254a7Smrg              */
223181254a7Smrg             @trusted void put(scope const(ubyte)[] data...)
224181254a7Smrg             {
225181254a7Smrg 
226181254a7Smrg             }
227181254a7Smrg 
228181254a7Smrg             /**
229181254a7Smrg              * This function is used to (re)initialize the digest.
230181254a7Smrg              * It must be called before using the digest and it also works as a 'reset' function
231181254a7Smrg              * if the digest has already processed data.
232181254a7Smrg              */
233181254a7Smrg             @trusted void start()
234181254a7Smrg             {
235181254a7Smrg 
236181254a7Smrg             }
237181254a7Smrg 
238181254a7Smrg             /**
239181254a7Smrg              * The finish function returns the final hash sum and resets the Digest.
240181254a7Smrg              *
241181254a7Smrg              * Note:
242181254a7Smrg              * The actual type returned by finish depends on the digest implementation.
243*b1e83836Smrg              * `ubyte[16]` is just used as an example. It is guaranteed that the type is a
244181254a7Smrg              * static array of ubytes.
245181254a7Smrg              *
246181254a7Smrg              * $(UL
247181254a7Smrg              * $(LI Use $(LREF DigestType) to obtain the actual return type.)
248181254a7Smrg              * $(LI Use $(LREF digestLength) to obtain the length of the ubyte array.)
249181254a7Smrg              * )
250181254a7Smrg              */
251181254a7Smrg             @trusted ubyte[16] finish()
252181254a7Smrg             {
253181254a7Smrg                 return (ubyte[16]).init;
254181254a7Smrg             }
255181254a7Smrg     }
256181254a7Smrg }
257181254a7Smrg 
258181254a7Smrg ///
259181254a7Smrg @system unittest
260181254a7Smrg {
261181254a7Smrg     //Using the OutputRange feature
262181254a7Smrg     import std.algorithm.mutation : copy;
263181254a7Smrg     import std.digest.md;
264181254a7Smrg     import std.range : repeat;
265181254a7Smrg 
266181254a7Smrg     auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
267181254a7Smrg     auto ctx = makeDigest!MD5();
268181254a7Smrg     copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy!
269181254a7Smrg     assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21");
270181254a7Smrg }
271181254a7Smrg 
272181254a7Smrg /**
273181254a7Smrg  * Use this to check if a type is a digest. See $(LREF ExampleDigest) to see what
274181254a7Smrg  * a type must provide to pass this check.
275181254a7Smrg  *
276181254a7Smrg  * Note:
277181254a7Smrg  * This is very useful as a template constraint (see examples)
278181254a7Smrg  *
279181254a7Smrg  * BUGS:
280181254a7Smrg  * $(UL
281181254a7Smrg  * $(LI Does not yet verify that put takes scope parameters.)
282181254a7Smrg  * $(LI Should check that finish() returns a ubyte[num] array)
283181254a7Smrg  * )
284181254a7Smrg  */
285181254a7Smrg template isDigest(T)
286181254a7Smrg {
287181254a7Smrg     import std.range : isOutputRange;
288181254a7Smrg     enum bool isDigest = isOutputRange!(T, const(ubyte)[]) && isOutputRange!(T, ubyte) &&
289181254a7Smrg         is(T == struct) &&
290181254a7Smrg         is(typeof(
291181254a7Smrg         {
292181254a7Smrg             T dig = void; //Can define
293181254a7Smrg             dig.put(cast(ubyte) 0, cast(ubyte) 0); //varags
294181254a7Smrg             dig.start(); //has start
295181254a7Smrg             auto value = dig.finish(); //has finish
296181254a7Smrg         }));
297181254a7Smrg }
298181254a7Smrg 
299181254a7Smrg ///
300181254a7Smrg @system unittest
301181254a7Smrg {
302181254a7Smrg     import std.digest.crc;
303181254a7Smrg     static assert(isDigest!CRC32);
304181254a7Smrg }
305181254a7Smrg ///
306181254a7Smrg @system unittest
307181254a7Smrg {
308181254a7Smrg     import std.digest.crc;
309181254a7Smrg     void myFunction(T)()
310181254a7Smrg     if (isDigest!T)
311181254a7Smrg     {
312181254a7Smrg         T dig;
313181254a7Smrg         dig.start();
314181254a7Smrg         auto result = dig.finish();
315181254a7Smrg     }
316181254a7Smrg     myFunction!CRC32();
317181254a7Smrg }
318181254a7Smrg 
319181254a7Smrg /**
320181254a7Smrg  * Use this template to get the type which is returned by a digest's $(LREF finish) method.
321181254a7Smrg  */
322181254a7Smrg template DigestType(T)
323181254a7Smrg {
324181254a7Smrg     static if (isDigest!T)
325181254a7Smrg     {
326181254a7Smrg         alias DigestType =
327181254a7Smrg             ReturnType!(typeof(
328181254a7Smrg             {
329181254a7Smrg                 T dig = void;
330181254a7Smrg                 return dig.finish();
331181254a7Smrg             }));
332181254a7Smrg     }
333181254a7Smrg     else
334181254a7Smrg         static assert(false, T.stringof ~ " is not a digest! (fails isDigest!T)");
335181254a7Smrg }
336181254a7Smrg 
337181254a7Smrg ///
338181254a7Smrg @system unittest
339181254a7Smrg {
340181254a7Smrg     import std.digest.crc;
341181254a7Smrg     assert(is(DigestType!(CRC32) == ubyte[4]));
342181254a7Smrg }
343181254a7Smrg ///
344181254a7Smrg @system unittest
345181254a7Smrg {
346181254a7Smrg     import std.digest.crc;
347181254a7Smrg     CRC32 dig;
348181254a7Smrg     dig.start();
349181254a7Smrg     DigestType!CRC32 result = dig.finish();
350181254a7Smrg }
351181254a7Smrg 
352181254a7Smrg /**
353*b1e83836Smrg  * Used to check if a digest supports the `peek` method.
354181254a7Smrg  * Peek has exactly the same function signatures as finish, but it doesn't reset
355181254a7Smrg  * the digest's internal state.
356181254a7Smrg  *
357181254a7Smrg  * Note:
358181254a7Smrg  * $(UL
359181254a7Smrg  * $(LI This is very useful as a template constraint (see examples))
360181254a7Smrg  * $(LI This also checks if T passes $(LREF isDigest))
361181254a7Smrg  * )
362181254a7Smrg  */
363181254a7Smrg template hasPeek(T)
364181254a7Smrg {
365181254a7Smrg     enum bool hasPeek = isDigest!T &&
366181254a7Smrg         is(typeof(
367181254a7Smrg         {
368181254a7Smrg             T dig = void; //Can define
369181254a7Smrg             DigestType!T val = dig.peek();
370181254a7Smrg         }));
371181254a7Smrg }
372181254a7Smrg 
373181254a7Smrg ///
374181254a7Smrg @system unittest
375181254a7Smrg {
376181254a7Smrg     import std.digest.crc, std.digest.md;
377181254a7Smrg     assert(!hasPeek!(MD5));
378181254a7Smrg     assert(hasPeek!CRC32);
379181254a7Smrg }
380181254a7Smrg ///
381181254a7Smrg @system unittest
382181254a7Smrg {
383181254a7Smrg     import std.digest.crc;
384181254a7Smrg     void myFunction(T)()
385181254a7Smrg     if (hasPeek!T)
386181254a7Smrg     {
387181254a7Smrg         T dig;
388181254a7Smrg         dig.start();
389181254a7Smrg         auto result = dig.peek();
390181254a7Smrg     }
391181254a7Smrg     myFunction!CRC32();
392181254a7Smrg }
393181254a7Smrg 
394181254a7Smrg /**
395*b1e83836Smrg  * Checks whether the digest has a `blockSize` member, which contains the
396181254a7Smrg  * digest's internal block size in bits. It is primarily used by $(REF HMAC, std,digest,hmac).
397181254a7Smrg  */
398181254a7Smrg 
399181254a7Smrg template hasBlockSize(T)
400181254a7Smrg if (isDigest!T)
401181254a7Smrg {
402181254a7Smrg     enum bool hasBlockSize = __traits(compiles, { size_t blockSize = T.blockSize; });
403181254a7Smrg }
404181254a7Smrg 
405181254a7Smrg ///
406181254a7Smrg @system unittest
407181254a7Smrg {
408181254a7Smrg     import std.digest.hmac, std.digest.md;
409181254a7Smrg     static assert(hasBlockSize!MD5        && MD5.blockSize      == 512);
410181254a7Smrg     static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512);
411181254a7Smrg }
412181254a7Smrg 
413181254a7Smrg package template isDigestibleRange(Range)
414181254a7Smrg {
415181254a7Smrg     import std.digest.md;
416181254a7Smrg     import std.range : isInputRange, ElementType;
417181254a7Smrg     enum bool isDigestibleRange = isInputRange!Range && is(typeof(
418181254a7Smrg           {
419181254a7Smrg           MD5 ha; //Could use any conformant hash
420181254a7Smrg           ElementType!Range val;
421181254a7Smrg           ha.put(val);
422181254a7Smrg           }));
423181254a7Smrg }
424181254a7Smrg 
425181254a7Smrg /**
426181254a7Smrg  * This is a convenience function to calculate a hash using the template API.
427181254a7Smrg  * Every digest passing the $(LREF isDigest) test can be used with this function.
428181254a7Smrg  *
429181254a7Smrg  * Params:
430*b1e83836Smrg  *  range= an `InputRange` with `ElementType` `ubyte`, `ubyte[]` or `ubyte[num]`
431181254a7Smrg  */
432181254a7Smrg DigestType!Hash digest(Hash, Range)(auto ref Range range)
433181254a7Smrg if (!isArray!Range
434181254a7Smrg     && isDigestibleRange!Range)
435181254a7Smrg {
436181254a7Smrg     Hash hash;
437181254a7Smrg     hash.start();
438*b1e83836Smrg     alias E = ElementType!Range; // Not necessarily ubyte. Could be ubyte[N] or ubyte[] or something w/alias this.
439*b1e83836Smrg     static if (!(__traits(isScalar, E) && E.sizeof == 1))
440*b1e83836Smrg     {
441*b1e83836Smrg         foreach (e; range)
442*b1e83836Smrg             hash.put(e);
443181254a7Smrg         return hash.finish();
444181254a7Smrg     }
445*b1e83836Smrg     else
446*b1e83836Smrg     {
447*b1e83836Smrg         static if (hasBlockSize!Hash)
448*b1e83836Smrg             enum bufferBytes = Hash.blockSize >= (8192 * 8) ? 8192 : Hash.blockSize <= 64 ? 8 : (Hash.blockSize / 8);
449*b1e83836Smrg         else
450*b1e83836Smrg             enum bufferBytes = 8;
451*b1e83836Smrg         ubyte[bufferBytes] buffer = void;
452*b1e83836Smrg         static if (isRandomAccessRange!Range && hasLength!Range)
453*b1e83836Smrg         {
454*b1e83836Smrg             const end = range.length;
455*b1e83836Smrg             size_t i = 0;
456*b1e83836Smrg             while (end - i >= buffer.length)
457*b1e83836Smrg             {
458*b1e83836Smrg                 foreach (ref e; buffer)
459*b1e83836Smrg                     e = range[i++];
460*b1e83836Smrg                 hash.put(buffer);
461*b1e83836Smrg             }
462*b1e83836Smrg             if (const remaining = end - i)
463*b1e83836Smrg             {
464*b1e83836Smrg                 foreach (ref e; buffer[0 .. remaining])
465*b1e83836Smrg                     e = range[i++];
466*b1e83836Smrg                 hash.put(buffer[0 .. remaining]);
467*b1e83836Smrg             }
468*b1e83836Smrg             return hash.finish();
469*b1e83836Smrg         }
470*b1e83836Smrg         else
471*b1e83836Smrg         {
472*b1e83836Smrg             for (;;)
473*b1e83836Smrg             {
474*b1e83836Smrg                 size_t n = buffer.length;
475*b1e83836Smrg                 foreach (i, ref e; buffer)
476*b1e83836Smrg                 {
477*b1e83836Smrg                     if (range.empty)
478*b1e83836Smrg                     {
479*b1e83836Smrg                         n = i;
480*b1e83836Smrg                         break;
481*b1e83836Smrg                     }
482*b1e83836Smrg                     e = range.front;
483*b1e83836Smrg                     range.popFront();
484*b1e83836Smrg                 }
485*b1e83836Smrg                 if (n)
486*b1e83836Smrg                     hash.put(buffer[0 .. n]);
487*b1e83836Smrg                 if (n != buffer.length)
488*b1e83836Smrg                     return hash.finish();
489*b1e83836Smrg             }
490*b1e83836Smrg         }
491*b1e83836Smrg     }
492*b1e83836Smrg }
493181254a7Smrg 
494181254a7Smrg ///
495181254a7Smrg @system unittest
496181254a7Smrg {
497181254a7Smrg     import std.digest.md;
498181254a7Smrg     import std.range : repeat;
499181254a7Smrg     auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
500181254a7Smrg     auto md5 = digest!MD5(testRange);
501181254a7Smrg }
502181254a7Smrg 
503181254a7Smrg /**
504181254a7Smrg  * This overload of the digest function handles arrays.
505181254a7Smrg  *
506181254a7Smrg  * Params:
507181254a7Smrg  *  data= one or more arrays of any type
508181254a7Smrg  */
509181254a7Smrg DigestType!Hash digest(Hash, T...)(scope const T data)
510181254a7Smrg if (allSatisfy!(isArray, typeof(data)))
511181254a7Smrg {
512181254a7Smrg     Hash hash;
513181254a7Smrg     hash.start();
514181254a7Smrg     foreach (datum; data)
515181254a7Smrg         hash.put(cast(const(ubyte[]))datum);
516181254a7Smrg     return hash.finish();
517181254a7Smrg }
518181254a7Smrg 
519181254a7Smrg ///
520181254a7Smrg @system unittest
521181254a7Smrg {
522181254a7Smrg     import std.digest.crc, std.digest.md, std.digest.sha;
523181254a7Smrg     auto md5   = digest!MD5(  "The quick brown fox jumps over the lazy dog");
524181254a7Smrg     auto sha1  = digest!SHA1( "The quick brown fox jumps over the lazy dog");
525181254a7Smrg     auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog");
526181254a7Smrg     assert(toHexString(crc32) == "39A34F41");
527181254a7Smrg }
528181254a7Smrg 
529181254a7Smrg ///
530181254a7Smrg @system unittest
531181254a7Smrg {
532181254a7Smrg     import std.digest.crc;
533181254a7Smrg     auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
534181254a7Smrg     assert(toHexString(crc32) == "39A34F41");
535181254a7Smrg }
536181254a7Smrg 
537181254a7Smrg /**
538181254a7Smrg  * This is a convenience function similar to $(LREF digest), but it returns the string
539181254a7Smrg  * representation of the hash. Every digest passing the $(LREF isDigest) test can be used with this
540181254a7Smrg  * function.
541181254a7Smrg  *
542181254a7Smrg  * Params:
543181254a7Smrg  *  order= the order in which the bytes are processed (see $(LREF toHexString))
544*b1e83836Smrg  *  range= an `InputRange` with `ElementType` `ubyte`, `ubyte[]` or `ubyte[num]`
545181254a7Smrg  */
546181254a7Smrg char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range)
547181254a7Smrg if (!isArray!Range && isDigestibleRange!Range)
548181254a7Smrg {
549181254a7Smrg     return toHexString!order(digest!Hash(range));
550181254a7Smrg }
551181254a7Smrg 
552181254a7Smrg ///
553181254a7Smrg @system unittest
554181254a7Smrg {
555181254a7Smrg     import std.digest.md;
556181254a7Smrg     import std.range : repeat;
557181254a7Smrg     auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
558181254a7Smrg     assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF");
559181254a7Smrg }
560181254a7Smrg 
561181254a7Smrg /**
562181254a7Smrg  * This overload of the hexDigest function handles arrays.
563181254a7Smrg  *
564181254a7Smrg  * Params:
565181254a7Smrg  *  order= the order in which the bytes are processed (see $(LREF toHexString))
566181254a7Smrg  *  data= one or more arrays of any type
567181254a7Smrg  */
568181254a7Smrg char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data)
569181254a7Smrg if (allSatisfy!(isArray, typeof(data)))
570181254a7Smrg {
571181254a7Smrg     return toHexString!order(digest!Hash(data));
572181254a7Smrg }
573181254a7Smrg 
574181254a7Smrg ///
575181254a7Smrg @system unittest
576181254a7Smrg {
577181254a7Smrg     import std.digest.crc;
578181254a7Smrg     assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339");
579181254a7Smrg }
580181254a7Smrg ///
581181254a7Smrg @system unittest
582181254a7Smrg {
583181254a7Smrg     import std.digest.crc;
584181254a7Smrg     assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339");
585181254a7Smrg }
586181254a7Smrg 
587181254a7Smrg /**
588181254a7Smrg  * This is a convenience function which returns an initialized digest, so it's not necessary to call
589181254a7Smrg  * start manually.
590181254a7Smrg  */
591181254a7Smrg Hash makeDigest(Hash)()
592181254a7Smrg {
593181254a7Smrg     Hash hash;
594181254a7Smrg     hash.start();
595181254a7Smrg     return hash;
596181254a7Smrg }
597181254a7Smrg 
598181254a7Smrg ///
599181254a7Smrg @system unittest
600181254a7Smrg {
601181254a7Smrg     import std.digest.md;
602181254a7Smrg     auto md5 = makeDigest!MD5();
603181254a7Smrg     md5.put(0);
604181254a7Smrg     assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71");
605181254a7Smrg }
606181254a7Smrg 
607181254a7Smrg /*+*************************** End of template part, welcome to OOP land **************************/
608181254a7Smrg 
609181254a7Smrg /**
610181254a7Smrg  * This describes the OOP API. To understand when to use the template API and when to use the OOP API,
611181254a7Smrg  * see the module documentation at the top of this page.
612181254a7Smrg  *
613181254a7Smrg  * The Digest interface is the base interface which is implemented by all digests.
614181254a7Smrg  *
615181254a7Smrg  * Note:
616*b1e83836Smrg  * A Digest implementation is always an `OutputRange`
617181254a7Smrg  */
618181254a7Smrg interface Digest
619181254a7Smrg {
620181254a7Smrg     public:
621181254a7Smrg         /**
622181254a7Smrg          * Use this to feed the digest with data.
623181254a7Smrg          * Also implements the $(REF isOutputRange, std,range,primitives)
624*b1e83836Smrg          * interface for `ubyte` and `const(ubyte)[]`.
625181254a7Smrg          *
626181254a7Smrg          * Example:
627181254a7Smrg          * ----
628181254a7Smrg          * void test(Digest dig)
629181254a7Smrg          * {
630181254a7Smrg          *     dig.put(cast(ubyte) 0); //single ubyte
631181254a7Smrg          *     dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic
632181254a7Smrg          *     ubyte[10] buf;
633181254a7Smrg          *     dig.put(buf); //buffer
634181254a7Smrg          * }
635181254a7Smrg          * ----
636181254a7Smrg          */
637181254a7Smrg         @trusted nothrow void put(scope const(ubyte)[] data...);
638181254a7Smrg 
639181254a7Smrg         /**
640181254a7Smrg          * Resets the internal state of the digest.
641181254a7Smrg          * Note:
642181254a7Smrg          * $(LREF finish) calls this internally, so it's not necessary to call
643*b1e83836Smrg          * `reset` manually after a call to $(LREF finish).
644181254a7Smrg          */
645181254a7Smrg         @trusted nothrow void reset();
646181254a7Smrg 
647181254a7Smrg         /**
648181254a7Smrg          * This is the length in bytes of the hash value which is returned by $(LREF finish).
649181254a7Smrg          * It's also the required size of a buffer passed to $(LREF finish).
650181254a7Smrg          */
651181254a7Smrg         @trusted nothrow @property size_t length() const;
652181254a7Smrg 
653181254a7Smrg         /**
654181254a7Smrg          * The finish function returns the hash value. It takes an optional buffer to copy the data
655181254a7Smrg          * into. If a buffer is passed, it must be at least $(LREF length) bytes big.
656181254a7Smrg          */
657181254a7Smrg         @trusted nothrow ubyte[] finish();
658181254a7Smrg         ///ditto
659181254a7Smrg         nothrow ubyte[] finish(ubyte[] buf);
660*b1e83836Smrg         // https://issues.dlang.org/show_bug.cgi?id=6549
661181254a7Smrg         /*in
662181254a7Smrg         {
663181254a7Smrg             assert(buf.length >= this.length);
664181254a7Smrg         }*/
665181254a7Smrg 
666181254a7Smrg         /**
667181254a7Smrg          * This is a convenience function to calculate the hash of a value using the OOP API.
668181254a7Smrg          */
669181254a7Smrg         final @trusted nothrow ubyte[] digest(scope const(void[])[] data...)
670181254a7Smrg         {
671181254a7Smrg             this.reset();
672181254a7Smrg             foreach (datum; data)
673181254a7Smrg                 this.put(cast(ubyte[]) datum);
674181254a7Smrg             return this.finish();
675181254a7Smrg         }
676181254a7Smrg }
677181254a7Smrg 
678181254a7Smrg ///
679181254a7Smrg @system unittest
680181254a7Smrg {
681181254a7Smrg     //Using the OutputRange feature
682181254a7Smrg     import std.algorithm.mutation : copy;
683181254a7Smrg     import std.digest.md;
684181254a7Smrg     import std.range : repeat;
685181254a7Smrg 
686181254a7Smrg     auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
687181254a7Smrg     auto ctx = new MD5Digest();
688181254a7Smrg     copy(oneMillionRange, ctx);
689181254a7Smrg     assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21");
690181254a7Smrg }
691181254a7Smrg 
692181254a7Smrg ///
693181254a7Smrg @system unittest
694181254a7Smrg {
695181254a7Smrg     import std.digest.crc, std.digest.md, std.digest.sha;
696181254a7Smrg     ubyte[] md5   = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog");
697181254a7Smrg     ubyte[] sha1  = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog");
698181254a7Smrg     ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog");
699181254a7Smrg     assert(crcHexString(crc32) == "414FA339");
700181254a7Smrg }
701181254a7Smrg 
702181254a7Smrg ///
703181254a7Smrg @system unittest
704181254a7Smrg {
705181254a7Smrg     import std.digest.crc;
706181254a7Smrg     ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
707181254a7Smrg     assert(crcHexString(crc32) == "414FA339");
708181254a7Smrg }
709181254a7Smrg 
710181254a7Smrg @system unittest
711181254a7Smrg {
712181254a7Smrg     import std.range : isOutputRange;
713181254a7Smrg     assert(!isDigest!(Digest));
714181254a7Smrg     assert(isOutputRange!(Digest, ubyte));
715181254a7Smrg }
716181254a7Smrg 
717181254a7Smrg ///
718181254a7Smrg @system unittest
719181254a7Smrg {
720181254a7Smrg     void test(Digest dig)
721181254a7Smrg     {
722181254a7Smrg         dig.put(cast(ubyte) 0); //single ubyte
723181254a7Smrg         dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic
724181254a7Smrg         ubyte[10] buf;
725181254a7Smrg         dig.put(buf); //buffer
726181254a7Smrg     }
727181254a7Smrg }
728181254a7Smrg 
729181254a7Smrg /*+*************************** End of OOP part, helper functions follow ***************************/
730181254a7Smrg 
731181254a7Smrg /**
732181254a7Smrg  * See $(LREF toHexString)
733181254a7Smrg  */
734181254a7Smrg enum Order : bool
735181254a7Smrg {
736181254a7Smrg     increasing, ///
737181254a7Smrg     decreasing ///
738181254a7Smrg }
739181254a7Smrg 
740*b1e83836Smrg ///
741*b1e83836Smrg @safe unittest
742*b1e83836Smrg {
743*b1e83836Smrg     import std.digest.crc : CRC32;
744*b1e83836Smrg 
745*b1e83836Smrg     auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
746*b1e83836Smrg     assert(crc32.toHexString!(Order.decreasing) == "414FA339");
747*b1e83836Smrg     assert(crc32.toHexString!(LetterCase.lower, Order.decreasing) == "414fa339");
748*b1e83836Smrg }
749*b1e83836Smrg 
750181254a7Smrg 
751181254a7Smrg /**
752181254a7Smrg  * Used to convert a hash value (a static or dynamic array of ubytes) to a string.
753181254a7Smrg  * Can be used with the OOP and with the template API.
754181254a7Smrg  *
755181254a7Smrg  * The additional order parameter can be used to specify the order of the input data.
756181254a7Smrg  * By default the data is processed in increasing order, starting at index 0. To process it in the
757181254a7Smrg  * opposite order, pass Order.decreasing as a parameter.
758181254a7Smrg  *
759181254a7Smrg  * The additional letterCase parameter can be used to specify the case of the output data.
760181254a7Smrg  * By default the output is in upper case. To change it to the lower case
761181254a7Smrg  * pass LetterCase.lower as a parameter.
762181254a7Smrg  *
763181254a7Smrg  * Note:
764181254a7Smrg  * The function overloads returning a string allocate their return values
765181254a7Smrg  * using the GC. The versions returning static arrays use pass-by-value for
766181254a7Smrg  * the return value, effectively avoiding dynamic allocation.
767181254a7Smrg  */
768181254a7Smrg char[num*2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper)
769*b1e83836Smrg (const ubyte[num] digest)
770181254a7Smrg {
771181254a7Smrg 
772181254a7Smrg     char[num*2] result;
773181254a7Smrg     size_t i;
774*b1e83836Smrg     toHexStringImpl!(order, letterCase)(digest, result);
775181254a7Smrg     return result;
776181254a7Smrg }
777181254a7Smrg 
778181254a7Smrg ///ditto
779181254a7Smrg char[num*2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest)
780181254a7Smrg {
781181254a7Smrg     return toHexString!(order, num, letterCase)(digest);
782181254a7Smrg }
783181254a7Smrg 
784181254a7Smrg ///ditto
785181254a7Smrg string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper)
786181254a7Smrg (in ubyte[] digest)
787181254a7Smrg {
788181254a7Smrg     auto result = new char[digest.length*2];
789*b1e83836Smrg     toHexStringImpl!(order, letterCase)(digest, result);
790181254a7Smrg     import std.exception : assumeUnique;
791181254a7Smrg     // memory was just created, so casting to immutable is safe
792181254a7Smrg     return () @trusted { return assumeUnique(result); }();
793181254a7Smrg }
794181254a7Smrg 
795181254a7Smrg ///ditto
796181254a7Smrg string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest)
797181254a7Smrg {
798181254a7Smrg     return toHexString!(order, letterCase)(digest);
799181254a7Smrg }
800181254a7Smrg 
801181254a7Smrg //For more example unittests, see Digest.digest, digest
802181254a7Smrg 
803181254a7Smrg ///
804181254a7Smrg @safe unittest
805181254a7Smrg {
806181254a7Smrg     import std.digest.crc;
807181254a7Smrg     //Test with template API:
808181254a7Smrg     auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
809181254a7Smrg     //Lower case variant:
810181254a7Smrg     assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41");
811181254a7Smrg     //Usually CRCs are printed in this order, though:
812181254a7Smrg     assert(toHexString!(Order.decreasing)(crc32) == "414FA339");
813181254a7Smrg     assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339");
814181254a7Smrg }
815181254a7Smrg 
816181254a7Smrg ///
817181254a7Smrg @safe unittest
818181254a7Smrg {
819181254a7Smrg     import std.digest.crc;
820181254a7Smrg     // With OOP API
821181254a7Smrg     auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
822181254a7Smrg     //Usually CRCs are printed in this order, though:
823181254a7Smrg     assert(toHexString!(Order.decreasing)(crc32) == "414FA339");
824181254a7Smrg }
825181254a7Smrg 
826181254a7Smrg @safe unittest
827181254a7Smrg {
828181254a7Smrg     ubyte[16] data;
829181254a7Smrg     assert(toHexString(data) == "00000000000000000000000000000000");
830181254a7Smrg 
831181254a7Smrg     assert(toHexString(cast(ubyte[4])[42, 43, 44, 45]) == "2A2B2C2D");
832181254a7Smrg     assert(toHexString(cast(ubyte[])[42, 43, 44, 45]) == "2A2B2C2D");
833181254a7Smrg     assert(toHexString!(Order.decreasing)(cast(ubyte[4])[42, 43, 44, 45]) == "2D2C2B2A");
834181254a7Smrg     assert(toHexString!(Order.decreasing, LetterCase.lower)(cast(ubyte[4])[42, 43, 44, 45]) == "2d2c2b2a");
835181254a7Smrg     assert(toHexString!(Order.decreasing)(cast(ubyte[])[42, 43, 44, 45]) == "2D2C2B2A");
836181254a7Smrg }
837181254a7Smrg 
838181254a7Smrg /*+*********************** End of public helper part, private helpers follow ***********************/
839181254a7Smrg 
840181254a7Smrg /*
841181254a7Smrg  * Used to convert from a ubyte[] slice to a ref ubyte[N].
842181254a7Smrg  * This helper is used internally in the WrapperDigest template to wrap the template API's
843181254a7Smrg  * finish function.
844181254a7Smrg  */
845181254a7Smrg ref T[N] asArray(size_t N, T)(ref T[] source, string errorMsg = "")
846181254a7Smrg {
847181254a7Smrg      assert(source.length >= N, errorMsg);
848181254a7Smrg      return *cast(T[N]*) source.ptr;
849181254a7Smrg }
850181254a7Smrg 
851181254a7Smrg /*
852*b1e83836Smrg  * Fill in a preallocated buffer with the ASCII hex representation from a byte buffer
853*b1e83836Smrg  */
854*b1e83836Smrg private void toHexStringImpl(Order order, LetterCase letterCase, BB, HB)
855*b1e83836Smrg (scope const ref BB byteBuffer, ref HB hexBuffer){
856*b1e83836Smrg     static if (letterCase == LetterCase.upper)
857*b1e83836Smrg     {
858*b1e83836Smrg         import std.ascii : hexDigits = hexDigits;
859*b1e83836Smrg     }
860*b1e83836Smrg     else
861*b1e83836Smrg     {
862*b1e83836Smrg         import std.ascii : hexDigits = lowerHexDigits;
863*b1e83836Smrg     }
864*b1e83836Smrg 
865*b1e83836Smrg     size_t i;
866*b1e83836Smrg     static if (order == Order.increasing)
867*b1e83836Smrg     {
868*b1e83836Smrg         foreach (u; byteBuffer)
869*b1e83836Smrg         {
870*b1e83836Smrg             hexBuffer[i++] = hexDigits[u >> 4];
871*b1e83836Smrg             hexBuffer[i++] = hexDigits[u & 15];
872*b1e83836Smrg         }
873*b1e83836Smrg     }
874*b1e83836Smrg     else
875*b1e83836Smrg     {
876*b1e83836Smrg         size_t j = byteBuffer.length -1;
877*b1e83836Smrg         while (i < byteBuffer.length*2)
878*b1e83836Smrg         {
879*b1e83836Smrg             hexBuffer[i++] = hexDigits[byteBuffer[j] >> 4];
880*b1e83836Smrg             hexBuffer[i++] = hexDigits[byteBuffer[j] & 15];
881*b1e83836Smrg             j--;
882*b1e83836Smrg         }
883*b1e83836Smrg     }
884*b1e83836Smrg }
885*b1e83836Smrg 
886*b1e83836Smrg 
887*b1e83836Smrg /*
888181254a7Smrg  * Returns the length (in bytes) of the hash value produced by T.
889181254a7Smrg  */
890181254a7Smrg template digestLength(T)
891181254a7Smrg if (isDigest!T)
892181254a7Smrg {
893181254a7Smrg     enum size_t digestLength = (ReturnType!(T.finish)).length;
894181254a7Smrg }
895181254a7Smrg 
896181254a7Smrg @safe pure nothrow @nogc
897181254a7Smrg unittest
898181254a7Smrg {
899181254a7Smrg     import std.digest.md : MD5;
900181254a7Smrg     import std.digest.sha : SHA1, SHA256, SHA512;
901181254a7Smrg     assert(digestLength!MD5 == 16);
902181254a7Smrg     assert(digestLength!SHA1 == 20);
903181254a7Smrg     assert(digestLength!SHA256 == 32);
904181254a7Smrg     assert(digestLength!SHA512 == 64);
905181254a7Smrg }
906181254a7Smrg 
907181254a7Smrg /**
908181254a7Smrg  * Wraps a template API hash struct into a Digest interface.
909181254a7Smrg  * Modules providing digest implementations will usually provide
910181254a7Smrg  * an alias for this template (e.g. MD5Digest, SHA1Digest, ...).
911181254a7Smrg  */
912181254a7Smrg class WrapperDigest(T)
913181254a7Smrg if (isDigest!T) : Digest
914181254a7Smrg {
915181254a7Smrg     protected:
916181254a7Smrg         T _digest;
917181254a7Smrg 
918181254a7Smrg     public final:
919181254a7Smrg         /**
920181254a7Smrg          * Initializes the digest.
921181254a7Smrg          */
922181254a7Smrg         this()
923181254a7Smrg         {
924181254a7Smrg             _digest.start();
925181254a7Smrg         }
926181254a7Smrg 
927181254a7Smrg         /**
928181254a7Smrg          * Use this to feed the digest with data.
929181254a7Smrg          * Also implements the $(REF isOutputRange, std,range,primitives)
930*b1e83836Smrg          * interface for `ubyte` and `const(ubyte)[]`.
931181254a7Smrg          */
932181254a7Smrg         @trusted nothrow void put(scope const(ubyte)[] data...)
933181254a7Smrg         {
934181254a7Smrg             _digest.put(data);
935181254a7Smrg         }
936181254a7Smrg 
937181254a7Smrg         /**
938181254a7Smrg          * Resets the internal state of the digest.
939181254a7Smrg          * Note:
940181254a7Smrg          * $(LREF finish) calls this internally, so it's not necessary to call
941*b1e83836Smrg          * `reset` manually after a call to $(LREF finish).
942181254a7Smrg          */
943181254a7Smrg         @trusted nothrow void reset()
944181254a7Smrg         {
945181254a7Smrg             _digest.start();
946181254a7Smrg         }
947181254a7Smrg 
948181254a7Smrg         /**
949181254a7Smrg          * This is the length in bytes of the hash value which is returned by $(LREF finish).
950181254a7Smrg          * It's also the required size of a buffer passed to $(LREF finish).
951181254a7Smrg          */
952181254a7Smrg         @trusted nothrow @property size_t length() const pure
953181254a7Smrg         {
954181254a7Smrg             return digestLength!T;
955181254a7Smrg         }
956181254a7Smrg 
957181254a7Smrg         /**
958181254a7Smrg          * The finish function returns the hash value. It takes an optional buffer to copy the data
959181254a7Smrg          * into. If a buffer is passed, it must have a length at least $(LREF length) bytes.
960181254a7Smrg          *
961181254a7Smrg          * Example:
962181254a7Smrg          * --------
963181254a7Smrg          *
964181254a7Smrg          * import std.digest.md;
965181254a7Smrg          * ubyte[16] buf;
966181254a7Smrg          * auto hash = new WrapperDigest!MD5();
967181254a7Smrg          * hash.put(cast(ubyte) 0);
968181254a7Smrg          * auto result = hash.finish(buf[]);
969181254a7Smrg          * //The result is now in result (and in buf). If you pass a buffer which is bigger than
970181254a7Smrg          * //necessary, result will have the correct length, but buf will still have it's original
971181254a7Smrg          * //length
972181254a7Smrg          * --------
973181254a7Smrg          */
974181254a7Smrg         nothrow ubyte[] finish(ubyte[] buf)
975181254a7Smrg         in
976181254a7Smrg         {
977*b1e83836Smrg             assert(buf.length >= this.length, "Given buffer is smaller than the local buffer.");
978181254a7Smrg         }
979*b1e83836Smrg         do
980181254a7Smrg         {
981181254a7Smrg             enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~
982181254a7Smrg                 "big, check " ~ typeof(this).stringof ~ ".length!";
983181254a7Smrg             asArray!(digestLength!T)(buf, msg) = _digest.finish();
984181254a7Smrg             return buf[0 .. digestLength!T];
985181254a7Smrg         }
986181254a7Smrg 
987181254a7Smrg         ///ditto
988181254a7Smrg         @trusted nothrow ubyte[] finish()
989181254a7Smrg         {
990181254a7Smrg             enum len = digestLength!T;
991181254a7Smrg             auto buf = new ubyte[len];
992181254a7Smrg             asArray!(digestLength!T)(buf) = _digest.finish();
993181254a7Smrg             return buf;
994181254a7Smrg         }
995181254a7Smrg 
996181254a7Smrg         version (StdDdoc)
997181254a7Smrg         {
998181254a7Smrg             /**
999*b1e83836Smrg              * Works like `finish` but does not reset the internal state, so it's possible
1000181254a7Smrg              * to continue putting data into this WrapperDigest after a call to peek.
1001181254a7Smrg              *
1002*b1e83836Smrg              * These functions are only available if `hasPeek!T` is true.
1003181254a7Smrg              */
1004181254a7Smrg             @trusted ubyte[] peek(ubyte[] buf) const;
1005181254a7Smrg             ///ditto
1006181254a7Smrg             @trusted ubyte[] peek() const;
1007181254a7Smrg         }
1008181254a7Smrg         else static if (hasPeek!T)
1009181254a7Smrg         {
1010181254a7Smrg             @trusted ubyte[] peek(ubyte[] buf) const
1011181254a7Smrg             in
1012181254a7Smrg             {
1013*b1e83836Smrg                 assert(buf.length >= this.length, "Given buffer is smaller than the local buffer.");
1014181254a7Smrg             }
1015*b1e83836Smrg             do
1016181254a7Smrg             {
1017181254a7Smrg                 enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~
1018181254a7Smrg                     "big, check " ~ typeof(this).stringof ~ ".length!";
1019181254a7Smrg                 asArray!(digestLength!T)(buf, msg) = _digest.peek();
1020181254a7Smrg                 return buf[0 .. digestLength!T];
1021181254a7Smrg             }
1022181254a7Smrg 
1023181254a7Smrg             @trusted ubyte[] peek() const
1024181254a7Smrg             {
1025181254a7Smrg                 enum len = digestLength!T;
1026181254a7Smrg                 auto buf = new ubyte[len];
1027181254a7Smrg                 asArray!(digestLength!T)(buf) = _digest.peek();
1028181254a7Smrg                 return buf;
1029181254a7Smrg             }
1030181254a7Smrg         }
1031181254a7Smrg }
1032181254a7Smrg 
1033181254a7Smrg ///
1034181254a7Smrg @system unittest
1035181254a7Smrg {
1036181254a7Smrg     import std.digest.md;
1037181254a7Smrg     //Simple example
1038181254a7Smrg     auto hash = new WrapperDigest!MD5();
1039181254a7Smrg     hash.put(cast(ubyte) 0);
1040181254a7Smrg     auto result = hash.finish();
1041181254a7Smrg }
1042181254a7Smrg 
1043181254a7Smrg ///
1044181254a7Smrg @system unittest
1045181254a7Smrg {
1046181254a7Smrg     //using a supplied buffer
1047181254a7Smrg     import std.digest.md;
1048181254a7Smrg     ubyte[16] buf;
1049181254a7Smrg     auto hash = new WrapperDigest!MD5();
1050181254a7Smrg     hash.put(cast(ubyte) 0);
1051181254a7Smrg     auto result = hash.finish(buf[]);
1052181254a7Smrg     //The result is now in result (and in buf). If you pass a buffer which is bigger than
1053181254a7Smrg     //necessary, result will have the correct length, but buf will still have it's original
1054181254a7Smrg     //length
1055181254a7Smrg }
1056181254a7Smrg 
1057181254a7Smrg @safe unittest
1058181254a7Smrg {
1059181254a7Smrg     // Test peek & length
1060181254a7Smrg     import std.digest.crc;
1061181254a7Smrg     auto hash = new WrapperDigest!CRC32();
1062181254a7Smrg     assert(hash.length == 4);
1063181254a7Smrg     hash.put(cast(const(ubyte[]))"The quick brown fox jumps over the lazy dog");
1064181254a7Smrg     assert(hash.peek().toHexString() == "39A34F41");
1065181254a7Smrg     ubyte[5] buf;
1066181254a7Smrg     assert(hash.peek(buf).toHexString() == "39A34F41");
1067181254a7Smrg }
1068181254a7Smrg 
1069181254a7Smrg /**
1070181254a7Smrg  * Securely compares two digest representations while protecting against timing
1071181254a7Smrg  * attacks. Do not use `==` to compare digest representations.
1072181254a7Smrg  *
1073181254a7Smrg  * The attack happens as follows:
1074181254a7Smrg  *
1075181254a7Smrg  * $(OL
1076181254a7Smrg  *     $(LI An attacker wants to send harmful data to your server, which
1077181254a7Smrg  *     requires a integrity HMAC SHA1 token signed with a secret.)
1078181254a7Smrg  *     $(LI The length of the token is known to be 40 characters long due to its format,
1079181254a7Smrg  *     so the attacker first sends `"0000000000000000000000000000000000000000"`,
1080181254a7Smrg  *     then `"1000000000000000000000000000000000000000"`, and so on.)
1081181254a7Smrg  *     $(LI The given HMAC token is compared with the expected token using the
1082181254a7Smrg  *     `==` string comparison, which returns `false` as soon as the first wrong
1083181254a7Smrg  *     element is found. If a wrong element is found, then a rejection is sent
1084181254a7Smrg  *     back to the sender.)
1085181254a7Smrg  *     $(LI Eventually, the attacker is able to determine the first character in
1086181254a7Smrg  *     the correct token because the sever takes slightly longer to return a
1087181254a7Smrg  *     rejection. This is due to the comparison moving on to second item in
1088181254a7Smrg  *     the two arrays, seeing they are different, and then sending the rejection.)
1089181254a7Smrg  *     $(LI It may seem like too small of a difference in time for the attacker
1090181254a7Smrg  *     to notice, but security researchers have shown that differences as
1091181254a7Smrg  *     small as $(LINK2 http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf,
1092181254a7Smrg  *     20µs can be reliably distinguished) even with network inconsistencies.)
1093181254a7Smrg  *     $(LI Repeat the process for each character until the attacker has the whole
1094181254a7Smrg  *     correct token and the server accepts the harmful data. This can be done
1095181254a7Smrg  *     in a week with the attacker pacing the attack to 10 requests per second
1096181254a7Smrg  *     with only one client.)
1097181254a7Smrg  * )
1098181254a7Smrg  *
1099181254a7Smrg  * This function defends against this attack by always comparing every single
1100181254a7Smrg  * item in the array if the two arrays are the same length. Therefore, this
1101181254a7Smrg  * function is always $(BIGOH n) for ranges of the same length.
1102181254a7Smrg  *
1103181254a7Smrg  * This attack can also be mitigated via rate limiting and banning IPs which have too
1104181254a7Smrg  * many rejected requests. However, this does not completely solve the problem,
1105181254a7Smrg  * as the attacker could be in control of a bot net. To fully defend against
1106181254a7Smrg  * the timing attack, rate limiting, banning IPs, and using this function
1107181254a7Smrg  * should be used together.
1108181254a7Smrg  *
1109181254a7Smrg  * Params:
1110181254a7Smrg  *     r1 = A digest representation
1111181254a7Smrg  *     r2 = A digest representation
1112181254a7Smrg  * Returns:
1113181254a7Smrg  *     `true` if both representations are equal, `false` otherwise
1114181254a7Smrg  * See_Also:
1115181254a7Smrg  *     $(LINK2 https://en.wikipedia.org/wiki/Timing_attack, The Wikipedia article
1116181254a7Smrg  *     on timing attacks).
1117181254a7Smrg  */
1118181254a7Smrg bool secureEqual(R1, R2)(R1 r1, R2 r2)
1119181254a7Smrg if (isInputRange!R1 && isInputRange!R2 && !isInfinite!R1 && !isInfinite!R2 &&
1120181254a7Smrg     (isIntegral!(ElementEncodingType!R1) || isSomeChar!(ElementEncodingType!R1)) &&
1121181254a7Smrg     !is(CommonType!(ElementEncodingType!R1, ElementEncodingType!R2) == void))
1122181254a7Smrg {
1123181254a7Smrg     static if (hasLength!R1 && hasLength!R2)
1124181254a7Smrg         if (r1.length != r2.length)
1125181254a7Smrg             return false;
1126181254a7Smrg 
1127181254a7Smrg     int result;
1128181254a7Smrg 
1129181254a7Smrg     static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 &&
1130181254a7Smrg                hasLength!R1 && hasLength!R2)
1131181254a7Smrg     {
1132181254a7Smrg         foreach (i; 0 .. r1.length)
1133181254a7Smrg             result |= r1[i] ^ r2[i];
1134181254a7Smrg     }
1135181254a7Smrg     else static if (hasLength!R1 && hasLength!R2)
1136181254a7Smrg     {
1137181254a7Smrg         // Lengths are the same so we can squeeze out a bit of performance
1138181254a7Smrg         // by not checking if r2 is empty
1139181254a7Smrg         for (; !r1.empty; r1.popFront(), r2.popFront())
1140181254a7Smrg         {
1141181254a7Smrg             result |= r1.front ^ r2.front;
1142181254a7Smrg         }
1143181254a7Smrg     }
1144181254a7Smrg     else
1145181254a7Smrg     {
1146181254a7Smrg         // Generic case, walk both ranges
1147181254a7Smrg         for (; !r1.empty; r1.popFront(), r2.popFront())
1148181254a7Smrg         {
1149181254a7Smrg             if (r2.empty) return false;
1150181254a7Smrg             result |= r1.front ^ r2.front;
1151181254a7Smrg         }
1152181254a7Smrg         if (!r2.empty) return false;
1153181254a7Smrg     }
1154181254a7Smrg 
1155181254a7Smrg     return result == 0;
1156181254a7Smrg }
1157181254a7Smrg 
1158181254a7Smrg ///
1159181254a7Smrg @system pure unittest
1160181254a7Smrg {
1161181254a7Smrg     import std.digest.hmac : hmac;
1162181254a7Smrg     import std.digest.sha : SHA1;
1163181254a7Smrg     import std.string : representation;
1164181254a7Smrg 
1165181254a7Smrg     // a typical HMAC data integrity verification
1166181254a7Smrg     auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation;
1167181254a7Smrg     auto data = "data".representation;
1168181254a7Smrg 
1169*b1e83836Smrg     auto hex1 = data.hmac!SHA1(secret).toHexString;
1170*b1e83836Smrg     auto hex2 = data.hmac!SHA1(secret).toHexString;
1171*b1e83836Smrg     auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString;
1172181254a7Smrg 
1173*b1e83836Smrg     assert( secureEqual(hex1[], hex2[]));
1174*b1e83836Smrg     assert(!secureEqual(hex1[], hex3[]));
1175181254a7Smrg }
1176181254a7Smrg 
1177181254a7Smrg @system pure unittest
1178181254a7Smrg {
1179181254a7Smrg     import std.internal.test.dummyrange : ReferenceInputRange;
1180181254a7Smrg     import std.range : takeExactly;
1181181254a7Smrg     import std.string : representation;
1182181254a7Smrg     import std.utf : byWchar, byDchar;
1183181254a7Smrg 
1184181254a7Smrg     {
1185181254a7Smrg         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".representation;
1186181254a7Smrg         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".representation;
1187181254a7Smrg         assert(!secureEqual(hex1, hex2));
1188181254a7Smrg     }
1189181254a7Smrg     {
1190181254a7Smrg         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018"w.representation;
1191181254a7Smrg         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018"d.representation;
1192181254a7Smrg         assert(secureEqual(hex1, hex2));
1193181254a7Smrg     }
1194181254a7Smrg     {
1195181254a7Smrg         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byWchar;
1196181254a7Smrg         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar;
1197181254a7Smrg         assert(secureEqual(hex1, hex2));
1198181254a7Smrg     }
1199181254a7Smrg     {
1200181254a7Smrg         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".byWchar;
1201181254a7Smrg         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar;
1202181254a7Smrg         assert(!secureEqual(hex1, hex2));
1203181254a7Smrg     }
1204181254a7Smrg     {
1205181254a7Smrg         auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9);
1206181254a7Smrg         auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9);
1207181254a7Smrg         assert(secureEqual(hex1, hex2));
1208181254a7Smrg     }
1209181254a7Smrg     {
1210181254a7Smrg         auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9);
1211181254a7Smrg         auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 9]).takeExactly(9);
1212181254a7Smrg         assert(!secureEqual(hex1, hex2));
1213181254a7Smrg     }
1214181254a7Smrg }
1215