Discuz! authcode 函數自 2001 年誕生以來,成為 PHP 開源圈最被廣泛複製、移植、討論的加密工具。儅今主流框架皆採用 OpenSSL / Sodium 等現代加密庫,但理解其設計思想對學習對稱加密原理、金鑰派生、完整性驗證、防重放攻擊極具教學價值。
本質上是一個基於 RC4 改良的流式加密演算法,結合動態金鑰(Key C)、時間戳、HMAC 風格完整性校驗,實現:
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4; // 動態金鑰長度
$key = md5($key ? $key : $GLOBALS['discuz_auth_key']); // 主金鑰 MD5
$keya = md5(substr($key, 0, 16)); // 加解密金鑰
$keyb = md5(substr($key, 16, 16)); // 完整性驗證金鑰
$keyc = $ckey_length
? ($operation == 'DECODE' ? substr($string, 0, $ckey_length)
: substr(md5(microtime()), -$ckey_length))
: ''; // 動態金鑰
$cryptkey = $keya . md5($keya . $keyc); // 最終加密金鑰
}
設計亮點:
$string = sprintf('%010d', $expiry ? $expiry + time() : 0) // 10位過期時間戳
. substr(md5($string . $keyb), 0, 16) // 16位完整性校驗碼
. $string; // 原始明文
解密時則從第 $ckey_length 位開始 Base64 解碼,還原上述結構。
$box = range(0, 255);
$rndkey = array();
for ($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// KSA: Key-Scheduling Algorithm
for ($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp;
}
標準 RC4 KSA,將 256 字節 S-box 依金鑰打亂。
for ($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a]; $box[$a] = $box[$j]; $box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
標準 RC4 PRGA,每次迴圈產生一字節關鍵流,與明文異或。
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0)
&& substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26); // 返回真實明文
}
return ''; // 驗證失敗返回空字串
三重防護:
| 項目 | 評價 |
|---|---|
| 算法強度 | RC4 已知存在偏差攻擊(Fluhrer-Mantin-Shamir),不建議用於高機密資料 |
| 金鑰管理 | 單一主金鑰衍生所有子金鑰,缺乏前向安全性 |
| 完整性 | MD5 碰撞風險,且非標準 HMAC 結構 |
| 重放攻擊 | 依賴時間戳防禦,時鐘不同步會失效 |
| 適用場景 | Token、Cookie 簽名、低敏感度 API 參數加密、教學演示 |
// 推薦:PHP 7.2+ 原生 Sodium (libsodium)
$key = sodium_crypto_secretbox_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($message, $nonce, $key);
// 存儲: base64_encode($nonce . $ciphertext)
// 或 OpenSSL AES-256-GCM (需 PHP 7.1+)
$iv = random_bytes(12);
$ciphertext = openssl_encrypt($msg, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
authcode 是 PHP 早期工程師在無現代加密庫條件下,用有限原語構建出的「足夠好」方案。其動態金鑰、時間戳嵌入、完整性校驗三大設計模式至今仍具參考價值。但新專案請務必使用經過密碼學專家審計的標準庫,不要在生產環境直接沿用此函數處理敏感資料。