diff --git a/.env.development b/.env.development index 2fe5cda..e7952cd 100644 --- a/.env.development +++ b/.env.development @@ -8,9 +8,14 @@ VITE_GLOB_API_URL=/basic-api VITE_GLOB_ENABLE_ENCRYPT=true # VITE_APP_ENCRYPT=true # 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公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对 -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 VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e diff --git a/.env.production b/.env.production index f310b61..29aad10 100644 --- a/.env.production +++ b/.env.production @@ -15,10 +15,12 @@ VITE_GLOB_API_URL=/prod-api VITE_GLOB_ENABLE_ENCRYPT=true # 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公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对 -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 VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e diff --git a/package.json b/package.json index d810bb0..b905e01 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,8 @@ "vxe-table": "4.6.17", "vxe-table-plugin-export-xlsx": "4.0.1", "xe-utils": "3.5.25", - "xlsx": "0.18.5" + "xlsx": "0.18.5", + "sm-crypto":"0.3.13" }, "devDependencies": { "@commitlint/cli": "19.3.0", diff --git a/src/utils/encryption/crypto.ts b/src/utils/encryption/crypto.ts index 91ffa60..480700c 100644 --- a/src/utils/encryption/crypto.ts +++ b/src/utils/encryption/crypto.ts @@ -1,8 +1,9 @@ import CryptoJS from 'crypto-js'; +import {sm4} from 'sm-crypto' function randomUUID() { const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); - const uuid = new Array(36); + const uuid = new Array(32); let rnd = 0; let r: number; for (let i = 0; i < 36; i++) { @@ -20,12 +21,68 @@ function randomUUID() { 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 密钥 * @returns */ -export function generateAesKey() { - return CryptoJS.enc.Utf8.parse(randomUUID()); +export function generateSM4Key() { + // return CryptoJS.enc.Utf8.parse(randomUUID()); + //获取前16位作为密钥 + return randomUUID(); } /** @@ -33,7 +90,7 @@ export function generateAesKey() { * @param str * @returns */ -export function encryptBase64(str: CryptoJS.lib.WordArray) { +export function encryptBase64(str) { return CryptoJS.enc.Base64.stringify(str); } @@ -43,12 +100,13 @@ export function encryptBase64(str: CryptoJS.lib.WordArray) { * @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(); +export function encryptWithAes(message: string, aesKey) { + // const encrypted = CryptoJS.AES.encrypt(message, aesKey, { + // mode: CryptoJS.mode.ECB, + // padding: CryptoJS.pad.Pkcs7, + // }); + // 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) { - const decrypted = CryptoJS.AES.decrypt(message, aesKey, { - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7, - }); - return decrypted.toString(CryptoJS.enc.Utf8); +export function decryptWithAes(message: string, aesKey) { + // const decrypted = CryptoJS.AES.decrypt(message, aesKey, { + // mode: CryptoJS.mode.ECB, + // padding: CryptoJS.pad.Pkcs7, + // }); + // return decrypted.toString(CryptoJS.enc.Utf8); + return sm4.decrypt(message, aesKey) } diff --git a/src/utils/encryption/jsencrypt.ts b/src/utils/encryption/jsencrypt.ts index 6bf6cd2..6155756 100644 --- a/src/utils/encryption/jsencrypt.ts +++ b/src/utils/encryption/jsencrypt.ts @@ -2,6 +2,7 @@ import JSEncrypt from 'jsencrypt'; // 密钥对生成 http://web.chacuo.net/netrsakeypair import { useGlobSetting } from '@/hooks/setting'; +import {sm2} from 'sm-crypto' const globSetting = useGlobSetting(); const publicKey = globSetting.rsaPublicKey; @@ -9,24 +10,59 @@ const publicKey = globSetting.rsaPublicKey; /** ??? 意义何在 */ 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); +// } + + /** - * 加密 - * @param txt 需要加密的数据 - * @returns + * SM2公钥加密 + * @param message 待加密数据 + * @param publicKey 公钥 (以04开头的十六进制字符串) + * @returns 十六进制格式的密文 */ -export function encrypt(txt: string) { - const instance = new JSEncrypt(); - instance.setPublicKey(publicKey); - return instance.encrypt(txt); +export function encrypt(message: string) { + try { + const cipherData = sm2.doEncrypt(message, publicKey,1); + + return cipherData; + } catch (error) { + throw new Error('SM2加密失败: ' + error.message); + } } /** - * 解密 - * @param txt 需要解密的数据 - * @returns + * SM2私钥解密 + * @param ciphertext 密文(十六进制格式) + * @param privateKey 私钥(十六进制格式) + * @returns 解密后的明文 */ -export function decrypt(txt: string) { - const instance = new JSEncrypt(); - instance.setPrivateKey(privateKey); - return instance.decrypt(txt); -} +export function decrypt(ciphertext: string) { + try { + //去掉密文的开头的04 + const ciphertextHex = ciphertext.slice(2); + const decrypted = sm2.doDecrypt(ciphertextHex, privateKey,1); + + return decrypted; + } catch (error) { + throw new Error('SM2解密失败: ' + error.message); + } +} \ No newline at end of file diff --git a/src/utils/http/axios/index.ts b/src/utils/http/axios/index.ts index a08790d..0dae758 100644 --- a/src/utils/http/axios/index.ts +++ b/src/utils/http/axios/index.ts @@ -20,7 +20,7 @@ import { useUserStoreWithOut } from '@/store/modules/user'; import { AxiosRetry } from '@/utils/http/axios/axiosRetry'; import axios from 'axios'; import { - generateAesKey, + generateSM4Key, encryptBase64, encryptWithAes, decryptBase64, @@ -29,6 +29,7 @@ import { import * as encryptUtil from '@/utils/encryption/jsencrypt'; import { axiosCanceler } from './axiosCancel'; import { useLocaleStoreWithOut } from '@/store/modules/locale'; +import CryptoJS from 'crypto-js'; const globSetting = useGlobSetting(); const localeStore = useLocaleStoreWithOut(); @@ -50,8 +51,10 @@ const transform: AxiosTransform = { const base64Str = encryptUtil.decrypt(encryptKey); /** base64 解码 得到请求头的 AES 秘钥 */ const aesSecret = decryptBase64(base64Str.toString()); + // aesSecret此时为数组,需要变成字符串 + const asciiStr=CryptoJS.enc.Utf8.stringify(aesSecret) /** 使用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); } @@ -206,8 +209,11 @@ const transform: AxiosTransform = { encrypt && ['POST', 'PUT'].includes(config.method?.toUpperCase() || '') ) { - const aesKey = generateAesKey(); - config.headers['encrypt-key'] = encryptUtil.encrypt(encryptBase64(aesKey)); + const aesKey = generateSM4Key(); + // 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') { config.data = encryptWithAes(JSON.stringify(config.data), aesKey);