密码学基础:对称加密(AES)、非对称加密(RSA/ECC)、哈希函数

做密文检索,密码学是绕不开的地基。说实话,刚开始接触这个领域时,我也觉得这些概念很枯燥。但后来在实际开发中踩过几次坑才明白——不理解这些基础,根本写不出安全又高效的检索代码。

这一章我们只讲三样东西:对称加密、非对称加密、哈希函数。它们是密文检索的三大支柱。我会结合自己踩过的坑,帮你把每个原理和选型要点说透。

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

对称加密很好理解:加密和解密用同一把密钥。就像你家里的大门钥匙,锁门和开门都是它。

我个人习惯在密文检索场景里优先选 AES(Advanced Encryption Standard)。为什么?因为它快,硬件支持好,而且经过全球密码学家多年审视,安全性公认可靠。

AES 的核心参数

参数说明我的建议
密钥长度128 / 192 / 256 bit必须 256 bit,别省那点性能
工作模式ECB / CBC / GCM / CTR …推荐 GCM(认证加密),其次 CTR
填充方式PKCS#7 / NoPadding流模式不需要填充,GCM 自带认证标签
初始化向量IV / Nonce每次加密必须不同,可以用随机数+计数器
我曾经踩过的坑: 刚做项目时图省事用了 ECB 模式,结果相同明文加密出相同密文,索引几乎失效。后来全部改成 GCM 模式,既保密又防篡改,检索正确率才上来。

为什么 AES 能用在密文检索里?因为我们可以把加密后的数据直接建索引,只要工作模式选对了(比如确定性的保序加密模式或支持相等检索的格式保留加密),就能在不解密的情况下完成匹配。

一个简单的 AES-GCM 加密示例(伪代码)

// 注意:实际生产不要硬编码密钥
key = random_bytes(32);        // 256位密钥
iv  = random_bytes(12);        // 96位Nonce

cipher = AES_GCM_Encrypt(plaintext, key, iv, aad);
// cipher = (密文 || 认证标签)

decrypted = AES_GCM_Decrypt(cipher, key, iv, aad);
// 验证失败返回错误,否则返回明文

做密文检索时,如果你需要做范围查询(比如“大于”“小于”),对称加密的保序加密(OPE)是个方向。我试过 CLOZ 方案,但要注意泄露边界——少泄露不等于零泄露。

非对称加密:公钥私钥分着用

对称加密有个通病:密钥分发很棘手。你想想看,加密检索的双方怎么安全地交换那把密钥?非对称加密就解决了这个问题——公钥随便发,私钥自己藏。

密文检索里,非对称加密通常用来做两件事:密钥交换和数字签名。主流的算法有 RSA 和 ECC(椭圆曲线密码学)。

RSA vs ECC 对比

特性RSA (2048位)ECC (256位, 如 secp256r1)
安全性等价112 位对称安全128 位对称安全
密钥长度2048 位256 位
加密性能较慢(模幂运算)更快(标量乘)
签名大小256 字节64 字节
推荐场景兼容旧系统、无性能瓶颈移动端、IoT、高频签名

我个人更偏爱 ECC,尤其在资源受限的环境里。我记得有一次集成密文检索 SDK 到嵌入式设备,RSA 一次签名要 50ms,换成 ECC 后降到 5ms,差距肉眼可见。

重点: 在密文检索里,非对称加密很少直接加密原始数据(太慢)。通常用对称加密加密内容,用非对称加密加密对称密钥。这叫「混合加密」,既安全又高效。

RSA 示例(密钥生成、加密、解密)

# 生成 2048 位 RSA 密钥对
rsa_keypair = RSA_Generate(2048)

# 用公钥加密对称密钥
encrypted_key = RSA_Encrypt(symmetric_key, rsa_keypair.public)

# 用私钥解密对称密钥
decrypted_key = RSA_Decrypt(encrypted_key, rsa_keypair.private)

注意:RSA 能加密的明文长度有限制(< 密钥位数/8 - 填充长度)。2048 位 RSA 大约只能加密 245 字节。别直接把大文件往上怼,否则会报错。

哈希函数:不可逆的指纹

哈希函数会把任意长度的输入,变成固定长度的输出。像指纹一样,很难找到两个不同输入有相同输出(抗碰撞),而且从哈希值反推原始输入几乎不可能(单向性)。

在密文检索里,哈希最常见的用途就是构建 关键词索引。你把每个关键词哈希一下,把哈希值作为索引,之后搜的时候把搜索词的哈希值拿过来匹配就行。这样服务器不知道你搜的是什么词。

常用哈希算法选型

算法输出长度安全性性能(相对)
MD5128 位已破解,不推荐极快
SHA-1160 位已破解,不推荐快
SHA-256256 位安全中等
SHA-3-256256 位安全,新一代略慢于 SHA-2
BLAKE2可配置安全,极快比 SHA-2 快 2-3 倍

平时做密文检索索引,我几乎只用 SHA-256 或 BLAKE2b。BLAKE2 在软件实现上特别快,而且支持输出长度自定义,非常灵活。

你可能会问:哈希后的索引会不会碰撞?理论上有,但概率极低。如果你要做多关键词的联合检索,还可以把多个哈希值拼接后再次哈希,或者用布隆过滤器压缩存储——我在项目里就是这么做的,内存占用降了 80%。

哈希索引构建伪代码

// 构建倒排索引(关键词 -> 文档列表)
for each document in corpus:
    for each keyword in extract_keywords(document):
        h = SHA256(keyword)
        inverted_index[h].append(document.id)

// 查询
query_hash = SHA256(user_query)
results = inverted_index.get(query_hash, [])

别直接用原始哈希做相等检索!因为相同关键词的哈希值永远一样,这能泄露频率信息——攻击者可以统计每个哈希出现次数,推断出热门关键词。解决办法:加盐(随机数),或者用可搜索加密专用的原语。

三种技术的关系:一张图理清

我把对称加密、非对称加密、哈希在密文检索中的应用画成了下面这张图。你看一遍就能明白它们各自扮演什么角色。

密码学基础在密文检索中的应用关系图 密文检索密码学三件套 对称加密 (AES) 加密数据,快速建索引 非对称加密 (RSA/ECC) 密钥交换、数字签名 哈希函数 (SHA-256) 关键词索引、完整性验证 混合加密 索引构建 密文检索核心流程 ① 对称加密加密文档 → ② 哈希关键词建索引 ③ 非对称加密传输对称密钥 → ④ 检索时哈希匹配 ⚠️ 常见误区: • 不要只用一种密码原语:密文检索需要组合使用 • 哈希不加盐会导致频率泄露,对称加密不认证会导致篡改 三者协同:安全 × 效率 × 可检索

实战选型建议

说了这么多理论,到了真要做密文检索 SDK 时,该怎么选?我给你一个我自己的参考清单:

  • 数据加密: 用 AES-256-GCM。既加密又认证,一个 API 搞定全部。
  • 密钥交换: 用 ECDH(基于 ECC 的 Diffie-Hellman),安全级别高,握手快。
  • 关键词索引: 用 SHA-256 或 BLAKE2b,配合随机盐值防频率分析。
  • 数字签名 / 身份验证: 用 ECDSA(基于 ECC 的签名算法),签名短,验证快。
  • 混合封装: 用 ECC 公钥加密 AES 密钥,AES 密钥加密数据,哈希索引独立构建。

另外,别忘了考虑量子计算抗性。虽然现在还不急,但如果你的产品生命周期超过 5 年,建议关注 NIST 后量子密码标准(如 Kyber、Dilithium)。我已经在下一代 SDK 里预留了替换接口。

嗯,这一章的内容量不少,但都是实打实要用的。你不需要一次性记住所有参数,只要理解每个原语在密文检索里的定位——对称加密负责速度,非对称加密负责安全分发,哈希负责可搜索性。后面讲具体 SDK 接口实现时,我们再深入每个环节的代码细节。