ハッシュ関数の基礎

更新日:

ハッシュ関数は現代のコンピューティングの基礎であり、ファイル整合性検証・電子署名・パスワード保存など、あらゆる場面で利用されます。しかし同時に誤解も多く、SHA-256 が必要なのに MD5 を使う、パスワードに高速ハッシュを使う、ハッシュを「復号」できると思っている、といった誤りが頻発します。本ガイドでは、ハッシュ関数の基礎、SHA-256 と SHA-1 の違い、MD5 が安全でなくなった理由、そしてパスワードハッシュの特別なルールを整理します。

ハッシュ関数とは

暗号学的ハッシュ関数は、任意サイズの入力から固定長の出力(ダイジェスト、ハッシュ値)を生成します。同じ入力からは常に同じ出力が得られますが、出力からは入力に関する情報を取り出せません。優れた暗号学的ハッシュは 3 つの主要な性質を持ちます: 原像計算困難性(ハッシュ値から入力を求められない)、第二原像計算困難性(既知入力と同じハッシュ値を持つ別の入力を求められない)、衝突困難性(同じハッシュ値を持つ任意の 2 入力を求められない)。

ハッシュの主な用途

  • ファイル整合性検証 — 公開されているチェックサムとダウンロードファイルの照合。
  • 電子署名 — 文書自体ではなくハッシュに署名する(署名処理が遅いため)。
  • 重複排除 — ハッシュをコンテンツアドレスとして使う(Git のオブジェクトストアなど)。
  • キャッシュ — リクエストのハッシュをキャッシュキーにする。
  • パスワード保存 — ただし Argon2 や bcrypt などパスワード専用のハッシュを使う(後述)。
  • Proof-of-Work・ブロックチェーン — 特定の出力性質を持つ入力を見つけることの困難性を利用する。

SHA-256

SHA-256 は 256 ビット(32 バイト、16 進数で 64 文字)のダイジェストを生成します。NSA が設計し NIST が標準化した SHA-2 ファミリの一員です。現時点で実用的な攻撃手法は知られておらず、衝突を見つけることは計算量的に不可能です。新規アプリケーションで高速な暗号学的ハッシュが必要な場合の第一選択であり、TLS 証明書・Git(新しい版)・Bitcoin・ほとんどのファイル整合性ワークフローで使われています。

SHA-1

SHA-1 は 160 ビット(20 バイト、16 進数で 40 文字)のダイジェストを生成します。2000 年代には広く使われていましたが、2017 年に実用的な衝突攻撃「SHAttered」が実証されました。衝突耐性を必要とする新規アプリケーションには SHA-1 を使うべきではありません。電子署名・証明書・攻撃者がファイルを供給できる「同じファイルか?」のチェックなどが該当します。攻撃者の関与しない単なる整合性チェック(Git の従来のオブジェクト ID など)であれば許容範囲です。

MD5

MD5 は 128 ビット(16 バイト、16 進数で 32 文字)のダイジェストを生成します。高速で広く普及していますが、完全に破られています。市販のハードウェアで数秒以内に衝突を作れます。セキュリティ用途には絶対に使ってはいけません。信頼できる社内ネットワーク内での転送破損チェックなど、非セキュリティ用途のフィンガープリントとしてのみ使えます。

ハッシュは暗号化ではない

ハッシュ関数は一方向です。値をハッシュ化したら、ハッシュから元の値を復元することはできません。これはパスワード保存や整合性検証に有用な性質ですが、同時に「SHA-256 を復号する」ことは不可能だという意味でもあります。「MD5 や SHA-256 を復号する」と謳うコードを見たら、それは短い入力や典型パスワードに対する事前計算テーブル(レインボーテーブル)を引いているか、嘘をついているかのどちらかです。

パスワードハッシュは別物

SHA-256 のような汎用ハッシュは「速い」ことを目指して設計されています。この速さはパスワードにとってはセキュリティ上の弱点になります。ハッシュ DB が漏洩した場合、攻撃者は GPU 1 枚で 1 秒間に数十億のパスワード候補を試せるためです。パスワードハッシュ関数は意図的に遅く、メモリも消費するように設計されています。Argon2id(現在のベストプラクティス)、bcrypt(依然として広く受け入れられている)、scrypt のいずれかを使ってください。SHA-256・SHA-1・MD5 にソルトを足しただけでパスワードを保存してはいけません。ソルトはレインボーテーブルを防ぐだけで、総当たりを遅くしません。

ソルトとペッパー

ソルトはハッシュ化前にパスワードに混ぜる、ユーザーごとに異なるランダムな値です。ソルトはハッシュとともに保存します。これにより、攻撃者が一般的なパスワードのハッシュを事前計算しても、複数ユーザーぶんを一括で照合できなくなります。ペッパーはすべてのパスワードに加える単一の秘密値で、データベースとは別の場所(HSM や環境変数)に保管します。ソルトとペッパーを組み合わせると、オフライン攻撃のコストが大幅に増大します。

用途に合わせたハッシュ選択

  • ファイル整合性・証明書・コンテンツアドレス指定: SHA-256(速度重視で利用可能なら BLAKE3 も検討可)。
  • 非セキュリティのフィンガープリント・レガシー互換: SHA-1 または MD5 も許容(選択理由を文書化)。
  • パスワード保存: Argon2id、bcrypt、scrypt のいずれか。汎用ハッシュは絶対不可。
  • メッセージ認証: HMAC-SHA-256(SHA-256 単体ではない)。

よくある質問

異なる 2 つのファイルが同じ SHA-256 になることはありますか?
理論上はあります(出力空間が有限のため)。実用上は、現在の技術で偶然に衝突を見つけるには宇宙の年齢より長い時間が必要なため、起こりません。SHA-256 は当面のあいだ衝突耐性が保たれると考えられています。
MD5 は非セキュリティ用途では今でも安全ですか?
偶発的な整合性チェック(信頼できるネットワーク内のファイルコピー)であれば許容範囲です。ただし攻撃者がファイルを供給できる場合は、衝突を容易に作成できるため不可です。
bcrypt が SHA-256 より遅いのはなぜですか?
意図的にそう設計されています。bcrypt は「ワークファクター」と呼ばれる調整可能な反復回数を持ち、その遅さがパスワードを守ります。標準的な設定では 1 ハッシュあたり約 100 ms 程度かかり、ユーザー体験には影響しませんが、総当たり攻撃のスループットは SHA-256 に比べて約 6 桁低下します。
SHA-256 を解読するのにどれくらいかかりますか?
解読が「ハッシュから入力を求める」ことを指し、入力が十分長くランダムであれば、現実的には不可能です。一般的なパスワードでソルトもなければ、事前計算済みのレインボーテーブルで瞬時に答えが返ります。だからこそパスワードは Argon2 / bcrypt / scrypt にソルトを加える必要があり、生の SHA-256 では駄目なのです。

まとめ

ハッシュ関数は使い分けが重要です。汎用の整合性には SHA-256、パスワードには Argon2id(または bcrypt)、認証メッセージには HMAC、敵対的文脈では MD5 と SHA-1 を避けてください。本サイトのハッシュジェネレーターは SHA-256 / SHA-1 をブラウザ内だけで計算し、入力データは端末から外部へ送信されません。

関連ツール