鋭い疑問だ。それを最初に解いたのが 1976 年の Diffie-Hellman 鍵共有なんだ。ざっくり言うと、二人で共通の素数 p と原始根 g を公開で決めておく。Alice は秘密の数 a を決めて A = g^a mod p を相手に送る。Bob も同じく b から B = g^b mod p を送る。すると二人とも g^(ab) mod p という同じ値に到達できるんだよ。上のシミュレーターで p=23, g=5, a=6, b=15 にすると、A=8, B=19、共通鍵 K=2 が出てくる。
🙋
え、A も B も公開で送るんですか?それを盗聴された人は鍵を計算できないんですか?
🎓
そこが鍵共有のミソだ。盗聴者は p, g, A, B を全部知っていても、A から a を逆算するには「離散対数問題」を解かなきゃならない。これが大きな p ではめちゃくちゃ難しいんだ。シミュレーターは p ≤ 997 の小さな素数しか扱わないから、現実には a を総当たりで見つけられてしまう。実運用では p を 2048 ビット以上にする。それで初めて計算量的に「事実上不可能」と言えるんだよ。
🙋
なるほど。でも Alice の K_A と Bob の K_B が同じ値になるのって、なんでですか?
🎓
単に指数法則だよ。$(g^a)^b = (g^b)^a = g^{ab}$ ——これは普通の数学でも成り立つけど、mod p のべき乗でも同じことが言える。Alice は B = g^b に自分の a をべき乗するから (g^b)^a = g^(ab)、Bob は A = g^a に自分の b をべき乗するから (g^a)^b = g^(ab)、結果は同じだ。シミュレーターで a, b をいろいろ変えても、必ず K_A = K_B になるのが見えるはず。
🙋
じゃあ Diffie-Hellman さえあれば暗号通信は完璧なんですか?
🎓
残念ながら、素の DH は「中間者攻撃」に弱いんだ。攻撃者が Alice にも Bob にもなりすまして、二人と別々に鍵共有を成立させちゃう。だから実用システムでは公開値に署名を付ける、サーバ証明書と組み合わせるなど、相手を確実に認証する仕組みと一緒に使う。TLS の ECDHE はその典型例だね。
よくある質問
p が素数だと、g のべき乗 g^1, g^2, … g^(p-1) mod p が p 未満の全ての非ゼロ値を一度ずつ取る性質を持ちます(g が原始根の場合)。これにより秘密鍵 a の取りうる値の空間が最大化され、攻撃者の総当たりが厳しくなります。p が合成数だったり g の位数が小さいと、共通鍵の取りうる値が少なくなり安全性が低下します。
実運用では a, b は 256 ビット以上のランダム整数を使います。教育用のこのシミュレーターでは 1〜100 の小さな範囲にしていますが、現実にはこの大きさだと総当たりで一瞬で解読されます。重要なのは秘密鍵を毎回ランダムに生成すること。固定値だと過去の通信が将来漏れる可能性があります(前方秘匿性の喪失)。
ECDH は同じ DH の原理を、整数の mod p 演算ではなく楕円曲線上の点の加算で実現します。同じ安全性を、より小さな鍵サイズで達成できるのが利点です。例えば従来の DH で 2048 ビット必要なところを、ECDH なら 256 ビットで同等以上の安全性が得られます。スマホや IoT 機器など計算資源が限られる環境では ECDH が標準的に使われます。
直接そのまま使うのは推奨されません。実用では K を「鍵導出関数(KDF、HKDF など)」に通して、目的別に複数の鍵(暗号化用、認証用、初期化ベクトル用など)を派生させます。これにより、もし一部の鍵が漏れても他の用途に影響しにくくなり、また K の偏りを取り除いて疑似ランダム性を高めることができます。
実世界での応用
HTTPS と TLS:ブラウザが Web サイトに安全に接続する TLS プロトコルでは、鍵共有として ECDHE(楕円曲線 Diffie-Hellman 一時鍵)が標準的に使われています。サーバ証明書で相手を認証しつつ、各セッションで使い捨ての鍵を共有することで、サーバの長期秘密鍵が将来漏れても過去の通信が解読されない「前方秘匿性」を実現しています。
最も多い誤解は、「Diffie-Hellman で交換した鍵があれば、それだけで安全な暗号通信ができる」と考えてしまうことです。素の DH は中間者攻撃(MITM)に対して無防備で、攻撃者が Alice と Bob の間に割り込めば、両者と別々に鍵共有を成立させて全ての通信を解読できます。実用システムでは必ず「相手が本当に Bob か」を確かめる認証を組み合わせます。TLS ではサーバ証明書、SSH では既知ホストキー、Signal では識別キーフィンガープリントが、その認証の役割を果たします。
次に多いのが、「教育用デモの小さな p でも安全だろう」という油断です。このシミュレーターのように p ≤ 997 の小さな素数では、攻撃者が a の値を 1 から順に試して g^a mod p が公開値 A と一致するものを見つけるだけで、瞬時に秘密鍵が復元されます。実運用では p を最低 2048 ビット(10 進で 600 桁以上)にするか、ECDH なら 256 ビット以上の楕円曲線パラメータを使います。安全性は p の大きさに指数的に依存するため、サイズの妥協は致命的です。
最後に、「秘密鍵 a, b を使い回しても問題ない」と考える誤解に注意してください。同じ秘密鍵を複数のセッションで使うと、過去のいずれかのセッション鍵が漏れた瞬間、その秘密鍵に基づく全てのセッションが復号されてしまいます。実用システムでは「各セッションごとに新しい a, b を生成して即座に破棄する」一時鍵方式(DHE / ECDHE の "E" は ephemeral の頭文字)を採用し、前方秘匿性を確保しています。