連載
» 2005年01月25日 10時00分 公開

JavaTips 〜Javaプログラミング編:Javaでダイジェストを生成する

[BULL,@IT]

ダイジェストの概要

 ダイジェストは、ハッシュ関数(1方向関数)を用いて、ある長さを持つデータを固定長のデータに変換したものです。ダイジェストから元のデータは復元できず、また理論上は異なるデータが同じダイジェストを持つ可能性はあるものの、そのようなデータを見つけることは非常に困難なため、データの一貫性のチェックや認証、暗号化に使用されます。ダイジェスト生成のアルゴリズムとしては、MD5やSHA-1が有名です。

ダイジェストを生成する

 Javaでダイジェストを生成するには、java.security.MessageDigestを使用します。ダイジェストの生成手順は以下のとおりです。

  • 手順1:
    使用するダイジェストのアルゴリズム名を引数としてセットして、getInstanceメソッドを呼び、MessageDigest型のインスタンスを取得します。以降はこのオブジェクトに対して操作を行います。
  • 手順2:
    ダイジェストを求めたいデータをbyte[]型の引数としてセットし、引数がbyte[]型1つであるupdateメソッドを呼びます。データが大きく、一度にすべてをメモリに取り込むことが困難なときは、データを細かく分割し、分割したデータごとにbyte[]型、int型、int型の3引数を取るupdateメソッドを呼びます。第2引数と第3引数で、第1引数のどの範囲をダイジェスト計算に使用するのかを指定します。
  • 手順3:
    digestメソッドを呼び、ダイジェストをbyte[]型として取得します。

 手順1の引数としてセット可能なアルゴリズム名としては、MD5、SHA-1、SHA-256、SHA-384、SHA-512等があります。

ダイジェストの生成例

 ファイルの中身が“1234”であるファイルsecret.txtと、文字列“1234”のバイト配列から、MD5のダイジェストを生成する例を以下に示します。実行例を見ると分かるように、ダイジェストの生成元データが同じであるため、どちらの結果も同じになっています。

リスト1 Digest.java
import java.security.MessageDigest;
import java.io.FileInputStream;

public class Digest {
  public void printDigest(byte[] digest) {//ダイジェストを16進数で表示する
    for (int i = 0; i < digest.length; i++) {
      int d = digest[i];
      if (d < 0) {//byte型では128〜255が負値になっているので補正
        d += 256;
      }
      if (d < 16) {//0〜15は16進数で1けたになるので、2けたになるよう頭に0を追加
        System.out.print("0");
      }
      System.out.print(Integer.toString(d, 16));//ダイジェスト値の1バイトを16進数2けたで表示
    }
    System.out.println();
  }
  public byte[] getFileDigest(String filename) throws Exception {//ファイルの中身からダイジェストを生成する
    MessageDigest md = MessageDigest.getInstance("MD5");
    FileInputStream in = new FileInputStream(filename);
    byte[] dat = new byte[256];
    int len;
    while ((len = in.read(dat)) >=0) {
      md.update(dat, 0, len);//dat配列の先頭からlenまでのダイジェストを計算する
    }
    in.close();
    return md.digest();
  }
  public byte[] getStringDigest(String data) throws Exception {//文字列からダイジェストを生成する
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] dat = data.getBytes();
    md.update(dat);//dat配列からダイジェストを計算する
    return md.digest();
  }
  
  public static void main(String args[]) throws Exception {
    Digest d = new Digest();
    d.printDigest(d.getFileDigest("secret.txt"));
    d.printDigest(d.getStringDigest("1234"));
  }
}


リスト2  secret.txt
1234


実行結果(Windows)
81dc9bdb52d04dc20036dbd8313ed055
81dc9bdb52d04dc20036dbd8313ed055


ダイジェスト使用時の注意点

 最近、MD5や縮小版のSHA-1について衝突(異なるデータで同じダイジェストが生成される)があることが発見されました(http://japan.cnet.com/news/sec/story/0,2000050480,20070525,00.htm)。任意のデータと衝突する別データを検索するアルゴリズムについては、全検索よりも効率が良いものは現時点ではまだ発見されていません。MD5やSHA-1の安全性がすぐに脅かされるわけではありませんが、今後の動向に注意する必要があります。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。