王京 的个人博客

记录精彩的程序人生

  menu
44 文章
0 浏览
1 当前访客
ღゝ◡╹)ノ❤️

国密算法SM2 的JAVA实现(基于BC实现)

一、pom文件引用

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.58</version>
</dependency>

二、国密公私钥对 工具类

package com.prison.common.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author WangJing
 * @Description 国密公私钥对 工具类
 * @date 2021/11/24 16:10
 */
public class KeyUtils {

    /**
     * 生成国密公私钥对
     *
     * @return
     * @throws Exception
     */
    public static String[] generateSmKey() throws Exception {
        KeyPairGenerator keyPairGenerator = null;
        SecureRandom secureRandom = new SecureRandom();
        ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        keyPairGenerator.initialize(sm2Spec);
        keyPairGenerator.initialize(sm2Spec, secureRandom);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        //String[0] 公钥
        //String[1] 私钥
        String[] result = {
                new String(Base64.getEncoder().encode(publicKey.getEncoded()))
                , new String(Base64.getEncoder().encode(privateKey.getEncoded()))
        };
        return result;
    }

    /**
     * 将Base64转码的公钥串,转化为公钥对象
     *
     * @param publicKey
     * @return
     */
    public static PublicKey createPublicKey(String publicKey) {
        PublicKey publickey = null;
        try {
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
            KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
            publickey = keyFactory.generatePublic(publicKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publickey;
    }

    /**
     * 将Base64转码的私钥串,转化为私钥对象
     *
     * @param privateKey
     * @return
     */
    public static PrivateKey createPrivateKey(String privateKey) {
        PrivateKey publickey = null;
        try {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
            publickey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publickey;
    }

}

三、SM2实现工具类

package com.prison.common.util;

import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;

import java.security.*;

/**
 * @author WangJing
 * @Description SM2实现工具类
 * @date 2021/11/24 16:10
 */
public class Sm2Util {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 根据publicKey对原始数据data,使用SM2加密
     *
     * @param data
     * @param publicKey
     * @return
     */
    public static byte[] encrypt(byte[] 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, 0, data.length);
            return arrayOfByte2;
        } catch (InvalidCipherTextException e) {

            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据privateKey对加密数据encodedata,使用SM2解密
     *
     * @param encodedata
     * @param privateKey
     * @return
     */
    public static byte[] decrypt(byte[] encodedata, PrivateKey privateKey) {
        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(encodedata, 0, encodedata.length);
            return arrayOfByte3;
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 私钥签名
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] signByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {
        Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
        sig.initSign(privateKey);
        sig.update(data);
        byte[] ret = sig.sign();
        return ret;
    }

    /**
     * 公钥验签
     *
     * @param data
     * @param publicKey
     * @param signature
     * @return
     * @throws Exception
     */
    public static boolean verifyByPublicKey(byte[] data, PublicKey publicKey, byte[] signature) throws Exception {
        Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
        sig.initVerify(publicKey);
        sig.update(data);
        boolean ret = sig.verify(signature);
        return ret;
    }

}

四、Sm2Util 的测试类

package com.prison.common.util;

import org.junit.Test;

import java.util.Base64;

/**
 * @author WangJing
 * @Description Sm2Util 的测试类
 * @date 2021/11/24 16:10
 */
public class Sm2UtilTest {

    private String testStr = "wangjing";

    java.security.PublicKey publicKey = null;
    java.security.PrivateKey privateKey = null;


    @Test
    public void test() throws Exception {
        //生成公私钥对
        String[] keys = KeyUtils.generateSmKey();

        System.out.println("原始字符串:" + testStr);
        System.out.println("公钥:" + keys[0]);
        publicKey = KeyUtils.createPublicKey(keys[0]);

        System.out.println("私钥:" + keys[1]);
        privateKey = KeyUtils.createPrivateKey(keys[1]);

        System.out.println("");


        byte[] encrypt = Sm2Util.encrypt(testStr.getBytes(), publicKey);
        String encryptBase64Str = Base64.getEncoder().encodeToString(encrypt);
        System.out.println("加密数据:" + encryptBase64Str);

        byte[] decode = Base64.getDecoder().decode(encryptBase64Str);
        byte[] decrypt = Sm2Util.decrypt(decode, privateKey);
        System.out.println("解密数据:" + new String(decrypt));

        byte[] sign = Sm2Util.signByPrivateKey(testStr.getBytes(), privateKey);
        System.out.println("数据签名:" + Base64.getEncoder().encodeToString(sign));

        boolean b = Sm2Util.verifyByPublicKey(testStr.getBytes(), publicKey, sign);
        System.out.println("数据验签:" + b);
    }
}

五、执行效果

原始字符串:wangjing
公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEPWEqpTEQ1hjyHY8zBZszVb+R/JoXrnbnlrrJ9AgWlEcotEMlzoKpO5qPcJ02sm9UsWhYtMsxYZWpN5BLQn+Iyg==
私钥:MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgwAiExBi5nLzMynDVGdhnFU0ONgeREPeJsNm7iH7Rk2+gCgYIKoEcz1UBgi2hRANCAAQ9YSqlMRDWGPIdjzMFmzNVv5H8mheudueWusn0CBaURyi0QyXOgqk7mo9wnTayb1SxaFi0yzFhlak3kEtCf4jK

加密数据:BGDG3Ejl93WTO7Iv8AgYY+REzlHuVhEJW7TEhmJ8FrywWIQM+8USbVAKTulS3hysPl+JVgcvBAnL+z7kzkbP8ajw+sqptGznTuIavvclrTEhT44/uKNCcF3L/4lS3fxzf8YTaf85F42y
解密数据:wangjing
数据签名:MEYCIQDvggaW8idugfKiPixGpaOO46h8yg52hzA4sz3KiFfhfgIhAIcwOc94GtmPERvZksIHOUBjahJKVhKw6QUQSS4+s/1Q
数据验签:true

注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!


标题:国密算法SM2 的JAVA实现(基于BC实现)
作者:wangjing
地址:https://www.codedblogs.cn/articles/2024/04/12/1712900258779.html