1、升级dproto依赖,2、添加77,78指令的接口,sm2加解密密文结构为C1C2C3,3、生成数字信封添加机构码

This commit is contained in:
zhoubin
2022-01-07 17:08:01 +08:00
parent 8a38108727
commit 61456f74b6
11 changed files with 389 additions and 225 deletions
+38 -6
View File
@@ -14,6 +14,9 @@
<option cn="SM2_SM4_ECB"> <option cn="SM2_SM4_ECB">
<hex>1</hex> <hex>1</hex>
</option> </option>
<option cn="SM2_SM4_ECB 机构码|02|密钥">
<hex>2</hex>
</option>
</options> </options>
</alg> </alg>
@@ -50,6 +53,14 @@
LMK 下加密密钥的方案。 LMK 下加密密钥的方案。
</keyType> </keyType>
<orgCodeLen len="2" :value="orgCodeLen()" :if="hasOrgCode()" cn="机构码长度">
公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
</orgCodeLen>
<orgCode :if="hasOrgCode()" cn="机构码长度">
公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
</orgCode>
<tailSep len="1" :if=" null != $packet.data.tail " cn="尾分隔"> <tailSep len="1" :if=" null != $packet.data.tail " cn="尾分隔">
可选项。如果显示消息尾域,则该域必须显示。值为 可选项。如果显示消息尾域,则该域必须显示。值为
“X’19”。 “X’19”。
@@ -140,7 +151,8 @@
</res> </res>
<script>function certificateLen(){ <script>
function certificateLen(){
var data = $packet.data; var data = $packet.data;
if( 0 == data.certificateModel$option ){ if( 0 == data.certificateModel$option ){
return data.certificateSn.length return data.certificateSn.length
@@ -148,15 +160,15 @@
if( 1 == data.certificateModel$option ){ if( 1 == data.certificateModel$option ){
return data.certificateDn.length return data.certificateDn.length
} }
} }
function getKeyLen() { function getKeyLen() {
return Util.a2i( $final.getSection('data').getSection('keyLen') ) return Util.a2i( $final.getSection('data').getSection('keyLen') )
} }
function lmkLen() { function lmkLen() {
if( Arrays.equals("L".getBytes(), if( Arrays.equals("L".getBytes(),
$final.getSection('data').getSection('lmkHead').getValue() $final.getSection('data').getSection('lmkHead').getValue()
) ){ ) ){
@@ -164,5 +176,25 @@ function lmkLen() {
}else{ }else{
return 32 return 32
} }
} </script> }
<![CDATA[
function hasOrgCode() {
if(2 == $packet.data.alg$option && 'P' == $packet.data.pFlag) {
return true;
}
return false;
}
function orgCodeLen() {
def len = $packet.data.orgCode.length();
def data = new byte[2];
data[0] = (byte)(len >> 8 & 0xFF)
data[1] = (byte)(len & 0xFF)
return data;
}
]]>
</script>
</packet> </packet>
+21 -8
View File
@@ -120,6 +120,14 @@
密钥校验值 密钥校验值
</keyCheck> </keyCheck>
<orgCodeLen len="4" cn="机构码长度">
公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
</orgCodeLen>
<orgCode :len="orgCodeLen()" cn="机构码长度">
公钥加密的密钥格式3所需机构码长度,仅当格式3以及'P'存在时存在
</orgCode>
<tailSep len="1" required="false" cn="尾分隔"> <tailSep len="1" required="false" cn="尾分隔">
可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。 可选项。如果显示消息尾域,则该域必须显示。值为 “X’19”。
<hex>19</hex> <hex>19</hex>
@@ -133,7 +141,8 @@
</res> </res>
<script>function certificateLen(){ <script>
function certificateLen(){
var data = $packet.data; var data = $packet.data;
if( 0 == data.certificateModel$option ){ if( 0 == data.certificateModel$option ){
return data.certificateSn.length() return data.certificateSn.length()
@@ -141,18 +150,18 @@
if( 1 == data.certificateModel$option ){ if( 1 == data.certificateModel$option ){
return data.certificateDn.length() return data.certificateDn.length()
} }
} }
function keyLen() { function keyLen() {
return $packet.data.key.length() return $packet.data.key.length()
} }
function getKeyLen() { function getKeyLen() {
return Util.a2i( $final.getSection('data').getSection('keyLen') ) return Util.a2i( $final.getSection('data').getSection('keyLen') )
} }
function lmkLen() { function lmkLen() {
if( Arrays.equals("L".getBytes(), if( Arrays.equals("L".getBytes(),
$final.getSection('data').getSection('lmkHead').getValue() $final.getSection('data').getSection('lmkHead').getValue()
) ){ ) ){
@@ -160,5 +169,9 @@ function lmkLen() {
}else{ }else{
return 32 return 32
} }
} </script> }
function orgCodeLen() {
return Util.a2i( $final.getSection('data').getSection('orgCodeLen') )
}
</script>
</packet> </packet>
Binary file not shown.
+1 -1
View File
@@ -77,7 +77,7 @@
<dependency> <dependency>
<groupId>com.sunyard</groupId> <groupId>com.sunyard</groupId>
<artifactId>dproto</artifactId> <artifactId>dproto</artifactId>
<version>1.0-20211220</version> <version>1.0-20220107</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -95,6 +95,16 @@ interface SydASYMApi {
); );
/**
* 用指定的 SM2 公钥对指定的密文数据进行加密。
* 输出的sm2密文结构为C1C2C3格式
* @param publicKey 公钥钥串,DER 编码,HEX 格式。
* @param pOrgData 加密的数据。
* @return 加密的数据 base64 编码。
*/
String SM2EncryptOrder(byte[] publicKey, byte[] pOrgData);
/** /**
* 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。 * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。
* *
@@ -112,6 +122,15 @@ interface SydASYMApi {
*/ */
byte[] SM2Decrypt(byte[] sk, String enData); byte[] SM2Decrypt(byte[] sk, String enData);
/**
* 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。
* 输入的sm2密文结构为C1C2C3格式
* @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。
* @param enData 加密的数据,base64 编码。
* @return 明文数据。
*/
byte[] SM2DecryptOrder(String userId, String enData);
/** /**
* 用指定的 RSA 私钥对指定的密文数据进行加密。 * 用指定的 RSA 私钥对指定的密文数据进行加密。
* *
@@ -228,6 +228,18 @@ public interface SydGenApi {
*/ */
RetWrap generateDEbyGS(String certSerial, byte nAlg); 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 * @return RetWrap 包含 SessionKey KCV
* SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文 * SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文
* KCV 会话密钥的检验值,HEX 格式,长度为 36H。 * KCV 会话密钥的检验值,HEX 格式,长度为 36H。
* orgCode 如果有机构码的话会返回机构码
*/ */
RetWrap decryptDE( RetWrap decryptDE(
String pCertSerial, String pCertSerial,
+106 -3
View File
@@ -2129,15 +2129,20 @@ public class SydApi4j implements SydApi {
@Override @Override
public RetWrap generateDEbyGS(String certSerial, byte nAlg) { 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 @Override
public RetWrap generateDE(String certSerial, byte nAlg) { 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"); //ProtocolRender render = pset.getProtocolReqRender("6A");
Proto6A proto = new Proto6A(); Proto6A proto = new Proto6A();
@@ -2149,6 +2154,14 @@ public class SydApi4j implements SydApi {
data.put("alg$option", nAlg - 0x30); data.put("alg$option", nAlg - 0x30);
if (pFlag == 1) { if (pFlag == 1) {
data.put("pFlag", 'P'); 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("certificateModel$option", 0);
data.put("certificateSn", certSerial.getBytes()); data.put("certificateSn", certSerial.getBytes());
@@ -2225,6 +2238,11 @@ public class SydApi4j implements SydApi {
} }
RetWrap rw = new RetWrap(); 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() + rw.put(SydApi.RET_SESSION_KEY, ((PacketSection) ret.get("lmkHead")).getString() +
((PacketSection) ret.get("lmk")).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<String, Object> packet = new HashMap<String, Object>();
HashMap<String, Object> data = new HashMap<String, Object>();
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<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());
}
System.out.println("内部输出: " + Util.bytes2HexString(((PacketSection) ret.get("cipherData")).getBytes()));
return SYMUtil.derEnData2Base64EnC1C2C3(((PacketSection) ret.get("cipherData")).getBytes());
}
@Override @Override
public String SM2Encrypt(byte[] publicKey, byte[] pOrgData) { public String SM2Encrypt(byte[] publicKey, byte[] pOrgData) {
@@ -4092,6 +4147,54 @@ public class SydApi4j implements SydApi {
return ((PacketSection) ret.get("data")).getBytes(); 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<String, Object> packet = new HashMap<String, Object>();
HashMap<String, Object> data = new HashMap<String, Object>();
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<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("data")).getBytes();
}
public byte[] SM3HashSNaId(String sn, String userId, byte[] msg) { public byte[] SM3HashSNaId(String sn, String userId, byte[] msg) {
return SM3Hash(null, sn, null, userId, msg); return SM3Hash(null, sn, null, userId, msg);
} }
@@ -39,9 +39,10 @@ public class ABCNorthBranch {
SM2PublicKey = api.SM2GetPublicKeyC(SM2PrivateKeyTag); SM2PublicKey = api.SM2GetPublicKeyC(SM2PrivateKeyTag);
SM2PrivateKey = api.SM2GetPrivateKeyC(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("=========================================密钥获取完成========================================="); System.out.println("=========================================密钥获取完成=========================================");
} }
@@ -776,6 +776,8 @@ public class TestAllMethods {
String index = "333333333333333300A00000001"; String index = "333333333333333300A00000001";
RetWrap retWrap = api.readKey(index); RetWrap retWrap = api.readKey(index);
printRetWrap(retWrap); printRetWrap(retWrap);
System.out.println("aaaaaaaa: " + new String((byte[]) retWrap.get("key")));
} }
// 测试通过 // 测试通过
@@ -932,9 +934,10 @@ public class TestAllMethods {
// String index = "1111111111111148"; // String index = "1111111111111148";
// 0342000450420312F4ABAD98AA8EFC1F8F8204BD9E2F752C59C25A4025E675EDA5FB2337A449E00241EFA4A2F76A6C58D9834D6F0AB1164652E9C588E0EBD539C8ECB9EF // 0342000450420312F4ABAD98AA8EFC1F8F8204BD9E2F752C59C25A4025E675EDA5FB2337A449E00241EFA4A2F76A6C58D9834D6F0AB1164652E9C588E0EBD539C8ECB9EF
// 1111111111111149 000 00000001 // 1111111111111151 000 00000001
String index = "1111111111111149"; String index = "1111111111111151";
// 03420004080589A33A4DB304A3C48355761AC216B8BB5493966996E532B664A5B9CD8F1374F0DAACBF3F6D1F0E48E10DAA91889DB632FF4BE19D903502680D1AB56584D5 // 034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E
// 00010000BEF3ECEF9CC88ED5F1159F2B18DCFC648D9FF6A8D6F36516F0333B106805A9B30000000000000000000000000000000000000000000000000000000000000000
// SM2 // SM2
RetWrap retWrap = api.SM2OrRSAGenKeyPair(1, index, 0); RetWrap retWrap = api.SM2OrRSAGenKeyPair(1, index, 0);
@@ -1296,6 +1299,19 @@ public class TestAllMethods {
printRetWrap(retWrap1); 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 // 6C
@Test @Test
@@ -1684,16 +1700,36 @@ public class TestAllMethods {
// 78 // 78
@Test @Test
public void testSM2DecryptC() { public void testSM2DecryptC() {
String certId = "1111111111111122"; String certId = "1111111111111151";
String publicKey = "0342000469DE3847DD6A66DA96DB8F2DCFA32E10E680FF2EF4A592079E7C3A44320BB15084E7CA9782A39B6E28F07C04FE00D68958A2605921E71712D56C1E4435A39FA5"; String publicKey = "034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E";
String orgData = "FFFFFFFFFFFFFFFF"; String orgData = "FFFFFFFFFFF1111111111FFFFF";
String s = api.SM2Encrypt(Util.hexString2Bytes(publicKey), orgData.getBytes()); 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); byte[] bytes = api.SM2DecryptC(certId, s);
System.out.println("decData:" + new String(bytes)); 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 // QQ
@Test @Test
public void testSM2GetPublicKeyC() { public void testSM2GetPublicKeyC() {
@@ -1,6 +1,7 @@
package com.sunyard.sydapi.test; package com.sunyard.sydapi.test;
import com.sunyard.RetWrap; import com.sunyard.RetWrap;
import com.sunyard.SydApi;
import com.sunyard.cert.X509; import com.sunyard.cert.X509;
import com.sunyard.proto.Util; import com.sunyard.proto.Util;
import org.junit.After; import org.junit.After;
@@ -11,6 +12,8 @@ import racal.sunyard.main.SydApi4j;
import java.io.IOException; import java.io.IOException;
import java.util.Base64; import java.util.Base64;
import static com.sunyard.sydapi.util.PrintUtil.printRetWrap;
/** /**
* 甘肃银行数字货币 * 甘肃银行数字货币
*/ */
@@ -26,10 +29,19 @@ public class TestGSYH {
public void before() { public void before() {
// 通过设置debug的属性开启debug,如果不设置则默认不打开 // 通过设置debug的属性开启debug,如果不设置则默认不打开
System.setProperty("com.sunyard.sydapi4j.debug", "true"); 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 @Test
public void test02() { public void test02() {
Base64.Encoder encoder = Base64.getEncoder(); Base64.Encoder encoder = Base64.getEncoder();
@@ -38,24 +50,25 @@ public class TestGSYH {
// 2. // 2.
String data = "1111111111111111"; String data = "1111111111111111";
// 随机生成对称密钥,由指定的公钥加密生成数字信封 // 随机生成对称密钥,由指定的公钥加密生成数字信封
RetWrap retWrap = api.generateDE(sn, (byte) 0x31); RetWrap retWrap = api.generateDEbyGS(sn, SydApi.ALG_SM4);
String sessionKey = (String) retWrap.get("SessionKey"); String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY);
// sm4加密账号等数据 // sm4加密账号等数据
byte[] dataEnc = api.SYMEncryptData(3, sessionKey, data.getBytes()); byte[] dataEnc = api.SYMEncryptData(SydApi.NALG_SM4, sessionKey, data.getBytes());
// base64转码 // base64转码
byte[] dataEncBs64 = encoder.encode(dataEnc); byte[] dataEncBs64 = encoder.encode(dataEnc);
// 将sm2加密后的数据进行base64转码 System.out.println("dataEncBs64: " + Util.bytes2HexString(dataEncBs64));
String cipherKey = (String) retWrap.get("CipherKey");
byte[] cipherKeyBs64 = encoder.encode(cipherKey.getBytes());
// 将sm2加密后的数据进行base64转码
String cipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY);
byte[] cipherKeyBs64 = encoder.encode(cipherKey.getBytes());
// 3. // 3.
// 报文正文 // 报文正文
String msg = "12313146464564"; String msg = "12313146464564";
// 对报文正文签名(内部会计算hash) // 对报文正文签名(内部会计算hash)
String msgSign = api.netSign(sn1, msg.getBytes()); String msgSign = api.netGSSign(sn1, msg.getBytes());
// base64转码 // base64转码
byte[] msgSignBs64 = encoder.encode(msgSign.getBytes()); byte[] msgSignBs64 = encoder.encode(msgSign.getBytes());
@@ -65,31 +78,22 @@ public class TestGSYH {
// base64解码 // base64解码
byte[] msgSignB = decoder.decode(msgSignBs64); 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); System.out.println("验签结果: " + b);
// 8. // 8.
byte[] cipherKeyB = decoder.decode(cipherKeyBs64); byte[] cipherKeyB = decoder.decode(cipherKeyBs64);
// 解密数字信封获取对称密钥 // 解密数字信封获取对称密钥
RetWrap retWrap1 = api.decryptDE(sn, new String(cipherKeyB)); RetWrap retWrap1 = api.decryptDE(sn, new String(cipherKeyB));
sessionKey = (String) retWrap1.get("SessionKey"); sessionKey = (String) retWrap1.get(SydApi.RET_SESSION_KEY);
// 9. // 9.
// 使用对称密钥解密报文 // 使用对称密钥解密报文
dataEnc = decoder.decode(dataEncBs64); 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)); System.out.println("data: " + new String(bytes1));
} }
@After
public void after() {
try {
this.api.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
// 测试通过 // 测试通过
// 8017 // 8017
@Test @Test
@@ -102,7 +106,7 @@ public class TestGSYH {
* @param nCertType 证书类型,0:签名证书, 1:加密证书 * @param nCertType 证书类型,0:签名证书, 1:加密证书
* @return base64 编码的证书 * @return base64 编码的证书
*/ */
String s = api.GetX509CertFileBySN(sn2, 0); String s = api.GetX509CertFileBySN(sn2, SydApi.FOR_SIGN);
System.out.println(s); System.out.println(s);
/** /**
@@ -115,34 +119,6 @@ public class TestGSYH {
System.out.println("证书主题DN: " + x509.getSubject()); 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 @Test
public void testimportCertAddHT() { public void testimportCertAddHT() {
@@ -202,45 +178,75 @@ public class TestGSYH {
System.out.println("证书公钥: " + Util.bytes2HexString(x509.getPubKey())); System.out.println("证书公钥: " + Util.bytes2HexString(x509.getPubKey()));
} }
// 测试通过
// 78
@Test @Test
public void test() { public void testSM2DecryptC() {
// 证书序号 String certId = "1111111111111151";
String sn = "1004282451"; String publicKey = "034200048043AF118B45629857DB693105849B2617FED249D59DFD29BE9A891ADEE7441A2D8C62020953DAEF038184E0244310CF2123C507F26F5380FFECC8D53E79B24E";
String data = "111";
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";
/** /**
* 用指定的证书私钥对指定的数据进行数字签名。 * 用指定的 SM2 公钥对指定的密文数据进行加密。
* @param pCertSerial 输入。签名 X509 证书的序列号。 * 输出的sm2密文结构为C1C2C3格式
* @param pOrgData 输入。 待签名的原始数据。 * @param publicKey 公钥钥串,DER 编码,HEX 格式。
* @return 签名数据(BASE64 编码)。 * @param pOrgData 加密的数据。
* @return 加密的数据 base64 编码。
*/ */
String s = api.netSign(sn, data.getBytes()); String s = api.SM2EncryptOrder(Util.hexString2Bytes(publicKey), orgData.getBytes());
System.out.println("加密后的数据: " + s);
/** /**
* 用指定证书对指定的原始数据进行数字签名验证。 * 通过使用者 ID 所对应的私钥对指定的密文数据进行解密。
* @param pCertSerial 输入。 签名 X509 证书的序列号。 * 输入的sm2密文结构为C1C2C3格式
* @param pOrgData 输入。 待签名的原始数据。 * @param userId 使用者的 ID,最大长度为 16 位数字,右对齐。
* @param pSignData 输入。 签名数据(BASE64 编码)。 * @param enData 加密的数据,base64 编码。
* @return true 表示验证正确;false 表示失败; * @return 明文数据。
*/ */
// 12、对正文进行验签(内部会计算hash) byte[] bytes = api.SM2DecryptOrder(certId, s);
boolean b = api.netVerify(sn, data.getBytes(), s);
System.out.println(b);
System.out.println("decData:" + new String(bytes));
}
@Test
public void testDecryptDE4() {
String sn = "1004282452";
String sn1 = "1004282452";
/** /**
* 产生对称密钥,通过公钥加密生成网联格式的数字信封。 * 产生对称密钥,通过公钥加密生成网联格式的数字信封。
* *
* @param certSerial 对*方 X509 证书的序列号。 * @param certSerial 对*方 X509 证书的序列号。
* @param nAlg 算法标识,0:AES,1:SM4 * @param orgCode 机构码
* @return RetWrap 包含 CipherKey, SessionKey, KCV * @return RetWrap 包含 CipherKey, SessionKey, KCV
* CipherKey 公钥加密的会话密钥 ,BASE64 编码 * CipherKey 公钥加密的会话密钥 ,BASE64 编码
* SessionKey 本地LMK 加密的会话密钥,HEX 格式, 本地 LMK 加密的会话密钥长度,HEX 格式(不包括第 1 个字符),一般为 33 个 Bytes。默认输入值为缓冲区的大小。 * SessionKey 本地LMK 加密的会话密钥,HEX 格式, 本地 LMK 加密的会话密钥长度,HEX 格式(不包括第 1 个字符),一般为 33 个 Bytes。默认输入值为缓冲区的大小。
* KCV 会话密钥的检验值,HEX 格式,长度为 32H。 * KCV 会话密钥的检验值,HEX 格式,长度为 32H。
*/ */
RetWrap retWrap = api.generateDE(sn1, (byte) 0x31); RetWrap retWrap = api.generateDEbyGS(sn, "00001111222233");
String CipherKey = (String) retWrap.get("CipherKey"); 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 * @return RetWrap 包含 SessionKey KCV
* SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文 * SessionKey 输出。 本地LMK 加密的会话密钥,格式为:密钥类型|密钥密文,比如:02|密钥密文
* KCV 会话密钥的检验值,HEX 格式,长度为 36H。 * KCV 会话密钥的检验值,HEX 格式,长度为 36H。
* orgCode 如果有机构码的话会返回机构码
*/ */
// 13、解密数字信封获取对称密钥 RetWrap retWrap1 = api.decryptDE(sn, CipherKey);
RetWrap rw = api.decryptDE(sn1, CipherKey); printRetWrap(retWrap1);
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));
} }
// 签名验签流程 // =========================工具方法=====================
@Test
public void testNetGSSign() {
// 本行的
String sn = "10000000000000000000001042580423";
String data = "111";
/** public static void printRetWrap(RetWrap rw) {
* 用指定的证书私钥对指定的数据进行数字签名。 printRetWrap(rw, false);
* 最大签名原始数据为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);
} }
/**
* 输出
* @param rw
*/
public static void printRetWrap(RetWrap rw, boolean flag) {
for (String s : rw.keySet()) {
@Test Object o = rw.get(s);
public void testVerify() { if (o instanceof String) {
System.out.println(s + ":" + o);
String orgData = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + } else if (o instanceof byte[]) {
"<Document xmlns=\"urn:cbcc:std:dcep:2020:tech:xsd:dcep.433.001.01\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + if (flag) {
" <BankAttAcctReq>\n" + System.out.println(s + ": " + Util.bytes2HexString((byte[]) o));
" <GrpHdr>\n" + } else {
" <MsgId>20211231058043300311422380336000</MsgId>\n" + System.out.println(s + ": " + new String((byte[]) o));
" <CreDtTm>2021-12-31T14:22:38</CreDtTm>\n" + }
" <InstgPty>\n" + } else {
" <InstgDrctPty>C1030131001288</InstgDrctPty>\n" + System.out.println(s + ":" + o);
" </InstgPty>\n" + }
" <InstdPty>\n" + }
" <InstdDrctPty>C1175662000017</InstdDrctPty>\n" +
" </InstdPty>\n" +
" </GrpHdr>\n" +
" <MgmtTp>MT01</MgmtTp>\n" +
" <SgnInf>\n" +
" <SgnAcctPtyId>C1175662000017</SgnAcctPtyId>\n" +
" <SgnAcctTp>AT00</SgnAcctTp>\n" +
" <SgnAcctId>983zGfqfC3O7xbgYwsW9TfRp1ddVT7vfaAAGhZ7Y7M0=</SgnAcctId>\n" +
" <SgnAcctNm>VbuPbl33/yi8OsQkme0kqZ0Tmvf8eJIyngC8CRyIk8E=</SgnAcctNm>\n" +
" <IDTp>IT01</IDTp>\n" +
" <IDNo>v1NPE/GPSooCXY4Z4RomtgDGpLxcm7RnF/VS16LEd3U=</IDNo>\n" +
" <Tel>G8DUftbIJTJpjrIgvoF3KQ==</Tel>\n" +
" <SgnTp>SG01</SgnTp>\n" +
" </SgnInf>\n" +
" <WltInf>\n" +
" <WltPtyId>C1030131001288</WltPtyId>\n" +
" <WltId>ZyBTxt3R/zN6AD7KqWotug==</WltId>\n" +
" <WltTp>WT01</WltTp>\n" +
" <WltLvl>WL01</WltLvl>\n" +
" </WltInf>\n" +
" </BankAttAcctReq>\n" +
"</Document>";
String sn = "10000000000000000000001042580423";
String sign = "MEUCIGpByl+Q1uSLXVPHdRvPXufgGEru+kUDj13jBY68b3NrAiEA3WbN3tYTCK7GRIsfnVA+3jbGTYluKs/Xz+JZkFZ4tIM=";
boolean b = api.netGSVerify(sn, orgData.getBytes(), sign);
System.out.println("验签结果: " + b);
} }
} }
@@ -40,20 +40,33 @@ public class TestHT {
@Test @Test
public void testSM2ConfirmSessionKeyC() { 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); RetWrap retWrap = api.SM2GenSessionKey(pk);
printRetWrap(retWrap); printRetWrap(retWrap);
String cipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY); String cipherKey = (String) retWrap.get(SydApi.RET_CIPHER_KEY);
String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY); String sessionKey = (String) retWrap.get(SydApi.RET_SESSION_KEY);
String kcv = (String) retWrap.get(SydApi.RET_KCV); String kcv = (String) retWrap.get(SydApi.RET_KCV);
// 使用生成的对称密钥加密数据
byte[] dataEnc = api.SYMEncryptData(SydApi.NALG_SM4, sessionKey, data.getBytes());
// 解密数字信封
RetWrap retWrap1 = api.SM2ConfirmSessionKeyC(userId, cipherKey); RetWrap retWrap1 = api.SM2ConfirmSessionKeyC(userId, cipherKey);
printRetWrap(retWrap1); printRetWrap(retWrap1);
sessionKey = (String) retWrap1.get(SydApi.RET_SESSION_KEY); sessionKey = (String) retWrap1.get(SydApi.RET_SESSION_KEY);
kcv = (String) retWrap1.get(SydApi.RET_KCV); kcv = (String) retWrap1.get(SydApi.RET_KCV);
// 使用解密出来的对称密钥解密数据
byte[] bytes1 = api.SYMDecryptData(SydApi.NALG_SM4, sessionKey, dataEnc);
System.out.println("解密后的数据:" + new String(bytes1));
} }
// 测试通过 // 测试通过