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

PHP OpenSSL 實現 RSA 非對稱加密完整類庫:金鑰生成、加解密、簽名驗簽一站式封裝

     編輯:PHP 相關知識

前言

RSA 非對稱加密是資料傳輸、API 簽名、授權碼驗證的基石。PHP openssl 擴展提供完整 RSA 操作介面。本文封裝一個 Rsa 類,涵蓋金鑰對生成、Pem 檔案讀寫、公鑰/私鑰加解密、Base64 編碼輸出,開箱即用。

完整 Rsa 類程式碼

<?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";
?>

關鍵注意事項

  1. 資料長度限制: RSA 直接加密資料長度 不能超過金鑰長度 - 11 位元組 (PKCS#1 v1.5 padding)。2048 位元鍵 = 256 位元組,最大加密 245 位元組。長資料請採用混合加密:AES 隨機金鑰加密資料 + RSA 加密 AES 金鑰。
  2. OpenSSL 版本: 需 PHP 編譯時包含 --with-openssl,且 OpenSSL 庫版本 ≥ 1.0.0。
  3. 金鑰格式: 本類使用 PKCS#8 PEM 格式,跨語言互通性佳(Java PKCS8EncodedKeySpec、Python cryptography 均支援)。
  4. 錯誤處理: 生產環境建議捕獲 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)。

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