122 lines
4.1 KiB
JavaScript
122 lines
4.1 KiB
JavaScript
import CryptoJS from 'crypto-js';
|
||
import pako from 'pako';
|
||
|
||
const key2 = CryptoJS.enc.Utf8.parse(',Lscj312.;[]sc`1dsajcjc;;wislacx'); // 32字节的密钥
|
||
const iv2 = CryptoJS.enc.Utf8.parse(',>ew:[7890;,wd[2'); // 16字节的IV
|
||
|
||
// 新增PKCS5Padding移除函数(更健壮)
|
||
function removePadding(data) {
|
||
if (data.length === 0) return data;
|
||
|
||
const paddingLength = data[data.length - 1];
|
||
|
||
|
||
if (data.length < paddingLength) {
|
||
console.warn("Padding length greater than data length");
|
||
return data;
|
||
}
|
||
|
||
return data.slice(0, data.length - paddingLength);
|
||
}
|
||
|
||
// 辅助函数:打印ArrayBuffer内容(调试用)
|
||
function arrayBufferToString(buffer) {
|
||
return [...new Uint8Array(buffer)].map(b => b.toString(16).padStart(2, '0')).join(' ');
|
||
}
|
||
|
||
export default {
|
||
methods: {
|
||
encryptAndCompress(data) {
|
||
try {
|
||
// 压缩数据
|
||
const dataArray = new TextEncoder().encode(data);
|
||
const compressed = pako.gzip(dataArray);
|
||
|
||
// 加密数据
|
||
const wordArray = CryptoJS.lib.WordArray.create(compressed);
|
||
const encrypted = CryptoJS.AES.encrypt(wordArray, key2, {
|
||
iv: iv2,
|
||
mode: CryptoJS.mode.CBC,
|
||
padding: CryptoJS.pad.Pkcs7
|
||
});
|
||
|
||
return encrypted.toString();
|
||
} catch (error) {
|
||
console.error("Encryption error:", error);
|
||
throw error;
|
||
}
|
||
},
|
||
decompressAndDecrypt(encryptedData, key = key2, iv = iv2) {
|
||
try {
|
||
if (!encryptedData || encryptedData.length < 16) {
|
||
throw new Error("Invalid or empty encrypted data");
|
||
}
|
||
|
||
// 确保 Base64 格式正确
|
||
const properB64Str = encryptedData.trim().replace(/\s+/g, '');
|
||
if (!/^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/.test(properB64Str)) {
|
||
throw new Error("Invalid Base64 string");
|
||
}
|
||
// 解密数据
|
||
const cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(properB64Str) });
|
||
const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
|
||
iv: iv,
|
||
padding: CryptoJS.pad.Pkcs7
|
||
});
|
||
if (!decrypted || !decrypted.words) {
|
||
throw new Error("Decryption failed or returned invalid data");
|
||
}
|
||
function wordArrayToUint8Array(wordArray) {
|
||
const byteArray = [];
|
||
const words = wordArray.words;
|
||
const sigBytes = wordArray.sigBytes;
|
||
|
||
for (let i = 0; i < sigBytes; i++) {
|
||
byteArray.push((words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
|
||
}
|
||
|
||
return new Uint8Array(byteArray);
|
||
}
|
||
const compressedArray = wordArrayToUint8Array(decrypted);
|
||
const debugHex = [...compressedArray.slice(0, 32)].map(b => b.toString(16).padStart(2, '0')).join(' ');
|
||
// 移除PKCS7 Padding
|
||
const decryptedWithoutPadding = removePadding(compressedArray);
|
||
// 手动验证是否是合法的GZIP格式
|
||
if (decryptedWithoutPadding.length < 10 ||
|
||
(decryptedWithoutPadding[0] !== 0x1f || decryptedWithoutPadding[1] !== 0x8b)) {
|
||
// 调试输出前32字节
|
||
const debugHexPostPadding = [...decryptedWithoutPadding.slice(0, 32)].map(b => b.toString(16).padStart(2, '0')).join('');
|
||
return '';
|
||
}
|
||
|
||
// 解压数据
|
||
let decompressed;
|
||
try {
|
||
decompressed = pako.ungzip(decryptedWithoutPadding);
|
||
} catch (e) {
|
||
console.error("GZIP decompression failed", e);
|
||
throw new Error("Failed to decompress data - invalid gzip format");
|
||
}
|
||
|
||
if (!decompressed || decompressed.length === 0) {
|
||
throw new Error("Empty decompressed data");
|
||
}
|
||
|
||
// 解压成功,返回解压后的文本数据
|
||
return new TextDecoder().decode(decompressed);
|
||
} catch (error) {
|
||
console.error("Decryption error:", error);
|
||
throw error;
|
||
}
|
||
},
|
||
|
||
// 移除PKCS7 Padding的函数
|
||
removePadding(byteArray) {
|
||
// 假设是PKCS7 padding,最后一个字节的值即为填充的字节数
|
||
const paddingLength = byteArray[byteArray.length - 1];
|
||
return byteArray.slice(0, byteArray.length - paddingLength);
|
||
}
|
||
|
||
}
|
||
};
|