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