import random
from my_modules import modules
import itertools
import copy
qu_chong=[]#防止在破解密码时相同的明文输出情况重复出现
# 初始化
def init(length, interval):
listV = [] # 超递增向量
listV_b = [] # 每个元素对应的乘数
bagCapacity = 1000 # 背包容积
# 初始化超递增向量与listV_b
for i in range(length):
listV.append(sum(listV) + random.randrange(1, interval))
listV_b.append(0)
# 求超递增背包的解
bagCapacityTmp = bagCapacity
for i in range(len(listV)-1, -1, -1):
if bagCapacityTmp >= listV[i]:
bagCapacityTmp -= listV[i]
listV_b[i] = 1
return listV
# 产生私钥:k、t、t的逆元
def creatPKey(listV):
# listV = init()
while True:
k = int(input("输入私钥k(大于%d):" % (sum(listV))))
if k <= sum(listV):
continue
while True:
t = int(input("输入私钥t(与k互素):"))
if not modules.judgeCoPrime(k, t):
continue
break
break
inverse_t = modules.getInverse(t, k)
return k, t, inverse_t
# 产生公钥:
def creatSKey(listV, t, k):
sKeyList = [] # 公钥序列
for i in listV:
sKeyList.append((int(i) * t) % k)
return sKeyList
# 加密
def encrypt(massage, sKeyList):
massageList = [] # 明文分组后的列表
ciphertextList = [] # 存储密文的列表
# 扩充明文消息串
while len(massage) % len(sKeyList) != 0:
massage = "0" + massage
# 对明文进行分组
for i in range(int(len(massage) / len(sKeyList))):
start = (i * len(sKeyList))
end = ((i + 1) * len(sKeyList))
massageList.append(massage[start : end])
# 采用内积和的方法加密
for i in massageList:
# 此处使用lambda时,要注意类型转换
multiplyList = list(map(lambda x, y: int(x) * int(y), list(i), sKeyList))
ciphertextList.append(sum(multiplyList))
return ciphertextList
# 解密
def decrypt(massage, sKeyList, k, inverse_t):
pliantextList = [] # 存储明文的列表
reductListV = [] # 还原后的初始超递增向量
# 还原超递增向量
for i in sKeyList:
reductListV.append(int(i) * inverse_t % k)
# 计算出用于解密的临时背包容积
bagCapacityList = []
for i in massage:
bagCapacityList.append(int(i) * inverse_t % k)
# 利用求出的临时背包容积求解背包问题,结果即明文
for bagCap in bagCapacityList:
pliantextTmp = [] # 存储密文列表中每个密文解密后的序列
for i in range(len(reductListV)):
pliantextTmp.append(0)
for i in range(len(reductListV) - 1, -1, -1):
if bagCap >= reductListV[i]:
bagCap -= reductListV[i]
pliantextTmp[i] = 1
pliantextList += pliantextTmp
# 去除扩充的0并转换为字符串
start, end = 0, 0
for i in range(len(pliantextList)):
if pliantextList[i] !=0:
break
end = i + 1
del pliantextList[start : end]
pliantextList = map(str, pliantextList)
pliantext = "".join(pliantextList)
return pliantext
#破解背包公钥密码
def crack (sKeyList,ciphertextList):
list_len=len(sKeyList)
flag=1
pkh=sKeyList[0]+sKeyList[1]
pkl=sKeyList[0]
for i in range(1,list_len):
if(i>=1 and sKeyList[i]<sKeyList[i-1]):
if(pkh<sKeyList[i-1]+sKeyList[i]):
pkh=sKeyList[i-1]+sKeyList[i]
if(pkl>sKeyList[i-1]):
pkl=sKeyList[i-1]
if(flag):
flag=0
if(flag):
pkh=sKeyList[list_len-1]+1
pkl=sKeyList[0]-1
AA=[]
t=0
NS=1 #破解状态
FA=1 #寻找超递增向量,找不到为0
k=pkh
while (NS and FA):
sum=0
t=t+1
AA.clear()
AA.append(sKeyList[0]*t%k)
for i in range(1,list_len):
AA.append(sKeyList[i]*t%k)
sum=sum+AA[i-1]
if (sum>=AA[i]): #判断是否为超递增序列
break
elif( i==list_len-1):
#print("k=",k,"t=",t,"AA",AA)
decryption(ciphertextList,AA,k,t)
#NS=0
if (k>pkl and t >=k): #判断能否找到超递增序列
k=k-1
t=0
elif (k<=pkl):
FA=0
if(not qu_chong):
print("输入的公钥不存在或无法求得(k&&t)以求得递增背包序列")
else:
print("输出完毕!")
# decryption(ciphertextList,AA,k,t)
# 利用破解所得的k,t和递增背包序列以及待破解密文,解密明文,思路同上述“解密”
def decryption(cipher,input_list,k,inv_t):
sumx = []
result_list=[]
global qu_chong
for i in cipher:
sumx .append((inv_t * int(i)) % k)
for sumxx in sumx:
between_list=[]
for i in range(len(input_list)):
between_list.append(0)
for i in range(len(input_list)-1,-1,-1):
if(sumxx>=input_list[i]):
sumxx-=input_list[i]
between_list[i]=1
result_list+=between_list
if(qu_chong !=result_list):
qu_chong=copy.deepcopy(result_list)#使用深拷贝
print("去除前导0之前的result_list:",result_list)
start=0
end=0
for i in range(len(result_list)):
if result_list[i] !=0:
break
end = i + 1
del result_list[start : end]
result_list = map(str, result_list)
result_list = "".join(result_list)
print("解密以及去除前导0后的明文为:",result_list)
if __name__ == "__main__":
listV = [1, 3, 7, 13, 26, 65, 119, 267]
length = int(input("输入超递增向量元素个数:"))
interval = int(input("输入随机增量:"))
#length, interval = 8, 4
listV = init(length, interval)
print("初始向量:", listV)
k, t, inverse_t = creatPKey(listV)
print("\n私钥验证成功,分别为 <k:%d>, <t:%d>,<t逆元:%d>" %(k, t, inverse_t))
sKeyList = creatSKey(listV, t, k)
print("公钥向量为:", sKeyList, "\n")
while True:
choice = input("1、加密 2、解密 3、破解\n请选择:")
if choice == "1":
massage = input("输入明文(01序列):")
ciphertextList = encrypt(massage, sKeyList)
print("加密结果:", ciphertextList)
elif choice == "2":
ciphertextList = list(map(int, list(input("输入密文:").split(","))))
sKeyList = list(map(int, list(input("输入公钥向量:").split(","))))
k = int(input("输入密钥k:"))
inverse_t = int(input("输入密钥t逆:"))
pliantext = decrypt(ciphertextList, sKeyList, k, inverse_t)
print("解密结果:", pliantext)
elif choice=="3":
ciphertext =list(map(int, list(input("输入密文:").split(","))))
public =list(map(int, list(input("输入公钥向量:").split(","))))
crack(public,ciphertext)
同时将两个常用函数分离了出来,组成模块modules,在源码中插入:
# 判断互质
def judgeCoPrime(a, b):
# 求最大公因数
def maxCommonFactor(m, n):
result = 0
while m % n > 0:
result = m % n
m = n
n = result
return result
if maxCommonFactor(a, b) == 1:
return True
return False
# 求逆元
def getInverse(a, b):
# 扩展的欧几里得
def extGcd(a_, b_, arr):
if b_ == 0:
arr[0] = 1
arr[1] = 0
return a_
g = extGcd(b_, a_ % b_, arr)
t = arr[0]
arr[0] = arr[1]
arr[1] = t - int(a_ / b_) * arr[1]
return g
# 求a模b的乘法逆x
arr = [0,1,]
gcd = extGcd(a, b, arr)
if gcd == 1:
return (arr[0] % b + b) % b
else:
return -1