第2章:常见加密算法介绍 —— 对称、非对称与哈希

加密算法这东西,说玄乎也玄乎,说简单也简单。我见过不少团队在接口上随手选个算法就用,结果要么慢得要命,要么被第三方轻松拖库。其实你只要搞懂三类常用算法——对称加密、非对称加密、哈希——就能应对 90% 的 RESTful 加密场景。下面我按自己的习惯,一个个拆开跟你聊。

2.1 对称加密:一把钥匙开一把锁

对称加密,说白了就是加密和解密用同一个密钥。就像你家里的大门钥匙——谁拿着它都能进门,谁拿着它也都能锁门。优点是快,加解密吞吐量极高;缺点是密钥怎么安全地传给对方——这是个一直让人头疼的问题。

2.1.1 AES — 当今业界标准

AES(Advanced Encryption Standard)是我项目中用到最多的对称算法。它取代了老旧的 DES,目前几乎没有哪个正经系统还在用 DES 做核心加密。AES 有三种密钥长度:128 / 192 / 256 位。我个人习惯直接用 AES-256,因为密钥长了,暴力破解的难度指数级增加。

核心参数:分组长度固定 128 位(16 字节),密钥长度可选 128/192/256 位,工作模式常用 CBC、GCM。

工作模式很重要。我遇到过几次奇怪问题,就是因为选错了模式。这里列个表,你可以对照项目需求选:

模式 特点 适用场景
ECB 每个分组独立加密,相同明文得相同密文,不安全 几乎不用(除非你清楚后果)
CBC 需要初始向量 IV,密文前后关联,抗破解较好 文件加密、数据库字段加密
GCM 自带认证标签,能同时校验完整性 API 接口传输、流式加密
CTR 可并行加解密,没有填充问题 高性能场景
我的建议:对 RESTful 接口,优先选 AES-256-GCM。它自带完整性校验,你不需要再加一层 HMAC。我就是用这个方案解决过一个支付回调伪造问题。

代码示例(Java,仅展示核心逻辑):

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);
byte[] cipherText = cipher.doFinal(plainText);
// 附带认证标签(后16字节)

2.1.2 DES — 可以退休了

DES 密钥只有 56 位,现在 GPU 暴力破解几十分钟就能跑完。我曾在一次遗留系统维护中见过一个老加密模块还在用 DES,替换成 AES 后速度反而更快——因为硬件对 AES 做了指令集优化。

警告:新系统不要选 DES 或 3DES。就连 3DES(Triple DES)也只是过渡方案,性能差且不再被 NIST 推荐。

2.2 非对称加密:你手里一把,我手里一把

非对称加密,加密和解密用不同的密钥。公钥可以公开,私钥必须保密。虽然算法开销比对称加密大 2~3 个数量级,但它解决了密钥配送的世纪难题。

2.2.1 RSA — 最通用的选择

RSA 基于大整数分解的数学难题。常见密钥长度:2048 位、4096 位。我记得 2017 年有个项目,客户要求“RSA 1024 位足够”,我没坚持,结果次年就被爆出 1024 位已被碰撞攻击破解。后来我花了两个通宵升级密钥……嗯,从那以后我做任何加密选型,都不低于 2048 位。

RSA 加解密性能比较:

  • 加密:比 AES 慢 100~1000 倍
  • 解密:受私钥指数影响,更慢
  • 场景:只用来加密对称密钥(混合加密),或者做数字签名

2.2.2 ECC — 未来方向

ECC(椭圆曲线密码学)能用更短的密钥达到同等安全强度。比如 ECC-256 位的安全级别 ≈ RSA-3072 位。但 ECC 的数学实现更复杂,库的兼容性不如 RSA 全面。我做跨国接口时,会优先选 RSA——因为接收端的加密库版本参差不齐,ECC 有时会踩坑。

安全级别 RSA 密钥长度 ECC 密钥长度
80 位 1024 160-223
112 位 2048 224-255
128 位 3072 256-383
192 位 7680 384-511
避坑指南:ECC 有不同的曲线参数(P-256、P-384、Curve25519)。我曾经对接一个系统,它只支持 secp256k1(比特币用的曲线),而我的库默认用 P-256,导致握手失败。所以选 ECC 时,必须提前约定好曲线名称。

2.3 哈希算法:单向不可逆的指纹

哈希不是为了加密,而是为了完整性校验和存证。它把任意长度的输入变成固定长度的摘要,且不可反向还原。注意,哈希不是加密!

2.3.1 SHA-256 — 当前最常用的安全哈希

SHA-256 输出 256 位(32 字节)摘要。它属于 SHA-2 家族。我在做接口签名时,几乎只用 SHA-256。为什么?因为 MD5 和 SHA-1 已经被证明存在碰撞攻击。

习惯用法:

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest("待签名字符串".getBytes(StandardCharsets.UTF_8));
// 转十六进制输出

哈希算法的安全性演进:

  1. MD5:128 位摘要,2004 年已被碰撞攻击完全破解(你能用普通笔记本在几秒内伪造两个不同文件的 MD5 相同)
  2. SHA-1:160 位摘要,2017 年 Google 和 CWI 联合发布了第一个公开碰撞案例
  3. SHA-256:目前安全,预计几十年内无重大风险
  4. SHA-3:最新标准(Keccak 算法),可作为未来备选
切记:不要在密码存储时直接做一次 SHA-256!我见过有团队把用户密码直接 SHA-256 入库,结果撞库时攻击者通过彩虹表一秒还原。正确做法是用 bcrypt / scrypt / Argon2 等慢哈希,并加盐(salt)。

2.3.2 MD5 — 只适合做校验和

MD5 虽然快,但已不安全。我仅在以下场景使用:

  • 下载大文件的完整性校验(如 ISO 镜像 MD5 校验码)——前提是你信任源站且能接受非抗碰撞风险
  • 非安全敏感的内部去重标记

绝不用于:数字签名、密码存储、接口鉴权。

2.4 三类算法的协同关系

实际 RESTful 加密接口很少只用一种算法。最经典的组合是混合加密:用 RSA/ECC 加密对称密钥,用 AES 加密业务数据,再用 SHA-256 做消息摘要校验。你看,三种算法正好互补:非对称解决密钥分发,对称解决性能,哈希解决完整性。

一句话总结:对称加密管速度,非对称加密管安全交付,哈希管完整性验证。三者缺一不可。
三类加密算法协同结构图 三类加密算法协同关系 对称加密 AES / DES 非对称加密 RSA / ECC 哈希算法 SHA-256 / MD5 混合加密方案 (TLS / JWE) 非对称加密密钥 → 对称加密数据 → 哈希完整性校验 💡 实际接口选型建议 AES-256-GCM + RSA-2048 签名 + SHA-256 摘要

2.5 选型速查表

我最后给一个快速对照表。你在设计接口加密方案时,直接对着它划勾就行:

需求 推荐算法 备注
传输数据加密 AES-256-GCM 自带认证,防重放
数字签名 RSA-2048 / ECDSA P-256 验证来源和完整性
密码存储 bcrypt / Argon2 不要用明文哈希
消息摘要 SHA-256 标准安全
旧系统兼容(降级) AES-128-CBC + SHA-256 确保 IV 随机且每次不同
个人心得:选加密算法时,别贪图“更安全”堆砌多层——每加一层就多一个隐患和性能消耗。够用就好,但需要提前预留升级空间(比如密钥可轮换、算法可配置)。我曾经把一个接口写死成 AES-128-CBC,结果客户要求合规升级到 GCM 模式,改动波及了好几个微服务……嗯,架构设计上多留个心眼总没错。