五岁小站 - 免费在线工具箱

加载中...

PBKDF2 密钥派生

PBKDF2 密钥派生 · 严格遵循 RFC 2898 / RFC 8018 / PKCS#5 v2.1 标准 · 默认 OWASP 2023 推荐迭代 600,000 次 · 优先 Web Crypto,回退 CryptoJS · 纯前端本地计算
OWASP 2023: SHA256=600k / SHA512=210k / SHA1=1.3M
AES128=16 / AES192=24 / AES256=32 / HMAC-SHA512=64
当前: 0 字符 | 强度: -
当前: 0 字符
长度: 0 字符 · 字节数: 0 · 耗时: -
典型场景模板
代码示例(PBKDF2-HMAC-SHA256)
// Node.js 内置 (推荐)
const crypto = require('crypto');

const dk = crypto.pbkdf2Sync(
    'mypassword',                                  // 密码
    Buffer.from('1234567890abcdef', 'hex'),        // 16 字节 Salt
    600000,                                        // 迭代次数
    32,                                            // DkLen
    'sha256');                                     // PRF

console.log(dk.toString('hex'));

// 浏览器 (Web Crypto API, 高性能)
async function pbkdf2(password, salt, iterations, dkLenBytes) {
    const enc = new TextEncoder();
    const baseKey = await crypto.subtle.importKey(
        'raw', enc.encode(password),
        { name: 'PBKDF2' }, false, ['deriveBits']);
    const bits = await crypto.subtle.deriveBits(
        { name: 'PBKDF2', hash: 'SHA-256', salt: salt, iterations: iterations },
        baseKey, dkLenBytes * 8);
    return new Uint8Array(bits);
}
import hashlib, secrets

password = b'mypassword'
salt = secrets.token_bytes(16)        # 16 字节随机 Salt
iterations = 600_000
dk_len = 32                            # 256 位

dk = hashlib.pbkdf2_hmac('sha256', password, salt, iterations, dk_len)
print(dk.hex())

# 校验 (时序安全比较)
import hmac
hmac.compare_digest(dk_a, dk_b)
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;

byte[] salt = new byte[16];
new SecureRandom().nextBytes(salt);

PBEKeySpec spec = new PBEKeySpec(
    "mypassword".toCharArray(),
    salt,
    600_000,        // 迭代
    256);           // DkLen 位 (256 / 8 = 32 字节)

byte[] dk = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
                            .generateSecret(spec).getEncoded();
// dk -> Hex / Base64
package main

import (
    "crypto/rand"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "golang.org/x/crypto/pbkdf2"
)

func main() {
    salt := make([]byte, 16)
    _, _ = rand.Read(salt)

    dk := pbkdf2.Key(
        []byte("mypassword"),
        salt,
        600000,        // iterations
        32,            // DkLen
        sha256.New)

    fmt.Println(hex.EncodeToString(dk))
}
<?php
$password = 'mypassword';
$salt = random_bytes(16);
$dk = hash_pbkdf2('sha256', $password, $salt, 600000, 32, true); // raw output 32 字节
echo bin2hex($dk), PHP_EOL;

// 时序安全比较
hash_equals($dk_a, $dk_b);
# OpenSSL 1.1.1+
openssl kdf -keylen 32 -kdfopt digest:SHA256 \
            -kdfopt pass:mypassword \
            -kdfopt hexsalt:1234567890abcdef \
            -kdfopt iter:600000 PBKDF2

# 旧版 OpenSSL (用于 enc 派生 IV)
openssl enc -aes-256-cbc -P -pbkdf2 -iter 600000 \
            -pass pass:mypassword -S 1234567890abcdef
PBKDF2 算法说明 / OWASP 2023 推荐参数
PRF 输出/块 OWASP 2023 迭代 典型应用
HMAC-SHA120 / 64 字节1,300,000 次WPA2-PSK(4096 固定)、iOS Data Protection、老旧系统
HMAC-SHA22428 / 64 字节过渡用途
HMAC-SHA25632 / 64 字节600,000 次(推荐)密码存储、JWT 密钥派生、AES 密钥派生、KeePass
HMAC-SHA38448 / 128 字节210,000 次高安全级 JWT
HMAC-SHA51264 / 128 字节210,000 次BIP39(2048 固定)、1Password、64 位机器更快
HMAC-SHA3-25632 / 136 字节新协议、抗量子潜力
HMAC-SHA3-51264 / 72 字节新协议、最高安全级
HMAC-MD516 / 64 字节仅供调试与遗留对接,新项目避免使用
RFC 6070 标准测试向量(PBKDF2-HMAC-SHA1)
P (密码) S (盐值) c dkLen DK (Hex)
"password""salt"1200c60c80f961f0e71f3a9b524af6012062fe037a6
"password""salt"220ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957
"password""salt"4096204b007901b765489abead49d926f721d065a429c1
"passwordPASSWORDpassword""saltSALTsaltSALTsaltSALTsaltSALTsalt"4096253d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038
安全使用清单
  • Salt 必须使用 CSPRNG 生成,每用户/每次密码变更唯一,长度 ≥ 16 字节;本工具使用 crypto.getRandomValues
  • 迭代次数随硬件升级,建议每 2 年翻倍;存储时连同 PRF / 迭代 / Salt 一起保存(如 PHC 字符串格式)
  • 密码哈希比较使用时序安全 compare_digest / hash_equals / 本工具自动使用恒定时间比较
  • 派生 AES + IV:DkLen 设为 32+16=48 字节(AES-256),前 32 作为密钥、后 16 作为 IV;或分别使用不同 Salt 派生
  • ⚠️ 严禁固定 Salt(如 "salt12345"),等于没有加盐,攻击者可建立专用彩虹表
  • ⚠️ 新项目优先 Argon2id / scrypt,PBKDF2 是 FIPS 合规与最广泛兼容的选择,但 GPU/ASIC 抗性较弱
常见问题 FAQ
PBKDF2 与 bcrypt / scrypt / Argon2 该如何选择?

PBKDF2 CPU 密集,FIPS 140-2 合规,被 NIST、PKCS#5 等标准认可,跨平台支持极好;缺点是 GPU/FPGA/ASIC 抗性较弱。bcrypt 限制 72 字节输入;scrypt 内存密集,抗 GPU 强;Argon2id 是 2015 年密码哈希竞赛冠军,OWASP 首推。
选型:政府/金融合规 → PBKDF2-SHA512;新业务首选 → Argon2id;老 PHP/Rails → bcrypt。

迭代次数(iterations)应该设多少?

原则:在用户可接受时间内(100~500ms)尽可能多。OWASP 2023 推荐:SHA256 = 600,000;SHA512 = 210,000;SHA1 = 1,300,000。建议每 2 年翻倍以匹配硬件性能提升;保存哈希时连同迭代次数一起存储,便于平滑升级。

Salt 该怎么生成?为什么必须随机?

Salt 必须使用密码学安全随机数生成器(CSPRNG):JS 用 crypto.getRandomValues、Go 用 crypto/rand、Python 用 secrets。长度 ≥ 16 字节;每用户、每次密码变更唯一;不需保密可与哈希一起存储。固定 Salt = 无 Salt,攻击者可建立专用彩虹表。

怎么从派生的密钥得到 AES 密钥 + IV?

DkLen 设为「AES 密钥长度 + IV 长度」,例如 AES-256-CBC:DkLen = 32 + 16 = 48 字节,前 32 作为密钥、后 16 作为 IV;或者分别用不同 Salt 派生。文件加密格式头通常存储:Magic + Salt + 迭代次数 + IV + 密文 + HMAC。

为什么浏览器计算这么快?iOS/手机会很慢吗?

本工具优先使用 Web Crypto API(浏览器原生 C 实现,调用底层 OpenSSL/BoringSSL),比纯 JavaScript 实现快 10~100 倍;不支持 SHA3/MD5 时回退 CryptoJS 4.2。手机性能比桌面慢 3~5 倍,60 万次 SHA256 桌面约 200ms、iPhone 约 800ms、低端 Android 约 1.5s,仍在用户可接受范围。