🏠 首页 攻略 AES 加密实战:别再拿 MD5 当加密用了

AES 加密实战:别再拿 MD5 当加密用了

MD5 是哈希不是加密!AES 才是真正的对称加密标准。本文手把手教你用在线 AES 工具完成加解密,附实战案例和常见踩坑指南。

上周帮一个朋友排查线上问题,发现他把用户密码用 MD5「加密」后存数据库,还信誓旦旦地说「这很安全」。我差点一口气没上来——MD5 是哈希,不是加密。哈希不可逆,加密可逆,这是两个完全不同的概念。

做后端开发,对称加密几乎是避不开的必修课。从支付回调验签、接口参数加密传输,到敏感数据落地存储,每天都要跟 AES 打交道。

今天就拿我们站上的 AES 在线加密解密工具,把 AES 实战从头到尾捋一遍。

AES 是什么?为什么是它?

AES(Advanced Encryption Standard)是美国国家标准与技术研究院(NIST)在 2001 年发布的对称加密标准。说人话:加密和解密用同一把钥匙

特性AES3DESRC4(已弃用)
密钥长度128/192/256 位56×3 位40-2048 位
安全性极高(当前无实用攻击)中等(易受中间人攻击)低(已知多种攻击)
速度快(硬件加速)快(但不安全)
行业标准✅ 合规❌ 不推荐❌ 已弃用

AES-256 直到今天仍然是学术界公认的安全标准。量子计算机来了?AES-256 在量子攻击下也只需要将密钥长度翻倍,安全性依然够用。

必知参数:5 个关键要素

AES 加解密不是「点一下就行」的事。加密方和解密方必须用完全一样的参数,差一个字母都解不出来。

1. 密钥(Key)

密钥是 AES 的核心。128 位密钥需要 16 个字节(字符),256 位需要 32 个字节。

密钥生成建议:不要用「123456」这种弱口令当密钥。用我们的 密码生成器 生成一个 32 位随机字符串,或者用工具内置的「随机生成密钥」功能。

好密钥示例:a8F#mK2p$9xQ&zN4wE7*LvR@cT1yB6
坏密钥示例:1234567890123456

2. 加密模式(Mode)

模式特点适用场景
ECB每个块独立加密,同样明文→同样密文❌ 不推荐(有模式攻击风险)
CBC每个块与前一块异或,引入 IV✅ 最常用,安全性好
CTR将 AES 变成流密码,可并行计算需要并行加解密
GCM自带认证标签,检测篡改✅ 推荐用于网络传输
CFB/OFB适合流式数据特定协议场景

实战中,CBC 和 GCM 是最常见的两个选择。 ECB 除非你非常清楚自己在做什么,否则别用。

3. 初始向量(IV)

CBC、GCM 等模式需要 IV(Initialization Vector)。IV 的作用是让同样明文每次加密都得到不同的密文。

  • IV 长度:固定 16 字节(128 位)
  • IV 要求:随机生成,可以不保密(通常和密文一起传输)
  • IV≠密钥:IV 不需要保密,但每次加密必须用不同的 IV

4. 填充方式(Padding)

AES 加密是按块(16 字节)处理的,最后一块不够 16 字节时要填充。

填充方式说明推荐
PKCS7缺少 N 字节就补 N 个值为 N 的字节✅ 最常用
ZeroPadding补零不推荐(二义性)
ISO10126随机填充较少用
NoPadding不填充(数据必须刚好 16 的倍数)特殊场景

5. 输出格式

AES 加密的结果是二进制数据,需要编码后传输。

  • Base64:最常用,比原始数据膨胀约 33%,可读性好
  • Hex:每个字节转两位十六进制,长度翻倍,适合调试用
  • Raw:原始的二进制数据,非文本传输场景用

实战:加密一段 JSON 数据

假设你正在开发支付回调接口,需要把订单信息加密后传给第三方。

原始数据

{
  "order_id": "ORD20260530001",
  "amount": 299.00,
  "currency": "CNY",
  "user_id": "u_10086",
  "timestamp": 1748534400
}

加密步骤

  1. 打开 AES 加密/解密工具
  2. 选择模式:CBC
  3. 密钥:a8F#mK2p$9xQ&zN4wE7*LvR@cT1yB6(32 位 → AES-256)
  4. IV:点「随机生成」按钮
  5. 填充:PKCS7(默认)
  6. 输出:Base64
  7. 把 JSON 贴到明文区 → 点加密

得到的密文类似这样:

7vG3kR2xY9pQmN4wL8zA5bC1dE6fH0iJ2kL4mO6pQ8rS0tU2vW4xY6zA8

解密时,把这段 Base64 密文、同样的密钥、同样的 IV、同样的模式输入解密区,就能还原原始 JSON。

踩坑记录:我吃过这些亏

坑 1:密钥编码不一致

Java 的 SecretKeySpec 用字节数组构造密钥,而 Node.js 的 crypto.createCipheriv 接受字符串。如果双方的字符编码不一致(UTF-8 vs ASCII),密钥就不同了,解密必定失败。

解决方法:约定密钥用 Base64 或 Hex 编码传输,双方解析成同样的字节序列。

坑 2:IV 忘了传

CBC 模式解密时,IV 必须和加密时一样。很多人加密时生成了随机 IV,解密时却忘了保存,结果死活解不出来。

解决方法:IV 和密文拼接在一起传输。常见做法:IV(16 字节)+ 密文,解密时先取前 16 字节做 IV。

坑 3:跨语言加解密

不同语言对 AES 的默认参数不同:

语言/平台默认模式默认填充默认密钥编码
Java (JCE)ECBPKCS5Padding字节数组
Python (PyCryptodome)无默认必须指定字节数组
Node.js (crypto)CBCPKCS7UTF-8 字符串
OpenSSLCBCPKCS7ASCII 字符串

跨语言对接时,手动指定所有参数,不要依赖默认值。

最佳实践:生产环境怎么用

加密数据传输

客户端                        服务端
  │                              │
  │  1. 生成随机 AES 密钥        │
  │  2. 用 RSA 公钥加密 AES 密钥  │
  │  3. AES 加密业务数据          │
  │  4. 发送 RSA(AES_KEY) + IV   │
  │     + AES(Data)              │
  │─────────────────────────────>│
  │                              │  5. RSA 私钥解密出 AES 密钥
  │                              │  6. AES 解密出业务数据

这种「RSA 加密 AES 密钥 + AES 加密数据」的混合加密方案,兼顾了非对称加密的安全性和对称加密的效率,是 TLS 协议也在用的思路。

加密后数据标记

建议在加密数据前加一个标识前缀,方便识别是否已加密:

ENCRYPTED_PREFIX = "ENC:"

def encrypt(data, key):
    encrypted = aes_encrypt(data, key)
    return ENCRYPTED_PREFIX + base64_encode(encrypted)

def decrypt(data, key):
    if not data.startswith(ENCRYPTED_PREFIX):
        return data  # 未加密的直接返回
    encrypted = base64_decode(data[len(ENCRYPTED_PREFIX):])
    return aes_decrypt(encrypted, key)

密钥轮换

密钥不要写死,定期更换。建议:

  • 每 90 天更换一次密钥
  • 使用密钥管理服务(AWS KMS / HashiCorp Vault)
  • 旧密钥保留至少一个轮换周期用于解密历史数据

总结

AES 加密不是什么玄学,记住五个参数(密钥、模式、IV、填充、输出格式)就能上手。实际工作中,最常用的组合是 AES-256-CBC + PKCS7 + Base64 输出

下次再看到有人用 MD5 当加密用,记得把这篇文章甩给他。

需要 AES 加解密不想敲命令行的,收藏 NavBox 在线 AES 工具,全浏览器端处理,不断网也能用。