环境:
在工作中,前端页面发送的报文可能涉及到用户信息,为确保数据安全,需要对请求的数据加密,采用SM2非对称加密,可以有效解决数据的安全问题。
前端加密,后端解密Demo源码下载地址
https://gitee.com/iroc-git/springboot-encryptreq.git
实现步骤:
第一步:在Maven项目中引入pom依赖
1
2
3
4
5
|
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.67</version> </dependency> |
第二步:生成公钥和私钥
工具类GetPKs
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();
}
}
}
执行后:
private Key :5e3dcfb19758d7829ebce1ee4276f8193951e0cb77040a319403fce5231cab0e Public Key :045417fe9233682d37355d2f64db75fb6ff1146efb68cf409cdd64bb7e31a448047c337b0edd919501f678181a230d91e621029bc64faf7fca3631ac2c869673b9
第三步:在前端页面中对请求数据加密
1.引入crypto-js.js和sm2.js
请在github中下载(https://github.com/Saberization/SM2)
2.对请求报文加密
//sm2公钥var pubkeyHex = "045417fe9233682d37355d2f64db75fb6ff1146efb68cf409cdd64bb7e31a448047c337b0edd919501f678181a230d91e621029bc64faf7fca3631ac2c869673b9";//对请求报文加密jsonReqParams=sm2Encrypt(jsonReqParams, pubkeyHex, 0);
前端页面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>
第四步:后端接收前端的请求报文,并解密
1.在后端引入解密工具类DecryptUtil.java
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.解密前端请求的报文
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();
}
}
转自https://www.cnblogs.com/iroc1994/p/16399496.html