資料加密是 Web 安全基礎建設。Discuz! 論壇早期採用的對稱加密算法結構簡單、效能優異,廣泛應用於 Cookie 加密、Token 簽名、API 參數保護等場景。本文整理並現代化該算法,封裝為符合 PSR-12 風格的 SysCrypt 類,支援任意長度字串加解密,附帶測試範例。
$encrypt_key)$crypt_key 的 MD5)對第一層結果再次 XOR解密為逆向操作:Base64 解碼 → 第二層 XOR 還原 → 提取隨機金鑰 → 第一層 XOR 還原明文。
<?php
declare(strict_types=1);
namespace App\Security;
/**
* 對稱加密工具類(參考 Discuz! passport 算法)
*
* @package App\Security
*/
class SysCrypt
{
private string $cryptKey;
public function __construct(string $cryptKey)
{
$this->cryptKey = $cryptKey;
}
/**
* 加密
* @param string $plaintext 明文
* @return string Base64 編碼的密文
*/
public function encrypt(string $plaintext): string
{
// 隨機金鑰
$encryptKey = md5((string)mt_rand(0, 32000));
$ctr = 0;
$tmp = '';
// 第一層:明文 ^ 隨機金鑰,並插入金鑰字元
for ($i = 0, $len = strlen($plaintext); $i < $len; $i++) {
$ctr = ($ctr === strlen($encryptKey)) ? 0 : $ctr;
$tmp .= $encryptKey[$ctr] . ($plaintext[$i] ^ $encryptKey[$ctr++]);
}
// 第二層:實例金鑰 XOR + Base64
return base64_encode($this->xorWithKey($tmp, $this->cryptKey));
}
/**
* 解密
* @param string $ciphertext Base64 密文
* @return string 明文
* @throws \RuntimeException 解密失敗
*/
public function decrypt(string $ciphertext): string
{
// Base64 解碼 + 第二層 XOR 還原
$decoded = $this->xorWithKey(base64_decode($ciphertext), $this->cryptKey);
$tmp = '';
// 還原:奇位為隨機金鑰,偶位為明文 ^ 金鑰
for ($i = 0, $len = strlen($decoded); $i < $len; $i++) {
$md5Char = $decoded[$i];
$tmp .= $decoded[++$i] ^ $md5Char;
}
return $tmp;
}
/**
* 核心 XOR 操作(實例金鑰 MD5 循環 XOR)
*/
private function xorWithKey(string $data, string $key): string
{
$key = md5($key);
$ctr = 0;
$result = '';
for ($i = 0, $len = strlen($data); $i < $len; $i++) {
$ctr = ($ctr === strlen($key)) ? 0 : $ctr;
$result .= $data[$i] ^ $key[$ctr++];
}
return $result;
}
public function __destruct()
{
$this->cryptKey = '';
}
}
<?php
require_once 'vendor/autoload.php';
use App\Security\SysCrypt;
$crypt = new SysCrypt('your-secret-master-key'); // 生產環境從環境變數/配置中心讀取
$original = 'user_id=12345&role=admin&expire=1735689600';
$encrypted = $crypt->encrypt($original);
echo "Encrypted: {$encrypted}\n";
$decrypted = $crypt->decrypt($encrypted);
echo "Decrypted: {$decrypted}\n";
// 驗證
var_dump($original === $decrypted); // bool(true)
| 維度 | 評估 | 建議 |
|---|---|---|
| 算法強度 | 自定義 XOR 流加密,非標準密碼學算法 | 僅用於非極高敏感資料(Cookie、Token、內部 API 參數) |
| 金鑰管理 | 單一 Master Key,無前向保密性 | 定期輪換 Master Key;敏感資料改用 AES-GCM / Libsodium |
| 隨機性 | mt_rand() 非密碼學安全 | PHP 7+ 改用 random_bytes(16) + bin2hex 生成隨機金鑰 |
| 完整性 | 無認證標籤,易遭篡改 | 關鍵資料加上 HMAC-SHA256 或改用 AEAD 模式 |
| 效能 | 極快,無外部擴展依賴 | 高頻場景(如每請求 Cookie 解密)優於 OpenSSL |
// 1. 使用密碼學安全隨機源
$encryptKey = bin2hex(random_bytes(16)); // 32 字元十六進制
// 2. 加入 HMAC 完整性驗證
$payload = $this->xorWithKey($tmp, $this->cryptKey);
$hmac = hash_hmac('sha256', $payload, $this->cryptKey, true);
return base64_encode($payload . $hmac);
// 3. 解密時先驗證 HMAC
$decoded = base64_decode($ciphertext);
$payload = substr($decoded, 0, -32);
$hmac = substr($decoded, -32);
if (!hash_equals(hash_hmac('sha256', $payload, $this->cryptKey, true), $hmac)) {
throw new \RuntimeException('HMAC verification failed');
}
password_hash() / bcrypt / Argon2)理解算法邊界,在正確場景用正確工具,才是安全工程的基本功。