ハッシュ関数

2008年03月21日

ハッシュ関数

ハッシュ関数

ハッシュ関数 (Hash Function) とは任意長のバイナリデータから数十~数百 ビット程度の固定長バイナリを算出する関数です。古くから CRCWikipedia検索 のようなアルゴリズムが 誤り検出Google I'm Feeling Lucky™の用途で使用されてきましたが、暗号 などのセキュリティで使用されるハッシュ関数はような特徴を持ちます。

  1. 同じバイナリデータに対して常に同じ値が算出される。
  2. 異なるバイナリデータに対して同じ値が算出される (衝突) 確率が極めて低い。
  3. 算出された値から元のバイナリデータの推測が極めて難しい。

最近ではマシンパフォーマンスの向上もあって、セキュリティの用途で使用できる強い ハッシュ関数がバイナリデータの誤り検出や同一性検証 (インデックス付け) などにも 使用されています。

ハッシュアルゴリズム

Java で使用できる ハッシュアルゴリズム には Message Digest と SHA があります。誤り検出の用途であればツール等にも広く 普及している MD5 (128bit)、セキュリティ的な用途では SHA-256 (256bit) 以上で 十分と思われます (速度は大差ない)。

MD5 128bit Message Digest Algorithm 5: RSA と組み合わせて電子署名を行える よう開発されたアルゴリズム。データの誤り検出からパスワードの保存まで 広く使用されていますが、現在では (緊急性はないものの) いくつかの脆弱性が 報告されているためセキュリティの用途では SHA を使用した方が良い。
SHA 160,224,256,
384,512bit
Secure Hash Algorithm: SHA-1 (160bit), SHA-224~SHA-512 まで 存在するアルゴリズム。MD5 より攻撃に強いと言われ SSL, SSH や IPSec などにも使用されている。

ハッシュ値の生成

ハッシュ値はアルゴリズムを指定した MessageDigestJava™ API リファレンス にバイト配列を与えるだけで取得できます。

Java
byte[] binary = "hello, world".getBytes();
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(binary);

対象のバイナリが大きい場合は update() メソッドを使用することで内容を何度かに 分けて更新することができます。

Java
InputStream in = // ...
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[1024];
while(true){
    int len = in.read(buffer);
    if(len < 0) break;
    md.update(buffer, 0, len);
}
byte[] digest = md.digest();

DigestInputStreamJava™ API リファレンス, DigestOutputStreamJava™ API リファレンス クラスを使用することでストリームに入出力されるデータから透過的にハッシュ値を算出することができます。

Java
InputStream in = // ...
MessageDigest md = MessageDigest.getInstance("SHA-256");
in = new DigestInputStream(in, md);
byte[] buffer = new byte[1024];
while(true){
    int len = in.read(buffer);
    if(len < 0) break;
}
byte[] digest = md.digest();

アルゴリズムの確認

実行環境で使用できるハッシュアルゴリズムは SecurityJava™ API リファレンス クラスで列挙することができます。

Java
Set<String> algorithms = Security.getAlgorithms("MessageDigest");
for(String algorithm: algorithms) {
    MessageDigest md = MessageDigest.getInstance(algorithm);
    System.out.printf("%-7s: %dbit%n", algorithm, md.getDigestLength()*8);
}

Java SE 6 でのデフォルトの実行結果は以下の通り。

実行結果
SHA-256: 256bit
SHA-512: 512bit
SHA    : 160bit
SHA-384: 384bit
MD5    : 128bit
MD2    : 128bit
CVS 2008/04/01