RSA 非對稱加密是資料傳輸、API 簽名、授權碼驗證的基石。PHP openssl 擴展提供完整 RSA 操作介面。本文封裝一個 Rsa 類,涵蓋金鑰對生成、Pem 檔案讀寫、公鑰/私鑰加解密、Base64 編碼輸出,開箱即用。
<?php
class Rsa {
private $_privKey; // 私鑰資源
private $_pubKey; // 公鑰資源
private $_keyPath; // 金鑰儲存目錄
/**
* 建構子:指定金鑰儲存路徑
* @param string $path 目錄路徑,需可寫入
*/
public function __construct($path) {
if (empty($path) || !is_dir($path)) {
throw new Exception('Must set valid keys save path');
}
$this->_keyPath = $path;
}
/** 生成 2048 位元金鑰對並儲存為 priv.key / pub.key */
public function createKey() {
$config = [
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$res = openssl_pkey_new($config);
if (!$res) throw new Exception('Key generation failed: ' . openssl_error_string());
// 匯出私鑰 (PKCS#8 PEM 格式)
openssl_pkey_export($res, $privKeyPem);
file_put_contents($this->_keyPath . DIRECTORY_SEPARATOR . 'priv.key', $privKeyPem);
$this->_privKey = openssl_pkey_get_private($privKeyPem);
// 取得公鑰
$pubKeyArr = openssl_pkey_get_details($res);
$pubKeyPem = $pubKeyArr['key'];
file_put_contents($this->_keyPath . DIRECTORY_SEPARATOR . 'pub.key', $pubKeyPem);
$this->_pubKey = openssl_pkey_get_public($pubKeyPem);
}
/** 載入私鑰資源 */
public function setupPrivKey() {
if (is_resource($this->_privKey)) return true;
$file = $this->_keyPath . DIRECTORY_SEPARATOR . 'priv.key';
$pem = file_get_contents($file);
$this->_privKey = openssl_pkey_get_private($pem);
return true;
}
/** 載入公鑰資源 */
public function setupPubKey() {
if (is_resource($this->_pubKey)) return true;
$file = $this->_keyPath . DIRECTORY_SEPARATOR . 'pub.key';
$pem = file_get_contents($file);
$this->_pubKey = openssl_pkey_get_public($pem);
return true;
}
/** 私鑰加密 → Base64 (適用簽名、授權碼生成) */
public function privEncrypt($data) {
if (!is_string($data)) return null;
$this->setupPrivKey();
$ok = openssl_private_encrypt($data, $encrypted, $this->_privKey);
return $ok ? base64_encode($encrypted) : null;
}
/** 私鑰解密 (配合公鑰加密) */
public function privDecrypt($encrypted) {
if (!is_string($encrypted)) return null;
$this->setupPrivKey();
$decoded = base64_decode($encrypted);
$ok = openssl_private_decrypt($decoded, $decrypted, $this->_privKey);
return $ok ? $decrypted : null;
}
/** 公鑰加密 → Base64 (適用資料傳輸加密) */
public function pubEncrypt($data) {
if (!is_string($data)) return null;
$this->setupPubKey();
$ok = openssl_public_encrypt($data, $encrypted, $this->_pubKey);
return $ok ? base64_encode($encrypted) : null;
}
/** 公鑰解密 (配合私鑰加密/驗簽) */
public function pubDecrypt($crypted) {
if (!is_string($crypted)) return null;
$this->setupPubKey();
$decoded = base64_decode($crypted);
$ok = openssl_public_decrypt($decoded, $decrypted, $this->_pubKey);
return $ok ? $decrypted : null;
}
/** 釋放資源 */
public function __destruct() {
if (is_resource($this->_privKey)) openssl_free_key($this->_privKey);
if (is_resource($this->_pubKey)) openssl_free_key($this->_pubKey);
}
}
?>
<?php
require 'Rsa.php';
// 1. 初始化並生成金鑰 (僅首次執行)
$rsa = new Rsa(__DIR__ . '/ssl-key');
if (!file_exists(__DIR__ . '/ssl-key/priv.key')) {
$rsa->createKey();
echo "金鑰對已生成至 ssl-key/ 目錄\n";
}
// 2. 私鑰加密 -> 公鑰解密 (數位簽名場景模擬)
$source = '我是老鱉';
echo "原文:$source\n";
$encrypted = $rsa->privEncrypt($source);
echo "私鑰加密:$encrypted\n";
$decrypted = $rsa->pubDecrypt($encrypted);
echo "公鑰解密:$decrypted\n\n";
// 3. 公鑰加密 -> 私鑰解密 (資料機密傳輸場景)
$source2 = '干IT的';
echo "原文:$source2\n";
$encrypted2 = $rsa->pubEncrypt($source2);
echo "公鑰加密:$encrypted2\n";
$decrypted2 = $rsa->privDecrypt($encrypted2);
echo "私鑰解密:$decrypted2\n";
?>
--with-openssl,且 OpenSSL 庫版本 ≥ 1.0.0。PKCS8EncodedKeySpec、Python cryptography 均支援)。openssl_error_string() 記錄詳細失敗原因。若需數位簽名(防篡改、防抵賴),請使用 openssl_sign() (私鑰簽名) + openssl_verify() (公鑰驗證),支援 SHA256、SHA512 等演算法,比手動「私鑰加密」更標準、安全。
// 簽名
$signature = '';
openssl_sign($data, $signature, $privKey, OPENSSL_ALGO_SHA256);
$sigBase64 = base64_encode($signature);
// 驗簽
$ok = openssl_verify($data, base64_decode($sigBase64), $pubKey, OPENSSL_ALGO_SHA256);
// $ok === 1 成功, 0 失敗, -1 錯誤
這個 Rsa 類封裝了金鑰全生命週期管理與核心加解密操作,符合 PSR 風格,可直接併入 Composer 專案。記住「短資料直加、長資料混合加密」原則,並妥善保管私鑰檔案權限(建議 600)。