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

PHP AES-128-ECB 加密解密類:PKCS7 填充完整實現

     編輯:PHP 綜合知識

核心類別結構

class Aes {
    private string $_secret_key;
    
    public function __construct() {
        $this->_secret_key = 'MYgGnQE2jDFADSFFDSEWsdD'; // 實際應從配置讀取
    }
    
    public function encrypt(string $str): string {
        $key = base64_decode($this->_secret_key);
        $str = trim($str);
        $str = $this->addPKCS7Padding($str);
        $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
        $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB, $iv);
        return base64_encode($encrypted);
    }
    
    public function decrypt(string $str): string {
        $key = base64_decode($this->_secret_key);
        $str = base64_decode($str);
        $key = base64_decode($key);
        $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
        $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB, $iv);
        $decrypted = trim($decrypted);
        return $this->stripPKSC7Padding($decrypted);
    }
    
    private function addPKCS7Padding(string $source): string {
        $block = mcrypt_get_block_size('rijndael-128', 'ecb'); // 16 bytes
        $pad = $block - (strlen($source) % $block);
        if ($pad <= $block) {
            $source .= str_repeat(chr($pad), $pad);
        }
        return $source;
    }
    
    private function stripPKSC7Padding(string $source): string {
        $char = substr($source, -1);
        $num = ord($char);
        if ($num == 62) return $source; // 疑似特殊處理
        return substr($source, 0, -$num);
    }
}

關鍵技術點解析

1. mcrypt 擴展已棄用/移除

PHP 7.1 棄用,7.2 移除至 PECL。 必須遷移至 openssl 或 sodium。

2. ECB 模式不安全

  • 相同明文塊產生相同密文塊,洩露模式資訊
  • 無 IV (初始化向量),無語義安全性
  • **生產環境強制使用 CBC 或 GCM 模式**

3. 密鑰管理問題

  • 硬編碼密鑰極度危險
  • base64_decode 密鑰長度需為 16/24/32 字節 (AES-128/192/256)
  • 應使用 PBKDF2/Argon2 從密碼派生密鑰

現代化重寫 (OpenSSL + AES-256-CBC)

class ModernAES {
    private string $key;
    private string $method = 'AES-256-CBC';
    
    public function __construct(string $keyBase64) {
        $this->key = base64_decode($keyBase64);
        if (strlen($this->key) !== 32) {
            throw new InvalidArgumentException('Key must be 32 bytes (256-bit) after base64 decode');
        }
    }
    
    public function encrypt(string $plaintext): string {
        $iv = random_bytes(openssl_cipher_iv_length($this->method));
        $ciphertext = openssl_encrypt($plaintext, $this->method, $this->key, OPENSSL_RAW_DATA, $iv);
        if ($ciphertext === false) throw new RuntimeException('Encryption failed');
        // 格式: IV (16 bytes) + Ciphertext
        return base64_encode($iv . $ciphertext);
    }
    
    public function decrypt(string $ciphertextBase64): string {
        $data = base64_decode($ciphertextBase64);
        $ivLen = openssl_cipher_iv_length($this->method);
        if (strlen($data) < $ivLen) throw new InvalidArgumentException('Invalid ciphertext');
        $iv = substr($data, 0, $ivLen);
        $ciphertext = substr($data, $ivLen);
        $plaintext = openssl_decrypt($ciphertext, $this->method, $this->key, OPENSSL_RAW_DATA, $iv);
        if ($plaintext === false) throw new RuntimeException('Decryption failed');
        return $plaintext;
    }
}

更推薦:Libsodium (PHP 7.2+ 內建)

class SodiumEncryption {
    public function encrypt(string $plaintext, string $key): string {
        $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
        $ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key);
        return base64_encode($nonce . $ciphertext);
    }
    
    public function decrypt(string $ciphertextBase64, string $key): string {
        $data = base64_decode($ciphertextBase64);
        $nonce = substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
        $ciphertext = substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
        $plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
        if ($plaintext === false) throw new RuntimeException('Decryption failed');
        return $plaintext;
    }
}

遷移檢查清單

  • [ ] 替換 mcrypt 為 openssl/sodium
  • [ ] 改用 CBC/GCM 模式,棄用 ECB
  • [ ] 密鑰從環境變數/金鑰管理系統讀取
  • [ ] 密鑰長度符合演算法要求
  • [ ] IV/Nonce 使用 CSPRNG 生成 (random_bytes)
  • [ ] 密文格式包含 IV/Nonce 以便解密
  • [ ] 加入認證加密 (AEAD) 或單獨 HMAC 完整性驗證
  • [ ] 完善錯誤處理、日誌、測試向量
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved