SM2 implements front-end sending encrypted messages and back-end decrypting messages.

The original author https://www.cnblogs.com/iroc1994/p/16399496.htmlwould like to thank the original author
for the record and use of this article. At the same time, he has made slight modifications. The idea is correct. The content has not been verified. If there are any questions, please feel free to correct them. It will be verified and modified later!
environment:

At work, the messages sent by the front-end page may involve user information. To ensure data security, the requested data needs to be encrypted. Using SM2 asymmetric encryption can effectively solve the data security problem.

Front-end encryption, back-end decryption Demo source code download address

https://gitee.com/iroc-git/springboot-encryptreq.git

Implementation steps:

Step 1: Introduce pom dependencies into the Maven project. Note that the dependent jar package version must be above 1.6. Also check whether there is a bcprov-jdk16.*. jar package (usually there will be), which needs to be deleted (if you are not worried, you can first Backup), otherwise conflicts and errors will be reported

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

Step 2: Generate public and private keys

ToolsGetPKs

package com.iroc.springboot.util;

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

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

//获取sm2公钥与私钥
public class GetPKs
{
    
    
    public static void main(String[] args)
    {
    
    
        try
        {
    
    
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
            ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();

            //上面的代码都是直接用maven依赖中的包直接import就可以用了
            //还有一些更底层的写法,可以自己搜索一下,图方便的这个挺好的

            //私钥,16进制格式,自己保存
            BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
            String privateKeyHex = privatekey.toString(16);
            System.out.println("private Key :" + privateKeyHex);

            //公钥,16进制格式,发给前端
            ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
            String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
            System.out.println("Public Key :" + publicKeyHex);
        } catch (Exception e)
        {
    
    
            e.printStackTrace();
        }
    }

}

After execution:


private Key :5e3dcfb19758d7829ebce1ee4276f8193951e0cb77040a319403fce5231cab0e
Public Key :045417fe9233682d37355d2f64db75fb6ff1146efb68cf409cdd64bb7e31a448047c337b0edd919501f678181a230d91e621029bc64faf7fca3631ac2c869673b9

Step 3: Encrypt the request data in the front-end page

1.Introduce crypto-js.js and sm2.js

Please download these two files from github (https://github.com/Saberization/SM2)
and put them in the corresponding locations of the project
Insert image description here2. Encrypt the request message

//sm2公钥
var pubkeyHex = "045417fe9233682d37355d2f64db75fb6ff1146efb68cf409cdd64bb7e31a448047c337b0edd919501f678181a230d91e621029bc64faf7fca3631ac2c869673b9";
//对请求报文加密
jsonReqParams=sm2Encrypt(jsonReqParams, pubkeyHex, 0);

The complete code of the front-end page login.html

<!DOCTYPE html>

<head>
    <meta charset="utf-8" />
    <script src="../js/crypto-js.js"></script>
    <script src="../js/sm2.js"></script>
    <script src="../js/jquery-3.4.1.min.js"></script>
    <script>

        $(document).ready(function () {
    
    
            $("#submit").click(function () {
    
    
                var username = $("#username").val();
                var password = $("#password").val();
                var jsonReqParams = {
    
    

                };
                jsonReqParams.username=username;
                jsonReqParams.password=password;
                jsonReqParams=JSON.stringify(jsonReqParams);
                //sm2公钥
                var pubkeyHex = "045417fe9233682d37355d2f64db75fb6ff1146efb68cf409cdd64bb7e31a448047c337b0edd919501f678181a230d91e621029bc64faf7fca3631ac2c869673b9";
                //对请求报文加密
                jsonReqParams=sm2Encrypt(jsonReqParams, pubkeyHex, 0);
                //发送请求到后端
                $.ajax({
    
    
                    type: 'POST', //方法类型
                    dataType: 'json', //预期服务器返回的数据类型
                    url: '/login', //请求地址
                    data: {
    
     'jsonReqParams': jsonReqParams },
                    contentType: 'application/x-www-form-urlencoded; charset=utf-8',
                    success: function (data) {
    
    
                        if(data.code == "1001"){
    
    
                            $("#result").html("登录成功");
                        }else if(data.code== "1002"){
    
    
                            $("#result").html("登录失败");
                        }else{
    
    
                            $("#result").html("出现异常,请联系管理员");
                        }
                    },
                    error: function () {
    
    
                        $("#result").html("出现异常,请联系管理员");
                    },
                });
            });
        });

    </script>
</head>

<body>

    用户名:<input type="text" id="username" /><br />
    密码:<input type="password" id="password" /><br />
    <button id="submit">登录</button><br />
    <span id="result"></span>

</body>

Step 4: The backend receives the request message from the frontend and decrypts it

1.Introduce the decryption tool class DecryptUtil.java in the backend

package com.iroc.springboot.util;

import org.apache.tomcat.util.codec.binary.Base64;
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.util.encoders.Hex;

import java.math.BigInteger;

//解密前端页面的请求报文
public class DecryptUtil
{
    
    
    public static String decrypt(String cipherData) throws Exception{
    
    
        byte[] cipherDataByte = Hex.decode(cipherData);

        //sm2私钥
        String privateKey = "5e3dcfb19758d7829ebce1ee4276f8193951e0cb77040a319403fce5231cab0e";
        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 sm2Engine = new SM2Engine();
        sm2Engine.init(false, privateKeyParameters);

        //processBlock得到Base64格式,记得解码
        byte[] arrayOfBytes = Base64.decodeBase64(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));

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

2. Decrypt the message requested by the front end

package com.iroc.springboot.controller;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.iroc.springboot.util.DecryptUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
public class LoginController
{
    
    

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    @ResponseBody
    public String login(@RequestParam(value = "jsonReqParams") String jsonReqParams){
    
    
        JsonObject result = new JsonObject();
        //设数据库中username为zhangsan,password为123456
        try
        {
    
    
            //解密前端请求的报文
            jsonReqParams = DecryptUtil.decrypt(jsonReqParams);
            JsonObject jsonObject = new JsonParser().parse(jsonReqParams).getAsJsonObject();
            String username = jsonObject.get("username").getAsString();
            String password = jsonObject.get("password").getAsString();
            if("zhangsan".equals(username)&&"123456".equals(password)){
    
    
                result.addProperty("code","1001");
                result.addProperty("desc","登录成功");
            }else {
    
    
                result.addProperty("code","1002");
                result.addProperty("desc","账号或密码有误");
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
            result.addProperty("code","1003");
            result.addProperty("desc","出现异常,请联系管理员");
        }

        return result.toString();
    }

}

Reference article

  1. https://blog.csdn.net/python_small_pan/article/details/120064529

  2. https://github.com/Saberization/SM2

  3. https://blog.51cto.com/boytnt/2503384

Guess you like

Origin blog.csdn.net/m0_46364149/article/details/125885586