1. 密钥派生基础:从密码学原语到实际应用场景

大家好,我是这门课的主讲人。今天咱们聊聊密钥派生——这个听起来有点学术,但实际上每天都在用的东西。

你可能会问:为什么需要密钥派生?直接拿用户密码当密钥不行吗?嗯,我刚开始做密码学工程时也这么想过。直到有一次,我在一个项目中看到用户密码直接被当成 AES 密钥使用……那场面,怎么说呢,就像把家门钥匙挂在门外墙上。

1.1 密码学原语:密钥从哪来?

先看几个基础概念。密码学里,密钥的来源大致分三类:

来源类型 典型例子 特点
用户输入 密码、PIN码、口令 低熵、可预测、长度不固定
硬件生成 HSM、TPM、安全芯片 高熵、不可导出、成本高
协议派生 DH协商、KDF计算 可控、可重复、可分层

说白了,用户密码的熵值通常只有 20-30 比特。而 AES-128 需要 128 比特的均匀随机密钥。这中间的差距,就是密钥派生要解决的问题。

核心观点:密钥派生不是锦上添花,而是安全工程的刚需。没有它,你的加密系统就像用生日当密码的保险柜。

1.2 为什么不能直接用原始密钥材料?

我见过不少团队踩过这个坑。直接使用原始密钥材料,至少有三个致命问题:

  • 熵不匹配:用户密码只有几十比特熵,直接当密钥会被暴力破解轻松拿下
  • 结构泄露:原始密钥材料往往有固定模式(比如密码开头大写、结尾数字),攻击者可以利用这些模式
  • 重用风险:同一个密码用在多个地方,一个泄露全部完蛋

举个例子。我曾经审计过一个物联网项目,他们把设备序列号直接当成加密密钥。结果呢?序列号是递增的,攻击者拿到一个设备就能推算出所有设备的密钥。这就是典型的「原始密钥材料直接使用」灾难。

1.3 密钥派生函数(KDF)的核心职责

密钥派生函数,英文叫 Key Derivation Function,简称 KDF。它的工作就是:把任意长度的输入,变成固定长度、高熵、无结构的密钥。

一个合格的 KDF 必须做到:

  1. 单向性:从输出无法反推输入
  2. 均匀性:输出比特分布均匀,没有统计偏差
  3. 雪崩效应:输入改一比特,输出完全变样
  4. 抗碰撞:不同输入产生相同输出的概率极低

我的经验:判断一个 KDF 好不好,最简单的测试就是:把输入改一个字符,看输出是不是完全不一样。如果只有几个比特变化,赶紧换算法。

1.4 实际应用场景:你每天都在用

密钥派生不是实验室里的玩具。它无处不在:

  • Wi-Fi 密码:你输入的路由器密码,通过 PBKDF2 派生出 WPA2/WPA3 的成对主密钥
  • HTTPS:TLS 握手过程中,通过 HKDF 从预主密钥派生出会话密钥
  • 加密货币钱包:助记词通过 BIP32/BIP39 派生出一系列子密钥
  • 全盘加密:BitLocker、FileVault 用用户口令派生出磁盘加密密钥

你看,密钥派生不是可选项,而是现代密码系统的标配。

1.5 密钥派生树:为什么需要分层?

单次派生够用吗?大多数场景下不够。为什么呢?

想象一下:你的应用需要加密数据、签名消息、认证用户。如果所有操作都用同一个密钥,一旦泄露,全线崩溃。更合理的做法是:从一个主密钥,派生出多个子密钥,每个子密钥只负责一件事。

这就是密钥派生树的由来。它像一棵树:

  • 根节点:主密钥(高熵、严格保护)
  • 分支节点:中间派生密钥(按用途或路径划分)
  • 叶子节点:实际使用的密钥(加密、签名、认证等)

我在做金融系统时,就遇到过密钥管理混乱的问题。所有业务线共用一个密钥,结果一条业务线被攻破,整个系统都得换密钥。后来我们引入了密钥派生树,每条业务线有自己的派生路径,隔离性好了很多。

注意:密钥派生树不是越深越好。每层派生都有计算开销,而且深度过大会增加密钥管理的复杂度。一般 3-5 层就够用了。

1.6 本章知识体系总览

下面这张图,概括了密钥派生的核心逻辑:

密钥派生核心逻辑 原始密钥材料 密钥派生函数 (KDF) PBKDF2 / HKDF / Argon2 主密钥 (MK) 加密密钥 (EK) 签名密钥 (SK) 认证密钥 (AK) 每个子密钥只负责单一用途,隔离性好,泄露一个不影响其他

从这张图可以看到:原始密钥材料经过 KDF 处理后,变成主密钥;主密钥再通过派生树,生成多个用途不同的子密钥。每个子密钥各司其职,互不干扰。

1.7 常见 KDF 算法对比

市面上常见的 KDF 算法,各有千秋:

算法 设计目标 抗暴力破解 适用场景
PBKDF2 慢哈希 + 加盐 中等(可调迭代次数) 密码存储、Wi-Fi 密钥派生
HKDF 提取 + 扩展 低(设计目标不是慢) TLS 会话密钥、协议派生
Argon2 内存硬 + 时间硬 高(抗 GPU/ASIC) 密码哈希、高安全场景
scrypt 内存硬 较高 加密货币挖矿、密码存储

我的建议:如果是新项目,优先考虑 Argon2id。它在抗 GPU 和 ASIC 方面做得最好。如果是兼容旧系统,PBKDF2 也够用,但迭代次数别低于 100000。

1.8 避坑指南:我踩过的那些坑

最后分享几个我亲身经历过的教训:

  • 忘记加盐:曾经有个同事直接用密码做 KDF 输入,不加盐。结果两个用户密码相同,派生出的密钥也相同。攻击者只要破解一个,就知道另一个。
  • 迭代次数太低:早期一个项目用 PBKDF2 只迭代 1000 次。当时觉得够快了,后来发现 GPU 破解速度惊人。现在我都用 100000 次起步。
  • 混淆 KDF 和哈希:有人用 SHA-256 直接当 KDF 用。SHA-256 是哈希函数,不是 KDF。它没有加盐机制,也没有可调计算成本。

嗯,这些坑说起来都是泪。但踩过之后,你就知道密钥派生这件事,真不能马虎。