Vue+Springboot 前后端完整使?國密算法SM2雙公私鑰對數(shù)據(jù)加密傳輸交互完整解決?案項(xiàng)?,特別是企事業(yè)單位的項(xiàng)?,第三方測試公司做安全測試時(shí),常常要求使用國密算法,因涉及服務(wù)端和客戶端的交互,傳遞關(guān)鍵數(shù)據(jù)時(shí)要求使用SM2非對稱加密。
引入相關(guān)依賴
這里我使用的是jdk1.8 的maven項(xiàng)目,需要在pom.xml里引入以下依賴:
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.22</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version> </dependency>
?可復(fù)用代碼
import cn.hutool.core.util.HexUtil; import cn.hutool.crypto.BCUtil; import cn.hutool.crypto.asymmetric.SM2; import lombok.extern.slf4j.Slf4j; 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.math.ec.ECPoint; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; @Slf4j public class SM2Utils { static final BouncyCastleProvider bc = new BouncyCastleProvider(); public static Map<String,Object> generateKey(){ Map<String,Object> map = new HashMap<>(); SM2 sm2=new SM2(); BCECPrivateKey privateKey = (BCECPrivateKey) (sm2.getPrivateKey()); BigInteger d = privateKey.getD(); BCECPublicKey publicKey = (BCECPublicKey) sm2.getPublicKey(); ECPoint q = publicKey.getQ(); String hutoolPrivateKeyHex = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(privateKey)); String hutoolPublicKeyHex = HexUtil.encodeHexStr(q.getEncoded(false)); map.put("publicKeyHex",hutoolPublicKeyHex); map.put("privateKeyHex",hutoolPrivateKeyHex); return map; } }
服務(wù)端在登錄校驗(yàn)成功后生成服務(wù)端公私鑰對,并把改公私鑰對存放到session中,便于下次會(huì)話提取,同時(shí)將公鑰字符串返回給客戶端:?
//生成服務(wù)器公私鑰對,并將服務(wù)器公私鑰放入session Map<String,Object> mapKey = SM2Utils.generateKey(); session.setAttribute("publicKeyHex",mapKey.get("publicKeyHex").toString()); session.setAttribute("privateKeyHex",mapKey.get("privateKeyHex").toString()); //公鑰和正常消息一起返回給客戶端 map.put("publicKeyHex", mapKey.get("publicKeyHex").toString());
客戶端收到服務(wù)端給出的公鑰后,存入localStorage,并生成客戶端公私鑰對,存入localStorage,并用接收到的服務(wù)端公鑰加密客戶端公私鑰對,將加密后的密文發(fā)給服務(wù)端
npm install --save sm-crypto
const sm2 = require('sm-crypto').sm2
//生成客戶端公私鑰
const { publicKey, privateKey } = sm2.generateKeyPairHex()
window.localStorage.setItem("publicKey", publicKey)
window.localStorage.setItem("privateKey", privateKey)
//獲取服務(wù)器端公鑰
let serverPublicKey = res.spk
window.localStorage.setItem("serverPublicKey", serverPublicKey)
//加密客戶端公私鑰
encryptpublickeyClient = sm2.doEncrypt(publicKey, serverPublicKey,cipherMode);
encryptpublickeyClient = '04' + encryptpublickeyClient;
encryptprivatekeyClient = sm2.doEncrypt(privateKey, serverPublicKey,cipherMode);
encryptprivatekeyClient = '04' + encryptprivatekeyClient;
?服務(wù)端在二次接收客戶端請求時(shí),從參數(shù)中獲取加密后的客戶端公私鑰對密文,使用服務(wù)端秘鑰解密后,將客戶端公私鑰對存入會(huì)話,并在服務(wù)器生成隨機(jī)數(shù),用客戶端公鑰加密后返回?cái)?shù)據(jù)給前端:
String publicKeyHex = session.getAttribute("publicKeyHex").toString(); String privateKeyHex = session.getAttribute("privateKeyHex").toString(); //privateKey 為上述生成的私鑰 publicKey為生成的公鑰,注意 此處不是Q值 SM2 sm2 = SmUtil.sm2(privateKeyHex, publicKeyHex); //body為加密后的數(shù)據(jù)(注意:此處加密數(shù)據(jù)可能缺少04開頭,解密會(huì)失敗,需要手動(dòng)在body前拼上04,body="04"+body) String clientPublicKeyStr = sm2.decryptStr(userDTO.getClientPublicKey(), KeyType.PrivateKey); String clientPrivateKeyStr = sm2.decryptStr(userDTO.getClientPrivateKey(), KeyType.PrivateKey); SM2 sm2Client = SmUtil.sm2(clientPrivateKeyStr, clientPublicKeyStr); String uid = UUID.randomUUID().toString().replaceAll("-",""); String uidEncode = sm2Client.encryptHex(uid,KeyType.PublicKey); map.put("uid", uidEncode);
客戶端接收到服務(wù)端的uid密文后,使用客戶端私鑰解密,并存入localStorage中
let uidEcrpyptCode = res.uid;
let headerStr = uidEcrpyptCode.substring(0, 2)? ? ? ? ? ? ? ? ?
if(headerStr == '04'){
? ? ? ?uidEcrpyptCode = uidEcrpyptCode.substring(2, uidEcrpyptCode.length)
?}
//解密uid
let uidStr = sm2.doDecrypt(uidEcrpyptCode, '00'+privateKey)
window.localStorage.setItem("uid", uidStr);文章來源:http://www.zghlxwxcb.cn/news/detail-817899.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-817899.html
到了這里,關(guān)于Vue+Springboot前后端完整使用國密算法SM2雙公私鑰對數(shù)據(jù)加密傳輸交互完整解決方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!