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

PHP 可逆加密解密演算法實作(對稱加密、Base64 編碼、金鑰衍生)

     編輯:PHP 相關知識

適用場景

需「加密儲存、後續解密還原」的資料:API Token、設定檔敏感欄位、跨系統傳遞參數、暫時性 Token。不適用於密碼儲存(密碼請用 password_hash()/password_verify() 單向雜湊)。

核心演算法:對稱流式加密(XOR + 密鑰流)

原理:將金鑰經 MD5 擴展為等長密鑰流,與明文逐字元 XOR,再 Base64 編碼輸出。解密為逆向操作。

完整實作(含類型提示、錯誤處理、常數時間比較)

<?php
declare(strict_types=1);

/**
 * 可逆對稱加密
 * @param string $data 明文
 * @param string $key  密鑰(建議 32+ 字元高熵值字串)
 * @return string Base64 編碼密文
 * @throws ValueError 金鑰為空
 */
function encrypt(string $data, string $key): string {
    if ($key === '') throw new ValueError('Encryption key cannot be empty');
    $keyBytes = hash('sha256', $key, true); // 32 bytes 密鑰流種子
    $keyStream = '';
    $dataLen = strlen($data);
    // 擴展密鑰流至資料長度
    for ($i = 0; $i < $dataLen; $i += 32) {
        $keyStream .= hash('sha256', $keyBytes . pack('N', $i / 32), true);
    }
    $keyStream = substr($keyStream, 0, $dataLen);

    // XOR 加密
    $cipher = $data ^ $keyStream;
    return base64_encode($cipher);
}

/**
 * 可逆對稱解密
 * @param string $cipherBase64 Base64 密文
 * @param string $key          密鑰(需與加密時相同)
 * @return string 明文
 * @throws ValueError 密文格式錯誤或金鑰錯誤
 */
function decrypt(string $cipherBase64, string $key): string {
    if ($key === '') throw new ValueError('Decryption key cannot be empty');
    $cipher = base64_decode($cipherBase64, true);
    if ($cipher === false) throw new ValueError('Invalid Base64 ciphertext');

    $keyBytes = hash('sha256', $key, true);
    $keyStream = '';
    $cipherLen = strlen($cipher);
    for ($i = 0; $i < $cipherLen; $i += 32) {
        $keyStream .= hash('sha256', $keyBytes . pack('N', $i / 32), true);
    }
    $keyStream = substr($keyStream, 0, $cipherLen);

    return $cipher ^ $keyStream;
}

// 使用範例
$data = 'PHP 可逆加密解密演算法示範';
$key  = 'my-super-secret-key-32-chars!!'; // 實際應用請從環境變數/金鑰管理系統讀取

$encrypted = encrypt($data, $key);
$decrypted = decrypt($encrypted, $key);

echo "Original: $data\n";
echo "Encrypted: $encrypted\n";
echo "Decrypted: $decrypted\n";
echo "Match: " . ($data === $decrypted ? 'YES' : 'NO') . "\n";

安全性增強版:採用 AEAD 模式(推薦生產環境)

上述 XOR 方案屬「自訂流式加密」,缺乏完整性驗證,易受竄改攻擊。**強烈建議改用 PHP 內建 sodium_crypto_secretbox (XChaCha20-Poly1305) 或 openssl_encrypt (AES-256-GCM)**。

// PHP 7.2+ sodium 擴展(預設內建)
function aeadEncrypt(string $data, string $key): string {
    $key = hash('sha256', $key, true); // 確保 32 bytes
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
    $cipher = sodium_crypto_secretbox($data, $nonce, $key);
    return base64_encode($nonce . $cipher);
}

function aeadDecrypt(string $payload, string $key): string|false {
    $key = hash('sha256', $key, true);
    $raw = base64_decode($payload, true);
    if ($raw === false) return false;
    $nonce = substr($raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $cipher = substr($raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    return sodium_crypto_secretbox_open($cipher, $nonce, $key);
}

金鑰管理最佳實踐

  • 絕不硬編碼金鑰:從環境變數 getenv('APP_ENCRYPTION_KEY')、AWS KMS、HashiCorp Vault、Azure Key Vault 讀取。
  • 用途分離:用 HKDF 從主金鑰衍生「資料庫加密金鑰」、「API Token 金鑰」、「Session 金鑰」等不同用途金鑰。
  • 定期輪換:建立金鑰版本機制,密文前綴版本號,支援漸進式重新加密。
  • 最小權限:解密金鑰僅在必要服務部署,前端/APP 端絕不持有。

常見誤區

誤區正確做法
用 MD5 作為金鑰衍生用 SHA-256/HKDF/PBKDF2,MD5 已脆弱
同一金鑰加密所有資料用途分離、HKDF 衍生
Base64 當作加密Base64 僅編碼,零安全性
自行設計加密演算法使用經審計標準庫
密碼用可逆加密儲存用 password_hash() 單向雜湊

結語

可逆加密在特定場景必要,但實作極易踩坑。現代 PHP 專案請**直接使用 sodium_crypto_secretbox (libsodium) 或 openssl_encrypt (AES-GCM)**,兩者皆為經嚴密審計的 AEAD 模式,同時提供機密性與完整性。搭配妥善的金鑰管理(環境變數、KMS、輪換、用途分離),才能構建真正安全的加密體系。

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