ハッシュアルゴリズム比較:MD5 / SHA-1 / SHA-256 / SHA-3 / BLAKE3
「MD5でいいでしょ」がなぜ危険か
2012年、Flameというマルウェアが MD5 の衝突を利用して Microsoft の正規コード署名証明書を偽造し、Windows Update 経由で配布されました。MD5 の衝突攻撃が理論から実害に移った事件として記録されています。
SHA-1 についても 2017 年に Google が SHAttered 攻撃を実証。同一の SHA-1 ハッシュを持つ 2 つの異なる PDF ファイルを公開し、衝突を現実のものとしました(計算コスト:約 110 GPU 年)。
現在、MD5 と SHA-1 はセキュリティ用途では使用禁止です。しかし「どれを代替として選ぶか」については、用途によって答えが変わります。
ハッシュ関数の基本:何を保証するか
暗号学的ハッシュ関数は、任意長の入力から固定長の出力(ダイジェスト)を生成します。安全なハッシュ関数には 3 つの性質が求められます。
| 性質 | 説明 |
|---|---|
| 一方向性 | ダイジェストから元の入力を復元できない |
| 第二原像困難性 | 同じハッシュを持つ別の入力を見つけられない |
| 衝突困難性 | 同じハッシュを持つ任意の 2 入力を見つけられない |
「衝突困難性」は最も強い要件です。MD5 と SHA-1 はこれを満たせなくなりました。
MD5 ── 1991 年生まれ、現役引退
仕様
MD5(Message Digest Algorithm 5)は Ron Rivest が 1991 年に設計し、RFC 1321 で定義されました。128 ビットのダイジェストを生成します。
Merkle–Damgård 構造(入力をブロックに分割して反復処理)を採用しており、この設計が後の攻撃に利用されました。
衝突攻撃の歴史
- 2004 年: Xiaoyun Wang らが MD5 の衝突を発見
- 2008 年: Sotirov らが MD5 衝突を利用して偽の CA 証明書を作成
- 2012 年: Flame マルウェアが MD5 衝突を悪用(冒頭で述べた事件)
import hashlib
# MD5 - チェックサム用途のみ許容
md5 = hashlib.md5(b"Hello, World!").hexdigest()
print(md5) # "65a8e27d8879283831b664bd8b7f0ad4"
# セキュリティ用途では絶対に使わない
現在許容される用途
MD5 の使用が許容されるのは、セキュリティが不要なチェックサム用途のみです。
- ファイルの整合性確認(ダウンロードエラーの検出)
- キャッシュのキー生成
- 非暗号学的な重複チェック
SHA-1 ── 20 年間の主役、2017 年に引退
仕様
SHA-1(Secure Hash Algorithm 1)は NIST FIPS 180-4 の一部として定義されています。160 ビットのダイジェストを生成し、1993 年〜2005 年頃まで事実上の標準でした。
SHAttered 攻撃(2017 年)
Google Research と CWI Amsterdam のチームが 2017 年 2 月に公表した SHAttered 攻撃は、SHA-1 の衝突を初めて実証しました。
- コスト: 約 110 GPU 年の計算
- 証拠: 同一 SHA-1 ハッシュを持つ 2 つの異なる PDF を公開
- 影響: Git リポジトリのオブジェクト識別に SHA-1 を使っているという懸念が高まる
Git は内部で SHA-1 を使っていましたが、この発表を受けて SHA-256 への移行(git hash-object --format sha256)が進んでいます。
# Git でのリポジトリハッシュの確認
git cat-file -t HEAD
git log --oneline --abbrev-commit
現在の状況
NIST は 2011 年に SHA-1 の非推奨を発表し、2030 年以降の TLS 証明書への使用を禁止しています。主要ブラウザはすでに SHA-1 署名証明書を拒否します。
SHA-256 ── 現在のデファクトスタンダード
仕様
SHA-256 は NIST FIPS 180-4(Secure Hash Standard)で定義されています。SHA-2 ファミリー(SHA-224、SHA-256、SHA-384、SHA-512)の一つで、256 ビットのダイジェストを生成します。
MD5・SHA-1 と同じ Merkle–Damgård 構造を使いますが、より大きなブロックサイズ(512 ビット)と多数のラウンド処理(64 ラウンド)により、現在の計算能力では衝突を見つけることが現実的に不可能です。
// Node.js での SHA-256
const { createHash } = require('crypto');
const hash = createHash('sha256')
.update('Hello, World!')
.digest('hex');
console.log(hash);
// "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986d"
// ファイルのハッシュ(ストリーミング)
const fs = require('fs');
function hashFile(path) {
return new Promise((resolve, reject) => {
const hash = createHash('sha256');
const stream = fs.createReadStream(path);
stream.on('data', chunk => hash.update(chunk));
stream.on('end', () => resolve(hash.digest('hex')));
stream.on('error', reject);
});
}
主な用途
- TLS/SSL 証明書の署名
- コード署名(アプリケーション配布)
- ブロックチェーン(Bitcoin は SHA-256d = SHA-256(SHA-256(x)) を使用)
- HMAC-SHA256(API 認証の署名)
- パスワードハッシュの下地(後述)
SHA-3 ── まったく異なる設計のバックアップ
設計思想:スポンジ構造
SHA-3 は NIST FIPS 202(2015 年)で標準化されました。SHA-2 の代替として公募されたコンテスト(2007〜2012 年)で選ばれた Keccak アルゴリズムが採用されています。
SHA-2 とは根本的に異なる**スポンジ構造(Sponge Construction)**を採用しています。
吸収フェーズ: 入力データを内部状態に「吸収」
搾り出しフェーズ: 内部状態からダイジェストを「搾り出す」
スポンジ構造が SHA-2 と本質的に異なる点は、Merkle–Damgård 構造の弱点(長さ拡張攻撃)を根本的に排除していることです。
import hashlib
# SHA-3 (Keccak)
sha3_256 = hashlib.sha3_256(b"Hello, World!").hexdigest()
sha3_512 = hashlib.sha3_512(b"Hello, World!").hexdigest()
# SHAKE(可変長出力)
shake = hashlib.shake_256(b"Hello, World!").hexdigest(32) # 32バイト出力
SHA-2 と SHA-3 の位置づけ
SHA-3 は SHA-2 を「置き換える」ものではなく、**「バックアップ」**です。SHA-2 に致命的な脆弱性が発見された場合に切り替えられるよう、まったく異なる設計で標準化されました。
| 特性 | SHA-256 | SHA-3-256 |
|---|---|---|
| ダイジェスト長 | 256 ビット | 256 ビット |
| 構造 | Merkle–Damgård | スポンジ |
| ハードウェア最適化 | 広く普及 | 普及中 |
| パフォーマンス(ソフトウェア) | 速い | SHA-256 と同程度 |
| 長さ拡張攻撃 | 脆弱(HMAC で回避) | 免疫 |
BLAKE3 ── 速度と安全性の新世代
仕様
BLAKE3 は 2020 年に公開されたハッシュアルゴリズムです(公式仕様書)。BLAKE2 の後継であり、SHA-3 コンテストの入賞者 BLAKE を前身とします。
圧倒的な速度
BLAKE3 の最大の特徴は並列処理です。内部で Merkle-tree 構造を使い、SIMD 命令や複数スレッドを活用できます。
ベンチマーク(参考値、x86-64 環境):
BLAKE3: 2,000+ MB/s
SHA-256: 500–1,000 MB/s(AES-NI 拡張なし)
SHA-3: 500–800 MB/s
MD5: 800–1,200 MB/s(速いが安全でない)
// Rust での BLAKE3
use blake3;
let hash = blake3::hash(b"Hello, World!");
println!("{}", hash.to_hex());
// 大きなデータのストリーミング
let mut hasher = blake3::Hasher::new();
hasher.update(b"Hello, ");
hasher.update(b"World!");
let hash = hasher.finalize();
// JavaScript/Node.js: blake3 パッケージ
const blake3 = require('blake3');
const hash = blake3.hash('Hello, World!');
console.log(hash.toString('hex'));
NIST 標準化の状況
BLAKE3 は 2026 年 4 月時点では NIST の公式標準ではありません。NIST は 2023 年に BLAKE3 の NIST 標準化に向けたプロセスを開始しておらず、BLAKE2b が NIST SP 800-107 で言及されている程度です。規制要件や政府システムで NIST 標準が必要な場合、BLAKE3 は現時点では選択できません。
各アルゴリズムの総合比較
| アルゴリズム | ダイジェスト長 | 速度(参考) | セキュリティ | NIST標準 | 用途 |
|---|---|---|---|---|---|
| MD5 | 128 ビット | 速い | ❌ 破られた | 非推奨 | チェックサムのみ |
| SHA-1 | 160 ビット | 速い | ❌ 衝突実証済 | 非推奨 | 禁止 |
| SHA-256 | 256 ビット | 中程度 | ✓ 安全 | FIPS 180-4 | 汎用 |
| SHA-512 | 512 ビット | 中程度 | ✓ 安全 | FIPS 180-4 | 高セキュリティ |
| SHA-3-256 | 256 ビット | 中程度 | ✓ 安全 | FIPS 202 | バックアップ |
| BLAKE3 | 256 ビット+ | 非常に速い | ✓ 安全 | なし(2026年時点) | 高速チェックサム |
チェックサム vs セキュリティ:用途別選択
チェックサム用途(ファイル整合性確認)
セキュリティ攻撃者が介在しない場合、MD5 や SHA-1 でも整合性確認には機能します。ただし、ダウンロードサイトが提供するチェックサムは攻撃者に書き換えられる可能性があるため、実際には SHA-256 を使うのがベストプラクティスです。
# ファイルのSHA-256チェックサム確認
sha256sum ubuntu-22.04-desktop-amd64.iso
# または
shasum -a 256 ubuntu-22.04-desktop-amd64.iso
# macOS
shasum -a 256 file.iso
# Windows (PowerShell)
Get-FileHash file.iso -Algorithm SHA256
ファイルハッシュチェッカーを使えば、ブラウザ上でファイルのハッシュを確認できます。
デジタル署名・証明書
SHA-256(またはSHA-384/SHA-512) 一択です。TLS 1.3 の仕様(RFC 8446)では SHA-256 が必須アルゴリズムに含まれています。
HMAC(メッセージ認証コード)
HMAC-SHA256 が標準的な選択です。HMAC は SHA-256 の長さ拡張攻撃の問題を回避します。
import hmac
import hashlib
key = b'secret-key'
message = b'data to authenticate'
mac = hmac.new(key, message, hashlib.sha256).hexdigest()
print(mac) # HMAC-SHA256
# 定時間比較(タイミング攻撃対策)
def verify_mac(mac1, mac2):
return hmac.compare_digest(mac1, mac2)
パスワードハッシュ
SHA-256 や BLAKE3 をパスワードの直接ハッシュに使ってはいけません。これらは高速すぎるため、ブルートフォース攻撃に弱いです。
パスワードハッシュには、意図的に遅くコストを調整できるアルゴリズムを使います:
| アルゴリズム | 推奨度 | 特徴 |
|---|---|---|
| Argon2id | 最推奨 | 2015 Password Hashing Competition 優勝。メモリ・時間・並列度を調整可能 |
| bcrypt | 推奨 | 1999 年から広く使われ、成熟している |
| scrypt | 推奨 | メモリハード。bcrypt よりも大きなメモリを要求 |
| PBKDF2 | 許容 | NIST 推奨だが他より弱い。FIPS コンプライアンスが必要な場合 |
# Python での Argon2id
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=3, # 反復回数
memory_cost=65536, # 64 MB
parallelism=2 # 並列スレッド数
)
# ハッシュ生成
hash = ph.hash("user-password")
# 検証
try:
ph.verify(hash, "user-password") # 一致すれば True
except Exception:
pass # パスワード不一致
ハッシュの生成やフォーマットの確認には ハッシュジェネレーター を活用できます。
まとめ
| 用途 | 推奨アルゴリズム |
|---|---|
| 汎用デジタル署名 / TLS | SHA-256 |
| HMAC(API認証) | HMAC-SHA256 |
| パスワードハッシュ | Argon2id |
| 高速チェックサム(非規制用途) | BLAKE3 |
| NIST規制環境のバックアップ用 | SHA-3-256 |
| 非セキュリティのファイルチェックサム | SHA-256(MD5/SHA-1 は非推奨) |
MD5 と SHA-1 は歴史的な産物として残っていますが、新規開発でセキュリティ用途に使う理由はありません。SHA-256 が汎用の選択、パスワードには Argon2id というのが、2026 年時点での実務標準です。
参考文献
- NIST FIPS 180-4 — Secure Hash Standard (SHS) — SHA-256, SHA-512 など
- NIST FIPS 202 — SHA-3 Standard — Keccak ベース
- RFC 1321 — The MD5 Message-Digest Algorithm
- SHAttered — SHA-1 衝突攻撃の実証 — Stevens et al., 2017
- BLAKE3 仕様書 — O'Connor et al., 2020
- RFC 9106 — Argon2 Memory-Hard Function
