AES(高级加密标准)是目前应用最广泛的对称加密算法之一。它由美国国家标准与技术研究院(NIST)于 2001 年正式采纳,取代了旧的 DES 算法。AES 是一个分组密码算法,支持 128 位、192 位和 256 位三种密钥长度。
一、AES 算法概述
| 特性 | 说明 |
|---|---|
| 算法类型 | 对称分组密码 |
| 分组长度 | 128 位(固定) |
| 密钥长度 | 128/192/256 位 |
| 轮数 | 10/12/14 轮(对应不同密钥长度) |
| 安全性 | 极高,目前无有效攻击方法 |
二、AES 加密流程
AES 的加密过程主要包括以下几个步骤:
2.1 初始轮(AddRoundKey)
将明文分组与第一轮轮密钥进行逐位异或运算:
state = state XOR roundKey[0]
2.2 主轮变换(重复 N-1 轮)
每一轮包含四个变换:
- SubBytes:使用 S 盒进行字节替换
- ShiftRows:行移位操作
- MixColumns:列混合操作
- AddRoundKey:与轮密钥异或
2.3 最终轮(不包含 MixColumns)
最后一轮只包含三个变换:
- SubBytes
- ShiftRows
- AddRoundKey
三、核心变换详解
3.1 SubBytes:字节替换
SubBytes 使用一个固定的查找表(S 盒)对每个字节进行非线性替换:
// AES S-Box example (partial)
const sBox = [
[0x63, 0x7c, 0x77, 0x7b, ...],
[0xf2, 0x6b, 0x6f, 0xc5, ...],
// ... total 16x16 bytes
];
function subBytes(state) {
for (let i = 0; i < 16; i++) {
const row = (state[i] >> 4) & 0x0f;
const col = state[i] & 0x0f;
state[i] = sBox[row][col];
}
return state;
}
3.2 ShiftRows:行移位
ShiftRows 对矩阵的行进行循环移位,第 i 行循环左移 i 位:
// Input state matrix (4x4)
// [ s0 s4 s8 s12 ]
// [ s1 s5 s9 s13 ]
// [ s2 s6 s10 s14 ]
// [ s3 s7 s11 s15 ]
function shiftRows(state) {
// Row 0: no shift
// Row 1: shift left by 1
[state[1], state[5], state[9], state[13]] =
[state[5], state[9], state[13], state[1]];
// Row 2: shift left by 2
[state[2], state[6], state[10], state[14]] =
[state[10], state[14], state[2], state[6]];
// Row 3: shift left by 3
[state[3], state[7], state[11], state[15]] =
[state[15], state[3], state[7], state[11]];
return state;
}
3.3 MixColumns:列混合
MixColumns 对矩阵的每列进行线性变换,使用固定的多项式:
function mixColumns(state) {
const matrix = [
[2, 3, 1, 1],
[1, 2, 3, 1],
[1, 1, 2, 3],
[3, 1, 1, 2]
];
const newState = new Uint8Array(16);
for (let col = 0; col < 4; col++) {
for (let row = 0; row < 4; row++) {
let sum = 0;
for (let i = 0; i < 4; i++) {
sum ^= gfMultiply(matrix[row][i], state[col * 4 + i]);
}
newState[col * 4 + row] = sum;
}
}
return newState;
}
// Galois field multiplication
function gfMultiply(a, b) {
let result = 0;
for (let i = 0; i < 8; i++) {
if (b & 1) result ^= a;
const carry = a & 0x80;
a = (a << 1) & 0xff;
if (carry) a ^= 0x1b; // AES polynomial
b >>= 1;
}
return result;
}
3.4 AddRoundKey:轮密钥加
将状态与轮密钥进行逐位异或:
function addRoundKey(state, roundKey) {
for (let i = 0; i < 16; i++) {
state[i] ^= roundKey[i];
}
return state;
}
四、密钥扩展
AES 使用密钥扩展算法将原始密钥扩展为多轮轮密钥:
function expandKey(key) {
const keyLen = key.length;
const rounds = keyLen === 16 ? 10 : (keyLen === 24 ? 12 : 14);
const expanded = new Uint8Array(16 * (rounds + 1));
// Copy original key
expanded.set(key);
for (let i = keyLen; i < expanded.length; i += 4) {
let temp = expanded.slice(i - 4, i);
// Transform every 4 bytes
if (i % keyLen === 0) {
temp = subWord(rotWord(temp));
temp[0] ^= rcon[i / keyLen];
} else if (keyLen > 24 && i % keyLen === 16) {
temp = subWord(temp);
}
for (let j = 0; j < 4; j++) {
expanded[i + j] = expanded[i + j - keyLen] ^ temp[j];
}
}
return expanded;
}
function rotWord(word) {
return [word[1], word[2], word[3], word[0]];
}
function subWord(word) {
return word.map(byte => sBox[(byte >> 4) & 0x0f][byte & 0x0f]);
}
五、完整 AES 加密实现
class AES {
constructor(key) {
this.key = key;
this.rounds = key.length === 16 ? 10 : (key.length === 24 ? 12 : 14);
this.expandedKey = this.expandKey(key);
}
encrypt(plaintext) {
// Initial round
let state = this.addRoundKey(plaintext, this.expandedKey.slice(0, 16));
// Main rounds
for (let round = 1; round < this.rounds; round++) {
state = this.subBytes(state);
state = this.shiftRows(state);
state = this.mixColumns(state);
state = this.addRoundKey(state, this.expandedKey.slice(round * 16, (round + 1) * 16));
}
// Final round
state = this.subBytes(state);
state = this.shiftRows(state);
state = this.addRoundKey(state, this.expandedKey.slice(this.rounds * 16));
return state;
}
// ... other methods (subBytes, shiftRows, mixColumns, addRoundKey, expandKey)
}
// Usage example
const key = new Uint8Array(16); // 128-bit key
const aes = new AES(key);
const plaintext = new Uint8Array(16); // 128-bit plaintext
const ciphertext = aes.encrypt(plaintext);
六、AES 工作模式
AES 本身是分组密码,需要配合工作模式才能处理任意长度的数据:
| 模式 | 特点 | 安全性 | 适用场景 |
|---|---|---|---|
| ECB | 相同明文产生相同密文 | 低 | 不推荐 |
| CBC | 需要初始化向量 IV | 中 | 通用场景 |
| CFB | 流密码模式 | 中 | 流式数据 |
| OFB | 流密码模式,误差不传播 | 中 | 网络传输 |
| CTR | 流密码模式,并行加密 | 高 | 高性能场景 |
| GCM | 认证加密模式 | 高 | 需要认证的场景 |
七、前端实现示例
现代浏览器原生支持 AES,使用 Web Crypto API:
async function aesEncrypt(key, data, iv) {
const cryptoKey = await window.crypto.subtle.importKey(
'raw',
key,
{ name: 'AES-GCM' },
false,
['encrypt']
);
const ciphertext = await window.crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
cryptoKey,
data
);
return ciphertext;
}
async function aesDecrypt(key, ciphertext, iv) {
const cryptoKey = await window.crypto.subtle.importKey(
'raw',
key,
{ name: 'AES-GCM' },
false,
['decrypt']
);
const plaintext = await window.crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
cryptoKey,
ciphertext
);
return plaintext;
}
// Usage example
const key = window.crypto.getRandomValues(new Uint8Array(16)); // 128-bit key
const iv = window.crypto.getRandomValues(new Uint8Array(12)); // GCM recommended 12-byte IV
const data = new TextEncoder().encode('Hello, AES!');
const ciphertext = await aesEncrypt(key, data, iv);
const decrypted = await aesDecrypt(key, ciphertext, iv);
console.log(new TextDecoder().decode(decrypted)); // "Hello, AES!"
💡 提示:推荐使用 AES-GCM 模式,它同时提供加密和认证功能,可以检测数据是否被篡改。
八、安全最佳实践
- 密钥管理:密钥必须保密,避免硬编码
- IV 使用:每次加密使用随机 IV,IV 可以公开
- 模式选择:优先使用 GCM 或 CTR 模式,避免 ECB
- 密钥派生:使用 PBKDF2 或 scrypt 从密码派生密钥
- 认证:确保数据完整性,使用认证加密模式
九、总结
AES 是现代密码学的基石,理解其原理对于安全开发至关重要。AES 的安全性基于其复杂的轮函数设计和有限域运算,目前没有有效的攻击方法。
在实际开发中,应优先使用浏览器原生的 Web Crypto API 或经过验证的第三方库,避免自行实现加密算法。正确的密钥管理和模式选择同样重要。