MD5、SHA 等單向哈希無法還原,適用於密碼驗證;但某些場景(API Token、配置解密、URL 簽名)需要可逆加密。本文提供一個輕量、無依賴、支持自定義密鑰的加解密實現,並分析其安全特性。
<?php
class SimpleCrypt {
/** 加密:返回 Base64 字符串,每次結果不同 */
public static function encrypt(string $data, string $key): string {
$key = md5($key); // 固定 32 字節密鑰
$ivLen = 16;
$iv = random_bytes($ivLen); // 每次隨機 IV,確保密文不同
$cipher = 'aes-256-cbc';
$encrypted = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv);
if ($encrypted === false) throw new Exception('Encryption failed');
// 組合:IV + 密文 -> Base64
return base64_encode($iv . $encrypted);
}
/** 解密 */
public static function decrypt(string $encryptedData, string $key): string {
$key = md5($key);
$ivLen = 16;
$cipher = 'aes-256-cbc';
$raw = base64_decode($encryptedData, true);
if ($raw === false) throw new Exception('Invalid Base64');
if (strlen($raw) < $ivLen) throw new Exception('Data too short');
$iv = substr($raw, 0, $ivLen);
$ciphertext = substr($raw, $ivLen);
$decrypted = openssl_decrypt($ciphertext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
if ($decrypted === false) throw new Exception('Decryption failed');
return $decrypted;
}
}
// === 使用示例 ===
$key = 'my_secret_key_2024';
$plain = '敏感信息:用戶ID=10086';
$encrypted = SimpleCrypt::encrypt($plain, $key);
echo "加密: $encrypted\n";
$decrypted = SimpleCrypt::decrypt($encrypted, $key);
echo "解密: $decrypted\n";
// 輸出:解密: 敏感信息:用戶ID=10086
?>
| 特性 | 說明 |
|---|---|
| 算法 | AES-256-CBC,業界標準對稱加密 |
| 密鑰派生 | MD5 固化為 32 字節(建議生產用 PBKDF2/Argon2) |
| 隨機 IV | random_bytes(16) 確保同明文每次密文不同,抵抗重放/字典攻擊 |
| 數據格式 | IV(16字節) || 密文 -> Base64,便於存儲傳輸 |
| 錯誤處理 | 異常拋出,避免靜默失敗 |
md5($key) 為 hash_pbkdf2('sha256', $key, $salt, 100000, 32),鹽值隨機存儲。aes-256-gcm(PHP 7.1+)獲得認證加密(AEAD),防篡改。原文提供的 keyED/encrypt/decrypt 基於簡單 XOR 與隨機種子,屬於流密碼自制實現,存在嚴重缺陷:
srand(microtime()*1e6),熵極低,可預測。結論:學習原理可參考,實際項目務必使用 OpenSSL/libsodium 等經驗證庫。