TLS 1.2 中的 PRF(伪随机函数)与密钥派生过程详解
题目描述
在 TLS 1.2 协议中,PRF(Pseudo-Random Function,伪随机函数)是一个核心组件,用于从主密钥(Master Secret)派生出会话所需的各类密钥材料(如客户端和服务器端的加密密钥、MAC 密钥、初始化向量等)。本题将详细讲解 TLS 1.2 中 PRF 的设计结构、工作流程,以及如何通过该 PRF 生成密钥块(key block),并最终分割出各个密钥。我们将专注于 TLS 1.2 中使用的基于 HMAC 的 PRF 结构。
解题过程
第一步:理解 PRF 在 TLS 1.2 中的作用与输入
TLS 1.2 的密钥派生分为两个主要阶段:
- 预主密钥 → 主密钥:使用 PRF 从预主密钥(Pre-Master Secret)、客户端和服务器随机数(ClientHello.random 和 ServerHello.random)计算得到 48 字节的主密钥(Master Secret)。
- 主密钥 → 密钥材料:再次使用 PRF,从主密钥、客户端和服务器随机数计算出一个足够长的密钥块(key block),然后按顺序分割出客户端写 MAC 密钥、服务器写 MAC 密钥、客户端写加密密钥、服务器写加密密钥等。
PRF 在两次计算中结构相同,只是输入参数不同。PRF 定义为:
PRF(secret, label, seed) = P_<hash>(secret, label + seed)
其中:
secret:密钥材料,第一阶段是预主密钥,第二阶段是主密钥。label:一个 ASCII 字符串标签,用于区分不同的派生用途(例如,"master secret" 或 "key expansion")。seed:种子,由客户端随机数和服务器随机数拼接而成。P_<hash>:一个扩展函数,使用两种哈希算法(在 TLS 1.2 中默认为 SHA-256 和 MD5)进行组合,但在大多数现代实现中,当使用 TLS 1.2 且密码套件指定了单一哈希算法(如 SHA-256)时,PRF 可简化为仅使用该种哈希算法的 HMAC。
为了通用性,我们讲解 TLS 1.2 RFC 中定义的、同时使用 MD5 和 SHA-1(或 SHA-256)的“传统”PRF 结构,这也是理解其设计的关键。
第二步:剖析 PRF 的核心扩展函数 P_hash
P_hash(secret, seed) 是一个基于 HMAC 的扩展函数,用于生成任意长度的伪随机字节流。
- 定义:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + HMAC_hash(secret, A(2) + seed) + HMAC_hash(secret, A(3) + seed) + ...
其中+表示字节拼接。 - A(i) 的计算:
A(0) = seedA(1) = HMAC_hash(secret, A(0))A(2) = HMAC_hash(secret, A(1))A(3) = HMAC_hash(secret, A(2))- ...
- 通用公式:
A(i) = HMAC_hash(secret, A(i-1)),其中i >= 1。
- 工作原理:
- 首先计算
A(1) = HMAC_hash(secret, seed)。 - 输出第一块数据:
HMAC_hash(secret, A(1) + seed)。 - 计算
A(2) = HMAC_hash(secret, A(1))。 - 输出第二块数据:
HMAC_hash(secret, A(2) + seed)。 - 重复此过程,直到生成的字节总数达到所需长度。
- 每次迭代都使用同一个
secret和seed,但A(i)不断更新,确保输出的每一块都不同。
- 首先计算
第三步:构建完整的 PRF——组合两种哈希算法
TLS 1.2 的 PRF 将两个 P_hash 实例(一个使用 MD5,一个使用 SHA-1 或 SHA-256)的输出进行异或(XOR)组合。
- 公式:
PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA256(S2, label + seed)。 - 密钥分割:
secret被分割成两半S1和S2。- 如果
secret长度是偶数,则S1取前半部分,S2取后半部分。 - 如果
secret长度是奇数,则S1取前半部分(包括中间字节),S2取后半部分(包括中间字节)。具体来说,S1 = secret[0 .. (length+1)/2],S2 = secret[(length-1)/2 .. length-1]。
- 如果
- 设计意图:这种组合利用了 MD5 的速度优势和 SHA 系列的安全性,旨在通过组合不同密码学原语来增强安全性(“组合密码学”思路)。但在 TLS 1.2 中,对于使用 SHA-256 的密码套件,PRF 可以直接用
P_SHA256单独实现,无需 MD5 参与。
第四步:密钥派生全过程示例(从主密钥到密钥块)
假设我们正在派生密钥材料,使用的密码套件需要以下密钥(长度取决于密码套件):
- 客户端写 MAC 密钥
- 服务器写 MAC 密钥
- 客户端写加密密钥
- 服务器写加密密钥
- 客户端写 IV(如果需要)
- 服务器写 IV(如果需要)
- 确定密钥块总长度:根据协商的密码套件,确定每个密钥和 IV 所需的字节数,将它们相加得到密钥块的总长度
key_block_length。 - 计算密钥块:
key_block = PRF(master_secret, "key expansion", server_random + client_random),直到输出key_block_length字节。
注意:这里 seed 是server_random + client_random,顺序固定。 - 分割密钥块:按照密码套件定义的固定顺序,将
key_block分割成独立的密钥和 IV。
例如:key_block = client_write_MAC_key || server_write_MAC_key || client_write_encryption_key || server_write_encryption_key || client_write_IV || server_write_IV。
每个部分按预定义长度依次切分。
第五步:总结与安全性要点
- 伪随机性:PRF 的设计目标是在
secret保密且seed公开的情况下,其输出在计算上不可区分于真正的随机串。 - 前向安全性:由于每次会话的
client_random和server_random不同,即使主密钥泄露,攻击者也无法推算出之前或之后会话的密钥材料。 - 密钥分离:通过使用不同的
label("master secret" 和 "key expansion")和不同的seed(随机数顺序可能不同),确保了不同阶段的密钥材料是独立的。 - 演进:在 TLS 1.3 中,PRF 被更简洁、更安全的 HKDF 所取代,但理解 TLS 1.2 的 PRF 对于掌握协议演进和遗留系统分析至关重要。
通过以上步骤,我们循序渐进地解析了 TLS 1.2 中 PRF 的结构、其核心组件 P_hash 的工作机制、以及如何利用 PRF 完成从主密钥到具体会话密钥的安全派生过程。