Diffie-Hellman(DH)密钥交换协议是现代密码学的基石之一,它解决了在不安全信道上协商共享密钥的难题。本文将讲解 DH 的原理,并通过 OpenSSL 演示实际操作。

问题背景

假设 Alice 和 Bob 想要通过公开信道协商一个共享密钥,用于后续的加密通信。如果信道被窃听者监听,如何安全地交换密钥?

传统方案需要一个安全的密钥传输渠道,但这往往不现实。Diffie-Hellman 协议巧妙地解决了这个问题:双方可以在公开信道上协商出共享密钥,而窃听者无法得知最终密钥

数学原理

离散对数难题

DH 的安全性基于离散对数难题

对于素数 p 和生成元 g,已知 g^a mod p 很容易计算,但从结果反推 a 却极其困难(当 p 足够大时)。

密钥交换流程

假设参数 p(大素数)和 g(生成元)已公开:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Alice                          Bob
----------------------------------------------
1. 选择私钥 a(随机数)      1. 选择私钥 b(随机数)

2. 计算公钥 A = g^a mod p    2. 计算公钥 B = g^b mod p

3. 发送 A 给 Bob  -------->  3. 接收 A

4. 接收 B        <--------   4. 发送 B 给 Alice

5. 计算 K = B^a mod p        5. 计算 K = A^b mod p
   = (g^b)^a mod p              = (g^a)^b mod p
   = g^(ab) mod p               = g^(ab) mod p

双方得到相同的 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 参数:

1
2
# 生成 2048 位 DH 参数(推荐)
openssl dhparam -out dhparam.pem 2048

输出示例:

1
2
3
4
5
6
Generating DH parameters, 2048 bit long safe prime
...++*++*++*++*++*++*++*
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA2ArBiD10WWXt6bTweo3pnh0YYACW5984Ejk3rrJBbN/QP7c57ez+
...
-----END DH PARAMETERS-----

查看 DH 参数内容

1
openssl dhparam -in dhparam.pem -text -noout

输出包含:

  • P:大素数(模数)
  • G:生成元(通常为 2)
1
2
3
4
5
DH Parameters: (2048 bit)
    P:   
        00:d8:0a:c1:88:3d:74:59:65:ed:e9:b4:f0:7a:8d:
        ...
    G:    2 (0x2)

生成 ECDH 密钥

ECDH 使用椭圆曲线,更加高效:

1
2
# 生成 P-256 曲线的 EC 私钥
openssl ecparam -name prime256v1 -genkey -noout -out ecdh-key.pem

查看椭圆曲线密钥

1
openssl ec -in ecdh-key.pem -text -noout

输出示例:

1
2
3
4
5
6
7
8
9
Private-Key: (256 bit)
priv:
    b5:64:75:72:04:8c:5d:65:47:4f:dd:70:cb:98:c9:
    ...
pub:
    04:d7:97:9f:8a:e5:4a:e7:71:43:76:72:88:68:ae:
    ...
ASN1 OID: prime256v1
NIST CURVE: P-256

查看支持的椭圆曲线

1
openssl ecparam -list_curves

常用曲线包括:

  • prime256v1(P-256):最广泛使用,128 位安全
  • secp384r1(P-384):192 位安全
  • secp521r1(P-521):256 位安全

在 TLS 中的应用

TLS 握手中使用 DH/ECDH 进行密钥协商:

传统 DH 密钥交换

  1. 服务器发送 DH 参数和签名
  2. 客户端验证签名,生成临时私钥
  3. 双方计算预主密钥

ECDHE(临时 ECDH)

  1. 服务器发送 EC 参数和签名
  2. 客户端生成临时 EC 密钥对
  3. 双方通过 ECDH 计算共享密钥

ECDHE 的优势:每次会话使用临时密钥,提供前向保密(Forward Secrecy),即使服务器私钥泄露,历史会话也无法解密。

安全注意事项

DH 参数安全

  • 避免使用 1024 位及以下的 DH 参数
  • 使用强随机数生成器
  • 服务器应优先使用 ECDHE 而非固定 DH

已知攻击

攻击名称 原理 防护
Logjam 弱 DH 参数攻击 使用 2048 位以上参数
Small Subgroup 小子群攻击 验证参数合法性
Invalid Curve 无效曲线攻击 实现时验证公钥

Nginx 配置示例

1
2
3
4
5
6
7
# 使用 ECDHE(推荐)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;

# 如需支持传统 DH(不推荐)
# ssl_dhparam /path/to/dhparam.pem;

TLS 1.3 已移除静态 DH,仅保留 ECDHE,进一步提升了安全性。

总结

Diffie-Hellman 密钥交换协议是 TLS 安全通信的基础:

  • 传统 DH 需要较长的参数,计算开销大
  • ECDH 在相同安全级别下效率更高
  • TLS 1.3 强制使用 ECDHE,提供前向保密
  • OpenSSL 可生成和管理 DH 参数

理解 DH 原理有助于正确配置 TLS 服务器,选择合适的密钥交换方式。

参考来源