| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- import CryptoJS from "crypto-js";
- /**
- * 加密配置接口
- */
- export interface CryptoConfig {
- key: string;
- iv: string;
- }
- /**
- * AES 加密工具类
- * 使用 AES-128-CBC 算法进行加解密
- */
- export class CryptoUtils {
- private static readonly KEY_LENGTH = 16;
- private static readonly IV_LENGTH = 16;
- /**
- * 验证密钥和向量的长度
- * @param key AES 密钥(16字节)
- * @param iv AES 向量(16字节)
- * @returns 是否有效
- */
- static validateConfig(key: string, iv: string): boolean {
- return key.length === this.KEY_LENGTH && iv.length === this.IV_LENGTH;
- }
- /**
- * 加密数据
- * @param data 待加密的数据(对象或字符串)
- * @param key AES 密钥(16字节)
- * @param iv AES 向量(16字节)
- * @returns Base64 编码的加密字符串
- */
- static encrypt(data: any, key: string, iv: string): string {
- if (!this.validateConfig(key, iv)) {
- throw new Error(`Invalid crypto config: key must be ${this.KEY_LENGTH} bytes, iv must be ${this.IV_LENGTH} bytes`);
- }
- try {
- // 将对象转换为 JSON 字符串
- const plainText = typeof data === "object" ? JSON.stringify(data) : String(data);
- // 将密钥和向量转换为 WordArray
- const keyWordArray = CryptoJS.enc.Utf8.parse(key);
- const ivWordArray = CryptoJS.enc.Utf8.parse(iv);
- // 使用 AES-128-CBC 加密
- const encrypted = CryptoJS.AES.encrypt(plainText, keyWordArray, {
- iv: ivWordArray,
- mode: CryptoJS.mode.CBC,
- padding: CryptoJS.pad.Pkcs7
- });
- // 返回 Base64 编码的密文
- return encrypted.toString();
- } catch (error) {
- throw new Error(`Encryption failed: ${error instanceof Error ? error.message : String(error)}`);
- }
- }
- /**
- * 解密数据
- * @param ciphertext Base64 编码的密文
- * @param key AES 密钥(16字节)
- * @param iv AES 向量(16字节)
- * @returns 解密后的数据(对象或字符串)
- */
- static decrypt(ciphertext: string, key: string, iv: string): any {
- if (!this.validateConfig(key, iv)) {
- throw new Error(`Invalid crypto config: key must be ${this.KEY_LENGTH} bytes, iv must be ${this.IV_LENGTH} bytes`);
- }
- try {
- // 将密钥和向量转换为 WordArray
- const keyWordArray = CryptoJS.enc.Utf8.parse(key);
- const ivWordArray = CryptoJS.enc.Utf8.parse(iv);
- // 使用 AES-128-CBC 解密
- const decrypted = CryptoJS.AES.decrypt(ciphertext, keyWordArray, {
- iv: ivWordArray,
- mode: CryptoJS.mode.CBC,
- padding: CryptoJS.pad.Pkcs7
- });
- // 将解密结果转换为 UTF-8 字符串
- const result = decrypted.toString(CryptoJS.enc.Utf8);
- // 如果解密结果为空,返回空字符串
- if (!result) {
- return "";
- }
- // 尝试解析为 JSON 对象
- try {
- return JSON.parse(result);
- } catch (e) {
- // 如果不是 JSON,则直接返回字符串
- return result;
- }
- } catch (error) {
- throw new Error(`Decryption failed: ${error instanceof Error ? error.message : String(error)}`);
- }
- }
- }
- /**
- * 默认加密工具实例
- */
- export const crypto = {
- /**
- * 加密数据(使用默认配置)
- */
- encrypt(data: any, config?: Partial<CryptoConfig>): string {
- const key = config?.key || import.meta.env.VITE_API_ENCRYPTION_KEY || "";
- const iv = config?.iv || import.meta.env.VITE_API_ENCRYPTION_IV || "";
- if (!key || !iv) {
- console.warn("Encryption keys not configured, returning plaintext");
- return typeof data === "object" ? JSON.stringify(data) : String(data);
- }
- return CryptoUtils.encrypt(data, key, iv);
- },
- /**
- * 解密数据(使用默认配置)
- */
- decrypt(ciphertext: string, config?: Partial<CryptoConfig>): any {
- const key = config?.key || import.meta.env.VITE_API_ENCRYPTION_KEY || "";
- const iv = config?.iv || import.meta.env.VITE_API_ENCRYPTION_IV || "";
- if (!key || !iv) {
- console.warn("Decryption keys not configured, returning ciphertext");
- return ciphertext;
- }
- return CryptoUtils.decrypt(ciphertext, key, iv);
- },
- /**
- * 检查是否启用了加密配置
- */
- isConfigured(): boolean {
- const key = import.meta.env.VITE_API_ENCRYPTION_KEY || "";
- const iv = import.meta.env.VITE_API_ENCRYPTION_IV || "";
- return CryptoUtils.validateConfig(key, iv);
- }
- };
|