Blowfish 是對稱分組加密演算法,區塊大小 64 位,密鑰長度 32-448 位。PHP 早期通過 mcrypt 擴展支援,PHP 7.1 棄用、7.2 移除,現代專案建議改用 openssl 或 sodium。本文保留 mcrypt 版本供維舊專案參考,並提供 OpenSSL 現代替代方案對照。
<?php
class BlowfishCBC
{
private $key;
private $iv;
public function __construct(string $key, string $iv = '')
{
$this->key = $key;
$this->iv = $iv ?: substr(hash('sha256', $key, true), 0, 8); // 8 字節 IV
}
/** PKCS#5 填充 */
private function pad(string $data, int $block): string
{
$pad = $block - (strlen($data) % $block);
return $data . str_repeat(chr($pad), $pad);
}
/** PKCS#5 去填充 */
private function unpad(string $data): string
{
$pad = ord($data[strlen($data) - 1]);
return substr($data, 0, -$pad);
}
/** 加密 → Base64 */
public function encrypt(string $plain): string
{
$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');
$block = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$padded = $this->pad($plain, $block);
mcrypt_generic_init($td, $this->key, $this->iv);
$cipher = mcrypt_generic($td, $padded);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return base64_encode($cipher);
}
/** Base64 → 解密 */
public function decrypt(string $cipherB64): string
{
$td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($td, $this->key, $this->iv);
$decrypted = mdecrypt_generic($td, base64_decode($cipherB64));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $this->unpad($decrypted);
}
}
// 使用範例
$bf = new BlowfishCBC('my-32-byte-secret-key-1234567890');
$encrypted = $bf->encrypt('敏感資料');
$decrypted = $bf->decrypt($encrypted);
?>
openssl_encrypt 原生支援 BF-CBC,無需額外擴展:
<?php
function bfEncrypt(string $data, string $key, string $iv = ''): string
{
$iv = $iv ?: random_bytes(8); // Blowfish IV 必須 8 字節
$ct = openssl_encrypt($data, 'BF-CBC', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $ct); // IV 前置存儲
}
function bfDecrypt(string $payload, string $key): string
{
$raw = base64_decode($payload);
$iv = substr($raw, 0, 8);
$ct = substr($raw, 8);
return openssl_decrypt($ct, 'BF-CBC', $key, OPENSSL_RAW_DATA, $iv);
}
// 測試
$key = 'my-32-byte-secret-key-1234567890';
$enc = bfEncrypt('Hello Blowfish!', $key);
echo $enc . "\n";
echo bfDecrypt($enc, $key); // Hello Blowfish!
?>
sodium_crypto_aead_*)AES-256-GCM(openssl_encrypt(..., 'aes-256-gcm'))或 Sodium crypto_aead_xchacha20poly1305_ietf