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

三步輕松實現(xiàn)Java的SM2前端加密后端解密

 更新時間:2024年01月30日 10:31:15   作者:秦?zé)o解423  
SM2算法和RSA算法都是公鑰密碼算法,SM2算法是一種更先進安全的算法,在我們國家商用密碼體系中被用來替換RSA算法,這篇文章主要給大家介紹了關(guān)于如何通過三步輕松實現(xiàn)Java的SM2前端加密后端解密的相關(guān)資料,需要的朋友可以參考下

話不多說,先上需要用到的js文件下載鏈接  和  jsp前端代碼。

第一步:下載兩個必備的js文件—— crypto-js.js、sm2.js 。

它們的下載鏈接如下↓(該網(wǎng)頁會很卡,畢竟github,建議卡的話就多重新加載幾次,我差不多試了8次才進去):

https://github.com/Saberization/SM2

進入網(wǎng)頁,下載后拿取下方↓圖片上的兩個js就行:

然后,將這兩js放到存放靜態(tài)資源(static)的目錄下,我放的是static中的sm2目錄(sm2這個目錄是我創(chuàng)的)

后面,在jsp的<head></head>中引入這兩個js文件

<!--jsp引入sm2,實現(xiàn)前端加密-->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/sm2/crypto-js.js" charset="utf-8"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/sm2/sm2.js" charset="utf-8"></script>

第二步:前端jsp代碼實現(xiàn),下方的代碼寫在jsp頁面的<script type="text/javascript"></script>中。

作用是,當(dāng)調(diào)用下方↓函數(shù)的時候,會給你傳入的值進行加密并返回。

注:【你生成的公鑰】的生成方式可以在文章末尾的SM2Utils.java工具類中可以找到,是個main方法,一鍵生成,簡單粗暴

<!--sm2加密函數(shù)-->
function sm2EncryptPwd(data) {
		<!--sm2公鑰-->
		var publicKey = '你生成的公鑰';
		return sm2Encrypt(data, publicKey, 1);
}

至此,前端加密結(jié)束,進入后端解密環(huán)節(jié)——

后端需要的jar包是:bcprov-jdk15on-1.68.jar

注意?。?!該jar包必須要1.60版本以上的,不然解密的時候會缺少必要的條件!?。〔⑶椅矣玫臅r候,本地環(huán)境是JDK1.8的,其他環(huán)境沒試過,建議如有不同,先查一下。

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

第三步:后端代碼實現(xiàn)。

導(dǎo)入jar包后,就是必要的工具類實體類:SM2Utils.java

你可以用工具類本身的加密方法解密,也可以用工具類中我寫的 getJieMiJieGuo() 方法解密。

我個人建議用我寫的,因為操作起來更簡單些,只需要傳入加密后的字符串,就可以返回解密的數(shù)據(jù)。

其中【你生成的公鑰】和【你生成的私鑰】可以通過工具類中的方法生成,生成完復(fù)制粘貼進去就行

注!后端和前端的公鑰要保持一致!因為公鑰私鑰是配對使用的!

package com.test.common.utils;

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

import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;

public class SM2Utils {

    private static final String publicKey = "你生成的公鑰";
    private static final String privateKey = "你生成私鑰";

    /**
     * 解密,并且獲取解密后的字符串
     *
     * @return 秦?zé)o解
     */
    public static String getJieMiJieGuo(String cipherData) {
        byte[] cipherDataByte = Hex.decode(cipherData);
        BigInteger privateKeyD = new BigInteger(privateKey, 16);
        X9ECParameters sm2ECParameters1 = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domainParameters1 = new ECDomainParameters(sm2ECParameters1.getCurve(), sm2ECParameters1.getG(), sm2ECParameters1.getN());
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters1);

        //用私鑰解密,SM2Engine.Mode.C1C3C2得加,不然就會報錯invalid cipher text
        SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
        sm2Engine.init(false, privateKeyParameters);

        //processBlock得到Base64格式,記得解碼
        byte[] arrayOfBytes = null;
        try {
            arrayOfBytes = Base64.decodeBase64(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        //得到明文:SM2 Encryption Test
        return new String(arrayOfBytes);
    }

    /**
     * @Description 生成秘鑰對
     * @Author msx
     * @return KeyPair
     */
    public static KeyPair createECKeyPair() {
        //使用標(biāo)準(zhǔn)名稱創(chuàng)建EC參數(shù)生成的參數(shù)規(guī)范
        final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");

        // 獲取一個橢圓曲線類型的密鑰對生成器
        final KeyPairGenerator kpg;
        try {
            kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
            // 使用SM2算法域參數(shù)集初始化密鑰生成器(默認使用以最高優(yōu)先級安裝的提供者的 SecureRandom 的實現(xiàn)作為隨機源)
            // kpg.initialize(sm2Spec);

            // 使用SM2的算法域參數(shù)集和指定的隨機源初始化密鑰生成器
            kpg.initialize(sm2Spec, new SecureRandom());

            // 通過密鑰生成器生成密鑰對
            return kpg.generateKeyPair();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @Description 公鑰加密
     * @Author msx
     * @param publicKeyHex SM2十六進制公鑰
     * @param data         明文數(shù)據(jù)
     * @return String
     */
    public static String encrypt1(String publicKeyHex, String data) {
        return encrypt(getECPublicKeyByPublicKeyHex(publicKeyHex), data, 1);
    }

    /**
     * @Description 公鑰加密
     * @Author msx
     * @param data         明文數(shù)據(jù)
     * @return String
     */
    public static String encrypt(String data) {
        return encrypt(getECPublicKeyByPublicKeyHex(publicKey), data, 1);
    }

    /**
     * @Description 公鑰加密
     * @Author msx
     * @param publicKey SM2公鑰
     * @param data      明文數(shù)據(jù)
     * @param modeType  加密模式
     * @return String
     */
    public static String encrypt(BCECPublicKey publicKey, String data, int modeType) {
        //加密模式
        SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;
        if (modeType != 1) {
            mode = SM2Engine.Mode.C1C2C3;
        }
        //通過公鑰對象獲取公鑰的基本域參數(shù)。
        ECParameterSpec ecParameterSpec = publicKey.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());
        //通過公鑰值和公鑰基本參數(shù)創(chuàng)建公鑰參數(shù)對象
        ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);
        //根據(jù)加密模式實例化SM2公鑰加密引擎
        SM2Engine sm2Engine = new SM2Engine(mode);
        //初始化加密引擎
        sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
        byte[] arrayOfBytes = null;
        try {
            //將明文字符串轉(zhuǎn)換為指定編碼的字節(jié)串
            byte[] in = data.getBytes("utf-8");
            //通過加密引擎對字節(jié)數(shù)串行加密
            arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
        } catch (Exception e) {
            System.out.println("SM2加密時出現(xiàn)異常:" + e.getMessage());
            e.printStackTrace();
        }
        //將加密后的字節(jié)串轉(zhuǎn)換為十六進制字符串
        return Hex.toHexString(arrayOfBytes);
    }

    /**
     * @Description 私鑰解密
     * @Author msx
     * @param privateKeyHex SM2十六進制私鑰
     * @param cipherData    密文數(shù)據(jù)
     * @return String
     */
    public static String decrypt1(String privateKeyHex, String cipherData) {
        return decrypt(getBCECPrivateKeyByPrivateKeyHex(privateKeyHex), cipherData, 1);
    }

    /**
     * @Description 私鑰解密
     * @Author msx
     * @param s
     * @param cipherData    密文數(shù)據(jù)
     * @return String
     */
    public static String decrypt(String s, String cipherData) {
        return decrypt(getBCECPrivateKeyByPrivateKeyHex(privateKey), cipherData, 1);
    }

    /**
     * @Description 私鑰解密
     * @Author msx
     * @param privateKey SM私鑰
     * @param cipherData 密文數(shù)據(jù)
     * @param modeType   解密模式
     * @return
     */
    public static String decrypt(BCECPrivateKey privateKey, String cipherData, int modeType) {
        //解密模式
        SM2Engine.Mode mode = SM2Engine.Mode.C1C3C2;
        if (modeType != 1) {
            mode = SM2Engine.Mode.C1C2C3;
        }
        //將十六進制字符串密文轉(zhuǎn)換為字節(jié)數(shù)組(需要與加密一致,加密是:加密后的字節(jié)數(shù)組轉(zhuǎn)換為了十六進制字符串)
        byte[] cipherDataByte = Hex.decode(cipherData);
        //通過私鑰對象獲取私鑰的基本域參數(shù)。
        ECParameterSpec ecParameterSpec = privateKey.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                ecParameterSpec.getG(), ecParameterSpec.getN());
        //通過私鑰值和私鑰鑰基本參數(shù)創(chuàng)建私鑰參數(shù)對象
        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(),
                ecDomainParameters);
        //通過解密模式創(chuàng)建解密引擎并初始化
        SM2Engine sm2Engine = new SM2Engine(mode);
        sm2Engine.init(false, ecPrivateKeyParameters);
        String result = null;
        try {
            //通過解密引擎對密文字節(jié)串進行解密
            byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
            //將解密后的字節(jié)串轉(zhuǎn)換為utf8字符編碼的字符串(需要與明文加密時字符串轉(zhuǎn)換成字節(jié)串所指定的字符編碼保持一致)
            result = new String(arrayOfBytes, "utf-8");
        } catch (Exception e) {
            System.out.println("SM2解密時出現(xiàn)異常" + e.getMessage());
        }
        return result;
    }
    //橢圓曲線ECParameters ASN.1 結(jié)構(gòu)
    private static X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
    //橢圓曲線公鑰或私鑰的基本域參數(shù)。
    private static ECParameterSpec ecDomainParameters = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());

    /**
     * @Description 公鑰字符串轉(zhuǎn)換為 BCECPublicKey 公鑰對象
     * @Author msx
     * @param pubKeyHex 64字節(jié)十六進制公鑰字符串(如果公鑰字符串為65字節(jié)首個字節(jié)為0x04:表示該公鑰為非壓縮格式,操作時需要刪除)
     * @return BCECPublicKey SM2公鑰對象
     */
    public static BCECPublicKey getECPublicKeyByPublicKeyHex(String pubKeyHex) {
        //截取64字節(jié)有效的SM2公鑰(如果公鑰首個字節(jié)為0x04)
        if (pubKeyHex.length() > 128) {
            pubKeyHex = pubKeyHex.substring(pubKeyHex.length() - 128);
        }
        //將公鑰拆分為x,y分量(各32字節(jié))
        String stringX = pubKeyHex.substring(0, 64);
        String stringY = pubKeyHex.substring(stringX.length());
        //將公鑰x、y分量轉(zhuǎn)換為BigInteger類型
        BigInteger x = new BigInteger(stringX, 16);
        BigInteger y = new BigInteger(stringY, 16);
        //通過公鑰x、y分量創(chuàng)建橢圓曲線公鑰規(guī)范
        ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(x9ECParameters.getCurve().createPoint(x, y), ecDomainParameters);
        //通過橢圓曲線公鑰規(guī)范,創(chuàng)建出橢圓曲線公鑰對象(可用于SM2加密及驗簽)
        return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION);
    }

    /**
     * @Description 私鑰字符串轉(zhuǎn)換為 BCECPrivateKey 私鑰對象
     * @Author msx
     * @param privateKeyHex 32字節(jié)十六進制私鑰字符串
     * @return BCECPrivateKey SM2私鑰對象
     */
    public static BCECPrivateKey getBCECPrivateKeyByPrivateKeyHex(String privateKeyHex) {
        //將十六進制私鑰字符串轉(zhuǎn)換為BigInteger對象
        BigInteger d = new BigInteger(privateKeyHex, 16);
        //通過私鑰和私鑰域參數(shù)集創(chuàng)建橢圓曲線私鑰規(guī)范
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecDomainParameters);
        //通過橢圓曲線私鑰規(guī)范,創(chuàng)建出橢圓曲線私鑰對象(可用于SM2解密和簽名)
        return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);
    }

    public static void main(String[] args) {
        String publicKeyHex = null;
        String privateKeyHex = null;
        KeyPair keyPair = createECKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        if (publicKey instanceof BCECPublicKey) {
            //獲取65字節(jié)非壓縮縮的十六進制公鑰串(0x04)
            publicKeyHex = Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false));
            System.out.println("---->SM2公鑰:" + publicKeyHex);
        }
        PrivateKey privateKey = keyPair.getPrivate();
        if (privateKey instanceof BCECPrivateKey) {
            //獲取32字節(jié)十六進制私鑰串
            privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16);
            System.out.println("---->SM2私鑰:" + privateKeyHex);
        }

        /**
         * 公鑰加密
         */
        String data = "=========待加密數(shù)據(jù)=========";

        //將十六進制公鑰串轉(zhuǎn)換為 BCECPublicKey 公鑰對象
        String encryptData = encrypt1(publicKeyHex, data);
        System.out.println("---->加密結(jié)果:" + encryptData);

        /**
         * 私鑰解密
         */
        //將十六進制私鑰串轉(zhuǎn)換為 BCECPrivateKey 私鑰對象
        data = decrypt1(privateKeyHex, encryptData);
        System.out.println("---->解密結(jié)果:" + data);
    }
}

最后,在后端接口中調(diào)用工具類的解密方法,就可以對前端傳來的加密數(shù)據(jù)進行解密。

擴展資料:

國密即國家密碼局認定的國產(chǎn)密碼算法。主要有SM1,SM2,SM3,SM4。密鑰長度和分組長度均為128位。

(1)SM1 為對稱加密。其加密強度與AES相當(dāng)。該算法不公開,調(diào)用該算法時,需要通過加密芯片的接口進行調(diào)用。

(2)SM2為非對稱加密,基于ECC。該算法已公開。由于該算法基于ECC,故其簽名速度與秘鑰生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一種)安全強度比RSA 2048位高,但運算速度快于RSA。

(3)SM3 消息摘要??梢杂肕D5作為對比理解。該算法已公開。校驗結(jié)果為256位。

(4)SM4 無線局域網(wǎng)標(biāo)準(zhǔn)的分組數(shù)據(jù)算法。對稱加密,密鑰長度和分組長度均為128位。

至此,??ヽ(°▽°)ノ?撒花。

總結(jié)

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

相關(guān)文章

  • IDE 搭配 Lombok 注解的配置方法

    IDE 搭配 Lombok 注解的配置方法

    Lombok是一個Java庫,通過注解簡化代碼編寫,減少樣板代碼,在使用IDE如IntelliJ IDEA或Eclipse結(jié)合Lombok時,需要先添加Lombok依賴,然后在IDE中配置,以啟用注解處理器,配置完成后,使用Lombok注解來簡化Java類的編寫,本文介紹IDE搭配Lombok注解的配置,感興趣的朋友一起看看吧
    2025-03-03
  • SpringBoot超詳細講解集成Flink的部署與打包方法

    SpringBoot超詳細講解集成Flink的部署與打包方法

    昨天折騰了下SpringBoot與Flink集成,實際上集成特簡單,主要是部署打包的問題折騰了不少時間。想打出的包直接可以java -jar運行,同時也可以flink run運行,或者在flink的dashboard上上傳點擊啟動。結(jié)果是不行,但是使用不同的插件打包還是可以的
    2022-05-05
  • Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題示例

    Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題示例

    這篇文章主要介紹了Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題,涉及java針對數(shù)組的遍歷、計算、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • java?環(huán)境配置(2023年詳細教程)

    java?環(huán)境配置(2023年詳細教程)

    這篇文章首先為了完善我的知識體系,今后一些軟件的安裝教程也可能會用到想寫一個更加詳細的,因為這并不僅僅是寫給?IT?行業(yè)的,其它行業(yè)可能也需要配置java環(huán)境
    2023-06-06
  • SpringBoot日志的使用解讀

    SpringBoot日志的使用解讀

    本文主要介紹了SpringBoot中日志的使用方法,包括默認輸出格式、使用Lombok簡化日志代碼、通過yml和xml配置日志等
    2025-02-02
  • Java管道流實現(xiàn)線程間通信過程解析

    Java管道流實現(xiàn)線程間通信過程解析

    這篇文章主要介紹了Java管道流實現(xiàn)線程間通信過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • Maven setting.xml配置文件詳解

    Maven setting.xml配置文件詳解

    本篇文章主要介紹了Maven setting.xml 配置文件詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Java 和 JavaScript 真正通用的Base64編碼詳解

    Java 和 JavaScript 真正通用的Base64編碼詳解

    這篇文章主要介紹了Java 和 JavaScript 真正通用的Base64編碼詳解的相關(guān)資料,附有Java和Javascript 的Base64編碼,需要的朋友可以參考下
    2016-11-11
  • jconsole使用介紹(圖文)

    jconsole使用介紹(圖文)

    大家在學(xué)習(xí)java的時候,難免會對jvm進行一些深入的了解。推薦大家使用jdk下面的jconsole.exe來輔助理解jvm的一些概念
    2015-12-12
  • 通過Spring AOP實現(xiàn)異常捕捉機制

    通過Spring AOP實現(xiàn)異常捕捉機制

    在開發(fā)過程中,異常處理是一個不可忽視的重要環(huán)節(jié),合理、優(yōu)雅地處理異常不僅能提高代碼的魯棒性,還能提升系統(tǒng)的用戶體驗,本文將介紹如何通過Spring AOP實現(xiàn)一個高效的異常捕捉機制,使得異常處理變得更加優(yōu)雅和統(tǒng)一,需要的朋友可以參考下
    2024-08-08

最新評論

疏附县| 望谟县| 宜君县| 中山市| 哈尔滨市| 延吉市| 河西区| 达拉特旗| 本溪| 获嘉县| 舒兰市| 青浦区| 平邑县| 利津县| 仙桃市| 鹿泉市| 静海县| 昆明市| 伊通| 腾冲县| 南丹县| 巴彦淖尔市| 上虞市| 罗田县| 芷江| 顺义区| 许昌县| 玉林市| 罗田县| 会同县| 新兴县| 昔阳县| 晋江市| 濮阳县| 宜宾县| 仁怀市| 通州区| 霍邱县| 河津市| 普陀区| 加查县|