萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 可逆加密解密類別實作 (AES 替代方案)

專案常需加密敏感資料 (Email、ID、Token) 傳遞或儲存。本文提供一個對稱加密類別,採用自定義演算法 + Base64,並說明為何生產環境應改用 OpenSSL AES。

自定義加密類別 (教學用途)

<?php
class SysCrypt {
    private string $crypt_key;
    
    public function __construct(string $crypt_key = 'default_secret_key') {
        $this->crypt_key = $crypt_key;
    }
    
    public function encrypt(string $plaintext): string {
        // 產生隨機加密金鑰
        $encrypt_key = md5((string)random_int(0, 32000));
        $ctr = 0;
        $tmp = '';
        
        // XOR 加密 + 插入金鑰字元
        for ($i = 0; $i < strlen($plaintext); $i++) {
            $ctr = ($ctr === strlen($encrypt_key)) ? 0 : $ctr;
            $tmp .= $encrypt_key[$ctr] . ($plaintext[$i] ^ $encrypt_key[$ctr++]);
        }
        
        // 二次加密 + Base64
        return base64_encode($this->xorCipher($tmp, $this->crypt_key));
    }
    
    public function decrypt(string $ciphertext): string {
        // Base64 解碼 -> 二次解密 -> 還原 XOR
        $data = $this->xorCipher(base64_decode($ciphertext), $this->crypt_key);
        
        $tmp = '';
        for ($i = 0; $i < strlen($data); $i++) {
            $md5_char = $data[$i];
            $tmp .= $data[++$i] ^ $md5_char;
        }
        return $tmp;
    }
    
    private function xorCipher(string $data, string $key): string {
        $key = md5($key);
        $ctr = 0;
        $result = '';
        for ($i = 0; $i < strlen($data); $i++) {
            $ctr = ($ctr === strlen($key)) ? 0 : $ctr;
            $result .= $data[$i] ^ $key[$ctr++];
        }
        return $result;
    }
    
    public function __destruct() {
        $this->crypt_key = '';
    }
}

// 使用範例
$crypt = new SysCrypt('my_secret_key_2024');
$original = 'user@example.com';
$encrypted = $crypt->encrypt($original);
$decrypted = $crypt->decrypt($encrypted);

echo "原文: $original\n";
echo "密文: $encrypted\n";
echo "解密: $decrypted\n";
// 原文: user@example.com
// 密文: BS8DbFU6AioCNFFlVGZQMgRGBDUOYlEzBXoAZgo0Bjk=
// 解密: user@example.com
?>

⚠️ 關鍵安全警告

此類別僅供教學/非敏感資料!生產環境請勿使用自製加密。

  • 未經密碼學驗證:自製演算法極易存在側通道攻擊、金鑰洩露、碰撞等漏洞
  • 無完整性驗證:密文被竄改後解密不會報錯,產生垃圾資料
  • 隨機性不足:md5(rand()) 熵值極低,可被暴力破解
  • 無認證加密 (AEAD):無法防止選擇密文攻擊 (CCA)

生產環境標準:OpenSSL AES-256-GCM

<?php
class SecureCrypt {
    private string $key;   // 32 bytes (256 bits)
    private int $ivLength = 12;  // GCM 建議 12 bytes
    private int $tagLength = 16; // GCM 標籤 16 bytes
    
    public function __construct(string $keyBase64) {
        $this->key = base64_decode($keyBase64);
        if (strlen($this->key) !== 32) {
            throw new InvalidArgumentException('Key must be 32 bytes (256 bits) Base64 encoded');
        }
    }
    
    public function encrypt(string $plaintext, string $associatedData = ''): string {
        $iv = random_bytes($this->ivLength);
        $ciphertext = openssl_encrypt(
            $plaintext,
            'aes-256-gcm',
            $this->key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            $associatedData,
            $this->tagLength
        );
        
        if ($ciphertext === false) {
            throw new RuntimeException('Encryption failed: ' . openssl_error_string());
        }
        
        // 格式: IV (12) + Ciphertext + Tag (16) -> Base64
        return base64_encode($iv . $ciphertext . $tag);
    }
    
    public function decrypt(string $payload, string $associatedData = ''): string {
        $data = base64_decode($payload);
        if (strlen($data) < $this->ivLength + $this->tagLength) {
            throw new InvalidArgumentException('Invalid payload length');
        }
        
        $iv = substr($data, 0, $this->ivLength);
        $tag = substr($data, -$this->tagLength);
        $ciphertext = substr($data, $this->ivLength, -$this->tagLength);
        
        $plaintext = openssl_decrypt(
            $ciphertext,
            'aes-256-gcm',
            $this->key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            $associatedData
        );
        
        if ($plaintext === false) {
            throw new RuntimeException('Decryption failed: authentication tag mismatch (data tampered?)');
        }
        
        return $plaintext;
    }
}

// 使用
$keyBase64 = base64_encode(random_bytes(32)); // 安全儲存此金鑰!
$crypt = new SecureCrypt($keyBase64);

$encrypted = $crypt->encrypt('敏感資料', 'user_id:123'); // 附加關聯資料
$decrypted = $crypt->decrypt($encrypted, 'user_id:123');
?>

金鑰管理最佳實務

  1. 環境變數儲存:ENCRYPTION_KEY=base64_string,不進程式碼庫
  2. 金鑰輪換:定期更換,舊資料重新加密
  3. 分層金鑰:主金鑰加密資料金鑰 (Envelope Encryption)
  4. 硬體安全模組 (HSM):高安全需求使用 AWS KMS、Azure Key Vault、HashiCorp Vault

適用場景對照

場景推薦方案
API Token、Session IDrandom_bytes() + Base64 (無需解密)
密碼儲存password_hash() / bcrypt / Argon2 (單向)
資料庫敏感欄位AES-256-GCM (可逆)
URL 參數加密傳遞AES-256-GCM + Base64URL
檔案加密AES-256-GCM 分塊或 age/rage 工具
copyright © 萬盛學電腦網 all rights reserved