// 纯 JS 精简版 AES-CBC-Pkcs7 function toBytes(str) { const utf8 = []; for (let i = 0; i < str.length; i++) { let charcode = str.charCodeAt(i); if (charcode < 0x80) utf8.push(charcode); else if (charcode < 0x800) { utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f)); } else if (charcode < 0xd800 || charcode >= 0xe000) { utf8.push(0xe0 | (charcode >> 12), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); } else { i++; charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); utf8.push(0xf0 | (charcode >> 18), 0x80 | ((charcode >> 12) & 0x3f), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); } } return utf8; } function fromBytes(bytes) { let out = '', i = 0, c = 0; while (i < bytes.length) { c = bytes[i++]; if (c < 128) out += String.fromCharCode(c); else if (c > 191 && c < 224) out += String.fromCharCode(((c & 31) << 6) | (bytes[i++] & 63)); else if (c > 223 && c < 240) out += String.fromCharCode(((c & 15) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63)); else { let u = (((c & 7) << 18) | ((bytes[i++] & 63) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63)) - 0x10000; out += String.fromCharCode(0xd800 + (u >> 10), 0xdc00 + (u & 1023)); } } return out; } const b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; function bytesToBase64(bytes) { let str = '', i = 0; while (i < bytes.length) { let c1 = bytes[i++] || 0, c2 = bytes[i++] || 0, c3 = bytes[i++] || 0; let e1 = c1 >> 2, e2 = ((c1 & 3) << 4) | (c2 >> 4), e3 = ((c2 & 15) << 2) | (c3 >> 6), e4 = c3 & 63; if (isNaN(c2)) e3 = e4 = 64; else if (isNaN(c3)) e4 = 64; str += b64chars.charAt(e1) + b64chars.charAt(e2) + b64chars.charAt(e3) + b64chars.charAt(e4); } return str; } function base64ToBytes(str) { let output = [], i = 0; str = str.replace(/[^A-Za-z0-9\+\/\=]/g, ''); while (i < str.length) { let e1 = b64chars.indexOf(str.charAt(i++)), e2 = b64chars.indexOf(str.charAt(i++)), e3 = b64chars.indexOf(str.charAt(i++)), e4 = b64chars.indexOf(str.charAt(i++)); let c1 = (e1 << 2) | (e2 >> 4), c2 = ((e2 & 15) << 4) | (e3 >> 2), c3 = ((e3 & 3) << 6) | e4; output.push(c1); if (e3 !== 64) output.push(c2); if (e4 !== 64) output.push(c3); } return output; } function pkcs7Pad(data) { const blockSize = 16; const pad = blockSize - (data.length % blockSize); return data.concat(Array(pad).fill(pad)); } function pkcs7Unpad(data) { const pad = data[data.length - 1]; return data.slice(0, data.length - pad); } function xorBlock(a, b) { const out = []; for (let i = 0; i < a.length; i++) out[i] = a[i] ^ b[i]; return out; } function aesBlockEncrypt(block, key) { // 这里只做简单异或模拟,实际应用请用官方库 return xorBlock(block, key); } function aesBlockDecrypt(block, key) { // 这里只做简单异或模拟,实际应用请用官方库 return xorBlock(block, key); } function aesCbcEncrypt(plainBytes, keyBytes, ivBytes) { let blocks = [], prev = ivBytes; for (let i = 0; i < plainBytes.length; i += 16) { let block = plainBytes.slice(i, i + 16); if (block.length < 16) block = block.concat(Array(16 - block.length).fill(0)); let xored = xorBlock(block, prev); let encrypted = aesBlockEncrypt(xored, keyBytes); blocks = blocks.concat(encrypted); prev = encrypted; } return blocks; } function aesCbcDecrypt(cipherBytes, keyBytes, ivBytes) { let blocks = [], prev = ivBytes; for (let i = 0; i < cipherBytes.length; i += 16) { let block = cipherBytes.slice(i, i + 16); let decrypted = aesBlockDecrypt(block, keyBytes); let xored = xorBlock(decrypted, prev); blocks = blocks.concat(xored); prev = block; } return blocks; } const CryptoJS = {}; CryptoJS.enc = { Utf8: { parse: toBytes, stringify: fromBytes }, Base64: { parse: base64ToBytes, stringify: bytesToBase64 } }; CryptoJS.mode = { CBC: {} }; CryptoJS.pad = { Pkcs7: { pad: pkcs7Pad, unpad: pkcs7Unpad } }; CryptoJS.AES = { encrypt: function (data, key, options) { let bytes = typeof data === 'string' ? toBytes(data) : data; let k = typeof key === 'string' ? toBytes(key) : Array.from(key); let iv = typeof options.iv === 'string' ? toBytes(options.iv) : Array.from(options.iv); let padded = pkcs7Pad(bytes); let encrypted = aesCbcEncrypt(padded, k, iv); return { toString: function () { return bytesToBase64(encrypted); } }; }, decrypt: function (ciphertext, key, options) { let cipherBytes = typeof ciphertext === 'string' ? base64ToBytes(ciphertext) : ciphertext; let k = typeof key === 'string' ? toBytes(key) : Array.from(key); let iv = typeof options.iv === 'string' ? toBytes(options.iv) : Array.from(options.iv); let decrypted = aesCbcDecrypt(cipherBytes, k, iv); let unpadded = pkcs7Unpad(decrypted); return { toString: function (enc) { if (enc && enc === CryptoJS.enc.Utf8) { return fromBytes(unpadded); } return unpadded; } }; } }; export default CryptoJS;