請求格式與加密
所有介面的業務參數都要用 RSA 加密後傳輸。
密鑰
商戶後台「開發者 → API 與回調」裡有一對 RSA 密鑰(4096 位,PEM 格式):
| 密鑰 | 開頭 | 你用它做什麼 |
|---|---|---|
| 公鑰 | -----BEGIN RSA PUBLIC KEY----- | 加密請求參數 |
| 私鑰 | -----BEGIN RSA PRIVATE KEY----- | 解密平台發來的回調 |
注意
- 私鑰只放在你的伺服器上(文件或密鑰管理服務),不要寫進程式碼、不要提交到程式碼倉庫、不要發到聊天工具裡。
- 在商戶後台「重新生成」密鑰後,舊密鑰立刻失效:用舊公鑰加密的請求會解密失敗(40000),回調也會改用新公鑰加密。請先準備好切換再重新生成。
請求體
json
{
"merchantNo": "你的商戶號",
"encryptedData": "Base64 字串"
}encryptedData 的生成方法:
把業務參數寫成 JSON(UTF-8),裡面也帶上
merchantNo,例如:json{"merchantNo":"你的商戶號","merchantOrderNo":"A20261013001","amount":100,"currencyType":"CNY","customerName":"張三"}用公鑰做 RSA 加密,填充方式 PKCS#1 v1.5(
RSA/ECB/PKCS1Padding)。把加密結果做 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,不要填網段或帶通配符的寫法。