SM2非对称加密实例

发布时间 2023-06-27 14:40:02作者: 茫无所知
import com.alibaba.fastjson.JSON;
import com.zs.common.core.domain.entity.SysUser;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class SM2Utils {

    private static final Logger log = LoggerFactory.getLogger(SM2Utils.class);
    public static String staticPublicKey = "0408fda0c0f6d1e51289cd5edcef7386a696e1a63659dd4ae3516cfd4d0a5dfaa341ff9c86f2572cae9e1406a036d43b71862e8acf0dbfaeb6216c775038b46d40";
    public static String staticPrivateKey = "2158c2678f7ee7685392ddc31916b8c835a98887040bbf69f76fa4aa0acff42e";

    /**
     * 生成SM2公私钥对
     *
     * @return
     */
    private static void getSM2Key() {
        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");

        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        //1.创建密钥生成器
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();

        //2.初始化生成器,带上随机数
        try {
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
        } catch (NoSuchAlgorithmException e) {
            log.error("生成公私钥对时出现异常:", e);
//            e.printStackTrace();
        }

        //3.生成密钥对
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        String publicKey = Hex.toHexString(ecPoint.getEncoded(false));
        System.out.println("公钥:" + publicKey);
        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String priKey = privatekey.toString(16);
        System.out.println("私钥:" + priKey);
    }

    /**
     * SM2加密算法
     *
     * @param publicKey 公钥
     * @param data      数据
     * @return
     */
    public static String encrypt(String publicKey, String data) {
        // 获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        // 构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(),
                sm2ECParameters.getN());
        //提取公钥点
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));

        byte[] arrayOfBytes = null;
        try {
            byte[] in = data.getBytes("utf-8");
            arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
        } catch (Exception e) {
            log.error("SM2加密时出现异常:", e);
        }
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * SM2解密算法
     *
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return
     */
    public static String decrypt(String privateKey, String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);

        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                sm2ECParameters.getG(), sm2ECParameters.getN());

        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);

        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, privateKeyParameters);

        String result = null;
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            log.error("SM2解密时出现异常:", e);
        }
        return result;

    }

    /**
     * 加密:返回加密串
     * @param message
     * @return
     */
    public static String encryptionMessage(String message){
        //加密
        String resultPublic = encrypt(staticPublicKey, message);
        return resultPublic;
    }

    /**
     * 解析加密串返回解析内容
     * @param encrypted
     * @return
     */
    public static String analysisMessage(String encrypted){
        //解密
        String resultPrivate = decrypt(staticPrivateKey, encrypted);
        return resultPrivate;
    }


    public static void main(String[] args) {
        //生成公私钥匙对
//        getSM2Key();
        SysUser su = new SysUser();
        su.setUserName("ll123456789");
        su.setPassword("ll123456789");
        su.setCreateTime(DateUtils.getNowDate());
        String message = JSON.toJSONString(su);
        //加密
        String resultPublic = encryptionMessage(message);
        System.out.println("加密结果:" + resultPublic);
        //解密
        String resultPrivate = analysisMessage(resultPublic);
        System.out.println("解密结果:" + resultPrivate);
    }

}

 

        <!--国密-->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.65</version>
        </dependency>