mirror of
http://112.124.100.131/ebiz-ai/ebiz-ai-knowledge-manage.git
synced 2025-12-10 03:16:49 +08:00
feat(encrypt): 实现 SM2 加密并集成到请求中-重写 encrypt.js为 sm2-utils.js,实现 SM2 加密功能- 添加 extractSm2RawPublicKey
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user