PHP 內建 mcrypt 擴展已於 PHP 7.2 棄用、PHP 8.0 移除。若專案需「可逆加密」且不想引入 OpenSSL/Sodium 依賴,可參考本文提供的純 PHP 實作 keyED/encrypt/decrypt 三函式組合。採用 MD5 派生金鑰 + XOR 流式加密,支援自訂私鑰,適合配置檔、API Token 等輕量資料保護。
<?php
/**
* 核心 XOR 加密/解密引擎(對稱)
* @param string $txt 明文或密文
* @param string $encrypt_key 已經過 MD5 的 32 字元金鑰
* @return string 處理後字串
*/
function keyED($txt, $encrypt_key) {
$encrypt_key = md5($encrypt_key);
$ctr = 0;
$tmp = '';
for ($i = 0; $i < strlen($txt); $i++) {
if ($ctr == strlen($encrypt_key)) $ctr = 0;
$tmp .= substr($txt, $i, 1) ^ substr($encrypt_key, $ctr, 1);
$ctr++;
}
return $tmp;
}
/**
* 加密:產生隨機金鑰 XOR 明文 → 再以主金鑰二次 XOR
* @param string $txt 明文
* @param string $key 主金鑰(私鑰)
* @return string 密文(含隨機金鑰前綴)
*/
function encrypt($txt, $key) {
srand((double)microtime() * 1000000);
$encrypt_key = md5(rand(0, 32000)); // 32 字元隨機金鑰
$ctr = 0;
$tmp = '';
for ($i = 0; $i < strlen($txt); $i++) {
if ($ctr == strlen($encrypt_key)) $ctr = 0;
// 隨機金鑰字元 + (明文 XOR 隨機金鑰字元)
$tmp .= substr($encrypt_key, $ctr, 1) . (substr($txt, $i, 1) ^ substr($encrypt_key, $ctr, 1));
$ctr++;
}
// 二次加密:以主金鑰處理
return keyED($tmp, $key);
}
/**
* 解密:先以主金鑰還原 → 再以密文內嵌的隨機金鑰還原明文
* @param string $txt 密文
* @param string $key 主金鑰
* @return string 明文
*/
function decrypt($txt, $key) {
$txt = keyED($txt, $key); // 先解第二層
$tmp = '';
for ($i = 0; $i < strlen($txt); $i++) {
$md5 = substr($txt, $i, 1); // 取出隨機金鑰字元
$i++;
$tmp .= (substr($txt, $i, 1) ^ $md5); // 密文字元 XOR 隨機金鑰字元
}
return $tmp;
}
// --- 測試範例 ---
$key = 'YITU.org';
$string = '我是加密字符';
$enc = encrypt($string, $key);
$dec = decrypt($enc, $key);
echo "加密: $enc
";
echo "解密: $dec
"; // 輸出:我是加密字符
?>
$encrypt_key(MD5 of rand),相同明文產生不同密文,防止彩虹表/頻率分析。K1⊕P1, K2⊕P2, ... 交織,解密時順序讀取金鑰字元即可還原,無需額外儲存 IV/Nonce。| 維度 | 評估 | 建議 |
|---|---|---|
| 保密性 | 中等(XOR 流式密碼,金鑰重複使用易受已知明文攻擊) | 僅用於低敏感度資料;高敏感請改用 AES-GCM |
| 完整性 | 無(密文竄改解密後會產生亂碼,但無法偵測) | 需外層加 HMAC-SHA256 或改用 AEAD 模式 |
| 效能 | 極快(純 PHP 迴圈,無擴展依賴) | 適合高頻、短資料場景 |
| 相容性 | PHP 5.3+ 全版本可用 | 舊專案遷移過渡方案 |
<?php
// 推薦:使用 Sodium (PHP 7.2+ 內建)
// 加密
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = sodium_crypto_secretbox($message, $nonce, $key);
$stored = base64_encode($nonce . $cipher);
// 解密
$raw = base64_decode($stored);
$nonce = substr($raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = substr($raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$message = sodium_crypto_secretbox_open($cipher, $nonce, $key);
?>
本文提供的自訂類適合「無法安裝擴展、需快速落地、資料敏感度中低」的情境。長期專案請規劃遷移至 Sodium 或 OpenSSL,獲得經過密碼學驗證的 AEAD 保護。