Key derivation function
密钥导出函数 (KDF)是一种密码算法,它从现有秘密(例如共享密钥、密钥协商结果或密码)以及上下文信息和其他参数中派生出一组或多组密钥材料。[1] KDF 让协议将一个秘密转换为所需长度的密钥,并将单独的密钥分配给不同的用途。
该术语涵盖两个相关但不同的类别。一个 基于密钥的 KDF 从已经具有强大加密强度的输入开始。一个 基于密码的 KDF 从人类选择的密码或密码短语开始,并故意提高测试猜测的成本。混淆两者可能会产生不安全的设计:快速的通用 KDF 并不能使弱密码抵抗离线猜测。
基于密钥的派生
协议通常通过密钥协商操作获得初始秘密,然后需要不同的密钥进行加密、消息身份验证或不同的连接方向。 KDF 可以将秘密与标签和上下文(例如协议标识符、参与方身份或转录数据)结合起来,以便将不同目的的输出分开。
NIST SP 800-108 指定了基于伪随机函数(包括 HMAC、CMAC 和 KMAC)的计数器、反馈和双管道结构。[2] 确切的结构及其输入是协议规范的一部分;仅对秘密进行散列而不进行域分离可能无法提供所需的属性。
提取并扩展
HKDF 是 RFC 5869 中标准化的基于 HMAC 的 KDF。它遵循 提取然后扩展 设计。提取阶段将潜在的不一致输入密钥材料转换为固定长度的伪随机密钥。扩展阶段在绑定可选上下文信息的同时导出一个或多个输出。[3]
HKDF 适用于加密密钥材料,例如 Diffie-Hellman 结果。当可以从小字典中猜测输入时,它是有意提高效率的,并且不能替代密码散列方案。
基于密码的推导
基于密码的 KDF 将密码与盐和成本参数结合起来。盐通常与结果一起存储,无需保密。其目的是使相同的密码产生不同的输出,并防止一张预先计算的表在许多记录中重复使用。工作因素使得每一次猜测对于合法系统和攻击者来说都更加昂贵。[4]
PBKDF2 重复应用伪随机函数,并由 PKCS #5 和 NIST 指南指定。其主要可调整成本是迭代计数。该参数必须针对应用程序和硬件进行选择,并且应在兼容性允许的情况下随着时间的推移而增加;不存在适合每个系统的永久迭代计数。
现代密码散列方案还可以施加可配置的内存成本。内存困难函数的目的是使大规模猜测不仅在处理器操作方面而且在内存和带宽方面都变得昂贵。 scrypt, Argon2 和 Lyra2 是该系列的设计示例。 RFC 9106 指定了 Argon2,并推荐使用混合 Argon2id 变体进行一般密码哈希处理,并根据可用内存和延迟选择配置文件。[5]
用途
KDF 用于:
- 密钥交换后导出流量密钥和初始化材料;
- 从一个主密钥创建单独的加密和身份验证密钥;
- 将密钥绑定到协议、会话、身份或目的;
- 从密码导出存储加密密钥;
- 存储从密码而不是密码本身派生的验证器;和
- 生成另一个加密原语所需的精确长度的密钥。
密码验证器和加密密钥都可以是基于密码的推导的输出,但它们周围的威胁模型不同。密码验证必须限制在线尝试并保护验证者数据库;存储加密还必须考虑如何删除、保留和恢复派生密钥。
安全考虑
KDF 的安全性取决于其输入的强度、构造、参数选择和上下文绑定。 KDF 无法创建可猜测密码中不存在的熵。盐可以防止交叉记录预计算,但不需要猜测,并且它们本身不会减缓有针对性的攻击。
对于基于密码的使用,应在实际部署中校准成本参数,以便合法使用仍然可以接受,而猜测的成本很高。实现还必须绑定攻击者控制的参数以避免拒绝服务,比较密码验证程序而不泄露有用的计时信息,并在成功身份验证后迁移旧参数集。 秘密服务器端值(有时称为胡椒)可以添加单独的保护层,但不能替代唯一的盐或合适的密码散列函数。
对于基于密钥的使用,应用程序应遵循其协议定义的 KDF,而不是发明新的组合。对不相关的算法重复使用一个派生密钥或省略协议上下文可能会破坏使用之间的分离。
标准和历史发展
早期的 Unix 密码存储是现代基于密码的 KDF 的重要前身。罗伯特·莫里斯 (Robert Morris) 和肯·汤普森 (Ken Thompson) 在 1979 年的叙述中描述了 地穴 该设计使用前 8 个密码字符作为密钥,应用修改后的 DES 计算 25 次,并选择 4,096 个具有 12 位盐的变体之一。[6] 盐阻碍了在所有帐户中重复使用一个预先计算的字典,而重复计算增加了当代硬件上每次猜测的成本。固定的限制和不断增加的计算能力最终使该方案不适合现代密码保护。
后来的密码哈希引入了可调整的成本参数和更强的原语。 Bcrypt 在 20 世纪 90 年代添加了适应性工作因素; scrypt 添加了可配置的内存成本;密码哈希竞赛选择了 Argon2,同时对 Catena、Lyra2、Makwa 和 yescrypt 给予特别认可。[7] 这些函数不能互换,仅仅是因为每个函数都可以处理密码:应用程序必须遵循所选函数的编码、参数和迁移规则。
NIST SP 800-132 指定了基于 PBKDF2 的派生来保护存储的数据,并带有 NIST 计划修订该出版物的通知。[8] 当前的 NIST 数字身份指南要求使用合适的方案进行加盐密码散列,并推荐使用难记忆函数。这些要求适用于密码验证器;它们不应该被概括为每个加密 KDF 都必须很慢或内存困难的主张。[9]
参考
- ↑ NIST Computer Security Resource Center, “Key-derivation function”, accessed 13 September 2026
- ↑ NIST SP 800-108 Rev. 1, Recommendation for Key Derivation Using Pseudorandom Functions, updated 2 February 2024
- ↑ Hugo Krawczyk and Pasi Eronen, RFC 5869, “HMAC-based Extract-and-Expand Key Derivation Function”, May 2010
- ↑ K. Moriarty, B. Kaliski and A. Rusch, RFC 8018, PKCS #5: Password-Based Cryptography Specification Version 2.1, January 2017
- ↑ Alex Biryukov et al., RFC 9106, “Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications”, September 2021
- ↑ Robert Morris and Ken Thompson, “Password Security: A Case History”, Communications of the ACM, November 1979; Niels Provos, “Bcrypt at 25: A Retrospective on Password Security”, USENIX, 22 May 2023
- ↑ Password Hashing Competition, “Password Hashing Competition”, accessed 13 September 2026
- ↑ NIST SP 800-132, Recommendation for Password-Based Key Derivation: Part 1: Storage Applications, December 2010
- ↑ NIST SP 800-63B, Digital Identity Guidelines: Authentication and Authenticator Management, 2025
