| 常數 | 全名 | 特點 |
| MCRYPT_MODE_ECB | Electronic Codebook | 不需 IV、相同明文產生相同密文 (不安全) |
| MCRYPT_MODE_CBC | Cipher Block Chaining | 需 IV、推薦一般用途 |
| MCRYPT_MODE_CFB | Cipher Feedback | 串流模式、需 IV |
| MCRYPT_MODE_OFB | Output Feedback | 串流模式、需 IV |
| MCRYPT_MODE_NOFB | Output Feedback (n-bit) | 較少用 |
完整加密解密範例 (AES-128-CBC)
<?php
// 參數
$plaintext = "機密資料:信用卡號 1234-5678-9012-3456";
$key = "ThisIsASecretKey123456"; // 16/24/32 bytes 對應 128/192/256 bits
$cipher = MCRYPT_RIJNDAEL_128;
$mode = MCRYPT_MODE_CBC;
// 產生 IV (初始化向量)
$ivSize = mcrypt_get_iv_size($cipher, $mode);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM); // 安全隨機源
// 加密
$ciphertext = mcrypt_encrypt($cipher, $key, $plaintext, $mode, $iv);
// 通常將 IV + 密文一起儲存/傳輸 (IV 不需保密)
$encoded = base64_encode($iv . $ciphertext);
echo "Encrypted: $encoded\n";
// 解密
$decoded = base64_decode($encoded);
$iv = substr($decoded, 0, $ivSize);
$ciphertext = substr($decoded, $ivSize);
$decrypted = mcrypt_decrypt($cipher, $key, $ciphertext, $mode, $iv);
// 移除 PKCS#7 padding
$decrypted = rtrim($decrypted, "\0");
echo "Decrypted: $decrypted\n";
關鍵安全細節
- 金鑰長度:必須精確符合演算法要求 (AES-128=16 bytes、AES-256=32 bytes)
- IV 唯一性:CBC 模式下,**每次加密必須使用新的隨機 IV**
- IV 儲存:IV 可公開,通常預置在密文前方
- Padding:Mcrypt 使用零填充,解密後需
rtrim($data, "\0");OpenSSL 預設 PKCS#7
- 金鑰管理:勿硬編碼,使用環境變數、Key Vault、KMS
- 認證加密:Mcrypt 無內建認證,建議加密後計算 HMAC (Encrypt-then-MAC)
現代替代:OpenSSL (PHP 5.3+ 內建)
function encrypt(string $data, string $key): string {
$cipher = 'AES-256-CBC';
$ivLen = openssl_cipher_iv_length($cipher);
$iv = random_bytes($ivLen);
$ct = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $ct);
}
function decrypt(string $encoded, string $key): string {
$cipher = 'AES-256-CBC';
$data = base64_decode($encoded);
$ivLen = openssl_cipher_iv_length($cipher);
$iv = substr($data, 0, $ivLen);
$ct = substr($data, $ivLen);
return openssl_decrypt($ct, $cipher, $key, OPENSSL_RAW_DATA, $iv);
}
現代替代:libsodium (PHP 7.2+ 內建、最高安全性)
function encrypt_sodium(string $data, string $key): string {
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = sodium_crypto_secretbox($data, $nonce, $key);
return base64_encode($nonce . $cipher);
}
function decrypt_sodium(string $encoded, string $key): string {
$data = base64_decode($encoded);
$nonce = substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
return sodium_crypto_secretbox_open($cipher, $nonce, $key);
}
// 金鑰需為 SODIUM_CRYPTO_SECRETBOX_KEYBYTES (32 bytes)
$key = sodium_crypto_secretbox_keygen();
遷移清單
| Mcrypt | OpenSSL | libsodium |
| mcrypt_encrypt | openssl_encrypt | sodium_crypto_secretbox |
| mcrypt_decrypt | openssl_decrypt | sodium_crypto_secretbox_open |
| mcrypt_create_iv | random_bytes | random_bytes |
| MCRYPT_RIJNDAEL_128 | AES-128/256-CBC | XChaCha20-Poly1305 |
| 零填充 | PKCS#7 (自動) | 內建認證加密 |
- 上一篇文章: PHP Email 驗證正則表達式深度解析: eregi 時代遺產與現代替代
- 下一篇文章: PHP 多圖片上傳與格式驗證完整實現指南
Copyright ©
程式碼之家 All Rights Reserved