HMAC、PBKDF2、HKDF — キー付きハッシュをゼロから解説
一文で言うと:SHA-256 のような裸のハッシュは誰でも計算できるため、誰がメッセージを送ったかについて何も証明しません — HMAC は秘密鍵を混ぜ、鍵保持者だけがダイジェストを生成(または検証)できるようにします。PBKDF2 と HKDF はその同じ HMAC 機構を再利用して秘密を鍵に変えます。パスワードにはゆっくりと、すでにランダムな素材には速やかに。
HMAC とは何か(RFC 2104)
構成。 HMAC は 1 回ではなく 2 回のハッシュ実行です。鍵はハッシュのブロックサイズまでパディングされ(MD5/SHA-1/SHA-256 は 64 バイト、SHA-384/512 は 128 バイト)、メッセージは鍵 XOR 固定の内側パッドで 1 回ハッシュされ、そのダイジェストが鍵 XOR 固定の外側パッドで再度ハッシュされます。この二重サンドイッチは、基盤のハッシュがまともな擬似乱数関数である限り証明可能に安全です — だから HMAC-MD5 は、平文 MD5 を破った実用的な衝突攻撃にもまだ耐えています(とはいえ引退済み。下記参照)。
鍵。 任意の鍵長が動作します:ブロックサイズより短いものはそのまま使われ(ただし 32 バイト未満は推奨されません)、長いものは先にハッシュされます。このページは鍵をテキスト・16 進・Base64 で入力できるため、64 桁の 16 進運用鍵を、64 文字のテキストパスワードと誤解されずに貼り付けられます — 出力行に読み取り方法が記録されるのはまさにそのためです。
出会う場所。 JWT ヘッダーの HS256 は、文字どおり base64url エンコードされたトークン部分に対する HMAC-SHA-256 です(このサイトのJWT デコーダーは、HS256 シークレットを貼ると正確にそれを計算します)。Webhook 署名(Stripe、GitHub)、AWS SigV4、TLS レコード保護(旧バージョン)、OpenSSH の umac-64@openssh.com いとこはすべて同じファミリーです。
なぜ hash(message || key) ではだめ? 長さ延長攻撃です:MD5/SHA-1/SHA-2 ファミリのすべてのハッシュは、H(secret || msg) を知る攻撃者に、秘密なしで H(secret || msg || padding || anything) を計算させます。HMAC の内側/外側分割がこの種の攻撃を排除します。API 署名コードの自作実装で最も多い単一の過ちであり — HMAC が存在する理由です。
PBKDF2 とは何か(RFC 8018)
設計上遅い。 パスワードの本当のエントロピーはせいぜい 40 ビット。攻撃者の GPU は毎秒数十億回の生 SHA-256 を試します。PBKDF2 は HMAC(password, salt) を何度も — iter 回 — 実行するため、各推量はあなたにも攻撃者にも同じ iter 回の HMAC のコストがかかります。ここのデフォルトは 600,000 反復 + HMAC-SHA-256(OWASP パスワード保存チートシートのベースライン)で、スライダーは 1,000 万まで行きます。ハードウェアが速くなるにつれてセキュリティ指針は上方に巻き上げられるからです。
ソルト。 パスワードごとのランダムソルトにより、同じユーザーでも同じハッシュにならず、事前計算表(レインボーテーブル)が無価値になります。秘密ではありません — ハッシュの隣に保存されます — 一意であればよいだけです。ランダム 16 バイトが標準です。
既知の弱点。 PBKDF2 は CPU 固有の困難さはありますがメモリ困難ではありません:GPU と ASIC が恥ずかしいほどよく並列化します。だから現代の助言は、パスワードハッシュ保管を設計するなら scrypt か Argon2id(この族のパスワードハッシュ生成ページがカバー)で、PBKDF2 は互換性と FIPS-140 環境の正解として残ります。
HKDF とは何か(RFC 5869)
抽出、それから展開。 HKDF は 2 つの仕事をします。抽出:歪みのあるかもしれない入力鍵素材(例:Diffie–Hellman 共有秘密)をソルトと一緒に 1 つの短い擬似乱数鍵 PRK = HMAC(salt, IKM) に押し潰します。展開:その PRK を最大 255 ハッシュブロックまで引き伸ばし、各出力ブロックは前のブロックに連鎖し info フィールドでタグ付けされます。結果、1 つの秘密から暗号化鍵、MAC 鍵、IV を安全に — すべて分離して — 得られます。
パスワードには使わない。 HKDF は入力がすでに全エントロピーを持つと仮定します — 出力 32 バイトごとに 1 回の HMAC しかしないため、人間のパスワードは実質一瞬で通過し、まさに攻撃者の望む通りです。PBKDF2 の代わりに HKDF にパスワードを通すのは古典的な設計エラーです。info フィールドは目的ラベル("client traffic key"、"server iv")のためのもので、追加エントロピーのためではありません。
出会う場所。 TLS 1.3 はハンドシェイク秘密から使うすべての鍵を HKDF で導出します。WireGuard、Signal、EAP-TLS 1.3、JSON Web Encryption(直接鍵合意 KDF として)はすべて同じ家系図に現れます。
アンカー値 — このページで再現
最初の 2 つの表は、このページのサンプルボタンとセルフテストの基盤となるテストベクトルです(鍵 "key"、メッセージ「The quick brown fox jumps over the lazy dog」。次に 16 バイトの 0x0b 鍵とメッセージ「Hi There」の RFC 風ケース)。すべて独立したネイティブ実装で生成され、このページで再検証されています。
「fox」の HMAC、鍵 = key | ダイジェスト(16 進) |
| HMAC-MD5 | 80070713463e7749b90c2dc24911e275 |
| HMAC-SHA-1 | de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9 |
| HMAC-SHA-256 | f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 |
| HMAC-SHA-384 | d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1ae50700582a96cf35e1e554995fe4e03381c237 |
| HMAC-SHA-512 | b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a |
| KDF アンカー | パラメータ | 出力(16 進、先頭バイト) |
| PBKDF2-HMAC-SHA-1 | password / salt、c=4096、32 バイト | 4b007901b765489abead49d926f721d065a429c12e463f6c4cd79401085b03db |
| PBKDF2-HMAC-SHA-256 | password / salt、c=4096、32 バイト | c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a |
| HKDF-SHA-256 (RFC 5869 A.1) | IKM=0x0b×22、ソルト=00..0c、info=f0..f9、L=42 | 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 |
| HKDF-SHA-256 (RFC 5869 A.2) | IKM=00..4f、ソルト=60..af、info=b0..ff、L=82 | b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c… |
| HKDF-SHA-256 (RFC 5869 A.3) | IKM=0x0b×22、空のソルトと info、L=42 | 8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8 |
よくある間違い
- HMAC を暗号化と混同する。 HMAC は(共有秘密があれば)完全性と出所を証明しますが、何も隠しません。鍵を持たない人はメッセージ全体を見られます。
- HMAC を署名と混同する。 デジタル署名は公開鍵式です:1 人が署名し、誰でも検証します。HMAC は対称式です:すべての検証者が偽造もできます。否認防止には RSA/ECDSA(この族の RSA ツールを参照)が必要で、HMAC ではありません。
- 鍵の読み取り不一致。 64 桁の 16 進文字列をテキスト鍵欄に貼ると、32 ではなく 64 バイトになります — HMAC は完全に変わります。このページは出力行に読み取り方法を表示します。2 つのツールが食い違うとき、最初に比較すべきはそれです。
- PBKDF2 の反復が少なすぎる。 1,000 反復は 2000 年には合理的でした。今日の GPU リグはそれを平らげます。システムがまだ 1,000 反復のハッシュを保存しているなら、ログイン時再ハッシュ移行を計画してください。
- パスワードに HKDF。 出力ブロックごとに 1 回の HMAC しかないため、パスワードは一瞬で通過します — パスワードには PBKDF2(または Argon2id)、高エントロピー秘密には HKDF を。
- 1 つの導出鍵をすべてに再利用。 修正は無料です:異なる
info ラベルで別々の鍵を導出してください。異なるラベルの 1 つの IKM からの 2 つの鍵は、設計上独立です。
よくある質問
HMAC-MD5 は破られていますか? 衝突耐性ハッシュとしての MD5 は死んでいますが、HMAC-MD5 の安全性は MD5 を擬似乱数関数として使うことに依存し、実用的な破壊は知られていません。それでも引退済み — 古いプロトコルとの互換性以外に HMAC-SHA-256 の代わりに選ぶ理由はありません。
HMAC 鍵はどのくらいの長さに? 少なくともハッシュの出力サイズ(SHA-256 なら 32 バイト)で、CSPRNG で生成してください。ダイジェストより短い鍵も許されますが、不足する各ビットが安全性を直接下げます。
PBKDF2 は反復を増やせば無限に「より安全」に? 攻撃者のコストを線形に上げますが、あなたのログインコストも線形に上がります。ゲームは、ユーザーが耐えられる最大の回数を選ぶことです — OWASP の数値がそれを較正しています。
HKDF が 255 × ハッシュサイズで上限なのはなぜ? 展開ループは 1 バイトカウンタ i 付きの T(i) = HMAC(PRK, T(i-1) || info || i) です — 255 が最大カウンタ値で、RFC 5869 の構造上の上限であり、ポリシー上の選択ではありません。
このページの PBKDF2 とパスワードハッシュ生成の違いは? 同じアルゴリズム、別の仕事です。このページは、他で使う生の鍵バイトを導出します。パスワードハッシュページは、(ソルトとパラメータを埋め込んだ)保存用クレデンシャル文字列を生成し、貼り付けられた候補を検証します。