不可逆ハッシュの基礎と実務ガイド:ハッシュ関数の性質・代表アルゴリズムと対策を徹底解説

不可逆ハッシュとは

「不可逆ハッシュ」(一般には「ハッシュ関数」や「ハッシュ値」)は、任意長の入力データを固定長のビット列(ハッシュ値、ダイジェスト)に写像する関数のうち、元のデータを事実上復元できない(逆算が計算上困難である)性質を持つものを指します。特に暗号学で使われる「暗号学的ハッシュ関数」は、データの整合性検査やパスワード保護、デジタル署名など多くのセキュリティ用途に不可欠です。

ハッシュ関数に期待される主要な性質

  • 決定性:同じ入力は常に同じハッシュ値を返す。
  • 固定長出力:入力長に関係なく出力長は一定(例えば SHA-256 は 256 ビット)。
  • 効率的計算:入力からハッシュ値を速く計算できる。
  • 事実上の不可逆性(Preimage Resistance):与えられたハッシュ値から元の入力(あるいは入力の一つ)を見つけることが計算上困難である(理論的に不可能とは限らないが現実的な時間で解けない)。
  • 第二原像耐性(Second-preimage Resistance):ある入力が与えられたとき、その異なる入力で同じハッシュ値を作ることが困難である。
  • 衝突耐性(Collision Resistance):任意の2つの異なる入力を見つけて同じハッシュ値にすることが困難である(任意の衝突の発見が困難)。
  • アバランチ効果:入力をわずかに変えると出力が大きく変わる(予測不能な変化を示す)。

ここで留意すべき点は「不可逆=数学的に逆関数が存在しない」わけではなく、計算上実行不可能(困難)であることを意味する点です。またハッシュ長が n ビットならば一般的に「原像探索(preimage)」には約 2^n の計算が必要と期待され、「衝突探索」は誕生日攻撃により約 2^(n/2) の計算量で見つかる可能性があります。

暗号学的ハッシュと非暗号学的ハッシュの違い

  • 暗号学的ハッシュ関数:セキュリティ特性(不可逆性、衝突耐性、第二原像耐性)を備え、メッセージ認証やデジタル署名、パスワード保護などに使われる(例:SHA-2, SHA-3, BLAKE2/3)。
  • 非暗号学的ハッシュ関数:高速なハッシュテーブルやチェックサム、データ構造(Bloomフィルタなど)に使われる。セキュリティ耐性は保証されない(例:CRC32, MurmurHash)。

代表的なアルゴリズムとその現状

  • MD5:かつて広く使われたが、衝突が実際に生成可能であり(2000年代前半から脆弱性が判明)セキュリティ用途には不適。
  • SHA-1:長年標準的に使われたが、2017年に実実装の衝突(Shattered / Google + CWI)が公開され、もはや衝突耐性を期待して使うべきではない。
  • SHA-2(SHA-224, SHA-256, SHA-384, SHA-512):現状広く使われている。出力長により理論的な安全度合いが異なる。注意点として、SHA-256等は内部構造(Merkle–Damgård系)により長さ拡張攻撃の対象となる場合がある。
  • SHA-3(Keccak):SHA-2とは別設計のフェーズシフタ構造を持ち、長さ拡張への耐性が異なる。
  • BLAKE2 / BLAKE3:高速かつ安全性の高い設計で、実務での採用が増えている。
  • パスワード用ハッシュ(鍵導出関数):PBKDF2、bcrypt、scrypt、Argon2(PHC 勝者)。これらは計算・メモリコストを意図的に上げて総当たり攻撃を難しくする。

攻撃の種類とその影響

  • 衝突攻撃:任意の2入力を見つけて同じハッシュにする。衝突が実現するとデジタル署名や整合性チェックの信頼性が損なわれる(例:偽造文書の署名)。
  • 原像攻撃(Preimage):ハッシュ値から対応する入力を見つける攻撃。パスワードリストの逆引きに相当。
  • 第二原像攻撃:既存のメッセージと同じハッシュを持つ別メッセージを見つける攻撃で、置換攻撃などに利用される。
  • 長さ拡張攻撃:Merkle–Damgård構造のハッシュ(例:MD5、SHA-1、SHA-256)では、ハッシュ(M) と M の長さが分かればハッシュ(M || padding || X) を追加計算できる場合があり、単純な H = Hash(secret || message) の設計は危険。HMAC のような構成で防ぐ。
  • レインボーテーブル・辞書攻撃:事前計算したハッシュ表を使った逆引き。ソルト(salt)で対策。
  • GPU/ASICによる総当たり:高速なハードウェアで大量試行が可能。パスワード用には計算コスト・メモリコストを増やす必要。

実務的な使い方とベストプラクティス

  • パスワード保存:決して単純なハッシュ(例:SHA-256(password))のまま保存しない。必ずユーザーごとにランダムなソルトを付け、計算コスト(反復回数)やメモリコストを調整できる専用関数を使う。現在の推奨は Argon2id(PHC 勝者)だが、bcrypt や scrypt、PBKDF2(設定に注意)も使用される。さらに「pepper」としてサーバー側で管理する固定秘密を付与する運用もある。
  • メッセージ認証:単純なハッシュは改ざん検知には不十分。共有鍵がある場合は HMAC(RFC2104)を使うと長さ拡張攻撃から守れる。
  • データ整合性・チェックサム:ファイルの整合性チェックや重複検出では高速の非暗号ハッシュが有用だが、セキュリティ(改ざん防止)目的なら SHA-2/3 等の暗号学的ハッシュを使う。
  • デジタル署名・証明:ハッシュ関数は署名前のダイジェスト計算に用いられる。衝突耐性が破られると署名システム全体が危険に晒されるため、弱いハッシュは避ける。
  • ブロックチェーン・Merkle木:トランザクションの整合性や不変性保証にハッシュが使われる。設計ミスやアルゴリズムの脆弱性はチェーン全体の信頼性に影響する。

実装上の落とし穴(現場でよく見るミス)

  • ソルトを使わない、あるいはソルトを固定・推測可能にする。
  • 単純なハッシュをパスワード保存に使う(例:SHA-256 の一回だけ)。
  • ハッシュ値を短く切り詰めて出力長を減らすことで安全性を低下させる。
  • 文字列の正規化を行わない(同じ見た目でも異なるバイト列になる可能性)。
  • 安全でない乱数生成器でソルトやキーを作る。
  • 古い・破られたアルゴリズム(MD5, SHA-1)を放置する。

よくある疑問と簡潔な答え

  • 不可逆=絶対に元に戻せないの?
    数学的に逆関数が存在しないわけではなく、「実用上(現代の計算リソースで)復元できない」ことを指す。ハッシュ長が短ければブルートフォースで復元可能。
  • 衝突が見つかると何が壊れる?
    デジタル署名、改ざん検知、認証トークンなどの信頼性が崩れる可能性がある。例として SHA-1 衝突の公開以降、多くのプロトコル・ソフトは SHA-1 からの移行を進めた。
  • パスワードにはどれを使えば良い?
    Argon2id を推奨。既存システムでは bcrypt/scrypt/PBKDF2 の適切設定でも許容されるが、反復回数・メモリ量は現状に合わせて強化すること。

まとめ

不可逆ハッシュ(暗号学的ハッシュ関数)は現代の情報セキュリティの基礎技術であり、正しく設計・運用すればデータ整合性の担保、認証や署名の基礎を提供します。しかし「不可逆」という表現を過信せず、アルゴリズムの強度、ソルト/ペッパーの利用、鍵導出関数の選定、既知の攻撃(衝突・長さ拡張・総当たり)への対策を講じることが重要です。独自実装や古いアルゴリズムの継続使用は避け、標準・コミュニティの勧告に従って更新・移行を行ってください。

参考文献