论文复现:基于盲存储的动态可搜索对称加密技术》- 操作说明与代码详细注解
注意index里存的是HMAC处理后的关键词指纹。当我们要添加包含"urgent"关键词的文档时,系统不会直接存这个单词,而是存储它的密码学指纹——相当于给每个关键词戴了面具。注意看index结构,攻击者就算拿到数据库,也只能看到一堆随机字符串对应文档ID,根本不知道原始关键词是什么。今天咱们来盘一个既能动态更新又能快速搜索的加密方案,基于《Blind Storage》这篇论文的实现思路。动态可搜
动态可搜索对称加密 论文复现《Dynamic Searchable Encryption via Blind Storage》 动态可搜索对称加密运行客户在服务器上存储加密文档的动态集合 并在这些加密文档上快速执行关键字搜索 #包含操作说明 代码详细注解
把数据隐私和查询效率放在一个系统里折腾,总得整点有意思的活。今天咱们来盘一个既能动态更新又能快速搜索的加密方案,基于《Blind Storage》这篇论文的实现思路。先扔个代码片段热热身:
class BlindStorage:
def __init__(self, key_size=256):
self.index = defaultdict(list) # 关键词 -> [加密文档ID列表]
self.doc_store = {} # 文档ID -> 密文
self.key = os.urandom(key_size//8) # AES密钥生成
def _pseudo_random_func(self, keyword):
hmac_obj = HMAC.new(self.key, digestmod=sha256)
hmac_obj.update(keyword.encode())
return hmac_obj.hexdigest()
这段看着像普通存储结构?注意index里存的是HMAC处理后的关键词指纹。当我们要添加包含"urgent"关键词的文档时,系统不会直接存这个单词,而是存储它的密码学指纹——相当于给每个关键词戴了面具。
动态添加文档的操作挺有意思:
def add_document(self, doc_id, keywords, content):
# 加密内容
cipher = AES.new(self.key, AES.MODE_CTR)
ciphertext = cipher.encrypt(pad(content.encode(), AES.block_size))
# 更新关键词索引
for kw in set(keywords):
token = self._pseudo_random_func(kw)
self.index[token].append(doc_id)
# 存储加密文档
nonce = cipher.nonce # 保留随机数用于解密
self.doc_store[doc_id] = (nonce, ciphertext)
这里有两个骚操作:1)用CTR模式加密避免相同内容产生相同密文;2)关键词去重后生成索引。注意看index结构,攻击者就算拿到数据库,也只能看到一堆随机字符串对应文档ID,根本不知道原始关键词是什么。

搜索过程更带劲:
def search(self, keyword):
search_token = self._pseudo_random_func(keyword)
matched_ids = self.index.get(search_token, [])
results = []
for doc_id in matched_ids:
nonce, ciphertext = self.doc_store[doc_id]
cipher = AES.new(self.key, AES.MODE_CTR, nonce=nonce)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
results.append(plaintext.decode())
return results
整个过程就像拿着特制磁卡开快递柜——服务器只能验证搜索令牌是否匹配,但完全不知道你在找什么关键词。这种设计巧妙避开了传统方案需要遍历整个数据库的问题,时间复杂度直接降到O(1)。
实际跑起来的时候要注意几个坑:
- 密钥管理得用硬件安全模块(HSM)或者KMS服务
- 文档ID建议用UUID4生成避免规律性
- 定期刷新密钥时需要重新加密所有文档(可用密钥派生解决)
测试时用pytest写个简单用例:
def test_dynamic_update():
storage = BlindStorage()
doc_id = uuid4().hex
# 添加包含两个关键词的文档
storage.add_document(doc_id, ["project", "secret"], "设计图纸V3")
# 正常搜索
assert len(storage.search("project")) == 1
# 删除操作(论文中的核心动态特性)
storage.delete_document(doc_id)
assert len(storage.search("project")) == 0
删除功能实现有个精妙之处:直接在索引里移除对应文档ID,而不用动密文存储。这种惰性删除策略既能保证实时性,又避免了全量扫描的开销。
最后说个优化方向:实际部署时可以给index加布隆过滤器,把常见误搜请求提前拦截。或者用LRU缓存高频搜索词的结果,毕竟每次HMAC计算还是有点小贵的。代码仓库里已经放了带注释的完整实现,需要自取。

更多推荐
所有评论(0)