密码学基础回顾:对称加密、非对称加密、哈希
聊索引加密之前,得先把密码学基本功打牢。我这些年做安全项目,见过太多人把AES当万能药,或者拿RSA直接加密大文件,结果性能崩得一塌糊涂。说白了,每种算法都有自己的脾气和适用场景。这一节咱们就捋一捋三种最常见的密码学原语——对称加密、非对称加密、哈希函数,我尽量结合踩过的坑来说。
对称加密:AES 是现在的工业标准
对称加密,意思就是加密和解密用同一把钥匙。你想象一下,你和朋友共用一把锁。AES(Advanced Encryption Standard)是目前最主流的对称加密算法,没有之一。为什么?因为它快,而且经过这么多年破解,依然坚挺。
我个人习惯用 AES-256,虽然多费一点点计算量,但安全裕度大。你想想看,密钥长度每增加1位,暴力破解的难度翻一倍。AES-128 现在也够安全,但量子计算要真来了,256 位能多撑一阵子。
AES 有三种密钥长度:128、192、256。对应的轮数不一样:
| 算法 | 密钥长度 | 轮数 | 安全级别 |
|---|---|---|---|
| AES-128 | 128 位 | 10 轮 | 够用,但别用在前瞻性系统 |
| AES-192 | 192 位 | 12 轮 | 中等安全,较少直接用 |
| AES-256 | 256 位 | 14 轮 | 推荐,能抗较长时期 |
提到 AES,就绕不过模式。ECB 模式千万别用——它会把同样的明文块加密成相同的密文块,你想想看,一张图片的轮廓都能透出来。我就在项目里见过有人图省事直接用 ECB,结果被安全审计打了个大红叉。CBC 模式稍微好一点,但需要 IV 随机化,而且没有认证,容易遭 padding oracle 攻击。我个人现在基本只用 GCM 模式——它在 CBC 基础上加了认证标签,既能防篡改,又能检测伪造。
来看个简单的 Python 示例,用 PyCryptodome 实现 AES-GCM 加密:
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
key = get_random_bytes(32) # AES-256
cipher = AES.new(key, AES.MODE_GCM)
plaintext = b"Hello, Index Encryption!"
ciphertext, tag = cipher.encrypt_and_digest(plaintext)
# 存储 cipher.nonce, ciphertext, tag 即可解密
嗯,这里要注意——nonce 和解密时的 IV 必须传输给接收方,但不需要保密。解密时:
cipher_dec = AES.new(key, AES.MODE_GCM, nonce=nonce)
data = cipher_dec.decrypt_and_verify(ciphertext, tag)
防坑建议:千万不要重复使用同一个 nonce+key 做两次加密,否则认证直接失效。我曾经在测试时就干过这事,排查了好久。
非对称加密:RSA 的取舍
非对称加密就有点意思了——它有两个钥匙,一个公开(公钥),一个自己私藏(私钥)。RSA 是其中最经典的一种,靠的是大整数分解的数学难题。你用它加密,公钥加密的数据只能用私钥解开,反过来也可以用私钥签名、公钥验证。
但是它有个致命的弱点:慢。我印象特别深,有一次用 RSA-4096 加密一个 1KB 的文本,花了差不多 5 毫秒。相比 AES 加密同样数据只要微秒级,差了三个数量级。所以实际项目中,从来不会用 RSA 直接加密大文件。正确的做法是:用 RSA 加密一个临时生成的 AES 密钥,再用 AES 加密真正的数据——也就是混合加密体系。
RSA 密钥长度的选择也得留神。目前 1024 位已经被视为不安全,我见过的厂商最小也要求 2048 位。下面这张表总结了常见长度:
| 密钥长度 | 安全状态 | 建议 |
|---|---|---|
| 1024 位 | 已破解(普通计算资源可攻破) | 禁用 |
| 2048 位 | 目前安全,但长远看可能不够 | 最低标准 |
| 4096 位 | 足够长期安全 | 推荐用于敏感场景 |
一个典型的 RSA 加密(OAEP)代码片段:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
key = RSA.generate(2048)
cipher_rsa = PKCS1_OAEP.new(key.publickey())
ciphertext = cipher_rsa.encrypt(b"AES key data")
哈希函数:不可逆的指纹
哈希函数跟加密不一样——它没有解密这一说。你把任意长度的数据塞进去,出来固定长度的摘要,而且理论上不可能反向还原。它的核心用途是完整性校验和密码存储。我习惯管它叫数据的指纹。
市面上的哈希算法一大堆,但很多已经不顶用了。MD5 和 SHA-1 已经能人为制造碰撞,说白了就是两个不同的文件可以算出相同的哈希值。我几年前做文件去重,用的 MD5,结果发现两个不同的文档居然哈希一样,差点酿成大错。从那以后,我就只认 SHA-256。
常用的哈希算法对比:
| 算法 | 摘要长度 | 安全性 | 推荐使用 |
|---|---|---|---|
| MD5 | 128 位 | 已破解,碰撞易构造 | 仅用于非安全场景(如非关键的校验) |
| SHA-1 | 160 位 | 已破解(SHAttered 攻击) | 禁用 |
| SHA-256 | 256 位 | 目前安全 | 推荐 |
| SHA-3 | 可变 | 新一代安全 | 可选,兼容性稍差 |
还有一点容易被忽略:哈希函数不是用来“加密”数据的。做密码存储时,别直接用 SHA-256 哈希密码,因为彩虹表分分钟反向查出来。要用加盐的慢哈希算法,比如 bcrypt、scrypt、Argon2。我有个项目就是直接 SHA-256,被安全评审要求全部重写密码存储逻辑,别提多麻烦了。
三种原语怎么搭配?
好,现在我们把这三种技术放一块儿看。它们不是互相取代的关系,而是各司其职:
- 对称加密(AES):跑得快,适合加密大量数据。但密钥分发麻烦。
- 非对称加密(RSA):解决密钥分发问题,还能做数字签名。但慢,只能加密小块数据。
- 哈希函数(SHA-256):生成不可逆的摘要,用于完整性验证、指纹提取,不是用来藏数据的。
在我做的索引加密系统里,典型流程是这样:用户输入文档 ——> 用 SHA-256 计算文档指纹(用于去重和校验) ——> 用 AES-256-GCM 加密文档内容 ——> 用 RSA 加密随机的 AES 密钥 ——> 最后把加密后的文档和加密后的密钥存到一起。是不是清晰多了?
这张结构图把整个密码学基础的关系理了一遍,你看一眼就明白了。
好了,这一节的基础就这么多。你记住这三者的分工和配合,后面做索引加密时就能清楚每一步该用什么算法,为什么用。我不会一开始就让你写密码实现,先把这些底层概念嚼透,后面写代码才不会手忙脚乱。