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