跳转到内容
HexaTransfer
返回博客
加密与安全

密钥派生函数:PBKDF2、Argon2和scrypt对比

比较基于密码加密的密钥派生函数。PBKDF2、Argon2和scrypt的优势和权衡。

2026 年密码派生加密密钥的推荐选择:Argon2id 排首位(密码哈希竞赛获胜者,OWASP 首选,能有效抵御 GPU 和 ASIC 攻击);scrypt 是可靠的次选(内存硬化,广泛用于加密货币领域);PBKDF2-SHA-256 在 60 万次以上迭代下仍在兼容性场景中可接受,但对 GPU 的抵抗力有限。对于允许用户设置密码来保护共享文件的传输应用,Argon2id(3 次迭代、64 MiB 内存、4 并行度)是当前的现代基准。PBKDF2 之所以仍在使用,是因为它内置于 Web Crypto API,无需 WASM 依赖。以下是三者的差异与各自的适用场景。

快速对比

属性 PBKDF2 scrypt Argon2id
引入年份 2000 年(RFC 2898) 2009 年(RFC 7914) 2015 年(PHC 获胜者)
内存硬化
参数灵活性 仅迭代次数 N、r、p 时间、内存、并行度
GPU 抗性 中等
ASIC 抗性 非常弱 中等
浏览器原生(Web Crypto)
OWASP 2024 建议 可接受的备选 可接受 首选
典型浏览器耗时(现代硬件) 60 万次迭代 ≈ 500 ms N=2^17 ≈ 800 ms 3 次迭代、64 MiB ≈ 1 s

为什么内存硬化至关重要

密码派生加密的威胁模型是离线暴力破解。攻击者获取密文和盐值后,通过密码字典逐一尝试,看哪个推导出的密钥能解密成功。防御的核心是让每次尝试代价高昂。

PBKDF2 只在 CPU 时间上增加代价(SHA-256 迭代)。现代 GPU 每秒可执行数十亿次 SHA-256 运算;一张游戏 GPU 每天可测试 1000 万至 1 亿次 PBKDF2-SHA-256(60 万次迭代)的猜测。ASIC 攻击者的效率还要高出数个数量级。

内存硬化函数(scrypt、Argon2)要求每次尝试都占用固定量的内存。GPU 和 ASIC 受限于内存带宽,每台设备的并行度有上限。64 MiB 内存需求意味着一张 16 GB 显存的 GPU 最多只能并行运行 256 次猜测,而不是数百万次。暴力破解的经济成本因此提高 2–3 个数量级。

PBKDF2:沿用至今的遗留标准

PBKDF2(RFC 2898)在密码和盐值上迭代调用一个伪随机函数,通常是 HMAC-SHA-256 或 HMAC-SHA-512。迭代次数是唯一可调参数。

const passwordKey = await crypto.subtle.importKey(
  "raw", new TextEncoder().encode(password),
  "PBKDF2", false, ["deriveKey"]
);
const aesKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt,  // 16 字节随机数
    iterations: 600000,
    hash: "SHA-256",
  },
  passwordKey,
  { name: "AES-GCM", length: 256 },
  false,
  ["encrypt", "decrypt"]
);

OWASP 2023 建议 PBKDF2-SHA-256 至少使用 60 万次迭代。部分旧规范(例如 LastPass 2018 年默认的 100100 次)在 2026 年已被认为过低。

优势:内置于 Web Crypto,无需 WASM,经 FIPS 验证,在 Node 和浏览器中行为一致。

局限:没有内存硬化,易受 GPU 和 ASIC 大规模并行攻击。迭代次数翻倍,攻击者和合法用户的代价都翻倍。用户忍耐度有限,迭代次数到一定程度就会遇到 UX 天花板。

scrypt:首个大规模部署的内存硬化方案

scrypt(RFC 7914)由 Colin Percival 于 2009 年为 Tarsnap 设计。它将密码材料通过一个大内存缓冲区混合处理,迫使攻击者在每次猜测时都必须持有该缓冲区。

三个参数:

  • N:成本因子(通常为 2^14 至 2^20)。内存占用约为 128 × N × r 字节。
  • r:块大小(通常为 8)。影响内存占用和 GHASH 迭代次数。
  • p:并行度(通常为 1)。更高的值可加速合法计算,但同样加速攻击者;通常保持为 1。

OWASP 建议基准参数为 N=2^17、r=8、p=1,内存占用约 128 MiB,现代硬件运行约 800 ms。

scrypt 不在 Web Crypto API 中。在 JavaScript 里,使用 scrypt-js、@noble/hashes 或 libsodium.js。Litecoin 和 Dogecoin 以 scrypt 作为工作量证明算法,这反而激励了专用 ASIC 的开发,一定程度上削弱了它最初对 ASIC 的非对称优势。

Argon2id:2026 年的默认选择

Argon2 在 2015 年密码哈希竞赛中获胜。三个变体:Argon2d(最快,数据相关访问,存在侧信道风险)、Argon2i(数据无关访问,较慢)、Argon2id(混合模式,大多数场景推荐)。RFC 9106 于 2021 年将其标准化。

三个参数:

  • t(时间):遍历内存的迭代次数,通常为 2–3。
  • m(内存):以 KiB 计的内存量,通常为 65536(64 MiB)或更高。
  • p(并行度):并行度,通常为 1–4。

OWASP 2024 基准:最低 t=2、m=19456(19 MiB)、p=1;更强保护为 t=3、m=65536(64 MiB)、p=4。

import { argon2id } from '@noble/hashes/argon2';
import { utf8ToBytes } from '@noble/hashes/utils';

const derivedKey = argon2id(utf8ToBytes(password), salt, {
  t: 3, m: 65536, p: 4, dkLen: 32
});

也可通过 argon2-browser(WASM)使用:

import argon2 from 'argon2-browser';
const hash = await argon2.hash({
  pass: password, salt,
  type: argon2.ArgonType.Argon2id,
  time: 3, mem: 65536, parallelism: 4, hashLen: 32
});

Argon2id 对 GPU 攻击者的抵抗力强于 scrypt,因为其内存访问模式不适合批量内存设计。针对 Argon2 的 ASIC 在研究层面已有进展,但尚未达到经济可行的攻击规模。

为你的应用选择合适的参数

校准方法:确定用户能接受的最长等待时间(通常 500 ms 至 2 秒),在最慢的目标设备上测量,将参数调整到接近该预算。

对于 HexaTransfer 风格的密码保护文件共享(上传时派生一次,下载时派生一次),1–2 秒是可接受范围。参数建议:

  • PBKDF2-SHA-256:60 万至 120 万次迭代
  • scrypt:N=2^17、r=8、p=1
  • Argon2id:t=3、m=65536、p=4

用户输入密码后需即时等待的登录系统,UX 上限通常在 300–500 ms,参数大致减半。后台重加密等无需等待的批处理场景,可将时间预算提高到 3–5 秒。

盐值管理

三种 KDF 都需要盐值。规则如下:

  • 至少 16 字节随机数
  • 通过 crypto.getRandomValues() 生成,绝对不用 Math.random()
  • 每个密码独立生成(Alice 和 Bob 即使使用相同密码,盐值也应不同,从而派生出不同密钥)
  • 不需要保密——随密文一起存储

有时会讨论到"pepper"(服务器端的全局密钥附加值)。对于使用哑存储后端的文件传输服务,pepper 没有价值,因为没有服务器端的秘密。对于基于账户的系统,将 pepper 单独存储于密码数据库之外,可降低数据库泄露的危害。

在不同 KDF 之间迁移

如果现有系统基于 PBKDF2,想迁移到 Argon2id:

  • 在密文元数据中存储 KDF 标识符(如 "kdf": "pbkdf2-sha256-600000""kdf": "argon2id-3-65536-4"
  • 新上传使用 Argon2id
  • 解密时读取 KDF 标识符,调用对应函数
  • 切勿盲目升级旧密文;需要原始密码才能重新派生密钥

LastPass、1Password 和 Bitwarden 都经历过这个迁移过程。三者目前默认使用 60 万次以上迭代的 PBKDF2,较新版本提供 Argon2id 选项。即便是密码管理器,向 Argon2 的过渡也是循序渐进的——生态工具链的成熟需要时间。

bcrypt 怎么样

bcrypt(1999 年)是具备适度内存硬化的密码哈希函数。它将输入截断为 72 字节(一个众所周知的陷阱——超长密码会被静默截断)。它是 Ruby on Rails 和许多 PHP 框架的历史默认值。2026 年的新代码,优先选 Argon2id;维护现有使用 bcrypt 的系统,保持现状即可。

实际推荐

2026 年新建的文件传输服务:

  • 如果可以接受 15–200 KB 的依赖:通过 @noble/hashes 或 libsodium.js 使用 Argon2id
  • 如果追求零依赖和最小包体积:通过 Web Crypto 使用 PBKDF2-SHA-256(60 万次迭代)
  • 如果编写加密货币钱包或继承了 scrypt 遗留代码:scrypt(N=2^17)

对于处理敏感文件的生产应用,Argon2id 值得引入 WASM 依赖。对于简单的密码保护共享(用户本就会生成随机密码的场景),PBKDF2 已经足够,因为安全性来自密码本身的熵,而非 KDF。

在 hexatransfer.com 上试试 — 免费、无需注册、最多 10 GB。

通过端到端加密安全发送大文件

通过端到端加密免费传输最大10GB的文件。无需注册账户。文件在上传前在浏览器中加密,其他人无法读取。

发送文件