1976 年,两个人证明了:素不相识的双方,可以在满是窃听者的房间里当众商定一个只有他们知道的秘密。
这是密码学的分水岭。在 Diffie 和 Hellman 之前,"共享密钥"这件事被认为必须事先线下完成。他们证明了这个"常识"是错的——而且解法优雅得近乎魔术。你每一次 HTTPS 握手,背后都在跑它的现代变体。
先忘掉数学,想象混合颜料。有一个关键的不对称:混合两种颜色很容易,但从混合色分离出原色几乎不可能(这就是第 14 章的单向函数)。Alice 和 Bob 隔空协商,当着窃听者 Eve 的面:
两人都得到了 "黄+红+蓝" 的混合色,而这个最终色他们从未直接传输过。Eve 看到了黄、橙、绿,但要配出那个棕色,她必须从橙色里"减掉"红或从绿色里"减掉"蓝——而分离颜色是做不到的。公共信道上跑的全是公开信息,共享秘密却凭空诞生了。
"混合颜色"的数学化身,就是第 14 章的模幂。公共色是 (g, p),秘密色是各自的私钥指数,"混合"就是求幂:
| 步骤 | Alice | Bob | Eve 看到 |
|---|---|---|---|
| 公共参数 | 约定素数 p 和底数 g | g, p | |
| 选私钥 | 秘密 a | 秘密 b | —(看不到) |
| 算公钥 | A = gᵃ mod p | B = gᵇ mod p | A, B |
| 交换 | ← 收到 B | 收到 A → | A, B 在信道上 |
| 算共享密钥 | s = Bᵃ mod p | s = Aᵇ mod p | ??? |
为什么两人算出同一个 s?因为指数可以交换顺序:
Eve 手里有 g, p, A=gᵃ, B=gᵇ,想算出 s=g^{ab},就必须先从 A 反推出 a(或从 B 反推 b)——这正是离散对数难题。p 一大,她就卡死了。这个"Eve 拿到两个公钥也算不出共享秘密"的假设,叫 计算性 Diffie-Hellman 假设(CDH)。
下面的 Demo 让你完整走一遍 DH。点"协商",看 Alice 和 Bob 各自算出相同的共享密钥。然后切到 Eve 视角:你只拿到公开信息,试试能不能在合理时间里算出共享密钥——参数小的时候你能暴力破(离散对数在小 p 下可解),但把 p 调大,你会亲身体会到那堵墙。
DH 完美抵御被动窃听者 Eve。但还记得第 1 章那个更坏的角色 Mallory(主动攻击者)吗?DH 对她毫无防备。
问题在于:DH 让双方协商出一把共享密钥,却没有验证对方的身份。Mallory 可以站在中间,对 Alice 假扮 Bob、对 Bob 假扮 Alice,和两边各做一次 DH:
于是 Mallory 拿到两把密钥,坐在中间:Alice 发来的消息她能解密、看完、再用另一把密钥重新加密转发给 Bob。双方全程以为通信是安全的,实际每个字都经过 Mallory 的手。这就是中间人攻击(MITM)。
裸 DH 只解决了"协商密钥",没解决"确认对方是谁"。要堵住 MITM,必须给 DH 的公钥加上认证——用数字签名证明"这个公钥确实来自 Bob"(第 18 章),而签名的可信又来自证书/CA 体系(第 18、19 章)。TLS 握手(第 19 章)本质就是"DH 协商密钥 + 证书签名认证身份"的组合。记住这条接缝:密钥交换和身份认证是两件必须同时做对的事——这正是第 1 章说的"错在接缝"。
① 前向保密(Forward Secrecy):实践中用临时(ephemeral)DH——每次会话都生成一次性的 a、b,用完即弃。好处是即使某天你的长期私钥泄露,攻击者也无法解密之前录下的历史流量,因为那些会话密钥早已不存在。这是 TLS 1.3 的强制特性,也是第 25 章 Signal 协议的核心思想。
② 椭圆曲线 DH(ECDH):把"素数钟面"换成"椭圆曲线"(第 17 章),用短得多的密钥达到同等安全。今天的 TLS/Signal 用的几乎都是 X25519 这个 ECDH 变体。原理完全一样,只是换了更高效的数学舞台。
DH 让双方协商出密钥,但我们还缺两样东西:一是能加密给特定公钥、二是能签名证明身份。这两件事,历史上第一个把它们一次性全做到的算法,就是大名鼎鼎的 RSA。下一章,我们亲手用小素数把它从密钥生成到签名完整跑一遍。
gˣ mod p 交换公钥,再互相求幂得 g^{ab}。