web-dev-qa-db-ja.com

Java-ハッシュアルゴリズム-最速の実装

Java特にMD5およびSHA-2 512(SHA512)または256のハッシュアルゴリズムの最良かつ最速の実装は何かを知りたいです。引数として文字列を取得する関数が必要です。結果としてハッシュを返します。

編集:これは、各URLを一意のハッシュにマッピングするためのものです。 MD5はこの分野ではそれほど信頼性が高くないため、SHA-2アルゴリズムの最適かつ最速の実装を見つけることに興味があります。 SHA-2でさえ、一部のURLに対して同じハッシュを生成する可能性があることは知っていますが、それでも問題ありません。

29
Alireza Noori

まず最初に:速度が過大評価されています。特定のアルゴリズムが「遅すぎる」と宣言する前に対策を講じる必要があります。ほとんどの場合、ハッシュ関数の速度は目立った違いはありません。セキュリティに不安がある場合は、まず十分に安全なハッシュ関数を選択してから、パフォーマンスのみを心配します。

さらに、「文字列」をハッシュする必要があります。 A Java Stringは、内部的に、Unicodeコードポイントを表すchar値の配列からのチャンクです(実際には、エンコードするUnicode 16ビットコード単位UTF-16を使用したコードポイント)ハッシュ関数は、入力としてビットまたはバイトのシーケンスを受け取ります。したがって、文字列をバイトの束として取得するために、たとえばstr.getBytes("UTF-8")などの変換ステップを行う必要があります。ハッシュ自体と比較した場合、変換ステップのコストは無視できないものになる可能性があります。

注:URLエンコードに注意してください! URLでは、一部のバイトを「_%_」記号で始まるシーケンスに置き換えることができます。これは印刷不可能な文字をサポートするためのものですが、「標準」文字でも使用できます(たとえば、「a」を「_%61_」に置き換えます)。これは、(String.equals()の意味で)異なる2つの文字列が(URL処理に関する限り)実際に同じURLを表す場合があることを意味します。状況に応じて、これは問題になる場合とそうでない場合があります。

最初に、JavaのMessageDigest AP​​Iを標準(インストール済みの)JCEプロバイダー(つまり、MessageDigest.getInstance("SHA-256")を呼び出す)で使用して、結果をベンチしようとする必要があります。理論的には、JCEは呼び出しを「ネイティブ」コード(Cまたはアセンブリで記述された)を使用して実装にマップします。これは、Javaで取得できるものよりも高速になります。

言われていること...

sphlib は、CおよびJavaの多くの暗号化ハッシュ関数のオープンソース実装です。コードは速度が最適化されており、実際にはJavaバージョンはSun/Oracleの標準JREが提供するものよりも高速であることが判明しています。使用 このリンク =前のリンクが失敗した場合(現在のように、メインホストサーバーがメンテナンスのためダウンしている場合があります)(警告:10 MBのダウンロード)。アーカイブにはレポートも含まれています(レポートは 2番目のSHA-3候補者会議 2010年)、SHA-2および今後のSHA-3の14の「第2ラウンド」候補者について、いくつかのプラットフォームで測定されたパフォーマンス値を示します。

しかし、実際にその場でベンチマークを作成する必要があります。たとえば、L1キャッシュへの影響はパフォーマンスに大きな影響を与える可能性があり、関数コードを取得して単独で実行しても正確に予測できません。

49
Thomas Pornin

編集:私はもともと質問を「最速のハッシュアルゴリズム」と読み、「各アルゴリズムの最速の実装」であることを明確にしました。それは有効な質問であり、他の人はより速い実装を指摘しています。ただし、大量のデータを短時間でハッシュしない限り、それほど重要ではありません。通常、標準のJCEで提供されるもの以外のものを使用することは、時間と複雑さの価値があるとは思いません。

URLアドレスについては、より高速なものを必要とする現代のハードウェアでは、SHA-256で1秒あたりミリオン以上にハッシュする必要があります。ほとんどのアプリケーションが1秒あたり1,000以上(1日あたり8,600万を超える)を必要とすることは想像できません。つまり、ハッシュに費やされる全体的なCPU時間は1%をはるかに下回ります。したがって、無限に高速なハッシュアルゴリズムを使用していても、全体のパフォーマンスを最大で1%しか向上させることはできません。

元の回答:最高と最速の両方を取得することは、互いに対立します。一般的に、より良いハッシュは遅くなります。あなたが本当に速度を必要とし、セキュリティがそれほど重要でないなら、MD5を使用してください。最高のセキュリティが必要な場合は、SHA-256またはSHA-512を使用してください。あなたはそれを使用しているものについて言及していないので、どちらかを推薦するのは難しいです。 SHA-256は、最新のハードウェアでのほとんどのユースケースに対して十分に高速であるため、おそらく最も安全です。方法は次のとおりです。

String input = "your string";
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(input.getBytes("UTF-8"));
byte[] hash = digest.digest();

パスワードのハッシュなど、セキュリティの目的でこれを使用している場合は、ダイジェストにソルトも追加する必要があります。ハッシュから印刷可能な文字列が必要な場合は、16進数として文字列にエンコードして戻すことができます。

static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte b : hash) {
    sb.append(HEX_CHARS[(b & 0xF0) >> 4]);
    sb.append(HEX_CHARS[b & 0x0F]);
}
String hex = sb.toString();
21
WhiteFang34

考慮すべきもう1つのことは、MD4の使用です。 MD5ほど安全ではありませんが、さらに高速に計算されます。 Windows XPはMD4でパスワードを保存および交換するために使用されます。このプラットフォームに認証サービスを提供できるため、このハッシュを使用します。

2
Daniel

これらをチェックしてください: SHA/MD5の例

また: 同じスレッドから:Fast MD5

文字列ハッシュ= MD5.asHex(MD5.getHash(new File(filename)));

2
AndyMac

上記のハッシュよりも高速で安全なBLAKE2を検討してください。

MD5、SHA-1、SHA256、およびSHA-512は、長さの延長の影響を受けます。

MD5およびSHA-1は衝突に対して脆弱です。

MD5は、選択されたプレフィックスの衝突に対して脆弱です。

SHA-3およびBLAKE2には既知のセキュリティ問題はなく、さまざまな長さのダイジェストを生成できます。

SHA-3は、ハードウェアに実装した場合に最速です。 BLAKE2は、ソフトウェア実装を使用する場合に最速です。

BLAKE2bは64ビットプラットフォーム向けに最適化されており、1〜64バイトの任意のサイズのダイジェストを生成します。

BLAKE2sは8〜32ビットプラットフォーム向けに最適化されており、1〜32バイトの任意のサイズのダイジェストを生成します。

AES、MD5、SHA-256、およびBLAKE2bのベンチマークは次のとおりです。

https://blake2.net/

https://www.cryptopp.com/benchmarks.html

最初のリンクでは、BLAKE2b(947 Mbits)はSHA-256(413 Mbits)およびMD5(632 Mbits)よりもはるかに高速です。

2番目のリンクでは、AES-256 CBC(805 Mbits)およびBLAKE2b(776 Mbits)は、SHA-256(275 Mbits)およびMD5(602)Mbitsとほぼ同等の速度で高速です。

1

文字列の場合は、メモリオーバーヘッドが少ないため、hashCode()を呼び出すだけです。

それ以外の場合、プライベートハッシュに次のコードをお勧めします。

public static int hash8(String val) throws UnsupportedEncodingException {
    return hash8(val.getBytes("UTF-8"));
}

public static int hash8(byte[] val) {
    int h = 1, i = 0;
    for (; i + 7 < val.length; i += 8) {
        h = 31 * 31 * 31 * 31 * 31 * 31 * 31 * 31 * h + 31 * 31 * 31 * 31
                * 31 * 31 * 31 * val[i] + 31 * 31 * 31 * 31 * 31 * 31
                * val[i + 1] + 31 * 31 * 31 * 31 * 31 * val[i + 2] + 31
                * 31 * 31 * 31 * val[i + 3] + 31 * 31 * 31 * val[i + 4]
                + 31 * 31 * val[i + 5] + 31 * val[i + 6] + val[i + 7];
    }
    for (; i + 3 < val.length; i += 4) {
        h = 31 * 31 * 31 * 31 * h + 31 * 31 * 31 * val[i] + 31 * 31
                * val[i + 1] + 31 * val[i + 2] + val[i + 3];
    }
    for (; i < val.length; i++) {
        h = 31 * h + val[i];
    }
    return h;
}

参考: http://lemire.me/blog/2015/10/22/faster-hashing-without-effort/

0
Daniel De León