首页/安全/加密与证书速查/HKDF 密钥派生(RFC 5869)
加密算法基础95 条

HKDF 密钥派生(RFC 5869)

两阶段通用 KDF:先从输入提取伪随机密钥(Extract),再按上下文标签扩展出多个子密钥(Expand);TLS 1.3 用它派生握手与记录层全部密钥。

加密与证书速查安全更新于 2026-10-13

HKDF 是什么

HKDF 是 RFC 5869 定义的两阶段通用密钥派生函数。第一阶段 Extract 把输入密钥材料压缩成固定长度的伪随机密钥 PRK,作用是把分布不均匀的熵「提纯」;第二阶段 Expand 用 PRK 加上上下文标签 info 扩展出任意长度、彼此独立的子密钥。TLS 1.3 的密钥调度完全建立在它之上,握手密钥与记录层密钥都由它派生。

基本信息

阶段一Extract(salt, IKM) → PRK
阶段二Expand(PRK, info, L) → OKM
适用输入已具备一定熵的共享秘密、DH 协商输出
不适用输入低熵口令,应先经过慢散列
salt可省略,省略时按全零处理
隔离手段不同用途必须使用不同的 info 标签

典型使用场景

  • 从 DH 或 ECDH 协商出的共享秘密派生会话密钥,为加密与认证分配不同子密钥
  • 实现 TLS 1.3 风格的密钥调度:用握手上下文派生每条记录的独立密钥
  • 文件加密生成数据密钥:主密钥经 HKDF 扩展出每份文件各自的密钥
  • 协议设计里把一次协商结果拆成多个方向、多个用途的密钥
  • 做密钥版本管理:info 中携带版本号,升级前后派生出互不干扰的密钥

Python 示例(cryptography)

Python 示例(cryptography)
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

# 同一共享秘密派生两把用途不同的密钥,靠 info 标签隔离
enc = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b'enc-key').derive(shared_secret)
mac = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b'mac-key').derive(shared_secret)
# info 中带上协议版本与实体标识,避免不同场景派生出一把密钥

参数读法

参数作用取值建议
saltExtract 阶段的初始盐有协议上下文时传明确值,无则省略
info绑定派生用途的标签包含用途、版本与实体标识
length输出长度按算法需要,不超过 255 倍哈希长度
TLS 1.3 的密钥调度使用 HKDF-Expand-Label,把握手上下文(Transcript-Hash)作为输入,实现每条记录密钥的独立派生。
HKDF 假设输入已有足够熵:它不增加计算代价,也不会慢化攻击者的尝试。低熵口令必须先经过 PBKDF2、scrypt 或 Argon2id,再交给 HKDF 扩展。
info 标签最容易被忽视:同一 PRK 派生的密钥如果 info 相同,得到的其实是同一把密钥,多用途共用会让某一处的泄露波及全部场景。

易错点

  • HKDF 不慢化输入:对低熵口令直接使用会让暴力破解变得廉价
  • salt 传空是允许的,但同一 PRK 派生的多路密钥必须用不同 info 标签隔离
  • 派生长度设得过大:超过 255 倍哈希长度的输出不被规范允许
  • 用同一 info 标签为加密与认证派生密钥,会让两者的失败模式相互牵连
  • 协议升级时不更新 info 中的版本标识,导致新旧版本派生出相同密钥

数据来源与参考

  • RFC 5869(HKDF)
  • RFC 8446 §7.1(TLS 1.3 密钥调度)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌