TLS1.3---**的计算
TLS1.2中的PRF
通过对TLS1.2的学习,我了解到其中具有三种**:预主**、主**和会话**。
在其握手过程中,客户端和服务器都会根据密码套件生成自己的临时公私钥对,并且将公钥发送给对方,当客户端接收到服务器的公钥时,会生成预主**。
之后客户端会使用PRF函数计算出主**发送给服务器,计算时需要三个输入:
- 预主**
- 客户端生成的随机数
- 服务器生成的随机数
如果使用的是RSA,那么预主**的结构如下:
struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;
struct {
ProtocolVersion client_version;
opaque random[46];
} PreMasterSecret;
struct {
uint8 major;
uint8 minor;
} ProtocolVersion;
会话**也是通过PRF函数生成的,需要输入:
- 主**
- 客户端生成的随机数
- 服务器生成的随机数
Session ID 缓存和 Session Ticket 里面保存的也是主**,而不是会话**,这样每次会话复用的时候再用双方的随机数和主**导出会话**,从而实现每次加密通信的会话**不一样,即使一个会话的主**泄露了或者被**了也不会影响到另一个会话。
P_HASH算法
它使用一个 hash 函数扩展成一个 secret 和种子,形成任意大小的输出。其中的哈希函数取决于协商的密码套件。
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
其中的A():
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))
"+"表示连接,HMAC_hash的运算次数取决于想要结果的长度。
在计算不同类型的**时,对应的secret值也是不同的
HKDF
通过前面的介绍,我们已经大概了解了TLS1.2中的**生成实现过程,在TLS1.3中主要使用的是HKDF中的 HKDF-Extract 和 HKDF-Expand 函数,HKDF的主要的目标是获取一些初始的**材料,并从中派生出一个或多个安全强度很大的**。主要分为两步:
提取
HKDF-Extract(salt, IKM) -> PRK
使用协商好的哈希算法将输入的**尽量的伪随机化。
- Salt:输入,如果不提供则全部初始化为0的字符串,长度则为所采用哈希函数的散列值长度。
- IKM:输入,**材料,在TLS1.3中比较复杂。
- PRK:输出,伪随机化后的**,长度则为所采用哈希函数的散列值长度。
扩展
通过一系列的哈希运算,将**扩展到我们所需要的长度,有点类似TLS1.2中的P_HASH。
HKDF-Expand(PRK,info,L)-> OKM
- info:可选上下文和应用程序特定信息(可以是零长度字符串),我们可以理解为要计算**的名称。
- L:所需要的长度。
- OKM:计算得出的**结果
下面看一下OKM的计算方式:
N = ceil(L / HashLen)
T = T(1)| T(2)| T(3)| ... | T(N)
OKM = T的前L个八位位组,
其中:
T(0)= 空字符串(零长度)
T(1)= HMAC-Hash(PRK,T(0)| info | 0x01)
T(2)= HMAC-Hash(PRK,T(1)| info | 0x02 )
T(3)= HMAC-Hash(PRK,T(2)| info | 0x03)
...
(其中,连接到每个T(n)末尾的常数是一个
八位位组。)
n为0-255的整数,L除以所用哈希函数输出摘要的长度,再向上取整,我们将其记为n。
然后将T(n)串接起来,而我们想要获得的OKM正是取T的前L个字节组成。这要我们就得到了我们想要的**材料。
TLS1.3**计算
HKDF-Expand-Label(Secret, Label, Context, Length) =
HKDF-Expand(Secret, HkdfLabel, Length)
Where HkdfLabel is specified as:
struct {
uint16 length = Length;
opaque label<7..255> = "tls13 " + Label;
opaque context<0..255> = Context;
} HkdfLabel;
Derive-Secret(Secret, Label, Messages) =
HKDF-Expand-Label(Secret, Label,
Transcript-Hash(Messages), Hash.length)
Transcript-Hash 和 HKDF 使用的 Hash 函数是密码套件哈希算法,Hash.length 是其输出长度(以字节为单位)。消息是表示的握手消息的串联,包括握手消息类型和长度字段,但不包括记录层头,labels 都是 ASCII 字符串。
TLS 1.3 完整的**导出流程图
0
|
v
PSK -> HKDF-Extract = Early Secret
|
+-----> Derive-Secret(., "ext binder" | "res binder", "")
| = binder_key
|
+-----> Derive-Secret(., "c e traffic", ClientHello)
| = client_early_traffic_secret
|
+-----> Derive-Secret(., "e exp master", ClientHello)
| = early_exporter_master_secret
v
Derive-Secret(., "derived", "")
|
v
(EC)DHE -> HKDF-Extract = Handshake Secret
|
+-----> Derive-Secret(., "c hs traffic",
| ClientHello...ServerHello)
| = client_handshake_traffic_secret
|
+-----> Derive-Secret(., "s hs traffic",
| ClientHello...ServerHello)
| = server_handshake_traffic_secret
v
Derive-Secret(., "derived", "")
|
v
0 -> HKDF-Extract = Master Secret
|
+-----> Derive-Secret(., "c ap traffic",
| ClientHello...server Finished)
| = client_application_traffic_secret_0
|
+-----> Derive-Secret(., "s ap traffic",
| ClientHello...server Finished)
| = server_application_traffic_secret_0
|
+-----> Derive-Secret(., "exp master",
| ClientHello...server Finished)
| = exporter_master_secret
|
+-----> Derive-Secret(., "res master",
ClientHello...client Finished)
= resumption_master_secret