Quickly fork, edit online, and submit a pull request for this page.
Requires a signed-in GitHub account. This works well for small changes.
If you'd like to make larger changes you may want to consider using
a local clone.

std.digest

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.

APIs
There are two APIs for digests: The template API and the OOP API. The template API uses structs
and template helpers like isDigest. The OOP API implements digests as classes inheriting
the Digest interface. All digests are named so that the template API struct is called "x"
and the OOP API class is called "xDigest". For example we have MD5 <--> MD5Digest,
CRC32 <--> 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 Digest classes still have to be created using 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 "x" structs
directly.

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.

//using a supplied buffer
import std.digest.md;
ubyte[16] buf;
auto hash = newWrapperDigest!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

Notefinish calls this internally, so it's not necessary to call
reset manually after a call to finish.

const pure nothrow @property @trusted size_t length();

This is the length in bytes of the hash value which is returned by finish.
It's also the required size of a buffer passed to finish.

nothrow ubyte[] finish(ubyte[] buf);

nothrow @trusted ubyte[] finish();

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 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

const @trusted ubyte[] peek(ubyte[] buf);

const @trusted ubyte[] peek();

Works like finish but does not reset the internal state, so it's possible
to continue putting data into this WrapperDigest after a call to peek.

Securely compares two digest representations while protecting against timing
attacks. Do not use == to compare digest representations.

The attack happens as follows:

An attacker wants to send harmful data to your server, which
requires a integrity HMAC SHA1 token signed with a secret.

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.

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.

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.

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 20µs can be reliably distinguished even with network inconsistencies.

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 Ο(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.