diff --git a/DProto/6A.xml b/DProto/6A.xml index 30f4544..37b25e0 100644 --- a/DProto/6A.xml +++ b/DProto/6A.xml @@ -14,6 +14,9 @@ + @@ -50,6 +53,14 @@ LMK 下加密密钥的方案。 + + 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在 + + + + 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在 + + 可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。 @@ -140,29 +151,50 @@ - + function lmkLen() { + if( Arrays.equals("L".getBytes(), + $final.getSection('data').getSection('lmkHead').getValue() + ) ){ + return 64 + }else{ + return 32 + } + } + + > 8 & 0xFF) + data[1] = (byte)(len & 0xFF) + + return data; + } + ]]> + diff --git a/DProto/6B.xml b/DProto/6B.xml index a67bb3c..9cd0fc2 100644 --- a/DProto/6B.xml +++ b/DProto/6B.xml @@ -120,6 +120,14 @@ 密钥校验值 + + 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在 + + + + 公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在 + + 可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。 19 @@ -133,32 +141,37 @@ - + function lmkLen() { + if( Arrays.equals("L".getBytes(), + $final.getSection('data').getSection('lmkHead').getValue() + ) ){ + return 64 + }else{ + return 32 + } + } + function orgCodeLen() { + return Util.a2i( $final.getSection('data').getSection('orgCodeLen') ) + } + diff --git a/doc/java接口说明文档.docx b/doc/java接口说明文档.docx index e176303..c2f88f6 100644 Binary files a/doc/java接口说明文档.docx and b/doc/java接口说明文档.docx differ diff --git a/pom.xml b/pom.xml index 1036450..c5a5e6e 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ com.sunyard dproto - 1.0-20211220 + 1.0-20220107 diff --git a/src/main/java/com/sunyard/inf/SydCryptionApi.java b/src/main/java/com/sunyard/inf/SydCryptionApi.java index 2ee413b..b41d45b 100644 --- a/src/main/java/com/sunyard/inf/SydCryptionApi.java +++ b/src/main/java/com/sunyard/inf/SydCryptionApi.java @@ -95,6 +95,16 @@ interface SydASYMApi { ); + /** + * 用指定的 SM2 公钥对指定的密文数据进行加密。 + * 输出的sm2密文结构为C1C2C3格式 + * @param publicKey 公钥钥串,DER 编码,HEX 格式。 + * @param pOrgData 加密的数据。 + * @return 加密的数据 base64 编码。 + */ + String SM2EncryptOrder(byte[] publicKey, byte[] pOrgData); + + /** * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 * @@ -112,6 +122,15 @@ interface SydASYMApi { */ byte[] SM2Decrypt(byte[] sk, String enData); + /** + * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 + * 输入的sm2密文结构为C1C2C3格式 + * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param enData 加密的数据,base64 编码。 + * @return 明文数据。 + */ + byte[] SM2DecryptOrder(String userId, String enData); + /** * 用指定的 RSA 私钥对指定的密文数据进行加密。 * diff --git a/src/main/java/com/sunyard/inf/SydGenApi.java b/src/main/java/com/sunyard/inf/SydGenApi.java index e13a18e..421227b 100644 --- a/src/main/java/com/sunyard/inf/SydGenApi.java +++ b/src/main/java/com/sunyard/inf/SydGenApi.java @@ -228,6 +228,18 @@ public interface SydGenApi { */ RetWrap generateDEbyGS(String certSerial, byte nAlg); + /** + * 产生对称密钥,通过公钥加密生成网联格式的数字信封。 + * + * @param certSerial 对*方 X509 证书的序列号。 + * @param orgCode 机构码 + * @return RetWrap 包含 CipherKey, SessionKey, KCV + * CipherKey 公钥加密的会话密钥 ,BASE64 编码 + * SessionKey 本地LMK 加密的会话密钥,HEX 格式, 本地 LMK 加密的会话密钥长度,HEX 格式(不包括第 1 个字符),一般为 33 个 Bytes。默认输入值为缓冲区的大小。 + * KCV 会话密钥的检验值,HEX 格式,长度为 32H。 + */ + RetWrap generateDEbyGS(String certSerial, String orgCode); + /** * 产生对称密钥,通过公钥加密生成网联格式的数字信封。 @@ -252,6 +264,7 @@ public interface SydGenApi { * @return RetWrap 包含 SessionKey KCV * SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文 * KCV 会话密钥的检验值,HEX 格式,长度为 36H。 + * orgCode 如果有机构码的话会返回机构码 */ RetWrap decryptDE( String pCertSerial, diff --git a/src/main/java/racal/sunyard/main/SydApi4j.java b/src/main/java/racal/sunyard/main/SydApi4j.java index 70ad057..47f065c 100644 --- a/src/main/java/racal/sunyard/main/SydApi4j.java +++ b/src/main/java/racal/sunyard/main/SydApi4j.java @@ -2129,15 +2129,20 @@ public class SydApi4j implements SydApi { @Override public RetWrap generateDEbyGS(String certSerial, byte nAlg) { - return generateDE(1, certSerial, nAlg); + return generateDE(1, certSerial, nAlg, null); + } + + @Override + public RetWrap generateDEbyGS(String certSerial, String orgCode) { + return generateDE(1, certSerial, (byte) 0x32, orgCode); } @Override public RetWrap generateDE(String certSerial, byte nAlg) { - return generateDE(0, certSerial, nAlg); + return generateDE(0, certSerial, nAlg, null); } - public RetWrap generateDE(int pFlag, String certSerial, byte nAlg) { + private RetWrap generateDE(int pFlag, String certSerial, byte nAlg, String orgCode) { // 获取协议 //ProtocolRender render = pset.getProtocolReqRender("6A"); Proto6A proto = new Proto6A(); @@ -2149,6 +2154,14 @@ public class SydApi4j implements SydApi { data.put("alg$option", nAlg - 0x30); if (pFlag == 1) { data.put("pFlag", 'P'); + + if (nAlg == 0x32) { + if (orgCode.length() != 14) { + throw new SydApiException("机构码长度错(只能==14)", -6); + } + + data.put("orgCode", orgCode); + } } data.put("certificateModel$option", 0); data.put("certificateSn", certSerial.getBytes()); @@ -2225,6 +2238,11 @@ public class SydApi4j implements SydApi { } RetWrap rw = new RetWrap(); + 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() ); @@ -3974,6 +3992,43 @@ public class SydApi4j implements SydApi { } + @Override + public String SM2EncryptOrder(byte[] publicKey, byte[] pOrgData) { + Proto77 proto = new Proto77(); + + // 填充数据 + HashMap packet = new HashMap(); + HashMap data = new HashMap(); + packet.put("data", data); + PacketSN sn = PacketSN.gen(); + packet.put("header", sn.getSn().array()); + data.put("AlgorithmKey$option", 1); + data.put("publicKey", publicKey); + data.put("infoData", pOrgData); + // 渲染发送 + 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()); + } + + System.out.println("内部输出: " + Util.bytes2HexString(((PacketSection) ret.get("cipherData")).getBytes())); + + return SYMUtil.derEnData2Base64EnC1C2C3(((PacketSection) ret.get("cipherData")).getBytes()); + } @Override public String SM2Encrypt(byte[] publicKey, byte[] pOrgData) { @@ -4092,6 +4147,54 @@ public class SydApi4j implements SydApi { return ((PacketSection) ret.get("data")).getBytes(); } + /** + * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 + * 输入的sm2密文结构为C1C2C3格式 + * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param enData 加密的数据,base64 编码。 + * @return 明文数据。 + */ + @Override + public byte[] SM2DecryptOrder(String userId, String enData) { + //ProtocolRender render = pset.getProtocolReqRender("78"); + Proto78 proto = new Proto78(); + + byte[] pOrgData = SYMUtil.base64EnData2DerEnDataC1C2C3(enData); + + System.out.println("解密内部输出: " + Util.bytes2HexString(pOrgData)); + + // 填充数据 + HashMap packet = new HashMap(); + HashMap data = new HashMap(); + packet.put("data", data); + PacketSN sn = PacketSN.gen(); + packet.put("header", sn.getSn().array()); + data.put("AlgorithmKey$option", 1); + data.put("infoData", pOrgData); + data.put("privateKeyTag", SYMUtil.genPrivateKeyMark(userId, SYMUtil.KT_ENCRYPT, "00000001")); + // 渲染发送 + 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()); + } + + return ((PacketSection) ret.get("data")).getBytes(); + } + public byte[] SM3HashSNaId(String sn, String userId, byte[] msg) { return SM3Hash(null, sn, null, userId, msg); } diff --git a/src/test/java/com/sunyard/sydapi/example/ABCNorthBranch.java b/src/test/java/com/sunyard/sydapi/example/ABCNorthBranch.java index ed969a9..8834e8f 100644 --- a/src/test/java/com/sunyard/sydapi/example/ABCNorthBranch.java +++ b/src/test/java/com/sunyard/sydapi/example/ABCNorthBranch.java @@ -39,9 +39,10 @@ public class ABCNorthBranch { SM2PublicKey = api.SM2GetPublicKeyC(SM2PrivateKeyTag); SM2PrivateKey = api.SM2GetPrivateKeyC(SM2PrivateKeyTag); - SM4Key = new String(Util.hexString2Bytes(Util.bytes2HexString((byte[]) api.readKey(SM4PrivateKeyTag).get("key")))); + SM4Key = new String((byte[]) api.readKey(SM4PrivateKeyTag).get("key")); + System.out.println("=========================================密钥获取完成========================================="); } diff --git a/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java b/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java index 0a27935..be79b2e 100644 --- a/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java +++ b/src/test/java/com/sunyard/sydapi/test/TestAllMethods.java @@ -776,6 +776,8 @@ public class TestAllMethods { String index = "333333333333333300A00000001"; RetWrap retWrap = api.readKey(index); printRetWrap(retWrap); + + System.out.println("aaaaaaaa: " + new String((byte[]) retWrap.get("key"))); } // 测试通过 @@ -932,9 +934,10 @@ public class TestAllMethods { // String index = "1111111111111148"; // 0342000450420312F4ABAD98AA8EFC1F8F8204BD9E2F752C59C25A4025E675EDA5FB2337A449E00241EFA4A2F76A6C58D9834D6F0AB1164652E9C588E0EBD539C8ECB9EF - // 1111111111111149 000 00000001 - String index = "1111111111111149"; - // 03420004080589A33A4DB304A3C48355761AC216B8BB5493966996E532B664A5B9CD8F1374F0DAACBF3F6D1F0E48E10DAA91889DB632FF4BE19D903502680D1AB56584D5 + // 1111111111111151 000 00000001 + String index = "1111111111111151"; + // 034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E + // 00010000BEF3ECEF9CC88ED5F1159F2B18DCFC648D9FF6A8D6F36516F0333B106805A9B30000000000000000000000000000000000000000000000000000000000000000 // SM2 RetWrap retWrap = api.SM2OrRSAGenKeyPair(1, index, 0); @@ -1296,6 +1299,19 @@ public class TestAllMethods { printRetWrap(retWrap1); } + @Test + public void testDecryptDE4() { + String sn = "1004282452"; + + RetWrap retWrap = api.generateDEbyGS(sn, "00001111222233"); + String CipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY); + String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY); + printRetWrap(retWrap); + + RetWrap retWrap1 = api.decryptDE(sn, CipherKey); + printRetWrap(retWrap1); + } + // 测试通过 // 6C @Test @@ -1684,16 +1700,36 @@ public class TestAllMethods { // 78 @Test public void testSM2DecryptC() { - String certId = "1111111111111122"; - String publicKey = "0342000469DE3847DD6A66DA96DB8F2DCFA32E10E680FF2EF4A592079E7C3A44320BB15084E7CA9782A39B6E28F07C04FE00D68958A2605921E71712D56C1E4435A39FA5"; - String orgData = "FFFFFFFFFFFFFFFF"; + String certId = "1111111111111151"; + String publicKey = "034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E"; + String orgData = "FFFFFFFFFFF1111111111FFFFF"; String s = api.SM2Encrypt(Util.hexString2Bytes(publicKey), orgData.getBytes()); + System.out.println("加密后的数据: " + s); + byte[] pOrgData = SYMUtil.base64EnData2DerEnData(s); + System.out.println("加密后的数据解base64-2: " + Util.bytes2HexString(pOrgData)); + byte[] bytes = api.SM2DecryptC(certId, s); System.out.println("decData:" + new String(bytes)); } + // 测试通过 + // 78 + @Test + public void testSM2DecryptOrder() { + String certId = "1111111111111151"; + String publicKey = "034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E"; + String orgData = "FfffffffffffffFfffffffffffffffff"; + String s = api.SM2EncryptOrder(Util.hexString2Bytes(publicKey), orgData.getBytes()); + + System.out.println("加密后的数据: " + s); + + byte[] bytes = api.SM2DecryptOrder(certId, s); + + System.out.println("decData:" + new String(bytes)); + } + // QQ @Test public void testSM2GetPublicKeyC() { diff --git a/src/test/java/com/sunyard/sydapi/test/TestGSYH.java b/src/test/java/com/sunyard/sydapi/test/TestGSYH.java index c9355cd..8235081 100644 --- a/src/test/java/com/sunyard/sydapi/test/TestGSYH.java +++ b/src/test/java/com/sunyard/sydapi/test/TestGSYH.java @@ -1,6 +1,7 @@ package com.sunyard.sydapi.test; import com.sunyard.RetWrap; +import com.sunyard.SydApi; import com.sunyard.cert.X509; import com.sunyard.proto.Util; import org.junit.After; @@ -11,6 +12,8 @@ import racal.sunyard.main.SydApi4j; import java.io.IOException; import java.util.Base64; +import static com.sunyard.sydapi.util.PrintUtil.printRetWrap; + /** * 甘肃银行数字货币 */ @@ -26,10 +29,19 @@ public class TestGSYH { public void before() { // 通过设置debug的属性开启debug,如果不设置则默认不打开 System.setProperty("com.sunyard.sydapi4j.debug", "true"); - api = (SydApi4j) new SydApi4j().connect("192.168.0.66", 8889, null, 1000); + api = (SydApi4j) new SydApi4j().connect("61.164.40.82", 8889, null, 1000); } + @After + public void after() { + try { + this.api.disconnect(); + } catch (Exception e) { + e.printStackTrace(); + } + } + @Test public void test02() { Base64.Encoder encoder = Base64.getEncoder(); @@ -38,24 +50,25 @@ public class TestGSYH { // 2. String data = "1111111111111111"; // 随机生成对称密钥,由指定的公钥加密生成数字信封 - RetWrap retWrap = api.generateDE(sn, (byte) 0x31); - String sessionKey = (String) retWrap.get("SessionKey"); + RetWrap retWrap = api.generateDEbyGS(sn, SydApi.ALG_SM4); + String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY); // sm4加密账号等数据 - byte[] dataEnc = api.SYMEncryptData(3, sessionKey, data.getBytes()); + byte[] dataEnc = api.SYMEncryptData(SydApi.NALG_SM4, sessionKey, data.getBytes()); // base64转码 byte[] dataEncBs64 = encoder.encode(dataEnc); - // 将sm2加密后的数据进行base64转码 - String cipherKey = (String) retWrap.get("CipherKey"); - byte[] cipherKeyBs64 = encoder.encode(cipherKey.getBytes()); + System.out.println("dataEncBs64: " + Util.bytes2HexString(dataEncBs64)); + // 将sm2加密后的数据进行base64转码 + String cipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY); + byte[] cipherKeyBs64 = encoder.encode(cipherKey.getBytes()); // 3. // 报文正文 String msg = "12313146464564"; // 对报文正文签名(内部会计算hash) - String msgSign = api.netSign(sn1, msg.getBytes()); + String msgSign = api.netGSSign(sn1, msg.getBytes()); // base64转码 byte[] msgSignBs64 = encoder.encode(msgSign.getBytes()); @@ -65,31 +78,22 @@ public class TestGSYH { // base64解码 byte[] msgSignB = decoder.decode(msgSignBs64); // 对报文验签 - boolean b = api.netVerify(sn1, dataEncBs64, new String(msgSignB)); + boolean b = api.netGSVerify(sn1, msg.getBytes(), new String(msgSignB)); System.out.println("验签结果: " + b); // 8. byte[] cipherKeyB = decoder.decode(cipherKeyBs64); // 解密数字信封获取对称密钥 RetWrap retWrap1 = api.decryptDE(sn, new String(cipherKeyB)); - sessionKey = (String) retWrap1.get("SessionKey"); + sessionKey = (String) retWrap1.get(SydApi.RET_SESSION_KEY); // 9. // 使用对称密钥解密报文 dataEnc = decoder.decode(dataEncBs64); - byte[] bytes1 = api.SYMDecryptData(3, sessionKey, dataEnc); + byte[] bytes1 = api.SYMDecryptData(SydApi.NALG_SM4, sessionKey, dataEnc); System.out.println("data: " + new String(bytes1)); } - @After - public void after() { - try { - this.api.disconnect(); - } catch (Exception e) { - e.printStackTrace(); - } - } - // 测试通过 // 8017 @Test @@ -102,7 +106,7 @@ public class TestGSYH { * @param nCertType 证书类型,0:签名证书, 1:加密证书 * @return base64 编码的证书 */ - String s = api.GetX509CertFileBySN(sn2, 0); + String s = api.GetX509CertFileBySN(sn2, SydApi.FOR_SIGN); System.out.println(s); /** @@ -115,34 +119,6 @@ public class TestGSYH { System.out.println("证书主题DN: " + x509.getSubject()); } - @Test - public void testImportCert2() throws IOException { - - String cert2 = "-----BEGIN CERTIFICATE-----\n" + - "MIIB4TCCAYSgAwIBAgIIPJMAAAAAACswDAYIKoEcz1UBg3UFADAmMQswCQYDVQQG\n" + - "EwJDTjEXMBUGA1UEAwwOU3VueWFyZFNNMlJvb3QwHhcNMTcxMTE3MDIzMDUxWhcN\n" + - "MjMwMTI1MDIzMDUxWjBZMQswCQYDVQQGEwJDTjELMAkGA1UECAwCWkoxCzAJBgNV\n" + - "BAcMAkhaMQ4wDAYDVQQKDAVISkpZUzERMA8GA1UECwwIMDAwMDAwMDAxDTALBgNV\n" + - "BAMMBDIyMjIwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAATxqegqlmc/lduzBaKR\n" + - "EyeNuPf78RA3wfJuhAv8zymLwQ6doefs1Iul+kMOukhfwY9aEhVdqws34FZMm2vs\n" + - "1+wXo2cwZTAOBgNVHQ8BAf8EBAMCAMAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHwYD\n" + - "VR0jBBgwFoAU93/arv8hxtk6eq2g+6z+AqVO1cEwHQYDVR0OBBYEFHfjFl72707A\n" + - "6s+YVuGvEuyvFWTMMAwGCCqBHM9VAYN1BQADSQAwRgIhALzg7+QW7RU4phv+4arE\n" + - "v0IOeaA6dtR8VT4Bwin9oHTWAiEA9kLESGiYm8L5Htf7GBXgH+pk7BJ68clml41B\n" + - "/ejZglI=\n" + - "-----END CERTIFICATE-----"; - - String organizationId = "00000000"; - - /** - * 上传指定证书到加密设备 - * @param certData 证书的字节数组 - * @param organizationId 机构号的字节数组 - * @return - */ - RetWrap retWrap = api.importCert(Util.getSafeBytes(cert2), organizationId.getBytes()); - System.out.println(retWrap); - } @Test public void testimportCertAddHT() { @@ -202,45 +178,75 @@ public class TestGSYH { System.out.println("证书公钥: " + Util.bytes2HexString(x509.getPubKey())); } + + // 测试通过 + // 78 @Test - public void test() { - // 证书序号 - String sn = "1004282451"; - String data = "111"; + public void testSM2DecryptC() { + String certId = "1111111111111151"; + String publicKey = "034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E"; + + String orgData = "FFFFFFFFFFFFFFFF"; + String s = api.SM2Encrypt(Util.hexString2Bytes(publicKey), orgData.getBytes()); + + System.out.println("加密后的数据: " + s); + System.out.println("加密后的数据解base64: " + Util.bytes2HexString(Base64.getDecoder().decode(s))); + + byte[] bytes = api.SM2DecryptC(certId, s); + + System.out.println("decData:" + new String(bytes)); + } + + // 测试通过 + // 78 + @Test + public void testSM2DecryptOrder() { + String certId = "1111111111111151"; + String publicKey = "034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E"; + String orgData = "FfffffffffffffFfffffffffffffffff"; /** - * 用指定的证书私钥对指定的数据进行数字签名。 - * @param pCertSerial 输入。签名 X509 证书的序列号。 - * @param pOrgData 输入。 待签名的原始数据。 - * @return 签名数据(BASE64 编码)。 + * 用指定的 SM2 公钥对指定的密文数据进行加密。 + * 输出的sm2密文结构为C1C2C3格式 + * @param publicKey 公钥钥串,DER 编码,HEX 格式。 + * @param pOrgData 加密的数据。 + * @return 加密的数据 base64 编码。 */ - String s = api.netSign(sn, data.getBytes()); + String s = api.SM2EncryptOrder(Util.hexString2Bytes(publicKey), orgData.getBytes()); + + System.out.println("加密后的数据: " + s); /** - * 用指定证书对指定的原始数据进行数字签名验证。 - * @param pCertSerial 输入。 签名 X509 证书的序列号。 - * @param pOrgData 输入。 待签名的原始数据。 - * @param pSignData 输入。 签名数据(BASE64 编码)。 - * @return true 表示验证正确;false 表示失败; + * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 + * 输入的sm2密文结构为C1C2C3格式 + * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。 + * @param enData 加密的数据,base64 编码。 + * @return 明文数据。 */ - // 12、对正文进行验签(内部会计算hash) - boolean b = api.netVerify(sn, data.getBytes(), s); - System.out.println(b); + byte[] bytes = api.SM2DecryptOrder(certId, s); + System.out.println("decData:" + new String(bytes)); + } + + @Test + public void testDecryptDE4() { + String sn = "1004282452"; - String sn1 = "1004282452"; /** * 产生对称密钥,通过公钥加密生成网联格式的数字信封。 * * @param certSerial 对*方 X509 证书的序列号。 - * @param nAlg 算法标识,0:AES,1:SM4 + * @param orgCode 机构码 * @return RetWrap 包含 CipherKey, SessionKey, KCV * CipherKey 公钥加密的会话密钥 ,BASE64 编码 * SessionKey 本地LMK 加密的会话密钥,HEX 格式, 本地 LMK 加密的会话密钥长度,HEX 格式(不包括第 1 个字符),一般为 33 个 Bytes。默认输入值为缓冲区的大小。 * KCV 会话密钥的检验值,HEX 格式,长度为 32H。 */ - RetWrap retWrap = api.generateDE(sn1, (byte) 0x31); - String CipherKey = (String) retWrap.get("CipherKey"); + RetWrap retWrap = api.generateDEbyGS(sn, "00001111222233"); + String CipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY); + String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY); + String kcv = (String) retWrap.get(SydApi.RET_KCV); + printRetWrap(retWrap); /** * 接收用私钥解密数字信封,还原对称密钥。 @@ -250,110 +256,38 @@ public class TestGSYH { * @return RetWrap 包含 SessionKey KCV * SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文 * KCV 会话密钥的检验值,HEX 格式,长度为 36H。 + * orgCode 如果有机构码的话会返回机构码 */ - // 13、解密数字信封获取对称密钥 - RetWrap rw = api.decryptDE(sn1, CipherKey); - String sessionKey = (String) rw.get("SessionKey"); - - /** - * 用输入的会话密钥,对指定报文数据进行加密处理。填充模式为1 - * - * @param nAlg 算法标识. 3:SM4。 - * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 - * @param pINdata 要加密的报文明文。必须是 8 或16 的倍数。 - * @return 输出的报文密文, 长度为报文明文 + 16 - */ - byte[] bytes = api.SYMEncryptData(3, sessionKey, "1111111111111111".getBytes()); - - /** - * 用输入的会话密钥,对指定报文数据进行解密处理。填充模式为1 - * - * @param nAlg  算法标识.3:SM4。 - * @param seesionKey 本地LMK 加密的会话密钥,HEX 格式 - * @param pINdata 要解密的报文密文。长度必须是8 或16 的倍数。 - * @return 输出的报文明文。 - */ - // 13、使用对称密钥解密敏感数据 - byte[] bytes1 = api.SYMDecryptData(3, sessionKey, bytes); - System.out.println(new String(bytes1)); - + RetWrap retWrap1 = api.decryptDE(sn, CipherKey); + printRetWrap(retWrap1); } - // 签名验签流程 - @Test - public void testNetGSSign() { - // 本行的 - String sn = "10000000000000000000001042580423"; - String data = "111"; + // =========================工具方法===================== - /** - * 用指定的证书私钥对指定的数据进行数字签名。 - * 最大签名原始数据为8161byte - * @param publicKey 输入。公钥。 - * @param pCertSerial 输入。签名 X509 证书的序列号。 - * @param pOrgData 输入。 待签名的原始数据。 - * @return 签名数据(BASE64 编码)。 - */ - String sign = api.netGSSign(sn, data.getBytes()); - System.out.println("签名结果: " + sign); - - /** - * 用指定证书对指定的原始数据进行数字签名验证。 - * @param publicKey 输入。公钥。 - * @param pCertSerial 输入。 签名 X509 证书的序列号。 - * @param pOrgData 输入。 待签名的原始数据。 - * @param pSignData 输入。 签名数据(BASE64 编码)。 - * @return true 表示验证正确;false 表示失败; - */ - boolean b = api.netGSVerify(sn, data.getBytes(), sign); - System.out.println("验签结果: " + b); + public static void printRetWrap(RetWrap rw) { + printRetWrap(rw, false); } + /** + * 输出 + * @param rw + */ + public static void printRetWrap(RetWrap rw, boolean flag) { + for (String s : rw.keySet()) { - @Test - public void testVerify() { - - String orgData = "\n" + - "\n" + - " \n" + - " \n" + - " 20211231058043300311422380336000\n" + - " 2021-12-31T14:22:38\n" + - " \n" + - " C1030131001288\n" + - " \n" + - " \n" + - " C1175662000017\n" + - " \n" + - " \n" + - " MT01\n" + - " \n" + - " C1175662000017\n" + - " AT00\n" + - " 983zGfqfC3O7xbgYwsW9TfRp1ddVT7vfaAAGhZ7Y7M0=\n" + - " VbuPbl33/yi8OsQkme0kqZ0Tmvf8eJIyngC8CRyIk8E=\n" + - " IT01\n" + - " v1NPE/GPSooCXY4Z4RomtgDGpLxcm7RnF/VS16LEd3U=\n" + - " G8DUftbIJTJpjrIgvoF3KQ==\n" + - " SG01\n" + - " \n" + - " \n" + - " C1030131001288\n" + - " ZyBTxt3R/zN6AD7KqWotug==\n" + - " WT01\n" + - " WL01\n" + - " \n" + - " \n" + - ""; - - String sn = "10000000000000000000001042580423"; - - String sign = "MEUCIGpByl+Q1uSLXVPHdRvPXufgGEru+kUDj13jBY68b3NrAiEA3WbN3tYTCK7GRIsfnVA+3jbGTYluKs/Xz+JZkFZ4tIM="; - - boolean b = api.netGSVerify(sn, orgData.getBytes(), sign); - System.out.println("验签结果: " + b); + Object o = rw.get(s); + if (o instanceof String) { + System.out.println(s + ":" + o); + } else if (o instanceof byte[]) { + if (flag) { + System.out.println(s + ": " + Util.bytes2HexString((byte[]) o)); + } else { + System.out.println(s + ": " + new String((byte[]) o)); + } + } else { + System.out.println(s + ":" + o); + } + } } - - } diff --git a/src/test/java/com/sunyard/sydapi/test/TestHT.java b/src/test/java/com/sunyard/sydapi/test/TestHT.java index c6dd81c..4f0fcd5 100644 --- a/src/test/java/com/sunyard/sydapi/test/TestHT.java +++ b/src/test/java/com/sunyard/sydapi/test/TestHT.java @@ -40,20 +40,33 @@ public class TestHT { @Test public void testSM2ConfirmSessionKeyC() { - String userId = "1111111111111149"; + String userId = "1111111111111151"; + String data = "12343242"; - String pk = api.SM2GetPublicKeyC(userId, 1); + // 通过用户id获取公钥 + String pk = api.SM2GetPublicKeyC(userId, SydApi.FOR_ENCRYPT); + // 生成数字信封 RetWrap retWrap = api.SM2GenSessionKey(pk); printRetWrap(retWrap); String cipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY); String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY); String kcv = (String) retWrap.get(SydApi.RET_KCV); + // 使用生成的对称密钥加密数据 + byte[] dataEnc = api.SYMEncryptData(SydApi.NALG_SM4, sessionKey, data.getBytes()); + + + + // 解密数字信封 RetWrap retWrap1 = api.SM2ConfirmSessionKeyC(userId, cipherKey); printRetWrap(retWrap1); sessionKey = (String) retWrap1.get(SydApi.RET_SESSION_KEY); kcv = (String) retWrap1.get(SydApi.RET_KCV); + + // 使用解密出来的对称密钥解密数据 + byte[] bytes1 = api.SYMDecryptData(SydApi.NALG_SM4, sessionKey, dataEnc); + System.out.println("解密后的数据:" + new String(bytes1)); } // 测试通过