SM2加解密


SM2算法(國密算法)

國密即國家密碼局認定的國產密碼算法。主要有SM1,SM2,SM3,SM4。密鑰長度和分組長度均為128位
一、SM1 為對稱加密。其加密強度與AES相當。該算法不公開,調用該算法時,需要通過加密芯片的接口進行調用。
二、SM2為非對稱加密,基於ECC。該算法已公開。由於該算法基於ECC,故其簽名速度與秘鑰生成速度都快於RSA。ECC 256位(SM2采用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快於RSA。
三、SM3 消息摘要。可以用MD5作為對比理解。該算法已公開。校驗結果為256位。
四、SM4 無線局域網標准的分組數據算法。對稱加密,密鑰長度和分組長度均為128位。

 

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
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 org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECGenParameterSpec;


public class SM2Demo {
    private static String mStr="zym55mmyz";

    public static void main(String[] args) {
        try {
            final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
            // 獲取一個橢圓曲線類型的密鑰對生成器
            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
            // 使用SM2參數初始化生成器
            kpg.initialize(sm2Spec);
            // 獲取密鑰對
            KeyPair keyPair = kpg.generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            String data = encrypt(publicKey,mStr);
            System.out.println("SM2加密:" + data);
            String text = decrypt(privateKey, data);
            System.out.println("SM2解密:" + text);
            byte[] privateKeyEncoded = privateKey.getEncoded();
            /*// 進行Base64編碼
            String privateKeyString = Base64.getEncoder().encodeToString(privateKeyEncoded);

            //Base64.encode(privateKeyEncoded);*/
            String privateKeyStr = "";
            if (privateKey instanceof BCECPrivateKey){
                privateKeyStr = ((BCECPrivateKey)privateKey).getD().toString(16);
            }
            String ret = sm2Decrypt(privateKeyStr, data);
            System.out.println("SM2解密2:" + ret);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * SM2加密算法
     * @param publicKey     公鑰
     * @param data          明文數據
     * @return
     **/
    public static String encrypt(PublicKey publicKey, String data) {
        ECPublicKeyParameters ecPublicKeyParameters = null;
        if (publicKey instanceof BCECPublicKey) {
            BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;
            ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(),ecDomainParameters);
        }
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));

        byte[] arrayOfBytes = null;
        try {
            byte[] in = data.getBytes(StandardCharsets.UTF_8);
            arrayOfBytes = sm2Engine.processBlock(in,0, in.length);
        }
        catch (Exception e) {
            System.out.println("SM2加密時出現異常:");
        }
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * SM2解密算法
     * @param privateKey        私鑰
     * @param cipherData        密文數據
     * @return
     **/
    public static String decrypt(PrivateKey privateKey, String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);
        BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;
        ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());
        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                ecDomainParameters);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, ecPrivateKeyParameters);
        String result = null;
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            return new String(arrayOfBytes, StandardCharsets.UTF_8);
        }
        catch (Exception e) {
            System.out.println("SM2解密時出現異常");
        }
        return result;
    }

    /**
     * SM2解密算法
     * @param key 私鑰
     * @param cipherData 密文數據
     * @return
     */
    public static String sm2Decrypt(String key, String cipherData){
        String result = null;
        try {
            // 加密算法
            String algorithm = "EC";
            //私鑰Hex,還原私鑰
            BigInteger privateKeyD = new BigInteger(key, 16);
            //使用標准名稱創建EC參數生成的參數規范
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            //獲取私鑰的基本域參數
            ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
            ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(privateKeyD,ecParameterSpec);
            //獲取私鑰對象
            BCECPrivateKey bcecPrivateKey = new BCECPrivateKey(algorithm,ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);

            byte[] cipherDataByte = Hex.decode(cipherData);
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
            //通過私鑰值和私鑰基本參數創建私鑰參數對象
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                    ecDomainParameters);
            //通過解密模式創建解密引擎並初始化
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, ecPrivateKeyParameters);
            try {
                byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
                return new String(arrayOfBytes, StandardCharsets.UTF_8);
            }
            catch (Exception e) {
            }
        } catch (Exception e) {
        }
        return result;
    }
}

 參考:https://blog.csdn.net/coolclouds/article/details/130627364


免責聲明!

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



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