原作者在这
https://www.cnblogs.com/iroc1994/p/16399496.html
感谢原创
此文做记录使用,同时稍作修改,思路正确,内容未核验,有问题请不吝指正,后期会验证不断修改!
环境:
在工作中,前端页面发送的报文可能涉及到用户信息,为确保数据安全,需要对请求的数据加密,采用SM2非对称加密,可以有效解决数据的安全问题。
前端加密,后端解密Demo源码下载地址
https://gitee.com/iroc-git/springboot-encryptreq.git
实现步骤:
第一步:在Maven项目中引入pom依赖,注意依赖的jar包版本要在1.6以上,同时检查是否有bcprov-jdk16.*.的jar包(一般都会有),需要删掉(不放心可以先备份),否则会冲突报错
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.67</version></dependency>
第二步:生成公钥和私钥
工具类GetPKs
packagecom.iroc.springboot.util;importorg.bouncycastle.asn1.gm.GMNamedCurves;importorg.bouncycastle.asn1.x9.X9ECParameters;importorg.bouncycastle.crypto.AsymmetricCipherKeyPair;importorg.bouncycastle.crypto.generators.ECKeyPairGenerator;importorg.bouncycastle.crypto.params.ECDomainParameters;importorg.bouncycastle.crypto.params.ECKeyGenerationParameters;importorg.bouncycastle.crypto.params.ECPrivateKeyParameters;importorg.bouncycastle.crypto.params.ECPublicKeyParameters;importorg.bouncycastle.math.ec.ECPoint;importorg.bouncycastle.util.encoders.Hex;importjava.math.BigInteger;importjava.security.SecureRandom;//获取sm2公钥与私钥publicclassGetPKs{publicstaticvoidmain(String[] args){try{X9ECParameters sm2ECParameters =GMNamedCurves.getByName("sm2p256v1");ECDomainParameters domainParameters =newECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());ECKeyPairGenerator keyPairGenerator =newECKeyPairGenerator();
keyPairGenerator.init(newECKeyGenerationParameters(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();}}}
执行后:
privateKey:5e3dcfb19758d7829ebce1ee4276f8193951e0cb77040a319403fce5231cab0e
PublicKey: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("登录成功");}elseif(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
packagecom.iroc.springboot.util;importorg.apache.tomcat.util.codec.binary.Base64;importorg.bouncycastle.asn1.gm.GMNamedCurves;importorg.bouncycastle.asn1.x9.X9ECParameters;importorg.bouncycastle.crypto.engines.SM2Engine;importorg.bouncycastle.crypto.params.ECDomainParameters;importorg.bouncycastle.crypto.params.ECPrivateKeyParameters;importorg.bouncycastle.util.encoders.Hex;importjava.math.BigInteger;//解密前端页面的请求报文publicclassDecryptUtil{publicstaticStringdecrypt(String cipherData)throwsException{byte[] cipherDataByte =Hex.decode(cipherData);//sm2私钥String privateKey ="5e3dcfb19758d7829ebce1ee4276f8193951e0cb77040a319403fce5231cab0e";BigInteger privateKeyD =newBigInteger(privateKey,16);X9ECParameters sm2ECParameters1 =GMNamedCurves.getByName("sm2p256v1");ECDomainParameters domainParameters1 =newECDomainParameters(sm2ECParameters1.getCurve(), sm2ECParameters1.getG(), sm2ECParameters1.getN());ECPrivateKeyParameters privateKeyParameters =newECPrivateKeyParameters(privateKeyD, domainParameters1);//用私钥解密SM2Engine sm2Engine =newSM2Engine();
sm2Engine.init(false, privateKeyParameters);//processBlock得到Base64格式,记得解码byte[] arrayOfBytes =Base64.decodeBase64(sm2Engine.processBlock(cipherDataByte,0, cipherDataByte.length));//得到明文:SM2 Encryption TestString data =newString(arrayOfBytes);return data;}}
2.解密前端请求的报文
packagecom.iroc.springboot.controller;importcom.google.gson.JsonObject;importcom.google.gson.JsonParser;importcom.iroc.springboot.util.DecryptUtil;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.*;@ControllerpublicclassLoginController{@RequestMapping(value ="/login",method =RequestMethod.POST)@ResponseBodypublicStringlogin(@RequestParam(value ="jsonReqParams")String jsonReqParams){JsonObject result =newJsonObject();//设数据库中username为zhangsan,password为123456try{//解密前端请求的报文
jsonReqParams =DecryptUtil.decrypt(jsonReqParams);JsonObject jsonObject =newJsonParser().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();}}
参考文章
版权归原作者 Xfei0314 所有, 如有侵权,请联系我们删除。