sm2-加密

This commit is contained in:
wu.jifen
2025-08-22 17:51:01 +08:00
parent 8a0e70ba93
commit de5c3e2f46
2 changed files with 48 additions and 68 deletions

View File

@@ -3,11 +3,11 @@ import { sm2 } from 'sm-crypto'
// DER 编码的 SM2 公钥hex
const derPublicKeyHex =
'3059301306072a8648ce3d020106082a811ccf5501822d0342000463c7ed894e2e4a1c2de4adb8b71c2fa15409356e6851d2f965ddd0e09283044fabb3457bad5a0cbb689d2668309cdb96f987716f0f83125d6f7fa6b295ac0e1f'
'3059301306072a8648ce3d020106082a811ccf5501822d034200042daac81f3b87c9f2feb2ca4cb68f4538bd1b43a587f345338b855dd7f8bb9c4de6696f1c41312ad49a2301aaadc754c5357754244ff2766420dcf550d7d3016d'
// 私钥64位 HEX
const privateKeyHex =
'3f5f667ca627d9a442fc5144cbd5ebd81d7fb66158665c7381186c93de4d8edf'
export const privateKeyHex =
'a9250b543a7d79ef103d803a4e7552cbf75ef20e92f9e64544f99ca0bd962a44'
// 缓存提取后的原始公钥
let cachedPublicKeyHex = null
@@ -80,7 +80,10 @@ export function encrypt(data, url) {
try {
const plaintext = typeof data === 'string' ? data : JSON.stringify(data)
const publicKeyHex = extractSm2RawPublicKey(derPublicKeyHex)
var publicKeyHex = extractSm2RawPublicKey(derPublicKeyHex)
publicKeyHex = '04' + publicKeyHex
publicKeyHex =
'042daac81f3b87c9f2feb2ca4cb68f4538bd1b43a587f345338b855dd7f8bb9c4de6696f1c41312ad49a2301aaadc754c5357754244ff2766420dcf550d7d3016d'
// 执行标准 SM2 加密C1C3C2 模式)
const ciphertext = sm2.doEncrypt(plaintext, publicKeyHex, 1)
@@ -109,7 +112,9 @@ export function decryptWithPrivateKey(cipherHex, privateKeyHex, mode = 1) {
try {
// 校验私钥
if (!/^[0-9a-fA-F]{64}$/.test(privateKeyHex)) {
throw new Error('私钥格式错误:必须是 64 位十六进制字符串')
throw new Error(
'私钥格式错误:必须是 64 位十六进制字符串' + privateKeyHex.length
)
}
let cleanCipher = cipherHex.trim()
@@ -169,3 +174,22 @@ if (result) {
} else {
console.error('❌ 解密失败,请检查:私钥、密文完整性、模式')
}
// 不加密的URL列表
const ENCRYPT_EXCLUDE_URLS = ['/bpic/ta/*']
// 将ENCRYPT_EXCLUDE_URLS通配符模式转换为正则表达式
const excludePatterns = ENCRYPT_EXCLUDE_URLS.map(pattern => {
// 将 * 转换为 .* 用于正则匹配
const regexPattern = pattern.replace(/\*/g, '.*')
return new RegExp('^' + regexPattern + '$')
})
// 检查是否需要加密
export function shouldEncrypt(config) {
// 获取url eg:/sysUserEx/baseLogin
const url = config.url.substring(config.url.lastIndexOf(':')).substring(6)
// 排除不加密的url
const isExcluded = excludePatterns.some(pattern => pattern.test(url))
return !isExcluded
}

View File

@@ -3,10 +3,15 @@ import { Loading, Message, MessageBox } from 'element-ui'
import store from '@/store'
import { getToken, removeToken } from '@/assets/js/utils/auth'
import router from '@/router'
import SM, { sm2 } from 'sm-crypto'
import { sm2 } from 'sm-crypto'
import { logger } from 'runjs/lib/common'
import { encrypt } from '@/assets/js/utils/encrypt'
import {
decryptWithPrivateKey,
encrypt,
shouldEncrypt,
privateKeyHex
} from '@/assets/js/utils/encrypt'
// create an axios instance
const service = axios.create({
@@ -14,54 +19,6 @@ const service = axios.create({
timeout: 600000 // request timeout
})
// SM2公钥
const SM2_PUBLIC_KEY =
'3059301306072a8648ce3d020106082a811ccf5501822d0342000463c7ed894e2e4a1c2de4adb8b71c2fa15409356e6851d2f965ddd0e09283044fabb3457bad5a0cbb689d2668309cdb96f987716f0f83125d6f7fa6b295ac0e1f'
// SM2私钥
const SM2_PRIVATE_KEY =
'3f5f667ca627d9a442fc5144cbd5ebd81d7fb66158665c7381186c93de4d8edf'
// 不加密的URL列表
const ENCRYPT_EXCLUDE_URLS = ['/bpic/ta/*']
// 将ENCRYPT_EXCLUDE_URLS通配符模式转换为正则表达式
const excludePatterns = ENCRYPT_EXCLUDE_URLS.map(pattern => {
// 将 * 转换为 .* 用于正则匹配
const regexPattern = pattern.replace(/\*/g, '.*')
return new RegExp('^' + regexPattern + '$')
})
// 加密函数
const encryptData = data => {
try {
const dataStr = JSON.stringify(data)
const encrypted = sm2.doEncrypt(dataStr, SM2_PUBLIC_KEY, 1)
// 使用加密模式1
return { encrypted: encrypted }
} catch (e) {
return data // 失败时返回原始数据
}
}
// 解密函数
const decryptData = encrypted => {
try {
encrypted =
'04496dfb4a38707c6ac95416f5dc855c9b5d02a3778ebf6bff18efe9e02fdd132bf65437f3283efeadbf52bec92793e16014b284ea034cdc0e3061fea56ff9495c50af6b0aa8c444ca87976e7ba05fcac47dbda652dad7de54cf0d51f9b6c264eea53fa4f28983f174fb5a702bd8517116340dd77cbb7f385fa02106913a8fa4e61394742a989862c804e43179'
const decrypted = sm2.doDecrypt(encrypted, SM2_PRIVATE_KEY, 1)
return JSON.parse(decrypted)
} catch (e) {
return encrypted // 失败时返回原始数据
}
}
// 检查是否需要加密
const shouldEncrypt = config => {
// 获取url eg:/sysUserEx/baseLogin
const url = config.url.substring(config.url.lastIndexOf(':')).substring(6)
// 排除不加密的url
const isExcluded = excludePatterns.some(pattern => pattern.test(url))
return !isExcluded
}
let loading
function startLoading() {
//使用Element loading-start 方法
@@ -102,10 +59,9 @@ service.interceptors.request.use(
// 保存原始数据用于调试
config.originalData = config.data
// config.data = encryptData(config.data)
var s = { content: encrypt(config.data, config.url) }
config.data = JSON.stringify(s)
var requestJson = { content: encrypt(config.data, config.url) }
config.data = JSON.stringify(requestJson)
config.headers['Content-Type'] = 'application/json'
console.log('config', config)
}
}
@@ -122,18 +78,18 @@ service.interceptors.request.use(
// response interceptor
service.interceptors.response.use(
response => {
let res = response.data
// 解密处理
if (response.config.headers['X-Encrypted'] === 'true') {
try {
res = decryptWithPrivateKey(res, privateKeyHex, 1)
} catch (e) {
logger.error('解密响应失败', e)
}
}
res = JSON.parse(res)
endLoading()
if (response.config.back) {
let res = response.data
// 解密处理
if (response.config.headers['X-Encrypted'] === 'true') {
try {
const contentStr = decryptData(res.content)
res.content = contentStr
} catch (e) {
logger.error('解密响应失败', e)
}
}
return res
}
// 二进制数据则直接返回