深入理解 TLS 密钥协商

前置知识

阅读本文前,你需要先学习:

深入理解数字证书和 CA 这篇文章中,我们学习了 HTTPS 如何通过数字证书验证服务器身份,防止中间人攻击。

文章讲到,浏览器通过证书链验证服务器身份后,就可以开始加密通信了。但是,具体怎么进行加密通信呢?

你可能会想:既然有了服务器的公钥,直接用它加密数据不就行了?

直接用非对称性加密和解密大量数据的效率比较差,所以最早的 TLS 版本(TLS 1.0/1.1/1.2)支持一种简单的密钥交换方式:RSA 密钥交换

流程很直接,用非对称性秘钥加密一个对称性会话秘钥,然后用这个会话密钥进行加密通信:

  1. 浏览器验证服务器证书后,从证书中获取服务器的 RSA 公钥。
  2. 浏览器生成一个随机密钥,叫做「预主密钥」(Pre-Master Secret)。
  3. 浏览器用服务器的 RSA 公钥加密这个预主密钥。
  4. 发送给服务器,只有服务器能用私钥解密。双方对这个预主密钥做一些处理,推导出一个共享的会话密钥。
  5. 之后的通信都用会话密钥加密(对称加密,速度快)。

这个方案简单直接,证书的公钥既用于验证身份,又用于加密预主密钥。但是,RSA 密钥交换有一个致命的安全隐患:缺乏前向保密性(Forward Secrecy)。

想象这个场景:

2024年:黑客录制了你和银行服务器的加密通信,包括:

  • 浏览器发送的预主密钥
  • 所有加密的通信数据

2026年:银行服务器的私钥泄露了,黑客就可以:

  • 用泄露的私钥解密 2024 年录制的预主密钥
  • 推导出当年的会话密钥
  • 解密当年的所有加密通信数据

只要服务器的私钥泄露,过去所有使用 RSA 密钥交换的通信都会被破解。这对于需要长期保密的数据(比如医疗记录、金融交易)来说,是不可接受的安全风险。

因此,现代 TLS 放弃了 RSA 密钥交换,转而使用 Diffie-Hellman 密钥交换

Diffie-Hellman 密钥协商算法

Diffie-Hellman(DH)密钥交换是一种神奇的算法,它允许双方在不安全的信道上协商出一个共享密钥,即使黑客监听了整个过程,也无法计算出这个密钥。

就好比说,我们俩当着全世界的面,互相报几个数字,就可以拥有一个只有我们俩知道的秘密,而其他人却无法知道这个秘密。

听起来很玄乎,但其实原理并不复杂。

生活化比喻

在讲数学原理前,先用一个生活化的比喻来理解 DH 算法的核心思想。

假设 Alice 和 Bob 想在公开场合(黑客 Eve 在旁边监听)协商出一个共同的秘密颜色。

初始状态:
├─ 黄色是公开的基础颜色,Eve 知道
├─ Alice 有一个秘密颜色:红色,Eve 不知道
└─ Bob 有一个秘密颜色:蓝色,Eve 不知道

步骤 1:Alice 混合颜色
├─ Alice 把黄色 + 红色混合 → 得到橙色
└─ Alice 把橙色公开发送给 Bob(Eve 能看到橙色)

步骤 2:Bob 混合颜色
├─ Bob 把黄色 + 蓝色混合 → 得到绿色
└─ Bob 把绿色公开发送给 Alice(Eve 能看到绿色)

步骤 3:二次混合
├─ Alice 收到绿色,加入自己的红色 
|        绿色 + 红色 = 黄色 + 蓝色 + 红色 = 棕色
└─ Bob 收到橙色,加入自己的蓝色
         橙色 + 蓝色 = 黄色 + 红色 + 蓝色 = 棕色

结果:
├─ Alice 和 Bob 都得到了棕色(共享密钥)
└─ Eve 只能看到:黄色、橙色、绿色,无法得到棕色
    └─ 因为 Eve 不知道 Alice 的红色和 Bob 的蓝色

这里面的关键原理在于:颜色混合是不可逆的。Eve 看到橙色,无法反推出是黄色 + 什么颜色混合的。

这就是 DH 算法的核心思想:利用数学上的「单向函数」,让监听者无法反推出秘密。

DH 算法的数学原理

真实的 DH 算法用的不是颜色混合,而是模幂运算(Modular Exponentiation)。

模幂运算有一个特性:计算很容易,但逆运算(离散对数)很难:

  • 已知 ggxxpp,计算 gxmodpg^x \bmod p 的结果 yy 很容易。
  • 已知 ggpp 和结果 yy,反推 xx 几乎不可能(当 pp 很大时)。

这个困难的反推问题叫做离散对数难题,是现代密码学的基础之一。

DH 算法完整流程

下面用一个详细的流程图和具体数值示例来说明 DH 算法。

第 1 步:协商公开参数

双方先协商两个公开的数字(Eve 可以看到):

  • p=23p = 23(一个质数,作为模数)
  • g=5g = 5(一个生成元)

实际应用中,pp 是一个巨大的质数(2048 位或更长),这里为了演示用小数字。

第 2 步:各自生成私钥

Alice 生成私钥:a=6a = 6(随机选择,保密)

Bob 生成私钥:b=15b = 15(随机选择,保密)

私钥只在本地保存,不发送给任何人。

提示

本文所说的「私钥」不是指 非对称加密 中的「RSA 私钥」,而是指双方各自生成的一个保密的随机数。

第 3 步:计算并交换公钥

Alice 计算公钥:

A=gamodp=56mod23=15625mod23=8A = g^a \bmod p = 5^6 \bmod 23 = 15625 \bmod 23 = 8

Bob 计算公钥:

B=gbmodp=515mod23=30517578125mod23=19B = g^b \bmod p = 5^{15} \bmod 23 = 30517578125 \bmod 23 = 19

然后:

  • Alice 把 A=8A=8 发送给 Bob(Eve 能看到)
  • Bob 把 B=19B=19 发送给 Alice(Eve 能看到)

第 4 步:计算共享密钥

Alice 收到 Bob 的公钥 B=19B=19,计算:

s=Bamodp=196mod23=47045881mod23=2s = B^a \bmod p = 19^6 \bmod 23 = 47045881 \bmod 23 = 2

Bob 收到 Alice 的公钥 A=8A=8,计算:

s=Abmodp=815mod23=35184372088832mod23=2s = A^b \bmod p = 8^{15} \bmod 23 = 35184372088832 \bmod 23 = 2

神奇的事情发生了:Alice 和 Bob 都得到了相同的密钥 s=2s=2

为什么计算结果相同?

数学上可以证明:

Alice 计算:

Bamodp=(gb)amodp=g(ba)modpB^a \bmod p = (g^b)^a \bmod p = g^{(b \cdot a)} \bmod p

Bob 计算:

Abmodp=(ga)bmodp=g(ab)modpA^b \bmod p = (g^a)^b \bmod p = g^{(a \cdot b)} \bmod p

因为 ab=baa \cdot b = b \cdot a,所以结果相同。

这就是 DH 算法的"数学魔法"。

公开参数p=23p=23, g=5g=5(Eve 知道)

Eve 的困境

Eve 能看到的信息:

  • p=23p = 23
  • g=5g = 5
  • A=8A = 8
  • B=19B = 19

Eve 想计算共享密钥 ss,但需要知道 aabb

要从 A=8A=8 反推出 aa,需要解决:5amod23=85^a \bmod 23 = 8,求 aa

这就是离散对数问题,当 pp 很大时(实际应用中 pp 是 2048 位或更长),计算量是天文数字,即使用超级计算机也需要几百万年。

黑客为什么无法破解 DH 算法

离散对数难题

前面说了,从 gxmodpg^x \bmod p 的结果反推 xx 是极其困难的。

在经典计算机上,目前没有已知的高效算法能够在合理时间内解决大数的离散对数问题。

这是经过几十年密码学研究验证的数学难题。对于 2048 位的 pp,即使用超级计算机,破解也需要数百万年。

临时密钥

更重要的安全特性是:每次 TLS 连接都生成新的临时私钥,从而保证了前向保密性。

假设 2024 年你访问银行网站:

2024年的连接

  • 浏览器临时私钥 a1a_1(连接结束后从内存中删除)
  • 服务器临时私钥 b1b_1(连接结束后从内存中删除)
  • 共享密钥 s1s_1(加密通信,连接结束后删除)

即使黑客录制了整个通信过程,2026 年服务器的证书私钥泄露了:

黑客拥有的信息

  • 服务器证书私钥(2026年泄露)
  • 2024年的公开参数 pp, gg
  • 2024年的公钥 A1A_1, B1B_1
  • 2024年的加密通信数据

黑客无法获得的信息

  • 临时私钥 a1a_1(已从内存删除,永远无法恢复)
  • 临时私钥 b1b_1(已从内存删除,永远无法恢复)
  • 共享密钥 s1s_1(无法计算,因为缺少 a1a_1b1b_1

在这里,服务器的私钥只用于验证证书,完全不用于加密通信,所以即使证书私钥泄露也无法破解过去的通信。

ECDHE 密钥协商算法

实际应用中,TLS 不直接使用传统的 DH 算法,而是使用其椭圆曲线版本:ECDHE(Elliptic Curve Diffie-Hellman Ephemeral)

传统 DH 算法基于模幂运算 gxmodpg^x \bmod p,其中 xx 是双方各自生成的临时私钥。

椭圆曲线版本基于椭圆曲线点乘 xGx \cdot G,其中 xx 同样是私钥,GG 是椭圆曲线上的一个基点(公开参数)。

核心思想相同:正向计算容易,逆向计算困难。椭圆曲线的优势是密钥更短(256位椭圆曲线密钥 ≈ 3072位RSA密钥安全性),计算更快,特别适合移动设备。

总结

  • RSA 密钥交换:证书公钥直接加密预主密钥,简单但缺乏前向保密,TLS 1.3 已废弃。
  • Diffie-Hellman 算法:利用离散对数难题,双方在不安全信道上协商出共享密钥,监听者无法破解。
  • ECDHE:椭圆曲线版本的 DH,每次连接生成临时密钥对,用完销毁,实现前向保密。
  • 证书的角色:在 ECDHE 中,证书只用于签名验证身份,不参与密钥协商,因此证书私钥泄露也无法破解过去的通信。

现代 HTTPS 的完整流程:验证服务器证书(防中间人攻击)→ 用 ECDHE 协商临时密钥(前向保密)→ 用会话密钥加密通信(性能与安全兼顾)。