Javaでハッシュ値(メッセージ・ダイジェスト)の生成を行い、暗号化する(SHA1,SHA256,MD5)

暗号化のために、文字列からハッシュダイジェスト値を生成するというのをよくやります。

大きくは2つの方法があるので、両方記載しておきますね。

  • 「Apache Commons Codec」のDigestUtilsを使う方法
  • Java標準のjava.security.MessageDigestを使う方法

簡単かつ、すっきりしているのはDigestUtilsを使う方法ですが、これだけのために「Apache Commons Codec」を使うのもちょっとな・・というときもあるので。

「Apache Commons Codec」のDigestUtilsを使う方法

DigestUtilsは「Apache Commons Codec」のクラスで、SHA-1など暗号化方式に基づいた、16進数文字列を返してくれるユーティリティです。使い方はすごく簡単で、

//ハッシュアルゴリズム SHA-1
String sha1 = DigestUtils.sha1Hex( "HashValueだよ" );

のようにハッシュ化したい文字列を渡すだけ。

同様に、SHA-256やMD5も以下のようなメソッドを使えます。

//ハッシュアルゴリズム SHA-256
String sha256 = DigestUtils.sha256Hex( "HashValueだよ" );

//ハッシュアルゴリズム MD5
String md5 = DigestUtils.md5Hex( "HashValueだよ" );

Java標準のjava.security.MessageDigestを使う方法

もう一つの方法はJava標準のMessageDigestクラスを使います。

このメソッドのダイジェスト値も戻りはbyte[]型なので、16進数の文字列に変換するには、少しテクニックが必要になります。

というのも、byte値によって負値を補正したり、0埋めする必要があるためです。まとめて行うには「String.format」と、大きな数字を扱うBigIntegerクラスを使ったテクニックが使えます。

MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] result = digest.digest(value.getBytes());

String sha1 = String.format("%040x", new BigInteger(1, result));

“%040x”を使うのがミソですね。

実は、「Apache Commons Codec」の「org.apache.commons.codec.binary.Hex」クラスを使うと

String sha1 = Hex.encodeHexString(result);

のようにも書けますが、だったら、最初っから「Apache Commons Codec」使えばいいじゃん。。っていうことで。

さらに追記(Java標準でやる場合)

実は、javaの標準クラスのjavax.xml.bind.DatatypeConverterで以下のようにしてもハッシュ値を生成することはできます。

ただ、生成された値は、「57F40DEB66EAF5C887X98F992DB3EC12A37B222A」のように全部大文字になります。

小文字の方がよいという場合もあると思うので、場合によって使い分けることをお勧めします。

//ハッシュ生成処理
byte[] bytes = MessageDigest.getInstance(algorithm).digest(source.getBytes(charset));
String result = DatatypeConverter.printHexBinary(bytes);

コピペで使えるJavaソース

上記の2つの方法でハッシュ値を求めるソースを貼っておきます。

import java.math.BigInteger;
import java.security.MessageDigest;
 
import org.apache.commons.codec.digest.DigestUtils;
 
 
public class Main3 {
 
    public static void main(String[] args) {
         
        String value = "HashValueだよ";
        String sha1 = "";
         
        // Apache commons でのやり方
        sha1 = DigestUtils.sha1Hex( value );
        System.out.println( "DigestUtils" );
        System.out.println( sha1 );
         
        // java 標準 でのやり方
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            byte[] result = digest.digest(value.getBytes());
            sha1 = String.format("%040x", new BigInteger(1, result));
        } catch (Exception e){
            e.printStackTrace();
        }
         
        System.out.println( "MessageDigest" );
        System.out.println( sha1 );
         
    }
}

実行結果は、こんな感じ。どちらも同じ値が導き出されていることが分かりますね。