From 4993fe2b517d1f85152230f10d0b1ad67c9af0f1 Mon Sep 17 00:00:00 2001 From: wujingling0908 <2.com> Date: Wed, 23 Sep 2026 15:45:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E6=97=A0=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E4=BB=A5=E6=9D=A5=E5=92=8C=E6=B3=A8=E9=87=8A=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 - src/utils/anysignXml.js | 320 ++++++++++++++++++++-------------------- src/utils/sm4.js | 124 ++++++++-------- 3 files changed, 222 insertions(+), 226 deletions(-) diff --git a/package.json b/package.json index e8e83a8..9ff8fe7 100644 --- a/package.json +++ b/package.json @@ -19,17 +19,13 @@ "dependencies": { "axios": "^1.14.0", "crypto-js": "^4.2.0", - "jsencrypt": "^3.3.2", "lodash": "^4.18.1", "mescroll.js": "^1.4.2", - "node-forge": "^1.4.0", "pinia": "^3.0.4", "pdfjs-dist": "5.4.149", "qs": "^6.15.0", "recorder-core": "^1.3.26070800", "sa-sdk-javascript": "^1.27.14", - "signature_pad": "^5.1.3", - "sm-crypto": "^0.5.7", "vant": "^4.9.24", "vconsole": "^3.15.1", "vue": "^3.5.31", diff --git a/src/utils/anysignXml.js b/src/utils/anysignXml.js index 3f48ad3..71fc9ca 100644 --- a/src/utils/anysignXml.js +++ b/src/utils/anysignXml.js @@ -1,160 +1,160 @@ -import CryptoJS from 'crypto-js' -import forge from 'node-forge' -import JSEncrypt from 'jsencrypt' - -const DEFAULT_PUBLIC_KEY = { - //pubN: - // 'a8e745832ad4792735a3113ab103f5622222449dfcb68c69008f9f3452943e555749a607a6147bb79db1779a645944caa1314a077e0ffc48dfd9c2a6b5fb121e7909d84b88c02e8019746dcbb9339c037ab31ab3620524f6c61bdedaf8d68277dc59a9b0bcf804757db40b7687d9b95a7b15504073fd87c58698441d577d4bab', - pubN: 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo3O/QrFgmor+MsUZ5iWKmINK0c6nI+cEguJHjuJzeP52vMfHlsyyXgkCaI62xUAUWVjbeCD4UIFph07c0AjYtGp/r5V3V9oAtcU9w9nXa43bqprTrSbasXZpK+BVG4xZXf448pG3G5tUNyzLTm4pRt2Z3Q9OJ3IEzkrRAvCHIPQIDAQAB', - pubE: '10001', - encCertSN: '1021020000067221ed', -} - -function stripImagePrefix(value) { - return value.replace(/^data:image\/[a-zA-Z0-9.+-]+;base64,/, '') -} - -function normalizeContexts(contexts, stripPrefix = false) { - const source = contexts || {} - - if (Array.isArray(source)) { - return source - .filter( - (item) => - item && - item.cid !== undefined && - item.cid !== null && - item.value !== undefined && - item.value !== null, - ) - .map(({ cid, value }) => { - const normalizedValue = stripPrefix ? stripImagePrefix(String(value)) : String(value) - return `${normalizedValue}` - }) - .join('') - } - - return Object.keys(source) - .filter((cid) => source[cid] !== undefined && source[cid] !== null) - .map((cid) => { - const rawValue = String(source[cid]) - const normalizedValue = stripPrefix ? stripImagePrefix(rawValue) : rawValue - return `${normalizedValue}` - }) - .join('') -} - -function getRandomBytes(length) { - const randomBytes = new Uint8Array(length) - const cryptoProvider = globalThis.crypto || globalThis['msCrypto'] - - if (!cryptoProvider || typeof cryptoProvider.getRandomValues !== 'function') { - throw new Error('当前环境不支持生成随机密钥') - } - - cryptoProvider.getRandomValues(randomBytes) - return randomBytes -} - -function uint8ArrayToHex(uint8Array) { - return Array.from(uint8Array, (byte) => byte.toString(16).padStart(2, '0')).join('') -} - -function uint8ArrayToBinaryString(uint8Array) { - return Array.from(uint8Array, (byte) => String.fromCharCode(byte)).join('') -} -function rsaPubkeyUint8EncByDefault(uint8Array, pubN) { - var encrypt = new JSEncrypt() - - // 设置公钥 - encrypt.setPublicKey(pubN) - - // 加密 - var encrypted = encrypt.encrypt(uint8Array) - - // 输出加密结果(Base64编码的字符串) - // console.log("加密后的密文:", encrypted); - return encrypted - - //return rsaPubkeyUint8Enc(pubN, pubE, uint8Array) -} -function encryptRandomKey(randomBytes, pubN, pubE) { - const modulus = new forge.jsbn.BigInteger(pubN, 16) - const exponent = new forge.jsbn.BigInteger(pubE, 16) - const publicKey = forge.pki.setRsaPublicKey(modulus, exponent) - const encryptedBinary = publicKey.encrypt( - uint8ArrayToBinaryString(randomBytes), - 'RSAES-PKCS1-V1_5', - ) - - return forge.util.encode64(encryptedBinary) -} - -function encryptPayload(payload, randomBytes) { - const key = CryptoJS.enc.Hex.parse(uint8ArrayToHex(randomBytes)) - return String( - CryptoJS.TripleDES.encrypt(payload, key, { - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7, - }), - ) -} - -export function buildEncryptedAnysignXml({ - tid, - signContexts = {}, - dataContexts = {}, - deviceInfo = {}, - randomBytes, - publicKey = DEFAULT_PUBLIC_KEY, -} = {}) { - if (tid === undefined || tid === null || tid === '') { - throw new Error('tid 不能为空') - } - - const toEnc = `${normalizeContexts(signContexts, true)}${normalizeContexts(dataContexts)}` - const random = randomBytes instanceof Uint8Array ? randomBytes : getRandomBytes(24) - - if (random.length !== 24) { - throw new Error('randomBytes 必须是 24 字节') - } - - // const encKey = encryptRandomKey(random, publicKey.pubN, publicKey.pubE) - const encKey = rsaPubkeyUint8EncByDefault(uint8ArrayToHex(random), publicKey.pubN) - const encData = encryptPayload(toEnc, random) - const deviceMF = deviceInfo.appName || navigator.appName - const deviceOS = deviceInfo.platform || navigator.platform - const deviceSN = deviceInfo.appVersion || navigator.appVersion - - let root = '' - root += '' - root += '1' - root += `${tid}` - root += `${encKey}` - root += '' - root += `${publicKey.encCertSN}` - root += 'N/A' - root += '1' - root += '' - root += `${encData}` - root += `${deviceMF}${deviceOS}${deviceSN}` - root += 'NA' - root += 'NULL' - root += '' - - return root -} -// import { buildEncryptedAnysignXml } from '@/utils/anysignXml.js' - -// const xml = buildEncryptedAnysignXml({ -// tid: '20011', -// signContexts: { -// 22: 'data:image/png;base64,iVBORw0KGgoAAA...', -// }, -// dataContexts: { -// 13: JSON.stringify({ foo: 'bar' }), -// 14: JSON.stringify({ userName: '张三' }), -// 15: 'hash', -// 16: '1000105', -// }, -// }) +// import CryptoJS from 'crypto-js' +// import forge from 'node-forge' +// import JSEncrypt from 'jsencrypt' + +// const DEFAULT_PUBLIC_KEY = { +// //pubN: +// // 'a8e745832ad4792735a3113ab103f5622222449dfcb68c69008f9f3452943e555749a607a6147bb79db1779a645944caa1314a077e0ffc48dfd9c2a6b5fb121e7909d84b88c02e8019746dcbb9339c037ab31ab3620524f6c61bdedaf8d68277dc59a9b0bcf804757db40b7687d9b95a7b15504073fd87c58698441d577d4bab', +// pubN: 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo3O/QrFgmor+MsUZ5iWKmINK0c6nI+cEguJHjuJzeP52vMfHlsyyXgkCaI62xUAUWVjbeCD4UIFph07c0AjYtGp/r5V3V9oAtcU9w9nXa43bqprTrSbasXZpK+BVG4xZXf448pG3G5tUNyzLTm4pRt2Z3Q9OJ3IEzkrRAvCHIPQIDAQAB', +// pubE: '10001', +// encCertSN: '1021020000067221ed', +// } + +// function stripImagePrefix(value) { +// return value.replace(/^data:image\/[a-zA-Z0-9.+-]+;base64,/, '') +// } + +// function normalizeContexts(contexts, stripPrefix = false) { +// const source = contexts || {} + +// if (Array.isArray(source)) { +// return source +// .filter( +// (item) => +// item && +// item.cid !== undefined && +// item.cid !== null && +// item.value !== undefined && +// item.value !== null, +// ) +// .map(({ cid, value }) => { +// const normalizedValue = stripPrefix ? stripImagePrefix(String(value)) : String(value) +// return `${normalizedValue}` +// }) +// .join('') +// } + +// return Object.keys(source) +// .filter((cid) => source[cid] !== undefined && source[cid] !== null) +// .map((cid) => { +// const rawValue = String(source[cid]) +// const normalizedValue = stripPrefix ? stripImagePrefix(rawValue) : rawValue +// return `${normalizedValue}` +// }) +// .join('') +// } + +// function getRandomBytes(length) { +// const randomBytes = new Uint8Array(length) +// const cryptoProvider = globalThis.crypto || globalThis['msCrypto'] + +// if (!cryptoProvider || typeof cryptoProvider.getRandomValues !== 'function') { +// throw new Error('当前环境不支持生成随机密钥') +// } + +// cryptoProvider.getRandomValues(randomBytes) +// return randomBytes +// } + +// function uint8ArrayToHex(uint8Array) { +// return Array.from(uint8Array, (byte) => byte.toString(16).padStart(2, '0')).join('') +// } + +// function uint8ArrayToBinaryString(uint8Array) { +// return Array.from(uint8Array, (byte) => String.fromCharCode(byte)).join('') +// } +// function rsaPubkeyUint8EncByDefault(uint8Array, pubN) { +// var encrypt = new JSEncrypt() + +// // 设置公钥 +// encrypt.setPublicKey(pubN) + +// // 加密 +// var encrypted = encrypt.encrypt(uint8Array) + +// // 输出加密结果(Base64编码的字符串) +// // console.log("加密后的密文:", encrypted); +// return encrypted + +// //return rsaPubkeyUint8Enc(pubN, pubE, uint8Array) +// } +// function encryptRandomKey(randomBytes, pubN, pubE) { +// const modulus = new forge.jsbn.BigInteger(pubN, 16) +// const exponent = new forge.jsbn.BigInteger(pubE, 16) +// const publicKey = forge.pki.setRsaPublicKey(modulus, exponent) +// const encryptedBinary = publicKey.encrypt( +// uint8ArrayToBinaryString(randomBytes), +// 'RSAES-PKCS1-V1_5', +// ) + +// return forge.util.encode64(encryptedBinary) +// } + +// function encryptPayload(payload, randomBytes) { +// const key = CryptoJS.enc.Hex.parse(uint8ArrayToHex(randomBytes)) +// return String( +// CryptoJS.TripleDES.encrypt(payload, key, { +// mode: CryptoJS.mode.ECB, +// padding: CryptoJS.pad.Pkcs7, +// }), +// ) +// } + +// export function buildEncryptedAnysignXml({ +// tid, +// signContexts = {}, +// dataContexts = {}, +// deviceInfo = {}, +// randomBytes, +// publicKey = DEFAULT_PUBLIC_KEY, +// } = {}) { +// if (tid === undefined || tid === null || tid === '') { +// throw new Error('tid 不能为空') +// } + +// const toEnc = `${normalizeContexts(signContexts, true)}${normalizeContexts(dataContexts)}` +// const random = randomBytes instanceof Uint8Array ? randomBytes : getRandomBytes(24) + +// if (random.length !== 24) { +// throw new Error('randomBytes 必须是 24 字节') +// } + +// // const encKey = encryptRandomKey(random, publicKey.pubN, publicKey.pubE) +// const encKey = rsaPubkeyUint8EncByDefault(uint8ArrayToHex(random), publicKey.pubN) +// const encData = encryptPayload(toEnc, random) +// const deviceMF = deviceInfo.appName || navigator.appName +// const deviceOS = deviceInfo.platform || navigator.platform +// const deviceSN = deviceInfo.appVersion || navigator.appVersion + +// let root = '' +// root += '' +// root += '1' +// root += `${tid}` +// root += `${encKey}` +// root += '' +// root += `${publicKey.encCertSN}` +// root += 'N/A' +// root += '1' +// root += '' +// root += `${encData}` +// root += `${deviceMF}${deviceOS}${deviceSN}` +// root += 'NA' +// root += 'NULL' +// root += '' + +// return root +// } +// // import { buildEncryptedAnysignXml } from '@/utils/anysignXml.js' + +// // const xml = buildEncryptedAnysignXml({ +// // tid: '20011', +// // signContexts: { +// // 22: 'data:image/png;base64,iVBORw0KGgoAAA...', +// // }, +// // dataContexts: { +// // 13: JSON.stringify({ foo: 'bar' }), +// // 14: JSON.stringify({ userName: '张三' }), +// // 15: 'hash', +// // 16: '1000105', +// // }, +// // }) diff --git a/src/utils/sm4.js b/src/utils/sm4.js index 6356903..8d9dea5 100644 --- a/src/utils/sm4.js +++ b/src/utils/sm4.js @@ -1,71 +1,71 @@ -import smCrypto from 'sm-crypto' +// import smCrypto from 'sm-crypto' -const { sm4 } = smCrypto -const currentHostname = window.location.hostname +// const { sm4 } = smCrypto +// const currentHostname = window.location.hostname -export const SM4_SAMPLE_CONFIG = { - cipherTextBase64: 'At1K/lI9/xqGNOqc7LMKVw==', - keyHex: stringToHex( - currentHostname.includes('localhost') || currentHostname.includes('aioblu-dev.trace.com.cn') - ? '0123456789abcdef' || 'a1b2c3d4e5f67890' - : currentHostname.includes('aioblu-sit.trace.com.cn') - ? '9f8e7d6c5b4a3210' - : '7h9k2m5n8p1q4r6s', - ), - ivHex: stringToHex( - currentHostname.includes('localhost') || currentHostname.includes('aioblu-dev.trace.com.cn') - ? 'abcdef0123456789' || '1a2b3c4d5e6f7089' - : currentHostname.includes('aioblu-sit.trace.com.cn') - ? '0123456789abcdef' - : '3t6w9z2b5e8h1k4n', - ), -} -function stringToHex(str) { - return Array.from(str) - .map((c) => c.charCodeAt(0).toString(16).padStart(2, '0')) - .join('') -} -function base64ToHex(base64) { - const binary = atob(base64) - let hex = '' +// export const SM4_SAMPLE_CONFIG = { +// cipherTextBase64: 'At1K/lI9/xqGNOqc7LMKVw==', +// keyHex: stringToHex( +// currentHostname.includes('localhost') || currentHostname.includes('aioblu-dev.trace.com.cn') +// ? '0123456789abcdef' || 'a1b2c3d4e5f67890' +// : currentHostname.includes('aioblu-sit.trace.com.cn') +// ? '9f8e7d6c5b4a3210' +// : '7h9k2m5n8p1q4r6s', +// ), +// ivHex: stringToHex( +// currentHostname.includes('localhost') || currentHostname.includes('aioblu-dev.trace.com.cn') +// ? 'abcdef0123456789' || '1a2b3c4d5e6f7089' +// : currentHostname.includes('aioblu-sit.trace.com.cn') +// ? '0123456789abcdef' +// : '3t6w9z2b5e8h1k4n', +// ), +// } +// function stringToHex(str) { +// return Array.from(str) +// .map((c) => c.charCodeAt(0).toString(16).padStart(2, '0')) +// .join('') +// } +// function base64ToHex(base64) { +// const binary = atob(base64) +// let hex = '' - for (let i = 0; i < binary.length; i += 1) { - hex += binary.charCodeAt(i).toString(16).padStart(2, '0') - } +// for (let i = 0; i < binary.length; i += 1) { +// hex += binary.charCodeAt(i).toString(16).padStart(2, '0') +// } - return hex -} +// return hex +// } -export function decryptSm4EcbBase64(cipherTextBase64) { - try { - const cipherHex = base64ToHex(cipherTextBase64) - return sm4.decrypt( - cipherHex, - SM4_SAMPLE_CONFIG.keyHex, - // { padding: 'none' } - ) - } catch (error) { - console.log('cipherTextBase64', cipherTextBase64) - const cipherHex = base64ToHex(cipherTextBase64) - try { - return sm4.decrypt(cipherHex, SM4_SAMPLE_CONFIG.keyHex, { padding: 'none' }) - } catch (error) { - return cipherHex - } - } -} +// export function decryptSm4EcbBase64(cipherTextBase64) { +// try { +// const cipherHex = base64ToHex(cipherTextBase64) +// return sm4.decrypt( +// cipherHex, +// SM4_SAMPLE_CONFIG.keyHex, +// // { padding: 'none' } +// ) +// } catch (error) { +// console.log('cipherTextBase64', cipherTextBase64) +// const cipherHex = base64ToHex(cipherTextBase64) +// try { +// return sm4.decrypt(cipherHex, SM4_SAMPLE_CONFIG.keyHex, { padding: 'none' }) +// } catch (error) { +// return cipherHex +// } +// } +// } -export function decryptSm4CbcBase64(cipherTextBase64, keyHex, ivHex) { - const cipherHex = base64ToHex(cipherTextBase64) +// export function decryptSm4CbcBase64(cipherTextBase64, keyHex, ivHex) { +// const cipherHex = base64ToHex(cipherTextBase64) - return sm4.decrypt(cipherHex, keyHex, { - mode: 'cbc', - iv: ivHex, - }) -} +// return sm4.decrypt(cipherHex, keyHex, { +// mode: 'cbc', +// iv: ivHex, +// }) +// } -export function decryptCurrentSample() { - return decryptSm4EcbBase64(SM4_SAMPLE_CONFIG.cipherTextBase64, SM4_SAMPLE_CONFIG.keyHex) -} +// export function decryptCurrentSample() { +// return decryptSm4EcbBase64(SM4_SAMPLE_CONFIG.cipherTextBase64, SM4_SAMPLE_CONFIG.keyHex) +// } -export const CURRENT_SAMPLE_PLAIN_TEXT = decryptCurrentSample() +// export const CURRENT_SAMPLE_PLAIN_TEXT = decryptCurrentSample()