Diffie-Hellman鍵共有方式
通信する二者が公開してもよい値だけを交換し、盗聴されていても同じ秘密の値を互いに計算できる鍵共有方式である。公開された値から秘密の値を逆算する離散対数問題が難しいことを安全性の根拠とする。交換した値が本当に相手のものかを確かめないと中間者攻撃を受けるため、署名などによる認証と組み合わせて使う。
イマシルちゃんの解説
共通鍵暗号で通信するには、送る側と受け取る側が同じ鍵を用意する必要があるんだ。
そのために鍵の材料を共有するのが、Diffie-Hellman鍵共有方式だよ。
お互いに自分だけの秘密の数を決めて、そこから計算した公開値を交換するの。
受け取った公開値と自分の秘密の数を使うと、両者で同じ秘密の値を計算できるんだ。
その値を加工して暗号化に使う鍵を作るから、鍵そのものを相手へ送らずに済むよ。
十分に安全な数や計算方法を選べば、公開値を盗み見ただけで鍵を求めるのは難しいんだ。
ただし相手のなりすましは防げないから、署名などで通信相手を確かめることも必要だよ。
この解説はわかりやすかったですか?
より深い解説
鍵を「送る」のではなく「作る」方式
共通鍵暗号方式は処理が速いが、通信を始める前に同じ鍵を両者が持つ必要がある。鍵そのものを送れば盗聴者にも渡ってしまう。この鍵配送の問題に対する答えの一つが、Diffie-Hellman鍵共有方式(以下DH)である。
DHでは、どちらか一方が鍵を決めて相手に届けるのではない。両者がそれぞれ秘密の値を選び、そこから計算した公開値だけを交換する。受け取った公開値と自分の秘密の値から、両者は同じ値を計算できる。このように両者の寄与から共通の秘密を導く方式を鍵共有(key agreement)と呼ぶ。
これに対し、TLS 1.2までのRSA鍵交換は、クライアントが作った値をサーバの公開鍵で暗号化して送る鍵配送型である。DHは公開鍵暗号方式の仲間に数えられるが、DH単体ではデータの暗号化も署名もできない。役割は、共通鍵の素となる秘密を共有することだけである。手順と計算式はRFC 2631に定められている。
公開値の交換と共有値の計算
有限体を使う基本のDHでは、大きな素数 p と、生成元と呼ぶ値 g を事前に決めて公開する。これらの組をDHグループと呼び、両者は同じグループを使う必要がある。
- Aさんは秘密の値 a を選び、公開値 A = g^a mod p を計算してBさんへ送る。
- Bさんは秘密の値 b を選び、公開値 B = g^b mod p を計算してAさんへ送る。
- Aさんは受け取った B を使って B^a mod p を計算する。
- Bさんは受け取った A を使って A^b mod p を計算する。
- どちらの計算結果も g^(a×b) mod p に等しくなるので、両者は同じ値を得る。
| 値 | Aさん | Bさん | 盗聴者 |
|---|---|---|---|
| p、g | 知っている | 知っている | 知っている |
| 公開値 A、B | 知っている | 知っている | 知っている |
| 秘密の値 a | 知っている | 知らない | 知らない |
| 秘密の値 b | 知らない | 知っている | 知らない |
| 共有値 g^(a×b) mod p | 計算できる | 計算できる | 計算が困難 |
両者が同じ値になるのは、累乗の順序を入れ替えても結果が変わらないためである。(g^b)^a と (g^a)^b はどちらも g^(a×b) に等しく、mod p をとっても一致する。得られた共有値はそのまま暗号鍵にせず、鍵導出関数に通して暗号化用や改ざん検知用の鍵を作る。
小さな数値で計算を確かめる
仕組みを確かめるため、実際には使えない小さな値で計算する。p = 23、g = 5 とし、Aさんの秘密の値を a = 6、Bさんの秘密の値を b = 15 とする。
Aさんの公開値 A = 5^6 mod 23
5^2 = 25 → 25 − 23 = 2
5^4 = 2 × 2 = 4
A = 5^6 = 5^4 × 5^2 = 4 × 2 = 8
Bさんの公開値 B = 5^15 mod 23
5^8 = 5^4 × 5^4 = 4 × 4 = 16
5^15 = 5^8 × 5^4 × 5^2 × 5 = 16 × 4 × 2 × 5 = 640
B = 640 − 23 × 27 = 640 − 621 = 19
Aさんの計算 B^6 mod 23
B^2 = 361 → 361 − 23 × 15 = 16
B^4 = 16 × 16 = 256 → 256 − 23 × 11 = 3
B^6 = B^4 × B^2 = 3 × 16 = 48 → 48 − 46 = 2
Bさんの計算 A^15 mod 23
A^2 = 64 → 64 − 46 = 18
A^4 = 18 × 18 = 324 → 324 − 23 × 14 = 2
A^8 = 2 × 2 = 4
A^15 = A^8 × A^4 × A^2 × A = 4 × 2 × 18 × A = 144 × A
144 − 23 × 6 = 6 なので、A^15 mod 23 = 6 × A mod 23 = 2
公開値 A を代入すれば、Bさんの計算もAさんと同じ共有値になることを確かめられる。
ネットワーク上を流れるのは p、g と2つの公開値だけである。共有値も2人の秘密の値も、通信路には一度も現れない。
逆算が難しいことが安全性を支える
盗聴者は g、p、A を知っている。A = g^a mod p を満たす a を求められれば、共有値も計算できる。累乗した結果から指数を求めるこの問題を離散対数問題と呼ぶ。g^a mod p の計算は速いが、逆向きに a を求めるのは p が十分大きければ現実的な時間では解けないと考えられている。
上の例では p = 23 なので、5^1 から 5^22 までを順に計算すれば、Aさんの公開値と一致する指数をすぐに見つけられる。実際の利用では、IKE向けにRFC 3526が定める2,048ビット以上の素数を使うグループなどを選ぶ。小さすぎるグループを許すと、総当たりや事前計算による攻撃の対象になる。
楕円曲線上の点の演算で同じ考え方を実現したものをECDH(楕円曲線Diffie-Hellman)と呼ぶ。楕円曲線上でも、点の演算結果から元の値を逆算するのは難しい。そのため有限体のDHより短い鍵長で同程度の安全性を得られる。例えばRFC 7748のX25519は公開値が32バイトで、約128ビットの安全性を目標にしている。
| 観点 | 有限体のDH | 楕円曲線のDH |
|---|---|---|
| 使う演算 | 素数 p を法とする累乗 | 楕円曲線上の点のスカラー倍 |
| 逆算が難しい問題 | 累乗の結果から指数を求める | 点のスカラー倍の結果から倍数を求める |
| 公開値の大きさの例 | 2,048ビットのグループなら256バイト程度 | X25519なら32バイト |
| TLS 1.3のグループ名の例 | ffdhe2048、ffdhe3072 | x25519、secp256r1 |
公開値をすり替えられる危険
DHは盗聴だけを行う受動的な攻撃者には強い。しかし公開値のやり取りに相手を確かめる仕組みはない。通信路の途中で公開値をすり替えられる攻撃者がいると、中間者攻撃が成立する。
上の例に攻撃者Mを加える。Mは秘密の値 m = 9 を選び、M = 5^9 mod 23 = 11 を計算する。MはAさんの公開値 A を奪ってBさんには11を渡し、Bさんの公開値 B を奪ってAさんにも11を渡す。
| 区間 | 当事者が計算する共有値 | 攻撃者が計算する共有値 |
|---|---|---|
| AさんとMの間 | 11^6 mod 23 = 9 | A^9 mod 23 = 9 |
| MとBさんの間 | 11^15 mod 23 = 10 | B^9 mod 23 = 10 |
AさんもBさんも鍵共有に成功したと思っているが、実際の相手はMである。Mは片方の鍵で復号した内容を読み、もう片方の鍵で暗号化し直して転送できる。
そのため、実際のプロトコルでは公開値を認証された情報と結び付ける。証明書認証を使うTLS 1.3では、サーバが証明書に対応する秘密鍵で、それまでのハンドシェイク記録に基づく値へ署名し、CertificateVerifyメッセージで送る。IKEv2では、鍵共有の後の交換で証明書による署名や事前共有鍵を使い、それまでのメッセージを相手が作ったことを確かめる。DHが秘密を作り、署名や事前共有鍵が相手を確かめるという分担で考える。
使い捨ての鍵と前方秘匿性
秘密の値をいつまで使い続けるかで、安全性の性質が変わる。サーバが長期間同じ秘密の値を使う方式を静的DH、接続ごとに新しい秘密の値を作って使い終わったら捨てる方式を一時的(ephemeral)なDHと呼ぶ。有限体のものをDHE、楕円曲線のものをECDHEと書く。末尾のEは一時的であることを表す。
一時的な鍵を使えば、後でサーバの長期的な秘密鍵が漏えいしても、過去に記録された通信の共有値は求められない。長期的な秘密鍵は署名による認証にしか使っておらず、共有値の計算には関わらないためである。この性質を前方秘匿性と呼ぶ。
| 鍵交換の方式 | 共有の仕方 | 長期鍵が漏えいしたときの過去の通信 |
|---|---|---|
| RSA鍵交換 | サーバの公開鍵で暗号化して送る | 記録があれば復号される |
| 静的DH | 長期間同じDHの秘密の値を使う | 記録があれば共有値を計算される |
| DHE・ECDHE | 接続ごとに秘密の値を作り直して捨てる | 共有値は求められない |
RFC 2631は、受信側だけが証明書付きの静的な鍵を持つ方式と、両者が静的な鍵を持つ方式を定めている。後者では両者の組合せが同じ限り共有値も変わらないため、メッセージごとに異なる追加情報を混ぜて鍵を作る。
TLS 1.3での使われ方
TLS 1.3では、静的なRSAと静的なDHによる鍵交換が廃止された。証明書を使う完全なハンドシェイクでは、必ずDHEかECDHEで鍵を共有する。そのため、この形の接続は前方秘匿性を持つ。
クライアントは、対応するグループの一覧をsupported_groups拡張で示し、実際の公開値をkey_share拡張に入れてClientHelloで送る。サーバは選んだグループの公開値をServerHelloのkey_share拡張で返す。この1往復で鍵を共有できるため、TLS 1.2より早く暗号化を始められる。
クライアントが送った公開値のグループをサーバが受け入れない場合、サーバはHelloRetryRequestで使えるグループを伝える。クライアントはそのグループの公開値を作り直して再送する。TLS 1.3で定義されたグループには、x25519やsecp256r1などの楕円曲線と、RFC 7919由来のffdhe2048などの有限体がある。
ただし、TLS 1.3でもすべての通信が前方秘匿性を持つわけではない。事前共有鍵(PSK)だけで鍵を作る再開モードではアプリケーションデータの前方秘匿性が失われ、0-RTTで送るデータも前方秘匿性を持たない。PSKとDHEを組み合わせるモードなら前方秘匿性を保てる。これらはRFC 8446の2章に整理されている。
IKEでの使われ方
IPsecの鍵管理を行うIKEv2では、最初のIKE_SA_INIT交換で、暗号アルゴリズムの提案、乱数(ノンス)とともにDHの公開値をKEペイロードで交換する。ここで共有した値から、以降のIKEメッセージを保護する鍵を導出する。続くIKE_AUTH交換は、この鍵で暗号化したうえで相手を認証する。
IPsecの通信に使う子SAの鍵は、通常はIKE SAの鍵材料から導出する。子SAの作成や再鍵更新で使うCREATE_CHILD_SA交換では、KEペイロードを加えて新しくDHを行うこともできる。こうするとIKE SAの鍵が漏えいしても子SAの鍵を求められず、IPsecの設定項目で「PFS」と呼ばれる動作になる。手順はRFC 7296に定められている。IKEは通常UDPの500番ポートを使い、NATトラバーサルではUDPの4500番ポートも使う。
IKEでは使うDHグループを番号で指定する。RFC 3526では2,048ビットのグループが14番、3,072ビットが15番である。両端で提案するグループが一致しないとSAを確立できない。
グループ番号は、計算に使う方式やパラメータの大きさを識別する。有限体のMODPグループでは、この大きさを鍵長と表すことがある。歴史的なグループ1は768ビット、グループ14は2,048ビットである。同じ種類の計算では一般に大きな値ほど逆算が難しくなるが、処理負荷も増える。グループ1は安全性が不足するため、現在のIKEv2では使用しない。有限体と楕円曲線では安全性の関係が異なり、ビット数だけを横並びに比べることはできない。
設計・運用で確認すること
DHの設定で迷ったときは、次の観点を順に確認する。
| 観点 | 確認すること |
|---|---|
| グループの強さ | 小さすぎる有限体グループを候補から外し、2,048ビット以上や楕円曲線のグループを選んでいるか |
| 両端の一致 | VPNの両端で、DHグループやPFSの有無の設定がそろっているか |
| 認証との組合せ | 証明書や事前共有鍵などの認証が設定され、公開値の差し替えを検出できるか |
| 処理負荷 | 大きな有限体グループは計算量が多い。接続数の多い装置では楕円曲線のグループも検討する |
| 監視・検査の方式 | サーバの秘密鍵を預けて記録済みの通信を後から復号する方式が使えるか |
最後の観点は見落としやすい。DHEやECDHEを使う通信では、サーバの秘密鍵を持っていても、記録した通信から共有値を計算できない。IDSなどがサーバの秘密鍵を使って通信を受動的に復号する設計は成り立たない。内容を検査するには、TLSを終端する装置やプロキシ型の検査装置を通信経路に置く必要がある。
VPNで「片方の拠点だけ設定を変えたらトンネルが張れない」という障害なら、まず両端の提案内容を比べる。DHグループの番号、子SAでのPFSの有無とそのグループがずれていないかを、ログに出る提案内容と照合する。
参考資料
- RFC 2631:Diffie-Hellman Key Agreement Method
- RFC 3526:More Modular Exponential (MODP) Diffie-Hellman groups for IKE
- RFC 7748:Elliptic Curves for Security
- RFC 7296:Internet Key Exchange Protocol Version 2 (IKEv2)
- RFC 8446:The Transport Layer Security (TLS) Protocol Version 1.3
- RFC 8247:IKEv2で使う暗号アルゴリズムとDHグループの要件
実際の試験ではここに出る!全1問
ネットワークスペシャリスト
- 午後Ⅰ