当前位置: 首页 > news >正文

在 JavaScript 中轻松实现 AES 加密与解密:从原理到实战

在当今的 Web 开发中,数据安全至关重要,而 AES(Advanced Encryption Standard,高级加密标准)作为目前最流行的对称加密算法之一,被广泛应用于接口数据传输、本地数据存储等场景。本文将带大家深入了解 AES 加密的核心概念,并通过纯 JavaScript 代码案例,详细讲解加密、解密的实现过程,同时清晰剖析每个参数的作用,让你看完就能直接上手使用。

一、AES 加密的核心概念铺垫

在开始代码实现前,我们需要先明确几个 AES 加密的关键概念,这是理解后续参数和代码的基础:

  1. 对称加密:AES 属于对称加密算法,意味着加密和解密使用同一把密钥(Key),因此密钥的安全性直接决定了数据的安全性。

  2. 分组密码:AES 是分组密码,会将明文按照固定长度(称为 “分组大小”)分成若干组进行加密,AES 的分组大小固定为128 位(16 字节)。

  3. 密钥长度:AES 支持三种密钥长度:128 位、192 位、256 位,对应的算法通常称为 AES-128、AES-192、AES-256。密钥长度越长,安全性越高,但加密速度会略有下降,日常开发中 AES-128 已能满足大部分场景需求。

  4. 模式(Mode):由于 AES 是分组加密,需要通过 “模式” 定义多组数据的加密方式,常用的模式有CBC(Cipher Block Chaining,密码分组链接模式)、GCM(Galois/Counter Mode,伽罗瓦 / 计数器模式)等。其中 CBC 模式需要配合 “初始化向量(IV)” 使用,而 GCM 模式自带完整性校验,安全性更高。

  5. 填充(Padding):当明文长度不是分组大小(16 字节)的整数倍时,需要通过 “填充” 方式补全到分组大小。常用的填充方式有PKCS#7(在 JavaScript 中常用)、PKCS#5 等。

二、JavaScript 实现 AES 的依赖:CryptoJS

在浏览器环境中,原生 JavaScript 并没有直接提供 AES 加密的 API,因此我们通常使用第三方库 ——CryptoJS(一个轻量级的加密库,支持 AES、MD5、SHA 等多种加密算法)。

1. 引入 CryptoJS

可以通过 CDN 直接引入,也可以下载源码本地引入:

<!-- 通过CDN引入CryptoJS(包含所有加密算法) --><script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js"></script><!-- 若只需要AES模块,可引入单独的AES文件(体积更小) --><script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/aes.min.js"></script><script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/pad-pkcs7.min.js"></script> <!-- 用于PKCS#7填充 --><script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/mode-cbc.min.js"></script> <!-- 用于CBC模式 -->

三、AES 加密:参数详解与代码实现

AES 加密的核心是构建加密配置,并传入明文、密钥、初始化向量(IV)等参数。下面以最常用的 “AES-128-CBC-PKCS#7” 组合为例,讲解加密过程。

1. 加密所需核心参数

参数名作用要求与说明
plaintext待加密的明文数据可以是字符串(如接口参数、用户信息)、JSON 对象(需先转为字符串)
key加密密钥(对称密钥)需与解密密钥完全一致;若使用 AES-128,密钥长度需为 16 字节(128 位)
iv初始化向量(仅 CBC、CFB 等模式需要)长度固定为 16 字节(与 AES 分组大小一致);建议每次加密生成随机 IV,增强安全性
mode加密模式常用CryptoJS.mode.CBCCryptoJS.mode.GCM
padding填充方式常用CryptoJS.pad.PKCS7(当明文长度不是 16 的倍数时自动补全)
outputType加密结果的输出格式可选Base64(常用,结果简洁)、Hex(十六进制字符串)

2. 加密代码实现(AES-128-CBC)

下面的代码包含 “生成随机 IV”“明文加密”“结果格式化” 三个核心步骤,并添加了详细注释:

/*** AES加密函数(AES-128-CBC-PKCS#7,输出Base64格式)* @param {string} plaintext - 待加密的明文(字符串)* @param {string} key - 加密密钥(16字节,若长度不足会自动补全,建议手动控制为16字节)* @returns {object} - 包含加密结果(ciphertext)和初始化向量(iv)的对象*/function aesEncrypt(plaintext, key) {// 1. 生成随机IV(16字节,CBC模式必须)// CryptoJS.lib.WordArray.random(16) 生成16字节的随机数,再转为Base64格式方便存储/传输const iv = CryptoJS.lib.WordArray.random(16).toString(CryptoJS.enc.Base64);// 2. 将密钥和IV转为CryptoJS可识别的格式(WordArray)// CryptoJS.enc.Utf8.parse(key):将UTF-8编码的密钥转为WordArrayconst keyWordArray = CryptoJS.enc.Utf8.parse(key);const ivWordArray = CryptoJS.enc.Base64.parse(iv); // IV是Base64格式,需用Base64解析// 3. 执行AES加密// 参数1:明文(需转为WordArray);参数2:密钥;参数3:加密配置(模式、IV、填充)const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(plaintext), // 明文转为WordArraykeyWordArray,{mode: CryptoJS.mode.CBC, // 加密模式:CBCiv: ivWordArray,         // 初始化向量padding: CryptoJS.pad.PKCS7 // 填充方式:PKCS#7});// 4. 加密结果转为Base64格式(encrypted.toString() 默认就是Base64)const ciphertext = encrypted.toString();// 返回加密结果和IV(解密时需要IV)return { ciphertext, iv };}// ------------------- 加密示例 -------------------const originalData = '{"username":"admin","password":"123456"}'; // 待加密的JSON字符串const secretKey = 'mySecretKey123456'; // 16字节的密钥(AES-128)// 执行加密const encryptResult = aesEncrypt(originalData, secretKey);console.log('加密结果:', encryptResult.ciphertext);console.log('使用的IV:', encryptResult.iv);// 输出示例:// 加密结果: U2FsdGVkX1+...(Base64字符串)// 使用的IV: abc123def456...(Base64字符串)

四、AES 解密:参数详解与代码实现

解密过程是加密的逆操作,需要使用与加密相同的密钥、IV、模式、填充方式,否则无法正确解密。

1. 解密所需核心参数

参数名作用要求与说明
ciphertext待解密的密文(加密后的结果)需与加密输出格式一致(如 Base64,若加密用 Hex 则解密也用 Hex)
key解密密钥必须与加密密钥完全一致
iv初始化向量必须与加密时使用的 IV 完全一致(CBC 模式必需)
mode/padding解密模式 / 填充方式必须与加密时的配置完全一致(否则解密会失败或出现乱码)

2. 解密代码实现(AES-128-CBC)

解密代码与加密代码结构对称,核心是 “解析密文和 IV”“执行解密”“还原明文”:

/*** AES解密函数(AES-128-CBC-PKCS#7,输入Base64格式密文)* @param {string} ciphertext - 待解密的密文(Base64格式)* @param {string} key - 解密密钥(与加密密钥一致,16字节)* @param {string} iv - 加密时使用的IV(Base64格式)* @returns {string} - 解密后的明文(字符串)*/function aesDecrypt(ciphertext, key, iv) {// 1. 将密钥、IV、密文转为CryptoJS可识别的格式const keyWordArray = CryptoJS.enc.Utf8.parse(key);const ivWordArray = CryptoJS.enc.Base64.parse(iv); // IV是Base64格式,需解析const ciphertextWordArray = CryptoJS.enc.Base64.parse(ciphertext); // 密文是Base64格式,需解析// 2. 执行AES解密const decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertextWordArray }, // 密文需包装为 { ciphertext: WordArray } 格式keyWordArray,{mode: CryptoJS.mode.CBC, // 与加密模式一致iv: ivWordArray,         // 与加密IV一致padding: CryptoJS.pad.PKCS7 // 与加密填充方式一致});// 3. 解密结果转为UTF-8字符串(还原明文)const plaintext = decrypted.toString(CryptoJS.enc.Utf8);return plaintext;}// ------------------- 解密示例 -------------------// 使用加密时的结果(密文和IV)进行解密const decryptResult = aesDecrypt(encryptResult.ciphertext, // 加密后的密文secretKey,                // 与加密一致的密钥encryptResult.iv          // 与加密一致的IV);console.log('解密结果:', decryptResult);// 输出示例:{"username":"admin","password":"123456"}(与原始明文一致)// 若原始数据是JSON,可进一步解析为JSON对象const decryptedData = JSON.parse(decryptResult);console.log('解密后的JSON对象:', decryptedData);// 输出示例:{ username: 'admin', password: '123456' }

五、常见问题与注意事项

  1. 密钥长度不匹配怎么办?

    若密钥长度不是 16/24/32 字节(对应 AES-128/192/256),CryptoJS 会自动用0x00补全或截断,但这会降低安全性。建议手动控制密钥长度,例如通过 SHA-256 哈希将任意长度的字符串转为 32 字节(256 位)密钥:

// 将任意长度的密钥转为32字节(AES-256)const rawKey = 'myLongerSecretKey123'; // 任意长度const key = CryptoJS.SHA256(rawKey).toString().slice(0, 32); // SHA-256哈希后取前32字节
  1. IV 需要保密吗?

    不需要!IV 的作用是防止相同明文加密后得到相同密文,因此 IV 可以随密文一起传输(如放在接口返回的 JSON 中),但必须保证每次加密使用不同的 IV(建议随机生成)。

  2. GCM 模式与 CBC 模式的区别?

    GCM 模式支持 “加密 + 完整性校验”,可以检测密文是否被篡改,安全性更高,且不需要单独的填充方式(自带处理)。若需使用 GCM 模式,只需将mode改为CryptoJS.mode.GCM,并在加密结果中获取authTag(解密时需传入):

// GCM模式加密(示例片段)const encrypted = CryptoJS.AES.encrypt(plaintextWordArray, keyWordArray, {mode: CryptoJS.mode.GCM,iv: ivWordArray});const authTag = encrypted.getAuthTag().toString(CryptoJS.enc.Base64); // 获取认证标签// GCM模式解密(示例片段)const decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertextWordArray },keyWordArray,{mode: CryptoJS.mode.GCM,iv: ivWordArray,authTag: CryptoJS.enc.Base64.parse(authTag) // 传入认证标签});
  1. 浏览器环境与 Node.js 环境的差异?

    本文代码适用于浏览器环境(依赖 CryptoJS);若在 Node.js 环境中,可使用原生的crypto模块(无需第三方库),核心参数(密钥、IV、模式、填充)的逻辑一致,只是 API 写法不同。

六、总结

本文通过 CryptoJS 库,详细讲解了 JavaScript 中 AES 加密、解密的实现过程,核心要点可总结为:

  1. 参数一致性:加密和解密的密钥、IV、模式、填充方式必须完全一致,否则无法正确解密;

  2. 密钥安全性:密钥需手动控制长度(16/24/32 字节),且避免硬编码在前端代码中(建议通过后端接口动态获取);

  3. IV 随机性:每次加密生成随机 IV,避免相同明文加密后得到相同密文;

  4. 模式选择:日常场景用 CBC 模式足够,对安全性要求高的场景(如支付、敏感数据)建议用 GCM 模式。

掌握这些知识后,你可以轻松将 AES 加密应用到实际项目中,例如接口请求参数加密、本地 Storage 数据加密等,为你的 Web 应用增加一层安全保障。


文章转载自:

http://Sy2bIkOg.nwtkz.cn
http://eHT88MU7.nwtkz.cn
http://gGLeGajg.nwtkz.cn
http://Wr3rof6G.nwtkz.cn
http://Z17vcclD.nwtkz.cn
http://T19AhRpB.nwtkz.cn
http://myLaSIa4.nwtkz.cn
http://Pdk92xhH.nwtkz.cn
http://Gu4fiODL.nwtkz.cn
http://SP6IEqwz.nwtkz.cn
http://YQvUeQMA.nwtkz.cn
http://AzEMdSya.nwtkz.cn
http://nNS2ClRB.nwtkz.cn
http://FzVr8PNF.nwtkz.cn
http://tLJphGWY.nwtkz.cn
http://IxYLV7YY.nwtkz.cn
http://4A66zR38.nwtkz.cn
http://DYQPUzXv.nwtkz.cn
http://DxnjMVI1.nwtkz.cn
http://rHo0luBF.nwtkz.cn
http://we2TB6Gr.nwtkz.cn
http://eTojATDT.nwtkz.cn
http://I4lTk7Tv.nwtkz.cn
http://M0jS4sxc.nwtkz.cn
http://J9vNXosg.nwtkz.cn
http://kU0Ud6ba.nwtkz.cn
http://ZXDaVuOh.nwtkz.cn
http://p13nNMsN.nwtkz.cn
http://GmnWwdUz.nwtkz.cn
http://aUWj5IsN.nwtkz.cn
http://www.dtcms.com/a/374179.html

相关文章:

  • Mockoon:开源免费的本地Mock服务工具,提升前后端联调效率
  • C/C++圣诞树②
  • segYolo添加界面
  • 初学Transformer核心——注意力机制
  • 第9篇:Freqtrade量化交易之config.json 基础入门与初始化
  • 推荐系统学习笔记(十六)LHUC(PPNet)
  • 前端开发实战 主流前端开发工具对比与最佳实践
  • 淘宝 API 技术架构与实战指南:从实时数据流到 AIGC 融合的电商开发新范式
  • 基于AD9689BBPZ-2600 的高速数字采集 板卡
  • Transformer 模型:Attention is All You Need 的真正含义
  • BUU MISC(看心情写)
  • 第三方网站数据库测评:【源码级SQL注入与数据泄露风险全面测评】
  • 【Linux基础】parted命令详解:从入门到精通的磁盘分区管理完全指南
  • 实践《数字图像处理》之Canny边缘检测、霍夫变换与主动二值化处理在短线段清除应用中的实践
  • sim2real_动作迁移常用的方法和思路(比如bvh->robot)
  • 第六届机器学习与计算机应用国际学术会议
  • 正交匹配追踪(OMP)详解:压缩感知的基石算法
  • Github项目推荐:Made-With-ML 机器学习工程学习指南
  • 【Java实战㉞】从0到1:Spring Boot Web开发与接口设计实战
  • Python从入门到精通_01_python基础
  • 基于开源做的图片压缩工具
  • 联邦学习与大模型结合
  • SQL隐式链接显式连接
  • pd19虚拟机安装Win11系统
  • 【面试场景题】如何进行高并发系统的性能测试?
  • Keepalived配置好后,域名解析到哪里
  • 滑动窗口题目:长度最小的子数组
  • 如何Maven 构建问题排查与依赖管理
  • 嵌入式学习日记(42)ARM
  • 盖奇的遭遇__[心理学和脑科学神经科学](1)