TLS 1.3 对密钥管理进行了重大改革,其中 HKDF (HMAC-based Key Derivation Function) 是核心组件。本文详细解释 HKDF 的工作原理以及在 TLS 1.3 中的实际应用。
什么是 HKDF?
HKDF 是一种基于 HMAC 的密钥派生函数,由 Hugo Krawczyk 和 Mihir Bellare 设计。它将短的输入密钥材料 (IKM) 扩展为更长的密钥,用于 TLS 握手后的各类密钥派生。
HKDF 由两个阶段组成:
- Extract(提取):将输入密钥材料转换为伪随机密钥
- Expand(扩展):从伪随机密钥派生出任意长度的输出
HKDF 工作原理
Extract 阶段
|
|
- Salt:可选的盐值(TLS 1.3 中使用空字符串或握手特定值)
- IKM:输入密钥材料(TLS 1.3 中为 DH 共享密钥)
- PRK:伪随机密钥(Pseudo Random Key)
Expand 阶段
|
|
- Info:上下文特定信息(TLS 1.3 中用于区分不同用途的密钥)
- T:计数器,扩展过程中逐步递增
- OKM:输出密钥材料
TLS 1.3 密钥派生流程
TLS 1.3 使用 HKDF 构建了清晰的密钥派生层级:
|
|
派生阶段详解
TLS 1.3 的 Derive-Secret 函数定义如下:
|
|
其中 Label 包含 tls13 前缀,用于区分不同用途:
| Label | 用途 |
|---|---|
tls13 early secret |
早期密钥材料 |
tls13 c e traffic |
客户端早期流量密钥 (0-RTT) |
tls13 s e traffic |
服务端早期流量密钥 (0-RTT) |
tls13 handshake secret |
握手密钥材料 |
tls13 c h traffic |
客户端握手流量密钥 |
tls13 s h traffic |
服务端握手流量密钥 |
tls13 master secret |
主密钥材料 |
tls13 application traffic |
应用层流量密钥 |
Python 验证 HKDF
使用 Python 的 cryptography 库可以验证 HKDF 派生过程:
|
|
输出长度为 32 字节(256 位),可用于 AES-256-GCM 加密。
TLS 1.3 密钥派生实例
以下是从 DH 共享密钥到应用层密钥的完整派生过程:
|
|
为什么使用 HKDF?
设计优点
- 灵活性:可从任意长度的输入派生出任意长度的输出
- 可证明安全性:基于 HMAC 的安全性证明
- 抗原像攻击:单向派生,无法从输出反推输入
- 上下文隔离:通过 Info 参数区分不同用途的密钥
TLS 1.3 改进
相比 TLS 1.2,TLS 1.3 的密钥派生:
| TLS 1.2 | TLS 1.3 |
|---|---|
| PRF (MD5/SHA) | HKDF (SHA-256/384) |
| 密钥交换与派生耦合 | 清晰的 HKDF 派生层级 |
| 4-RTT | 1-RTT 或 0-RTT |
实际应用
验证握手密钥
在调试 TLS 1.3 握手时,可以手动验证派生出的密钥:
|
|
排查 0-RTT 问题
0-RTT 使用 Early Secret 派生的密钥,如果遇到重放攻击问题,检查:
|
|
注意事项
- 密钥材料安全:输入密钥材料必须来自安全的密钥交换
- Info 参数:不同用途必须使用不同的 Info,防止密钥混淆
- 前向安全性:TLS 1.3 每个阶段使用独立的密钥,任何阶段泄露不影响其他阶段