當前位置: 首頁> 最新文章列表> 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()函數支持多種算法,不同算法通過鹽值的前綴來決定。下面是常見的幾種鹽值格式及其對應的加密算法:

演算法鹽值格式結果長度
DES 2個字符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. 不要依賴默認行為或短鹽值格式

理解這些底層細節後,就可以避免在密碼處理上出現隱蔽的安全風險,也能讓你的加密邏輯更可控、更可靠。