Deffie-Hellman 密钥交换算法
Whitfield Diffie 和 Martin Hellman 于 1976 提出该算法
是一种密钥交换算法,用于在不安全的信道上安全的交换密钥。
本篇文章, 我们以 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
为例,来学习一种 TLS Key 交换算法.: DHE key 交换算法
.
DH 算法已经很少见了,且不支持 PFS, 因此很少被使用. 这里, 我们通过 DHE 来学习一下.
数学基础
离散对数问题
假定 a, p 均是素数,下面两个集合相等
{
a
1
%
p
,
a
2
%
p
,
.
.
.
,
a
(
p
−
1
)
%
p
}
=
{
1
,
2
,
.
.
.
,
p
−
1
}
\{a^1 \% p, a^2 \% p, ..., a^{(p-1)} \% p \} = \{1, 2, ..., p - 1 \}
{a1%p,a2%p,...,a(p−1)%p}={1,2,...,p−1}
上述式子可概括成以下三点,对于
1
<
=
x
,
y
<
=
p
−
1
1 <= x,y <= p - 1
1<=x,y<=p−1,有:
- a x % p a^x \% p ax%p 一定属于 { 1 , 2 , . . . , p − 1 } \{1,2,...,p-1\} {1,2,...,p−1}
- 如果 x ! = y x!=y x!=y, 那么 a x % p ! = a y % p a^x \% p != a^y \% p ax%p!=ay%p
- 对于 1 < = b < = p − 1 1<=b<=p-1 1<=b<=p−1, 一定存在唯一的 1 < = x < = p − 1 1<=x<=p-1 1<=x<=p−1 使得 b = a x % p b=a^x \% p b=ax%p
已知 x 求 b 非常容易,已知 b 求 x 非常困难,特别当 p 很大时,求解的复杂度非常高,所以它又被称为离散对数问题,它是 DH 算法能够安全交换密钥的基础!
求模公式
假设 q 为素数,对于正整数 a,x,y,有:
(
a
x
%
p
)
y
%
p
=
a
(
x
y
)
%
p
(a^x \% p)^y \% p = a^{(xy)} \% p
(ax%p)y%p=a(xy)%p
证明略。
算法原理
假设 A, B 两方进行通信前需要交换密:
- 首先 A A A, B B B 共同选取 p p p 和 a a a 两个素数,其中 p p p 和 a a a 均公开。
- 之后 A A A 选择一个自然数 X a X_a Xa,计算出 Y a Y_a Ya, X a X_a Xa 保密, Y a Y_a Ya 公开;同理, B B B 选择 X b X_b Xb 并计算出 Y b Y_b Yb,其中 X b X_b Xb 保密, Y b Y_b Yb 公开。
- 之后 A A A 用 Y b Y_b Yb 和 X a X_a Xa 计算出密钥 K K K,而 B B B 用 Y a Y_a Ya 和 X b X_b Xb 计算密钥 K K K,
大体步骤如下:
- 全局公开参数:
- p: primary number
- a: primary number, a < p
- A 方: 选择一个 Xa(Xa < p), 生成 Ya (Ya = a^Xa mod p )
- B 方: 选择一个 Xb(Xb < p), 生成 Yb (Yb = a^Xb mod p)
- A 方: 通过 K = Yb^Xa mod p 计算得到私钥 K
- B 方: 通过 K = Ya^Xb mod p 计算得到私钥 K
上面一共出现了 a, p, Xa, Ya, Xb, Yb, K 共 7 个数,其中:
- 公开的数:a, p, Ya, Yb
- 非公开数:Xa, Xb, K
TLS 握手过程
使用 DHE Key 交换算法的 TLS 握手流程大体如下:
Client Server
ClientHello{CipherSuites: TLS_DHE_RSA_...} -->
<-- ServerHello{CipherSuite: TLS_DHE_RSA_...}
<-- Certificate(RSA)
<-- ServerKeyExchange**
<-- ServerHelloDone
ClientKeyExchange** -->
ChangeCipherSpec -->
EncryptedHandshakeMessage -->
<-- ChangeCipherSpec
<-- EncryptedHandshakeMessag
过程解析
ServerKeyExchange
当客户端和服务器端发送过 ClientHello 和 ServerHello,决定使用 DHE key 交换算法后。 服务器端需要做以下工作:
- 生成用于 DH Key 交换的参数: p, g(也就是上面说的 a), 和自己的私钥(Xs)和公钥(Ys)
- 其中 p,g, Ys 部分是要通过 ServerKeyExchange 数据包发送给客户端的
- 为了保证这个数据包不被修改,服务器端还会使用自己配置的证书对其进行签名
TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 655
Handshake Protocol: Server Key Exchange
Handshake Type: Server Key Exchange (12)
Length: 651
Diffie-Hellman Server Params
p Length: 256
p: ffffffffffffffffc90...
g Length: 1
g: 02
Pubkey Length: 256
Pubkey: 72ce8c26a1ff2814482fb0335841e...
Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
Signature Length: 128
Signature: b06738ba2c870c14fb2..
ClientKeyExchange
客户端在收到来自服务器端的 ServerKeyExchange 之后:
- 校验次数据包的签名是否正确
- 从里面解析 p,g, Ys, 并生成客户端的 Xc, Yc. 通过 Xc, p, g, Ys 便可计算得出 K。
- 把 Yc 通过 ClientKeyExchange 发送给服务器端. 当服务器端收到这个包之后,也可以计算得出相同的 K。 至此, Key 交换完成。
Handshake Protocol: Client Key Exchange
Handshake Type: Client Key Exchange (16)
Length: 258
Diffie-Hellman Client Params
Pubkey Length: 256
Pubkey: 73982e38f296cd0742...