diff --git a/src/assets/js/utils/encrypt.js b/src/assets/js/utils/encrypt.js index efb6289..73ac657 100644 --- a/src/assets/js/utils/encrypt.js +++ b/src/assets/js/utils/encrypt.js @@ -1,52 +1,107 @@ -//encrypt.js +// sm2-utils.js +import { sm2 } from 'sm-crypto' + +// DER 编码的 SM2 公钥(hex) +const derPublicKeyHex = + '3059301306072a8648ce3d020106082a811ccf5501822d0342000463c7ed894e2e4a1c2de4adb8b71c2fa15409356e6851d2f965ddd0e09283044fabb3457bad5a0cbb689d2668309cdb96f987716f0f83125d6f7fa6b295ac0e1f' + +// 缓存提取后的原始公钥 +let cachedPublicKeyHex = null + /** - * 通过crypto-js实现 加解密工具 - * AES - * @author: wmz + * 从 DER 编码的 SM2 公钥(hex)中提取原始未压缩公钥(04 开头) + * @param {string} derHex - DER 格式的公钥(十六进制字符串) + * @returns {string} 原始公钥 hex 字符串(04 开头,130位) */ -import CryptoJS from 'crypto-js' -const KP = { - key: 'AJDBW8D2zdDq3b5U', // 秘钥 16*n: - iv: '' // 偏移量 +function extractSm2RawPublicKey(derHex) { + if (cachedPublicKeyHex) { + return cachedPublicKeyHex + } + + let derBuffer + try { + derBuffer = + typeof Buffer !== 'undefined' + ? Buffer.from(derHex, 'hex') + : new Uint8Array(derHex.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16))) + } catch (error) { + throw new Error('公钥 hex 格式无效') + } + + // 查找 03 42 00 04 模式 + const pattern = [0x03, 0x42, 0x00, 0x04] + let offset = -1 + + for (let i = 0; i < derBuffer.length - pattern.length; i++) { + if ( + derBuffer[i] === pattern[0] && + derBuffer[i + 1] === pattern[1] && + derBuffer[i + 2] === pattern[2] && + derBuffer[i + 3] === pattern[3] + ) { + offset = i + 3 // 跳过 03 42 00 04 + break + } + } + + if (offset === -1) { + throw new Error('无法在 DER 中找到 SM2 公钥数据') + } + + // 提取 65 字节(04 + X + Y) + const publicKeyRaw = derBuffer.slice(offset, offset + 65) + + // 转为 hex 字符串 + const hex = + typeof Buffer !== 'undefined' + ? publicKeyRaw.toString('hex') + : Array.from(publicKeyRaw) + .map(b => b.toString(16).padStart(2, '0')) + .join('') + + cachedPublicKeyHex = hex + return hex } -function getAesString(data, key, iv) { - // 加密 - key = CryptoJS.enc.Utf8.parse(key) - iv = CryptoJS.enc.Utf8.parse(iv) - let encrypted = CryptoJS.AES.encrypt(data, key, { - // iv: iv, - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7 - }) - return encrypted.toString() // 返回的是base64格式的密文 + +/** + * SM2 加密函数(支持选择性加密) + * @param {any} data - 待加密的数据(对象、数组、字符串等) + * @param {string} url - 请求 URL,用于判断是否加密 + * @returns {any|string} 加密后的 hex 字符串,或原数据(白名单路径) + */ +export function encrypt(data, url) { + // 白名单:/bpic/ta/* 路径不加密 + if (/^\/bpic\/ta\//.test(url)) { + return data + } + + try { + // 准备明文(避免重复 stringify) + const plaintext = typeof data === 'string' ? data : JSON.stringify(data) + + // 提取并缓存公钥 + const publicKeyHex = extractSm2RawPublicKey(derPublicKeyHex) + + // 执行加密 + const ciphertext = sm2.doEncrypt(plaintext, publicKeyHex, { + cipherMode: 1 // 标准模式 + }) + + console.log('[SM2加密] 明文:', plaintext) + console.log('[SM2密钥] 明文:', publicKeyHex) + console.log('[SM2加密] 密文:', ciphertext) + + return ciphertext + } catch (error) { + console.error('[SM2加密失败]', error) + // 生产环境可选择抛出,或返回原数据 + 日志 + throw new Error(`SM2加密失败: ${error.message}`) + } } -function getDAesString(encrypted, key, iv) { - // 解密 - key = CryptoJS.enc.Utf8.parse(key) - iv = CryptoJS.enc.Utf8.parse(iv) - let decrypted = CryptoJS.AES.decrypt(encrypted, key, { - // iv: iv, - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7 - }) - return decrypted.toString(CryptoJS.enc.Utf8) // + +/** + * 可选:导出公钥(用于调试) + */ +export function getPublicKey() { + return extractSm2RawPublicKey(derPublicKeyHex) } -// AES 对称秘钥加密 -const aes = { - en: data => getAesString(data, KP.key, KP.iv), - de: data => getDAesString(data, KP.key, KP.iv) -} -// BASE64 -const base64 = { - en: data => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)), - de: data => CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8) -} -// SHA256 -const sha256 = data => { - return CryptoJS.SHA256(data).toString() -} -// MD5 -const md5 = data => { - return CryptoJS.MD5(data).toString() -} -export { aes, md5, sha256, base64 } diff --git a/src/assets/js/utils/request.js b/src/assets/js/utils/request.js index 6818623..e41afdb 100644 --- a/src/assets/js/utils/request.js +++ b/src/assets/js/utils/request.js @@ -6,6 +6,8 @@ import router from '@/router' import { sm2 } from 'sm-crypto' import { logger } from 'runjs/lib/common' +import { encrypt } from '@/assets/js/utils/encrypt' + // create an axios instance const service = axios.create({ baseURL: '', // url = base url + request url @@ -97,7 +99,9 @@ service.interceptors.request.use( if (config.data) { // 保存原始数据用于调试 config.originalData = config.data - config.data = encryptData(config.data) + // config.data = encryptData(config.data) + config.data = encrypt(config.data, config.url) + console.log('config', config) } }