ハッシュアルゴリズム比較:MD5、SHA、Bcryptはいつ使うべき?
様々なハッシュアルゴリズムの特徴と用途を比較し、各状況に合った選択ガイドを提供します。

ハッシュ関数とは何か?
ハッシュ関数は、任意のサイズのデータを固定サイズの一意の値に変換する数学的関数です。この変換された値をハッシュ(Hash)、ダイジェスト(Digest)、またはチェックサム(Checksum)と呼びます。ハッシュ関数は現代のコンピュータセキュリティの核心要素であり、パスワードの保存からブロックチェーンまで様々な分野で活用されています。
ハッシュ関数を理解するために例えを挙げてみましょう。ハッシュ関数は肉を挽いてハンバーガーパティにするミンサーのようなものです。同じ材料を入れれば常に同じ結果が出ますが、パティから元の肉の形を復元することは不可能です。これがまさにハッシュ関数の核心特性です。
ハッシュ関数の核心属性
安全な暗号化ハッシュ関数は、次の4つの必須属性を持つ必要があります。
1. 決定論的(Deterministic)
同じ入力は常に同じ出力を生成します。この属性がなければ、ハッシュはデータ検証に使用できません。
// 常に同一の結果
MD5("Hello") === "8b1a9953c4611296a827abf8c47804d7" // true
MD5("Hello") === "8b1a9953c4611296a827abf8c47804d7" // true(常に)
2. 一方向性(One-way)
ハッシュ値から元のデータを逆算することは計算上不可能でなければなりません。この属性のおかげで、ハッシュはパスワードの保存に安全に使用できます。データベースが流出しても、ハッシュ値だけでは元のパスワードを知ることができないからです。
3. 衝突耐性(Collision Resistance)
異なる2つの入力が同じハッシュ値を生成することを衝突と呼びます。良いハッシュ関数は衝突を見つけることが極めて困難でなければなりません。MD5とSHA-1がセキュリティ目的で推奨されなくなった理由は、まさに衝突が発見されたからです。
4. 雪崩効果(Avalanche Effect)
入力がたった1ビット変更されても、出力は完全に異なる必要があります。この属性は、類似した入力からハッシュ値のパターンを推測することを防ぎます。
MD5("Hello") = "8b1a9953c4611296a827abf8c47804d7"
MD5("hello") = "5d41402abc4b2a76b9719d911017c592"
// 大文字1つの違いだが結果は完全に異なる
主要ハッシュアルゴリズムの詳細分析
MD5:なぜセキュリティ用途に使ってはいけないのか?
MD5は1991年にRonald Rivestが設計した128ビットのハッシュ関数です。かつて最も広く使用されていましたが、現在はセキュリティ目的で使用してはいけません。
入力: "Hello World"
出力: b10a8db164e0754105b7a99be72e3fe5
長さ: 128ビット (32文字 hex)
MD5の衰退: 2004年、中国のWang Xiaoyun研究チームがMD5で衝突を発見しました。その後2008年には、偽のSSL証明書を生成するためにMD5衝突が悪用されることもありました。現在では一般的なコンピュータでも数秒以内にMD5衝突を生成できます。
現在MD5を使用してもよい場合:
- ファイルダウンロードの整合性確認(セキュリティではなくエラー検出目的)
- キャッシュキーの生成
- 非セキュリティチェックサム
SHA-1:GoogleのSHAttered攻撃
SHA-1はNSAが設計し、NISTが標準化した160ビットのハッシュ関数です。MD5より安全だと考えられていましたが、2017年にGoogleとCWI Amsterdamが「SHAttered」攻撃を通じて衝突を実証しました。
この攻撃で研究者たちは、同一のSHA-1ハッシュ値を持ちながら内容が異なる2つのPDFファイルを生成しました。攻撃に使用された計算量は、6,500年相当のCPU時間と110年相当のGPU時間でした。膨大なリソースが必要でしたが、衝突が実際に可能であることが証明された瞬間、SHA-1のセキュリティ信頼性は終わりました。
現在の状態: ほとんどのブラウザと認証機関はSHA-1証明書を拒否しています。
SHA-256(SHA-2):現在の標準
SHA-2ファミリーはSHA-1の後継で、SHA-224、SHA-256、SHA-384、SHA-512など様々なバリエーションがあります。その中でSHA-256が最も広く使用されています。
入力: "Hello World"
出力: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
長さ: 256ビット (64文字 hex)
SHA-256とビットコイン: ビットコインはSHA-256をコアで使用しています。マイナーはブロックヘッダーのSHA-256ハッシュ値が特定の条件(先頭に0が多い)を満たすnonce値を見つけるために数兆回のハッシュ計算を実行します。SHA-256の予測不可能性がこのプロセスを公正にしています。
用途:
- デジタル署名(RSA、ECDSAと共に)
- SSL/TLS証明書
- ブロックチェーン
- ファイル整合性検証
SHA-3:Keccakの新しいアプローチ
SHA-3は2015年にNISTが標準化した最新のハッシュ関数です。SHA-2とは完全に異なる構造(スポンジ構造)を使用するため、万が一SHA-2で脆弱性が発見されてもSHA-3は影響を受けません。
SHA-3の設計哲学は「異なるものを作ろう」でした。SHA-2がMerkle-Damgard構造を使用するのに対し、SHA-3のKeccakアルゴリズムはスポンジ関数に基づいています。これは一種の保険です。SHA-2はまだ安全ですが、将来の攻撃に備えた代替策が準備されています。
Bcrypt:パスワード用の特殊ハッシュ
Bcryptは汎用ハッシュとは異なり、意図的に遅く設計されています。パスワードハッシュにおいて「遅さ」は利点です。攻撃者が毎秒数十億個のパスワードを試行することを防ぐからです。
// 作業係数(cost factor)12を使用
bcrypt.hash("password", 12)
// 出力例
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4.VVzfQl0Pfy6.nO
Bcryptハッシュ値の構造:
$2b$- アルゴリズムバージョン12$- 作業係数(2^12 = 4,096回の反復)- 次の22文字 - Salt(Base64エンコード)
- 残り - 実際のハッシュ値
作業係数が1増加するごとに計算時間が2倍になります。現在の推奨値は10-12です。
Argon2:最新のパスワードハッシュ
Argon2は2015年のPassword Hashing Competitionで優勝したアルゴリズムです。メモリ集約的に設計されているため、GPU並列攻撃に強いです。
パラメータ:
- メモリ:どれだけのRAMを使用するか
- 時間:どれだけ長く計算するか
- 並列性:いくつのスレッドを使用するか
Argon2idバリエーションが一般用途に推奨されます。新規プロジェクトではArgon2を使用し、レガシー互換性が必要な場合はBcryptを使用してください。
実務活用ガイド
パスワード保存:SaltとPepper
Salt: 各パスワードごとに固有のランダム値を追加します。同じパスワードでも異なるハッシュ値を生成するため、レインボーテーブル攻撃を無力化します。
// Saltの使用
password: "password123"
salt: "x7Gh9kL2"(ランダム生成)
hash: bcrypt("password123" + "x7Gh9kL2")
Pepper: Saltがデータベースにハッシュと一緒に保存されるのに対し、Pepperは別の秘密として管理されます(環境変数、ハードウェアセキュリティモジュールなど)。データベースが流出しても、Pepperなしではパスワードを検証できません。
ファイル整合性検証
ソフトウェア配布時にSHA-256チェックサムを一緒に提供すれば、ダウンロードしたファイルが改ざんされていないことを確認できます。
# ファイルハッシュ生成
sha256sum ubuntu-22.04.iso
# a1b2c3d4e5f6... ubuntu-22.04.iso
# 検証
echo "a1b2c3d4e5f6... ubuntu-22.04.iso" | sha256sum --check
用途別アルゴリズム選択ガイド
| 用途 | 推奨アルゴリズム | 非推奨 |
|---|---|---|
| パスワード保存 | Argon2id、Bcrypt、PBKDF2 | MD5、SHAファミリー(速すぎる) |
| ファイル整合性 | SHA-256、SHA-512 | MD5(衝突可能) |
| デジタル署名 | SHA-256 + RSA/ECDSA | SHA-1(衝突攻撃) |
| APIトークン | HMAC-SHA256 | - |
| キャッシュキー | MD5、SHA-1(高速) | - |
コード例
Node.js
const crypto = require('crypto');
const bcrypt = require('bcrypt');
// SHA-256
const sha256 = crypto.createHash('sha256')
.update('Hello World')
.digest('hex');
// Bcrypt
const hash = await bcrypt.hash('password', 12);
const isValid = await bcrypt.compare('password', hash);
Python
import hashlib
import bcrypt
# SHA-256
sha256 = hashlib.sha256(b'Hello World').hexdigest()
# Bcrypt
hashed = bcrypt.hashpw(b'password', bcrypt.gensalt(12))
is_valid = bcrypt.checkpw(b'password', hashed)
Toolypet Hash Tools
Toolypetのハッシュツールで様々なハッシュを素早く生成・検証できます:
- MD5/SHA Generator: テキストやファイルのハッシュ値を即座に計算
- Bcrypt Tool: パスワードハッシュの生成と検証
- Hash Comparison: 2つのハッシュ値を安全に比較(タイミング攻撃防止)
開発とテストに必要なハッシュ作業をToolypetで簡単に処理しましょう。