1. 密钥派生算法概述:什么是KDF、核心用途与哈希函数的区别

各位同学,咱们今天开始聊密钥派生算法。说实话,这个主题在密码学里不算最炫酷的,但绝对是最实用的之一。我在做安全协议设计的时候,几乎每个项目都绕不开它。

先问大家一个问题:你有一个用户密码,想用它来加密文件,你会直接把密码当密钥用吗?

千万别。我见过有人这么干,结果密码稍微弱一点,整个加密体系就崩了。那该怎么办?这时候就需要 KDF 出场了。

1.1 什么是KDF

KDF,全称 Key Derivation Function,中文叫密钥派生函数。说白了,它就是一个能把「原始密钥材料」变成「安全密钥」的工具。

原始密钥材料是什么?可能是你的登录密码、一个共享秘密、甚至是一段随机数。但这些材料往往不够「好」——要么太短、要么有规律、要么熵不够高。KDF 的作用就是把这些材料「加工」成适合密码学算法使用的密钥。

核心定义:KDF 是一个确定性函数,输入一个或多个密钥材料,输出一个或多个符合密码学要求的密钥。

我习惯把 KDF 比作一个「密钥工厂」:你扔进去一堆矿石(原始材料),它给你吐出精炼过的金属(安全密钥)。这个过程是确定的——同样的输入,永远得到同样的输出。

1.2 KDF的核心用途

KDF 的应用场景比你想象的要多。我列几个最常见的:

  • 密码存储:网站不会存你的明文密码,而是存密码经过 KDF 处理后的哈希值。你登录时,系统把输入的密码再跑一遍 KDF,比对结果。
  • 密钥派生:从一个主密钥派生出多个子密钥,分别用于加密、认证、签名等不同用途。
  • 密钥拉伸:把弱密码(比如 6 位数字)变成强密钥,增加暴力破解的难度。
  • 密钥协商:在 Diffie-Hellman 等协议中,把共享秘密转换成对称密钥。

举个例子。我在做一个物联网项目时,设备之间需要共享一个会话密钥。但设备计算能力有限,不能跑太复杂的算法。我用了 HKDF,从预共享密钥里派生出一个 128 位的 AES 密钥。整个过程轻量又安全。

小提示:KDF 和「哈希函数」不是一回事。哈希函数是 KDF 的「零件」,但 KDF 有额外的设计目标。下面我会详细讲。

1.3 KDF与哈希函数的区别

很多人会把 KDF 和哈希函数搞混。我刚开始学的时候也犯过这个错。其实它们有本质区别。

哈希函数(比如 SHA-256)的设计目标是:快速、抗碰撞、单向。你给它一个输入,它很快给你一个固定长度的输出。但哈希函数没有「拉伸」能力——你跑一次和跑一万次,输出长度一样,计算时间也差不多。

KDF 的设计目标是:可控的计算成本、密钥质量保证、可派生多个密钥。KDF 通常会引入一个「迭代因子」或「内存硬性」,让攻击者破解的成本成倍增加。

对比维度 哈希函数 KDF
设计目标 快速、抗碰撞 可控成本、密钥质量
计算速度 尽量快 故意慢(可调节)
输出长度 固定(如 256 位) 可配置(任意长度)
迭代能力 无 有(迭代因子)
典型用途 数据完整性、数字签名 密码存储、密钥派生

你想想看,如果直接用 SHA-256 处理密码,攻击者一秒能算几亿次。但用 bcrypt 或 Argon2,一秒可能只能算几千次。这就是 KDF 的「拉伸」效果。

注意:千万不要用普通哈希函数(如 MD5、SHA-1、SHA-256)直接存储密码。我曾经审计过一个项目,他们用 SHA-256 哈希密码,结果被彩虹表一锅端。正确的做法是用专门的密码哈希 KDF,比如 bcrypt、scrypt 或 Argon2。

1.4 KDF的工作流程

下面这张图展示了 KDF 的典型工作流程。我画了一个简单的框架图,帮你理解整个过程。

KDF 典型工作流程 原始密钥材料 盐值(Salt) 迭代因子 KDF 核心函数 (迭代 + 混合) 派生密钥(固定长度) 说明:盐值防止彩虹表攻击,迭代因子增加破解成本

流程其实不复杂:原始密钥材料进来,加上一个随机盐值,再配合迭代因子,经过 KDF 核心函数的多次迭代混合,最终输出一个固定长度的安全密钥。

盐值的作用是什么?防止彩虹表攻击。就算两个用户用同样的密码,加了不同的盐值,最终派生出的密钥也完全不同。迭代因子呢?就是让计算变慢,攻击者想暴力破解,得花更多时间。

1.5 常见的KDF算法

市面上 KDF 算法不少,我挑几个常用的说说:

  • PBKDF2:老牌算法,基于 HMAC,可配置迭代次数。缺点是抗 GPU 攻击能力弱。
  • bcrypt:专门为密码存储设计,内部使用 Blowfish 加密算法。抗 GPU 能力比 PBKDF2 强。
  • scrypt:引入了内存硬性,需要大量内存,让 ASIC 和 GPU 攻击更难。
  • Argon2:2015 年密码哈希竞赛的冠军,支持内存硬性、CPU 硬性和并行度配置。目前最推荐的选择。
  • HKDF:基于 HMAC 的 KDF,适合密钥派生场景,不是密码存储。

我的建议:如果是新项目,密码存储直接用 Argon2id。如果是密钥派生场景,HKDF 就够用了。别自己造轮子,我见过太多「自定义 KDF」最后被攻破的案例。

1.6 避坑指南

最后分享几个我踩过的坑:

  • 不要复用密钥:同一个密钥不要既用于加密又用于认证。用 KDF 派生两个子密钥,各司其职。
  • 盐值要随机且足够长:至少 16 字节。我曾经见过有人用固定盐值,那跟没用一样。
  • 迭代因子不是越大越好:要在安全性和性能之间找平衡。我一般选让服务器耗时 50-100 毫秒的迭代次数。
  • 不要用 MD5 或 SHA-1 做 KDF:这两个已经被证明不安全,别碰。

嗯,这一章就到这里。KDF 的概念其实不难,关键是理解它「为什么存在」以及「怎么用对」。后面几章我们会深入具体的算法实现和选型策略。