PBKDF2とは
PBKDF2(Password-Based Key Derivation Function 2)は、人間が記憶できる程度の低エントロピーな「パスワード」を、暗号アルゴリズムがそのまま使える固定長の「鍵」に変換するための鍵導出関数(KDF)です。単純にパスワードをハッシュ化するのではなく、ソルトを加えたうえでハッシュ処理を数十万回以上繰り返すことで、攻撃者が総当たり(ブルートフォース)攻撃を行う際の計算コストを意図的に引き上げている点が最大の特徴です。
由来をたどると、PBKDF2はRSA Laboratoriesが1999年〜2000年頃に策定したPKCS #5 v2.0(RFC 2898、2000年発行)で初めて標準化されました。その後2017年にIETFから発行されたRFC 8018(PKCS #5 v2.1)が現行の標準仕様であり、本記事でもRFC 8018を基準に解説します。あわせて、PBKDF2で導出した鍵を使ってメッセージを暗号化する際のデータ構造はPKCS #5 / PKCS #12(証明書と秘密鍵をまとめて格納する.p12/.pfxファイル形式)でも規定されています。
実装面では標準ライブラリに組み込まれていることが多く、追加の暗号ライブラリを導入せずに利用できる手軽さから、次のような場面で広く採用されています。
- Wi-Fi(WPA2/WPA3-Personal):事前共有鍵(パスフレーズ)からペアワイズマスターキーを導出
- ディスク/ファイル暗号化:LUKS1(Linuxのディスク暗号化)、macOS FileVault、7-Zipのアーカイブ暗号化
- 証明書・鍵ストア:PKCS#12形式の秘密鍵ファイル、Javaのkeystore(JKS/PKCS12)
- Webアプリのパスワード保存:Django(PBKDF2PasswordHasherが既定)、Ruby on RailsのActive Model Secure Password(bcryptが既定だが設定変更でPBKDF2も利用可)
- パスワードマネージャー:一部の実装でマスターパスワードから暗号鍵を導出する際に使用(新しいバージョンではArgon2idへの移行が進む)
PBKDF2の基本的な動作は以下の通りです:
DK = PBKDF2(PRF, Password, Salt, c, dkLen)
PRF: 疑似乱数関数(通常はHMAC-SHA256)
Password: 入力パスワード
Salt: ランダムなソルト値
c: イテレーション回数
dkLen: 出力する鍵の長さ
PBKDF2の仕組み
PBKDF2は、ハッシュ関数(HMACベース)を指定回数繰り返し適用することで、計算コストを高めています。これにより、ブルートフォース攻撃に対する耐性を確保します。
import hashlib
import os
def pbkdf2_example():
password = b"my_secure_password"
salt = os.urandom(16) # 16バイトのランダムソルト
iterations = 600000 # OWASP推奨(SHA-256使用時)
# PBKDF2でAES-256鍵を導出
key = hashlib.pbkdf2_hmac(
'sha256',
password,
salt,
iterations,
dklen=32 # 256ビット
)
return key, salt
# cryptographyライブラリを使用した例
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
def derive_key_with_cryptography(password: bytes, salt: bytes) -> bytes:
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=600000
)
return kdf.derive(password)
内部構造:DK = T1 || T2 || ... というブロック結合
PBKDF2は、要求された鍵長(dkLen)を疑似乱数関数(PRF、通常HMAC-SHA256やHMAC-SHA512)の出力長(hLen)ごとのブロックに分割し、それぞれを独立に計算してから連結するという構造を取ります。RFC 8018の定義を文章で追うと次のようになります。
DK = T1 || T2 || ... || T_l (l = ceil(dkLen / hLen)、最後のブロックは必要な長さだけ切り出す)
各ブロック Ti は以下のように計算する:
Ti = F(Password, Salt, c, i)
F(Password, Salt, c, i) = U1 XOR U2 XOR ... XOR Uc
U1 = PRF(Password, Salt || INT_32_BE(i)) ← ソルトにブロック番号iを4バイトのビッグエンディアンで付加
U2 = PRF(Password, U1)
U3 = PRF(Password, U2)
…
Uc = PRF(Password, Uc-1)
つまり、1回目の計算(U1)だけソルトとブロック番号を使い、2回目以降(U2〜Uc)は「直前の出力」をそのまま次の入力にして同じ演算を繰り返し、最終的にU1〜Ucを排他的論理和(XOR)でまとめたものが1ブロック分の出力Tiです。イテレーション回数cを増やすほど、この繰り返し計算(=HMAC呼び出し)の回数が線形に増え、攻撃者が1回のパスワード推測を試すのに必要な計算量も比例して増加します。HMAC-SHA256を1回呼び出す内部ではSHA-256の圧縮関数がおよそ2回動くため、c=600,000であれば1回のパスワード検証だけで約120万回のSHA-256圧縮関数の実行が必要になる計算です。
ソルト長・鍵長の推奨値(NIST SP 800-132 / OWASP 2024)
PBKDF2を安全に使うためのパラメータには、イテレーション回数以外にもソルト長と出力鍵長があります。米国NISTのSP 800-132(Recommendation for Password-Based Key Derivation)は次のような指針を示しています。
| パラメータ | 推奨値・考え方 |
|---|---|
| ソルト長 | 128ビット(16バイト)以上をCSPRNG(暗号学的に安全な乱数生成器)で生成し、ユーザー・レコードごとに一意にする。使い回しはレインボーテーブル攻撃を招く |
| 出力鍵長(dkLen) | 用途に合わせる(AES-256鍵なら32バイト=256ビット)。PRFの出力長(hLenで例えばSHA-256なら32バイト)と一致させると計算がT1のみで完結し無駄がない |
| PRF(疑似乱数関数) | HMAC-SHA256またはHMAC-SHA512を使用。HMAC-SHA1は依然として仕様上サポートされるが、SHA-1の危殆化を踏まえ新規実装での使用は避ける |
| イテレーション回数 | OWASP Password Storage Cheat Sheet(2024年改訂版)の目安:PBKDF2-HMAC-SHA256で600,000回以上、PBKDF2-HMAC-SHA512で210,000回以上。サーバー1コアでの検証時間がおおむね100ミリ秒前後になるよう、実機で計測して調整するのが実務上の定石 |
具体的な導出例
実際にどの程度の計算が行われるのか、数値で追ってみます。仮に「AES-256の鍵(32バイト=256ビット)」をPBKDF2-HMAC-SHA256(hLen=32バイト)で導出するとします。
- 必要ブロック数 l = ceil(dkLen / hLen) = ceil(32 / 32) = 1ブロック。つまりT1だけで鍵長ちょうどになり、無駄な計算が発生しません。
- これがもしdkLen=64バイト(512ビット鍵、例えばAES-256を2本分導出するようなケース)だと l = ceil(64/32) = 2ブロックとなり、T1とT2をそれぞれ独立に(ブロック番号iを1と2に変えて)計算し連結する必要があります。
- イテレーション回数c=600,000の場合、U1からU600,000までを順番に計算するため、この部分は並列化できません(各Uiは直前のUi-1の出力に依存するため)。この「逐次実行を強制される」性質こそがブルートフォース攻撃のコストを引き上げる仕組みの核心です。
- 一方でブロックが複数(T1、T2、…)ある場合、ブロック間の計算は互いに独立しているため並列化が可能です。ただしdkLenが数十バイト程度であれば通常l=1〜2で収まるため、実務上のボトルネックにはなりません。
この「1コアで約100ミリ秒かかる」という体感値は、正規ユーザーのログイン時にはほぼ気にならない遅延ですが、攻撃者が数十億通りのパスワード候補を試そうとすると、1コアあたり単純計算で数十年オーダーの時間がかかる計算になります(実際にはGPU等で並列化されるため、後述の「メリット・デメリット」の通り実効的な耐性はbcryptやArgon2idより低くなります)。
メリット・デメリット
| 観点 | 内容 |
|---|---|
| メリット |
・RFC 8018として長年標準化されており、仕様の解釈揺れが少ない ・OpenSSL、Python標準ライブラリ(hashlib.pbkdf2_hmac)、Java(javax.crypto.SecretKeyFactory)、.NET(Rfc2898DeriveBytes)などほぼ全ての主要言語・ランタイムに標準実装がある ・演算がCPU中心でメモリをほとんど使わないため、組込み機器やHSM(ハードウェアセキュリティモジュール)、FIPS 140-2/140-3認証を受けた暗号モジュールでの実装が容易 ・イテレーション回数という単一パラメータだけで計算コストを調整でき、設計がシンプル |
| デメリット |
・メモリをほとんど消費しないため、GPUやFPGA、ASICを使った大規模並列ブルートフォースに対する耐性がbcrypt・scrypt・Argon2idより低い ・「メモリコスト」パラメータを持たないため、ハードウェアによる攻撃コストの非対称性(攻撃者側だけが安価に並列化できる状況)を作りにくい ・イテレーション回数を将来引き上げる際、既存の全ユーザーのハッシュを新パラメータで再計算するのは(元のパスワードを知らない限り)不可能なため、ログイン時に段階的に再ハッシュする移行処理が必要になる ・パスワード長に上限がない実装が多く、非常に長い入力を与えるとサーバー側の処理時間が想定より伸びるDoSのリスクがある(実装によっては長さ制限を設けて対処) |
混同されやすい用語・類似技術との違い
PBKDF2は「パスワードベースの鍵導出関数」というカテゴリの草分け的存在ですが、同じカテゴリや隣接分野の技術と混同されることが少なくありません。代表的なものを比較します。
| 名称 | 標準化・登場時期 | コストの種類 | GPU/ASIC耐性 | 主な用途 |
|---|---|---|---|---|
| PBKDF2 | RFC 8018(現行)、原型はRFC 2898(2000年) | CPU(反復回数)のみ | 低〜中 | WPA2/WPA3、PKCS#12、レガシー互換 |
| bcrypt | 1999年発表(Blowfish暗号ベース)、RFCではなく事実上の標準 | CPU+約4KB固定メモリ | 中 | Unix系のパスワードハッシュ、多くのWebフレームワークの既定 |
| scrypt | 2009年発表、RFC 7914で標準化 | CPU+可変メモリ(MB単位に調整可) | 高 | 暗号資産(Litecoin等のProof of Work)、ディスク暗号化 |
| Argon2id | 2015年 Password Hashing Competition優勝、RFC 9106で標準化 | CPU+可変メモリ+並列度 | 最高 | 新規システムでの第一選択(OWASP最推奨) |
HKDF(HMAC-based Key Derivation Function)との違いにも注意が必要です。HKDFはNIST SP 800-56Cおよび RFC 5869 で標準化された鍵導出関数で、TLS 1.3のハンドシェイクやSignalプロトコルの鍵管理などで使われますが、PBKDF2とは前提が異なります。PBKDF2は「人間が入力する低エントロピーなパスワード」を高コスト化して鍵にすることが目的なのに対し、HKDFは「既に十分な乱数性を持つ鍵材料(例えばDiffie-Hellman鍵交換の共有秘密)」を、用途別の複数の鍵に安全に展開(expand)することが目的です。低エントロピーなパスワードをHKDFに直接入力しても、総当たり耐性は得られません。両者は「鍵導出関数」という同じ分類に入るため名前だけで混同されがちですが、想定する入力のエントロピーが根本的に異なる点を押さえておくべきです。
また、旧規格のPBKDF1(同じくRFC 2898で定義)は出力鍵長がハッシュ関数の出力長に制限される(MD2/MD5/SHA-1利用時で最大20バイト程度)という制約があり、現在は非推奨です。RFC 8018でもPBKDF1は後方互換性のためだけに残されている位置づけであり、新規実装では必ずPBKDF2を使用します。
AIエンジニアとしての実体験
機密データを扱うAIプロジェクトでは、PBKDF2を使用してデータ暗号化鍵を導出することがあります。例えば、患者データを扱う医療AIプロジェクトでは、データベースの暗号化にPBKDF2で導出した鍵を使用しました。
ただし、新規プロジェクトではArgon2idへの移行を推奨しています。PBKDF2はGPU攻撃に対する耐性が比較的低いためです。
自社サーバー運用への応用
WPA2-PSKでの使用
Wi-FiのWPA2-PSKでは、PBKDF2(4096イテレーション)を使用してパスフレーズからPMK(Pairwise Master Key)を導出します。
macOS FileVaultとiOS
AppleのFileVaultやiOSのデータ保護機能は、PBKDF2を使用してユーザーパスワードからデバイス鍵を導出しています。
実装時の実務ポイント
自社サーバーやSaaS基盤でPBKDF2を導入・運用する際に、実務でよく論点になる項目を整理します。
- ソルトの保存場所:ソルトは秘匿する必要はなく、導出した鍵やハッシュ値と同じレコードに平文で保存して問題ありません。重要なのは「ユーザーごとに毎回新しく生成すること」であり、使い回しは厳禁です。
- イテレーション回数のバージョニング:将来イテレーション回数を引き上げられるよう、ハッシュ値と一緒に「使用したイテレーション回数」も保存しておく設計(例:
pbkdf2_sha256$600000$salt$hashのような文字列形式)にしておくと、新旧パラメータが混在していても検証時に困りません。DjangoのPBKDF2PasswordHasherはこの形式を採用しています。 - 段階的な再ハッシュ(アップグレード・オン・ログイン):ユーザーがログインした瞬間(=平文パスワードが手元にある瞬間)に、古いパラメータで保存されていたハッシュを新しいイテレーション回数で再計算して保存し直す実装が定石です。パスワードを一括で強制リセットする必要がありません。
- パスワードの正規化:Unicode文字(絵文字や合成文字を含むパスワード)を扱う場合は、NFKC等での正規化やUTF-8エンコードの一貫性を保たないと、同じ「見た目のパスワード」でも異なるバイト列としてハッシュ化されてしまうことがあります。
- ペッパー(pepper)との併用:ソルトに加えて、アプリケーション全体で共有するシークレット値(ペッパー)をHMACやアプリ側の秘密鍵管理サービス(AWS KMS、HashiCorp Vault等)で別管理し、DB漏洩だけでは解読できない多層防御にするケースもあります。
関連ブログ記事
📝 関連記事
トラブル事例と対策
⚠️ イテレーション数の過小設定
問題:古いシステムで1000回程度の設定が残っている
対策:ログイン時にイテレーション数をアップグレードする仕組みを実装
⚠️ SHA-1の使用
問題:古い実装でPBKDF2-HMAC-SHA1が使用されている
対策:SHA-256またはSHA-512に移行。移行時はイテレーション数を調整
⚠️ ソルトの使い回し・固定値化
問題:アプリ全体で共通の固定ソルトを使っている、あるいはソルトを空文字にしている実装が稀に見つかる
対策:ユーザーレコードごとにCSPRNGで16バイト以上のソルトを生成し直す。既存データは移行バッチでソルト・ハッシュを再発行する
⚠️ 長大な入力によるDoSリスク
問題:パスワード長に上限を設けていないAPIに、意図的に数MB単位の長大な文字列を送りつけられ、サーバーCPUを浪費される
対策:入力段階でパスワード長の上限(例:128〜256文字程度)を設け、極端に長い入力を弾く。既にHMACの内部処理でブロック化されるため長さそのものが脆弱性になるわけではないが、リソース制御の観点で制限しておくのが無難
最新動向(2026年)
推奨イテレーション数の増加
ハードウェアの進歩に伴い、OWASP推奨のイテレーション数は年々増加しています:
- PBKDF2-HMAC-SHA256: 600,000回以上
- PBKDF2-HMAC-SHA512: 210,000回以上
- PBKDF2-HMAC-SHA1: 1,300,000回以上(非推奨)
Argon2への移行推奨
新規開発では、メモリハードなArgon2idが推奨されています。PBKDF2はレガシーシステムや互換性が求められる場面で使用します。
NIST SP 800-63Bとデジタルアイデンティティガイドライン
米国NISTがまとめる電子認証のガイドライン「SP 800-63B(Digital Identity Guidelines: Authentication and Lifecycle Management)」では、記憶シークレット(パスワード)の検証者側実装として、ソルト付きハッシュ関数(PBKDF2、bcrypt、scrypt等)を適切なワークファクター(イテレーション回数)とともに使うことを求めています。同ガイドラインは定期的に改訂が進められており、最新の推奨値は必ず一次情報(NIST公式サイト)を確認することが望ましい状態です。組織のコンプライアンス要件でNIST準拠を求められる場合、SP 800-132(鍵導出)とSP 800-63B(認証)の両方を参照する必要がある点に注意してください。
量子コンピュータへの耐性についての考え方
PBKDF2はRSAや楕円曲線暗号のような公開鍵暗号とは異なり、ハッシュ関数(対称的な一方向関数)をベースにしているため、Shorのアルゴリズムのような量子コンピュータによる直接的な解読手法の対象にはなりません。一方でGroverのアルゴリズムにより、総当たり探索コストが理論上ルートオーダーで低減される(実効的な安全性ビット数がおよそ半分になる)とされており、長期的な安全性マージンを見込むのであれば、出力鍵長やイテレーション回数に余裕を持たせておく設計上の考慮は無駄ではありません。ただし現時点でこれは実用上の脅威というより設計上の保守的な配慮の域にとどまります。
関連用語
外部リンク・参考資料
よくある質問(FAQ)
Q. PBKDF2とは何ですか?
PBKDF2(Password-Based Key Derivation Function 2)はパスワードから暗号鍵を導出するアルゴリズムです。RFCで標準化されており、イテレーション回数を増やすことでブルートフォース攻撃への耐性を調整できます。TLS/SSL、WPA2-Personal(Wi-Fi暗号化)、パスワードマネージャーなどで広く使用されています。
Q. PBKDF2・bcrypt・Argon2の違いは何ですか?
PBKDF2はメモリ消費が少なく(CPUのみ)、GPUでのブルートフォースが比較的容易です。bcryptはメモリを約4KB固定で使用しGPU攻撃にある程度強いですが、パスワード長が72バイトまでという制約があります。Argon2idはメモリ消費量を可変で大きく設定でき、現在OWASPが最推奨するアルゴリズムです。新規システムではArgon2idが推奨です。
Q. PBKDF2のイテレーション回数はいくつが適切ですか?
OWASP Password Storage Cheat Sheetの目安はPBKDF2-HMAC-SHA512で210,000回以上、PBKDF2-HMAC-SHA256で600,000回以上です。イテレーション回数はサーバーのスペックによって検証1回あたり100ミリ秒前後になる値に調整するのが実務上の定石です。レガシーシステムでは1000回程度のものも多く、定期的なイテレーション数の見直しが必要です。
Q. PBKDF2のメリット・デメリットは何ですか?
メリットはRFC 8018として標準化されており、主要言語の標準ライブラリやFIPS 140-2/3認証モジュールで幅広く実装されている点、CPU中心の処理で組込み機器にも実装しやすい点です。デメリットはメモリをほとんど消費しないため、GPUやASICを使った並列ブルートフォース攻撃への耐性がbcrypt・scrypt・Argon2idより低いことです。既存ハッシュのイテレーション回数を後から引き上げるには、ログイン時に段階的に再ハッシュする移行処理が必要になります。
Q. PBKDF2とHKDFはどう違いますか?
どちらも「鍵導出関数」ですが目的が異なります。PBKDF2は人間が入力する低エントロピーな「パスワード」を、繰り返し計算で高コスト化して鍵にすることが目的です。一方HKDF(RFC 5869、NIST SP 800-56C)は、Diffie-Hellman鍵交換の共有秘密のように既に十分なランダム性を持つ鍵材料を、TLS 1.3などで用途別の複数の鍵に展開する目的で使われます。低エントロピーなパスワードをHKDFにそのまま入力しても総当たり耐性は得られません。
