Diffie-Hellman 密钥交换
是什么
Diffie-Hellman(DH)是一套让两个互不认识的人,在所有人都能听到的公开广播频道上,协商出一个只有他俩知道的共享密钥的方法。
日常类比:两个人各自手里调一种秘密颜料。
- 大家先约好一种公开的”基础颜料”(黄色)
- Alice 偷偷往黄色里加一勺”红”,得到橙色,把橙色寄给 Bob
- Bob 偷偷往黄色里加一勺”蓝”,得到绿色,把绿色寄给 Alice
- Alice 拿到绿色再加自己的”红”,得到棕色
- Bob 拿到橙色再加自己的”蓝”,得到棕色
两人都得到棕色——但中间偷看的窃听者只看到黄、橙、绿,没法把橙和绿”反向拆”出红和蓝,所以也调不出棕色。
DH 把这个直觉用数学(指数运算 + 模素数)实现,让”调颜料”从比喻变成可计算、可证明安全的协议。
为什么重要
不理解 DH,下面这些事都没法解释:
- 为什么打开 https:// 网站时,浏览器和服务器第一次连接就能加密——它们没预共享密码,靠的就是 DH(或它的椭圆曲线版 ECDH)
- 为什么 SSH / VPN / WhatsApp / Signal 都说”端到端加密”——底层全部是 DH 协商出会话密钥
- 为什么 1976 年的论文叫《New Directions in Cryptography》——它第一次提出”公钥密码”概念,把密码学从”先共享密钥”时代推进到”零信任也能加密”
- 为什么一年后 rsa 出现就直接成为另一座大山——DH 给了 RSA 灵感
核心要点
DH 协议三步:
-
公开参数:选一个大素数
p和生成元g(p通常 2048 位以上)。这两个数全世界都能看到。 -
各自生成私钥 + 公钥:
- Alice 选一个秘密整数
a(私钥),算出A = g^a mod p(公钥),公开发出去 - Bob 选秘密整数
b,算出B = g^b mod p,公开发出去
- Alice 选一个秘密整数
-
各自计算共享密钥:
- Alice 拿到
B,算B^a mod p = g^(ab) mod p - Bob 拿到
A,算A^b mod p = g^(ab) mod p - 两人得到同一个值——这就是共享密钥
- Alice 拿到
为什么窃听者算不出来:他看到 g、p、A、B,要算 g^(ab) 必须先从 A = g^a 反推出 a。这叫”离散对数难题”(DLP):在大素数下没有已知高效算法,2048 位需要超算跑几亿年。
椭圆曲线版(ECDH):把”指数运算 + 模素数”换成”椭圆曲线上的点乘”,安全性同等的前提下,密钥从 2048 位缩到 256 位,计算快几十倍。现代 TLS / Signal 默认用 ECDH。
实践案例
案例 1:toy DH 手算一遍
参数:p = 23、g = 5。
- Alice 选
a = 4,算A = 5^4 mod 23 = 625 mod 23 = 4 - Bob 选
b = 3,算B = 5^3 mod 23 = 125 mod 23 = 10 - 公开交换 A 和 B
- Alice 算
10^4 mod 23 = 10000 mod 23 = 18 - Bob 算
4^3 mod 23 = 64 mod 23 = 18
共享密钥 = 18。窃听者看到 p=23, g=5, A=4, B=10,要算 18 必须先从 5^x mod 23 = 4 反推 x——p=23 太小一秒就破,但换成 2048 位素数就是宇宙时间。
案例 2:TLS 1.3 握手简化版
Client Server | ClientHello (g, p, A=g^a) | |---------------------------------->| | | 生成 b,算 B=g^b、shared=A^b | ServerHello (B=g^b) + 加密内容 | |<----------------------------------| | 算 shared=B^a,解密后续 |TLS 1.3 一个 RTT(往返)就完成密钥协商 + 第一段加密数据,比 1.2 的两个 RTT 快一倍。
案例 3:openssl 命令行体验
# 生成 DH 参数(这一步慢,几分钟)openssl dhparam -out dhparams.pem 2048
# 生成 Alice 的私钥 + 公钥openssl genpkey -paramfile dhparams.pem -out alice.pem
# 提取公钥发给 Bobopenssl pkey -in alice.pem -pubout -out alice.pub踩过的坑
-
中间人攻击(MITM):原始 DH 不验证身份。攻击者站中间,分别和 Alice / Bob 各跑一次 DH,两边都以为在和对方说话,实际都是和攻击者说。修复:DH 必须配数字签名(如 RSA / ECDSA 签公钥),这就是 TLS 里”证书 + DH”的组合。
-
短素数被破(Logjam 2015):当年很多服务器为了兼容旧浏览器,用 512 位素数。研究者用学术级算力 1 周破了——影响 8% 的 HTTPS 站。教训:素数 < 2048 位别用。
-
静态 DH 没前向保密:如果 Alice 的私钥
a长期不变,攻击者今天截获密文存档,未来某天偷到a,就能解密所有历史会话。修复:每次会话用临时 DH(Ephemeral DH,DHE / ECDHE),私钥用完即扔。这是”前向保密”(Forward Secrecy)的来源。 -
不要自己实现:随机数生成器有偏 / 模幂运算时序泄露 / 参数选错 → 全是漏洞历史。用 OpenSSL / libsodium,别造轮子。
适用 vs 不适用场景
适用:
- 双方初次通信、没预共享密钥时协商会话密钥(HTTPS / SSH / VPN / IM)
- 需要前向保密的场景(用 ECDHE)
- 后续配对称加密用——DH 只协商密钥,加密本身用 AES 等
不适用:
- 直接加密大段数据 → 用 aes 等对称密码,DH 只是给 AES 提供密钥
- 数字签名 / 身份认证 → 用 RSA / ECDSA / Ed25519,不是 DH
- 后量子时代 → Shor 算法能用量子计算机破 DLP;2024 起标准转向 Kyber 等后量子 KEM
历史小故事(可跳过)
- 1976 年:Whitfield Diffie 和 Martin Hellman 在斯坦福发表《New Directions in Cryptography》——第一篇公开提出”公钥密码”概念的论文
- 1977 年:MIT 三人组(Rivest、Shamir、Adleman)受 DH 启发,造出 rsa——第一个能签名 + 加密的公钥算法
- 1985 年:Koblitz / Miller 提出椭圆曲线密码,后来演化成 ECDH
- 1997 年:英国 GCHQ 解密档案——他们 1969 年内部已经发现类似想法,但保密 28 年
- 2017 年:TLS 1.3 把所有非前向保密的密钥交换扔掉,强制 (EC)DHE
- 2024 年:NIST 标准化 Kyber,准备后量子时代——但 DH 仍会和 Kyber 混合用很多年
学到什么
- 公开通道也能协商秘密——这是密码学过去 50 年最反直觉的结论
- 难题驱动安全:DH 的安全性不靠”藏算法”,靠”DLP 计算上不可行”。算法完全公开
- 协议要配身份验证:DH 单用必被中间人攻击,必须配签名——给后来的 TLS / Signal 协议设计立了规矩
- 前向保密是重要属性:临时密钥让”今天截获、明天偷钥匙”的攻击失效
- 理论先行:1976 论文提出概念,工业落地花了 20 年(1995 SSL 才铺开)
延伸阅读
- 视频:Computerphile — Diffie Hellman -the Mathematics bit(10 分钟把数学讲透)
- 教材:Katz & Lindell《Introduction to Modern Cryptography》第 11 章——DH 的形式化定义和证明
- 论文 PDF:Diffie-Hellman 1976 原文(10 页,前 3 页就是核心思想)
- 互动可视化:CrypTool Online — DH(可改参数玩协议)
关联
- rsa —— DH 一年后的兄弟算法;DH 协商密钥、RSA 签名 + 加密;现代 TLS 同时用两者
- aes —— DH 协商出来的密钥用来给 AES 当对称密钥,两者搭档
- turing-1936 —— 计算可行性的边界;DH 安全性建立在”DLP 计算上不可行”之上
反向链接
- aes —— AES Rijndael 对称分组密码
- bitcoin —— Bitcoin 白皮书
- diffie-hellman-1976 —— New Directions 1976 — 给协议世界写下公钥宪法
- dwork-dp-icalp-2006 —— 差分隐私 — ε 与邻接数据集不可区分
- element-android —— Element Android — Matrix 协议官方 Android 客户端(Kotlin + Realm)
- logjam-2015 —— Logjam 2015 — 全世界共用一把锁,国家级窃听者一次撬完
- matrix-rust-sdk —— matrix-rust-sdk — Matrix 客户端的”共享发动机”
- rsa —— RSA 公钥密码
- saltzer-1984-e2e —— End-to-End Arguments — 把功能尽量推到端上做
- signal-android —— Signal Android — 让 Android 上的每条消息都只有两端能看见
- signal-ios —— Signal iOS — 让 iPhone 上的每条消息都只有两端能看见
- tamarin-2012 —— Tamarin — 让计算机自己证 Signal、TLS 1.3 这种带 DH 的协议是不是真安全
- turing-1936 —— Turing 1936 可计算性