feat(encrypt): 实现 SM2 加密并集成到请求中-重写 encrypt.js为 sm2-utils.js,实现 SM2 加密功能- 添加 extractSm2RawPublicKey

This commit is contained in:
陈昱达
2025-08-22 10:57:47 +08:00
parent f9b771ca66
commit 164e847ad2
2 changed files with 107 additions and 48 deletions

View File

@@ -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 }

View File

@@ -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)
}
}