| /** | 
 |  * This module describes the _digest APIs used in Phobos. All digests follow | 
 |  * these APIs. Additionally, this module contains useful helper methods which | 
 |  * can be used with every _digest type. | 
 |  * | 
 | $(SCRIPT inhibitQuickIndex = 1;) | 
 |  | 
 | $(DIVC quickindex, | 
 | $(BOOKTABLE , | 
 | $(TR $(TH Category) $(TH Functions) | 
 | ) | 
 | $(TR $(TDNW Template API) $(TD $(MYREF isDigest) $(MYREF DigestType) $(MYREF hasPeek) | 
 |   $(MYREF hasBlockSize) | 
 |   $(MYREF ExampleDigest) $(MYREF _digest) $(MYREF hexDigest) $(MYREF makeDigest) | 
 | ) | 
 | ) | 
 | $(TR $(TDNW OOP API) $(TD $(MYREF Digest) | 
 | ) | 
 | ) | 
 | $(TR $(TDNW Helper functions) $(TD $(MYREF toHexString)) | 
 | ) | 
 | $(TR $(TDNW Implementation helpers) $(TD $(MYREF digestLength) $(MYREF WrapperDigest)) | 
 | ) | 
 | ) | 
 | ) | 
 |  | 
 |  * APIs: | 
 |  * There are two APIs for digests: The template API and the OOP API. The template API uses structs | 
 |  * and template helpers like $(LREF isDigest). The OOP API implements digests as classes inheriting | 
 |  * the $(LREF Digest) interface. All digests are named so that the template API struct is called "$(B x)" | 
 |  * and the OOP API class is called "$(B x)Digest". For example we have $(D MD5) <--> $(D MD5Digest), | 
 |  * $(D CRC32) <--> $(D CRC32Digest), etc. | 
 |  * | 
 |  * The template API is slightly more efficient. It does not have to allocate memory dynamically, | 
 |  * all memory is allocated on the stack. The OOP API has to allocate in the finish method if no | 
 |  * buffer was provided. If you provide a buffer to the OOP APIs finish function, it doesn't allocate, | 
 |  * but the $(LREF Digest) classes still have to be created using $(D new) which allocates them using the GC. | 
 |  * | 
 |  * The OOP API is useful to change the _digest function and/or _digest backend at 'runtime'. The benefit here | 
 |  * is that switching e.g. Phobos MD5Digest and an OpenSSLMD5Digest implementation is ABI compatible. | 
 |  * | 
 |  * If just one specific _digest type and backend is needed, the template API is usually a good fit. | 
 |  * In this simplest case, the template API can even be used without templates: Just use the "$(B x)" structs | 
 |  * directly. | 
 |  * | 
 |  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). | 
 |  * Authors: | 
 |  * Johannes Pfau | 
 |  * | 
 |  * Source:    $(PHOBOSSRC std/_digest/_package.d) | 
 |  * | 
 |  * CTFE: | 
 |  * Digests do not work in CTFE | 
 |  * | 
 |  * TODO: | 
 |  * Digesting single bits (as opposed to bytes) is not implemented. This will be done as another | 
 |  * template constraint helper (hasBitDigesting!T) and an additional interface (BitDigest) | 
 |  */ | 
 | /*          Copyright Johannes Pfau 2012. | 
 |  * Distributed under the Boost Software License, Version 1.0. | 
 |  *    (See accompanying file LICENSE_1_0.txt or copy at | 
 |  *          http://www.boost.org/LICENSE_1_0.txt) | 
 |  */ | 
 | module std.digest; | 
 |  | 
 | public import std.ascii : LetterCase; | 
 | import std.meta : allSatisfy; | 
 | import std.range.primitives; | 
 | import std.traits; | 
 |  | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |  | 
 |     //Simple example | 
 |     char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog"); | 
 |     assert(hexHash == "39A34F41"); | 
 |  | 
 |     //Simple example, using the API manually | 
 |     CRC32 context = makeDigest!CRC32(); | 
 |     context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog"); | 
 |     ubyte[4] hash = context.finish(); | 
 |     assert(toHexString(hash) == "39A34F41"); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     //Generating the hashes of a file, idiomatic D way | 
 |     import std.digest.crc, std.digest.md, std.digest.sha; | 
 |     import std.stdio; | 
 |  | 
 |     // Digests a file and prints the result. | 
 |     void digestFile(Hash)(string filename) | 
 |     if (isDigest!Hash) | 
 |     { | 
 |         auto file = File(filename); | 
 |         auto result = digest!Hash(file.byChunk(4096 * 1024)); | 
 |         writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); | 
 |     } | 
 |  | 
 |     void main(string[] args) | 
 |     { | 
 |         foreach (name; args[1 .. $]) | 
 |         { | 
 |             digestFile!MD5(name); | 
 |             digestFile!SHA1(name); | 
 |             digestFile!CRC32(name); | 
 |         } | 
 |     } | 
 | } | 
 | /// | 
 | @system unittest | 
 | { | 
 |     //Generating the hashes of a file using the template API | 
 |     import std.digest.crc, std.digest.md, std.digest.sha; | 
 |     import std.stdio; | 
 |     // Digests a file and prints the result. | 
 |     void digestFile(Hash)(ref Hash hash, string filename) | 
 |     if (isDigest!Hash) | 
 |     { | 
 |         File file = File(filename); | 
 |  | 
 |         //As digests imlement OutputRange, we could use std.algorithm.copy | 
 |         //Let's do it manually for now | 
 |         foreach (buffer; file.byChunk(4096 * 1024)) | 
 |             hash.put(buffer); | 
 |  | 
 |         auto result = hash.finish(); | 
 |         writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); | 
 |     } | 
 |  | 
 |     void uMain(string[] args) | 
 |     { | 
 |         MD5 md5; | 
 |         SHA1 sha1; | 
 |         CRC32 crc32; | 
 |  | 
 |         md5.start(); | 
 |         sha1.start(); | 
 |         crc32.start(); | 
 |  | 
 |         foreach (arg; args[1 .. $]) | 
 |         { | 
 |             digestFile(md5, arg); | 
 |             digestFile(sha1, arg); | 
 |             digestFile(crc32, arg); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc, std.digest.md, std.digest.sha; | 
 |     import std.stdio; | 
 |  | 
 |     // Digests a file and prints the result. | 
 |     void digestFile(Digest hash, string filename) | 
 |     { | 
 |         File file = File(filename); | 
 |  | 
 |         //As digests implement OutputRange, we could use std.algorithm.copy | 
 |         //Let's do it manually for now | 
 |         foreach (buffer; file.byChunk(4096 * 1024)) | 
 |           hash.put(buffer); | 
 |  | 
 |         ubyte[] result = hash.finish(); | 
 |         writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result)); | 
 |     } | 
 |  | 
 |     void umain(string[] args) | 
 |     { | 
 |         auto md5 = new MD5Digest(); | 
 |         auto sha1 = new SHA1Digest(); | 
 |         auto crc32 = new CRC32Digest(); | 
 |  | 
 |         foreach (arg; args[1 .. $]) | 
 |         { | 
 |           digestFile(md5, arg); | 
 |           digestFile(sha1, arg); | 
 |           digestFile(crc32, arg); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | version (StdDdoc) | 
 |     version = ExampleDigest; | 
 |  | 
 | version (ExampleDigest) | 
 | { | 
 |     /** | 
 |      * This documents the general structure of a Digest in the template API. | 
 |      * All digest implementations should implement the following members and therefore pass | 
 |      * the $(LREF isDigest) test. | 
 |      * | 
 |      * Note: | 
 |      * $(UL | 
 |      * $(LI A digest must be a struct (value type) to pass the $(LREF isDigest) test.) | 
 |      * $(LI A digest passing the $(LREF isDigest) test is always an $(D OutputRange)) | 
 |      * ) | 
 |      */ | 
 |     struct ExampleDigest | 
 |     { | 
 |         public: | 
 |             /** | 
 |              * Use this to feed the digest with data. | 
 |              * Also implements the $(REF isOutputRange, std,range,primitives) | 
 |              * interface for $(D ubyte) and $(D const(ubyte)[]). | 
 |              * The following usages of $(D put) must work for any type which | 
 |              * passes $(LREF isDigest): | 
 |              * Example: | 
 |              * ---- | 
 |              * ExampleDigest dig; | 
 |              * dig.put(cast(ubyte) 0); //single ubyte | 
 |              * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic | 
 |              * ubyte[10] buf; | 
 |              * dig.put(buf); //buffer | 
 |              * ---- | 
 |              */ | 
 |             @trusted void put(scope const(ubyte)[] data...) | 
 |             { | 
 |  | 
 |             } | 
 |  | 
 |             /** | 
 |              * This function is used to (re)initialize the digest. | 
 |              * It must be called before using the digest and it also works as a 'reset' function | 
 |              * if the digest has already processed data. | 
 |              */ | 
 |             @trusted void start() | 
 |             { | 
 |  | 
 |             } | 
 |  | 
 |             /** | 
 |              * The finish function returns the final hash sum and resets the Digest. | 
 |              * | 
 |              * Note: | 
 |              * The actual type returned by finish depends on the digest implementation. | 
 |              * $(D ubyte[16]) is just used as an example. It is guaranteed that the type is a | 
 |              * static array of ubytes. | 
 |              * | 
 |              * $(UL | 
 |              * $(LI Use $(LREF DigestType) to obtain the actual return type.) | 
 |              * $(LI Use $(LREF digestLength) to obtain the length of the ubyte array.) | 
 |              * ) | 
 |              */ | 
 |             @trusted ubyte[16] finish() | 
 |             { | 
 |                 return (ubyte[16]).init; | 
 |             } | 
 |     } | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     //Using the OutputRange feature | 
 |     import std.algorithm.mutation : copy; | 
 |     import std.digest.md; | 
 |     import std.range : repeat; | 
 |  | 
 |     auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); | 
 |     auto ctx = makeDigest!MD5(); | 
 |     copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy! | 
 |     assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); | 
 | } | 
 |  | 
 | /** | 
 |  * Use this to check if a type is a digest. See $(LREF ExampleDigest) to see what | 
 |  * a type must provide to pass this check. | 
 |  * | 
 |  * Note: | 
 |  * This is very useful as a template constraint (see examples) | 
 |  * | 
 |  * BUGS: | 
 |  * $(UL | 
 |  * $(LI Does not yet verify that put takes scope parameters.) | 
 |  * $(LI Should check that finish() returns a ubyte[num] array) | 
 |  * ) | 
 |  */ | 
 | template isDigest(T) | 
 | { | 
 |     import std.range : isOutputRange; | 
 |     enum bool isDigest = isOutputRange!(T, const(ubyte)[]) && isOutputRange!(T, ubyte) && | 
 |         is(T == struct) && | 
 |         is(typeof( | 
 |         { | 
 |             T dig = void; //Can define | 
 |             dig.put(cast(ubyte) 0, cast(ubyte) 0); //varags | 
 |             dig.start(); //has start | 
 |             auto value = dig.finish(); //has finish | 
 |         })); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     static assert(isDigest!CRC32); | 
 | } | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     void myFunction(T)() | 
 |     if (isDigest!T) | 
 |     { | 
 |         T dig; | 
 |         dig.start(); | 
 |         auto result = dig.finish(); | 
 |     } | 
 |     myFunction!CRC32(); | 
 | } | 
 |  | 
 | /** | 
 |  * Use this template to get the type which is returned by a digest's $(LREF finish) method. | 
 |  */ | 
 | template DigestType(T) | 
 | { | 
 |     static if (isDigest!T) | 
 |     { | 
 |         alias DigestType = | 
 |             ReturnType!(typeof( | 
 |             { | 
 |                 T dig = void; | 
 |                 return dig.finish(); | 
 |             })); | 
 |     } | 
 |     else | 
 |         static assert(false, T.stringof ~ " is not a digest! (fails isDigest!T)"); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     assert(is(DigestType!(CRC32) == ubyte[4])); | 
 | } | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     CRC32 dig; | 
 |     dig.start(); | 
 |     DigestType!CRC32 result = dig.finish(); | 
 | } | 
 |  | 
 | /** | 
 |  * Used to check if a digest supports the $(D peek) method. | 
 |  * Peek has exactly the same function signatures as finish, but it doesn't reset | 
 |  * the digest's internal state. | 
 |  * | 
 |  * Note: | 
 |  * $(UL | 
 |  * $(LI This is very useful as a template constraint (see examples)) | 
 |  * $(LI This also checks if T passes $(LREF isDigest)) | 
 |  * ) | 
 |  */ | 
 | template hasPeek(T) | 
 | { | 
 |     enum bool hasPeek = isDigest!T && | 
 |         is(typeof( | 
 |         { | 
 |             T dig = void; //Can define | 
 |             DigestType!T val = dig.peek(); | 
 |         })); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc, std.digest.md; | 
 |     assert(!hasPeek!(MD5)); | 
 |     assert(hasPeek!CRC32); | 
 | } | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     void myFunction(T)() | 
 |     if (hasPeek!T) | 
 |     { | 
 |         T dig; | 
 |         dig.start(); | 
 |         auto result = dig.peek(); | 
 |     } | 
 |     myFunction!CRC32(); | 
 | } | 
 |  | 
 | /** | 
 |  * Checks whether the digest has a $(D blockSize) member, which contains the | 
 |  * digest's internal block size in bits. It is primarily used by $(REF HMAC, std,digest,hmac). | 
 |  */ | 
 |  | 
 | template hasBlockSize(T) | 
 | if (isDigest!T) | 
 | { | 
 |     enum bool hasBlockSize = __traits(compiles, { size_t blockSize = T.blockSize; }); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.hmac, std.digest.md; | 
 |     static assert(hasBlockSize!MD5        && MD5.blockSize      == 512); | 
 |     static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512); | 
 | } | 
 |  | 
 | package template isDigestibleRange(Range) | 
 | { | 
 |     import std.digest.md; | 
 |     import std.range : isInputRange, ElementType; | 
 |     enum bool isDigestibleRange = isInputRange!Range && is(typeof( | 
 |           { | 
 |           MD5 ha; //Could use any conformant hash | 
 |           ElementType!Range val; | 
 |           ha.put(val); | 
 |           })); | 
 | } | 
 |  | 
 | /** | 
 |  * This is a convenience function to calculate a hash using the template API. | 
 |  * Every digest passing the $(LREF isDigest) test can be used with this function. | 
 |  * | 
 |  * Params: | 
 |  *  range= an $(D InputRange) with $(D ElementType) $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) | 
 |  */ | 
 | DigestType!Hash digest(Hash, Range)(auto ref Range range) | 
 | if (!isArray!Range | 
 |     && isDigestibleRange!Range) | 
 | { | 
 |     import std.algorithm.mutation : copy; | 
 |     Hash hash; | 
 |     hash.start(); | 
 |     copy(range, &hash); | 
 |     return hash.finish(); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.md; | 
 |     import std.range : repeat; | 
 |     auto testRange = repeat!ubyte(cast(ubyte)'a', 100); | 
 |     auto md5 = digest!MD5(testRange); | 
 | } | 
 |  | 
 | /** | 
 |  * This overload of the digest function handles arrays. | 
 |  * | 
 |  * Params: | 
 |  *  data= one or more arrays of any type | 
 |  */ | 
 | DigestType!Hash digest(Hash, T...)(scope const T data) | 
 | if (allSatisfy!(isArray, typeof(data))) | 
 | { | 
 |     Hash hash; | 
 |     hash.start(); | 
 |     foreach (datum; data) | 
 |         hash.put(cast(const(ubyte[]))datum); | 
 |     return hash.finish(); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc, std.digest.md, std.digest.sha; | 
 |     auto md5   = digest!MD5(  "The quick brown fox jumps over the lazy dog"); | 
 |     auto sha1  = digest!SHA1( "The quick brown fox jumps over the lazy dog"); | 
 |     auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); | 
 |     assert(toHexString(crc32) == "39A34F41"); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); | 
 |     assert(toHexString(crc32) == "39A34F41"); | 
 | } | 
 |  | 
 | /** | 
 |  * This is a convenience function similar to $(LREF digest), but it returns the string | 
 |  * representation of the hash. Every digest passing the $(LREF isDigest) test can be used with this | 
 |  * function. | 
 |  * | 
 |  * Params: | 
 |  *  order= the order in which the bytes are processed (see $(LREF toHexString)) | 
 |  *  range= an $(D InputRange) with $(D ElementType) $(D ubyte), $(D ubyte[]) or $(D ubyte[num]) | 
 |  */ | 
 | char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range) | 
 | if (!isArray!Range && isDigestibleRange!Range) | 
 | { | 
 |     return toHexString!order(digest!Hash(range)); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.md; | 
 |     import std.range : repeat; | 
 |     auto testRange = repeat!ubyte(cast(ubyte)'a', 100); | 
 |     assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF"); | 
 | } | 
 |  | 
 | /** | 
 |  * This overload of the hexDigest function handles arrays. | 
 |  * | 
 |  * Params: | 
 |  *  order= the order in which the bytes are processed (see $(LREF toHexString)) | 
 |  *  data= one or more arrays of any type | 
 |  */ | 
 | char[digestLength!(Hash)*2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data) | 
 | if (allSatisfy!(isArray, typeof(data))) | 
 | { | 
 |     return toHexString!order(digest!Hash(data)); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339"); | 
 | } | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339"); | 
 | } | 
 |  | 
 | /** | 
 |  * This is a convenience function which returns an initialized digest, so it's not necessary to call | 
 |  * start manually. | 
 |  */ | 
 | Hash makeDigest(Hash)() | 
 | { | 
 |     Hash hash; | 
 |     hash.start(); | 
 |     return hash; | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.md; | 
 |     auto md5 = makeDigest!MD5(); | 
 |     md5.put(0); | 
 |     assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); | 
 | } | 
 |  | 
 | /*+*************************** End of template part, welcome to OOP land **************************/ | 
 |  | 
 | /** | 
 |  * This describes the OOP API. To understand when to use the template API and when to use the OOP API, | 
 |  * see the module documentation at the top of this page. | 
 |  * | 
 |  * The Digest interface is the base interface which is implemented by all digests. | 
 |  * | 
 |  * Note: | 
 |  * A Digest implementation is always an $(D OutputRange) | 
 |  */ | 
 | interface Digest | 
 | { | 
 |     public: | 
 |         /** | 
 |          * Use this to feed the digest with data. | 
 |          * Also implements the $(REF isOutputRange, std,range,primitives) | 
 |          * interface for $(D ubyte) and $(D const(ubyte)[]). | 
 |          * | 
 |          * Example: | 
 |          * ---- | 
 |          * void test(Digest dig) | 
 |          * { | 
 |          *     dig.put(cast(ubyte) 0); //single ubyte | 
 |          *     dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic | 
 |          *     ubyte[10] buf; | 
 |          *     dig.put(buf); //buffer | 
 |          * } | 
 |          * ---- | 
 |          */ | 
 |         @trusted nothrow void put(scope const(ubyte)[] data...); | 
 |  | 
 |         /** | 
 |          * Resets the internal state of the digest. | 
 |          * Note: | 
 |          * $(LREF finish) calls this internally, so it's not necessary to call | 
 |          * $(D reset) manually after a call to $(LREF finish). | 
 |          */ | 
 |         @trusted nothrow void reset(); | 
 |  | 
 |         /** | 
 |          * This is the length in bytes of the hash value which is returned by $(LREF finish). | 
 |          * It's also the required size of a buffer passed to $(LREF finish). | 
 |          */ | 
 |         @trusted nothrow @property size_t length() const; | 
 |  | 
 |         /** | 
 |          * The finish function returns the hash value. It takes an optional buffer to copy the data | 
 |          * into. If a buffer is passed, it must be at least $(LREF length) bytes big. | 
 |          */ | 
 |         @trusted nothrow ubyte[] finish(); | 
 |         ///ditto | 
 |         nothrow ubyte[] finish(ubyte[] buf); | 
 |         //@@@BUG@@@ http://d.puremagic.com/issues/show_bug.cgi?id=6549 | 
 |         /*in | 
 |         { | 
 |             assert(buf.length >= this.length); | 
 |         }*/ | 
 |  | 
 |         /** | 
 |          * This is a convenience function to calculate the hash of a value using the OOP API. | 
 |          */ | 
 |         final @trusted nothrow ubyte[] digest(scope const(void[])[] data...) | 
 |         { | 
 |             this.reset(); | 
 |             foreach (datum; data) | 
 |                 this.put(cast(ubyte[]) datum); | 
 |             return this.finish(); | 
 |         } | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     //Using the OutputRange feature | 
 |     import std.algorithm.mutation : copy; | 
 |     import std.digest.md; | 
 |     import std.range : repeat; | 
 |  | 
 |     auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); | 
 |     auto ctx = new MD5Digest(); | 
 |     copy(oneMillionRange, ctx); | 
 |     assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc, std.digest.md, std.digest.sha; | 
 |     ubyte[] md5   = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); | 
 |     ubyte[] sha1  = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); | 
 |     ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); | 
 |     assert(crcHexString(crc32) == "414FA339"); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); | 
 |     assert(crcHexString(crc32) == "414FA339"); | 
 | } | 
 |  | 
 | @system unittest | 
 | { | 
 |     import std.range : isOutputRange; | 
 |     assert(!isDigest!(Digest)); | 
 |     assert(isOutputRange!(Digest, ubyte)); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     void test(Digest dig) | 
 |     { | 
 |         dig.put(cast(ubyte) 0); //single ubyte | 
 |         dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic | 
 |         ubyte[10] buf; | 
 |         dig.put(buf); //buffer | 
 |     } | 
 | } | 
 |  | 
 | /*+*************************** End of OOP part, helper functions follow ***************************/ | 
 |  | 
 | /** | 
 |  * See $(LREF toHexString) | 
 |  */ | 
 | enum Order : bool | 
 | { | 
 |     increasing, /// | 
 |     decreasing /// | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Used to convert a hash value (a static or dynamic array of ubytes) to a string. | 
 |  * Can be used with the OOP and with the template API. | 
 |  * | 
 |  * The additional order parameter can be used to specify the order of the input data. | 
 |  * By default the data is processed in increasing order, starting at index 0. To process it in the | 
 |  * opposite order, pass Order.decreasing as a parameter. | 
 |  * | 
 |  * The additional letterCase parameter can be used to specify the case of the output data. | 
 |  * By default the output is in upper case. To change it to the lower case | 
 |  * pass LetterCase.lower as a parameter. | 
 |  * | 
 |  * Note: | 
 |  * The function overloads returning a string allocate their return values | 
 |  * using the GC. The versions returning static arrays use pass-by-value for | 
 |  * the return value, effectively avoiding dynamic allocation. | 
 |  */ | 
 | char[num*2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper) | 
 | (in ubyte[num] digest) | 
 | { | 
 |     static if (letterCase == LetterCase.upper) | 
 |     { | 
 |         import std.ascii : hexDigits = hexDigits; | 
 |     } | 
 |     else | 
 |     { | 
 |         import std.ascii : hexDigits = lowerHexDigits; | 
 |     } | 
 |  | 
 |  | 
 |     char[num*2] result; | 
 |     size_t i; | 
 |  | 
 |     static if (order == Order.increasing) | 
 |     { | 
 |         foreach (u; digest) | 
 |         { | 
 |             result[i++] = hexDigits[u >> 4]; | 
 |             result[i++] = hexDigits[u & 15]; | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         size_t j = num - 1; | 
 |         while (i < num*2) | 
 |         { | 
 |             result[i++] = hexDigits[digest[j] >> 4]; | 
 |             result[i++] = hexDigits[digest[j] & 15]; | 
 |             j--; | 
 |         } | 
 |     } | 
 |     return result; | 
 | } | 
 |  | 
 | ///ditto | 
 | char[num*2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest) | 
 | { | 
 |     return toHexString!(order, num, letterCase)(digest); | 
 | } | 
 |  | 
 | ///ditto | 
 | string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper) | 
 | (in ubyte[] digest) | 
 | { | 
 |     static if (letterCase == LetterCase.upper) | 
 |     { | 
 |         import std.ascii : hexDigits = hexDigits; | 
 |     } | 
 |     else | 
 |     { | 
 |         import std.ascii : hexDigits = lowerHexDigits; | 
 |     } | 
 |  | 
 |     auto result = new char[digest.length*2]; | 
 |     size_t i; | 
 |  | 
 |     static if (order == Order.increasing) | 
 |     { | 
 |         foreach (u; digest) | 
 |         { | 
 |             result[i++] = hexDigits[u >> 4]; | 
 |             result[i++] = hexDigits[u & 15]; | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         import std.range : retro; | 
 |         foreach (u; retro(digest)) | 
 |         { | 
 |             result[i++] = hexDigits[u >> 4]; | 
 |             result[i++] = hexDigits[u & 15]; | 
 |         } | 
 |     } | 
 |     import std.exception : assumeUnique; | 
 |     // memory was just created, so casting to immutable is safe | 
 |     return () @trusted { return assumeUnique(result); }(); | 
 | } | 
 |  | 
 | ///ditto | 
 | string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest) | 
 | { | 
 |     return toHexString!(order, letterCase)(digest); | 
 | } | 
 |  | 
 | //For more example unittests, see Digest.digest, digest | 
 |  | 
 | /// | 
 | @safe unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     //Test with template API: | 
 |     auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); | 
 |     //Lower case variant: | 
 |     assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41"); | 
 |     //Usually CRCs are printed in this order, though: | 
 |     assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); | 
 |     assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339"); | 
 | } | 
 |  | 
 | /// | 
 | @safe unittest | 
 | { | 
 |     import std.digest.crc; | 
 |     // With OOP API | 
 |     auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); | 
 |     //Usually CRCs are printed in this order, though: | 
 |     assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); | 
 | } | 
 |  | 
 | @safe unittest | 
 | { | 
 |     ubyte[16] data; | 
 |     assert(toHexString(data) == "00000000000000000000000000000000"); | 
 |  | 
 |     assert(toHexString(cast(ubyte[4])[42, 43, 44, 45]) == "2A2B2C2D"); | 
 |     assert(toHexString(cast(ubyte[])[42, 43, 44, 45]) == "2A2B2C2D"); | 
 |     assert(toHexString!(Order.decreasing)(cast(ubyte[4])[42, 43, 44, 45]) == "2D2C2B2A"); | 
 |     assert(toHexString!(Order.decreasing, LetterCase.lower)(cast(ubyte[4])[42, 43, 44, 45]) == "2d2c2b2a"); | 
 |     assert(toHexString!(Order.decreasing)(cast(ubyte[])[42, 43, 44, 45]) == "2D2C2B2A"); | 
 | } | 
 |  | 
 | /*+*********************** End of public helper part, private helpers follow ***********************/ | 
 |  | 
 | /* | 
 |  * Used to convert from a ubyte[] slice to a ref ubyte[N]. | 
 |  * This helper is used internally in the WrapperDigest template to wrap the template API's | 
 |  * finish function. | 
 |  */ | 
 | ref T[N] asArray(size_t N, T)(ref T[] source, string errorMsg = "") | 
 | { | 
 |      assert(source.length >= N, errorMsg); | 
 |      return *cast(T[N]*) source.ptr; | 
 | } | 
 |  | 
 | /* | 
 |  * Returns the length (in bytes) of the hash value produced by T. | 
 |  */ | 
 | template digestLength(T) | 
 | if (isDigest!T) | 
 | { | 
 |     enum size_t digestLength = (ReturnType!(T.finish)).length; | 
 | } | 
 |  | 
 | @safe pure nothrow @nogc | 
 | unittest | 
 | { | 
 |     import std.digest.md : MD5; | 
 |     import std.digest.sha : SHA1, SHA256, SHA512; | 
 |     assert(digestLength!MD5 == 16); | 
 |     assert(digestLength!SHA1 == 20); | 
 |     assert(digestLength!SHA256 == 32); | 
 |     assert(digestLength!SHA512 == 64); | 
 | } | 
 |  | 
 | /** | 
 |  * Wraps a template API hash struct into a Digest interface. | 
 |  * Modules providing digest implementations will usually provide | 
 |  * an alias for this template (e.g. MD5Digest, SHA1Digest, ...). | 
 |  */ | 
 | class WrapperDigest(T) | 
 | if (isDigest!T) : Digest | 
 | { | 
 |     protected: | 
 |         T _digest; | 
 |  | 
 |     public final: | 
 |         /** | 
 |          * Initializes the digest. | 
 |          */ | 
 |         this() | 
 |         { | 
 |             _digest.start(); | 
 |         } | 
 |  | 
 |         /** | 
 |          * Use this to feed the digest with data. | 
 |          * Also implements the $(REF isOutputRange, std,range,primitives) | 
 |          * interface for $(D ubyte) and $(D const(ubyte)[]). | 
 |          */ | 
 |         @trusted nothrow void put(scope const(ubyte)[] data...) | 
 |         { | 
 |             _digest.put(data); | 
 |         } | 
 |  | 
 |         /** | 
 |          * Resets the internal state of the digest. | 
 |          * Note: | 
 |          * $(LREF finish) calls this internally, so it's not necessary to call | 
 |          * $(D reset) manually after a call to $(LREF finish). | 
 |          */ | 
 |         @trusted nothrow void reset() | 
 |         { | 
 |             _digest.start(); | 
 |         } | 
 |  | 
 |         /** | 
 |          * This is the length in bytes of the hash value which is returned by $(LREF finish). | 
 |          * It's also the required size of a buffer passed to $(LREF finish). | 
 |          */ | 
 |         @trusted nothrow @property size_t length() const pure | 
 |         { | 
 |             return digestLength!T; | 
 |         } | 
 |  | 
 |         /** | 
 |          * The finish function returns the hash value. It takes an optional buffer to copy the data | 
 |          * into. If a buffer is passed, it must have a length at least $(LREF length) bytes. | 
 |          * | 
 |          * Example: | 
 |          * -------- | 
 |          * | 
 |          * import std.digest.md; | 
 |          * ubyte[16] buf; | 
 |          * auto hash = new WrapperDigest!MD5(); | 
 |          * hash.put(cast(ubyte) 0); | 
 |          * auto result = hash.finish(buf[]); | 
 |          * //The result is now in result (and in buf). If you pass a buffer which is bigger than | 
 |          * //necessary, result will have the correct length, but buf will still have it's original | 
 |          * //length | 
 |          * -------- | 
 |          */ | 
 |         nothrow ubyte[] finish(ubyte[] buf) | 
 |         in | 
 |         { | 
 |             assert(buf.length >= this.length); | 
 |         } | 
 |         body | 
 |         { | 
 |             enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ | 
 |                 "big, check " ~ typeof(this).stringof ~ ".length!"; | 
 |             asArray!(digestLength!T)(buf, msg) = _digest.finish(); | 
 |             return buf[0 .. digestLength!T]; | 
 |         } | 
 |  | 
 |         ///ditto | 
 |         @trusted nothrow ubyte[] finish() | 
 |         { | 
 |             enum len = digestLength!T; | 
 |             auto buf = new ubyte[len]; | 
 |             asArray!(digestLength!T)(buf) = _digest.finish(); | 
 |             return buf; | 
 |         } | 
 |  | 
 |         version (StdDdoc) | 
 |         { | 
 |             /** | 
 |              * Works like $(D finish) but does not reset the internal state, so it's possible | 
 |              * to continue putting data into this WrapperDigest after a call to peek. | 
 |              * | 
 |              * These functions are only available if $(D hasPeek!T) is true. | 
 |              */ | 
 |             @trusted ubyte[] peek(ubyte[] buf) const; | 
 |             ///ditto | 
 |             @trusted ubyte[] peek() const; | 
 |         } | 
 |         else static if (hasPeek!T) | 
 |         { | 
 |             @trusted ubyte[] peek(ubyte[] buf) const | 
 |             in | 
 |             { | 
 |                 assert(buf.length >= this.length); | 
 |             } | 
 |             body | 
 |             { | 
 |                 enum string msg = "Buffer needs to be at least " ~ digestLength!(T).stringof ~ " bytes " ~ | 
 |                     "big, check " ~ typeof(this).stringof ~ ".length!"; | 
 |                 asArray!(digestLength!T)(buf, msg) = _digest.peek(); | 
 |                 return buf[0 .. digestLength!T]; | 
 |             } | 
 |  | 
 |             @trusted ubyte[] peek() const | 
 |             { | 
 |                 enum len = digestLength!T; | 
 |                 auto buf = new ubyte[len]; | 
 |                 asArray!(digestLength!T)(buf) = _digest.peek(); | 
 |                 return buf; | 
 |             } | 
 |         } | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     import std.digest.md; | 
 |     //Simple example | 
 |     auto hash = new WrapperDigest!MD5(); | 
 |     hash.put(cast(ubyte) 0); | 
 |     auto result = hash.finish(); | 
 | } | 
 |  | 
 | /// | 
 | @system unittest | 
 | { | 
 |     //using a supplied buffer | 
 |     import std.digest.md; | 
 |     ubyte[16] buf; | 
 |     auto hash = new WrapperDigest!MD5(); | 
 |     hash.put(cast(ubyte) 0); | 
 |     auto result = hash.finish(buf[]); | 
 |     //The result is now in result (and in buf). If you pass a buffer which is bigger than | 
 |     //necessary, result will have the correct length, but buf will still have it's original | 
 |     //length | 
 | } | 
 |  | 
 | @safe unittest | 
 | { | 
 |     // Test peek & length | 
 |     import std.digest.crc; | 
 |     auto hash = new WrapperDigest!CRC32(); | 
 |     assert(hash.length == 4); | 
 |     hash.put(cast(const(ubyte[]))"The quick brown fox jumps over the lazy dog"); | 
 |     assert(hash.peek().toHexString() == "39A34F41"); | 
 |     ubyte[5] buf; | 
 |     assert(hash.peek(buf).toHexString() == "39A34F41"); | 
 | } | 
 |  | 
 | /** | 
 |  * Securely compares two digest representations while protecting against timing | 
 |  * attacks. Do not use `==` to compare digest representations. | 
 |  * | 
 |  * The attack happens as follows: | 
 |  * | 
 |  * $(OL | 
 |  *     $(LI An attacker wants to send harmful data to your server, which | 
 |  *     requires a integrity HMAC SHA1 token signed with a secret.) | 
 |  *     $(LI The length of the token is known to be 40 characters long due to its format, | 
 |  *     so the attacker first sends `"0000000000000000000000000000000000000000"`, | 
 |  *     then `"1000000000000000000000000000000000000000"`, and so on.) | 
 |  *     $(LI The given HMAC token is compared with the expected token using the | 
 |  *     `==` string comparison, which returns `false` as soon as the first wrong | 
 |  *     element is found. If a wrong element is found, then a rejection is sent | 
 |  *     back to the sender.) | 
 |  *     $(LI Eventually, the attacker is able to determine the first character in | 
 |  *     the correct token because the sever takes slightly longer to return a | 
 |  *     rejection. This is due to the comparison moving on to second item in | 
 |  *     the two arrays, seeing they are different, and then sending the rejection.) | 
 |  *     $(LI It may seem like too small of a difference in time for the attacker | 
 |  *     to notice, but security researchers have shown that differences as | 
 |  *     small as $(LINK2 http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf, | 
 |  *     20µs can be reliably distinguished) even with network inconsistencies.) | 
 |  *     $(LI Repeat the process for each character until the attacker has the whole | 
 |  *     correct token and the server accepts the harmful data. This can be done | 
 |  *     in a week with the attacker pacing the attack to 10 requests per second | 
 |  *     with only one client.) | 
 |  * ) | 
 |  * | 
 |  * This function defends against this attack by always comparing every single | 
 |  * item in the array if the two arrays are the same length. Therefore, this | 
 |  * function is always $(BIGOH n) for ranges of the same length. | 
 |  * | 
 |  * This attack can also be mitigated via rate limiting and banning IPs which have too | 
 |  * many rejected requests. However, this does not completely solve the problem, | 
 |  * as the attacker could be in control of a bot net. To fully defend against | 
 |  * the timing attack, rate limiting, banning IPs, and using this function | 
 |  * should be used together. | 
 |  * | 
 |  * Params: | 
 |  *     r1 = A digest representation | 
 |  *     r2 = A digest representation | 
 |  * Returns: | 
 |  *     `true` if both representations are equal, `false` otherwise | 
 |  * See_Also: | 
 |  *     $(LINK2 https://en.wikipedia.org/wiki/Timing_attack, The Wikipedia article | 
 |  *     on timing attacks). | 
 |  */ | 
 | bool secureEqual(R1, R2)(R1 r1, R2 r2) | 
 | if (isInputRange!R1 && isInputRange!R2 && !isInfinite!R1 && !isInfinite!R2 && | 
 |     (isIntegral!(ElementEncodingType!R1) || isSomeChar!(ElementEncodingType!R1)) && | 
 |     !is(CommonType!(ElementEncodingType!R1, ElementEncodingType!R2) == void)) | 
 | { | 
 |     static if (hasLength!R1 && hasLength!R2) | 
 |         if (r1.length != r2.length) | 
 |             return false; | 
 |  | 
 |     int result; | 
 |  | 
 |     static if (isRandomAccessRange!R1 && isRandomAccessRange!R2 && | 
 |                hasLength!R1 && hasLength!R2) | 
 |     { | 
 |         foreach (i; 0 .. r1.length) | 
 |             result |= r1[i] ^ r2[i]; | 
 |     } | 
 |     else static if (hasLength!R1 && hasLength!R2) | 
 |     { | 
 |         // Lengths are the same so we can squeeze out a bit of performance | 
 |         // by not checking if r2 is empty | 
 |         for (; !r1.empty; r1.popFront(), r2.popFront()) | 
 |         { | 
 |             result |= r1.front ^ r2.front; | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         // Generic case, walk both ranges | 
 |         for (; !r1.empty; r1.popFront(), r2.popFront()) | 
 |         { | 
 |             if (r2.empty) return false; | 
 |             result |= r1.front ^ r2.front; | 
 |         } | 
 |         if (!r2.empty) return false; | 
 |     } | 
 |  | 
 |     return result == 0; | 
 | } | 
 |  | 
 | /// | 
 | @system pure unittest | 
 | { | 
 |     import std.digest.hmac : hmac; | 
 |     import std.digest.sha : SHA1; | 
 |     import std.string : representation; | 
 |  | 
 |     // a typical HMAC data integrity verification | 
 |     auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation; | 
 |     auto data = "data".representation; | 
 |  | 
 |     string hex1 = data.hmac!SHA1(secret).toHexString; | 
 |     string hex2 = data.hmac!SHA1(secret).toHexString; | 
 |     string hex3 = "data1".representation.hmac!SHA1(secret).toHexString; | 
 |  | 
 |     assert( secureEqual(hex1, hex2)); | 
 |     assert(!secureEqual(hex1, hex3)); | 
 | } | 
 |  | 
 | @system pure unittest | 
 | { | 
 |     import std.internal.test.dummyrange : ReferenceInputRange; | 
 |     import std.range : takeExactly; | 
 |     import std.string : representation; | 
 |     import std.utf : byWchar, byDchar; | 
 |  | 
 |     { | 
 |         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".representation; | 
 |         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".representation; | 
 |         assert(!secureEqual(hex1, hex2)); | 
 |     } | 
 |     { | 
 |         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018"w.representation; | 
 |         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018"d.representation; | 
 |         assert(secureEqual(hex1, hex2)); | 
 |     } | 
 |     { | 
 |         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byWchar; | 
 |         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar; | 
 |         assert(secureEqual(hex1, hex2)); | 
 |     } | 
 |     { | 
 |         auto hex1 = "02CA3484C375EDD3C0F08D3F50D119E61077".byWchar; | 
 |         auto hex2 = "02CA3484C375EDD3C0F08D3F50D119E610779018".byDchar; | 
 |         assert(!secureEqual(hex1, hex2)); | 
 |     } | 
 |     { | 
 |         auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); | 
 |         auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); | 
 |         assert(secureEqual(hex1, hex2)); | 
 |     } | 
 |     { | 
 |         auto hex1 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 8]).takeExactly(9); | 
 |         auto hex2 = new ReferenceInputRange!int([0, 1, 2, 3, 4, 5, 6, 7, 9]).takeExactly(9); | 
 |         assert(!secureEqual(hex1, hex2)); | 
 |     } | 
 | } |