AES 加密算法详解:从原理到实现

AES 加密算法详解:从原理到实现

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 轮)

每一轮包含四个变换:

  1. SubBytes:使用 S 盒进行字节替换
  2. ShiftRows:行移位操作
  3. MixColumns:列混合操作
  4. AddRoundKey:与轮密钥异或

2.3 最终轮(不包含 MixColumns)

最后一轮只包含三个变换:

  1. SubBytes
  2. ShiftRows
  3. 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 或经过验证的第三方库,避免自行实现加密算法。正确的密钥管理和模式选择同样重要。