首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Discuz! X1.5 加密解密函數 authcode() 深度解析:RC4 變體、動態金鑰、時間戳驗證

     編輯:PHP 相關知識

Discuz! X1.5 加密解密函數 authcode() 深度解析:RC4 變體、動態金鑰、時間戳驗證

Discuz! 經典 authcode($string, $operation, $key, $expiry) 是一個基於 RC4 流加密演算法變體的對稱加密函數,廣泛用於 Cookie 加密、表單令牌、API 簽名。本文逐行解析其核心機制。

源碼還原與註釋

$authkey = ''; // 全域預設金鑰

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    global $authkey;
    $ckey_length = 4; // 動態金鑰長度

    // 1. 金鑰派生
    $key = md5($key ? $key : $authkey);           // 32 字元
    $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);       // 最終加密金鑰(含動態鹽)
    $key_length = strlen($cryptkey);              // 64 字元

    // 2. 數據預處理
    if ($operation == 'DECODE') {
        $string = base64_decode(substr($string, $ckey_length));
    } else {
        // 編碼格式:10位時間戳 + 16位完整性校驗 + 原文
        $string = sprintf('%010d', $expiry ? $expiry + time() : 0)
                . substr(md5($string . $keyb), 0, 16)
                . $string;
    }
    $string_length = strlen($string);

    // 3. RC4 核心:密鑰調度演算法 (KSA)
    $box = range(0, 255);
    $rndkey = [];
    for ($i = 0; $i <= 255; $i++) $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp;
    }

    // 4. RC4 核心:偽隨機生成演算法 (PRGA) + 異或加密
    $result = '';
    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]);
    }

    // 5. 解碼驗證
    if ($operation == 'DECODE') {
        // 檢查:時間戳未過期 + 完整性校驗通過
        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 ''; // 驗證失敗
    } else {
        // 編碼輸出:動態金鑰 + Base64(密文) 移除 =
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}

// 測試
$str = '1234'; $key = '1234';
$encode = authcode($str, 'ENCODE', $key);
$decode = authcode($encode, 'DECODE', $key);
// 輸出:明文:1234 / 密文:a52f67eXZGVy0HtQBo4vOREhq3WxnL6E2zlx75JGfoJW / 解密:1234

核心機制圖解

環節關鍵代碼安全作用
動態鹽$keyc = substr(md5(microtime()), -4)相同明文每次加密結果不同,防彩虹表
時間戳嵌入sprintf('%010d', $expiry+time())支援過期時間,防重放攻擊
完整性校驗substr(md5($string.$keyb),0,16)防篡改,解密時驗證
RC4 變體$box[($box[$a]+$box[$j])%256]雙重 S-box 查找增加分析難度
Base64 輸出str_replace('=', '', base64_encode())安全傳輸,移除填充字元

安全性已知問題

  • ⚠️ RC4 偏態:初始 keystream 存在統計偏差,現代密碼學已棄用 RC4。
  • ⚠️ 金鑰派生弱:單層 MD5,無鹽、無迭代,易受離線暴力破解。
  • ⚠️ 無認證加密:雖有完整性校驗,但非標準 AEAD 模式(如 GCM、ChaCha20-Poly1305)。
  • ⚠️ 時間戳精度秒級:高併發下可能碰撞。

現代替代方案

// PHP 7.2+ sodium 擴展(推薦)
function encrypt_modern($data, $key) {
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $cipher = sodium_crypto_secretbox($data, $nonce, $key);
    return $nonce . $cipher; // 儲存 nonce + 密文
}

function decrypt_modern($payload, $key) {
    $nonce = substr($payload, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $cipher = substr($payload, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    return sodium_crypto_secretbox_open($cipher, $nonce, $key);
}

// 金鑰生成:$key = sodium_crypto_secretbox_keygen();

authcode() 是 PHP 早期「自行實現加密」的縮影,理解其設計思路與缺陷,是避免重複造輪子、正確選用現代密碼學庫的關鍵一課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved