英語版
このページの英語版を見る

std.digest

このモジュールは "phobos"で使用されるダイジェストAPIについて説明する。すべてのダイジェストは APIに従う。さらに、このモジュールにはすべてのダイジェスト型で使用できる が含まれている。
カテゴリー 関数" 区分
Template API isDigestDigestTypehasPeek hasBlockSize ExampleDigestdigesthexDigestmakeDigest
OOP API Digest
Helper functions toHexStringsecureEqual
Implementation helpers digestLengthWrapperDigest

API ダイジェストには2つのAPIがある:テンプレートAPIとOOP APIである。テンプレートAPIは構造体 と isDigest.OOP APIは、ダイジェストを. を継承したクラスとして実装する。 Digestインターフェイスを継承するクラスとして実装される。すべてのダイジェストは、テンプレートAPI構造体を"x"、OOP APIクラスを" Digest "と呼ぶように命名されている。 と呼ばれ、OOP APIクラスは"xDigest "と呼ばれる。例えば、MD5 <-->MD5DigestCRC32 <-->CRC32Digest などである。

テンプレートAPIは若干効率的である。動的にメモリを確保する必要がない、 すべてのメモリはスタックに割り当てられる。OOP APIは、バッファが提供されなかった場合、finishメソッドで割り当てなければならない。 バッファが提供されていない場合、OOP APIはfinishメソッドで割り当てなければならない。もしOOP APIのfinish関数にバッファを提供すれば、バッファは確保されない、 しかし Digestクラスはnew 、GCを使って割り当てられる。
OOP APIは、"実行時"にダイジェスト関数やダイジェスト・バックエンドを変更するのに便利である。ここでの利点は は、例えば "phobos MD5Digest"とOpenSSLMD5Digestの実装を切り替えることで、ABI互換性が保たれることである。
特定のダイジェスト型とバックエンドが必要なだけなら、通常はテンプレートAPIが適している。 こ の最 も 簡単な場合、 テ ンプ レー ト API はテ ンプ レー ト な し で も 使え る :x" 構造体を直接使うだけである。 を直接使用すればよい。

Authors:
Johannes Pfau

CTFE ダイジェストはCTFEでは機能しない

TODO バイトではなく)シングルビットのダイジェストは実装されていない。これは、別の テンプレート制約ヘルパー(hasBitDigesting!T)と追加インターフェース(BitDigest)として行われる。

Examples:
import std.digest.crc;

//簡単な例
char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog");
writeln(hexHash); // "39A34F41"

//APIを手動で使用する簡単な例
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"
Examples:
//ファイルのハッシュを生成する、慣用的なDの方法
import std.digest.crc, std.digest.md, std.digest.sha;
import std.stdio;

// ファイルをダイジェストし、結果を表示する。
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);
    }
}
Examples:
//テンプレートAPIを使用してファイルのハッシュを生成する
import std.digest.crc, std.digest.md, std.digest.sha;
import std.stdio;
// ファイルをダイジェストし、結果を表示する。
void digestFile(Hash)(ref Hash hash, string filename)
if (isDigest!Hash)
{
    File file = File(filename);

    //ダイジェストはOutputRangeを実装しているので、std.algorithm.copyを使用できる
    //とりあえず手動でやってみよう
    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);
    }
}
Examples:
import std.digest.crc, std.digest.md, std.digest.sha;
import std.stdio;

// ファイルをダイジェストし、結果を表示する。
void digestFile(Digest hash, string filename)
{
    File file = File(filename);

    //ダイジェストはOutputRangeを実装しているので、std.algorithm.copyを使用できる
    //とりあえず手動でやってみよう
    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);
    }
}
struct ExampleDigest;
これは、テンプレートAPIにおけるダイジェストの一般的な構造を文書化したものである。 すべてのダイジェスト実装は以下のメンバを実装し、したがって テストに合格しなければならない。 isDigestテストに合格しなければならない。

注釈:

  • テストに合格するには、ダイジェストは構造体(値型)でなければならない。 isDigestテストに合格しなければならない。
  • ダイジェストが isDigestテストに合格したダイジェストは常にOutputRange

Examples:
//OutputRange機能を使う
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); //注釈: コピーにはポインターを渡さなければならない!
writeln(ctx.finish().toHexString()); // "7707D6AE4E027C70EEA2A935C2296F21"
@trusted void put(scope const(ubyte)[] data...);
ダイジェストにデータを供給するために使用する。 また std.range.primitives.isOutputRange ubyte const(ubyte)[] インターフェースも実装している。 以下の putを渡す "型"で動作しなければならない。 を渡す isDigest:

例:

ExampleDigest dig;
dig.put(cast(ubyte) 0); //シングルubyte
dig.put(cast(ubyte) 0, cast(ubyte) 0); //可変長
ubyte[10] buf;
dig.put(buf); //バッファ

@trusted void start();
この関数はダイジェストを(再)初期化するために使用される。 ダイジェストを使用する前にコールする必要があり、また "リセット"関数としても機能する。 としても機能する。
@trusted ubyte[16] finish();
finish関数は最終的なハッシュ合計を返し、ダイジェストをリセットする。

注釈: finishが実際に返す型は、ダイジェストの実装に依存する。 ubyte[16] は単なる例として使われている。ubytesの静的配列であることが保証されている。 の静的配列であることが保証されている。

  • 実際の戻り値の型を得るには DigestTypeを使って実際の戻り値の型を取得する。
  • ubyte配列の長さを得るには digestLengthを使ってubyte配列の長さを取得する。

enum bool isDigest(T);
型がダイジェストかどうかを調べる。を参照する。 ExampleDigestを参照のこと。 を参照のこと。

注釈: これはテンプレート制約として非常に有用である(例を参照)。

Bugs:
  • put がスコープ・パラメータを取ることをまだ確認していない。
  • finish()がubyte[num]配列を返すことを確認する必要がある。
Examples:
import std.digest.crc;
static assert(isDigest!CRC32);
Examples:
import std.digest.crc;
void myFunction(T)()
if (isDigest!T)
{
    T dig;
    dig.start();
    auto result = dig.finish();
}
myFunction!CRC32();
template DigestType(T)
このテンプレートを使って、ダイジェストの finishメソッドによって返される
Examples:
import std.digest.crc;
assert(is(DigestType!(CRC32) == ubyte[4]));
Examples:
import std.digest.crc;
CRC32 dig;
dig.start();
DigestType!CRC32 result = dig.finish();
enum bool hasPeek(T);
ダイジェストがpeek メソッドをサポートしているかどうかをチェックするために使用する。 Peekはfinishとまったく同じ関数シグネチャを持つが、ダイジェストの内部状態をリセットしない。 ダイジェストの内部状態をリセットしない。

注釈: ダイジェストの内部状態をリセットしない。

  • これはテンプレート制約として非常に有用である(例を参照)。
  • これはまた、Tが isDigest

Examples:
import std.digest.crc, std.digest.md;
assert(!hasPeek!(MD5));
assert(hasPeek!CRC32);
Examples:
import std.digest.crc;
void myFunction(T)()
if (hasPeek!T)
{
    T dig;
    dig.start();
    auto result = dig.peek();
}
myFunction!CRC32();
template hasBlockSize(T) if (isDigest!T)
ダイジェストにblockSize メンバがあるかどうかを調べる。 ダイジェストの内部ブロックサイズがビット単位で格納されている。これは主に std.digest.hmac.HMAC.
Examples:
import std.digest.hmac, std.digest.md;
static assert(hasBlockSize!MD5        && MD5.blockSize      == 512);
static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512);
DigestType!Hash digest(Hash, Range)(auto ref Range range)
if (!isArray!Range && isDigestibleRange!Range);
これは、テンプレートAPIを使ってハッシュを計算するための便利な関数である。 テストに合格したダイジェストはすべて isDigestテストに合格したすべてのダイジェストは、この関数で使用することができる。
Parameters:
Range range InputRangeElementType ubyte ,ubyte[] またはubyte[num]
Examples:
import std.digest.md;
import std.range : repeat;
auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
auto md5 = digest!MD5(testRange);
DigestType!Hash digest(Hash, T...)(scope const T data)
if (allSatisfy!(isArray, typeof(data)));
このdigest関数のオーバーロードは配列を扱う。
Parameters:
T data 任意の型の1つ以上の配列。
Examples:
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");
writeln(toHexString(crc32)); // "39A34F41"
Examples:
import std.digest.crc;
auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
writeln(toHexString(crc32)); // "39A34F41"
char[digestLength!Hash * 2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range)
if (!isArray!Range && isDigestibleRange!Range);
に似た便利な関数である。 digestに似ているが、ハッシュの文字列表現 表現を返す。をパスしたすべてのダイジェストは isDigestテストに合格したすべてのダイジェストは、この 関数で使用できる。
Parameters:
order バイトが処理される順序 ( toHexString)
Range range InputRangeElementType ubyte ubyte[] またはubyte[num]
Examples:
import std.digest.md;
import std.range : repeat;
auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
writeln(hexDigest!MD5(testRange)); // "36A92CC94A9E0FA21F625F8BFB007ADF"
char[digestLength!Hash * 2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data)
if (allSatisfy!(isArray, typeof(data)));
このhexDigest関数のオーバーロードは配列を扱う。
Parameters:
order バイトが処理される順序 ( toHexString)
T data 任意の型の1つ以上の配列
Examples:
import std.digest.crc;
// "414FA339"
writeln(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog"));
Examples:
import std.digest.crc;
// "414FA339"
writeln(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog"));
Hash makeDigest(Hash)();
これは初期化されたダイジェストを返す便利な関数である。 を手動で呼び出す必要はない。
Examples:
import std.digest.md;
auto md5 = makeDigest!MD5();
md5.put(0);
writeln(toHexString(md5.finish())); // "93B885ADFE0DA089CDF634904FD59F71"
interface Digest;
ここではOOP APIについて説明する。どのような場合にテンプレートAPIを使用し、どのような場合にOOP APIを使用するのかを理解するには、このページの上部にあるモジュール・ドキュメントを参照のこと、 このページの一番上にあるモジュール・ドキュメントを参照のこと。
ダイジェスト・インターフェースは、すべてのダイジェストが実装する基本インターフェースである。

注釈 ダイジェストの実装は常にOutputRange

Examples:
//OutputRange機能を使う
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);
writeln(ctx.finish().toHexString()); // "7707D6AE4E027C70EEA2A935C2296F21"
Examples:
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");
writeln(crcHexString(crc32)); // "414FA339"
Examples:
import std.digest.crc;
ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
writeln(crcHexString(crc32)); // "414FA339"
Examples:
void test(Digest dig)
{
    dig.put(cast(ubyte) 0); //シングルubyte
    dig.put(cast(ubyte) 0, cast(ubyte) 0); //可変長
    ubyte[10] buf;
    dig.put(buf); //バッファ
}
abstract nothrow @trusted void put(scope const(ubyte)[] data...);
ダイジェストにデータを供給するために使用する。 また std.range.primitives.isOutputRange ubyte const(ubyte)[] インターフェースも実装している。

例:

void test(Digest dig)
{
    dig.put(cast(ubyte) 0); //シングルubyte
    dig.put(cast(ubyte) 0, cast(ubyte) 0); //可変長
    ubyte[10] buf;
    dig.put(buf); //バッファ
}

abstract nothrow @trusted void reset();
ダイジェストの内部状態をリセットする。

注釈: ダイジェストの内部状態をリセットする。 finishを呼び出す必要はない。 resetを呼び出した後に手動で finish.

abstract const nothrow @property @trusted size_t length();
が返すハッシュ値のバイト数である。 finish. に渡されるバッファの必要サイズでもある。 finish.
abstract nothrow @trusted ubyte[] finish();

abstract nothrow ubyte[] finish(ubyte[] buf);
finish関数はハッシュ値を返す。にコピーするバッファをオプションで受け取る。 にコピーする。バッファを渡す場合は、少なくとも lengthバイトの大きさでなければならない。
final nothrow @trusted ubyte[] digest(scope const(void[])[] data...);
これは、OOP APIを使って値のハッシュを計算するための便利な関数である。
enum Order: bool;
以下を参照のこと。 toHexString
Examples:
import std.digest.crc : CRC32;

auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
writeln(crc32.toHexString!(Order.decreasing)); // "414FA339"
writeln(crc32.toHexString!(LetterCase.lower, Order.decreasing)); // "414fa339"
increasing
decreasing
char[num * 2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper)(const ubyte[num] digest);

char[num * 2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest);

string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper)(in ubyte[] digest);

string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest);
ハッシュ値(静的または動的なubyte配列)を文字列に変換する。 OOPやテンプレートAPIで使用できる。
追加の order パラメータを使用して、入力データの順序を指定することができる。 デフォルトでは、データはインデックス0から順に処理される。逆の順序で処理するには 逆の順序で処理するには、Order.decreasingをパラメータとして渡す。
追加のletterCaseパラメータを使用して、出力データの大文字と小文字を指定することができる。 デフォルトでは、出力は大文字である。小文字に変更するには LetterCase.lower をパラメータとして渡す。

注釈 文字列を返す関数のオーバーロードは、GCを使用して戻り値を割り当てる。 を割り当てる。静的配列を返すバージョンは、戻り値に対してパス・バイ・バリューを使用する。 を使用し、効果的に動的割り当てを回避する。

Examples:
import std.digest.crc;
//テンプレートAPIでテストする:
auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
//小文字のバリアント:
writeln(toHexString!(LetterCase.lower)(crc32)); // "39a34f41"
//通常、CRCはこの順序で表示されるが:
writeln(toHexString!(Order.decreasing)(crc32)); // "414FA339"
writeln(toHexString!(LetterCase.lower, Order.decreasing)(crc32)); // "414fa339"
Examples:
import std.digest.crc;
// OOP APIを使用する
auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
//通常、CRCはこの順番で表示されるが:
writeln(toHexString!(Order.decreasing)(crc32)); // "414FA339"
class WrapperDigest(T) if (isDigest!T): Digest;
テンプレートAPIのハッシュ構造体をダイジェストインターフェースにラップする。 ダイジェスト実装を提供するモジュールは通常、このテンプレートの別名 このテンプレートの別名(例えば MD5Digest、SHA1Digest、...)を提供する。
Examples:
import std.digest.md;
//簡単な例
auto hash = new WrapperDigest!MD5();
hash.put(cast(ubyte) 0);
auto result = hash.finish();
Examples:
//供給されたバッファを使用する
import std.digest.md;
ubyte[16] buf;
auto hash = new WrapperDigest!MD5();
hash.put(cast(ubyte) 0);
auto result = hash.finish(buf[]);
//結果はresult(およびbuf)に格納されている。必要以上に大きなバッファを渡した場合、
//resultには正しい長さのデータが格納されるが、bufは
//元の長さのままになる
this();
ダイジェストを初期化する。
nothrow @trusted void put(scope const(ubyte)[] data...);
ダイジェストにデータを供給するために使用する。 また std.range.primitives.isOutputRange ubyte const(ubyte)[] インターフェースも実装する。
nothrow @trusted void reset();
ダイジェストの内部状態をリセットする。

注釈: ダイジェストの内部状態をリセットする。 finishは内部的にこれを呼び出す。 resetを呼び出した後に手動で finish.

const pure nothrow @property @trusted size_t length();
が返すハッシュ値のバイト数である。 finish. に渡されるバッファの必要サイズでもある。 finish.
nothrow ubyte[] finish(ubyte[] buf);

nothrow @trusted ubyte[] finish();
finish関数はハッシュ値を返す。にコピーするバッファをオプションで受け取る。 にコピーする。バッファを渡す場合は、少なくとも lengthバイト以上でなければならない。

例:

import std.digest.md;
ubyte[16] buf;
auto hash = new WrapperDigest!MD5();
hash.put(cast(ubyte) 0);
auto result = hash.finish(buf[]);
//結果はresult(およびbuf)に格納されている。必要以上に大きなバッファを渡した場合、
//resultには正しい長さのデータが格納されるが、bufは
//元の長さのままになる

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

const @trusted ubyte[] peek();
finish のように動作するが、内部状態をリセットしないので、ピーキング(peek)コールの後、 このWrapperDigestにデータを入れ続けることが可能だ。 peekへのコールの後、このWrapperDigestにデータを入れ続けることができる。
これらの関数は、hasPeek!T がtrueであるときだけ利用可能である。
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));
タイミング攻撃から保護しながら、2つのダイジェスト表現を安全に比較する 攻撃から保護する。ダイジェスト表現の比較には== を使用しないこと。
攻撃は以下のように行われる:
  1. 攻撃者はあなたのサーバーに有害なデータを送ろうとする。 攻撃者はあなたのサーバーに有害なデータを送ろうとし、それには秘密で署名された完全性HMAC SHA1トークンが必要である。
  2. トークンの長さは、その形式から40文字であることがわかっている、 そのため、攻撃者はまず"0000000000000000000000000000000000000000" を送信する、 次に"1000000000000000000000000000000000000000" 、と続く。
  3. 与えられたHMACトークンは、文字列比較を使用して期待されるトークンと比較される。 == false 文字列比較を使用する。 を返す。間違ったエレメントが見つかると、拒否が送信者に返される。 が送信者に返される。
  4. 最終的に、攻撃者は正しいトークンの最初の文字を決定することができる。 の最初の文字を決定することができる。 を返すのに少し時間がかかるからである。これは、比較が2つの配列の2番目の項目に移るためである。 これは、比較が2つの配列の2番目の項目まで進み、それらが異なることを確認してから拒否を送信するためである。
  5. 攻撃者が気づくにはあまりにも小さな時間の差に思えるかもしれない。 しかし、セキュリティ研究者たちは、20µsの差であれば ネットワークの不整合があっても、20µsの差なら確実に識別できる。
  6. 攻撃者がトークン全体を正しく取得し、サーバーがトークンを受け入れるまで、各文字についてこのプロセスを繰り返す。 を取得し、サーバーが有害なデータを受け入れるまで、各文字の処理を繰り返す。これは 攻撃者が1秒間に10リクエストのペースで攻撃すれば、1週間で完了する。 クライアントが1つしかない場合である。
この"関数"は、2つの配列が同じ長さであれば、常に配列のすべての項目を比較することで、この攻撃を防御する。 を常に比較することで、この攻撃を防御する。したがって、この 関数は、同じ長さの範囲に対しては常にΟ(n)となる。
この攻撃は、レート制限や、拒否されたリクエストが多すぎるIPを禁止する ことによって軽減することもできる。 この攻撃は、レート制限や、拒否されたリクエストが多すぎる IPを禁止することでも軽減できる。しかし、これは問題を完全には解決しない、 攻撃者がボットネットをコントロールしている可能性があるからだ。完全に防御するには タイミング攻撃を完全に防御するためには、レート制限、IPの禁止、および「関数」 の使用を併用すべきである。 を併用すべきである。
Parameters:
R1 r1 ダイジェスト表示
R2 r2 ダイジェスト表示
Returns:
true 両方の表現が等しい場合、 。 false
See Also:
ウィキペディアのを参照のこと。
Examples:
import std.digest.hmac : hmac;
import std.digest.sha : SHA1;
import std.string : representation;

// 典型的なHMACデータ完全性検証
auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation;
auto data = "data".representation;

auto hex1 = data.hmac!SHA1(secret).toHexString;
auto hex2 = data.hmac!SHA1(secret).toHexString;
auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString;

assert( secureEqual(hex1[], hex2[]));
assert(!secureEqual(hex1[], hex3[]));