PHP 怎么密钥派生

wen PHP项目 1

本文目录导读:

PHP 怎么密钥派生

  1. 使用 hash_pbkdf2()(最通用)
  2. 使用 password_hash() + password_verify()(推荐用于密码存储)
  3. 使用 OpenSSL 的 KDF 功能
  4. 使用 Argon2(现代且更安全)
  5. 综合最佳实践函数
  6. 最佳实践建议
  7. 安全性比较

在 PHP 中实现密钥派生,最常用和推荐的方法是使用 哈希函数(如 PBKDF2)现代 KDF(如 Argon2),下面是几种主流方法的详细说明和代码示例。

使用 hash_pbkdf2()(最通用)

PBKDF2(Password-Based Key Derivation Function 2)是经典且广泛支持的密钥派生函数。

<?php
// 参数准备
$password = 'user_password';
$salt = random_bytes(16); // 始终使用随机盐
$iterations = 100000;     // 建议至少 100,000 次
$keyLength = 32;          // 输出密钥长度(字节)
$algorithm = 'sha256';
// 派生密钥
$derivedKey = hash_pbkdf2(
    $algorithm,
    $password,
    $salt,
    $iterations,
    $keyLength,
    true  // 返回二进制数据,而非十六进制
);
// 生成十六进制表示(便于存储)
$encodedKey = bin2hex($derivedKey);
echo "盐: " . bin2hex($salt) . "\n";
echo "派生密钥: " . $encodedKey . "\n";
?>

注意事项

  • 盐必须是唯一的、随机的,并且至少 16 字节
  • 迭代次数越多,安全性越高,但性能越低
  • 输出格式可以是二进制或十六进制

使用 password_hash() + password_verify()(推荐用于密码存储)

虽然这是为密码哈希设计的,但也可以用于密钥派生:

<?php
// 密码哈希(适合存储验证,不适合直接用作加密密钥)
$password = 'user_password';
$hash = password_hash($password, PASSWORD_BCRYPT, [
    'cost' => 12,  // 计算成本
]);
// 验证
if (password_verify($password, $hash)) {
    echo "密码验证成功\n";
}
?>

注意password_hash 不适合直接用于加密密钥,因为它使用的是单向哈希,但如果你需要存储密码凭证,这是最好的选择。

使用 OpenSSL 的 KDF 功能

<?php
// 使用 openssl_pbkdf2(PHP >= 5.5)
$password = 'user_password';
$salt = random_bytes(16);
$iterations = 100000;
$keyLength = 32;
$algorithm = 'sha256';
$derivedKey = openssl_pbkdf2(
    $password,
    $salt,
    $keyLength,
    $iterations,
    $algorithm
);
echo "派生密钥: " . bin2hex($derivedKey) . "\n";
?>

使用 Argon2(现代且更安全)

PHP 7.2+ 支持 Argon2,它被认为是目前最安全的 KDF 算法之一:

<?php
// 主要用途:密码哈希(PASSWORD_ARGON2I 或 PASSWORD_ARGON2ID)
$options = [
    'memory_cost' => 1024 * 64,    // 64 MB
    'time_cost'   => 4,            // 迭代次数
    'threads'     => 2,            // 线程数
];
$hash = password_hash('user_password', PASSWORD_ARGON2ID, $options);
// 验证
if (password_verify('user_password', $hash)) {
    echo "密码验证成功\n";
}
?>

注意:Argon2 主要用于密码哈希,不能直接输出为加密密钥,如果需要使用 Argon2 派生密钥,需要修改其输出设置(在 C 扩展层面),通常不建议这样做。

综合最佳实践函数

以下是一个完整的密钥派生函数封装:

<?php
/**
 * 使用 PBKDF2 派生加密密钥
 * 
 * @param string $password      密码
 * @param string $salt          盐(至少16字节)
 * @param int    $keyLength     密钥长度(字节)
 * @param int    $iterations   迭代次数
 * @return string               返回二进制密钥
 */
function deriveKey(
    string $password,
    string $salt,
    int $keyLength = 32,
    int $iterations = 100000
): string {
    if (strlen($salt) < 16) {
        throw new InvalidArgumentException('盐长度至少需要16字节');
    }
    return hash_pbkdf2(
        'sha256',
        $password,
        $salt,
        $iterations,
        $keyLength,
        true
    );
}
// 使用示例
$password = 'my_secure_password';
$salt = random_bytes(32);  // 推荐32字节
$key = deriveKey($password, $salt);
echo "生成的密钥: " . bin2hex($key) . "\n";
?>

最佳实践建议

  1. 始终使用随机盐:不要重复使用盐
  2. 选择适当的迭代次数:根据硬件性能调整,建议 100,000 次以上
  3. 使用安全的哈希算法:SHA-256 或更强
  4. 密钥长度:AES-256 建议 32 字节
  5. 存储格式:使用 bin2hex() 或 Base64 编码存储
  6. 更新策略:定期评估和更新参数

安全性比较

方法 安全性 用途 性能
PBKDF2 良好 通用密钥派生 中等
Argon2 优秀 密码哈希 较慢(但安全)
bcrypt 良好 密码存储 中等
OpenSSL PBKDF2 良好 通用密钥派生 中等

选择哪种方法取决于你的具体需求:

  • 加密密钥派生 → 使用 PBKDF2
  • 密码存储验证 → 使用 Argon2 或 bcrypt
  • 需要最大安全性 → 使用 Argon2id

抱歉,评论功能暂时关闭!