MessageDigestによる暗号学的ハッシュ
SHA-256でパスワードをハッシュ化し、ソルトを加えてレインボーテーブル攻撃を防ぎ、安全にダイジェストを比較します。
「MessageDigestによる暗号学的ハッシュ」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
暗号学的ハッシュとは
暗号学的ハッシュ関数は、任意のサイズのデータを固定サイズのダイジェストに変換します。一方向性(逆算できない)、決定性、衝突耐性を備えています。パスワードの保存、データの完全性検証、デジタル署名に使用されます。
MessageDigest API
MessageDigest.getInstance("SHA-256") は SHA-256 のダイジェスト計算器を返します。digest(bytes) を呼び出すとハッシュを計算し、バイト配列を取得できます。
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password123".getBytes(StandardCharsets.UTF_8));
String hex = HexFormat.of().formatHex(hash);
System.out.println(hex); // 64-char hex string一般的なアルゴリズム
JDK は次のアルゴリズムをサポートしています。MD5(破られているため、セキュリティ用途では決して使用しないでください)、SHA-1(セキュリティ用途では非推奨)、SHA-256(標準)、SHA-512(より強力)、SHA3-256(最新)。新しいコードでは、必ず SHA-256 または SHA-512 を使用してください。
MessageDigest.getInstance("SHA-256"); // recommended
MessageDigest.getInstance("SHA-512"); // stronger
MessageDigest.getInstance("SHA3-256"); // SHA-3 family
// Never: MessageDigest.getInstance("MD5"); // cryptographically brokenハッシュを 16 進数文字列に変換する
保存や比較を行うには、バイト配列の結果を 16 進数文字列に変換する必要があります。HexFormat(Java 17 以降)または古いバージョンでは String.format を使用します。
// Java 17+:
String hex = HexFormat.of().formatHex(hash);
// Older Java:
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
String hex = sb.toString();ソルト: レインボーテーブルへの対策
レインボーテーブルは、一般的なパスワードとそのハッシュの対応表です。ソルトを使用すると、ハッシュ化する前に各パスワードへランダムな値が追加されるため、レインボーテーブルが役に立たなくなります。ソルトはハッシュと一緒に保存します。
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] hash = md.digest("password".getBytes(StandardCharsets.UTF_8));
// Store: Base64.encode(salt) + ":" + Base64.encode(hash)パスワードのハッシュ化 — 代わりに BCrypt を使用
ソルト付き SHA-256 は単純な SHA-256 より優れていますが、それでも処理が高速です。攻撃者は 1 秒あたり数十億回の推測を試せます。パスワードには低速な KDF を使用します。BCryptPasswordEncoder(Spring Security)、または PBKDF2、Argon2 を使用してください。
// Spring Security — proper password hashing:
PasswordEncoder encoder = new BCryptPasswordEncoder(12); // cost factor 12
String hash = encoder.encode("password123");
boolean match = encoder.matches("password123", hash); // trueファイルの完全性チェック
ファイルをハッシュ化して、破損や改ざんを検出します。計算したハッシュを、正常なファイルから得た既知の値と比較します。
MessageDigest md = MessageDigest.getInstance("SHA-256");
try (InputStream is = Files.newInputStream(Path.of("app.jar"))) {
byte[] buf = new byte[8192];
int n;
while ((n = is.read(buf)) > 0) md.update(buf, 0, n);
}
String hash = HexFormat.of().formatHex(md.digest());
System.out.println("SHA-256: " + hash);ハッシュを安全に比較する
タイミング攻撃を防ぐため、一定時間で比較する MessageDigest.isEqual() を使用します。ハッシュの比較に String.equals() を決して使用しないでください。
byte[] expected = computeHash(storedHash);
byte[] actual = computeHash(inputPassword);
boolean match = MessageDigest.isEqual(expected, actual); // constant-time更新を連結する
分割して到着するデータ(ストリーミング)をハッシュ化するには、md.digest() の前に md.update(bytes) を複数回呼び出します。
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update("part1".getBytes());
md.update("part2".getBytes());
byte[] hash = md.digest(); // hash of "part1" + "part2"保存用のハッシュエンコーディング
バイナリ形式のハッシュは、Base64(16 進数より短い)または 16 進数文字列として保存します。Base64 では SHA-256 に 43 文字を使用するのに対し、16 進数では 64 文字を使用します。どちらも正しいため、一貫して使用してください。
byte[] hash = md.digest(data);
String base64 = Base64.getEncoder().encodeToString(hash); // 44 chars (with padding)
String hex = HexFormat.of().formatHex(hash); // 64 charsストリーミング用の DigestInputStream
InputStream を DigestInputStream でラップすると、読み取りながらハッシュを計算できます。ファイル全体をメモリに読み込む必要がありません。
MessageDigest md = MessageDigest.getInstance("SHA-256");
try (DigestInputStream dis = new DigestInputStream(Files.newInputStream(path), md)) {
dis.transferTo(OutputStream.nullOutputStream());
}
String hash = HexFormat.of().formatHex(md.digest());確認問題
ソルト付き SHA-256 が、パスワードの保存にまだ推奨されないのはなぜですか。
まとめ
データの完全性を確認するには MessageDigest.getInstance("SHA-256") を使用します。パスワードには必ずソルトを付けます。ただし、パスワードの保存には生の SHA ではなく BCrypt または Argon2 を使用してください。タイミング攻撃を防ぐため、一定時間の比較(MessageDigest.isEqual)を使用します。
よくある質問
「MessageDigestによる暗号学的ハッシュ」レッスンは無料ですか?
はい。「MessageDigestによる暗号学的ハッシュ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「MessageDigestによる暗号学的ハッシュ」で何を学びますか?
SHA-256でパスワードをハッシュ化し、ソルトを加えてレインボーテーブル攻撃を防ぎ、安全にダイジェストを比較します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「MessageDigestによる暗号学的ハッシュ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- MessageDigestによる暗号学的ハッシュ
- AES共通鍵暗号
- メッセージ完全性のためのHMAC-SHA256
- JWT:構造、生成、検証