JavaScript怎么使用CryptoJS实现AES加密

作者:寒星

时间:2026-11-02

浏览:325

详细讲解在JavaScript环境下如何使用CryptoJS库实现标准的AES加密与解密。包含环境引入、WordArray编码转换、CBC模式与IV配置、跨语言对接规范以及前端安全边界分析。

文章目录
密码学实践 环境:Node.js / 浏览器 核心库:crypto-js
JavaScript怎么使用CryptoJS实现AES加密
概览:CryptoJS AES 对称加密的三个核心技术维度

在 JavaScript 中使用 CryptoJS 实现 AES 加密,核心在于理解密钥格式解析、工作模式(如 CBC)、初始向量(IV)以及密文编码输出。初学者在对接 Java、Go 或 Python 服务端时,最容易出现“加密报错”或“解密出来全是乱码”的问题,其根源往往不在于 AES 算法本身,而在于未将字符串显式转换为 CryptoJS 内部标准的 WordArray,或者前后端的填充(Padding)与工作模式(Mode)未严格对齐。

一、引入 CryptoJS 依赖

在编写业务逻辑前,需要根据运行时环境(Node.js 或 Web 浏览器)将 CryptoJS 引入工程中。

1. Node.js / 打包工具环境(Webpack, Vite 等)

在工程根目录安装官方 npm 包:

npm install crypto-js

随后在 JavaScript 代码中按需或全量导入:

// CommonJS 规范
const CryptoJS = require("crypto-js");

// 或 ES Module 规范
import CryptoJS from "crypto-js";

2. 原生 HTML / 浏览器直引环境

如果在没有前端工程化构建工具的页面中使用,可以通过 CDN 脚本标签引入:

<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js"></script>

引入后,全局对象 window.CryptoJS 即可直接调用。

二、AES 加密工作机制与数据流向

AES(Advanced Encryption Standard,高级加密标准)属于对称分组密码体制,数据块大小固定为 128 位(16 字节)。密钥长度支持 128 位(16 字节)、192 位(24 字节)或 256 位(32 字节)。

在实际工程中,最常用且安全性受认可的分组模式是 CBC(Cipher Block Chaining,密文分组链接模式)。在 CBC 模式下,每一个明文块在被加密前,都会先与前一个密文块进行异或运算;而第一个明文块则与指定的“初始向量(IV)”进行异或。这意味着相同的明文即使多次加密,只要 IV 随机,产生的密文就完全不同,有效抵御模式分析攻击。

JavaScript怎么使用CryptoJS实现AES加密
图 1:AES-CBC 模式的分组链接加密机制及初始向量(IV)传递关系

三、使用 CryptoJS 实现 AES 加密的操作步骤

在实际编码中,实现一套标准、规范的 AES 加密解密流程,需要按部就班完成 4 个关键操作环节:

JavaScript怎么使用CryptoJS实现AES加密
图 2:CryptoJS 实现 AES 加解密的四步标准流程

四、标准代码示例:AES-CBC 加密与解密

下面是一个经过严格验证的生产级别完整实现代码。示例包含明文加密为 Base64 字符串、以及从 Base64 密文还原明文的全部逻辑:

const CryptoJS = require("crypto-js");

/**
 * AES-CBC 模式加密
 * @param {string} plainText 待加密明文
 * @param {string} keyStr 16位(AES-128)或32位(AES-256)密钥字符串
 * @param {string} ivStr 16位初始向量字符串
 * @returns {string} Base64 编码密文
 */
function encryptAES_CBC(plainText, keyStr, ivStr) {
  // 1. 将字符串转为 CryptoJS 内部的 WordArray
  const key = CryptoJS.enc.Utf8.parse(keyStr);
  const iv = CryptoJS.enc.Utf8.parse(ivStr);
  const srcs = CryptoJS.enc.Utf8.parse(plainText);

  // 2. 执行 AES 加密
  const encrypted = CryptoJS.AES.encrypt(srcs, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });

  // 3. 返回标准的 Base64 密文字符串
  return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}

/**
 * AES-CBC 模式解密
 * @param {string} cipherTextBase64 Base64 编码密文
 * @param {string} keyStr 密钥字符串
 * @param {string} ivStr 初始向量字符串
 * @returns {string} 解密后的明文字符串
 */
function decryptAES_CBC(cipherTextBase64, keyStr, ivStr) {
  // 1. 解析 key 与 iv
  const key = CryptoJS.enc.Utf8.parse(keyStr);
  const iv = CryptoJS.enc.Utf8.parse(ivStr);

  // 2. 解密过程可直接接收 Base64 字符串,也可先 parse 为 WordArray
  const decrypted = CryptoJS.AES.decrypt(cipherTextBase64, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });

  // 3. 将解密出来的 WordArray 转为 UTF-8 文本
  return decrypted.toString(CryptoJS.enc.Utf8);
}

// ==================== 运行验证 ====================
// 选用 16 字节(128位)的密钥与向量
const secretKey = "1234567890123456"; // 16 字符 = 16 字节
const secretIV  = "abcdef0123456789"; // 16 字符 = 16 字节
const originalText = "Hello CryptoJS! 中文测试与安全通信。";

console.log("原始明文:", originalText);

// 加密
const cipherResult = encryptAES_CBC(originalText, secretKey, secretIV);
console.log("加密输出 (Base64):", cipherResult);

// 解密
const plainResult = decryptAES_CBC(cipherResult, secretKey, secretIV);
console.log("解密还原:", plainResult);

// 验证一致性
console.log("还原校验:", originalText === plainResult ? "成功匹配" : "解密失败");
示例输出:
原始明文: Hello CryptoJS! 中文测试与安全通信。
加密输出 (Base64): R3vXm7q5G1YfI8u...(实际输出因密钥与明文而定)
解密还原: Hello CryptoJS! 中文测试与安全通信。
还原校验: 成功匹配

五、工作模式对比:为什么推荐 CBC 而非 ECB

CryptoJS 同时支持多种工作模式,如 CryptoJS.mode.CBC、CryptoJS.mode.ECB、CryptoJS.mode.CFB、CryptoJS.mode.CTR、CryptoJS.mode.OFB。但在实际业务中,最常引起争议和误用的是 ECB 与 CBC。

JavaScript怎么使用CryptoJS实现AES加密
图 3:AES-CBC 与 AES-ECB 关键特性与安全选型比对

在 ECB 模式下,明文被简单切成 16 字节小段单独加密。如果明文中有两段相同的内容(例如重复的空格或固定的 JSON 结构),其密文结果也是完全相同的。攻击者无需破解密钥,仅通过观察密文段的重复频率或对密文段进行重新拼接排序,就能伪造合法报文。因此在现代系统开发中,应坚决选用 CBC 模式或认证加密模式(如 GCM)。

六、跨语言对接的常见三大陷阱

前后端跨语言对接(例如 JavaScript 前端加密,Java/Spring Boot 或 Python 后端解密)时,超过 90% 的失败是由以下细节引起的:

陷阱 1:字符串未转 WordArray 导致隐式口令派生(OpenSSL 格式)

如果直接传入字符串而非 WordArray:

// 错误用法:传入普通字符串
CryptoJS.AES.encrypt("hello", "my-secret-key");

此时 CryptoJS 会认为传入的不是“原始密钥”,而是一个“口令(Passphrase)”。它会在内部生成一个随机的 8 字节 Salt(盐值),并通过 PBKDF/OpenSSL 规则计算出真正的密钥,最终导出的密文字符串会以 Salted__(Base64 表现为 U2FsdGVkX1...)开头。如果后端直接拿 my-secret-key 当作真实 Key 去解密,必定报“Bad Padding”或解密出乱码。

解决办法:必须始终使用 CryptoJS.enc.Utf8.parse(keyStr) 将 Key 与 IV 转成 WordArray。

陷阱 2:密钥与 IV 长度不足或超标

AES 算法严格要求:

  • AES-128:密钥长度必须是 16 字节(128 位)。
  • AES-192:密钥长度必须是 24 字节(192 位)。
  • AES-256:密钥长度必须是 32 字节(256 位)。
  • CBC 模式下的 IV:长度必须固定为 16 字节(128 位)。

如果传入了 15 个字符或包含中文多字节字符(一个汉字占 3 字节 UTF-8),字节总数未能精确匹配,将导致不可预期的截断或填充行为。在编写代码时应显式确认 key.sigBytes 达到对应字节数。

陷阱 3:密文编码格式不一致(Base64 与 Hex 混淆)

CryptoJS.AES.encrypt() 返回的是一个 CipherParams 对象。初学者常常直接调用 encrypted.toString()。如果加密时提供了 WordArray 格式的 Key 和 IV,encrypted.toString() 默认会输出 Base64 编码;但部分后端系统(如使用某些 C/C++ 或旧版 PHP 驱动)可能要求十六进制 Hex(如 e4a1b2...)。必须与后端接口文档核对清楚:

// 输出 Base64(最常见)
const base64Cipher = encrypted.ciphertext.toString(CryptoJS.enc.Base64);

// 输出 Hex(十六进制)
const hexCipher = encrypted.ciphertext.toString(CryptoJS.enc.Hex);

七、生产落地自查与安全边界认知

为了确保系统不仅能“跑通加解密”,还能真正具备工程安全性,建议在项目上线前依照下表进行安全自查:

JavaScript怎么使用CryptoJS实现AES加密
图 4:CryptoJS AES 工程化自查与安全落地方案

最后必须清醒认识到前端加密的威胁模型与局限性:在浏览器环境中,任何打包在 bundle.js 里的密钥或混淆算法,对具有调试能力的逆向者而言都是透明的。因此,前端 AES 加密通常用于提高爬虫和自动化脚本的数据提取门槛,或者与非对称加密(RSA/SM2)结合实现混合加密体系(例如使用 RSA 公钥加密临时的 AES Key,再用 AES 加密大批量业务报文)。全链路的信道安全,仍应依托底层的 TLS/HTTPS 协议来保障。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章