Diffie-Hellman(DH)密钥交换协议是现代密码学的基石之一,它解决了在不安全信道上协商共享密钥的难题。本文将讲解 DH 的原理,并通过 OpenSSL 演示实际操作。
问题背景
假设 Alice 和 Bob 想要通过公开信道协商一个共享密钥,用于后续的加密通信。如果信道被窃听者监听,如何安全地交换密钥?
传统方案需要一个安全的密钥传输渠道,但这往往不现实。Diffie-Hellman 协议巧妙地解决了这个问题:双方可以在公开信道上协商出共享密钥,而窃听者无法得知最终密钥。
数学原理
离散对数难题
DH 的安全性基于离散对数难题:
对于素数 p 和生成元 g,已知 g^a mod p 很容易计算,但从结果反推 a 却极其困难(当 p 足够大时)。
密钥交换流程
假设参数 p(大素数)和 g(生成元)已公开:
|
|
双方得到相同的 K = g^(ab) mod p,这就是共享密钥。窃听者只能获得 A 和 B,但无法计算出 ab。
传统 DH vs ECDH
传统 DH 使用大整数运算,需要较长的密钥才能保证安全:
| 密钥长度 | 安全等级 |
|---|---|
| 1024 位 | 已不安全 |
| 2048 位 | 推荐 |
| 4096 位 | 高安全 |
ECDH(椭圆曲线 Diffie-Hellman)使用椭圆曲线密码学,在相同安全级别下密钥更短:
| ECDH 曲线 | 等效 DH 长度 | 安全等级 |
|---|---|---|
| P-256 | 3072 位 | 128 位安全 |
| P-384 | 7680 位 | 192 位安全 |
| P-521 | 15360 位 | 256 位安全 |
OpenSSL 操作实践
生成 DH 参数
在 Nginx 等 Web 服务器中,需要预先生成 DH 参数:
|
|
输出示例:
|
|
查看 DH 参数内容
|
|
输出包含:
- P:大素数(模数)
- G:生成元(通常为 2)
|
|
生成 ECDH 密钥
ECDH 使用椭圆曲线,更加高效:
|
|
查看椭圆曲线密钥
|
|
输出示例:
|
|
查看支持的椭圆曲线
|
|
常用曲线包括:
- prime256v1(P-256):最广泛使用,128 位安全
- secp384r1(P-384):192 位安全
- secp521r1(P-521):256 位安全
在 TLS 中的应用
TLS 握手中使用 DH/ECDH 进行密钥协商:
传统 DH 密钥交换
- 服务器发送 DH 参数和签名
- 客户端验证签名,生成临时私钥
- 双方计算预主密钥
ECDHE(临时 ECDH)
- 服务器发送 EC 参数和签名
- 客户端生成临时 EC 密钥对
- 双方通过 ECDH 计算共享密钥
ECDHE 的优势:每次会话使用临时密钥,提供前向保密(Forward Secrecy),即使服务器私钥泄露,历史会话也无法解密。
安全注意事项
DH 参数安全
- 避免使用 1024 位及以下的 DH 参数
- 使用强随机数生成器
- 服务器应优先使用 ECDHE 而非固定 DH
已知攻击
| 攻击名称 | 原理 | 防护 |
|---|---|---|
| Logjam | 弱 DH 参数攻击 | 使用 2048 位以上参数 |
| Small Subgroup | 小子群攻击 | 验证参数合法性 |
| Invalid Curve | 无效曲线攻击 | 实现时验证公钥 |
Nginx 配置示例
|
|
TLS 1.3 已移除静态 DH,仅保留 ECDHE,进一步提升了安全性。
总结
Diffie-Hellman 密钥交换协议是 TLS 安全通信的基础:
- 传统 DH 需要较长的参数,计算开销大
- ECDH 在相同安全级别下效率更高
- TLS 1.3 强制使用 ECDHE,提供前向保密
- OpenSSL 可生成和管理 DH 参数
理解 DH 原理有助于正确配置 TLS 服务器,选择合适的密钥交换方式。