(1)接入方生成RSA2048公私钥对(公私钥对生成方法见下文),签名公钥录入至开放平台“个人中心-API认证账号-RSA验签公钥 (RSA-VerifyPublicKey) ”(需要用户先注册开放平台的登录账号,并进行登录),签名私钥SignPrivateKey用来计算签名。调 用接口时,请提前将服务器IP地址添加到用户IP白名单中,否则将无法调用,返回应答码为9901(详见:全局返回码说明)。
(2)使用请求头部信息和、RSA签名私钥SignPrivateKey计算得出签名信息sign。
签名规则:
a. 将请求头部信息的version、appid、bizMethod、reqId和请求报文body以&作为连接符拼接成待签名串, 型如:
"version=[version]&appId=[appId]&bizMethod= [bizMethod]&reqId=[reqId]&body=[body]";
b. 对待签名串使用SHA256做摘要(SHA256摘要算法见下文);
c. 用SignPrivateKey对摘要做RSA2048签名(RSA2048签名算法见下文),得到签名信息sign。
SignPrivateKey: RSA签名私钥;
body: 请求JSON报文;
(3)使用API认证账号AppId、签名信息sign、请求头部信息header、请求报文body,发出API调用请求。
HTTP 请求方式:
POST
HTTP URL:
https://openapi.unionpay.com/upapi/cardbin/cardinfo
HTTP 报文头(header):
Content-Type: application/json
其余参数请参考下表:
中文名称 | 英文名称 | 域类型 | 域长度 | 默认值 | 请求要求 | 备注 |
版本号 | version | string | 8 | M-必填 | 格式:xx.yy.zz 取值举例:1.0.0 | |
发送方索引类型 | appType | string | 2 | M-必填 | 取值: 00:银联索引 01:机构索引 02:商户索引 | |
发送方索引标识码 | appId | string | 32 | M-必填 | 由银联分配,请求或应答的发送方填写,标识签名验签对应的发送方 | |
接口类型 | bizMethod | string | 64 | M-必填 | 取值:宜全英文,不应出现中文 取值举例:cardbin.cardinfo | |
签名 | sign | string | 344 | M-必填 | 根据报文签名方法生成对报文摘要的签名 | |
签名或摘要方式 | signMethod | string | 20 | M-必填 | 取值: 1、RSA2 2、SM2 | |
发送方流水号 | reqId | string | 64 | M-必填 | 请求方自行生成,保证每笔交易不重复,但非交易主键 |
HTTP 报文体(body):
JSON格式接口请求报文,如{"cardNo":""}
(4)API接口的请求参数、应答参数依据业务需求会配置校验规则或加解密规则,相关内容请参考《参数规则说明》
方法一:
在Linux环境下,依次执行以下命令,使用OpenSSL生成RSA2048公私钥对。
a.生成RSA2048私钥-》upapi_private_key.pem
>openssl genrsa -out upapi_private_key.pem 2048
b.根据私钥生成公钥-》upapi_public_key.pem
>openssl rsa -in upapi_private_key.pem -out upapi_public_key.pem -pubout
将upapi_private_key.pem和upapi_public_key.pem中密钥取出整理为字符串即可。
方法二:
/** 加密算法RSA */
public static final String RSA_ALGORITHM = "RSA";
/** 获取公钥的key */
public static final String PUBLIC_KEY = "RSAPublicKey";
/** 获取私钥的key */
public static final String PRIVATE_KEY = "RSAPrivateKey";
/** 签名长度 */
private static final int KEY_SIZE = 2048;
static {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
} else {
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
}
}
/**
* 生成密钥对(公钥和私钥)
* @return
* @throws Exception
*/
public static Map<String, Object> genKeyPair() throws Exception {
KeyPairGenerator keyPairGen =KeyPairGenerator.getInstance(RSA_ALGORITHM);
keyPairGen.initialize(KEY_SIZE);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 获取公钥
* @param keyMap 密钥对
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap) {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return encode64(key.getEncoded());
}
/**
* 获取私钥
* @param keyMap 密钥对
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap) {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return encode64(key.getEncoded());
}
/**
* Discription:编码
* @return String
*/
public static String encode64(byte[] b) {
return Base64.encodeBase64String(b);
}
RSA非对称认证方式报文签名规则-Java语言
/**
* RSA非对称认证方式签名算法
*
* @param body 请求报文体
* @param SignPrivateKey RSA签名私钥
* @param ts 时间戳
*/
public static String getRSASign(String body,String SignPrivateKey,String version,String appId,String bizMethod,String reqId){
// 拼接待签名字符串,计算SHA256摘要
String signForVerify = signForRsaSignMethod(version,appId,bizMethod,reqId,body);
String realSign = null;
try {
// 对摘要做RSA2048签名
realSign = RSASignUtil.sign(signForVerify.getBytes(),SignPrivateKey);
} catch (Exception e) {
e.printStackTrace();
}
return realSign;
}
/**
* RSA非对称认证方式-SHA256摘要算法
*
* @param body 报文体
* @param ts 时间戳
* @return
*/
public static String signForRsaSignMethod(String version,String appId,String bizMethod,String reqId,String body) {
String result = "version="+version+"&appId="+appId+"&bizMethod="+bizMethod+"&reqId="+reqId+"&body="+body;;
String sign = EncodeUtils.encodeBySHA256(result);
return sign;
}
SHA256摘要算法实现样例-Java语言
private static final char[] HEX_DIGITS={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/**
* encode By SHA-256
*
* @param str
* @return
*/
public static String encodeBySHA256(String str) {
if (str == null) {
return null;
}
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.reset();
messageDigest.update(str.getBytes("UTF-8"));
return getFormattedText(messageDigest.digest());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 字节数组转换至十六进制字符串
*
* @param bytes
* @return String
*/
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
// 把密文转换成十六进制的字符串形式
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
RSA2048签名算法实现样例-Java语言
/** 需要导入包*/
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/* 加密算法*/
public static final String RSA_ALGORITHM = "RSA";
public static final String BC_PROVIDER = "BC";
/**
* 签名算法
*/
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
static {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
} else {
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
}
}
/**
* <p>
* 用私钥对信息生成数字签名
* </p>
*
* @param data
* 已加密数据
* @param privateKey
* 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static String sign(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = decode64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM,
BC_PROVIDER);
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM,
BC_PROVIDER);
signature.initSign(privateK);
signature.update(data);
return encode64(signature.sign());
}
/**
* Created on 2013-5-31
* <p>
* Discription:编码
* </p>
*
* @return String
*/
public static String encode64(byte[] b) {
return Base64.encodeBase64String(b);
}
/**
* Created on 2013-5-31
* <p>
* Discription:编码
* </p>
*
* @return btye[]
*/
public static byte[] decode64(String s) {
return Base64.decodeBase64(s);
}