首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP AES 加密類實作 (基於 OpenSSL,取代棄用 mcrypt)

     編輯:PHP 綜合知識

重要提醒

mcrypt 擴充自 PHP 7.2 起棄用,PHP 8.0 移除。 請改用 OpenSSL 或 Sodium (libsodium) 實作加密。本文提供 OpenSSL 版 AES 實作。

OpenSSL 版 AES 加密類


<?php

class AesEncryption
{
    private string $cipher;
    private string $key;
    private string $iv;
    
    /**
     * 建構子
     * 
     * @param string $key  16/24/32 位元組 (AES-128/192/256)
     * @param string $iv   16 位元組 (CBC 模式必須)
     * @param int    $bits 128, 192, 256
     */
    public function __construct(string $key, string $iv, int $bits = 256)
    {
        // 驗證金鑰長度
        $keyLen = strlen($key);
        $validKeys = [16 => 128, 24 => 192, 32 => 256];
        
        if (!isset($validKeys[$keyLen])) {
            throw new InvalidArgumentException("金鑰長度必須為 16/24/32 位元組,目前:{$keyLen}");
        }
        
        if ($validKeys[$keyLen] !== $bits) {
            throw new InvalidArgumentException("金鑰長度與位元數不符");
        }
        
        // 驗證 IV 長度 (AES 區塊大小固定 16 位元組)
        if (strlen($iv) !== 16) {
            throw new InvalidArgumentException("IV 長度必須為 16 位元組");
        }
        
        $this->cipher = "AES-{$bits}-CBC";
        $this->key    = $key;
        $this->iv     = $iv;
    }
    
    /**
     * 加密 (回傳 Base64 字串)
     */
    public function encrypt(string $data): string
    {
        $encrypted = openssl_encrypt(
            $data,
            $this->cipher,
            $this->key,
            OPENSSL_RAW_DATA,
            $this->iv
        );
        
        if ($encrypted === false) {
            throw new RuntimeException('加密失敗: ' . openssl_error_string());
        }
        
        return base64_encode($encrypted);
    }
    
    /**
     * 解密 (輸入 Base64 字串)
     */
    public function decrypt(string $encryptedData): string
    {
        $decoded = base64_decode($encryptedData, true);
        
        if ($decoded === false) {
            throw new InvalidArgumentException('無效的 Base64 資料');
        }
        
        $decrypted = openssl_decrypt(
            $decoded,
            $this->cipher,
            $this->key,
            OPENSSL_RAW_DATA,
            $this->iv
        );
        
        if ($decrypted === false) {
            throw new RuntimeException('解密失敗: ' . openssl_error_string());
        }
        
        return $decrypted;
    }
}

使用範例


// 金鑰與 IV 應從安全配置/環境變數取得,勿硬編碼
$key = random_bytes(32);  // AES-256 需 32 位元組
$iv  = random_bytes(16);  // 每次加密應使用隨機 IV

$aes = new AesEncryption($key, $iv, 256);

$plaintext = '機密資料:API 金鑰、個資等';
$encrypted = $aes->encrypt($plaintext);
$decrypted = $aes->decrypt($encrypted);

echo "原文:{$plaintext}\n";
echo "加密:{$encrypted}\n";
echo "解密:{$decrypted}\n";
// 驗證
assert($plaintext === $decrypted);

安全最佳實踐

原則說明
金鑰管理使用 KMS/環境變數/密鑰保管庫,勿寫死程式碼
IV 隨機性每次加密生成新 IV (random_bytes(16)),隨密文儲存
模式選擇CBC 需正確填充,GCM 提供認證加密 (AEAD) 更安全
完整性驗證CBC 模式建議額外 HMAC 驗證,或改用 GCM
金鑰輪換定期更換金鑰,保留舊金鑰解密歷史資料

GCM 模式範例 (PHP 7.1+,推薦)


class AesGcmEncryption
{
    public function encrypt(string $data, string $key): array
    {
        $iv = random_bytes(12);  // GCM 建議 12 位元組 IV
        $tag = '';
        
        $encrypted = openssl_encrypt(
            $data, 'AES-256-GCM', $key,
            OPENSSL_RAW_DATA, $iv, $tag, '', 16
        );
        
        return [
            'data' => base64_encode($encrypted),
            'iv'   => base64_encode($iv),
            'tag'  => base64_encode($tag),
        ];
    }
    
    public function decrypt(array $payload, string $key): string
    {
        return openssl_decrypt(
            base64_decode($payload['data']), 'AES-256-GCM', $key,
            OPENSSL_RAW_DATA, base64_decode($payload['iv']),
            base64_decode($payload['tag']), '', 16
        );
    }
}

現代替代方案:PHP 7.2+ 內建 Sodium (libsodium),提供 `sodium_crypto_aead_xchacha20poly1305_ietf_encrypt()` 等高層 API,更安全、更簡單、抗旁路攻擊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved