Diffie-HellmanとForward Secrecy


SSLで使われる暗号化方式にもいろんなものがありますが、それぞれに違った特性を持っています。

RSAによる鍵交換

かつて一般的に使われていたRSA鍵交換はシンプルな手法で、鍵の素材となるpre_master_secretを、サーバー側の公開鍵で暗号化するというものでした。これを復号化できるのは秘密鍵を持ったサーバサイドだけ…ということになって、普通に考えれば安全性は確保できます。

しかし、たとえばハートブリードのように、秘密鍵が漏洩してしまったとしたらどうでしょうか。また、NSAなど国家機関が暗号化後のデータをすべて保存していて、あとから流出なり計算なりで特定した秘密鍵を当てはめる攻撃をしたとしたらどうでしょうか。

このような場合も、暗号通信の安全性を確保できるようにする方法として、Forward Secrecyがあります。

Diffie-Hellman鍵共有

RSA暗号は、離散対数問題($a^b \bmod n$ はすぐに計算できるけど、逆に $a^x \equiv k \pmod{n}$ の$x$は容易に計算できない)を利用した公開鍵暗号ですが、Diffie-Hellman鍵共有は同じ離散対数問題を使って、鍵共有を実現するアルゴリズムです。

まず、暗号パラメーターとして、素数 $p$ と、その上で$g^n \bmod p$が0~p-1まで全パターンを取るような$g$を用意します(これは毎回使いまわしでも問題ありません)。

通信しようとするアリスとボブは、それぞれ0~p-1の範囲内で $a$と$b$という数を用意して、これは自分だけの秘密としておきます。そして、$A = g^a \bmod p$、$B = g^a \bmod p$を計算して、適当な通信路で相手に送信します。

受け取った側では、自分の秘密の値と相手から受け取った値を掛け合わせることで、同じ値を共有できます($Ab \equiv aB \equiv g^{ab} \pmod{p}$)。一方で、この通信を傍聴していても、$A$と$B$からは同じ値を決めることができません。

なお、楕円曲線についても、同様な方法で「楕円曲線Diffie-Hellman鍵共有」が構築されています(詳細は省略します)。

Forward Secrecy

このようなDiffie-Hellman鍵共有をSSLの中に取り入れるとどうなるでしょうか。鍵の共有には、もはや証明書の鍵は無関係となり、この通信の解読を行おうとすれば、「この通信の」ハンドシェイクなどから暗号鍵を割り出す必要が出てきます。このように、秘密保持を証明書などの固定的な鍵に頼らない暗号化方式を、Forward Secrecyといいます。

また、DSA、ECDSAなど、証明書の鍵が証明専用のものの場合も、暗号鍵は別にやり取りするForward Secrecyを使うしかありません。

欠点、実装上の問題

歴史的経緯もあって、DHEでは鍵交換が1024ビットしかなく弱くなってしまう設定や実装が広まっていたということがありましたが、これはきちっと設定すれば回避できます。あと、巨大な素数をハンドリングするDHEは通常のRSAと比べて鍵交換が遅くなる、ということもありましたが、ECDHEはあまり変わらないぐらいのスピードが出ます。