1.簡介
- 相關(guān)論文:An efficient privacy-preserving outsourced calculation toolkit with multiple keys政勃。這篇論文由Ximeng LIU,RobertH.DENG,Kim-Kwang Raymond CHOO,Jian WENG發(fā)表于TIFS(IEEE Transactions on Information Forensics and Security)渠概。該論文針對BCP算法構(gòu)建的多密鑰下同態(tài)運算的方案提出一些改進(改進后的方案稱為:DT-PKC)赐稽,將可以解密的系統(tǒng)主密鑰(
),拆分為兩個部分,任何一個部分都不能單獨解密。這樣可以解決中心節(jié)點擁有主密鑰所產(chǎn)生的安全性問題。
- 本文主要介紹其對BCP算法的改進部分,即如何拆分主密鑰及拆分主密鑰后的解密運算教翩。
- 關(guān)于BCP加密算法的簡介:參考文章BCP加密算法復(fù)現(xiàn)記錄。
2.DT-PKC復(fù)現(xiàn)記錄
2.1 環(huán)境配置
- 參考:BCP加密算法復(fù)現(xiàn)記錄贪壳。
2.2 重要步驟說明
- 導(dǎo)入依賴的庫及函數(shù)
from charm.toolbox.integergroup import IntegerGroup
from charm.schemes.pkenc.pkenc_rsa import RSA_Enc, RSA_Sig
from charm.core.math.integer import integer,randomBits,random,randomPrime,isPrime,encode,decode,hashInt,bitsize,legendre,gcd,lcm,serialize,deserialize,int2Bytes,toInt
- 第一步:初始化饱亿,生成公共參數(shù)及系統(tǒng)主密鑰。
首先選取一個安全參數(shù)闰靴,之后選取兩個安全素數(shù)(safe prime)
彪笼,使其位長度(bit length)為
,根據(jù)安全素數(shù)的定義蚂且,
和
也是素數(shù)配猫。之后計算
和
(
最小公倍數(shù))。定義一個函數(shù):
杏死。選取一個
階元
泵肄,
可以通過隨機選取
,計算
獲得捆交,相關(guān)論文:Universal Hash Proofs and a Paradigm for Adaptive Chosen Ciphertext Secure Public-Key Encryption。這樣,系統(tǒng)的主密鑰
腐巢。
相關(guān)代碼:
def __init__(self,secparam = 128):
self.p,self.q = randomPrime(secparam,True),randomPrime(secparam,True)
self.pp = (self.p - 1)/2
self.qq = (self.q - 1)/2
self.N = self.p * self.q
self.N2 = self.N**2
self.lamda = lcm(self.p-1,self.q-1)/2
# 一下為選取一個(p-1)(q-1)/2階元
# 先隨機選取a
self.a = random(self.N2)
# 計算a^2N
tmp = self.a**(2*self.N)
# 計算-a^2N
self.g = (int(self.N2)-int(tmp))%self.N2
self.mk = self.lamda
- 第二步:密鑰生成品追。
隨機選取,計算
冯丙。公鑰
肉瓦,私鑰
。
相關(guān)代碼:
def KeyGen(self):
theta = random(self.N/4)
h = self.g**(theta)%self.N2
pk = {"N":self.N,"g":self.g,"h":h}
sk = theta
return pk,sk
- 第三步:加密胃惜。
明文空間:泞莉,選取隨機數(shù)
。這樣使用公鑰
加密
得到密文可以表示為
蛹疯,
,
热监。
相關(guān)代碼:
def Encrypt(self,pk,plaintext):
r = random(self.N/4)
T1 = int(pk["h"]**(r))*int(1+plaintext*self.N) % self.N2
T2 = pk["g"]**(r) % self.N2
ciphertext = {"T1":T1,"T2":T2}
return ciphertext
- 第四步:使用私鑰解密捺弦。
密文可以由私鑰
解密,解密公式:
孝扛。
相關(guān)代碼:
def Decrypt(self,ciphertext,sk):
T1 = ciphertext["T1"]
T2 = ciphertext["T2"]
tmp = (T1 / (T2**sk)) % self.N2
m = (int(tmp)-1)/self.N
return m
- 第五步:使用主密鑰解密列吼。
密文還可以由主密鑰
解密。首先計算
苦始,由于
寞钥,
。
相關(guān)代碼:
def DecryptMK(self,ciphertext,mk):
tmp = ciphertext["T1"]**(mk) % self.N2
mk = mk % self.N
mk_1 = mk**(-1)
m = ((int(tmp)-1)/self.N)*int(mk_1)%self.N
return integer(m)
- 第六步:主密鑰切分陌选。
主密鑰可以被隨機切分為兩個部分
理郑,需要滿足
并且
。下面分析可以這樣切分的原因:
根據(jù)中國剩余定理咨油,由于您炉,因此存在
,使得
并且
役电,且
赚爵,參考:C. Ding, Chinese Remainder Theorem. Singapore: World Scientific,1996.
這樣,只需隨機選取法瑟,使得
即可冀膝,相關(guān)代碼:
def SplitMK(self,mk):
mk = mk % self.N
mk_1 = mk**(-1)
tmp = int(mk)*int(int(mk_1)%self.N2)
modulus = int(mk)*int(self.N2)
s = tmp % modulus
lamda1 = random(s)
lamda2 = s - int(lamda1)
return integer(lamda1),integer(lamda2)
- 第七步:利用切分后的主密鑰進行解密。
這一步又可以分為兩小步:
1)利用部分主密鑰得到中間結(jié)果
:
霎挟。相關(guān)代碼:
def PSDec1(self,ciphertext,lamda1):
ct1 = ciphertext["T1"]**(lamda1)
return ct1
2)利用部分主密鑰與中間結(jié)果
計算首先得到
窝剖,之后利用
計算得到結(jié)果:
,
,
酥夭。相關(guān)代碼:
def PSDec2(self,ciphertext,lamda2,ct1):
ct2 = ciphertext["T1"]**(lamda2)
T = ct1*ct2
m = (int(T)-1)/int(self.N)
return integer(int(m))
- 完整代碼:
from charm.toolbox.integergroup import IntegerGroup
from charm.schemes.pkenc.pkenc_rsa import RSA_Enc, RSA_Sig
from charm.core.math.integer import integer,randomBits,random,randomPrime,isPrime,encode,decode,hashInt,bitsize,legendre,gcd,lcm,serialize,deserialize,int2Bytes,toInt
class DTPKC():
def __init__(self,secparam = 128):
self.p,self.q = randomPrime(secparam,True),randomPrime(secparam,True)
self.pp = (self.p - 1)/2
self.qq = (self.q - 1)/2
self.N = self.p * self.q
self.N2 = self.N**2
self.lamda = lcm(self.p-1,self.q-1)/2
self.a = random(self.N2)
tmp = self.a**(2*self.N)
self.g = (int(self.N2)-int(tmp))%self.N2
self.mk = self.lamda
def GetMK(self):
return self.mk
def KeyGen(self):
theta = random(self.N/4)
h = self.g**(theta)%self.N2
pk = {"N":self.N,"g":self.g,"h":h}
sk = theta
return pk,sk
def Encrypt(self,pk,plaintext):
r = random(self.N/4)
T1 = int(pk["h"]**(r))*int(1+plaintext*self.N) % self.N2
T2 = pk["g"]**(r) % self.N2
ciphertext = {"T1":T1,"T2":T2}
return ciphertext
def Decrypt(self,ciphertext,sk):
T1 = ciphertext["T1"]
T2 = ciphertext["T2"]
tmp = (T1 / (T2**sk)) % self.N2
m = (int(tmp)-1)/self.N
return m
def DecryptMK(self,ciphertext,mk):
tmp = ciphertext["T1"]**(mk) % self.N2
mk = mk % self.N
mk_1 = mk**(-1)
m = ((int(tmp)-1)/self.N)*int(mk_1)%self.N
return integer(m)
def SplitMK(self,mk):
mk = mk % self.N
mk_1 = mk**(-1)
tmp = int(mk)*int(int(mk_1)%self.N2)
modulus = int(mk)*int(self.N2)
s = tmp % modulus
lamda1 = random(s)
lamda2 = s - int(lamda1)
return integer(lamda1),integer(lamda2)
def PSDec1(self,ciphertext,lamda1):
ct1 = ciphertext["T1"]**(lamda1)
return ct1
def PSDec2(self,ciphertext,lamda2,ct1):
ct2 = ciphertext["T1"]**(lamda2)
T = ct1*ct2
m = (int(T)-1)/int(self.N)
return integer(int(m))
3.測試
- 測試代碼:
if __name__ == "__main__":
dt_pkc = DTPKC()
mk = dt_pkc.GetMK()
print("mk is:",mk)
pk,sk = dt_pkc.KeyGen()
print("------------------------------")
print("pk is:",pk,"sk is:",sk)
plaintext = 1024
print("------------------------")
print("plaintext is:",plaintext)
ciphertext = dt_pkc.Encrypt(pk,1024)
print("------------------------")
print("ciphertext is:",ciphertext)
m1 = dt_pkc.Decrypt(ciphertext,sk)
print("-------------------------")
print("Using sk to decrypt ciphertext,result is:",m1)
m2 = dt_pkc.DecryptMK(ciphertext,mk)
print("-------------------------")
print("Using mk to decrypt ciphertext,result is:",m2)
lamda1,lamda2 = dt_pkc.SplitMK(mk)
print("-------------------------")
print("lamda1 is:",lamda1)
print("lamda2 is:",lamda2)
print("now we use lamda1 and lamda2 to decrypt:")
ct1 = dt_pkc.PSDec1(ciphertext,lamda1)
print("-------------------------")
print("The middle result is:",ct1)
print("-------------------------")
m3 = dt_pkc.PSDec2(ciphertext,lamda2,ct1)
print("Using lamda1 and lamda2 to decrypt ciphertext,result is:",m3)
- 測試結(jié)果:加解密運算正確
mk is: 22338062150910213287096358186084458203294109371215927224896109781996280749289
------------------------------
pk is: {'N': 89352248603640853148385432744337832813774312926927445628961672829724410984689, 'g': 5796069204765623542573279877045795421667308892848339471072299243822410092499008991382506301127284670227987017148628307351991077555531163469032056732101199 mod 7983824330526838791274511562029416677868477739833493115159981949744753275885355914958363600037866383924640499394589563036708131942917863905100086592426721, 'h': 7935721887038910245545505888433794372349511663547277093912096084521177913556538675688906850177251874779422538574782147394495941080326621060611267735334082 mod 7983824330526838791274511562029416677868477739833493115159981949744753275885355914958363600037866383924640499394589563036708131942917863905100086592426721} sk is: 76204058112965194407732331957567427660809926855819726246456305039472675957297 mod 89352248603640853148385432744337832813774312926927445628961672829724410984689
------------------------
plaintext is: 1024
------------------------
ciphertext is: {'T1': 1189202078396194739872313433810947540535206630405742685355335605588797450138354847755661690141041049479509074532983600670745074186493313833872690728336707 mod 7983824330526838791274511562029416677868477739833493115159981949744753275885355914958363600037866383924640499394589563036708131942917863905100086592426721, 'T2': 2031968094987867056707267176620567341361755305640188891998505629184921793767586718829208072634700218440322730486634379570080555010326243084347844702963534 mod 7983824330526838791274511562029416677868477739833493115159981949744753275885355914958363600037866383924640499394589563036708131942917863905100086592426721}
-------------------------
Using sk to decrypt ciphertext,result is: 1024
-------------------------
Using mk to decrypt ciphertext,result is: 1024
-------------------------
lamda1 is: 1505802704812095957081963280847475955421013132898588206367067311511714138058340080719320579687618270014411099365999155016669463468104328753042522940931295
lamda2 is: 260804022002047759634149184903924934389916372259491181826426268699503308739361628589967413175895360769713621921485147556575752847045942699929051799977835
now we use lamda1 and lamda2 to decrypt:
-------------------------
The middle result is: 3433002371868990949360033462226377385418613313243722104147586473147340479553469853206909391421965360453688842498974729295524950767714321345265678668705251 mod 7983824330526838791274511562029416677868477739833493115159981949744753275885355914958363600037866383924640499394589563036708131942917863905100086592426721
-------------------------
Using lamda1 and lamda2 to decrypt ciphertext,result is: 1024