よくある質問
HMAC と通常のハッシュの違い — メッセージを SHA-256 するだけではダメですか?
通常のハッシュは「メッセージが改変されていない」ことは示しますが、「特定の相手が作った」ことは示しません。メッセージを持つ誰でもハッシュを再計算できます。HMAC はハッシュに共有秘密を織り込むため、鍵を知る当事者だけがタグを生成・検証できます。「鍵を知っている誰かから来た」という保証が得られるのが本質で、Webhook の真正性検証、API リクエスト署名、セッショントークンなどで役立ちます。
SHA-1 は破られているのに HMAC-SHA-1 が残っているのはなぜですか?
2017 年の SHAttered 攻撃が SHA-1 の衝突(同じハッシュ値を持つ 2 つのメッセージ)を発見しました。これはデジタル署名(攻撃者が両方のメッセージを制御できる)では SHA-1 を破りますが、鍵を知らずにタグを偽造する必要のある HMAC は破りません。NIST は SP 800-107r1 まで HMAC-SHA-1 を MAC 用途として承認しており、多くのレガシープロトコル(古い AWS 署名、一部の Atlassian Webhook、Kerberos の一部など)が今も使っています。新規には SHA-256 を、SHA-1 は相互運用のみに留めてください。
秘密鍵はどれくらいの長さが必要ですか?
RFC 2104 はハッシュ出力以上の長さの鍵を推奨しています — SHA-256 で 32 バイト、SHA-384 で 48 バイト、SHA-512 で 64 バイトです。短い鍵も受け付けられますが(HMAC がパディングします)、実効的なセキュリティは鍵長で頭打ちになります。ハッシュの*ブロックサイズ*(SHA-1 / 256 は 64 バイト、SHA-384 / 512 は 128 バイト)より長い鍵は先に内部ハッシュへ縮約され、セキュリティは増えず無駄な計算が増えます。鍵は `crypto.getRandomValues(new Uint8Array(32))` などで生成し、他の秘密と同じ慎重さで保管してください。
サーバが署名を受け付けないのに値は一致しているように見えます — なぜですか?
原因は 2 つあります。第一に、検証側が定数時間比較を使う場合です。`==` は最初に違うバイトで早期終了し、どこまでバイトが一致しているかをタイミングで漏らします。サーバはそれを攻撃と見なして拒否することがあります。第二にエンコードの不一致です。hex の大小、base64 と base64url の違い、末尾 `=` パディングの有無などです。仕様書のフォーマットに正確に揃えてください。hex の大文字小文字を一文字でも違えるとよくある失敗パターンになります。
本ツールで署名の検証もできますか?
本ツールは生成のみです。検証とは、同じ入力で HMAC を再計算し、期待されるタグと定数時間比較で照合する処理です。検証したい場合は同じ鍵とメッセージをここに貼り付け、出力を期待値と一文字ずつ比較するか、コード側で `crypto.subtle.verify` を使ってください。ブラウザにはタイミング安全な比較関数が組み込まれていないため、本番の検証はサーバサイドライブラリを使うのが推奨です。
HMAC・デジタル署名・KDF の違いは?
**HMAC** は 1 つの共有秘密でタグを生成し、検証側も同じ秘密が必要です。鍵を共有できる二者間で高速・標準的です。**デジタル署名**(RSA・ECDSA・Ed25519)は秘密鍵で署名し、公開鍵で検証します。検証側に秘密は不要なので、発行者が一度署名すれば任意の読者が検証できます。**KDF**(PBKDF2・HKDF・Argon2)はパスワードや長い秘密を固定長の鍵に変換するもので、署名用途ではなく署名前の構成要素です。多くのプロトコルは重ねて使います。HKDF で鍵を派生し、HMAC でメッセージを認証し、デジタル署名で信頼の起点を作るといった流れです。
関連する概念
HMAC(Hash-based Message Authentication Code)は RFC 2104(1997)で定義され、FIPS 198-1(2008)として標準化されました。既存のハッシュ関数を固定された構成で包む方式で、メッセージに対しハッシュを 2 回パスし、内側と外側のパディング定数に鍵を XOR します。構成は下層ハッシュに対して*汎用*で、HMAC-SHA-256・HMAC-SHA-512・現在は非推奨の HMAC-MD5 まで同じテンプレートに従います。出力サイズは下層ハッシュに一致します — SHA-256 で 32 バイト、SHA-384 で 48 バイト、SHA-512 で 64 バイトです。
HMAC は 3 つの近隣プリミティブの中間に位置します。**通常のハッシュ**(`SHA-256(message)`)は整合性を示しますが、出所は示しません。誰でも再計算できます。**HMAC**(`HMAC(key, message)`)は整合性と「鍵を知る誰かが作った」ことの両方を示します。検証側は同じ鍵が必要です。**デジタル署名**(RSA・ECDSA・Ed25519)は、検証側が秘密を持たずに出所と整合性を示せます。代償は 100〜10000 倍の遅さと出力の大きさです。**AEAD**(AES-GCM・ChaCha20-Poly1305)は認証と暗号化を一体化し、現代のプロトコルで「暗号化後 HMAC」のパターンを置き換えます。
日常的な用途は業界全体で驚くほど一貫しています。**Webhook 署名** — Stripe `Stripe-Signature`、GitHub `X-Hub-Signature-256`、Slack `X-Slack-Signature`、Twilio `X-Twilio-Signature` はいずれも HMAC-SHA-256(旧版では HMAC-SHA-1)でタイムスタンプ + ペイロードを署名します。**API リクエスト署名** — AWS Signature v4、Snowflake、Twitter OAuth 1.0a はヘッダとパラメータの正規化文字列を署名します。**JWT HS256 / HS384 / HS512** は header.payload の連結を HMAC で署名し、3 つ目のセグメントとします。**セッショントークン** — Rails の `signed cookies` や Django の `signing` は HMAC を用い、暗号化なしで改ざんを検知可能にします。いずれの場合も脅威モデルは同じで、鍵を持たない第三者によるメッセージの偽造・改変を防ぐことが目的です。