關於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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM