暗号ハッシュ関数 完全ガイド:定義・代表アルゴリズムと実務での安全な実装
イントロダクション
暗号ハッシュ関数(cryptographic hash function)は、情報セキュリティや暗号化技術の基礎を成す重要なツールです。データの要約(ダイジェスト)を固定長のビット列に変換し、データ整合性の検証、電子署名、パスワード保護、ブロックチェーンの基盤など多様な用途で使われます。本コラムでは、暗号ハッシュ関数の定義と基本的性質、代表的なアルゴリズム、利用場面、攻撃手法と実装上の注意点、開発者向けのベストプラクティスまでを詳しく解説します。
暗号ハッシュ関数とは — 定義と基本特性
暗号ハッシュ関数 H は任意長の入力 M を受け取り、固定長 n ビットの出力 h = H(M) を返す一方向関数です。暗号学的に望ましい主な性質は次のとおりです:
- 完全性(完全性検査):小さな入力変化でも出力が大きく変わる(アバランチ効果)。
- 第一原像耐性(preimage resistance):与えられたハッシュ値 h から元の入力 M を見つけるのが計算上困難であること。
- 第二原像耐性(second-preimage resistance):特定の入力 M1 が与えられたとき、異なる M2(M2 ≠ M1)で H(M2) = H(M1) を見つけることが困難であること。
- 衝突耐性(collision resistance):任意の異なる二つの入力 M1 ≠ M2 を見つけて H(M1) = H(M2) とすることが困難であること。
これらは互いに関連しますが厳密には別個の性質です。出力ビット長 n によって安全性の度合いは影響を受けます。一般に、n ビット出力のハッシュ関数に対する衝突探索は誕生日攻撃により約 2^(n/2) の計算量、原像探索は約 2^n の計算量が目安です。
代表的なアルゴリズムと歴史的変遷
- MD5:1990年代に広く使われたが、2004 年頃からの衝突攻撃により暗号用途では不適格となった。
- SHA-1:米国標準(SHA)として長く使われたが、2017 年に Google/CWI による実用的な衝突("SHAttered")が示され、現在は非推奨。
- SHA-2(SHA-224/256/384/512):現代の多くのシステムで標準的に使われている。安全性は高いが内部構造(Merkle–Damgård)により長さ拡張攻撃に注意が必要。
- SHA-3 / Keccak:2015 年に標準化。スポンジ構造を採用し、SHA-2 と異なる設計原理で、長さ拡張攻撃の影響を受けにくい。
- BLAKE2 / BLAKE3:高速で安全性の高い設計。BLAKE3 は並列化と高性能を追求した新しい実装。
- パスワード専用関数(bcrypt, scrypt, Argon2):一般ハッシュ関数とは目的が異なり、計算コストとメモリコストを増やして総当たり攻撃を遅らせるために設計されている。Argon2(特に Argon2id)は現時点で推奨される選択肢。
利用用途(具体例)
- データ整合性検査:ファイルや通信内容が改変されていないかの検査(チェックサムとは区別)。
- メッセージ認証(MAC):HMAC(RFC 2104)はハッシュ関数を鍵付きで利用する安全な認証コード方式。単純な hash(secret || message) は長さ拡張攻撃に弱く推奨されない。
- 電子署名のダイジェスト:署名演算は大きなデータに対して重いので、まずハッシュしてから署名を行うのが一般的。
- パスワード保管:平文ではなく、ソルトと適切なパスワードハッシュ(Argon2 / bcrypt / scrypt)を用いる。単なる SHA-256 等は高速すぎて総当たり攻撃に脆弱。
- ブロックチェーンとマイニング:Proof-of-Work ではハッシュの計算難度を利用して計算競争を行う。トランザクション整合性には Merkle tree が使われる。
- コミットメント・ランダム化:後で値を明かすコミットメントや乱数生成の一部として使用される。
攻撃手法と実装上の落とし穴
暗号ハッシュの安全性を損なう要素はいくつかあります。
- 衝突攻撃:意図的に衝突ペアを作成してシステムを欺く攻撃。MD5・SHA-1 は実用的な衝突が示されている。
- 長さ拡張攻撃:Merkle–Damgård 構造のハッシュ(MD5/SHA-1/SHA-2 等)では、H(m) と m の長さを知らなくても H(m || pad || m2) のように拡張したハッシュが計算可能になることがある。これを使った MAC の誤用に注意。
- 総当たり(ブルートフォース)・辞書攻撃:パスワード等で入力空間が小さい場合、単純に大量計算で原像を見つけられる。これを遅らせるためにパスワード専用関数を用いる。
- 副チャネル攻撃:時間差やメモリアクセスパターンなどから情報が漏れる。比較は定数時間で行うなど注意が必要。
- ハッシュ出力の短縮や単純なトリケーション:出力を短くすると安全性が低下する。設計上必要なビット長を確保すること。
実装上のベストプラクティス
- 機能に応じて適切な関数を選ぶ:MAC には HMAC(既知の鍵付き安全方式)や authenticated encryption(AEAD)を使う。パスワード保存には Argon2/bcrypt/scrypt を選ぶ。
- 最新の標準と推奨に従う:SHA-256/512 や SHA-3、BLAKE2/3 が一般的。SHA-1/MD5 は避ける。
- ライブラリを使い、自前実装は避ける:低レベルの実装ミスや副チャネル脆弱性は見落としがち。OS/プラットフォームの信頼できる実装を利用する。
- 入力のエンコーディングを明確にする:ハッシュ対象のバイト列が何か(UTF-8, 改行など)を厳密に決める。
- 比較は定数時間で行う:ハッシュ値の等価比較にタイミング差を生じさせない。
- トークンやキーには十分なランダム性とビット長を確保する:攻撃者が簡単に予測できないように。
実務上のチェックリスト(短く実践可能)
- パスワード:Argon2id(推奨)や bcrypt を使用、ソルトを必ず付与。
- メッセージ認証:HMAC-SHA256 か、可能ならば AEAD(例:AES-GCM, ChaCha20-Poly1305)。
- データ整合性:SHA-256/512 や SHA-3 を利用。衝突耐性のレベルを評価して選ぶ。
- 暗号プロトコルでは:標準に従い、既知の安全パラメータを使用する(例:TLS, JWT ライブラリ設定等)。
- 古いハッシュ(MD5/SHA-1)に依存している場合は移行計画を立てる。
まとめ
暗号ハッシュ関数はセキュリティ設計で極めて重要ですが、用途に応じた正しい選択と実装が不可欠です。単に「ハッシュを使う」だけでは不十分で、MAC には HMAC を使う、パスワードには専用関数を使う、長さ拡張や衝突などの既知の脅威を理解して防御することが求められます。アルゴリズムの安全性は時間とともに変わるため、標準・勧告とコミュニティの最新情報を常にチェックすることが重要です。
参考文献
- FIPS PUB 180-4: Secure Hash Standard (SHA) — NIST
- FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions — NIST
- RFC 2104: HMAC — IETF
- OWASP Password Storage Cheat Sheet
- Google/CWI: SHAttered — SHA-1 collision demonstration (2017)
- Research on practical MD5 collision attacks (Wang et al., etc.)
- BLAKE2: simpler, faster, secure hashing
- Argon2 (Password Hashing Competition winner)


