AES 思想与可运行的分组/流密码
本节目标
- 区分分组密码与流密码
- 手写一个 XOR 流密码(可运行)
- 理解 AES "分组 + 多轮混淆"的思想(不实现完整算法)
两类对称加密:
- 流密码:逐字节/逐比特与密钥流异或(如一次性密码本、RC4)。简单、快。
- 分组密码:把明文分块(如 16 字节),每块经多轮替换/换位加密(如 AES-128 轮 10 次)。
// 运行环境:Node.js 14+
// 保存为 aj-l14.js,执行:node aj-l14.js
const crypto = require('crypto')
// 1) XOR 流密码:密钥流 = 由种子派生的伪随机字节
function xorStream(plaintext, key) {
const keyBytes = Buffer.from(key)
const out = Buffer.alloc(plaintext.length)
for (let i = 0; i < plaintext.length; i++) {
out[i] = plaintext[i] ^ keyBytes[i % keyBytes.length] // 逐字节异或
}
return out
}
const msg = Buffer.from('secret message')
const enc = xorStream(msg, 'mykey')
const dec = xorStream(enc, 'mykey') // 异或两次还原
console.log('密文:', enc.toString('hex'))
console.log('还原:', dec.toString()) // secret message
// 2) 直接用 Node 内置 AES(生产请用这个,别自己造轮子)
function aesDemo(plaintext, key32) {
const iv = crypto.randomBytes(16)
const cipher = crypto.createCipheriv('aes-256-cbc', key32, iv)
const enc = Buffer.concat([cipher.update(plaintext), cipher.final()])
return iv.toString('hex') + ':' + enc.toString('hex')
}
console.log('AES-256-CBC:', aesDemo(Buffer.from('hello'), crypto.randomBytes(32)))AES 思想:每轮做"字节替换(S盒)/ 行移位 / 列混淆 / 加轮密钥",多轮叠加让明文与密钥彻底混为一体。手写完整 AES 很繁琐,但思想就是"简单变换重复多轮"。
名词解释
- 对称加密:加密与解密用同一把密钥。分为流密码(逐字节异或)与分组密码(分块多轮变换)。
- 异或(XOR):二进制运算,相同为 0、不同为 1;
a ^ b ^ b = a,故用同一密钥流异或两次可还原——流密码的数学基础。 - AES(高级加密标准):分组密码代表,把 16 字节块经 10/12/14 轮"替换+置换+加密钥"变成密文。生产务必用标准库实现。
课后练习
- 为什么 XOR 流密码"密钥不能重复使用"?
- 答案:两份密文都用同一密钥流异或,攻击者把两份密文异或就抵消了密钥流、得到两份明文异或,结合语言统计可破译。一次性密码本要求密钥真随机且只用一次。
- 自己手写 AES 用于生产有什么风险?
- 答案:极易在轮数、S盒、模式(ECB 不安全)、填充、IV 处理上出错,导致可被攻破;标准库经过严格审计,应直接调用。
总结
加密这一节划清了一条铁律:理解原理 ≠ 能造轮子。你手写的 XOR 流密码足以讲清"异或两次还原"的数学美感,也能让你看穿为什么一次性密码本密钥绝不能重用;但真正上生产的 AES,必须调用经过审计的标准库——这不是偷懒,而是工程纪律。AES 的"分组 + 多轮混淆"思想本身很优雅:用几个简单变换(替换、移位、混淆、加密钥)重复十轮,就把明文和密钥搅得难解难分。我特别想强调"不要自己实现加密算法"这条红线:历史上无数系统因为"看似正确的自研加密"被轻易攻破。学加密的正确姿势是:懂它为什么安全(扩散、混淆、密钥管理),然后在代码里永远用 crypto 标准库。这节课给你的不是造加密的能力,而是"识别加密方案优劣、不踩安全坑"的判断力。