0Pricing
Java Academy · レッスン

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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. MessageDigestによる暗号学的ハッシュ
  2. AES共通鍵暗号
  3. メッセージ完全性のためのHMAC-SHA256
  4. JWT:構造、生成、検証
← Java Academyに戻る