Skip to main content
版本: 1.0.x

签名与验证

生成请求签名

在生成签名之前,请确保以下材料已准备好:

  • 获取您的 商户安全码
  • 生成一个 RSA 密钥对。您可以通过我们的服务或自己生成
  • 上传您的 RSA 公钥 到我们的服务

请按照以下指南生成您的请求签名:

  1. ASCII 顺序按键对请求参数进行排序
  2. 通过 = 连接每个参数的键值,并通过 & 连接所有参数,然后在签名字符串的末尾附加 & 和您的安全码
  3. 使用您的 RSA private key 对签名字符串进行 SHA256 加密
  4. 将加密后的字符串使用 base64 进行编码,以获得最终签名
// 签名前的连接字符串
amount=1&channel=alipay&currency=CNY&merchantid=123456&mid=1&notifyurl=www.abc.com/callback&returnurl=www.abc.com/returnurl&service=Payment&PUT_YOUR_SAFECODE_HERE

签名生成 - 示例代码

public static String generateSignature(Map<String, String> params, String signType) {
String serializeSign = serializeSign(params, signType);

System.out.println("generateSignature serializeSign::" + serializeSign);

try {
Signature privateSignature = Signature.getInstance("SHA256withRSA");
PrivateKey privateKey = getPrivateKey("src/main/resources/private_key.pem");
privateSignature.initSign(privateKey);
privateSignature.update(serializeSign.getBytes("UTF-8"));
byte[] sign = privateSignature.sign();
return Base64.getEncoder().encodeToString(sign);
} catch (Exception e) {
e.printStackTrace();
}

return null;
}

public static String serializeSign(Map<String, String> params, String signType) {
String[] signFields;
Map<String, String> signParams = new HashMap<>();

switch (signType) {
case "payment":
signFields = new String[] { "user_id", "order_id", "amount", "currency", "channel",
"bank_code", "callback_url", "redirect_url", "timestamp" };
break;
case "withdraw":
signFields = new String[] { "user_id", "order_id", "amount", "currency", "channel",
"card_no", "card_name", "card_type", "bank_code",
"bank_name", "bank_branch", "bank_province", "bank_city",
"cnaps_code", "callback_url", "timestamp" };
break;
case "order":
case "payment_order":
case "withdraw_order":
signFields = new String[] { "user_id", "order_id" };
break;
case "payment_order_response":
case "withdraw_order_response":
signFields = new String[] { "user_id", "order_id", "transaction_id", "channel",
"submit_currency", "submit_amount", "accept_currency", "accept_amount",
"exchange_rate", "status", "timestamp" };
break;
case "payment_response":
signFields = new String[] { "user_id", "order_id", "transaction_id", "channel",
"submit_currency", "submit_amount", "accept_currency", "accept_amount",
"exchange_rate", "pay_url" };
break;
case "withdraw_response":
signFields = new String[] { "user_id", "order_id", "transaction_id", "channel",
"submit_currency", "submit_amount", "accept_currency", "accept_amount",
"exchange_rate" };
break;
case "rate":
case "rate_response":
signFields = new String[] { "user_id", "trade_currency" };
break;
case "balance":
case "balance_response":
default:
signFields = new String[] { "user_id" };
break;
}

if (signFields.length > 0) {
for (String key : signFields) {
if (params.containsKey(key)) {
signParams.put(key, params.get(key));
}
}
}

Map<String, String> sortedParams = new TreeMap<>(signParams);

StringBuilder sign = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
sign.append(entry.getKey()).append('=').append(entry.getValue()).append('&');
}
sign.append(safecode);

return sign.toString();
}

public static PrivateKey getPrivateKey(String filePath) {
try {
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) file.length()];
dis.readFully(keyBytes);
dis.close();

String temp = new String(keyBytes);
String privateKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----\n", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] decoded = Base64.getDecoder().decode(privateKeyPEM.replace("\n", ""));

PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");

return kf.generatePrivate(privateKeySpec);
} catch (Exception e) {
e.printStackTrace();
}

return null;
}

验证响应签名

在验证签名之前,请确保准备好以下材料:

  • 获取您的 商户安全码
  • 获取 PTSRSA 公钥

请按照以下指南验证从 PTS 发送的签名:

  1. ASCII 顺序对响应参数(除了签名)进行排序。所有参数(除了签名)都应参与验证字符串的构建。
  2. 使用 = 符号连接参数的键/值,然后使用 & 符号连接所有参数。
  3. 在验证字符串的末尾附加 & 和您的 商户安全码
  4. 使用 base64 解码器将响应签名解码为二进制签名。
  5. 使用 SHA256 和验证字符串以及 PTS 的公钥来验证二进制签名。

签名验证 - 示例代码

def verify_signature(pub_key_pem, before_sign_str, sign):
h = SHA256.new(before_sign_str.encode('utf-8'))
pubkey = RSA.import_key(pub_key_pem)
try:
pkcs1_15.new(pubkey).verify(h, base64.b64decode(sign))
return True
except (ValueError, TypeError):
return False