PHP OpenSSL 加解密函數速查與 RSA 實戰範例
PHP openssl 擴展提供完整的非對稱加密、簽名驗證、對稱加密、摘要雜湊功能。本文整理核心函數速查表,並提供 RSA 金鑰生成、加解密、簽名驗證的完整可執行範例。
核心非對稱加密函數
| 函數 | 用途 | 關鍵參數 |
openssl_public_encrypt() | 公鑰加密 (資料機密性) | $data, &$crypted, $pubKey, $padding=OPENSSL_PKCS1_PADDING |
openssl_public_decrypt() | 公鑰解密 (驗證私鑰加密簽名) | $data, &$decrypted, $pubKey, $padding |
openssl_private_encrypt() | 私鑰加密 (數位簽名) | $data, &$crypted, $privKey, $padding |
openssl_private_decrypt() | 私鑰解密 (公鑰加密資料解密) | $data, &$decrypted, $privKey, $padding |
簽名與驗證函數
| 函數 | 用途 |
openssl_sign() | 私鑰簽名,回傳二進位簽名 |
openssl_verify() | 公鑰驗證簽名,回傳 1/0/-1 |
openssl_digest() | 計算摘要 (SHA256, SHA512, MD5...) |
金鑰管理函數
openssl_pkey_new() / openssl_pkey_export() / openssl_pkey_get_details() / openssl_pkey_free()
openssl_pkey_get_public() / openssl_pkey_get_private():從 PEM 字串/檔案載入資源
OpenSSL CLI 生成 RSA 金鑰對 (2048 位元)
# 1. 生成帶密碼保護的私鑰
openssl genrsa -des3 -out private.pem 2048
# 2. 移除密碼 (方便程式讀取,生產環境建議保留密碼)
openssl rsa -in private.pem -out private_nopass.pem
# 3. 從私鑰導出公鑰
openssl rsa -in private_nopass.pem -pubout -out public.pem
PHP 完整 RSA 加解密與簽名範例
<?php
// 載入金鑰
$privKey = openssl_pkey_get_private(file_get_contents('private_nopass.pem'));
$pubKey = openssl_pkey_get_public(file_get_contents('public.pem'));
$data = '敏感資料:身分證 A123456789、金額 10000';
// --- 公鑰加密 / 私鑰解密 (資料機密性) ---
openssl_public_encrypt($data, $encrypted, $pubKey, OPENSSL_PKCS1_OAEP_PADDING); // 建議 OAEP
echo "加密後 (Base64): " . base64_encode($encrypted) . "\n";
openssl_private_decrypt($encrypted, $decrypted, $privKey, OPENSSL_PKCS1_OAEP_PADDING);
echo "解密後: $decrypted\n";
assert($decrypted === $data);
// --- 私鑰簽名 / 公鑰驗證 (完整性、不可否認性) ---
openssl_sign($data, $signature, $privKey, OPENSSL_ALGO_SHA256);
echo "簽名: " . base64_encode($signature) . "\n";
$verify = openssl_verify($data, $signature, $pubKey, OPENSSL_ALGO_SHA256);
echo "驗證結果: " . ($verify === 1 ? '成功' : ($verify === 0 ? '失敗' : '錯誤')) . "\n";
// 釋放資源
openssl_free_key($privKey);
openssl_free_key($pubKey);
?>
實戰場景:API 介面簽名驗證流程
- 客戶端:將請求參數按鍵名排序拼接 → 私鑰簽名 → Base64 → 放入 Header
X-Signature
- 伺服端:取 Header 簽名、原始參數 → 公鑰驗證 → 通過才處理業務
- 防重放:請求含
timestamp + nonce,伺服端檢查時間窗 (±5min) + Redis 去重 nonce
常見坑位與最佳實踐
| 問題 | 解決 |
| 資料長度超過金鑰長度 (RSA-2048 最大加密 245 字節) | 採用混合加密:隨機生成 AES-256 金鑰加密資料,RSA 僅加密 AES 金鑰 |
| PKCS#1 v1.5 填充遭 Bleichenbacher 攻擊 | 強制使用 OPENSSL_PKCS1_OAEP_PADDING (PHP 5.4+) |
| 私鑰檔案洩露 | 生產環境私鑰加密儲存 (HSM、KMS、環境變數加密),程式啟動時解密載入 |
| 跨語言互通 (Java, Go, Python) | 統一使用 PKCS#8 格式私鑰、X.509 公鑰、Base64 編碼、OAEP+SHA256 |
| 效能瓶頸 | RSA 僅用於金鑰交換/簽名,大量資料改用 AES-GCM/ChaCha20-Poly1305 |
對稱加密補充 (AES-256-GCM)
$key = random_bytes(32); // 256-bit 金鑰
$iv = random_bytes(12); // GCM 建議 96-bit IV
$tag = '';
$ciphertext = openssl_encrypt($data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, '', 16);
// 傳輸: $iv . $ciphertext . $tag (Base64)
// 解密: openssl_decrypt(..., $iv, $tag)
掌握 OpenSSL 核心函數、金鑰格式、填充模式與混合加密架構,即可構建符合現代密碼學最佳實踐的 PHP 安全系統。