本文提供一個基於 mcrypt 擴展的 AES 加密/解密類別 AESMcrypt,支援多種金鑰長度(128/192/256 位元)與模式(CBC/ECB/CFB/OFB/NOFB)。注意:mcrypt 已於 PHP 7.1 棄用、PHP 7.2 移除,新專案請改用 openssl_encrypt() / openssl_decrypt()。
<?php
class AESMcrypt {
public $iv = null;
public $key = null;
public $bit = 128;
private $cipher;
private $mode;
public function __construct($bit, $key, $iv, $mode) {
if (empty($bit) || empty($key) || empty($iv) || empty($mode)) {
return null;
}
$this->bit = $bit;
$this->key = $key;
$this->iv = $iv;
$this->mode = $mode;
// 映射金鑰長度至 mcrypt 常數
switch ($this->bit) {
case 192: $this->cipher = MCRYPT_RIJNDAEL_192; break;
case 256: $this->cipher = MCRYPT_RIJNDAEL_256; break;
default: $this->cipher = MCRYPT_RIJNDAEL_128;
}
// 映射模式至 mcrypt 常數
switch (strtolower($this->mode)) {
case 'ecb': $this->mode = MCRYPT_MODE_ECB; break;
case 'cfb': $this->mode = MCRYPT_MODE_CFB; break;
case 'ofb': $this->mode = MCRYPT_MODE_OFB; break;
case 'nofb': $this->mode = MCRYPT_MODE_NOFB; break;
default: $this->mode = MCRYPT_MODE_CBC;
}
}
// 加密:輸出 Base64 編碼字串
public function encrypt($data) {
$encrypted = mcrypt_encrypt($this->cipher, $this->key, $data, $this->mode, $this->iv);
return base64_encode($encrypted);
}
// 解密:移除 PKCS#7 padding(mcrypt 使用零填充,需自行處理)
public function decrypt($data) {
$decrypted = mcrypt_decrypt($this->cipher, $this->key, base64_decode($data), $this->mode, $this->iv);
// 移除填充(null 字元與控制字元)
return rtrim(rtrim($decrypted), "\x00..\x1F");
}
}
?>
<?php
// 參數:金鑰長度、金鑰(16/24/32 位元組)、IV(16 位元組)、模式
$aes = new AESMcrypt(
$bit = 128,
$key = 'abcdef1234567890', // 16 bytes = 128 bits
$iv = '0987654321fedcba', // 16 bytes
$mode = 'cbc'
);
$plaintext = 'haowei.me';
$ciphertext = $aes->encrypt($plaintext);
echo "加密: $ciphertext<br>";
$decrypted = $aes->decrypt($ciphertext);
echo "解密: $decrypted<br>";
// 驗證
var_dump($plaintext === $decrypted); // bool(true)
?>
\x00 時解密錯誤。建議自行實作 PKCS#7 填充。推薦使用內建 openssl_encrypt(),支援 AES-GCM(自帶認證):
<?php
function aesGcmEncrypt(string $data, string $key, string &$iv, string &$tag): string {
$iv = random_bytes(12); // GCM 建議 12 位元組 IV
$ciphertext = openssl_encrypt($data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
return base64_encode($ciphertext);
}
function aesGcmDecrypt(string $ciphertextB64, string $key, string $iv, string $tag): string|false {
$ciphertext = base64_decode($ciphertextB64);
return openssl_decrypt($ciphertext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
}
// 使用
$key = random_bytes(32); // 256-bit 金鑰
$plaintext = '敏感資料';
$ciphertext = aesGcmEncrypt($plaintext, $key, $iv, $tag);
// 儲存:$ciphertext, $iv, $tag
$decrypted = aesGcmDecrypt($ciphertext, $key, $iv, $tag);
?>
| 特性 | mcrypt (AESMcrypt) | OpenSSL (AES-GCM) |
|---|---|---|
| PHP 版本支援 | < 7.2 | >= 7.1 |
| 認證加密 | 無(需自行實作 MAC) | 內建 (GCM/CCM) |
| 效能 | 較慢 | 硬體加速、較快 |
| 維護狀態 | 已移除 | 積極維護 |
結論:舊專案維護可暫用 AESMcrypt,但應規劃遷移至 OpenSSL AES-GCM 以確保安全性與相容性。