diff --git a/DProto/6A.xml b/DProto/6A.xml
index 37b25e0..c3c4ae8 100644
--- a/DProto/6A.xml
+++ b/DProto/6A.xml
@@ -17,6 +17,9 @@
+
@@ -49,6 +52,14 @@
可选项,只针对“证书模式”为 1时有。
+
+ 只针对算法标识为3时传入
+
+
+
+ 只针对算法标识为3时传入
+
+
LMK 下加密密钥的方案。
@@ -72,11 +83,10 @@
-
-
-
+
+
6B
@@ -162,12 +172,10 @@
}
}
-
function getKeyLen() {
return Util.a2i( $final.getSection('data').getSection('keyLen') )
}
-
function lmkLen() {
if( Arrays.equals("L".getBytes(),
$final.getSection('data').getSection('lmkHead').getValue()
@@ -178,6 +186,10 @@
}
}
+ function dataLen() {
+ return $packet.data.orgData.length()
+ }
+
+
+ 可选,如果输入P代表使用PKCS7_SM2_SM4_ECB模式解密数字信封
+
+
-
-
@@ -104,6 +106,14 @@
+
+ 明文原始数据长度(只针对P存在时,无P时为0)
+
+
+
+ 原始数据(只针对P存在时,无P时不存在)
+
+
@@ -173,5 +183,9 @@
function orgCodeLen() {
return Util.a2i( $final.getSection('data').getSection('orgCodeLen') )
}
+
+ function oDataLen() {
+ return Util.a2i( $final.getSection('data').getSection('oDataLen') )
+ }
diff --git a/DProto/6BXF.xml b/DProto/6BXF.xml
new file mode 100644
index 0000000..02f8c96
--- /dev/null
+++ b/DProto/6BXF.xml
@@ -0,0 +1,191 @@
+
+
+
+
+
+ 6B
+
+
+
+
+ 可选,如果输入P代表使用PKCS7_SM2_SM4_ECB模式解密数字信封
+
+
+
+
+
+
+
+
+
+
+
+ 根据证书模式,需要输入内容项的长度 n
+
+
+
+
+ 可选项,只针对“证书模式”为 0时有。
+
+
+
+ 可选项,只针对“证书模式”为 1时有。
+
+
+
+ 公钥加密的密钥密文长度
+
+
+
+ 公钥加密的密钥密文的 BASE64 编码
+
+
+
+ LMK 下加密密钥的方案。
+
+
+
+ 可选项。如果显示消息尾域,则该域必须显示。值为
+ “X’19”。
+ 19
+
+
+
+ 可选项。最大长度为 32个字符。
+
+
+
+
+
+
+
+ 6C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 明文原始数据长度(只针对P存在时,无P时为0)
+
+
+
+ 原始数据(只针对P存在时,无P时不存在)
+
+
+
+
+
+
+
+ 如果是 'L' ,lmk 32 个字节长,否则 lmk 64 个字节长。
+
+
+
+ 对称密钥的密文,由 LMK30-31 保护。
+
+
+
+ 密钥校验值
+
+
+
+ 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
+
+
+
+ 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
+
+
+
+ 可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。
+ 19
+
+
+
+ 可选项。最大长度为 32个字符。
+
+
+
+
+
+
+
+
diff --git a/doc/java接口说明文档.docx b/doc/java接口说明文档.docx
index bb1c88f..1443ad4 100644
Binary files a/doc/java接口说明文档.docx and b/doc/java接口说明文档.docx differ
diff --git a/pom.xml b/pom.xml
index 2c4dfb8..ab5498d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
com.sunyard
proto
- 1.0-20220402
+ 1.0-20220412
diff --git a/src/main/java/com/sunyard/inf/SydGenApi.java b/src/main/java/com/sunyard/inf/SydGenApi.java
index 421227b..98237ec 100644
--- a/src/main/java/com/sunyard/inf/SydGenApi.java
+++ b/src/main/java/com/sunyard/inf/SydGenApi.java
@@ -216,6 +216,32 @@ public interface SydGenApi {
*/
RetWrap generateDEByDn(byte[] dn, int alg, int model) throws Exception;
+ /**
+ * 产生对称密钥,通过公钥加密生成网联格式的数字信封。
+
+ * @param certSerial 证书DN。
+ * @param oData 明文数据
+ * @return RetWrap 包含 CipherKey SessionKey KCV
+ * CipherKey 公钥加密的会话密钥 ,BASE64 编码
+ * SessionKey 本地LMK 加密的会话密钥,HEX 格式, 本地 LMK 加密的会话密钥长度,HEX 格式(不包括第 1 个字符),一般为 33 个 Bytes。默认输入值为缓冲区的大小。
+ * KCV 会话密钥的检验值,HEX 格式,长度为 32H。
+ */
+ RetWrap generateDEByDn(byte[] certSerial, String oData);
+
+ /**
+ * 产生对称密钥,通过公钥加密生成网联格式的数字信封。
+
+ * @param certSerial 证书DN或SN。
+ * @param alg 算法标识,0:AES,1-3:SM4
+ * @param model 证书模式,0:证书序号,1:证书 DN
+ * @param oData 明文数据
+ * @return RetWrap 包含 CipherKey SessionKey KCV
+ * CipherKey 公钥加密的会话密钥 ,BASE64 编码
+ * SessionKey 本地LMK 加密的会话密钥,HEX 格式, 本地 LMK 加密的会话密钥长度,HEX 格式(不包括第 1 个字符),一般为 33 个 Bytes。默认输入值为缓冲区的大小。
+ * KCV 会话密钥的检验值,HEX 格式,长度为 32H。
+ */
+ RetWrap generateDE(byte[] certSerial, int alg, int model, String oData);
+
/**
* 产生对称密钥,通过公钥加密生成网联格式的数字信封。
@@ -271,6 +297,34 @@ public interface SydGenApi {
String pCipherKey
);
+ /**
+ * 接收用私钥解密数字信封,还原对称密钥。
+ * 默认会传P
+ * @param certSerial 输入。 对方 X509 证书的DN。
+ * @param pCipherKey 输入。 公钥加密的会话密钥,BASE64 编码
+ * @return RetWrap 包含 SessionKey KCV
+ * oData 如果有机构码的话会返回原数据
+ * SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文
+ * KCV 会话密钥的检验值,HEX 格式,长度为 36H。
+ * orgCode 如果有机构码的话会返回机构码
+ */
+ RetWrap decryptDEByDN(byte[] certSerial, String pCipherKey);
+
+ /**
+ * 接收用私钥解密数字信封,还原对称密钥。
+ *
+ * @param pFlag 输入。 p标识,如果为true,则传入P
+ * @param model 输入。 证书模式,0:证书序号,1:证书 DN
+ * @param certSerial 输入。 对方 X509 证书的序列号或DN。
+ * @param pCipherKey 输入。 公钥加密的会话密钥,BASE64 编码
+ * @return RetWrap 包含 SessionKey KCV
+ * oData 如果有机构码的话会返回原数据
+ * SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文
+ * KCV 会话密钥的检验值,HEX 格式,长度为 36H。
+ * orgCode 如果有机构码的话会返回机构码
+ */
+ RetWrap decryptDE(boolean pFlag, int model, byte[] certSerial, String pCipherKey);
+
/**
* 产生要求长度的随即数据串,可用于身份认证
*
diff --git a/src/main/java/racal/sunyard/main/SydApi4j.java b/src/main/java/racal/sunyard/main/SydApi4j.java
index 1ed7c56..908e32c 100644
--- a/src/main/java/racal/sunyard/main/SydApi4j.java
+++ b/src/main/java/racal/sunyard/main/SydApi4j.java
@@ -2115,58 +2115,6 @@ public class SydApi4j implements SydApi {
return repackEncrypt(packet);
}
- // 当证书模式为证书序号时,测试成功
- // 测试通过
- @Override
- public RetWrap generateDEByDn(byte[] dn, int alg, int model) {
- Proto6A proto = new Proto6A();
- // 填充数据
- PacketSN sn = PacketSN.gen();
- HashMap packet = new HashMap();
- packet.put("header", sn.getSn().array());
- HashMap data = new HashMap();
- data.put("alg$option", alg);
- data.put("certificateModel$option", model);
-
- if (model == 0) {
- data.put("certificateSn", dn);
- } else {
- data.put("certificateDn", dn);
- }
- data.put("keyType", "X");
-
- 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 ret = p.toMap();
- if (
- !Arrays.equals(sn.getSn().array(), ((PacketSection) ret.get("header")).getBytes())
- ) {
- throw new SydApiException("包序号不匹配", -4);
- }
- ret = (Map) ret.get("data");
- PacketSection error = (PacketSection) ret.get("error");
- if (!"00".equals(error.getString())) {
- throw new SydApiException(error.getInfo(), error.autoInt());
- }
- RetWrap rw = new RetWrap();
- rw.put(SydApi.RET_CIPHER_KEY, ((PacketSection) ret.get("key")).getString());
- rw.put(SydApi.RET_SESSION_KEY, ((PacketSection) ret.get("lmkHead")).getString() +
- ((PacketSection) ret.get("lmk")).getString()
- );
-
- rw.put(SydApi.RET_KCV, ((PacketSection) ret.get("keyCheck")).getString());
-
- return rw;
- }
-
@Override
public RetWrap generateDEbyGS(String certSerial, byte nAlg) {
return generateDE(1, certSerial, nAlg, null);
@@ -2238,7 +2186,74 @@ public class SydApi4j implements SydApi {
return rw;
}
+ // 当证书模式为证书序号时,测试成功
// 测试通过
+ @Override
+ public RetWrap generateDEByDn(byte[] dn, int alg, int model) {
+ return generateDE(dn, alg, model, null);
+ }
+
+ @Override
+ public RetWrap generateDEByDn(byte[] certSerial, String oData) {
+ return generateDE(certSerial, 3, 1, oData);
+ }
+
+ @Override
+ public RetWrap generateDE(byte[] certSerial, int alg, int model, String oData) {
+ Proto6A proto = new Proto6A();
+ // 填充数据
+ PacketSN sn = PacketSN.gen();
+ HashMap packet = new HashMap();
+ packet.put("header", sn.getSn().array());
+ HashMap data = new HashMap();
+ data.put("alg$option", alg);
+ data.put("certificateModel$option", model);
+
+ if (model == 0) {
+ data.put("certificateSn", certSerial);
+ } else {
+ data.put("certificateDn", certSerial);
+ }
+
+ if (alg == 3) {
+ data.put("orgData", oData);
+ }
+
+ data.put("keyType", "X");
+
+ 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 ret = p.toMap();
+ if (
+ !Arrays.equals(sn.getSn().array(), ((PacketSection) ret.get("header")).getBytes())
+ ) {
+ throw new SydApiException("包序号不匹配", -4);
+ }
+ ret = (Map) ret.get("data");
+ PacketSection error = (PacketSection) ret.get("error");
+ if (!"00".equals(error.getString())) {
+ throw new SydApiException(error.getInfo(), error.autoInt());
+ }
+ RetWrap rw = new RetWrap();
+ rw.put(SydApi.RET_CIPHER_KEY, ((PacketSection) ret.get("key")).getString());
+ rw.put(SydApi.RET_SESSION_KEY, ((PacketSection) ret.get("lmkHead")).getString() +
+ ((PacketSection) ret.get("lmk")).getString()
+ );
+
+ rw.put(SydApi.RET_KCV, ((PacketSection) ret.get("keyCheck")).getString());
+
+ return rw;
+ }
+
+
@Override
public RetWrap decryptDE(String certSerial, String pCipherKey) {
// 获取协议
@@ -2292,6 +2307,78 @@ public class SydApi4j implements SydApi {
return rw;
}
+ @Override
+ public RetWrap decryptDEByDN(byte[] certSerial, String pCipherKey) {
+ return decryptDE(true, 1, certSerial, pCipherKey);
+ }
+
+ // 测试通过
+ @Override
+ public RetWrap decryptDE(boolean pFlag, int model, byte[] certSerial, String pCipherKey) {
+ // 获取协议
+ //ProtocolRender render = pset.getProtocolReqRender("6B");
+ // 与6B相同
+ Proto6BXF proto = new Proto6BXF();
+ // 填充数据
+ PacketSN sn = PacketSN.gen();
+ HashMap packet = new HashMap();
+ packet.put("header", sn.getSn().array());
+ HashMap data = new HashMap();
+ if (pFlag) {
+ data.put("pFlag", "P");
+ }
+ data.put("certificateModel$option", model);
+
+ if (model == 0) {
+ data.put("certificateSn", certSerial);
+ } else {
+ data.put("certificateDn", certSerial);
+ }
+ data.put("key", pCipherKey);
+ data.put("keyType", "X");
+ 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 ret = p.toMap();
+ if (
+ !Arrays.equals(sn.getSn().array(), ((PacketSection) ret.get("header")).getBytes())
+ ) {
+ throw new SydApiException("包序号不匹配", -4);
+ }
+ ret = (Map) ret.get("data");
+ PacketSection error = (PacketSection) ret.get("error");
+ if (!"00".equals(error.getString())) {
+ throw new SydApiException(error.getInfo(), error.autoInt());
+ }
+ RetWrap rw = new RetWrap();
+
+ if (pFlag) {
+ rw.put("oData", ((PacketSection) ret.get("oData")).getString());
+ }
+
+ int orgCodeLen = Util.a2i(((PacketSection) ret.get("orgCodeLen")).getBytes(), 10);
+ if (orgCodeLen != 0) {
+ rw.put("orgCode", ((PacketSection) ret.get("orgCode")).getString());
+ }
+
+ rw.put(SydApi.RET_SESSION_KEY, ((PacketSection) ret.get("lmkHead")).getString() +
+ ((PacketSection) ret.get("lmk")).getString()
+ );
+
+ rw.put(SydApi.RET_KCV, ((PacketSection) ret.get("keyCheck")).getString());
+
+ return rw;
+ }
+
// 测试通过
@Override
public String GenerateRandom(int nRandomSize) {
diff --git a/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java b/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java
index c919cf4..f5f87bc 100644
--- a/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java
+++ b/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java
@@ -1353,8 +1353,7 @@ public class TestAllMethods {
String sessionKey = (String) retWrap.get("SessionKey");
String CipherKey = (String) retWrap.get("CipherKey");
String KCV = (String) retWrap.get("KCV");
-
- System.out.println("CipherKey: " + CipherKey);
+ printRetWrap(retWrap);
RetWrap retWrap1 = api.decryptDE(sn, CipherKey);
sessionKey = (String) retWrap1.get("SessionKey");
@@ -1365,8 +1364,8 @@ public class TestAllMethods {
// 6B
@Test
public void testDecryptDE2() {
-// String sn = "1004282452";
- String sn = "1FD9F2049860FD072F0CC71B072EBF9952E2784E";
+ String sn = "1004282452";
+// String sn = "1FD9F2049860FD072F0CC71B072EBF9952E2784E";
RetWrap retWrap = api.generateDE(sn, SydApi.ALG_SM4);
String CipherKey = (String) retWrap.get("CipherKey");
printRetWrap(retWrap);
@@ -1426,6 +1425,20 @@ public class TestAllMethods {
printRetWrap(retWrap1);
}
+ @Test
+ public void testDecryptDE5() throws UnsupportedEncodingException {
+ String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
+ String oData = "00001111222233";
+
+ RetWrap retWrap = api.generateDEByDn(dn.getBytes("gbk"), oData);
+ String CipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY);
+ String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY);
+ printRetWrap(retWrap);
+
+ RetWrap retWrap1 = api.decryptDEByDN(dn.getBytes("gbk"), CipherKey);
+ printRetWrap(retWrap1);
+ }
+
// 测试通过
// 6C
@Test
diff --git a/src/test/java/com/sunyard/sydapi/test/TestHT.java b/src/test/java/com/sunyard/sydapi/test/TestHT.java
index 90125f6..006201d 100644
--- a/src/test/java/com/sunyard/sydapi/test/TestHT.java
+++ b/src/test/java/com/sunyard/sydapi/test/TestHT.java
@@ -9,6 +9,11 @@ import org.junit.Before;
import org.junit.Test;
import racal.sunyard.main.SydApi4j;
+import java.io.UnsupportedEncodingException;
+import java.util.Base64;
+
+import static com.sunyard.sydapi.util.PrintUtil.printRetWrap;
+
/**
* 衡泰例子
*/
@@ -71,7 +76,7 @@ public class TestHT {
// 8018
@Test
public void testAttachedSignAndVerify() {
- String dn = "C=CN,O=Sunyard,OU=8001,CN=8001";
+ String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
String orgData = "111111213323143243243";
String sign = api.attachedSign(orgData.getBytes(), dn);
System.out.println("签名结果: " + sign);
@@ -82,7 +87,7 @@ public class TestHT {
@Test
public void testAttachedSignAndVerifyGetX509() {
- String dn = "C=CN,O=Sunyard,OU=8001,CN=8001";
+ String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
String orgData = "111111213323143243243";
String sign = api.attachedSign(orgData.getBytes(), dn);
System.out.println("签名结果: " + sign);
@@ -93,7 +98,7 @@ public class TestHT {
@Test
public void testAttachedSignAndVerifyRD() {
- String dn = "C=CN,O=Sunyard,OU=8001,CN=8001";
+ String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
String orgData = "111111213323143243243";
String sign = api.attachedSign(orgData.getBytes(), dn);
System.out.println("签名结果: " + sign);
@@ -104,7 +109,7 @@ public class TestHT {
@Test
public void testAttachedSignAndVerifyGetAll() {
- String dn = "C=CN,O=Sunyard,OU=8001,CN=8001";
+ String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
String orgData = "111111213323143243243";
String sign = api.attachedSign(orgData.getBytes(), dn);
System.out.println("签名结果: " + sign);
@@ -116,6 +121,20 @@ public class TestHT {
}
}
+ @Test
+ public void testDecryptDE5() throws UnsupportedEncodingException {
+ String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
+ String oData = "00001111222233";
+
+ RetWrap retWrap = api.generateDEByDn(dn.getBytes("gbk"), oData);
+ String CipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY);
+ String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY);
+ printRetWrap(retWrap);
+
+ RetWrap retWrap1 = api.decryptDEByDN(dn.getBytes("gbk"), CipherKey);
+ printRetWrap(retWrap1);
+ }
+
// 测试通过
// 76
@Test