可搜索加密原理:SSE 与 PEKS 的核心差异
聊完了倒排索引和加密算法的基础,我们终于要进入正题了——可搜索加密(Searchable Encryption)。
很多人一听到这个名字,第一反应都是:“不就是把加密后的数据存进去,然后按关键词查出来吗?”
嗯,大体逻辑没错,但实现起来道道很深。
我个人习惯把可搜索加密分为两大类来理解:对称可搜索加密(SSE)和非对称可搜索加密(PEKS)。这两者在密钥管理、适用场景、安全模型上差异很大。
我在第一个密文检索项目中,就是因为没搞清楚两者的适用边界,选错了方案,后面改得很痛苦。今天咱们就把这块彻底掰扯清楚。
对称可搜索加密 (SSE)
SSE 是实际落地中最常用的方案。为什么?很简单,性能好、实现成熟。
说白了,SSE 的核心思想就是:你提前把文档的关键字提取出来,构建一个加密的倒排索引,然后把加密后的文档和这个索引一起扔给服务器。
查询的时候,你用对称密钥生成一个“陷门”(Trapdoor),服务器拿着这个陷门在你的加密索引里查找匹配项。
SSE 的典型工作流程
- 数据持有方生成对称密钥 K
- 用 K 加密所有文档(比如 AES-GCM)
- 用 K 加密每个文档的关键字,建立加密倒排索引
- 将密文文档 + 加密索引上传到云服务器
- 客户端用 K 生成目标关键词的陷门
- 服务器在不解密的情况下遍历索引,返回匹配的文档 ID
- 客户端用 K 解密返回的密文文档
这里有个核心问题:陷门是怎么保证“不可区分”的?
我记得有一个很经典的例子。假设你的索引里存了“医院”和“学校”两个词。如果你每次查“医院”都生成同一个陷门,服务器用不了多久就能统计出来——这不是泄露了吗?
所以,SSE 的方案里通常会在陷门生成时引入一个随机数(Nonce),保证同一关键词多次查询的陷门不同。但请注意,这并不能完全隐藏查询模式(Query Pattern),只能阻止“直接明文映射”。
我曾经踩过的一个坑
我记得有一次做金融文档检索项目,我天真地以为加密索引里的陷门是不可追踪的。后来被安全审计的老师问:“你的陷门访问模式有没有做 Oblivious 处理?”我一查,才发现普通的 SSE 方案,服务器虽然不知道你查的是什么词,但它能判断出“这次查的和上次查的是同一个词”。这就是“访问模式泄露”(Access Pattern Leakage)。在金融、医疗等强隐私场景下,这是不可接受的。
解决方案是引入 ORAM(Oblivious RAM)或 Path ORAM 来隐藏访问模式,但性能代价极高。这一点在选型时要心里有数。
非对称可搜索加密 (PEKS)
PEKS 的全称是 Public-key Encryption with Keyword Search。和 SSE 最大的不同在于——密钥是对称的。
你想想看,SSE 要求客户端和服务器事先共享同一个对称密钥。但在很多真实场景里,这是做不到的。比如:
- Alice 想把加密邮件发送到服务器上,Bob 想从服务器上搜索特定关键词的邮件
- 多个不同的发送方需要加密数据给同一个接收方
这种情况下,你总不能把对称密钥分发给所有发送方吧?密钥管理会变成灾难。
PEKS 解决的就是这个问题。它用公钥加密搜索关键字,用私钥生成搜索凭证。
PEKS 典型场景举例
我记得之前有个医疗数据共享平台的设计,多个医院要把加密的病历上传到一个联邦服务器上。所有医院都使用同一个公钥加密关键字,而卫计委的人拿着私钥查询“肺癌患者”的相关病历。这就是 PEKS 的典型应用。如果换成 SSE,我得给每个医院发一把密钥,密钥分发就成了最头疼的事。
PEKS 的安全性假设比 SSE 更强。在 PEKS 中,攻击者无法区分给定了公钥的两个关键字加密结果。即使用户知道公钥,也无法推断出哪些关键字被加密了。这被称为“选择关键字攻击下的不可区分性”(IND-CKA)。
但硬币总有另一面。PEKS 的性能比 SSE 差很多。为什么呢?因为它依赖双线性对(Bilinear Pairing)运算。
每次匹配测试都需要做一次双线性对计算,而双线性对的计算开销是 AES 加密的几百倍甚至上千倍。
SSE vs PEKS:关键对比
| 维度 | SSE(对称可搜索加密) | PEKS(非对称可搜索加密) |
|---|---|---|
| 密钥关系 | 收发双方共享对称密钥 | 公钥加密,私钥查询 |
| 适用场景 | 单一用户自存储、单用户多设备 | 多发送方给同一接收方的加密场景 |
| 性能效率 | 极快(主要开销在伪随机函数 PRF) | 慢(主要开销在双线性对运算) |
| 安全模型 | KPA(已知明文攻击)或 stronger | IND-CKA(选择关键字攻击) |
| 关键词猜测攻击 | 天生不适用(无公钥) | 内部攻击者可以用 PK 做离线猜测攻击 |
| 查询模式泄露 | 容易泄露(基本方案) | 同样泄露(需引入模糊匹配) |
| 典型算法 | SWP 方案、OXT 方案、Diana | BDOP 方案、BCOP 方案 |
看到这个对比表,不知道你是不是也想到了:为什么没有一个方案能同时兼具 SSE 的高性能和 PEKS 的多发送方能力呢?
嗯,现实就是这么残酷。密码学里经常会有这样的“不可能三角”。
一个实战层面的选型建议
在我经历过的真实项目中,选择 SSE 还是 PEKS,通常遵循以下几条原则:
- 如果只有你一个人存、一个人查 —— 果断选 SSE。性能好,实现简单,安全性足够。
- 如果有多人加密、一人查询 —— 用 PEKS。别纠结性能,功能需求优先。
- 如果需要多人加密、多人查询 —— 两个都不行。你需要更复杂的方案(如 ABK-SE、属性基加密)。
- 如果对查询模式泄露有严格限制 —— 别只选 SSE 或 PEKS,必须叠加 ORAM 或 PIR 等混淆机制。
一个小经验
如果你刚开始学习或做原型,我建议先从 SSE 入手。为什么?因为它的数学基础相对简单(主要是伪随机函数和对称加密),代码实现可以完全自己写。PEKS 涉及双线性对,需要用 PBC 库或 pairing-based cryptography 库,调试起来会复杂得多。
我自己带的实习生,通常第一周能搞定一个简单的 SSE 原型,但要做 PEKS 的 demo,两三天不一定能跑通双线性对的配对运算。
安全和隐私的权衡
讲到这里,必须提一个容易被忽视的点:SSE 的安全假设其实是 KPA(Known-Plaintext Attack)。
什么意思?就是攻击者不能同时看到“明文”和“密文”。但在很多场景下,这是不太现实的。比如你的文档里包含了固定的模板文字,攻击者很容易猜出一部分内容。
PEKS 的安全性更强,因为它用的是公钥加密,明文空间是关键词,理论上更难被破解。但 PEKS 有一个致命弱点——关键词猜测攻击(Keyword Guessing Attack)。
想象一下:攻击者手里有你的公钥 PK,他知道你可能会搜的词语(比如“发票”、“合同”这些常见词),他就可以用 PK 把猜测的关键词加密,然后和你的密文比对。如果匹配,他就知道了你查的是什么词。
我当年第一次看到这个攻击的时候,后背一凉。心里想:“那 PEKS 还有什么用?”
后来发现,解决方法有:
- 加 Salt,让相同关键词每次加密结果不同
- 使用更复杂的方案(如 SCF-PEKS、指定测试者的 PEKS)
但这些方案本质上是在安全性和可用性之间做权衡。没有安全的方案,只有足够安全的方案。
选型时的两个硬约束
1. 如果业务场景允许预计算索引,用 SSE(如日志检索、归档数据)
2. 如果业务场景不允许提前知道谁要查询,用 PEKS(如邮件网关、医疗共享)
强行在一个场景下用另一个方案,最终都会在密钥管理或查询延迟上吃大亏。
这一节的内容,表面上是两个方案的区别,但背后其实是“对称密码 vs 公钥密码”在搜索场景下的延伸。理解了这两条路,再去看具体的方案(比如 OXT、BCOP、Diana),你会发现它们都不外乎是在这两个框架上做优化和修补。
花时间把 SSE 和 PEKS 的原理吃透,后面你读到那几十篇加密搜索时,就能很快抓住核心了。