1. ホーム
  2. c#

[解決済み] 暗号ハッシュ関数はどれを選べばいいですか?

2022-05-11 16:11:53

質問

.NETフレームワークには、6種類のハッシュアルゴリズムが同梱されています。

  • MD5:16バイト(500MBのハッシュ化に要する時間:1462ms)
  • SHA-1:20バイト(1644ミリ秒)
  • SHA256:32バイト(5618ミリ秒)
  • SHA384:48バイト(3839ミリ秒)
  • SHA512:64バイト(3820ミリ秒)
  • RIPEMD:20バイト(7066ミリ秒)

MD5が最も速く、RIPEMDが最も遅いというように、それぞれの関数が異なる性能を発揮します。

MD5は、組み込みのGuid型に収まるという利点があります。 であり、タイプ3のUUIDの基本である . SHA-1ハッシュは、タイプ5 UUIDのベースとなる。 そのため、識別のために実に簡単に使用することができます。

しかし、MD5は以下のような脆弱性があります。 コリジョンアタック SHA-1も脆弱ですが、その程度はそれほどでもありません。

どのような場合に、どのハッシュアルゴリズムを使うべきですか?

特に回答が欲しいのは、以下のような質問です。

  • MD5は信用できないのですか?悪意がなく、第三者が悪意を持っていない通常の状況でMD5アルゴリズムを使用する場合、衝突(任意の2つのbyte[]が同じハッシュを生成すること)が発生する可能性はありますか?

  • RIPEMDはSHA1よりどの程度優れているのですか?(計算速度は5倍遅いですが、ハッシュサイズはSHA1と同じです。

  • ファイル名(またはその他の短い文字列)をハッシュ化する際に、悪意のない衝突が発生する確率はどのくらいですか?(例えば、同じMD5ハッシュを持つ2つのランダムなファイル名) (MD5 / SHA1 / SHA2xxで) 一般的に、悪意のない衝突の確率はどのくらいですか?

これは私が使用したベンチマークです。

    static void TimeAction(string description, int iterations, Action func) {
        var watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < iterations; i++) {
            func();
        }
        watch.Stop();
        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
    }

    static byte[] GetRandomBytes(int count) {
        var bytes = new byte[count];
        (new Random()).NextBytes(bytes);
        return bytes;
    }
    

    static void Main(string[] args) {

        var md5 = new MD5CryptoServiceProvider();
        var sha1 = new SHA1CryptoServiceProvider();
        var sha256 = new SHA256CryptoServiceProvider();
        var sha384 = new SHA384CryptoServiceProvider();
        var sha512 = new SHA512CryptoServiceProvider();
        var ripemd160 = new RIPEMD160Managed();

        var source = GetRandomBytes(1000 * 1024);

        var algorithms = new Dictionary<string,HashAlgorithm>();
        algorithms["md5"] = md5;
        algorithms["sha1"] = sha1;
        algorithms["sha256"] = sha256;
        algorithms["sha384"] = sha384;
        algorithms["sha512"] = sha512;
        algorithms["ripemd160"] = ripemd160;

        foreach (var pair in algorithms) {
            Console.WriteLine("Hash Length for {0} is {1}", 
                pair.Key, 
                pair.Value.ComputeHash(source).Length);
        }

        foreach (var pair in algorithms) {
            TimeAction(pair.Key + " calculation", 500, () =>
            {
                pair.Value.ComputeHash(source);
            });
        }

        Console.ReadKey();
    }

解決方法は?

暗号技術において、ハッシュ関数は3つの機能を提供します。

  1. 耐衝突性 : 2つのメッセージ( いずれか 同じハッシュを持つ2つのメッセージ)。
  2. プリ画像耐性 : あるハッシュが与えられたとき、同じハッシュを持つ別のメッセージを見つけるのはどれくらい難しいか?としても知られている。 ワンウェイハッシュ関数 .
  3. 第二のプリ画像耐性 : あるメッセージが与えられたとき、同じハッシュを持つ別のメッセージを見つける。

これらの特性は関連しているが、独立している。例えば、耐衝突性は第2次プリ画像性を意味するが、その逆はない。どのようなアプリケーションでも、これらの特性のうち1つまたは複数を必要とする、異なる要件があるはずです。例えば、サーバー上のパスワードを保護するためのハッシュ関数では、通常、耐予像性だけが必要とされますが、メッセージダイジェストでは3つすべてが必要とされます。

MD5は耐衝突性がないことが示されていますが、だからといって耐衝突性を必要としない用途に使用することを妨げるものではありません。実際、鍵のサイズが小さく高速であることが有利なアプリケーションでは、今でもMD5がよく使われています。とはいえ、MD5には欠陥があるため、研究者は新しいシナリオでは他のハッシュ関数を使用することを推奨しています。

SHA1には、その長さの安全なハッシュ関数が必要とする2^80ステップよりも理論的にはるかに少ないステップで衝突を発見できる欠陥があります。この攻撃は継続的に修正されており、現在では2^63ステップで可能で、現在の計算可能な範囲にぎりぎり収まっています。このため、NISTはSHA1の使用を段階的に停止し、2010年以降はSHA2ファミリーを使用するよう述べています。

SHA2は、SHA1に続いて作られた新しいハッシュ関数ファミリーである。現在、SHA2関数に対する攻撃は確認されていない。SHA256、384、512はすべてSHA2ファミリーに属し、異なる鍵長を使用しているだけである。

RIPEMDについては、SHAファミリーほど一般的に使用されていないため、暗号研究者による綿密な調査が行われていないことを除けば、あまり多くのコメントはできません。そのため、私はSHA関数を使用することをお勧めします。あなたが使っている実装では、この関数はかなり遅いので、あまり役に立ちません。

結論として、最適な関数というのはありません。それぞれの欠点に注意することで、以下のような用途に適したハッシュ関数を選択することができます。 あなたの シナリオを作成します。