请求格式与加密
所有接口的业务参数都要用 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,不要填网段或带通配符的写法。