BCP加密算法复现记录

1.BCP算法简介

2.复现BCP加密算法

2.1 环境配置

2.2 重要步骤说明

  • 首先需要从Charm包中导入相关的函数、类。
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

这些函数的作用可以根据其名字推断,例如randomPrime是随机找一个质数,isPrime是判断一个数是否为质数,等等。

  • 第一步:初始化,生成公共参数和系统主密钥。
    选择一个安全参数secparam,用来表示位长度(一个整数转换为二进制后的长度,称为位长度)。选取两个安全素数p,q,之后计算p^{'} = (p -1)/2,q^{'} = (q-1)/2,根据安全素数的定义,p^{'}q^{'}也都是素数。之后计算N = pq作为模数,使其位长度为secparam。之后选取g\in Z^*_{N^2}(Z^*_{N^2}表示从1到N^2所有与N^2互质的数),使得g的阶(群中元素的阶的概念)为pp^{'}qq{'},并且使得g^{p^{'}q^{'}} mod N^2 = 1+ k N,k\in[1,N-1]。这样明文空间是Z_N,公共参数PP = (N,k,g),主密钥MK = (p^{'},q^{'})
    相关代码如下:
def __init__(self,secparam=1024,param = None):
        # 安全参数secparam被设置为1024,即默认的位长度是1024
        # 可以指定参数
        if param:
            self.N2 = param.N2
            self.N = param.N
            self.g = param.g
            self.k = param.k   
        # 如果未指定参数         
        else:
            # p,q用randomPrime()函数生成,位长度是512位(N=pq,要求N是1024位,则p,q为512位)
            # 第二个参数设置为True,表示是安全素数,即可以保证(p-1)/2和(q-1)/2也是素数
            self.p, self.q = randomPrime(int(secparam/2),True), randomPrime(int(secparam/2),True) 
            # pp,qq对应p',q'
            self.pp = (self.p -1)/2
            self.qq = (self.q - 1)/2
            # N = pq
            self.N = self.p * self.q
            # 下面这段while逻辑,是要找一个好的N
            while True: 
                if bitsize(self.N) ==secparam and len(int2Bytes(self.N)) == int(secparam/8) and int2Bytes(self.N)[0] &128 !=0:
                    break
                self.p, self.q = randomPrime(int(secparam/2),True), randomPrime(int(secparam/2),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.g = random(self.N2)
            one = integer(1)% self.N2
            # 下面这段逻辑,是找到一个好的g
            while True: 
                # 经过下面两步,保证g足够随机
                self.g = random(self.N2)
                self.g = integer((int(self.g)-1)*(int(self.g)-1))% self.N2
                # 保证g的阶不是0
                if self.g == one:
                    continue
                # 保证g的阶不是p
                tmp = self.g**self.p %self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是p'
                tmp = self.g**self.pp % self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是q
                tmp = self.g**self.q %self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是q'
                tmp = self.g**self.qq %self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是pp'
                tmp =self.g**(self.p*self.pp) % self.N2
                if tmp == one:
                    continue 
                # 保证g的阶不是pq
                tmp = self.g**(self.p*self.q) %self. N2
                if tmp== one:
                    continue 
                # 保证g的阶不是pq'
                tmp = self.g**(self.p*self.qq) % self.N2
                if tmp == one:
                    continue 
                # 保证g的阶不是p'q
                tmp = self.g**(self.pp*self.q) % self.N2
                if tmp == one:
                    continue 
                # 保证g的阶不是p'q'
                tmp = self.g**(self.pp*self.qq) % self.N2
                if tmp == one:
                    continue 
                # 保证g的阶不是qq'
                tmp = self.g**(self.q*self.qq) % self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是pp'q
                tmp = self.g**(self.p*self.pp*self.q) % self.N2
                if tmp == one:
                    continue   
                # 保证g的阶不是pp'q'
                tmp =self.g**(self.p*self.pp*self.qq) % self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是pqq'
                tmp =self.g**(self.p*self.q*self.qq) % self.N2
                if tmp == one:
                    continue
                # 保证g的阶不是p'qq'
                tmp =self.g**(self.pp*self.q*self.qq) % self.N2
                if tmp == one:
                    continue  
                break 
            # 求得k
            self.k = integer((int(self.g**(self.pp*self.qq)) - 1)) / self.N % self.N
            # 获得主密钥
            self.MK ={"pp":self.pp,"qq":self.qq}
  • 第二步:生成密钥
    根据公共参数PP = (N,k,g)生成密钥。
    随机选择\alpha \in Z_{N^2},计算h = g^\alpha mod N^2,公钥pk = h私钥sk = \alpha
    相关代码:
    def KeyGen(self):
        tmp = self.N2 /2
        sk = random(tmp) % self.N2
        pk = (self.g**sk) % self.N2
        return pk,sk
  • 第三步:加密
    明文m \in Z_N,随机选取r \in Z_{N^2},利用公钥pk = h加密得到密文(A,B),其中A = g^r mod N { ^2}B = h^r(1+mN) mod N^2
    相关代码:
def Encrypt(self,pk,plaintext):
        r = random(self.N/4) % self.N2
        A = (self.g** r ) % self.N2 
        B1 = (self.N*plaintext+1)% (self.N2)
        B2 = (pk**r) % (self.N2)
        B = B1*B2 % self.N2
        ciphertext = {"A":A,"B":B}
        return ciphertext
  • 第四步:解密
    当一个明文m由公钥pk = h加密得到密文(A,B)后,利用私钥sk = \alpha进行解密,解密公式:m = \frac{(B/(A^\alpha)-1)mod N^2} {N}
    相关代码:
    def Decrypt(self,ciphertext,sk):
        t1 = integer(int(ciphertext['B']*((ciphertext['A']**-1)**sk)) -1) % self.N2
        m = integer(t1) / self.N
        return m
  • 第五步:利用主密钥解密
    当一个明文m由公钥pk = h加密得到密文(A,B)后,还可以使用主密钥MK = (p^{'},q^{'})进行解密。解密步骤如下:
    首先计算私钥(\alpha) mod N = {(h^{p^{'}q^{'}}-1)mod N^2\over N}.k^{-1}mod N ,这里k^{-1}表示kN的逆。
    之后计算加密步骤中选取的随机数(r )mod N = {(A^{p^{'}q^{'}}-1)mod N^{2}\over N}.k^{-1}mod N
    \delta表示p^{'}q^{'}N的逆,并且令\gamma = (\alpha r)modN,这样明文m = {((B/(g^{\gamma}))^{p^{'}q^{'}}-1)mod N^{2}\over N}\delta mod N
    相关代码:
def DecryptMK(self,ciphertext,MK,pk):
        k_1 = self.k ** -1
        tmp = (int(pk**(MK['pp']*MK['qq'])) -1) % self.N2
        tmp = integer(tmp) /self.N 
        a = tmp * integer(k_1) % self.N
        
        tmp = (int(ciphertext['A'] **(MK['pp']*MK['qq'])) -1) % self.N2
        tmp = integer(tmp) /self.N 
        r = tmp * integer(k_1) % self.N
        
        gama = a*r %self.N
        sig = ((MK['pp']*MK['qq'])%self.N) **-1
        
        tmp = (self.g **-1)**gama
        tmp = ciphertext['B'] *tmp    
        tmp = (int(tmp**(MK['pp']*MK['qq'])) -1)% self.N2
        tmp = integer(tmp) /self.N
        
        m = integer(tmp) * integer(sig) %self.N
        return integer(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 Param():
    def __init__(self):
        pass
    def setParam(self,N2,N,g,k):
        self.N2 = N2
        self.N = N
        self.g = g
        self.k = k

class BCP():
    def __init__(self,secparam=1024,param = None):
        if param:
            self.N2 = param.N2
            self.N = param.N
            self.g = param.g
            self.k = param.k            
        else:
            self.p, self.q = randomPrime(int(secparam/2),True), randomPrime(int(secparam/2),True) 
            self.pp = (self.p -1)/2
            self.qq = (self.q - 1)/2
            self.N = self.p * self.q
            while True: 
                if bitsize(self.N) ==secparam and len(int2Bytes(self.N)) == int(secparam/8) and int2Bytes(self.N)[0] &128 !=0:
                    break
                self.p, self.q = randomPrime(int(secparam/2),True), randomPrime(int(secparam/2),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.g = random(self.N2)
            one = integer(1)% self.N2
            while True: #choose a good g
                self.g = random(self.N2)
                self.g = integer((int(self.g)-1)*(int(self.g)-1))% self.N2
                if self.g == one:
                    continue
                tmp = self.g**self.p %self.N2
                if tmp == one:
                    continue
                tmp = self.g**self.pp % self.N2
                if tmp == one:
                    continue
                tmp = self.g**self.q %self.N2
                if tmp == one:
                    continue
                tmp = self.g**self.qq %self.N2
                if tmp == one:
                    continue
                tmp =self.g**(self.p*self.pp) % self.N2
                if tmp == one:
                    continue 
                tmp = self.g**(self.p*self.q) %self. N2
                if tmp== one:
                    continue 
                tmp = self.g**(self.p*self.qq) % self.N2
                if tmp == one:
                    continue 
                tmp = self.g**(self.pp*self.q) % self.N2
                if tmp == one:
                    continue 
                tmp = self.g**(self.pp*self.qq) % self.N2
                if tmp == one:
                    continue 
                tmp = self.g**(self.q*self.qq) % self.N2
                if tmp == one:
                    continue
                tmp = self.g**(self.q*self.qq) % self.N2
                if tmp == one:
                    continue
                tmp = self.g**(self.p*self.pp*self.q) % self.N2
                if tmp == one:
                    continue   
                tmp =self.g**(self.p*self.pp*self.qq) % self.N2
                if tmp == one:
                    continue
                tmp =self.g**(self.p*self.q*self.qq) % self.N2
                if tmp == one:
                    continue
                tmp =self.g**(self.pp*self.q*self.qq) % self.N2
                if tmp == one:
                    continue  
                break 
            self.k = integer((int(self.g**(self.pp*self.qq)) - 1)) / self.N % self.N
            self.MK ={"pp":self.pp,"qq":self.qq}
    
    def GetMK(self):
        return self.MK
    
    def GetParam(self):
        param = Param()
        param.setParam(self.N2, self.N, self.g, self.k)
        return param
    
    def KeyGen(self):
        tmp = self.N2 /2
        sk = random(tmp) % self.N2
        pk = (self.g**sk) % self.N2
        return pk,sk
    
    def Encrypt(self,pk,plaintext):
        r = random(self.N/4) % self.N2
        A = (self.g** r ) % self.N2 
        B1 = (self.N*plaintext+1)% (self.N2)
        B2 = (pk**r) % (self.N2)
        B = B1*B2 % self.N2
        ciphertext = {"A":A,"B":B}
        return ciphertext
    
    def Decrypt(self,ciphertext,sk):
        t1 = integer(int(ciphertext['B']*((ciphertext['A']**-1)**sk)) -1) % self.N2
        m = integer(t1) / self.N
        return m
    
    def DecryptMK(self,ciphertext,MK,pk):
        k_1 = self.k ** -1
        tmp = (int(pk**(MK['pp']*MK['qq'])) -1) % self.N2
        tmp = integer(tmp) /self.N 
        a = tmp * integer(k_1) % self.N
        
        tmp = (int(ciphertext['A'] **(MK['pp']*MK['qq'])) -1) % self.N2
        tmp = integer(tmp) /self.N 
        r = tmp * integer(k_1) % self.N
        
        gama = a*r %self.N
        sig = ((MK['pp']*MK['qq'])%self.N) **-1
        
        tmp = (self.g **-1)**gama
        tmp = ciphertext['B'] *tmp    
        tmp = (int(tmp**(MK['pp']*MK['qq'])) -1)% self.N2
        tmp = integer(tmp) /self.N
        
        m = integer(tmp) * integer(sig) %self.N
        return integer(m) 

    def multiply(self,ciphertext1,ciphertext2):
        ciphertext={}
        ciphertext['A'] = ciphertext1['A'] * ciphertext2['A']
        ciphertext['B'] = ciphertext1['B'] * ciphertext2['B'] 
        return ciphertext

    def exponentiate(self,ciphertext,m):
        text={}    
        text['A'] = ciphertext['A'] **m % self.N2
        text['B'] = ciphertext['B'] **m % self.N2
        return text  

3.测试

  • 测试代码
if __name__ == "__main__":

    bcp = BCP()
    mk = bcp.GetMK()
    print("mk is:",mk)
    pk,sk = bcp.KeyGen()
    print("------------------------")
    print("pk is:",pk,"sk is:",sk)
    plaintext = 1024
    print("------------------------")
    print("plaintext is:",plaintext)
    ciphertext = bcp.Encrypt(pk,plaintext)
    print("-------------------------")
    print("ciphertext is:",ciphertext)
    m1 = bcp.Decrypt(ciphertext,sk)
    print("-------------------------")
    print("Using sk to decrypt ciphertext,result is:",m1)
    m2 = bcp.DecryptMK(ciphertext,mk,pk)
    print("-------------------------")
    print("Using mk to decrypt ciphertext,result is:",m2)
  • 结果:满足正常加解密运算
mk is: {'pp': 8085308361220211021, 'qq': 8074162483544779991}
------------------------
pk is: 2327067015883561054197990332426819861947346756531764313703384468027403763054 mod 68188027578479421068471198257847466460478763055291934213409505489802965962361 sk is: 57367126269859549947589515646769721080756993424096049630783473449899601736315 mod 68188027578479421068471198257847466460478763055291934213409505489802965962361
------------------------
plaintext is: 1024
-------------------------
ciphertext is: {'A': 938193878176646758481378597525256135099055012583309087654629417103271925777 mod 68188027578479421068471198257847466460478763055291934213409505489802965962361, 'B': 65213284378251907450069755084784844288839906212981359092246031298436351553270 mod 68188027578479421068471198257847466460478763055291934213409505489802965962361}
-------------------------
Using sk to decrypt ciphertext,result is: 1024
-------------------------
Using mk to decrypt ciphertext,result is: 1024
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容