Browse Source

前端加密修改为sm2和sm4

ai_dev
zhouhaibin 5 months ago
parent
commit
e94375a587
  1. 9
      .env.development
  2. 6
      .env.production
  3. 3
      package.json
  4. 91
      src/utils/encryption/crypto.ts
  5. 64
      src/utils/encryption/jsencrypt.ts
  6. 14
      src/utils/http/axios/index.ts

9
.env.development

@ -8,9 +8,14 @@ VITE_GLOB_API_URL=/basic-api
VITE_GLOB_ENABLE_ENCRYPT=true VITE_GLOB_ENABLE_ENCRYPT=true
# VITE_APP_ENCRYPT=true # VITE_APP_ENCRYPT=true
# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对 # RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== # VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
VITE_GLOB_RSA_PUBLIC_KEY=04236db2b9ce493053523b486590c435da3a957a7b25adde32f1bb42a5e7c4675c28ca3cf556b4e9014e220cb5faaf5f309950c9e172f0886674df23cc70bd4d76
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对 # RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= # VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
VITE_GLOB_RSA_PRIVATE_KEY=00ac220685ceb41f06153a459c43248695f9f81188f5835c1e6f40abb1a748ab2c
# 客户端id # 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e

6
.env.production

@ -15,10 +15,12 @@ VITE_GLOB_API_URL=/prod-api
VITE_GLOB_ENABLE_ENCRYPT=true VITE_GLOB_ENABLE_ENCRYPT=true
# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对 # RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== # VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
VITE_GLOB_RSA_PUBLIC_KEY=VITE_GLOB_RSA_PUBLIC_KEY=04236db2b9ce493053523b486590c435da3a957a7b25adde32f1bb42a5e7c4675c28ca3cf556b4e9014e220cb5faaf5f309950c9e172f0886674df23cc70bd4d76
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对 # RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= # VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
VITE_GLOB_RSA_PRIVATE_KEY=00ac220685ceb41f06153a459c43248695f9f81188f5835c1e6f40abb1a748ab2c
# 客户端id # 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e

3
package.json

@ -118,7 +118,8 @@
"vxe-table": "4.6.17", "vxe-table": "4.6.17",
"vxe-table-plugin-export-xlsx": "4.0.1", "vxe-table-plugin-export-xlsx": "4.0.1",
"xe-utils": "3.5.25", "xe-utils": "3.5.25",
"xlsx": "0.18.5" "xlsx": "0.18.5",
"sm-crypto":"0.3.13"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "19.3.0", "@commitlint/cli": "19.3.0",

91
src/utils/encryption/crypto.ts

@ -1,8 +1,9 @@
import CryptoJS from 'crypto-js'; import CryptoJS from 'crypto-js';
import {sm4} from 'sm-crypto'
function randomUUID() { function randomUUID() {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
const uuid = new Array(36); const uuid = new Array(32);
let rnd = 0; let rnd = 0;
let r: number; let r: number;
for (let i = 0; i < 36; i++) { for (let i = 0; i < 36; i++) {
@ -20,12 +21,68 @@ function randomUUID() {
return uuid.join('').replace(/-/gm, '').toLowerCase(); return uuid.join('').replace(/-/gm, '').toLowerCase();
} }
// /**
// * 随机生成aes 密钥
// * @returns
// */
// export function generateAesKey() {
// return CryptoJS.enc.Utf8.parse(randomUUID());
// }
// /**
// * base64编码
// * @param str
// * @returns
// */
// export function encryptBase64(str: CryptoJS.lib.WordArray) {
// return CryptoJS.enc.Base64.stringify(str);
// }
// /**
// * 使用公钥加密
// * @param message 加密内容
// * @param aesKey aesKey
// * @returns
// */
// export function encryptWithAes(message: string, aesKey: CryptoJS.lib.WordArray) {
// const encrypted = CryptoJS.AES.encrypt(message, aesKey, {
// mode: CryptoJS.mode.ECB,
// padding: CryptoJS.pad.Pkcs7,
// });
// return encrypted.toString();
// }
// /**
// * 解密base64
// */
// export function decryptBase64(str: string) {
// return CryptoJS.enc.Base64.parse(str);
// }
// /**
// * 使用密钥对数据进行解密
// */
// export function decryptWithAes(message: string, aesKey: CryptoJS.lib.WordArray) {
// const decrypted = CryptoJS.AES.decrypt(message, aesKey, {
// mode: CryptoJS.mode.ECB,
// padding: CryptoJS.pad.Pkcs7,
// });
// return decrypted.toString(CryptoJS.enc.Utf8);
// }
/** /**
* aes * aes
* @returns * @returns
*/ */
export function generateAesKey() { export function generateSM4Key() {
return CryptoJS.enc.Utf8.parse(randomUUID()); // return CryptoJS.enc.Utf8.parse(randomUUID());
//获取前16位作为密钥
return randomUUID();
} }
/** /**
@ -33,7 +90,7 @@ export function generateAesKey() {
* @param str * @param str
* @returns * @returns
*/ */
export function encryptBase64(str: CryptoJS.lib.WordArray) { export function encryptBase64(str) {
return CryptoJS.enc.Base64.stringify(str); return CryptoJS.enc.Base64.stringify(str);
} }
@ -43,12 +100,13 @@ export function encryptBase64(str: CryptoJS.lib.WordArray) {
* @param aesKey aesKey * @param aesKey aesKey
* @returns * @returns
*/ */
export function encryptWithAes(message: string, aesKey: CryptoJS.lib.WordArray) { export function encryptWithAes(message: string, aesKey) {
const encrypted = CryptoJS.AES.encrypt(message, aesKey, { // const encrypted = CryptoJS.AES.encrypt(message, aesKey, {
mode: CryptoJS.mode.ECB, // mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7, // padding: CryptoJS.pad.Pkcs7,
}); // });
return encrypted.toString(); // return encrypted.toString();
return sm4.encrypt(message, aesKey)
} }
/** /**
@ -61,10 +119,11 @@ export function decryptBase64(str: string) {
/** /**
* 使 * 使
*/ */
export function decryptWithAes(message: string, aesKey: CryptoJS.lib.WordArray) { export function decryptWithAes(message: string, aesKey) {
const decrypted = CryptoJS.AES.decrypt(message, aesKey, { // const decrypted = CryptoJS.AES.decrypt(message, aesKey, {
mode: CryptoJS.mode.ECB, // mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7, // padding: CryptoJS.pad.Pkcs7,
}); // });
return decrypted.toString(CryptoJS.enc.Utf8); // return decrypted.toString(CryptoJS.enc.Utf8);
return sm4.decrypt(message, aesKey)
} }

64
src/utils/encryption/jsencrypt.ts

@ -2,6 +2,7 @@ import JSEncrypt from 'jsencrypt';
// 密钥对生成 http://web.chacuo.net/netrsakeypair // 密钥对生成 http://web.chacuo.net/netrsakeypair
import { useGlobSetting } from '@/hooks/setting'; import { useGlobSetting } from '@/hooks/setting';
import {sm2} from 'sm-crypto'
const globSetting = useGlobSetting(); const globSetting = useGlobSetting();
const publicKey = globSetting.rsaPublicKey; const publicKey = globSetting.rsaPublicKey;
@ -9,24 +10,59 @@ const publicKey = globSetting.rsaPublicKey;
/** ??? 意义何在 */ /** ??? 意义何在 */
const privateKey = globSetting.rsaPrivateKey; const privateKey = globSetting.rsaPrivateKey;
// /**
// * RSA加密
// * @param txt 需要加密的数据
// * @returns
// */
// export function encrypt(txt: string) {
// const instance = new JSEncrypt();
// instance.setPublicKey(publicKey);
// return instance.encrypt(txt);
// }
// /**
// * RSA解密
// * @param txt 需要解密的数据
// * @returns
// */
// export function decrypt(txt: string) {
// const instance = new JSEncrypt();
// instance.setPrivateKey(privateKey);
// return instance.decrypt(txt);
// }
/** /**
* * SM2公钥加密
* @param txt * @param message
* @returns * @param publicKey (04)
* @returns
*/ */
export function encrypt(txt: string) { export function encrypt(message: string) {
const instance = new JSEncrypt(); try {
instance.setPublicKey(publicKey); const cipherData = sm2.doEncrypt(message, publicKey,1);
return instance.encrypt(txt);
return cipherData;
} catch (error) {
throw new Error('SM2加密失败: ' + error.message);
}
} }
/** /**
* * SM2私钥解密
* @param txt * @param ciphertext
* @returns * @param privateKey
* @returns
*/ */
export function decrypt(txt: string) { export function decrypt(ciphertext: string) {
const instance = new JSEncrypt(); try {
instance.setPrivateKey(privateKey); //去掉密文的开头的04
return instance.decrypt(txt); const ciphertextHex = ciphertext.slice(2);
const decrypted = sm2.doDecrypt(ciphertextHex, privateKey,1);
return decrypted;
} catch (error) {
throw new Error('SM2解密失败: ' + error.message);
}
} }

14
src/utils/http/axios/index.ts

@ -20,7 +20,7 @@ import { useUserStoreWithOut } from '@/store/modules/user';
import { AxiosRetry } from '@/utils/http/axios/axiosRetry'; import { AxiosRetry } from '@/utils/http/axios/axiosRetry';
import axios from 'axios'; import axios from 'axios';
import { import {
generateAesKey, generateSM4Key,
encryptBase64, encryptBase64,
encryptWithAes, encryptWithAes,
decryptBase64, decryptBase64,
@ -29,6 +29,7 @@ import {
import * as encryptUtil from '@/utils/encryption/jsencrypt'; import * as encryptUtil from '@/utils/encryption/jsencrypt';
import { axiosCanceler } from './axiosCancel'; import { axiosCanceler } from './axiosCancel';
import { useLocaleStoreWithOut } from '@/store/modules/locale'; import { useLocaleStoreWithOut } from '@/store/modules/locale';
import CryptoJS from 'crypto-js';
const globSetting = useGlobSetting(); const globSetting = useGlobSetting();
const localeStore = useLocaleStoreWithOut(); const localeStore = useLocaleStoreWithOut();
@ -50,8 +51,10 @@ const transform: AxiosTransform = {
const base64Str = encryptUtil.decrypt(encryptKey); const base64Str = encryptUtil.decrypt(encryptKey);
/** base64 解码 得到请求头的 AES 秘钥 */ /** base64 解码 得到请求头的 AES 秘钥 */
const aesSecret = decryptBase64(base64Str.toString()); const aesSecret = decryptBase64(base64Str.toString());
// aesSecret此时为数组,需要变成字符串
const asciiStr=CryptoJS.enc.Utf8.stringify(aesSecret)
/** 使用aesKey解密 responseData */ /** 使用aesKey解密 responseData */
const decryptData = decryptWithAes(res.data as unknown as string, aesSecret); const decryptData = decryptWithAes(res.data as unknown as string, asciiStr);
/** 赋值 需要转为对象 */ /** 赋值 需要转为对象 */
res.data = JSON.parse(decryptData); res.data = JSON.parse(decryptData);
} }
@ -206,8 +209,11 @@ const transform: AxiosTransform = {
encrypt && encrypt &&
['POST', 'PUT'].includes(config.method?.toUpperCase() || '') ['POST', 'PUT'].includes(config.method?.toUpperCase() || '')
) { ) {
const aesKey = generateAesKey(); const aesKey = generateSM4Key();
config.headers['encrypt-key'] = encryptUtil.encrypt(encryptBase64(aesKey)); // askey此时为字符串需要变成数组,去base64编码。与后端对应
const asciiStr=CryptoJS.enc.Utf8.parse(aesKey)
// config.headers['encrypt-key'] = encryptUtil.encrypt(encryptBase64(aesKey));
config.headers['encrypt-key'] = encryptUtil.encrypt(encryptBase64(asciiStr));
if (typeof config.data === 'object') { if (typeof config.data === 'object') {
config.data = encryptWithAes(JSON.stringify(config.data), aesKey); config.data = encryptWithAes(JSON.stringify(config.data), aesKey);

Loading…
Cancel
Save