对称加密 AES / DES

本节目标

对称加密 = 一把钥匙开一把锁。前端常用 AES(先进、推荐)或老旧的 DES(已不安全)。复现 AES 时,必须同时拿到:算法/模式、密钥、iv、填充方式,缺一不可。

// 运行环境:Node.js 18+(无需依赖,用内置 crypto)
// 运行:node jsr-l8.cjs
const crypto = require('crypto')

function aesEncrypt(plain, key, iv) {
  // AES-128-CBC:密钥 16 字节,iv 16 字节,PKCS7 填充(Node 默认)
  const cipher = crypto.createCipheriv('aes-128-cbc', Buffer.from(key), Buffer.from(iv))
  return Buffer.concat([cipher.update(plain, 'utf8'), cipher.final()]).toString('base64')
}
function aesDecrypt(b64, key, iv) {
  const decipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(key), Buffer.from(iv))
  return Buffer.concat([decipher.update(Buffer.from(b64, 'base64')), decipher.final()]).toString('utf8')
}
const key = '1234567890abcdef' // 16 字节
const iv = 'abcdef1234567890'  // 16 字节
const enc = aesEncrypt('你好世界', key, iv)
console.log('密文:', enc)
console.log('明文:', aesDecrypt(enc, key, iv)) // 你好世界

逆向要点:在 JS 里搜 createCipheriv / aes / CBC,找到 key、iv 的来源。它们可能硬编码、可能来自接口、也可能藏在闭包。四个要素必须对齐,否则解密出来是乱码。

名词解释

对称加密(Symmetric Encryption):加密和解密用「同一把密钥」。优点快,缺点是要安全地把密钥给对方。AES 是目前标准(DES 因密钥太短已淘汰)。逆向里前端 JS 里的对称密钥通常是「公开的」(在代码里),所以对称加密在前端主要防「看得懂」而非「防复现」。

IV(初始化向量)/ 模式 / 填充:IV 是「让同一明文每次密文不同」的随机量(CBC 模式必须);模式(ECB/CBC/...) 决定怎么分组;填充解决「明文不是块整数倍」的问题。复现 AES 时这三者必须和前端完全一致,否则解密失败。它们是 AES 的「四个拼图块」。

课后练习

练习 1:AES 的 key 和 iv 一般各多少字节(AES-128)?

答案:AES-128 的 key 是 16 字节(128 位);CBC 模式的 iv 也是 16 字节(一个分组大小)。key 长度错会直接报错,iv 错会解出乱码。

练习 2:ECB 模式和 CBC 模式哪个更不安全?为什么?

答案:ECB 更不安全。ECB 不依赖 IV、相同明文块加密出相同密文块,容易从密文看出结构(如图片轮廓)。CBC 用 iv 把块串起来,相同明文不同密文,所以更抗分析。逆向看到 ecb 要警惕它「没藏住结构」。

总结

AES 是前端加密的「主力」,也是逆向复现里最容易「差一个参数就全错」的类型。我的观点:复现 AES 别急着写代码,先像查字典一样把四个要素(算法+模式、key、iv、padding)从 JS 里一个个抠出来列在纸上,再动手。新手 90% 的失败是「iv 没找全」或「padding 假设错了」。另外要认清一个现实:前端 JS 里的 AES 密钥基本是公开的,它防的是「人肉读代码」,不是「防你复现」——所以这类加密在逆向里通常能 100% 还原,只是要细心。把四个要素当 checklist,一项项打勾,稳。