对称可搜索加密(SSE)原理:方案模型、安全定义、陷门生成
对称可搜索加密,缩写 SSE,是聊可搜索加密时绕不开的基础。我刚开始接触这玩意儿时觉得它挺玄乎——怎么在密文上做搜索呢?后来才明白,说白了就是先给关键词建个加密索引,搜的时候拿陷门去匹配,全程不泄露明文。
这一章咱们把它的核心三块拆开看:方案模型长什么样,安全定义到底保护什么,陷门又是怎么生成的。嗯,讲完这些,你再看 SSE 的就不会一头雾水了。
3.1 方案模型:角色、算法与数据流
先看角色。一共三个:
- 数据所有者(Data Owner):拥有明文数据,负责加密并上传。
- 用户(User):被授权搜索的人,掌握密钥,能生成陷门。
- 服务器(Server):存储加密数据,收到陷门后执行搜索并返回结果。
我早期做 SSE 实现时,经常把“数据所有者”和“用户”混在一起,后来发现多用户场景下权限管理才是大头。不过单用户模型是基础,先搞懂它。
标准 SSE 方案包含四个算法,我习惯用一个表格来记它们:
| 算法 | 输入 | 输出 | 一句话说明 |
|---|---|---|---|
KeyGen(1^λ) |
安全参数 λ | 密钥 K | 生成对称密钥 |
BuildIndex(K, D) |
密钥 K,文档集 D | 加密索引 I + 密文文档 C | 为每个关键词建立倒排索引并加密 |
Trapdoor(K, w) |
密钥 K,关键词 w | 陷门 T_w | 伪随机函数或哈希算出陷门,唯一对应 w |
Search(I, T_w) |
加密索引 I,陷门 T_w | 文档标识符集合 R | 扫描索引,匹配陷门,返回结果 |
BuildIndex 阶段用了非定长的加密方式,导致索引膨胀严重。后来换用定长布谷鸟过滤器 + 伪随机置换,性能才稳下来。
数据流其实很简单。数据所有者先跑 KeyGen 得到密钥,再用 BuildIndex 把文档集变成加密索引和密文包,一股脑丢给服务器。用户想搜“密码学”这个词,就用自己的密钥算个陷门发给服务器。服务器拿陷门在索引里比一比,找出所有匹配的文档 ID 返回。用户再用密钥解密那些文档就行。
你想想看,这个过程中服务器始终只看到加密数据和陷门,根本不知道搜的是什么词,也不知道文档内容,这就叫“可搜索加密”。
3.2 安全定义:泄露什么,保护什么
SSE 的安全模型,大家最常用的是 自适应选择关键词攻击安全(CKA2)。别被名字吓到,本质上在回答一个问题:攻击者(服务器)能从加密索引和陷门中推出多少信息?
理想情况下,我们希望服务器除了“知道哪些文档包含同一个关键词”之外,其他什么都学不到。但实际方案总要泄露一点东西,比如:
- 搜索模式(Search Pattern):同样的关键词是否被搜过多次。
- 访问模式(Access Pattern):哪些文档被返回。
- 大小模式(Size Pattern):索引中的条目数量。
安全定义通常用“真实游戏”和“理想游戏”的不可区分性来描述。简而言之:如果存在一个模拟器,它能在只知道泄露函数 L 的情况下,生成与真实协议无法区分的视图,那么方案就是安全的。
我建议你把泄露函数 L 当作一个“必须接受的代价”。比如 SS-1 方案的泄露函数 L 通常包含:
L = (搜索模式, 访问模式, 索引大小)
而方案越安全,泄露越少,但效率往往越低。选择哪个,取决于你的业务场景。
3.3 陷门生成:伪随机与可验证
陷门是搜索的“钥匙”。它必须做到:同一个关键词每次生成不同的陷门吗?不一定。早期方案采用确定性陷门——同一个 w 永远映射到同一个陷门。好处是服务器可以快速比对,坏处是搜索模式完全暴露。
现在的方案更倾向于使用 伪随机函数(PRF) 加状态来生成陷门。比如:
T_w = PRF(K, w) // 经典方式,确定性
T_w = PRF(K, w || c) // c 是计数器,每次搜索不同
我做过一个项目,需要对医保数据做关键词搜索。当时用了 Google 的 Key Transparency 里迭代的陷门设计——每次陷门关联一个随机 nonce,服务器虽然能判断两个陷门是否对应同个关键词,但无法链接不同的会话。这样既保证了效率,又增加了隐私。
另外,陷门生成时要注意 可验证性。服务器返回结果后,用户怎么知道服务器没有跳过一些匹配的文档?对于 SSE,一般通过在索引中嵌入验证标签或使用默克尔树来保证完整性。这块我后面章节会细讲。
3.4 知识体系总览图
下面这张图总结了 SSE 方案的核心逻辑,你可以对照着看整个流程:
3.5 实战选型建议
看到这里你可能想问:我到底该用哪种 SSE 方案?我给个参考:
- 静态数据集 + 少量关键词:直接用 Song-Wagner-Perrig 的经典方案(SWP)。实现简单,代码量小。
- 动态更新频繁:选支持更新的方案,比如 DSSE(动态对称可搜索加密)或 MITRA 变体。注意处理删除时的索引重组,我曾经吃过“只加不删”的亏,后面索引越积越大。
- 需要隐藏访问模式:考虑用 ORAM 包装 SSE,但务必先做性能测试——我见过一个金融项目因为没测 ORAM 延迟,上线后查询超时。
libsse 或 py-SSE 跑通一条链路,再根据业务需求调整索引结构。这样能快速验证陷门生成和搜索逻辑,避免从零造轮子踩坑。
好,这一章就到这。SSE 的方案模型、安全定义和陷门生成,这三块是后续所有可搜索加密技术的基石。你把它吃透了,后面学盲索引、动态 SSE、安全范围查询都会轻松很多。记住核心:加密索引 + 陷门匹配,泄露控制在可接受范围内。