crypto.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import CryptoJS from "crypto-js";
  2. /**
  3. * 加密配置接口
  4. */
  5. export interface CryptoConfig {
  6. key: string;
  7. iv: string;
  8. }
  9. /**
  10. * AES 加密工具类
  11. * 使用 AES-128-CBC 算法进行加解密
  12. */
  13. export class CryptoUtils {
  14. private static readonly KEY_LENGTH = 16;
  15. private static readonly IV_LENGTH = 16;
  16. /**
  17. * 验证密钥和向量的长度
  18. * @param key AES 密钥(16字节)
  19. * @param iv AES 向量(16字节)
  20. * @returns 是否有效
  21. */
  22. static validateConfig(key: string, iv: string): boolean {
  23. return key.length === this.KEY_LENGTH && iv.length === this.IV_LENGTH;
  24. }
  25. /**
  26. * 加密数据
  27. * @param data 待加密的数据(对象或字符串)
  28. * @param key AES 密钥(16字节)
  29. * @param iv AES 向量(16字节)
  30. * @returns Base64 编码的加密字符串
  31. */
  32. static encrypt(data: any, key: string, iv: string): string {
  33. if (!this.validateConfig(key, iv)) {
  34. throw new Error(`Invalid crypto config: key must be ${this.KEY_LENGTH} bytes, iv must be ${this.IV_LENGTH} bytes`);
  35. }
  36. try {
  37. // 将对象转换为 JSON 字符串
  38. const plainText = typeof data === "object" ? JSON.stringify(data) : String(data);
  39. // 将密钥和向量转换为 WordArray
  40. const keyWordArray = CryptoJS.enc.Utf8.parse(key);
  41. const ivWordArray = CryptoJS.enc.Utf8.parse(iv);
  42. // 使用 AES-128-CBC 加密
  43. const encrypted = CryptoJS.AES.encrypt(plainText, keyWordArray, {
  44. iv: ivWordArray,
  45. mode: CryptoJS.mode.CBC,
  46. padding: CryptoJS.pad.Pkcs7
  47. });
  48. // 返回 Base64 编码的密文
  49. return encrypted.toString();
  50. } catch (error) {
  51. throw new Error(`Encryption failed: ${error instanceof Error ? error.message : String(error)}`);
  52. }
  53. }
  54. /**
  55. * 解密数据
  56. * @param ciphertext Base64 编码的密文
  57. * @param key AES 密钥(16字节)
  58. * @param iv AES 向量(16字节)
  59. * @returns 解密后的数据(对象或字符串)
  60. */
  61. static decrypt(ciphertext: string, key: string, iv: string): any {
  62. if (!this.validateConfig(key, iv)) {
  63. throw new Error(`Invalid crypto config: key must be ${this.KEY_LENGTH} bytes, iv must be ${this.IV_LENGTH} bytes`);
  64. }
  65. try {
  66. // 将密钥和向量转换为 WordArray
  67. const keyWordArray = CryptoJS.enc.Utf8.parse(key);
  68. const ivWordArray = CryptoJS.enc.Utf8.parse(iv);
  69. // 使用 AES-128-CBC 解密
  70. const decrypted = CryptoJS.AES.decrypt(ciphertext, keyWordArray, {
  71. iv: ivWordArray,
  72. mode: CryptoJS.mode.CBC,
  73. padding: CryptoJS.pad.Pkcs7
  74. });
  75. // 将解密结果转换为 UTF-8 字符串
  76. const result = decrypted.toString(CryptoJS.enc.Utf8);
  77. // 如果解密结果为空,返回空字符串
  78. if (!result) {
  79. return "";
  80. }
  81. // 尝试解析为 JSON 对象
  82. try {
  83. return JSON.parse(result);
  84. } catch (e) {
  85. // 如果不是 JSON,则直接返回字符串
  86. return result;
  87. }
  88. } catch (error) {
  89. throw new Error(`Decryption failed: ${error instanceof Error ? error.message : String(error)}`);
  90. }
  91. }
  92. }
  93. /**
  94. * 默认加密工具实例
  95. */
  96. export const crypto = {
  97. /**
  98. * 加密数据(使用默认配置)
  99. */
  100. encrypt(data: any, config?: Partial<CryptoConfig>): string {
  101. const key = config?.key || import.meta.env.VITE_API_ENCRYPTION_KEY || "";
  102. const iv = config?.iv || import.meta.env.VITE_API_ENCRYPTION_IV || "";
  103. if (!key || !iv) {
  104. console.warn("Encryption keys not configured, returning plaintext");
  105. return typeof data === "object" ? JSON.stringify(data) : String(data);
  106. }
  107. return CryptoUtils.encrypt(data, key, iv);
  108. },
  109. /**
  110. * 解密数据(使用默认配置)
  111. */
  112. decrypt(ciphertext: string, config?: Partial<CryptoConfig>): any {
  113. const key = config?.key || import.meta.env.VITE_API_ENCRYPTION_KEY || "";
  114. const iv = config?.iv || import.meta.env.VITE_API_ENCRYPTION_IV || "";
  115. if (!key || !iv) {
  116. console.warn("Decryption keys not configured, returning ciphertext");
  117. return ciphertext;
  118. }
  119. return CryptoUtils.decrypt(ciphertext, key, iv);
  120. },
  121. /**
  122. * 检查是否启用了加密配置
  123. */
  124. isConfigured(): boolean {
  125. const key = import.meta.env.VITE_API_ENCRYPTION_KEY || "";
  126. const iv = import.meta.env.VITE_API_ENCRYPTION_IV || "";
  127. return CryptoUtils.validateConfig(key, iv);
  128. }
  129. };