diff --git a/src/main/java/com/sunyard/inf/SydSVApi.java b/src/main/java/com/sunyard/inf/SydSVApi.java index 8e4ed0e..efbe412 100644 --- a/src/main/java/com/sunyard/inf/SydSVApi.java +++ b/src/main/java/com/sunyard/inf/SydSVApi.java @@ -4,6 +4,8 @@ package com.sunyard.inf; import com.sunyard.RetWrap; import com.sunyard.cert.X509; +import java.io.UnsupportedEncodingException; + /** * 签名验签相关接口 */ @@ -177,7 +179,7 @@ interface SydAttachedSVApi { * @return * 符合PKCS7标准的签名结果 */ - String attachedSign(byte[] orgData, String sCertDN); + String attachedSign(byte[] orgData, String sCertDN) throws UnsupportedEncodingException; byte[] attachedSignC(byte[] orgData, String sCertDN); /** diff --git a/src/main/java/com/sunyard/util/ASN1Util.java b/src/main/java/com/sunyard/util/ASN1Util.java new file mode 100644 index 0000000..b99ffb5 --- /dev/null +++ b/src/main/java/com/sunyard/util/ASN1Util.java @@ -0,0 +1,67 @@ +package com.sunyard.util; + +import cn.hutool.core.bean.BeanUtil; +import com.sunyard.RetWrap; +import com.sunyard.proto.R; +import com.sunyard.proto.Util; +import org.bouncycastle.asn1.*; + +import java.io.IOException; + + +public class ASN1Util { + + + public static RetWrap takeOutOriginDataFromPKCS7Sign(String sign) throws IOException { + RetWrap ret = new RetWrap(); + + ASN1Sequence seq = ASN1Sequence.getInstance( Util.decodeBase64( sign ) ); + ASN1TaggedObject tag = (ASN1TaggedObject) seq.getObjectAt(1).toASN1Primitive(); + ASN1Sequence seq2 = (ASN1Sequence) tag.getObject(); + ASN1Sequence seq3 = (ASN1Sequence) seq2.getObjectAt( 2 ).toASN1Primitive(); + ASN1TaggedObject tag2 = (ASN1TaggedObject) seq3.getObjectAt( 1 ); + DEROctetString o = (DEROctetString) tag2.getObject(); + ret.put( "orgData", o.getOctets() ); + + + ASN1TaggedObject tag3 = (ASN1TaggedObject) seq2.getObjectAt(3).toASN1Primitive(); + ASN1Sequence seq4 = (ASN1Sequence) tag3.getObject(); + ret.put("cert", CertUtil.encodeBase64(seq4.getEncoded())); + + ASN1Sequence seq5 = (ASN1Sequence) seq4.getObjectAt( 0 ).toASN1Primitive(); + ASN1Sequence seq6 = (ASN1Sequence) seq5.getObjectAt( 6 ).toASN1Primitive(); + DERBitString pk = (DERBitString) seq6.getObjectAt( 1 ).toASN1Primitive(); + ret.put("pk", pk.getEncoded() ); + + ASN1Encodable[] elements = seq3.toArray(); + ASN1Encodable[] elements2 = new ASN1Encodable[ elements.length - 1]; + for ( int i = 0; i < elements.length -1 ; i++ ){ + elements2[i] = elements[i]; + } + + BeanUtil.setProperty( seq3, "elements", elements2); + + ret.put("sign", Util.encodeBase64(seq.getEncoded()) ); + return ret; + } + + public static String addOriginDataToPKCS7Sign( byte[] originData, String sign) throws IOException { + ASN1Sequence seq = ASN1Sequence.getInstance( Util.decodeBase64( sign ) ); + ASN1TaggedObject tag = (ASN1TaggedObject) seq.getObjectAt(1).toASN1Primitive(); + ASN1Sequence seq2 = (ASN1Sequence) tag.getObject(); + ASN1Sequence seq3 = (ASN1Sequence) seq2.getObjectAt( 2 ).toASN1Primitive(); + + ASN1Encodable[] elements = seq3.toArray(); + ASN1Encodable[] elements2 = new ASN1Encodable[ elements.length + 1]; + for ( int i = 0; i < elements.length ; i++ ){ + elements2[i] = elements[i]; + } + + elements2[ elements.length ] = new DERTaggedObject(true, 0, new DEROctetString( originData )); + + BeanUtil.setProperty( seq3, "elements", elements2); + + return Util.encodeBase64(seq.getEncoded()); + } + +} diff --git a/src/main/java/com/sunyard/util/CertUtil.java b/src/main/java/com/sunyard/util/CertUtil.java new file mode 100644 index 0000000..11d47fa --- /dev/null +++ b/src/main/java/com/sunyard/util/CertUtil.java @@ -0,0 +1,9 @@ +package com.sunyard.util; + +import sun.misc.BASE64Encoder; + +public class CertUtil { + public static String encodeBase64(byte[] data){ + return new BASE64Encoder().encode( data ); + } +} diff --git a/src/main/java/racal/sunyard/main/SydApi4j.java b/src/main/java/racal/sunyard/main/SydApi4j.java index ba818c6..b9eef27 100644 --- a/src/main/java/racal/sunyard/main/SydApi4j.java +++ b/src/main/java/racal/sunyard/main/SydApi4j.java @@ -4960,7 +4960,7 @@ public class SydApi4j implements SydApi { // 填充数据 PacketSN sn = PacketSN.gen(); - final int packLen = 2048; + final int packLen = 4064; // 2048 int loop = msg.length / packLen; if (msg.length % packLen > 0) { loop++; @@ -5016,7 +5016,7 @@ public class SydApi4j implements SydApi { } - ByteBuffer bb = ByteBuffer.allocate(3000); + ByteBuffer bb = ByteBuffer.allocate(4 * 1024 + 128); byte[] ret = new byte[2]; bb.put(ret); @@ -10424,6 +10424,64 @@ public class SydApi4j implements SydApi { return sign.getBytes(); } + public String attachedSignSoft(byte[] orgData, String sCertDN) throws UnsupportedEncodingException { + String pk = this.GetDNPublicKey( SydApi.FOR_SIGN, sCertDN.getBytes("GBK") ); + try { + byte[] hash = this.SM3Hash( pk, orgData ); + String sign = this.detachedSign(0, hash, sCertDN); + return ASN1Util.addOriginDataToPKCS7Sign( orgData, sign ); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException("解析 pkcs7 签名格式时错误"); + } + } + + private RetWrap attachedVerifySoftGetAll(byte[] sign){ + RetWrap ret = null; + + try { + ret = ASN1Util.takeOutOriginDataFromPKCS7Sign( new String(sign) ); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException("解析 pkcs7 签名格式时错误"); + } + + byte[] orgData = (byte[]) ret.get("orgData"); + byte[] pk = (byte[]) ret.get("pk"); + byte[] hash = this.SM3Hash( Util.bytes2HexString( pk ), orgData ); + String sign2 = (String) ret.get("sign"); + boolean pass = this.detachedVerify( 0, hash , sign2); + if ( pass ) { + ret.put("oData", orgData); + String certInfo = (String) ret.get("cert"); + certInfo = "-----BEGIN CERTIFICATE-----\r\n" + certInfo; + certInfo = certInfo + "\r\n-----END CERTIFICATE-----\r\n"; + + X509 x509 = GetX509CertInfo( certInfo ); + ret.put("x509", x509); + return ret; + } else { + return null; + } + } + + private boolean attachedVerifySoft(String sign){ + RetWrap ret = null; + try { + ret = ASN1Util.takeOutOriginDataFromPKCS7Sign( sign ); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException("解析 pkcs7 签名格式时错误"); + } + + byte[] orgData = (byte[]) ret.get("orgData"); + byte[] pk = (byte[]) ret.get("pk"); + byte[] hash = this.SM3Hash( Util.bytes2HexString( pk ), orgData ); + String sign2 = (String) ret.get("sign"); + return this.detachedVerify( 0, hash , sign2); + } + + /** * 带公钥证书与原始数据的数字签名(遵循 PKCS#7) * 使用指定的证书 DN,从加密设备获取对应的私钥证书,对指定的原始数据编制带公钥证书的数字签名(遵循 PKCS#7)。 @@ -10434,6 +10492,19 @@ public class SydApi4j implements SydApi { */ @Override public String attachedSign(byte[] orgData, String sCertDN) { + try { + if ( orgData.length > 4096 ) { + return attachedSignSoft( orgData, sCertDN ); + } else { + return attachedSignHsm( orgData, sCertDN ); + } + }catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("DN is not in GBK"); + } + } + + + public String attachedSignHsm(byte[] orgData, String sCertDN) { sCertDN = DnUtil.verifyDn( sCertDN ); Proto8018 proto = new Proto8018(); @@ -10483,9 +10554,17 @@ public class SydApi4j implements SydApi { return ((PacketSection) ret.get("signature")).getString(); } + public boolean attachedVerifyHsm(String sign) { + return attachedVerify( sign.getBytes() ); + } + @Override public boolean attachedVerify(String sign) { - return attachedVerify( sign.getBytes() ); + if ( sign.length() > 4096 ) { + return attachedVerifySoft( sign ); + } else { + return attachedVerify( sign.getBytes() ); + } } @Override @@ -10568,7 +10647,19 @@ public class SydApi4j implements SydApi { return attachedVerifyAndGetAll( sign.getBytes() ); } + // 大数据兼容处理 public RetWrap attachedVerifyAndGetAll(byte[] sign) { + if( sign.length > 4096 ) { + + return attachedVerifySoftGetAll( sign ); + + } else { + return attachedVerifyAndGetAllHsm( sign ); + } + } + + + public RetWrap attachedVerifyAndGetAllHsm(byte[] sign) { Proto8019 proto = new Proto8019(); // 填充数据 diff --git a/src/test/java/com/sunyard/sydapi/test/TestE0.java b/src/test/java/com/sunyard/sydapi/test/TestE0.java index 0a3fe90..6c6e256 100644 --- a/src/test/java/com/sunyard/sydapi/test/TestE0.java +++ b/src/test/java/com/sunyard/sydapi/test/TestE0.java @@ -12,7 +12,7 @@ import java.util.Arrays; public class TestE0 { private SydApi4j api; - private byte[] data = new byte[ 4 * 1024 -1 ]; + private byte[] data = new byte[ 0x501 ]; private byte[] iv = new byte[ 32 ]; @Before diff --git a/src/test/java/com/sunyard/sydapi/test/TestHT.java b/src/test/java/com/sunyard/sydapi/test/TestHT.java index 90acf88..4e4d6d9 100644 --- a/src/test/java/com/sunyard/sydapi/test/TestHT.java +++ b/src/test/java/com/sunyard/sydapi/test/TestHT.java @@ -11,7 +11,6 @@ import org.junit.Test; import racal.sunyard.main.SydApi4j; import java.io.UnsupportedEncodingException; -import java.util.Arrays; /** @@ -24,7 +23,7 @@ public class TestHT { @Before public void before() { // 通过设置debug的属性开启debug,如果不设置则默认不打开 - System.setProperty("com.sunyard.sydapi4j.debug", "true"); +// System.setProperty("com.sunyard.sydapi4j.debug", "true"); api = (SydApi4j) new SydApi4j().connect("172.16.18.59", 8889, null, 1000); // api = (SydApi4j) new SydApi4j().connect("192.168.0.66", 8889, null, 1000); } @@ -42,16 +41,16 @@ public class TestHT { * 流程演示 */ @Test - public void testProcess() throws UnsupportedEncodingException { + public void testProcess() { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; - byte[] orgData = "111111213323143243243".getBytes("UTF-8"); + byte[] orgData = new byte[2 * 1024 * 1024]; // 签名 String sign = api.attachedSign(orgData, dn); - System.out.println("签名结果: " + sign ); + System.out.println("签名结果: " + sign); // 生成数字信封 - RetWrap retWrap = api.generateDEByDn(dn, sign.getBytes() ); + RetWrap retWrap = api.generateDEByDn(dn, sign.getBytes()); byte[] cipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); System.out.println("数字信封: " + new String(cipherKey)); @@ -63,8 +62,8 @@ public class TestHT { // 验签 RetWrap verify = api.attachedVerifyAndGetAll(oData); if (verify != null) { - System.out.println("x509公钥: " + Util.bytes2HexString(((X509)verify.get("x509")).getPubKey())); - System.out.println("签名原数据: " + Util.bytes2HexString((byte[])(verify.get("oData")))); + System.out.println("x509公钥: " + Util.bytes2HexString(((X509) verify.get("x509")).getPubKey())); + System.out.println("签名原数据: " + Util.bytes2HexString((byte[]) (verify.get("oData")))); } } @@ -102,6 +101,67 @@ public class TestHT { System.out.println("解密后的数据:" + new String(bytes1)); } + + @Test + public void testDetachedSignAndVerify1() throws UnsupportedEncodingException { + 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); + System.out.println("签名结果 hex : " + Util.bytes2HexString(Util.decodeBase64(sign))); + + boolean verify = api.attachedVerify(sign); + System.out.println("验签结果: " + verify); + Assert.assertTrue(verify); + } + + + @Test + public void testDetachedSignAndVerify2() throws UnsupportedEncodingException { + String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; + String orgData = "111111213323143243243"; + + + String sign = api.attachedSignSoft(orgData.getBytes(), dn); + System.out.println("签名结果: " + sign); + System.out.println("签名结果 hex: " + Util.bytes2HexString(Util.decodeBase64(sign))); + + boolean verify = api.attachedVerify(sign); + System.out.println("验签结果: " + verify); + Assert.assertTrue(verify); + } + + + @Test + public void testDetachedSignAndVerify3() throws UnsupportedEncodingException { + String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; + byte[] orgData = new byte[3 * 1024]; + + String sign = api.attachedSign(orgData, dn); + System.out.println("签名结果: " + sign); + System.out.println("签名结果 hex: " + Util.bytes2HexString(Util.decodeBase64(sign))); + + boolean verify = api.attachedVerify(sign); + System.out.println("验签结果: " + verify); + Assert.assertTrue(verify); + } + + @Test + public void testDetachedSignAndVerify8() throws UnsupportedEncodingException { + String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; + byte[] orgData = new byte[8 * 1024]; + + String sign = api.attachedSign(orgData, dn); + System.out.println("签名结果: " + sign); + System.out.println("签名结果 hex: " + Util.bytes2HexString(Util.decodeBase64(sign))); + + boolean verify = api.attachedVerify(sign); + System.out.println("验签结果: " + verify); + Assert.assertTrue(verify); + } + // 测试通过 // 8018 @Test @@ -110,6 +170,7 @@ public class TestHT { String orgData = "111111213323143243243"; String sign = api.attachedSign(orgData.getBytes(), dn); System.out.println("签名结果: " + sign); + System.out.println("签名结果 hex : " + Util.bytes2HexString(Util.decodeBase64(sign))); boolean verify = api.attachedVerify(sign); System.out.println("验签结果: " + verify); @@ -120,7 +181,8 @@ public class TestHT { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; byte[] orgData = "111111213323143243243".getBytes(); String sign = api.attachedSign(orgData, dn); - System.out.println("签名结果: " + sign ); + System.out.println("签名结果: " + sign); + X509 verify = api.attachedVerifyAndGetX509(sign); System.out.println("验签结果: " + Util.bytes2HexString(verify.getPubKey())); @@ -146,7 +208,21 @@ public class TestHT { RetWrap verify = api.attachedVerifyAndGetAll(sign); if (verify != null) { - System.out.println("x509公钥: " + Util.bytes2HexString(((X509)verify.get("x509")).getPubKey())); + System.out.println("x509公钥: " + Util.bytes2HexString(((X509) verify.get("x509")).getPubKey())); + System.out.println("签名原数据: " + verify.get("oData")); + } + } + + @Test + public void testAttachedSignAndVerifyGetAll8k() { + String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; + byte[] orgData = new byte[ 8 * 1024 ]; + String sign = api.attachedSign(orgData, dn); + System.out.println("签名结果: " + sign); + + RetWrap verify = api.attachedVerifyAndGetAll(sign); + if (verify != null) { + System.out.println("x509公钥: " + Util.bytes2HexString(((X509) verify.get("x509")).getPubKey())); System.out.println("签名原数据: " + verify.get("oData")); } } @@ -157,7 +233,7 @@ public class TestHT { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; byte[] orgData = "111111213323143243243".getBytes(); byte[] sign = api.attachedSignC(orgData, dn); - System.out.println("签名结果: " + sign ); + System.out.println("签名结果: " + sign); X509 verify = api.attachedVerifyAndGetX509(sign); System.out.println("验签结果: " + Util.bytes2HexString(verify.getPubKey())); @@ -184,7 +260,7 @@ public class TestHT { RetWrap verify = api.attachedVerifyAndGetAll(sign); if (verify != null) { - System.out.println("x509公钥: " + Util.bytes2HexString(((X509)verify.get("x509")).getPubKey())); + System.out.println("x509公钥: " + Util.bytes2HexString(((X509) verify.get("x509")).getPubKey())); System.out.println("签名原数据: " + verify.get("oData")); } } @@ -192,7 +268,7 @@ public class TestHT { @Test public void testDecryptDE54k12() throws UnsupportedEncodingException { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; - byte[] oData = new byte[ 4 * 1024 ]; + byte[] oData = new byte[4 * 1024]; RetWrap retWrap = api.generateDEByDnHsm(dn, oData); byte[] CipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); @@ -202,13 +278,13 @@ public class TestHT { RetWrap retWrap1 = api.decryptDEByDNSoft(dn, new String(CipherKey)); printRetWrap(retWrap1); byte[] deData = (byte[]) retWrap1.get("oData"); - Assert.assertArrayEquals( deData, oData ); + Assert.assertArrayEquals(deData, oData); } @Test public void testDecryptDE54k21() throws UnsupportedEncodingException { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; - byte[] oData = new byte[ 4 * 1024 ]; + byte[] oData = new byte[4 * 1024]; RetWrap retWrap = api.generateDEByDnSoft(dn, oData); byte[] CipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); @@ -218,14 +294,14 @@ public class TestHT { RetWrap retWrap1 = api.decryptDEByDNHsm(dn, new String(CipherKey)); printRetWrap(retWrap1); byte[] deData = (byte[]) retWrap1.get("oData"); - Assert.assertArrayEquals( deData, oData ); + Assert.assertArrayEquals(deData, oData); } @Test public void testDecryptDE54k() throws UnsupportedEncodingException { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; - byte[] oData = new byte[ 4 * 1024 ]; + byte[] oData = new byte[4 * 1024]; RetWrap retWrap = api.generateDEByDn(dn, oData); byte[] CipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); @@ -240,7 +316,7 @@ public class TestHT { @Test public void testDecryptDE54kr() throws UnsupportedEncodingException { String dn = "CN=YCCA@黄金交易所@Zhuangj@1,OU=Individual-2,OU=YCCA,O=CFCA OCA1,C=CN"; - byte[] oData = new byte[ 4 * 1024 ]; + byte[] oData = new byte[4 * 1024]; RetWrap retWrap = api.generateDEByDn(dn, oData); byte[] CipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); @@ -255,7 +331,7 @@ public class TestHT { @Test public void testDecryptDE520M() throws UnsupportedEncodingException { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; - byte[] oData = new byte[ 20 * 1024 * 1024 ]; + byte[] oData = new byte[20 * 1024 * 1024]; RetWrap retWrap = api.generateDEByDn(dn, oData); byte[] CipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); @@ -269,7 +345,7 @@ public class TestHT { @Test public void testDecryptDE58k() throws UnsupportedEncodingException { String dn = "C=CN,O=CFCA OCA1,OU=YCCA,OU=Individual-2,CN=YCCA@黄金交易所@Zhuangj@1"; - byte[] oData = new byte[ 8 * 1024 ]; + byte[] oData = new byte[8 * 1024]; RetWrap retWrap = api.generateDEByDn(dn, oData); byte[] CipherKey = (byte[]) retWrap.get(SydApi.RET_CIPHER_KEY); @@ -295,10 +371,6 @@ public class TestHT { } - - - - // 测试通过 // 76 @Test @@ -311,7 +383,6 @@ public class TestHT { } - // =============================工具方法============================================== public static void printRetWrap(RetWrap rw) { @@ -320,6 +391,7 @@ public class TestHT { /** * 输出 + * * @param rw */ public static void printRetWrap(RetWrap rw, boolean flag) { @@ -339,7 +411,4 @@ public class TestHT { } } } - - - }