3. 可搜索加密概述:对称可搜索加密(SSE)、非对称可搜索加密

上一章我们把盲索引的概念讲清楚了。说白了,就是把明文信息藏到一个「只有钥匙才能打开的小盒子」里,然后在盒子上贴一些暴露的标签,方便你找到它。

那问题来了——谁来做这个小盒子?谁拿着钥匙去查?这就引出了可搜索加密的两大门派:对称可搜索加密(SSE)和非对称可搜索加密(也叫公钥可搜索加密,PEKS)。

我记得刚入行那会儿,老板让我调研可搜索加密方案。我在海里翻了三天,才弄明白这两个流派的核心区别。嗯,说白了就一个问题:加密和解密的钥匙,是不是同一把。

3.1 对称可搜索加密(SSE)——单钥匙方案

对称可搜索加密,你猜对了——加密数据用一把钥匙,搜索也用同一把钥匙。典型的结构是,数据拥有者自己加密数据,构建索引,然后自己拿着钥匙去搜。

我在项目中遇到过一个小型的文档加密系统,就是用的SSE方案。逻辑很直接:

  1. 数据拥有者把文档分词,对每个词生成一个 密文标签(就是盲索引中的那个标签)
  2. 把这些标签和加密文档一起上传到云服务器
  3. 想搜索的时候,用同一把钥匙对关键词加密,生成一个 搜索令牌()
  4. 服务器收到令牌,去密文标签列表里匹配,返回匹配结果

听起来很简单,对吧?但SSE有个硬伤:钥匙分发问题。数据拥有者想给别人查询权限,就必须把钥匙交出去。交出去之后,人家不但能搜,还能解密你的文档。这就很头疼了。

SSE的核心优势: 效率极高。对称加密的速度比公钥加密快好几个数量级,做倒排索引和布尔查询非常顺畅。

给你看一段简化的SSE搜索令牌生成和查询的伪代码——注意,这里只是逻辑示意,不是正经的实现。

// 生成搜索令牌
function generateSearchToken(keyword, secretKey):
    // 用伪随机函数(PRF)对关键词进行加密
     = PRF(secretKey, keyword)
    return 

// 服务端匹配
function searchOnServer(, encryptedIndex):
    for each entry in encryptedIndex:
        // 比较密文标签是否匹配
        if slow_equals(entry.label, ):
            results.append(entry.encryptedDocId)
    return results

你对这段代码可能觉得眼熟——没错,跟我上一章讲的「朴素标签索引法」很像。SSE其实就是盲索引在加密搜索领域的标准实现之一。

3.2 非对称可搜索加密(PEKS)——双钥匙方案

非对称可搜索加密就有点意思了。它用 公钥 加密数据和关键词,用 私钥 生成搜索令牌。数据拥有者可以把公钥公开,谁都可以往你的加密数据库里写入数据,但只有拿着私钥的人才能搜。

为什么会这样?你想想看,在实际应用中,往往是多用户往一个数据库里写入数据的情况——比如邮件系统,Alice、Bob、Charlie都给同一台邮件服务器发加密邮件,但只有邮件拥有者(比如你自己)才能搜。

我记得有一次帮一个医疗联盟做方案,多个实验室要给协作平台的病例库写入加密报告,但只有主治医生能搜报告内容。当时我就推荐了公钥可搜索加密。

实用小技巧: 非对称方案虽然灵活,但查询速度远不如对称方案。如果系统用户量不大、数据量也不大,用PEKS是可以的。数据量大到百万级,PEKS的配对运算会严重拖慢搜索响应。

PEKS的典型流程如下:

  • 发送方:用公钥加密关键词,生成可搜索密文,随加密数据一并发送给服务器
  • 接收方:用私钥生成某个关键词的搜索门限(trapdoor),发给服务器
  • 服务器:运行测试算法,检查门限与已有密文是否匹配

伪代码示意一下:

// 发送方:用公钥生成可搜索密文
function PEKS_Encrypt(publicKey, keyword):
    r = rand()
    // 典型的双线性配对运算
    out = H1( e( H2(keyword), publicKey^r ) )
    return out

// 接收方:用私钥生成搜索门限
function PEKS_Trapdoor(privateKey, keyword):
    return H2(keyword)^privateKey

// 服务器:测试匹配
function PEKS_Test(trapdoor, ciphertext):
    // 检查是否 e(trapdoor, g_r) == ciphertext
    result = H1( e(trapdoor, g_r) )
    return result == ciphertext

嗯,这里要注意——非对称方案的这个「测试算法」里,服务端只能做「是与否」的测试,不能提取关键词的任何信息。这是非对称方案的一个安全特性,但也是它的性能瓶颈(配对运算太耗时了)。

3.3 对称 vs 非对称:怎么选?

我直接给你一个我在项目中一直用的决策对照表:

维度 对称可搜索加密(SSE) 非对称可搜索加密(PEKS)
加密方式 对称加密(单钥匙) 公钥加密(双钥匙)
查询模式 单用户/少数信任用户 多用户写入 + 单用户搜索
功能扩展 容易支持布尔查询、范围查询 功能扩展较困难,典型是等值匹配
计算开销 极低(哈希、对称加密) 极高(双线性配对运算)
安全性 可达到自适应安全 可达到选择关键词攻击安全
适用场景 个人云盘搜索、企业内部文档搜索 加密邮件路由、多方数据上传场景
我曾经踩过的一个坑: 做一个医疗影像共享平台时,我一开始选了PEKS方案,觉得多个医院上传数据,一个中心搜索,很匹配。结果上线后查询速度惨不忍睹。后来我反思了一下——其实可以用SSE + 代理重加密的方案,把钥匙托管在可信任的代理模块里,既支持多写,又享受SSE的高效查询。所以,不要看到多用户就无脑用PEKS。

3.4 一张图看懂可搜索加密的流派

下面这张图我画了一下可搜索加密的两大分支。你看一下,整体脉络就很清晰了:

可搜索加密两大流派 对称可搜索加密 (SSE) 非对称可搜索加密 (PEKS) 单钥匙:加密=搜索 双钥匙:加密≠搜索 典型:倒排索引+PRF令牌 典型:双线性配对+门限 决策依据:效率优先选SSE

从图上你也能看出来,SSE和PEKS的适用场景基本是互补关系。SSE快、省资源,但是钥匙管理有隐患;PEKS灵活、支持多用户写入,但是慢得让人抓狂。

在实际选型时,我建议你不要只看里的「通用方案」,而是要问自己三个问题:

  1. 谁写数据?——单用户写还是多用户写?
  2. 谁查数据?——只有钥匙持有者查,还是多方共享查询能力?
  3. 延迟敏感吗?——响应时间能不能超过100ms?

对这个问题的答案,基本就决定了你该选SSE还是PEKS,或者——其实还有第三条路,也就是混合方案,这个我们在后面的章节里会详细讲。