From fd6ef6050f77d569e2ba2b8866a871bff736c791 Mon Sep 17 00:00:00 2001
From: yihzhou <468340218@qq.com>
Date: Fri, 28 Oct 2022 11:20:22 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84RSA=E5=A4=A7=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E6=95=B0=E5=AD=97=E4=BF=A1=E5=B0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
DProto/6A.xml | 356 +++++++++---------
DProto/6BRSA.xml | 191 ++++++++++
.../java/racal/sunyard/main/SydApi4j.java | 139 ++++++-
src/test/java/sample/Shanghairenhang.java | 8 +-
4 files changed, 501 insertions(+), 193 deletions(-)
create mode 100644 DProto/6BRSA.xml
diff --git a/DProto/6A.xml b/DProto/6A.xml
index 4c3c2f0..28e98ea 100644
--- a/DProto/6A.xml
+++ b/DProto/6A.xml
@@ -1,229 +1,229 @@
-
+
-
- 6A
-
-
-
-
-
-
-
-
-
-
-
+
+ 6A
+
+
+
+
+
+
+
+
+
+
+
-
- 可选,存在,则固定值为‘P’
-
+
+ 可选,存在,则固定值为‘P’
+
-
-
-
-
-
-
+
+
+
+
+
+
-
- 根据证书模式,需要输入内容项的长度 n
-
+
+ 根据证书模式,需要输入内容项的长度 n
+
-
- 可选项,只针对“证书模式”为 0时有。
-
+
+ 可选项,只针对“证书模式”为 0时有。
+
-
- 可选项,只针对“证书模式”为 1时有。
-
+
+ 可选项,只针对“证书模式”为 1时有。
+
-
- 只针对算法标识为3、4时传入
-
+
+ 只针对算法标识为3、4时传入
+
-
- 只针对算法标识为3、4时传入
-
+
+ 只针对算法标识为3、4时传入
+
-
- LMK 下加密密钥的方案。
-
+
+ LMK 下加密密钥的方案。
+
-
- 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
-
+
+ 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
+
-
- 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
-
+
+ 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
+
-
-
- 签名数字信封标识符,存在则为P
-
+
+
+ 签名数字信封标识符,存在则为P
+
-
- 可选项,只针对"可选字段"为P时存在。
-
+
+ 可选项,只针对"可选字段"为P时存在。
+
-
- 可选项,只针对“证书模式”为1时有,只针对"可选字段"为P时存在。
-
-
-
-
-
-
-
+
+ 可选项,只针对“证书模式”为1时有,只针对"可选字段"为P时存在。
+
+
+
+
+
+
+
-
- 可选项。如果显示消息尾域,则该域必须显示。值为
- “X’19”。
- 19
-
+
+ 可选项。如果显示消息尾域,则该域必须显示。值为
+ “X’19”。
+ 19
+
-
- 可选项。最大长度为 32个字符。
-
-
+
+ 可选项。最大长度为 32个字符。
+
+
-
+
-
-
- 6B
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 6B
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- 公钥加密的密钥密文长度
-
+
+ 公钥加密的密钥密文长度
+
-
- 公钥加密的密钥密文的 BASE64 编码
-
+
+ 公钥加密的密钥密文的 BASE64 编码
+
-
- 如果是 'L' ,lmk 32 个字节长,否则 lmk 64 个字节长。
-
+
+ 如果是 'L' ,lmk 32 个字节长,否则 lmk 64 个字节长。
+
-
- 对称密钥的密文,由 LMK30-31 保护。
-
+
+ 对称密钥的密文,由 LMK30-31 保护。
+
-
- 密钥校验值
-
+
+ 密钥校验值
+
-
- 可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。
- 19
-
+
+ 可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。
+ 19
+
-
- 可选项。最大长度为 32个字符。
-
-
+
+ 可选项。最大长度为 32个字符。
+
+
-
-
+
diff --git a/src/main/java/racal/sunyard/main/SydApi4j.java b/src/main/java/racal/sunyard/main/SydApi4j.java
index b35d542..2d68583 100644
--- a/src/main/java/racal/sunyard/main/SydApi4j.java
+++ b/src/main/java/racal/sunyard/main/SydApi4j.java
@@ -2766,7 +2766,7 @@ public class SydApi4j implements SydApi {
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
- return generateDE(dnBytes, 0, 1, oData);
+ return generateDE(dnBytes, 4, 1, oData);
}
@Override
@@ -2786,11 +2786,15 @@ public class SydApi4j implements SydApi {
data.put("certificateDn", certSerial);
}
- if (alg == 3 || alg == 0 ) {
+ if (alg == 3 || alg == 4 ) {
data.put("orgData", oData);
}
data.put("keyType", "X");
+ if(alg == 4 ){
+ data.put("keyType", "L");
+ }
+
packet.put("data", data);
// 渲染发送 耗时长
@@ -3072,12 +3076,12 @@ public class SydApi4j implements SydApi {
X500Principal issuser = x509.getIssuerX500Principal();
String pk = ByteUtils.toHexString(x509.getPublicKey().getEncoded());
- if (!pk.startsWith("03420004")) {
- int i = pk.indexOf("03420004");
+ if (!pk.startsWith("3082010")) {
+ int i = pk.indexOf("3082010");
if ( i >= 0 ) {
pk = pk.substring(i);
} else {
- pk = "03420004" + pk;
+ pk = "3082010" + pk;
}
}
@@ -3098,7 +3102,7 @@ public class SydApi4j implements SydApi {
byte[] enData = (byte[]) retWrap.get("msg_all");
// 组织格式
- ContentInfo cms = genCMSEnvelopedData( Util.hexString2Bytes(ciperKey), enData,
+ ContentInfo cms = genCMSEnvelopedDataRSA( Util.hexString2Bytes(ciperKey), enData,
x509.getSerialNumber().toString(16) ,
dnToMap(issuser.getName() )
);
@@ -3188,6 +3192,45 @@ public class SydApi4j implements SydApi {
return info;
}
+ public static ContentInfo genCMSEnvelopedDataRSA(byte[] sessionKeyDer, byte[] enData, String sn, Mapissuer) throws UnsupportedEncodingException {
+ String tmpl = "308201d506092a864886f70d010703a08201c6308201c20201003182017c3082017802010030623059310b300906035504061302434e3130302e060355040a13274368696e612046696e616e6369616c2043657274696669636174696f6e20417574686f72697479311830160603550403130f434643412054455354204f4341313102052003470933300b06092a864886f70d01010104820100e0f8d8cf94321e7b41452845e98d5998d8c0af8aaf63a5c67a05c27c82eac3f7251d0374e59a53af39898de43a6ed9e8ca642cf3b9d19be7529be767491452b990938199384f5f7f244055ed6472e29fec18103f868109cde28f40641ddaa3c408d0629c05ec8f34b1d629975f03e05734c9931f4eae9fce912a0f8e7f726b02f3696b31c6155c191b245c8ebbb381da6f19a0b5e00e3006a3084f6519874c871ae054eae1f723aaf20982d78864b72153e47960e606cc448ece1f75a8a2f08aab2b8773af1569089253c46b7c4deab20d47a671a7f5bf06546087b98885507b69bd186c73a658efbcdd2edd5b55ea515c38729dd386425132cd5a95b5cd8e2d303d060a2a811ccf550601040201301d060960864801650304012a041000000000000000000000000000000000801043cfb263acadf7f0a5071fd7f94282ab";
+ ContentInfo info = SydCmsUtil.getContentInfo(Util.hexString2Bytes(tmpl));
+ // 修改
+ ASN1Sequence seq = (ASN1Sequence) info.getContent().toASN1Primitive();
+
+ ASN1Set set = ASN1Set.getInstance(seq.getObjectAt(1).toASN1Primitive());
+ ASN1Sequence seq2 = (ASN1Sequence) set.getObjectAt(0).toASN1Primitive();
+
+ // 会话密钥
+ DEROctetString key = (DEROctetString) seq2.getObjectAt(3);
+ BeanUtil.setFieldValue(key, "string", sessionKeyDer);
+
+ // 签发信息段
+ ASN1Sequence seq3 = (ASN1Sequence) seq2.getObjectAt(1).toASN1Primitive();
+ ASN1Integer isn = (ASN1Integer) seq3.getObjectAt(1 ).toASN1Primitive();
+ BeanUtil.setFieldValue( isn, "bytes", Util.hexString2Bytes( sn ) );
+
+ //签发者名称
+ ASN1Sequence seq4 = (ASN1Sequence) seq3.getObjectAt( 0 ).toASN1Primitive();
+// ASN1Set setO = (ASN1Set) seq4.getObjectAt(1).toASN1Primitive();
+// ASN1Sequence seqO = (ASN1Sequence) setO.getObjectAt(0).toASN1Primitive();
+// DERUTF8String o = (DERUTF8String) seqO.getObjectAt(1).toASN1Primitive();
+// BeanUtil.setFieldValue(o, "string", issuer.get("O").getBytes("UTF-8") );
+
+ ASN1Set setCN = (ASN1Set) seq4.getObjectAt(2).toASN1Primitive();
+ ASN1Sequence seqCn = (ASN1Sequence) setCN.getObjectAt(0).toASN1Primitive();
+// DERUTF8String Cn = (DERUTF8String) seqCn.getObjectAt(1).toASN1Primitive();
+// BeanUtil.setFieldValue(Cn, "string", issuer.get("CN").getBytes("UTF-8") );
+
+ // 密文段
+ ASN1Sequence seq5 = (ASN1Sequence) seq.getObjectAt(2).toASN1Primitive();
+ ASN1TaggedObject tag = (ASN1TaggedObject) seq5.getObjectAt(2).toASN1Primitive();
+ DEROctetString data = (DEROctetString) tag.getObject();
+ BeanUtil.setFieldValue(data, "string", enData);
+ return info;
+ }
+
+
public RetWrap decryptDEByDN(String certSerial, byte[] pCipherKey){
if ( pCipherKey.length <= 4 * 1024 ) {
return decryptDEByDNHsm( certSerial, new String(pCipherKey) );
@@ -3272,7 +3315,9 @@ public class SydApi4j implements SydApi {
iv = Util.bytes2HexString( iv ).getBytes();
// 解密会话密钥
- ret = decryptDERSA(true, 1, dnBytes, Util.encodeBase64(sessionKeyDer) );
+ //ret = decryptDERSA(false, 1, dnBytes, Util.encodeBase64(sessionKeyDer) );
+ ret = decryptDERSA(false, 1, dnBytes,sessionKeyDer);
+
String sessionKey = new String((byte[]) ret.get("SessionKey") );
RetWrap retWrap = SYMEnDeData(false, 2, sessionKey, 1, 1, enData, iv, 0);
@@ -3364,8 +3409,9 @@ public class SydApi4j implements SydApi {
HashMap packet = new HashMap();
packet.put("header", sn.getSn().array());
HashMap data = new HashMap();
- if (pFlag) {
- data.put("pFlag", "R");
+ data.put("pFlag", "R");
+ if (!pFlag) {
+ data.put("pFlag", "Q");
}
data.put("certificateModel$option", model);
@@ -3375,7 +3421,7 @@ public class SydApi4j implements SydApi {
data.put("certificateDn", certSerial);
}
data.put("key", pCipherKey);
- data.put("keyType", "X");
+ data.put("keyType", "L");
packet.put("data", data);
// 渲染发送
@@ -3401,10 +3447,79 @@ public class SydApi4j implements SydApi {
}
RetWrap rw = new RetWrap();
- if (pFlag) {
- rw.put("oData", ((PacketSection) ret.get("oData")).getBytes());
+// if (pFlag) {
+// rw.put("oData", ((PacketSection) ret.get("oData")).getBytes());
+// }
+ rw.put("oData", ((PacketSection) ret.get("oData")).getBytes());
+
+ int orgCodeLen = Util.a2i(((PacketSection) ret.get("orgCodeLen")).getBytes(), 10);
+ if (orgCodeLen != 0) {
+ rw.put("orgCode", ((PacketSection) ret.get("orgCode")).getBytes());
}
+ rw.put(SydApi.RET_SESSION_KEY, (((PacketSection) ret.get("lmkHead")).getString() +
+ ((PacketSection) ret.get("lmk")).getString()).getBytes()
+ );
+
+ rw.put(SydApi.RET_KCV, ((PacketSection) ret.get("keyCheck")).getBytes());
+
+ return rw;
+ }
+
+
+ public RetWrap decryptDERSA(boolean pFlag, int model, byte[] certSerial, byte[] pCipherKey) {
+ // 获取协议
+ //ProtocolRender render = pset.getProtocolReqRender("6B");
+ // 与6B相同
+ Proto6BRSA proto = new Proto6BRSA();
+ // 填充数据
+ PacketSN sn = PacketSN.gen();
+ HashMap packet = new HashMap();
+ packet.put("header", sn.getSn().array());
+ HashMap data = new HashMap();
+ data.put("pFlag", "R");
+ if (!pFlag) {
+ data.put("pFlag", "Q");
+ }
+ data.put("certificateModel$option", model);
+
+ if (model == 0) {
+ data.put("certificateSn", certSerial);
+ } else {
+ data.put("certificateDn", certSerial);
+ }
+ data.put("key", pCipherKey);
+ data.put("keyType", "L");
+ 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")).getBytes());
+// }
+ rw.put("oData", ((PacketSection) ret.get("oData")).getBytes());
+
int orgCodeLen = Util.a2i(((PacketSection) ret.get("orgCodeLen")).getBytes(), 10);
if (orgCodeLen != 0) {
rw.put("orgCode", ((PacketSection) ret.get("orgCode")).getBytes());
diff --git a/src/test/java/sample/Shanghairenhang.java b/src/test/java/sample/Shanghairenhang.java
index 8f0599c..1eb2aa1 100644
--- a/src/test/java/sample/Shanghairenhang.java
+++ b/src/test/java/sample/Shanghairenhang.java
@@ -21,7 +21,7 @@ import java.util.List;
import static com.sunyard.sydapi.util.PrintUtil.printRetWrap;
public class Shanghairenhang {
- private static final byte[] orgData2k = new byte[ 16 ];
+ private static final byte[] orgData2k = new byte[ 5*1024 ];
private static final String pcDnEN = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1";
private static final String RSA = "C=cn,O=CFCA TEST CA,OU=NCS2,OU=Enterprises,CN=041@Z402451000010@ShanDong@00000001";
@@ -41,7 +41,7 @@ public class Shanghairenhang {
* @param pcData: 明文数据。
* @return RetWrap: 数字信封
*/
- RetWrap signData = api.generateDEByDn(0,RSA, orgData.getBytes());
+ RetWrap signData = api.generateDEByDn(4,RSA, orgData2k);
byte[] cpkey2 = (byte[]) signData.get("CipherKey");
System.out.println("加密信封:" + new String(cpkey2));
@@ -51,10 +51,12 @@ public class Shanghairenhang {
* @param cpkey: 数字信封。
* @return preData: 原数据
*/
- RetWrap oDataWrap = api.decryptDEByDN(0,RSA, cpkey2);
+ RetWrap oDataWrap = api.decryptDEByDN(4,RSA, cpkey2);
byte[] preData = (byte[]) oDataWrap.get("oData");
System.out.println("解密信封:" + Util.bytes2HexString(preData));
+
+
//
} catch (Exception e) {