Skip to content

請求格式與加密 ​

所有介面的業務參數都要用 RSA 加密後傳輸。

密鑰 ​

商戶後台「開發者 → API 與回調」裡有一對 RSA 密鑰(4096 位,PEM 格式):

密鑰開頭你用它做什麼
公鑰-----BEGIN RSA PUBLIC KEY-----加密請求參數
私鑰-----BEGIN RSA PRIVATE KEY-----解密平台發來的回調

注意

  • 私鑰只放在你的伺服器上(文件或密鑰管理服務),不要寫進程式碼、不要提交到程式碼倉庫、不要發到聊天工具裡。
  • 在商戶後台「重新生成」密鑰後,舊密鑰立刻失效:用舊公鑰加密的請求會解密失敗(40000),回調也會改用新公鑰加密。請先準備好切換再重新生成。

請求體 ​

json
{
  "merchantNo": "你的商戶號",
  "encryptedData": "Base64 字串"
}

encryptedData 的生成方法:

  1. 把業務參數寫成 JSON(UTF-8),裡面也帶上 merchantNo,例如:

    json
    {"merchantNo":"你的商戶號","merchantOrderNo":"A20261013001","amount":100,"currencyType":"CNY","customerName":"張三"}
  2. 用公鑰做 RSA 加密,填充方式 PKCS#1 v1.5(RSA/ECB/PKCS1Padding)。

  3. 把加密結果做 Base64 編碼。

平台用這個商戶號對應的私鑰解密,解不開回傳 40000。請求是按外層的 merchantNo 校驗 IP 白名單和密鑰的,加密內容裡的商戶號必須和外層一樣。

一次能加密的長度

RSA 一次最多加密「密鑰位元組數 − 11」位元組:4096 位密鑰是 501 位元組(中文一個字佔 3 位元組)。參數超長時加密會失敗,請去掉用不到的可選參數。範例程式碼會在超長時給出明確提示。

各語言寫法 ​

完整程式碼(含全部介面和回調核對)見範例程式碼,這裡只列加密的核心幾行。

js
const crypto = require('node:crypto');

function encrypt(publicKeyPem, params) {
  const data = Buffer.from(JSON.stringify(params), 'utf8');
  return crypto.publicEncrypt({ key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_PADDING }, data).toString('base64');
}
python
import base64, json
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

def encrypt(public_key_pem: str, params: dict) -> str:
    key = serialization.load_pem_public_key(public_key_pem.encode())
    data = json.dumps(params, ensure_ascii=False).encode("utf-8")
    return base64.b64encode(key.encrypt(data, padding.PKCS1v15())).decode()
php
function encrypt(string $publicKeyPem, array $params): string {
    $data = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
    openssl_public_encrypt($data, $encrypted, $publicKeyPem, OPENSSL_PKCS1_PADDING) or throw new RuntimeException('加密失敗');
    return base64_encode($encrypted);
}
java
// 商戶後台給的是 PKCS#1 公鑰(BEGIN RSA PUBLIC KEY),Java 自帶的 KeyFactory 只認 X.509,
// 範例裡的 IBitPayCrypto.readPublicKey() 已經處理好了轉換
RSAPublicKey key = IBitPayCrypto.readPublicKey(publicKeyPem);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(json.getBytes(StandardCharsets.UTF_8)));
csharp
using var rsa = RSA.Create();
rsa.ImportFromPem(publicKeyPem);   // PKCS#1 和 X.509 格式都能讀
var encryptedData = Convert.ToBase64String(rsa.Encrypt(Encoding.UTF8.GetBytes(json), RSAEncryptionPadding.Pkcs1));

安全要求 ​

  • 介面地址必須用 https://,並且要校驗證書(不要關掉證書校驗)。
  • 呼叫介面的伺服器出口 IP 要在白名單裡。下單、出款、查詢訂單、查詢流水、查詢黑名單、取消訂單、標記已付款這些介面都會檢查白名單;查詢餘額、查詢匯率、查詢收款方式目前還不檢查,但以後會統一檢查,請同樣從白名單裡的 IP 呼叫。
  • 填白名單時請填準確的出口 IP,不要填網段或帶通配符的寫法。