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

PHP OpenSSL RSA 加密解密完整實作:金鑰生成、公私鑰加解密、簽名驗簽、Base64 安全傳輸

     編輯:PHP 綜合知識

前言

RSA 非對稱加密是資料傳輸安全、數位簽名、API 鑑權的基石。PHP 透過 OpenSSL 擴展提供完整 RSA 功能。本文涵蓋:金鑰對生成、PKCS#1/PKCS#8 格式、公鑰加密/私鑰解密、私鑰簽名/公鑰驗證、Base64 編碼安全傳輸、常見坑與最佳實踐。

1. 生成 RSA 金鑰對

 2048,          // 建議 2048+ 位,1024 已不安全
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
];

// 生成私鑰資源
$res = openssl_pkey_new($config);

// 導出私鑰 (PKCS#1 格式,傳統 PEM)
openssl_pkey_export($res, $private_key_pem);
// 可選加密: openssl_pkey_export($res, $private_key_pem, 'passphrase');

// 導出公鑰
$pubkey_detail = openssl_pkey_get_details($res);
$public_key_pem = $pubkey_detail['key'];

echo "=== 私鑰 ===\n$private_key_pem\n";
echo "=== 公鑰 ===\n$public_key_pem\n";

// 儲存到檔案 (生產環境請設定嚴格權限 600)
file_put_contents('private_key.pem', $private_key_pem);
file_put_contents('public_key.pem', $public_key_pem);

OpenSSL 指令列生成 (更推薦,可離線、可加密)

# 生成 2048 位私鑰 (加密)
openssl genrsa -aes256 -out private_key.pem 2048

# 導出公鑰
openssl rsa -in private_key.pem -pubout -out public_key.pem

# 轉換為 PKCS#8 格式 (Java/.NET 相容)
openssl pkcs8 -topk8 -inform PEM -in private_key.pem -out private_key_pkcs8.pem -nocrypt

2. 載入金鑰資源



3. 加密與解密



關鍵限制:資料長度

金鑰長度最大加密資料 (PKCS#1 v1.5 padding)最大加密資料 (OAEP padding)
1024 bits117 bytes86 bytes
2048 bits245 bytes214 bytes
4096 bits501 bytes470 bytes

⚠️ 超長資料加密方案:混合加密 (Hybrid Encryption)

  1. 生成隨機 AES-256 金鑰 (32 bytes)
  2. 用 AES-256-GCM 加密大量資料
  3. 用 RSA 公鑰加密 AES 金鑰
  4. 傳輸: RSA加密的AES金鑰 + AES加密的資料 + IV + TAG

4. 數位簽名與驗證 (標準流程)

 比對 PKCS#1 v1.5 結構中的 hash

5. 完整可執行範例

 2048, 'private_key_type' => OPENSSL_KEYTYPE_RSA];
    $res = openssl_pkey_new($config);
    openssl_pkey_export($res, $private_key_pem);
    $public_key_pem = openssl_pkey_get_details($res)['key'];
    file_put_contents('private_key.pem', $private_key_pem);
    file_put_contents('public_key.pem', $public_key_pem);
} else {
    $private_key_pem = file_get_contents('private_key.pem');
    $public_key_pem = file_get_contents('public_key.pem');
}

$priv = openssl_pkey_get_private($private_key_pem);
$pub = openssl_pkey_get_public($public_key_pem);

// 測試資料
$tests = [
    "短字串",
    "中等長度字串: 這是一段測試資料,包含中文、English、數字 123、符號 !@#。",
    str_repeat("長字串測試 ", 50),  // 超過 RSA 直接加密限制
];

foreach ($tests as $i => $data) {
    echo "=== 測試 $i: 長度 " . strlen($data) " ===\n";
    
    // 混合加密演示 (簡化版)
    if (strlen($data) > 200) {
        echo "資料過長,實際應用請用混合加密 (AES + RSA)\n";
        continue;
    }
    
    // 公鑰加密
    $enc = '';
    openssl_public_encrypt($data, $enc, $pub);
    $enc_b64 = base64_encode($enc);
    
    // 私鑰解密
    $dec = '';
    openssl_private_decrypt(base64_decode($enc_b64), $dec, $priv);
    
    echo "原文: " . mb_substr($data, 0, 50) . "...\n";
    echo "解密: " . mb_substr($dec, 0, 50) . "...\n";
    echo "匹配: " . ($data === $dec ? "✓" : "✗") . "\n\n";
}

// 釋放資源
openssl_free_key($priv);
openssl_free_key($pub);

6. 常見坑與解決方案

問題原因解決
openssl_pkey_get_private 失敗 私鑰有密語、格式非 PKCS#1、檔案權限、換行符 傳入密語陣列 `[$pem, 'pass']`、轉 PKCS#8、chmod 600、確保 PEM 格式正確
加密資料過長錯誤 超過金鑰長度限制 使用混合加密 (AES + RSA)
Base64 編碼 URL 不安全 標準 Base64 含 + / = 用 strtr($b64, '+/=', '-_,') 或 base64url_encode
跨語言互通失敗 Padding 模式不同 (PKCS#1 v1.5 vs OAEP)、金鑰格式 (PKCS#1 vs PKCS#8) 統一 OAEP + PKCS#8,或雙方協商參數
效能差 RSA 運算慢,頻繁生成金鑰 金鑰重用、混合加密、考慮 ECC (openssl_pkey_new(['curve_name'=>'secp256r1']))

線上工具推薦

延伸閱讀

更多 PHP 相關內容可參考本站專題:《PHP 加密方法總結》、《PHP 運算與運算符用法總結》、《PHP 網絡編程技巧總結》、《PHP 基本語法入門教程》、《PHP 操作 Office 文檔技巧總結》、《PHP 日期與時間用法總結》、《PHP 面向對象程序設計入門教程》、《PHP 字符串用法總結》、《PHP+MySQL 數據庫操作入門教程》及《PHP 常見數據庫操作技巧匯總》。

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