Module 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.
Category | Functions |
---|---|
Template API | isDigest DigestType hasPeek
hasBlockSize
ExampleDigest digest hexDigest makeDigest
|
OOP API | Digest
|
Helper functions | toHexString secureEqual |
Implementation helpers | digestLength WrapperDigest |
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.
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)
Example
import std .digest .crc;
//Simple example
char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog");
writeln(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();
writeln(toHexString(hash)); // "39A34F41"
Example
//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);
}
}
Example
//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);
}
}
Example
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);
}
}
Functions
Name | Description |
---|---|
digest(range)
|
This is a convenience function to calculate a hash using the template API.
Every digest passing the isDigest test can be used with this function.
|
digest(data)
|
This overload of the digest function handles arrays. |
hexDigest(range)
|
This is a convenience function similar to digest , but it returns the string
representation of the hash. Every digest passing the isDigest test can be used with this
function.
|
hexDigest(data)
|
This overload of the hexDigest function handles arrays. |
makeDigest()
|
This is a convenience function which returns an initialized digest, so it's not necessary to call start manually. |
secureEqual(r1, r2)
|
Securely compares two digest representations while protecting against timing
attacks. Do not use == to compare digest representations.
|
toHexString(digest)
|
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. |
Interfaces
Name | Description |
---|---|
Digest
|
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. |
Classes
Name | Description |
---|---|
WrapperDigest
|
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, ...). |
Structs
Name | Description |
---|---|
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 isDigest test.
|
Enums
Name | Description |
---|---|
Order
|
See toHexString
|
Manifest constants
Name | Type | Description |
---|---|---|
hasBlockSize
|
Checks whether the digest has a blockSize member, which contains the
digest's internal block size in bits. It is primarily used by HMAC .
|
|
hasPeek
|
Used to check if a digest supports the peek method.
Peek has exactly the same function signatures as finish, but it doesn't reset
the digest's internal state.
|
|
isDigest
|
Use this to check if a type is a digest. See ExampleDigest to see what
a type must provide to pass this check.
|
Aliases
Name | Type | Description |
---|---|---|
DigestType
|
ReturnType!(typeof((){Tdig=void;returndig.finish();}))
|
Use this template to get the type which is returned by a digest's finish method.
|
Authors
Johannes Pfau