最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?SM2加密相關(guān)實現(xiàn)與簡單原理詳解

 更新時間:2024年01月26日 11:38:38   作者:LQX_XL  
SM2算法可以用較少的計算能力提供比RSA算法更高的安全強度,而所需的密鑰長度卻遠比RSA算法低,這篇文章主要給大家介紹了關(guān)于Java?SM2加密相關(guān)實現(xiàn)與簡單原理的相關(guān)資料,需要的朋友可以參考下

首先我們應(yīng)該了解SM2加密的主要用途:數(shù)字簽名、密鑰交換和公鑰加密等應(yīng)用。

以下為SM2加密的簡單原理:

  • 密鑰生成:首先,生成一對公鑰和私鑰。公鑰用于加密和驗證簽名,私鑰用于解密和生成簽名。

  • 加密過程:

    • 隨機選擇一個臨時的非零整數(shù)k,計算橢圓曲線點C = k * G,其中G是曲線上的基點。
    • 將明文數(shù)據(jù)轉(zhuǎn)換為橢圓曲線上的點M。
    • 計算橢圓曲線點C1 = k * G。
    • 計算橢圓曲線點S = (h + x) * C1,其中h是哈希值,x是私鑰。
    • 將明文數(shù)據(jù)與S進行異或運算,得到密文C2。
    • 將C1和C2組合在一起作為最終的加密結(jié)果。

解密過程:

  • 使用私鑰x計算橢圓曲線點C1' = x * C1。
  • 從C1'中提取出明文數(shù)據(jù)M'。
  • 將M'與密文C2進行異或運算,得到原始的明文數(shù)據(jù)。

我們要了解對于同一個公鑰和同一個數(shù)據(jù),多次加密的密文是不相同的?。?!

import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.CipherParameters;
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.crypto.signers.SM2Signer;
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.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

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

/**
 * SM2工具類
 * @author van
 */
public class SM2Util {

    /**
     * 生成 SM2 公私鑰對
     *
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     */
    public static KeyPair geneSM2KeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        // 獲取一個橢圓曲線類型的密鑰對生成器
        final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
        // 產(chǎn)生隨機數(shù)
        SecureRandom secureRandom = new SecureRandom();
        // 使用SM2參數(shù)初始化生成器
        kpg.initialize(sm2Spec, secureRandom);
        // 獲取密鑰對
        KeyPair keyPair = kpg.generateKeyPair();
        return keyPair;
    }

    /**
     * 生產(chǎn)hex秘鑰對
     */
    public static void geneSM2HexKeyPair(){
        try {
            KeyPair keyPair = geneSM2KeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            System.out.println("========  EC X Y keyPair    ========");
            System.out.println(privateKey);
            System.out.println(publicKey);
            System.out.println("========  hex keyPair       ========");
            System.out.println("hex priKey: " + getPriKeyHexString(privateKey));
            System.out.println("hex pubKey: " + getPubKeyHexString(publicKey));
            System.out.println("========  base64 keyPair    ========");
            System.out.println("base64 priKey: " + new String(Base64.getEncoder().encode(privateKey.getEncoded())));
            System.out.println("base64 pubKey: " + new String(Base64.getEncoder().encode(publicKey.getEncoded())));
            System.out.println("========  generate finished ========");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 獲取私鑰(16進制字符串,頭部不帶00長度共64)
     *
     * @param privateKey 私鑰PrivateKey型
     * @return
     */
    public static String getPriKeyHexString(PrivateKey privateKey) {
        // OK
//        BCECPrivateKey s=(BCECPrivateKey)privateKey;
//        String priKeyHexString = Hex.toHexString(s.getD().toByteArray());
//        if(null!= priKeyHexString && priKeyHexString.length()==66 && "00".equals(priKeyHexString.substring(0,2))){
//            return priKeyHexString.substring(2);
//        }
        // OK
        BCECPrivateKey key = (BCECPrivateKey) privateKey;
        BigInteger intPrivateKey = key.getD();
        String priKeyHexString = intPrivateKey.toString(16);
        return priKeyHexString;
    }
    /**
     * 獲取私鑰 base64字符串
     *
     * @param privateKey 私鑰PrivateKey型
     * @return
     */
    public static String getPriKeyBase64String(PrivateKey privateKey) {
        return new String(Base64.getEncoder().encode(privateKey.getEncoded()));
    }

    /**
     * 獲取公鑰(16進制字符串,頭部帶04長度共130)
     *
     * @param publicKey 公鑰PublicKey型
     * @return
     */
    public static String getPubKeyHexString(PublicKey publicKey) {
        BCECPublicKey key = (BCECPublicKey) publicKey;
        return Hex.toHexString(key.getQ().getEncoded(false));
    }
    /**
     * 獲取公鑰 base64字符串
     *
     * @param publicKey 公鑰PublicKey型
     * @return
     */
    public static String getPubKeyBase64String(PublicKey publicKey) {
        return new String(Base64.getEncoder().encode(publicKey.getEncoded()));
    }

    /**
     * SM2加密算法
     *
     * @param publicKey 公鑰
     * @param data      明文數(shù)據(jù)
     * @return
     */
    public static String encrypt(String data, PublicKey publicKey) {
        return encrypt(data.getBytes(StandardCharsets.UTF_8), publicKey);
    }

    public static String encrypt(byte[] data, PublicKey publicKey) {
        BCECPublicKey key = (BCECPublicKey) publicKey;
        return encrypt(data, Hex.toHexString(key.getQ().getEncoded(false)));
    }

    public static String encrypt(String data, String pubKeyHexString) {
        return encrypt(data.getBytes(StandardCharsets.UTF_8), pubKeyHexString);
    }

    /**
     * SM2加密算法
     *
     * @param pubKeyHexString 公鑰(16進制字符串)
     * @param data            明文數(shù)據(jù)
     * @return hex字符串
     */
    public static String encrypt(byte[] data, String pubKeyHexString) {
        // 獲取一條SM2曲線參數(shù)
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        // 構(gòu)造ECC算法參數(shù),曲線方程、橢圓曲線G點、大整數(shù)N
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        //提取公鑰點
        ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pubKeyHexString));
        // 公鑰前面的02或者03表示是壓縮公鑰,04表示未壓縮公鑰, 04的時候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);

        SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
        // 設(shè)置sm2為加密模式
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));

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

    }

    /**
     * SM2解密算法
     * @param cipherData    hex格式密文
     * @param privateKey    密鑰PrivateKey型
     * @return              明文
     */
    public static String decrypt(String cipherData, PrivateKey privateKey) {
        return decrypt(Hex.decode(cipherData), privateKey);
    }

    public static String decrypt(byte[] cipherData, PrivateKey privateKey) {
        BCECPrivateKey key = (BCECPrivateKey) privateKey;
        return decrypt(cipherData, Hex.toHexString(key.getD().toByteArray()));
    }

    public static String decrypt(String cipherData, String priKeyHexString) {
        // 使用BC庫加解密時密文以04開頭,傳入的密文前面沒有04則補上
        if (!cipherData.startsWith("04")) {
            cipherData = "04" + cipherData;
        }
        return decrypt(Hex.decode(cipherData), priKeyHexString);
    }

    /**
     * SM2解密算法
     *
     * @param cipherData      密文數(shù)據(jù)
     * @param priKeyHexString 私鑰(16進制字符串)
     * @return
     */
    public static String decrypt(byte[] cipherData, String priKeyHexString) {
        //獲取一條SM2曲線參數(shù)
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //構(gòu)造domain參數(shù)
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());

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

        SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
        // 設(shè)置sm2為解密模式
        sm2Engine.init(false, privateKeyParameters);

        String result = "";
        try {
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherData, 0, cipherData.length);
            return new String(arrayOfBytes);
        } catch (Exception e) {
            System.out.println("SM2解密時出現(xiàn)異常:" + e.getMessage());
        }
        return result;
    }

    /**
     * @param data
     * @param priKeyHexString hex私鑰,長度64
     * @return hex格式簽名值
     * @throws Exception
     */
    public static String sign(String data, String priKeyHexString) throws Exception {
        return sign(data.getBytes(StandardCharsets.UTF_8), priKeyHexString);
    }

    /**
     * 簽名
     * @param data              原始數(shù)據(jù),字節(jié)數(shù)組
     * @param priKeyHexString   hex私鑰,64長度
     * @return                  Hex字符串
     * @throws Exception
     */
    public static String sign(byte[] data, String priKeyHexString) throws Exception {
        String signValue = null;
        SM2Signer signer = new SM2Signer();
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //構(gòu)造domain參數(shù)
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        CipherParameters param = new ParametersWithRandom(new ECPrivateKeyParameters(new BigInteger(priKeyHexString, 16), domainParameters));
        signer.init(true, param);
        signer.update(data, 0, data.length);
        signValue = Hex.toHexString(signer.generateSignature());
        return signValue;
    }

    /**
     * 驗簽
     * @param data                  原始數(shù)據(jù)
     * @param signValue             原始簽名值(hex型)
     * @param publicKeyHexString    hex130長度公鑰
     * @return                      ture or false
     * @throws Exception
     */
    public static boolean verify(String data, String signValue, String publicKeyHexString) throws Exception {
        return verify(data.getBytes(StandardCharsets.UTF_8), Hex.decode(signValue), publicKeyHexString);
    }

    /**
     * 驗簽
     * @param data                  原始數(shù)據(jù)字節(jié)數(shù)組
     * @param sign                  字節(jié)數(shù)組()
     * @param publicKeyHexString    hex130長度公鑰
     * @return                      true or false
     * @throws Exception
     */
    public static boolean verify(byte[] data, byte[] sign, String publicKeyHexString) throws Exception {
        SM2Signer signer = new SM2Signer();
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //構(gòu)造domain參數(shù)
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        if (publicKeyHexString.length() == 128) {
            publicKeyHexString = "04" + publicKeyHexString;
        }
        ECPoint ecPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKeyHexString));
        CipherParameters param = new ECPublicKeyParameters(ecPoint, domainParameters);
        signer.init(false, param);
        signer.update(data, 0, data.length);
        return signer.verifySignature(sign);
    }

    /**
     * 私鑰生成公鑰
     * @param priKeyHexString 私鑰Hex格式,必須64位
     * @return 公鑰Hex格式,04開頭,130位
     * @throws Exception 例如:
     *                   04181db7fe400641115c0dec08e23d8ddb94c5999f2fb6efd03030780142e077a63eb4d47947ef5baee7f40fec2c29181d2a714d9c6cba87b582f252a4e3e9a9f8
     *                   11d0a44d47449d48d614f753ded6b06af76033b9c3a2af2b8b2239374ccbce3a
     */
    public static String getPubKeyByPriKey(String priKeyHexString) throws Exception {
        if (priKeyHexString == null || priKeyHexString.length() != 64) {
            System.err.println("priKey 必須是Hex 64位格式,例如:11d0a44d47449d48d614f753ded6b06af76033b9c3a2af2b8b2239374ccbce3a");
            return "";
        }
        String pubKeyHexString = null;
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        //構(gòu)造domain參數(shù)
        BigInteger privateKeyD = new BigInteger(priKeyHexString, 16);

        ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(privateKeyD, ecParameterSpec);
        PrivateKey privateKey = null;
        privateKey = KeyFactory.getInstance("EC", new BouncyCastleProvider()).generatePrivate(ecPrivateKeySpec);

        // 臨時解決辦法
        String pointString = privateKey.toString();
//        System.out.println(pointString);
        String pointString_X = pointString.substring(pointString.indexOf("X: ") + "X: ".length(), pointString.indexOf("Y: ")).trim();
        String pointString_Y = pointString.substring(pointString.indexOf("Y: ") + "Y: ".length()).trim();
//        System.out.println(pointString_X);
//        System.out.println(pointString_Y);

        pubKeyHexString = "04" + pointString_X + pointString_Y;
        return pubKeyHexString;

    }

    // 將字符串轉(zhuǎn)換為十六進制字符串
    public static String stringToHex(String str) {
        StringBuilder hexString = new StringBuilder();

        for (char ch : str.toCharArray()) {
            hexString.append(Integer.toHexString((int) ch));
        }

        return hexString.toString();
    }

    public static void main(String[] args) throws Exception {
        System.out.println("======  sm2utils test  ======");

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username","jsdxzx");
        jsonObject.put("password","1");
        jsonObject.put("clientId","jsdxzx");
        jsonObject.put("grantType","password_credentials");
        jsonObject.put("passwordEncode",true);
        String jsonString = JSON.toJSONString(jsonObject);

        String M = jsonString;
        System.out.println("mingwen\t" + M);

        System.out.println("begin 開始生成密鑰對>>>");
        KeyPair keyPair = geneSM2KeyPair();

        PublicKey publicKey = keyPair.getPublic();
        String pubKeyHexString = getPubKeyHexString(publicKey);
        System.out.println("publicKey\t" + pubKeyHexString);

        PrivateKey privateKey = keyPair.getPrivate();
        String priKeyHexString = getPriKeyHexString(privateKey);
        System.out.println("privateKey\t" + priKeyHexString);
        System.out.println("end   結(jié)束生成密鑰對>>>");

        priKeyHexString="4f0341e5977b175e0ec0e1fdefd2799b13dd25c51716133ef42ba76c0edd973d"; //1
        pubKeyHexString="04e523210b3407464839723558e0d82765b9e2cac9491bd86c99c89b9fc43fbe9a94395ee3138dbc4ae43daa8fe01fd512de8568102e34c66989eb2b306611b518"; //1
        System.out.println("publicKey\t" + pubKeyHexString);

        String cipherData = encrypt(M, pubKeyHexString);
        System.out.println("miwen\t" + cipherData);

        String text = decrypt(cipherData, priKeyHexString);
        System.out.println("jiemi\t" + text);

        String sign = sign(M, priKeyHexString);
        System.out.println("signvalue\t" + sign);
        sign="304402204bbd4b026f58f1e072c2ab1f736a730ed5c2f6773ef4855df5e87f9ea54f14be02205e9b6146b5273e6f37fe6d9d8f059bc46f7042a10da224130a4e0ba8619d967c";

        boolean verifyResult = verify(M, sign, pubKeyHexString);
        System.out.println("verifyResult\t" + verifyResult);

    }
}

總結(jié) 

到此這篇關(guān)于Java SM2加密相關(guān)實現(xiàn)與簡單原理的文章就介紹到這了,更多相關(guān)Java SM2加密實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中BigDecimal與0比較的一個坑實戰(zhàn)記錄

    Java中BigDecimal與0比較的一個坑實戰(zhàn)記錄

    BigDecimal屬于大數(shù)據(jù),精度極高,不屬于基本數(shù)據(jù)類型,屬于java對象,下面這篇文章主要給大家介紹了關(guān)于Java中BigDecimal與0比較的一個坑的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Java文件目錄下載并打包成ZIP壓縮包

    Java文件目錄下載并打包成ZIP壓縮包

    這篇文章主要介紹了在Java中如何實現(xiàn)文件夾、文件目錄的遞歸下載并打包成ZIP壓縮包,文中的示例代碼講解詳細,有需要的可以參考下
    2024-10-10
  • Java按順序提取Word內(nèi)容的方法步驟(文本+數(shù)學(xué)公式)

    Java按順序提取Word內(nèi)容的方法步驟(文本+數(shù)學(xué)公式)

    本文分享通過Java POI庫解析Word試卷內(nèi)容,將數(shù)學(xué)公式轉(zhuǎn)換為LaTeX并保持原有順序的方法,涉及XML文本提取、節(jié)點替換及文檔重構(gòu),解決公式位置錯亂問題,實現(xiàn)非結(jié)構(gòu)化到結(jié)構(gòu)化轉(zhuǎn)換,需要的朋友可以參考下
    2025-09-09
  • Java數(shù)組的運用詳解

    Java數(shù)組的運用詳解

    這篇文章主要給大家介紹了關(guān)于Java中數(shù)組的定義和使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • 解讀Spring配置文件中的property標簽中的屬性

    解讀Spring配置文件中的property標簽中的屬性

    這篇文章主要介紹了Spring配置文件中的property標簽中的屬性,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • springboot創(chuàng)建多module項目的實例

    springboot創(chuàng)建多module項目的實例

    這篇文章主要介紹了springboot創(chuàng)建多module項目的實例代碼,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 剖析SpringCloud Feign中所隱藏的坑

    剖析SpringCloud Feign中所隱藏的坑

    這篇文章主要為大家介紹了剖析SpringCloud Feign中所隱藏的坑示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 一篇文章帶你使用SpringBoot基于WebSocket的在線群聊實現(xiàn)

    一篇文章帶你使用SpringBoot基于WebSocket的在線群聊實現(xiàn)

    這篇文章主要介紹了一篇文章帶你使用SpringBoot基于WebSocket的在線群聊實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 一文弄懂java中POJO和bean區(qū)別

    一文弄懂java中POJO和bean區(qū)別

    本文主要介紹了一文弄懂java中POJO和bean區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-10-10
  • 通過Java計算文件的MD5值實現(xiàn)方式

    通過Java計算文件的MD5值實現(xiàn)方式

    本文將詳細介紹如何使用Java語言來計算文件的MD5值,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04

最新評論

赣榆县| 峨边| 吉木乃县| 策勒县| 绥中县| 庄河市| 崇仁县| 封开县| 合水县| 乐亭县| 温泉县| 叙永县| 宝应县| 汾阳市| 金昌市| 静宁县| 武山县| 三亚市| 波密县| 新源县| 上犹县| 莆田市| 深州市| 揭阳市| 安泽县| 民勤县| 包头市| 宁陕县| 金乡县| 高清| 佛山市| 阜新| 昌乐县| 呼和浩特市| 新和县| 宜宾市| 颍上县| 商城县| 泾阳县| 沙田区| 靖宇县|