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

PHP PKI 加密實戰:openssl_public_encrypt/decrypt、openssl_sign/verify 完整範例

     編輯:PHP 綜合知識

核心概念:非對稱加密雙模式

模式加密端解密端典型場景
公鑰加密 / 私鑰解密公開金鑰私鑰機密資料傳輸(僅持有私鑰者可讀)
私鑰加密 / 公鑰解密私鑰公開金鑰數位簽章/身份驗證(人人可驗證來源)

PHP OpenSSL 關鍵函數對照

函數用途參數順序
openssl_get_privatekey()從 PEM 字串/檔案載入私鑰資源($pem, $passphrase?)
openssl_get_publickey()載入公鑰資源($pem)
openssl_public_encrypt()公鑰加密($data, &$crypted, $pubKey)
openssl_private_decrypt()私鑰解密($crypted, &$decrypted, $privKey)
openssl_private_encrypt()私鑰加密(簽名用)($data, &$crypted, $privKey)
openssl_public_decrypt()公鑰解密(驗證用)($crypted, &$decrypted, $pubKey)
openssl_sign()私鑰簽名(含雜湊)($data, &$sig, $privKey, $algo)
openssl_verify()公鑰驗證簽名($data, $sig, $pubKey, $algo)
openssl_free_key()釋放金鑰資源($keyResource)

完整可執行範例

<?php
// 假設已有金鑰檔:private.pem (PKCS#1), public.pem
$data = '敏感業務資料: 訂單號 20231001001, 金額 999.00';

// === 1. 載入金鑰 ===
$privKey = openssl_get_privatekey(file_get_contents('private.pem'));
$pubKey  = openssl_get_publickey(file_get_contents('public.pem'));
if (!$privKey || !$pubKey) {
    die('金鑰載入失敗: ' . openssl_error_string());
}

// === 2. 模式 A:公鑰加密 -> 私鑰解密(機密傳輸) ===
openssl_public_encrypt($data, $encrypted, $pubKey);
echo "Encrypted (Base64): " . base64_encode($encrypted) . "\n";

openssl_private_decrypt($encrypted, $decrypted, $privKey);
echo "Decrypted: $decrypted\n";
assert($decrypted === $data);

// === 3. 模式 B:私鑰加密 -> 公鑰解密(簽名驗證等價) ===
openssl_private_encrypt($data, $signed, $privKey);
openssl_public_decrypt($signed, $verified, $pubKey);
assert($verified === $data);

// === 4. 標準簽名/驗證(推薦:含 SHA-256 雜湊) ===
openssl_sign($data, $signature, $privKey, OPENSSL_ALGO_SHA256);
$sigB64 = base64_encode($signature);
echo "Signature: $sigB64\n";

$verify = openssl_verify($data, $signature, $pubKey, OPENSSL_ALGO_SHA256);
echo "Verify result: $verify (1=OK, 0=Fail, -1=Error)\n";

// === 5. 釋放資源 ===
openssl_free_key($privKey);
openssl_free_key($pubKey);
?>

金鑰檔案準備(對應快錢/支付寶等支付閘道)

  • 支付方提供:**商戶私鑰**(merchant_private.pem)、**支付平台公鑰**(platform_public.cer)。
  • 商戶自行生成:**商戶公鑰**(對應私鑰導出)提交給支付平台。
  • 注意: 範例中 99bill-rsa.pem 和 99bill-rsa.cer **不構成一對**;實際部署時務必使用匹配的金鑰對。

常見坑點

  1. 資料長度限制: RSA-2048 直接加密最多 245 Bytes。超長資料請採用 混合加密:AES-256-GCM 加密資料 + RSA 加密 AES Key。
  2. 填充模式: PHP 預設 OPENSSL_PKCS1_PADDING。若對接 Java (PKCS1Padding) / .NET (OAEP) 需確認一致,或用 openssl_encrypt 手動控制。
  3. 編碼傳輸: 加密結果為二進位,**必須 Base64 編碼** 後才能放入 JSON/URL/表單傳輸。
  4. 錯誤處理: 所有函數失敗回傳 false,務必檢查並記錄 openssl_error_string()。

混合加密範例(大資料)

<?php
function hybridEncrypt(string $data, $pubKey): array {
    $aesKey = random_bytes(32);      // 256-bit
    $iv     = random_bytes(16);      // 128-bit
    $tag    = '';
    $ct     = openssl_encrypt($data, 'aes-256-gcm', $aesKey, OPENSSL_RAW_DATA, $iv, $tag);
    openssl_public_encrypt($aesKey, $encKey, $pubKey);
    return [
        'key'   => base64_encode($encKey),
        'iv'    => base64_encode($iv),
        'tag'   => base64_encode($tag),
        'data'  => base64_encode($ct),
    ];
}

function hybridDecrypt(array $pkg, $privKey): string {
    $aesKey = base64_decode($pkg['key']);
    openssl_private_decrypt($aesKey, $aesKeyRaw, $privKey);
    return openssl_decrypt(
        base64_decode($pkg['data']),
        'aes-256-gcm',
        $aesKeyRaw,
        OPENSSL_RAW_DATA,
        base64_decode($pkg['iv']),
        base64_decode($pkg['tag'])
    );
}
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved