修改网联签名验签接口,添加银联签名验签接口
This commit is contained in:
parent
e877e80da9
commit
c3c0c47095
@ -5,6 +5,7 @@ import com.sunyard.inf.*;
|
|||||||
import com.sunyard.inf.customize.SydHAApi;
|
import com.sunyard.inf.customize.SydHAApi;
|
||||||
import com.sunyard.inf.customize.SydQNUCApi;
|
import com.sunyard.inf.customize.SydQNUCApi;
|
||||||
import com.sunyard.inf.customize.SydSDNXApi;
|
import com.sunyard.inf.customize.SydSDNXApi;
|
||||||
|
import com.sunyard.inf.customize.SydUnionPayApi;
|
||||||
import racal.sunyard.main.SydApiBuilder;
|
import racal.sunyard.main.SydApiBuilder;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -13,7 +14,10 @@ import java.io.InputStream;
|
|||||||
* Created by Cheney on 2017/11/11.
|
* Created by Cheney on 2017/11/11.
|
||||||
* 程序调用接口
|
* 程序调用接口
|
||||||
*/
|
*/
|
||||||
public interface SydApi extends SydRawApi, SydCertApi, SydCryptionApi, SydGenApi, SydSVApi, SydHAApi, SydQNUCApi, SydPledge, SydPINOpt, SydManufactureApi, SydZYOption {
|
public interface SydApi extends
|
||||||
|
SydRawApi, SydCertApi, SydCryptionApi, SydGenApi,
|
||||||
|
SydSVApi, SydHAApi, SydQNUCApi, SydPledge, SydPINOpt,
|
||||||
|
SydManufactureApi, SydZYOption, SydUnionPayApi {
|
||||||
|
|
||||||
byte ALG_AES = 0x30;
|
byte ALG_AES = 0x30;
|
||||||
byte ALG_SM4 = 0x31;
|
byte ALG_SM4 = 0x31;
|
||||||
|
|||||||
@ -19,6 +19,15 @@ public interface SydCryptionApi extends SydSYMApi, SydASYMApi, SydHashApi {
|
|||||||
*/
|
*/
|
||||||
interface SydHashApi {
|
interface SydHashApi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算SM3散列值
|
||||||
|
* @param sn 证书序号
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param msg 原始数据,二进制的消息块
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
byte[] SM3HashSNaId(String sn, String userId, byte[] msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入对指定的原始数据和公钥,通过 SM3 算法计算数据的散列值。
|
* 输入对指定的原始数据和公钥,通过 SM3 算法计算数据的散列值。
|
||||||
* @param publicKey 公钥的 DER 编码(可以为空)
|
* @param publicKey 公钥的 DER 编码(可以为空)
|
||||||
|
|||||||
33
src/main/java/com/sunyard/inf/customize/SydUnionPayApi.java
Normal file
33
src/main/java/com/sunyard/inf/customize/SydUnionPayApi.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package com.sunyard.inf.customize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银联接口
|
||||||
|
*/
|
||||||
|
public interface SydUnionPayApi {
|
||||||
|
/**
|
||||||
|
* 用指定的证书私钥对指定的数据进行数字签名。
|
||||||
|
* 银联
|
||||||
|
* @param pCertSerial 输入。签名 X509 证书的序列号。
|
||||||
|
* @param userId 输入。用户id。
|
||||||
|
* @param pOrgData 输入。 待签名的原始数据。
|
||||||
|
* @return 签名数据(BASE64 编码)。
|
||||||
|
*/
|
||||||
|
String netSign(String pCertSerial, String userId, byte[] pOrgData);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用指定证书对指定的原始数据进行数字签名验证。
|
||||||
|
* 银联
|
||||||
|
* @param pCertSerial 输入。 签名 X509 证书的序列号。
|
||||||
|
* @param userId 输入。用户id。
|
||||||
|
* @param pOrgData 输入。 待签名的原始数据。
|
||||||
|
* @param pSignData 输入。 签名数据(BASE64 编码)。
|
||||||
|
* @return true 表示验证正确;false 表示失败;
|
||||||
|
*/
|
||||||
|
boolean netVerify(
|
||||||
|
String pCertSerial,
|
||||||
|
String userId,
|
||||||
|
byte[] pOrgData,
|
||||||
|
String pSignData
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2232,9 +2232,139 @@ public class SydApi4j implements SydApi {
|
|||||||
return ((PacketSection) ret.get("random")).getString();
|
return ((PacketSection) ret.get("random")).getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试通过
|
|
||||||
|
/**
|
||||||
|
* 用指定的证书私钥对指定的数据进行数字签名。
|
||||||
|
* 银联
|
||||||
|
* @param pCertSerial 输入。签名 X509 证书的序列号。
|
||||||
|
* @param userId 输入。用户id。
|
||||||
|
* @param pOrgData 输入。 待签名的原始数据。
|
||||||
|
* @return 签名数据(BASE64 编码)。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String netSign(String pCertSerial, String userId, byte[] pOrgData) {
|
||||||
|
|
||||||
|
// 针对传化需求定制
|
||||||
|
// 获取协议
|
||||||
|
Proto6C proto = new Proto6C();
|
||||||
|
|
||||||
|
// 先进行 HASH
|
||||||
|
pOrgData = SM3HashSNaId(pCertSerial, userId, pOrgData );
|
||||||
|
|
||||||
|
// 填充数据
|
||||||
|
PacketSN sn = PacketSN.gen();
|
||||||
|
HashMap<String, Object> packet = new HashMap<String, Object>();
|
||||||
|
packet.put("header", sn.getSn().array());
|
||||||
|
HashMap<String, Object> data = new HashMap<String, Object>();
|
||||||
|
data.put("certificateModel$option", 0);
|
||||||
|
data.put("certificateSn", pCertSerial);
|
||||||
|
data.put("inData", pOrgData);
|
||||||
|
data.put("dataFlag", 'P');
|
||||||
|
packet.put("data", data);
|
||||||
|
|
||||||
|
// 渲染发送
|
||||||
|
ByteBuffer bb = proto.rend(packet);
|
||||||
|
synchronized (this) {
|
||||||
|
// 响应解析
|
||||||
|
bb = syncRead(syncSend(bb));
|
||||||
|
}
|
||||||
|
|
||||||
|
//ProtocolParser parser = pset.getProtocolResParse();
|
||||||
|
Packet p = proto.parse(bb);
|
||||||
|
Map<String, Object> ret = p.toMap();
|
||||||
|
if (
|
||||||
|
!Arrays.equals(sn.getSn().array(), ((PacketSection) ret.get("header")).getBytes())
|
||||||
|
) {
|
||||||
|
throw new SydApiException("包序号不匹配", -4);
|
||||||
|
}
|
||||||
|
ret = (Map<String, Object>) ret.get("data");
|
||||||
|
PacketSection error = (PacketSection) ret.get("error");
|
||||||
|
if (!"00".equals(error.getString())) {
|
||||||
|
throw new SydApiException(error.getInfo(), error.autoInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((PacketSection) ret.get("sign")).getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用指定证书对指定的原始数据进行数字签名验证。
|
||||||
|
* 银联
|
||||||
|
* @param pCertSerial 输入。 签名 X509 证书的序列号。
|
||||||
|
* @param userId 输入。用户id。
|
||||||
|
* @param pOrgData 输入。 待签名的原始数据。
|
||||||
|
* @param pSignData 输入。 签名数据(BASE64 编码)。
|
||||||
|
* @return true 表示验证正确;false 表示失败;
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean netVerify(String pCertSerial, String userId, byte[] pOrgData, String pSignData) {
|
||||||
|
// 获取协议
|
||||||
|
Proto6D proto=new Proto6D();
|
||||||
|
|
||||||
|
pOrgData = SM3HashSNaId(pCertSerial, userId, pOrgData );
|
||||||
|
|
||||||
|
// 填充数据
|
||||||
|
PacketSN sn = PacketSN.gen();
|
||||||
|
HashMap<String, Object> packet = new HashMap<String, Object>();
|
||||||
|
packet.put("header", sn.getSn().array());
|
||||||
|
HashMap<String, Object> data = new HashMap<String, Object>();
|
||||||
|
data.put("certificateModel$option", 0);
|
||||||
|
data.put("certificateSn", pCertSerial);
|
||||||
|
data.put("inData", pOrgData);
|
||||||
|
data.put("sign", pSignData);
|
||||||
|
data.put("dataFlag", 'P');
|
||||||
|
packet.put("data", data);
|
||||||
|
|
||||||
|
// 渲染发送
|
||||||
|
ByteBuffer bb = proto.rend(packet);
|
||||||
|
synchronized (this) {
|
||||||
|
// 响应解析
|
||||||
|
bb = syncRead( syncSend(bb) );
|
||||||
|
}
|
||||||
|
//ProtocolParser parser = pset.getProtocolResParse();
|
||||||
|
Packet p = proto.parse(bb);
|
||||||
|
Map<String, Object> ret = p.toMap();
|
||||||
|
if (
|
||||||
|
!Arrays.equals(sn.getSn().array(), ((PacketSection) ret.get("header")).getBytes())
|
||||||
|
) {
|
||||||
|
throw new SydApiException("包序号不匹配", -4);
|
||||||
|
}
|
||||||
|
ret = (Map<String, Object>) ret.get("data");
|
||||||
|
PacketSection error = (PacketSection) ret.get("error");
|
||||||
|
if (!"00".equals(error.getString())) {
|
||||||
|
throw new SydApiException(error.getInfo(), error.autoInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用指定的证书私钥对指定的数据进行数字签名。
|
||||||
|
* 网联
|
||||||
|
* @param pCertSerial 输入。签名 X509 证书的序列号。
|
||||||
|
* @param pOrgData 输入。 待签名的原始数据。
|
||||||
|
* @return 签名数据(BASE64 编码)。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String netSign(String pCertSerial, byte[] pOrgData) {
|
public String netSign(String pCertSerial, byte[] pOrgData) {
|
||||||
|
return netSign(pCertSerial, null, pOrgData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用指定证书对指定的原始数据进行数字签名验证。
|
||||||
|
* 网联
|
||||||
|
* @param pCertSerial 输入。 签名 X509 证书的序列号。
|
||||||
|
* @param pOrgData 输入。 待签名的原始数据。
|
||||||
|
* @param pSignData 输入。 签名数据(BASE64 编码)。
|
||||||
|
* @return true 表示验证正确;false 表示失败;
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean netVerify(String pCertSerial, byte[] pOrgData, String pSignData) {
|
||||||
|
return netVerify(pCertSerial, null, pOrgData, pSignData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 测试通过
|
||||||
|
private String _netSign(String pCertSerial, byte[] pOrgData) {
|
||||||
|
|
||||||
|
|
||||||
// 获取协议
|
// 获取协议
|
||||||
@ -2276,8 +2406,7 @@ public class SydApi4j implements SydApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 测试通过
|
// 测试通过
|
||||||
@Override
|
private boolean _netVerify(String pCertSerial, byte[] pOrgData, String pSignData) {
|
||||||
public boolean netVerify(String pCertSerial, byte[] pOrgData, String pSignData) {
|
|
||||||
// 获取协议
|
// 获取协议
|
||||||
//ProtocolRender render = pset.getProtocolReqRender("6D");
|
//ProtocolRender render = pset.getProtocolReqRender("6D");
|
||||||
Proto6D proto = new Proto6D();
|
Proto6D proto = new Proto6D();
|
||||||
@ -3811,6 +3940,173 @@ public class SydApi4j implements SydApi {
|
|||||||
return ((PacketSection) ret.get("data")).getBytes();
|
return ((PacketSection) ret.get("data")).getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] SM3HashSNaId(String sn, String userId, byte[] msg) {
|
||||||
|
return SM3Hash(null, sn, null, userId, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算SM3散列值
|
||||||
|
* @param publicKey 公钥的 DER 编码(可以为空)
|
||||||
|
* @param csn 证书序号
|
||||||
|
* @param cdn 证书DN
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param msg 原始数据,二进制的消息块
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private byte[] SM3Hash(String publicKey, String csn, String cdn, String userId, byte[] msg) {
|
||||||
|
|
||||||
|
// 填充数据
|
||||||
|
PacketSN sn = PacketSN.gen();
|
||||||
|
final int packLen = 2048;
|
||||||
|
int loop = msg.length / packLen;
|
||||||
|
if (msg.length % packLen > 0) {
|
||||||
|
loop++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存上一轮的 hash
|
||||||
|
byte[] ctx = new byte[0];
|
||||||
|
byte packtype;
|
||||||
|
int i = 0;
|
||||||
|
while (i < loop) {
|
||||||
|
if (0 == i) {
|
||||||
|
if (1 == loop) {
|
||||||
|
packtype = '0';
|
||||||
|
} else {
|
||||||
|
packtype = '1';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i == (loop - 1)) {
|
||||||
|
packtype = '3';
|
||||||
|
} else {
|
||||||
|
packtype = '2';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(3000);
|
||||||
|
|
||||||
|
byte[] ret = new byte[2];
|
||||||
|
bb.put(ret);
|
||||||
|
bb.put(sn.getSn().array());
|
||||||
|
bb.put("76".getBytes());
|
||||||
|
bb.put(packtype);
|
||||||
|
|
||||||
|
|
||||||
|
int tmplen = (i < (loop - 1) || !(msg.length % packLen > 0)) ? packLen : (msg.length % packLen);
|
||||||
|
|
||||||
|
// 填充长度
|
||||||
|
bb.put(String.format("%04d", tmplen).getBytes());
|
||||||
|
|
||||||
|
// 填充数据
|
||||||
|
bb.put(msg, i * packLen, tmplen);
|
||||||
|
|
||||||
|
|
||||||
|
if ('0' == packtype || '1' == packtype) {
|
||||||
|
|
||||||
|
|
||||||
|
if ( null != csn || null != cdn ){
|
||||||
|
if (userId != null) {
|
||||||
|
bb.put(String.format("%02d", userId.length()).getBytes());
|
||||||
|
bb.put(userId.getBytes());
|
||||||
|
} else {
|
||||||
|
bb.put(String.format("%02d", 16).getBytes());
|
||||||
|
bb.put("1234567812345678".getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过证书查找公钥
|
||||||
|
bb.put("P".getBytes());
|
||||||
|
byte[] content;
|
||||||
|
if ( null != csn ){
|
||||||
|
content = csn.getBytes();
|
||||||
|
bb.put( "0".getBytes() );
|
||||||
|
} else {
|
||||||
|
content = cdn.getBytes();
|
||||||
|
bb.put( "1".getBytes() );
|
||||||
|
}
|
||||||
|
|
||||||
|
bb.put( String.format("%04d", content.length ).getBytes() );
|
||||||
|
bb.put( content );
|
||||||
|
}
|
||||||
|
else if (null == publicKey) {
|
||||||
|
|
||||||
|
// 无公钥
|
||||||
|
|
||||||
|
bb.put(String.format("%02d", 0).getBytes());
|
||||||
|
bb.put("".getBytes());
|
||||||
|
bb.put(String.format("%04d", 0).getBytes());
|
||||||
|
bb.put("".getBytes());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 传入公钥
|
||||||
|
bb.put(String.format("%02d", 16).getBytes());
|
||||||
|
bb.put("1234567812345678".getBytes());
|
||||||
|
bb.put(String.format("%04d", publicKey.length() / 2).getBytes());
|
||||||
|
bb.put(Util.hexString2Bytes(publicKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else if ('2' == packtype || '3' == packtype) {
|
||||||
|
|
||||||
|
bb.put(String.format("%04d", ctx.length).getBytes());
|
||||||
|
bb.put(ctx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int len = bb.position() - 2;
|
||||||
|
|
||||||
|
bb.put(0, (byte) (0xFF & (len / 256)));
|
||||||
|
bb.put(1, (byte) (0xFF & (len % 256)));
|
||||||
|
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
// 响应解析
|
||||||
|
bb = syncRead(syncSend(bb));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bb.flip();
|
||||||
|
|
||||||
|
// 忽略头部
|
||||||
|
bb.get(new byte[12], 0, 12);
|
||||||
|
|
||||||
|
|
||||||
|
// 检测错误
|
||||||
|
byte[] error = new byte[2];
|
||||||
|
|
||||||
|
bb.get(error, 0, 2);
|
||||||
|
|
||||||
|
int e = Util.a2i(error, 16);
|
||||||
|
|
||||||
|
if (0 != e) {
|
||||||
|
throw new SydApiException(0x80 == e ? "数据长度错" : "输入长度错", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ('0' == packtype || '3' == packtype) {
|
||||||
|
byte[] hash = new byte[32];
|
||||||
|
bb.get(hash, 0, 32);
|
||||||
|
return hash;
|
||||||
|
} else if ('1' == packtype || '2' == packtype) {
|
||||||
|
|
||||||
|
byte[] hashLen = new byte[4];
|
||||||
|
|
||||||
|
bb.get(hashLen, 0, 4);
|
||||||
|
|
||||||
|
|
||||||
|
byte[] hash = new byte[Util.a2i(hashLen, 10)];
|
||||||
|
|
||||||
|
bb.get(hash, 0, hash.length);
|
||||||
|
|
||||||
|
ctx = hash;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] SM3Hash(byte[] msg) {
|
public byte[] SM3Hash(byte[] msg) {
|
||||||
return SM3Hash(null, msg);
|
return SM3Hash(null, msg);
|
||||||
@ -3823,6 +4119,7 @@ public class SydApi4j implements SydApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] SM3Hash(String publicKey, byte[] msg, int block, byte[] mac) {
|
public byte[] SM3Hash(String publicKey, byte[] msg, int block, byte[] mac) {
|
||||||
|
|
||||||
|
|||||||
@ -1254,6 +1254,19 @@ public class TestAllMethods {
|
|||||||
System.out.println(b);
|
System.out.println(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测试通过
|
||||||
|
// 6D
|
||||||
|
@Test
|
||||||
|
public void testNetVerify2() {
|
||||||
|
String sn = "1004282451";
|
||||||
|
String userId = "1234567812345678";
|
||||||
|
String data = "111";
|
||||||
|
String s = api.netSign(sn, userId, data.getBytes());
|
||||||
|
|
||||||
|
boolean b = api.netVerify(sn, userId, data.getBytes(), s);
|
||||||
|
System.out.println(b);
|
||||||
|
}
|
||||||
|
|
||||||
// 测试通过
|
// 测试通过
|
||||||
// 6E
|
// 6E
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user