001package top.cenze.utils.crypt.sm.sm2;
002
003import org.bouncycastle.asn1.*;
004import org.bouncycastle.crypto.digests.SM3Digest;
005import org.bouncycastle.math.ec.ECPoint;
006import top.cenze.utils.ConvertUtil;
007
008import java.io.ByteArrayInputStream;
009import java.math.BigInteger;
010import java.util.Enumeration;
011
012/**
013 * 国密算法的签名、验签
014 */
015public class SM2SignVerUtils {
016        /**
017         * 默认USERID
018         */
019        public static String USER_ID = "1234567812345678";
020        /**
021         * 私钥签名
022         * 使用SM3进行对明文数据计算一个摘要值
023         * @param privatekey 私钥
024         * @param sourceData 明文数据
025         * @return 签名后的值
026         * @throws Exception
027         */
028        public static SM2SignVO Sign2SM2(byte[] privatekey,byte[] sourceData) throws Exception {
029                SM2SignVO sm2SignVO = new SM2SignVO();
030                sm2SignVO.setSm2_type("sign");
031                SM2Factory factory = SM2Factory.getInstance();
032                BigInteger userD = new BigInteger(1,privatekey);
033                //System.out.println("userD:"+userD.toString(16));
034                sm2SignVO.setSm2_userd(userD.toString(16));
035
036                ECPoint userKey = factory.ecc_point_g.multiply(userD);
037                //System.out.println("椭圆曲线点X: "+ userKey.getXCoord().toBigInteger().toString(16));
038                //System.out.println("椭圆曲线点Y: "+ userKey.getYCoord().toBigInteger().toString(16));
039
040                SM3Digest sm3Digest = new SM3Digest();
041                byte [] z = factory.sm2GetZ(USER_ID.getBytes(), userKey);
042                //System.out.println("SM3摘要Z: " + Util.getHexString(z));
043                //System.out.println("被加密数据的16进制: " + Util.getHexString(sourceData));
044                sm2SignVO.setSm3_z(ConvertUtil.getHexString(z));
045                sm2SignVO.setSign_express(ConvertUtil.getHexString(sourceData));
046
047                sm3Digest.update(z, 0, z.length);
048                sm3Digest.update(sourceData,0,sourceData.length);
049                byte [] md = new byte[32];
050                sm3Digest.doFinal(md, 0);
051                //System.out.println("SM3摘要值: " + ConvertUtil.getHexString(md));
052                sm2SignVO.setSm3_digest(ConvertUtil.getHexString(md));
053
054                SM2Result sm2Result = new SM2Result();
055                factory.sm2Sign(md, userD, userKey, sm2Result);
056                //System.out.println("r: " + sm2Result.r.toString(16));
057                //System.out.println("s: " + sm2Result.s.toString(16));
058                sm2SignVO.setSign_r(sm2Result.r.toString(16));
059                sm2SignVO.setSign_s(sm2Result.s.toString(16));
060
061                ASN1Integer d_r = new ASN1Integer(sm2Result.r);
062                ASN1Integer d_s = new ASN1Integer(sm2Result.s);
063                ASN1EncodableVector v2 = new ASN1EncodableVector();
064                v2.add(d_r);
065                v2.add(d_s);
066                DERSequence sign = new DERSequence(v2);
067                String result = ConvertUtil.byteToHex(sign.getEncoded());
068                sm2SignVO.setSm2_sign(result);
069                return sm2SignVO;
070        }
071        /**
072         * 验证签名
073         * @param publicKey 公钥信息
074         * @param sourceData 密文信息
075         * @param signData 签名信息
076         * @return 验签的对象 包含了相关参数和验签结果
077         */
078        @SuppressWarnings("unchecked")
079        public static SM2SignVO VerifySignSM2(byte[] publicKey,byte[] sourceData,byte[] signData){
080                try {
081                        byte[] formatedPubKey;
082                        SM2SignVO verifyVo = new SM2SignVO();
083                        verifyVo.setSm2_type("verify");
084                        if (publicKey.length == 64) {
085                                // 添加一字节标识,用于ECPoint解析
086                                formatedPubKey = new byte[65];
087                                formatedPubKey[0] = 0x04;
088                                System.arraycopy(publicKey, 0, formatedPubKey, 1, publicKey.length);
089                        } else{
090                                formatedPubKey = publicKey;
091                        }
092                        SM2Factory factory = SM2Factory.getInstance();
093                        ECPoint userKey = factory.ecc_curve.decodePoint(formatedPubKey);
094
095                        SM3Digest sm3Digest = new SM3Digest();
096                        byte [] z = factory.sm2GetZ(USER_ID.getBytes(), userKey);
097                        //System.out.println("SM3摘要Z: " + ConvertUtil.getHexString(z));
098                        verifyVo.setSm3_z(ConvertUtil.getHexString(z));
099                        sm3Digest.update(z,0,z.length);
100                        sm3Digest.update(sourceData,0,sourceData.length);
101                        byte [] md = new byte[32];
102                        sm3Digest.doFinal(md, 0);
103                        //System.out.println("SM3摘要值: " + ConvertUtil.getHexString(md));
104                        verifyVo.setSm3_digest(ConvertUtil.getHexString(md));
105                        ByteArrayInputStream bis = new ByteArrayInputStream(signData);
106                        ASN1InputStream dis = new ASN1InputStream(bis);
107                        SM2Result sm2Result = null;
108                        ASN1Primitive derObj = dis.readObject();
109                        Enumeration<ASN1Integer> e = ((ASN1Sequence)derObj).getObjects();
110                        BigInteger r = ((ASN1Integer) e.nextElement()).getValue();
111                        BigInteger s = ((ASN1Integer) e.nextElement()).getValue();
112                        sm2Result = new SM2Result();
113                        sm2Result.r = r;
114                        sm2Result.s = s;
115                        //System.out.println("vr: " + sm2Result.r.toString(16));
116                        //System.out.println("vs: " + sm2Result.s.toString(16));
117                        verifyVo.setVerify_r(sm2Result.r.toString(16));
118                        verifyVo.setVerify_s(sm2Result.s.toString(16));
119                        factory.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
120                        boolean verifyFlag = sm2Result.r.equals(sm2Result.R);
121                        verifyVo.setVerify(verifyFlag);
122                        return  verifyVo;
123                } catch (IllegalArgumentException e) {
124                        return null;
125                }catch (Exception e) {
126                        e.printStackTrace();
127                        return null;
128                }
129        }
130
131//      public static void main(String[] args) throws Exception {
132//              String text = "这是一段明文";
133//              byte [] sourceData = text.getBytes();
134//              //String publicKey ="FA05C51AD1162133DFDF862ECA5E4A481B52FB37FF83E53D45FD18BBD6F32668A92C4692EEB305684E3B9D4ACE767F91D5D108234A9F07936020A92210BA9447";
135//              //String privatekey = "5EB4DF17021CC719B678D970C620690A11B29C8357D71FA4FF9BF7FB6D89767A";
136//              String publicKey ="04BB34D657EE7E8490E66EF577E6B3CEA28B739511E787FB4F71B7F38F241D87F18A5A93DF74E90FF94F4EB907F271A36B295B851F971DA5418F4915E2C1A23D6E";
137//              String privatekey = "0B1CE43098BC21B8E82B5C065EDB534CB86532B1900A49D49F3C53762D2997FA";
138//              SM2SignVO sign = SM2SignVerUtils.Sign2SM2(ConvertUtil.hexStringToBytes(privatekey), sourceData);
139//              SM2SignVO verify = SM2SignVerUtils.VerifySignSM2(ConvertUtil.hexStringToBytes(publicKey), sourceData, ConvertUtil.hexStringToBytes(sign.getSm2_signForSoft()));
140//              System.out.println("签名得到的r值:"+sign.getSign_r()+"\n签名值 "+sign.getSm2_signForSoft());
141//              System.out.println("验签得到的R值:"+verify.getVerify_r());
142//              System.err.println("\n验签结果" +verify.isVerify());
143//      }
144}