第2章:常见加密算法介绍 —— 对称、非对称与哈希
加密算法这东西,说玄乎也玄乎,说简单也简单。我见过不少团队在接口上随手选个算法就用,结果要么慢得要命,要么被第三方轻松拖库。其实你只要搞懂三类常用算法——对称加密、非对称加密、哈希——就能应对 90% 的 RESTful 加密场景。下面我按自己的习惯,一个个拆开跟你聊。
2.1 对称加密:一把钥匙开一把锁
对称加密,说白了就是加密和解密用同一个密钥。就像你家里的大门钥匙——谁拿着它都能进门,谁拿着它也都能锁门。优点是快,加解密吞吐量极高;缺点是密钥怎么安全地传给对方——这是个一直让人头疼的问题。
2.1.1 AES — 当今业界标准
AES(Advanced Encryption Standard)是我项目中用到最多的对称算法。它取代了老旧的 DES,目前几乎没有哪个正经系统还在用 DES 做核心加密。AES 有三种密钥长度:128 / 192 / 256 位。我个人习惯直接用 AES-256,因为密钥长了,暴力破解的难度指数级增加。
工作模式很重要。我遇到过几次奇怪问题,就是因为选错了模式。这里列个表,你可以对照项目需求选:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| ECB | 每个分组独立加密,相同明文得相同密文,不安全 | 几乎不用(除非你清楚后果) |
| CBC | 需要初始向量 IV,密文前后关联,抗破解较好 | 文件加密、数据库字段加密 |
| GCM | 自带认证标签,能同时校验完整性 | API 接口传输、流式加密 |
| CTR | 可并行加解密,没有填充问题 | 高性能场景 |
代码示例(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 做了指令集优化。
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 |
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));
// 转十六进制输出
哈希算法的安全性演进:
- MD5:128 位摘要,2004 年已被碰撞攻击完全破解(你能用普通笔记本在几秒内伪造两个不同文件的 MD5 相同)
- SHA-1:160 位摘要,2017 年 Google 和 CWI 联合发布了第一个公开碰撞案例
- SHA-256:目前安全,预计几十年内无重大风险
- SHA-3:最新标准(Keccak 算法),可作为未来备选
2.3.2 MD5 — 只适合做校验和
MD5 虽然快,但已不安全。我仅在以下场景使用:
- 下载大文件的完整性校验(如 ISO 镜像 MD5 校验码)——前提是你信任源站且能接受非抗碰撞风险
- 非安全敏感的内部去重标记
绝不用于:数字签名、密码存储、接口鉴权。
2.4 三类算法的协同关系
实际 RESTful 加密接口很少只用一种算法。最经典的组合是混合加密:用 RSA/ECC 加密对称密钥,用 AES 加密业务数据,再用 SHA-256 做消息摘要校验。你看,三种算法正好互补:非对称解决密钥分发,对称解决性能,哈希解决完整性。
2.5 选型速查表
我最后给一个快速对照表。你在设计接口加密方案时,直接对着它划勾就行:
| 需求 | 推荐算法 | 备注 |
|---|---|---|
| 传输数据加密 | AES-256-GCM | 自带认证,防重放 |
| 数字签名 | RSA-2048 / ECDSA P-256 | 验证来源和完整性 |
| 密码存储 | bcrypt / Argon2 | 不要用明文哈希 |
| 消息摘要 | SHA-256 | 标准安全 |
| 旧系统兼容(降级) | AES-128-CBC + SHA-256 | 确保 IV 随机且每次不同 |