zoukankan      html  css  js  c++  java
  • 关于bouncycastle下国密SM2 API的使用

    本文不对SM2做过多的介绍,主要介绍java bouncycastle库关于SM2的相关API的使用及注意事项

    1. SM2 签名:

    注意:

      1)签名格式ASN1(描述了种对数据进行表示、编码、传输和解码的数据格式),包括两个大整数。

      2)注意USER_ID的一致性(规范默认是"1234567812345678"),否则影响验签。

      

    主要代码

    SM2Signer localSM2Signer = new SM2Signer();
           Security.addProvider(new BouncyCastleProvider());
           PublicKey publicKey = cert.getPublicKey();
           ECPublicKeyParameters param = null;
           
           if (publicKey instanceof BCECPublicKey)
           {
               BCECPublicKey localECPublicKey = (BCECPublicKey)publicKey;
               ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
               ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
               localECParameterSpec.getG(), localECParameterSpec.getN());
               param = new ECPublicKeyParameters(localECPublicKey.getQ(),localECDomainParameters);
           }
           ByteArrayInputStream inStream = new ByteArrayInputStream(signdatebyte);
           ASN1InputStream asnInputStream = new ASN1InputStream(inStream);
           ASN1Primitive derObject = asnInputStream.readObject();
           BigInteger R = null;
           BigInteger S = null;
           if (derObject instanceof ASN1Sequence) {  
               ASN1Sequence signSequence = (ASN1Sequence) derObject;  
               Enumeration<ASN1Integer> enumer = signSequence.getObjects();
                   R =  ((ASN1Integer)enumer.nextElement()).getValue();
                   S =  ((ASN1Integer)enumer.nextElement()).getValue();
           }
           ParametersWithID parametersWithID = new ParametersWithID(param,SM2_USER_ID);
           localSM2Signer.init(false, parametersWithID);
           boolean res = localSM2Signer.verifySignature(databyte, BigIntegerUtil.toPositiveInteger(R.toByteArray()),
               BigIntegerUtil.toPositiveInteger(S.toByteArray()));
           return res;


    2. SM2 验签:

    注意:同签名

    主要代码

    SM2Signer localSM2Signer = new SM2Signer();
           Security.addProvider(new BouncyCastleProvider());
           PublicKey publicKey = cert.getPublicKey();
           ECPublicKeyParameters param = null;
           
           if (publicKey instanceof BCECPublicKey)
           {
               BCECPublicKey localECPublicKey = (BCECPublicKey)publicKey;
               ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
               ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
               localECParameterSpec.getG(), localECParameterSpec.getN());
               param = new ECPublicKeyParameters(localECPublicKey.getQ(),localECDomainParameters);
           }
           ByteArrayInputStream inStream = new ByteArrayInputStream(signdatebyte);
           ASN1InputStream asnInputStream = new ASN1InputStream(inStream);
           ASN1Primitive derObject = asnInputStream.readObject();
           BigInteger R = null;
           BigInteger S = null;
           if (derObject instanceof ASN1Sequence) {  
               ASN1Sequence signSequence = (ASN1Sequence) derObject;  
               Enumeration<ASN1Integer> enumer = signSequence.getObjects();
                   R =  ((ASN1Integer)enumer.nextElement()).getValue();
                   S =  ((ASN1Integer)enumer.nextElement()).getValue();
           }
           ParametersWithID parametersWithID = new ParametersWithID(param,SM2_USER_ID);
           localSM2Signer.init(false, parametersWithID);
           boolean res = localSM2Signer.verifySignature(databyte, BigIntegerUtil.toPositiveInteger(R.toByteArray()),
               BigIntegerUtil.toPositiveInteger(S.toByteArray()));


    3. 加解密

    public static String encrypt(String data, PublicKey publicKey)
        {
    
            ECPublicKeyParameters localECPublicKeyParameters = null;
    
            if (publicKey instanceof BCECPublicKey)
            {
                BCECPublicKey localECPublicKey = (BCECPublicKey)publicKey;
                ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
                ECDomainParameters localECDomainParameters = new ECDomainParameters(
                    localECParameterSpec.getCurve(), localECParameterSpec.getG(),
                    localECParameterSpec.getN());
                localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(),
                    localECDomainParameters);
            }
            SM2Engine localSM2Engine = new SM2Engine();
            localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters,
                new SecureRandom()));
            byte[] arrayOfByte2;
            try
            {
                arrayOfByte2 = localSM2Engine.processBlock(data.getBytes(), 0, data.getBytes().length);
                return new String(Base64.encode(arrayOfByte2));
            }
            catch (InvalidCipherTextException e)
            {
    
                e.printStackTrace();
                return null;
            }
    
        }
    
        public static String decrypt(String encodedata, PrivateKey privateKey)
        {
            byte[] encodedataByte = Base64.decode(encodedata.getBytes());
            SM2Engine localSM2Engine = new SM2Engine();
            BCECPrivateKey sm2PriK = (BCECPrivateKey)privateKey;
            ECParameterSpec localECParameterSpec = sm2PriK.getParameters();
            ECDomainParameters localECDomainParameters = new ECDomainParameters(
                localECParameterSpec.getCurve(), localECParameterSpec.getG(),
                localECParameterSpec.getN());
            ECPrivateKeyParameters localECPrivateKeyParameters = new ECPrivateKeyParameters(
                sm2PriK.getD(), localECDomainParameters);
            localSM2Engine.init(false, localECPrivateKeyParameters);
            try
            {
                byte[] arrayOfByte3 = localSM2Engine.processBlock(encodedataByte, 0,
                    encodedataByte.length);
                return new String(arrayOfByte3);
            }
            catch (InvalidCipherTextException e)
            {
                e.printStackTrace();
                return null;
            }
    
        }


    4. pkcs#7(CMS)格式

    可以使用bouncycastle的CMS包下的API进行封装,或者自己实现,或使用j4sign库(基于bouncycastle)实现。这里就不贴代码了。

    注意:相关OID

    国密标准GM/T 0010定义的oid如下:
    数据类型data                                                            1.2.156.10197.6.1.4.2.1
    签名数据类型signedData                                                   1.2.156.10197.6.1.4.2.2
    数字信封数据类型envelopedData                                         1.2.156.10197.6.1.4.2.3
    签名及数字信封数据类型signedAndEnvelopedData                   1.2.156.10197.6.1.4.2.4
    加密数据类型encryptedData                                                1.2.156.10197.6.1.4.2.5
    密钥协商类型keyAgreementInfo                                            1.2.156.10197.6.1.4.2.6

    参考资料:

    1.GM T 0009-2012 SM2密码算法使用规范

    2.https://tools.ietf.org/html/rfc2315

    3.http://j4sign.sourceforge.net/

    4.http://gmssl.org/docs/oid.html

    5.https://stackoverflow.com/questions/39925946/generate-cmssigneddata-with-no-private-key-in-java

    6.https://github.com/bcgit/bc-java

    7.https://www.zhihu.com/question/62639301/answer/214184309

    转载请注明原博客地址http://www.cnblogs.com/jeffreyluo/p/sm2forjava.html)

  • 相关阅读:
    重塑矩阵
    数组拆分
    最大连续1的个数
    石子游戏
    概率与期望知识总结
    洛谷 P3951 NOIP 2017 小凯的疑惑
    关于结构体的初始化
    山海经:线段树维护最大子段和
    偏序 分块+bitset
    分块练习C. interval
  • 原文地址:https://www.cnblogs.com/jeffreyluo/p/sm2forjava.html
Copyright © 2011-2022 走看看