【Java】文字列をハッシュ化する

# はじめに

これまでに[PowerShell](https://qiita.com/nkojima/items/1daaebdbf39871725bcc)や[ExcelVBA](https://qiita.com/nkojima/items/89d2c53d34631b33d51e)、[DOSコマンド](https://qiita.com/nkojima/items/1dc5f021c9f34fefaf77)を使ってハッシュ値を求める方法を記事としてまとめましたが、今回はJavaで文字列をハッシュ化する方法を備忘録としてまとめてみました。

# 作成したコード

* Javaでハッシュ値を求める場合、MessageDigestというクラスを使います。
* `MessageDigest.getInstance()`でMessageDigestクラスのインスタンスを作りますが、この際にハッシュアルゴリズムの指定を誤ると`NoSuchAlgorithmException`、ハッシュアルゴリズムがnullだと`NullPointerException`が発生します。
  * ハッシュアルゴリズムの書き間違いで`NoSuchAlgorithmException`が発生しないように、ここではenumの`HashAlgorithm`を使ってハッシュアルゴリズムを指定しています。
* `MessageDigest#digest(byte[])`でハッシュ値を計算するためのバイト列の指定をして、ハッシュ計算を完了させます。
  * バイト列が複数ある時は、`MessageDigest#update(byte[])`を複数回呼び出した後に`MessageDigest#digest()`でハッシュ計算を完了させるようです。（※この点については試していないので不確かですが...）

```java:TextEncoder.java
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class TextEncoder {

	/**
	 * ハッシュアルゴリズムの種類
	 * https://docs.oracle.com/javase/jp/8/docs/technotes/guides/security/StandardNames.html#MessageDigest
	 * @author NKOJIMA
	 */
	private enum HashAlgorithm {
		MD5,
		SHA1,
		SHA256,
		SHA512
	}

	public static void main(String[] args) {
		String text = "qwerty2024";

		System.out.println("MD5: " + toHash(text, HashAlgorithm.MD5));
		System.out.println("SHA-1: " + toHash(text, HashAlgorithm.SHA1));
		System.out.println("SHA-256: " + toHash(text, HashAlgorithm.SHA256));
		System.out.println("SHA-512: " + toHash(text, HashAlgorithm.SHA512));
	}

	/**
	 * 文字列を指定した暗号化アルゴリズムでハッシュ化する。
	 * @param text 暗号化する文字列
	 * @param algorithm 暗号化アルゴリズム
	 * @return ハッシュ化された文字列。
	 */
	private static String toHash(String text, HashAlgorithm algorithm) {
		String hashAlgorithm = "";
		if (algorithm==HashAlgorithm.MD5) {
			hashAlgorithm = "MD5";
		} else if (algorithm==HashAlgorithm.SHA1) {
			hashAlgorithm = "SHA-1";
		} else if (algorithm==HashAlgorithm.SHA256) {
			hashAlgorithm = "SHA-256";
		} else {
			hashAlgorithm = "SHA-512";
		}

		StringBuffer sb = new StringBuffer();
		try {
			MessageDigest md = MessageDigest.getInstance(hashAlgorithm);
			byte[] cipherBytes = md.digest(text.getBytes());

			for (int i=0; i<cipherBytes.length; i++) {
				sb.append(String.format("%02x", cipherBytes[i]&0xff));
			}
		} catch (NoSuchAlgorithmException ex1) {
			System.out.println("ハッシュアルゴリズム名が不正です。");
		} catch (NullPointerException ex2) {
			System.out.println("ハッシュアルゴリズム名が指定されていません。");
		}

		return sb.toString();
	}
}
```

```text:実行結果
MD5: ba90bf4e632e2c47969a737c7f10e8ed
SHA-1: d0219b87cc88f83402a9a028cbe234e2c377a591
SHA-256: 27ee1080a481ba14a90066fcd22e1ef654539d94ff0b768905b9313abd6313bc
SHA-512: c3766c875ce0f0448fb93d24ff9d6d01e7d4dabda7f3713fd2b79c6a54cd18558151aaeb76132feb15fd1203914d1a39a5bcef6c8e16f776ca28de0aff70abcf
```


# 補足

* 上記のプログラムの結果は、Rubyの[Digestクラス](https://www.kkaneko.jp/pro/ruby/sha.html)を使って結果を検証しています。


# 参考URL

* [MessageDigestクラス (Java Platform SE 8 ) - Oracle Help Center](https://docs.oracle.com/javase/jp/8/docs/api/java/security/MessageDigest.html)
* [MessageDigestアルゴリズム - Java暗号化アーキテクチャ 標準アルゴリズム名のドキュメント(JDK 8用)](https://docs.oracle.com/javase/jp/8/docs/technotes/guides/security/StandardNames.html#MessageDigest)
* [JavaでSHA256を計算する](https://kaworu.jpn.org/java/Java%E3%81%A7SHA256%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B)
* [【PowerShell】ファイルのハッシュ値を求める](https://qiita.com/nkojima/items/1daaebdbf39871725bcc)
* [【ExcelVBA】ハッシュ値を取得する関数を自作してみた](https://qiita.com/nkojima/items/89d2c53d34631b33d51e)
* [certutilコマンドの出力結果の違い（Win8.1～/ Win11）](https://qiita.com/nkojima/items/1dc5f021c9f34fefaf77)
* [Ruby で文字列のハッシュ値を得る](https://www.kkaneko.jp/pro/ruby/sha.html)