公钥可搜索加密(Public-Key Encryption with Keyword Search,简称PEKS)定义如下:
PEKSBoneh2004方案构造如下:
令 e : G 1 × G 1 → G 2 e : \mathbb{G}_1 \times \mathbb{G}_1 \to \mathbb{G}_2 e:G1×G1→G2为双线性对,两个函数 H 1 : { 0 , 1 } ∗ → G 1 \mathsf{H}_1 : \{0, 1\}^* \to \mathbb{G}_1 H1:{0,1}∗→G1和 H 2 : G 2 → { 0 , 1 } log p \mathsf{H}_2 : \mathbb{G}_2 \to \{0, 1\}^{\log p} H2:G2→{0,1}logp为哈希函数。
验证正确性:
e ( t d , c 1 ) = e ( H 1 ( w ) α , g r ) = e ( H 1 ( w ) , g α r ) = e ( H 1 ( w ) , h r ) e( {\it td}, c_1) = e(\mathsf{H}_1(w)^\alpha, g^r) = e(\mathsf{H}_1(w), g^{\alpha r}) = e(\mathsf{H}_1(w), h^r) e(td,c1)=e(H1(w)α,gr)=e(H1(w),gαr)=e(H1(w),hr),进一步有 H 2 ( e ( t d , c 1 ) ) = c 2 \mathsf{H}_2(e(\it{td}, c_1)) = c_2 H2(e(td,c1))=c2。
直觉上(非理论层面,非严谨数学思维)对方案构造安全性进行分析:将 H 1 \mathsf{H}_1 H1当成随机谕言机,利用 H 1 \mathsf{H}_1 H1的单向性,敌手 A \mathscr{A} A很难根据 t d {\it td} td逆推出 w w w,同样很难根据 c c c逆推出 w w w。
为什么不直接使用 c : = H ( w ) c := \mathsf{H}(w) c:=H(w)和 t d : = H ( w ) {\it td} := \mathsf{H}(w) td:=H(w)的形式?注意,在该形式中,即使敌手 A \mathscr{A} A没有私钥 α \alpha α,它同样也可以生成有效陷门 t d {\it td} td;但在PEKSBoneh2004方案中,若 A \mathscr{A} A没有私钥 α \alpha α,那么它无法生成正确的陷门 t d {\it td} td。
为什么不直接使用 c : = H ( k , w ) c := \mathsf{H}(k, w) c:=H(k,w)和 t d : = H ( k , w ) {\it td} := \mathsf{H}(k, w) td:=H(k,w)的形式,然后在加密方和搜索方共享一条密钥 k k k?注意,该形式存在密钥管理问题,若有 n n n个加密方,那么搜索方需要将 k k k共享给这 n n n个加密方,加密方有可能是普通用户,不具备安全高防性,其易遭受黑客攻击,从而泄露 k k k。对比之下,在PEKSBoneh2004方案中,加密方仅需持有公钥,私钥泄露的风险大大减小。
并且上述两个做法 w w w对应的 c c c是固定的,若两个加密方同时加密同一 w w w,那么它们产生的两个密文是完全一样的,这显得有点不“安全”,监听者无需攻击服务器(一般假设云服务器具有安全高防性,需重点防范的是监听),仅需监听数据就可以自己对密文相关性进行一个分析。一种粗糙的应对策略是利用服务器的 p k ′ {\it pk}' pk′二次加密 c c c,但这样做服务器需要维护一条公钥 p k ′ {\it pk}' pk′,这增加了云服务商的花费开销,显得有点“不理想”。云服务商可能仅想提供计算服务,由搜索方自己去维护自己的公钥 p k {\it pk} pk。(至于防陷门监听,可以利用对称加密AES,注意,公钥可搜索加密在上传密文阶段是 n n n对 1 1 1,而在搜索阶段是 1 1 1对 1 1 1。)
PEKSBoneh2004方案用到双线性对,这里推荐一个实用的python密码工具库charm-crypto,该工具库由约翰斯·霍普金斯大学科研人员开发,© Copyright 2013, Johns Hopkins University ISI. Last updated on Feb 20, 2018. 写论文若使用该工具进行科研实验,请在Reference中标明
@article{charm13,
year={2013},
issn={2190-8508},
journal={Journal of Cryptographic Engineering},
volume={3},
number={2},
doi={10.1007/s13389-013-0057-3},
title={Charm: a framework for rapidly prototyping cryptosystems},
url={http://dx.doi.org/10.1007/s13389-013-0057-3},
publisher={Springer-Verlag},
keywords={Applied cryptography; Protocols; Software; Privacy},
author={Akinyele, Joseph A. and Garman, Christina and Miers, Ian
and Pagano, Matthew W. and Rushanan, Michael
and Green, Matthew and Rubin, Aviel D.},
pages={111-128},
}
项目地址:http://charm-crypto.io/
#coding=utf-8
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair
import hashlib
Hash1pre = hashlib.md5
def Hash1(w):
# 先对关键词w进行md5哈希
hv = Hash1pre(str(w).encode('utf8')).hexdigest()
print(hv)
# 再对md5值进行group.hash哈希,生成对应密文
# 完整的Hash1由md5和group.hash组成
hv = group.hash(hv, type=G1)
return hv
Hash2 = hashlib.sha256
def Setup(param_id='SS512'):
# 代码符号G1 x G2 → GT
group = PairingGroup(param_id)
# 方案选用的是对称双线性对,故G2 = G1
g = group.random(G1)
alpha = group.random(ZR)
# 生成私钥与公钥并进行序列化
# Serialize a pairing object into bytes
sk = group.serialize(alpha)
pk = [group.serialize(g), group.serialize(g ** alpha)]
return [sk, pk]
def Enc(pk, w, param_id='SS512'):
group = PairingGroup(param_id)
# 进行反序列化
g, h = group.deserialize(pk[0]), group.deserialize(pk[1])
r = group.random(ZR)
t = pair(Hash1(w), h ** r)
c1 = g ** r
c2 = t
# 对密文进行序列化
print(group.serialize(c2))
return [group.serialize(c1), Hash2(group.serialize(c2)).hexdigest()]
def TdGen(sk, w, param_id='SS512'):
group = PairingGroup(param_id)
sk = group.deserialize(sk)
td = Hash1(w) ** sk
# 对陷门进行序列化
return group.serialize(td)
def Test(td, c, param_id='SS512'):
group = PairingGroup(param_id)
c1 = group.deserialize(c[0])
c2 = c[1]
print(c2)
td = group.deserialize(td)
return Hash2(group.serialize(pair(td, c1))).hexdigest() == c2
if __name__ == '__main__':
# 'SS512'是对称双线性对
param_id = 'SS512'
[sk, pk] = Setup(param_id)
group = PairingGroup(param_id)
c = Enc(pk, "yes")
td = TdGen(sk, "yes")
assert(Test(td, c))
td = TdGen(sk, "no")
assert(not Test(td, c))
c = Enc(pk, "Su*re")
assert(not Test(td, c))
c = Enc(pk, "no")
assert(Test(td, c))
c = Enc(pk, 9 ** 100)
td = TdGen(sk, 9 ** 100)
assert(Test(td, c))
td = TdGen(sk, 9 ** 100 + 1)
assert(not Test(td, c))
[1] Dan Boneh, Giovanni Di Crescenzo, Rafail Ostrovsky, et al. Public Key Encryption with Keyword Search[C]// Advances in Cryptology - EUROCRYPT 2004, International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004, Proceedings. 2004.
[2] 双线性对映射 概念理解