当前位置: 首页> 最新文章列表> crypt() 结果长度不一致是哪里出问题了?

crypt() 结果长度不一致是哪里出问题了?

M66 2025-05-20

在使用 PHP 的 crypt() 函数进行密码加密时,不少开发者会注意到一个奇怪的现象:有时候加密结果长度是 13 个字符,有时候是 20、34,甚至更多。这种长度的不一致容易让人误以为代码出了问题,或是密码被截断或加密错误。那么,这到底是怎么回事?

一、crypt() 函数简介

PHP 的 crypt() 函数是一个封装的加密接口,底层依赖于操作系统提供的加密算法。这个函数的第一个参数是要加密的字符串,第二个参数是“盐值”(salt)。而这个盐值不仅影响加密结果的唯一性,更决定了使用哪种加密算法。

echo crypt("mypassword", "salt");

如果你不给出盐值或使用的盐值格式不正确,PHP 会自动退回到较旧的加密方式,比如传统的 DES(Data Encryption Standard)算法,而这就会导致输出结果非常短,通常只有 13 个字符。

二、不同的盐值代表不同的加密算法

crypt() 函数支持多种算法,不同算法通过盐值的前缀来决定。下面是常见的几种盐值格式及其对应的加密算法:

算法盐值格式结果长度
DES2个字符13字符
MD5$1$...34字符
Blowfish$2a$... / $2y$...60字符
SHA-256$5$...43字符
SHA-512$6$...86字符

所以如果你没有显式地传入带前缀的盐值,或传入了不符合格式的盐值,PHP 很可能退回使用旧的 DES 加密,而 DES 只输出 13 个字符。

例如:

// 使用 SHA-512 加密
echo crypt("mypassword", '$6$rounds=5000$usesomesillystring$');
// 输出类似于:$6$rounds=5000$usesomesill...(总长度约86)

而以下代码使用默认 DES 算法:

echo crypt("mypassword", 'sa');
// 输出类似于:sahGDf/YwKdl6(仅13个字符)

三、那应该怎么做?

为避免这个问题,请始终使用带有明确前缀的盐值,最好是生成的随机盐,并且选用更安全的算法,如 Blowfish($2y$)或 SHA-512($6$)。

你可以这样自动生成盐值:

function generateSalt($algo = 'sha512') {
    switch ($algo) {
        case 'blowfish':
            return '$2y$10$' . substr(str_replace('+', '.', base64_encode(random_bytes(22))), 0, 22);
        case 'sha256':
            return '$5$' . bin2hex(random_bytes(6));
        case 'sha512':
        default:
            return '$6$' . bin2hex(random_bytes(6));
    }
}

$password = 'mypassword';
$salt = generateSalt('sha512');
$hash = crypt($password, $salt);

echo $hash;

四、一个完整的示例

<?php
function hashPassword($password) {
    $salt = '$2y$10$' . substr(str_replace('+', '.', base64_encode(random_bytes(22))), 0, 22);
    return crypt($password, $salt);
}

$plainPassword = '123456';
$hashed = hashPassword($plainPassword);

// 假设保存到数据库中
file_put_contents('/var/www/m66.net/passwords.txt', $hashed . PHP_EOL);

// 验证密码
$inputPassword = '123456';
$isValid = crypt($inputPassword, $hashed) === $hashed;
echo $isValid ? '密码正确' : '密码错误';
?>

五、总结

使用 crypt() 函数时,结果长度不同的根本原因在于“盐值”的格式决定了加密算法。为确保加密安全和一致性:

  1. 始终显式传入正确格式的盐值

  2. 选择现代、安全的算法,如 $2y$$6$

  3. 不要依赖默认行为或短盐值格式

理解这些底层细节后,就可以避免在密码处理上出现隐蔽的安全风险,也能让你的加密逻辑更可控、更可靠。