Python维吉尼亚密码无密钥破解

  • Post author:
  • Post category:python


#密文
ctext='KCCPKBGUFDPHQTYAVINRRTMVGRKDNBVFDETDGILTXRGUDDKOTFMBPVGEGLTGCKQRACQCWDNAWCRXIZAKFTLEWRPTYCQKYVXCHKFTPONCQQRHJVAJUWETMCMSPKQDYHJVDAHCTRLSVSKCGCZQQDZXGSFRLSWCWSJTBHAFSIASPRJAHKJRJUMVGKMITZHFPDISPZLVLGWTFPLKKEBDPGCEBSHCTJRWXBAFSPEZQNRWXCVYCGAONWDDKACKAWBBIKFTIOVKCGGHJVLNHIFFSQESVYCLACNVRWBBIREPBBVFEXOSCDYGZWPFDTKFQIYCWHJVLNHIQIBTKHJVNPIST'

#破解密钥长度 计算重合指数

ctext.lower()
clen=len(ctext)
print("密文长度为:",clen)
maxlenkey=int(input("输入测试密钥长度上限:"))
lenkey=0

def groupzmexist(lenkey,list):              #统计'第list'组中各字母出现次数,以数组形式返回
    zmexist=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    for i in range (list-1,clen,lenkey):
        for j in range (0,26):
            if(ctext[i]==chr(97+j) or ctext[i]==chr(65+j)):
                zmexist[j]=zmexist[j]+1
    return zmexist


#######   sum(groupzmexist(lenkey,m))   key长lenkey时第m组字符个数
#######      groupzmexist(lenkey,m)    key长lenkey时第m组各个字母出现次数数组
def  count_ic(lenkey):        #密钥长lenkey,返回该密钥长度时平均IC
    average=0.0
    for m in range(1,lenkey+1):
        ic=0.0
        for i in range(0, 26):
            ic = ic + (groupzmexist(lenkey,m)[i] * (groupzmexist(lenkey,m)[i] - 1)) / (sum(groupzmexist(lenkey,m)) * (sum(groupzmexist(lenkey,m)) - 1))
        average = ic + average
    return (average/lenkey)

max=0                                   #IC取>0.06中最大的数
for i in range (1,maxlenkey+1):       #计算密钥长
    num=count_ic(i)
    if(num>=0.06 and num>max):        #取>0.06中最大的数
        max=num
        print("最可能密钥长度为:",i)
        lenkey=i

#确定密钥长度后计算互重合指数确定偏移量

frame=[0 for _ in range(lenkey)]       #相对偏移数组
judge=float(input("重合互指数判定标准:"))                
def count_mic(m,n,s):        #计算第m组和第n组偏移为s(t、t+s字符相同)时的互重合指数
    mic=0                     ########组数从1开始到第lenkey组############
    for i in range(0,26):
        mic=mic+(groupzmexist(lenkey,m)[i]*groupzmexist(lenkey,n)[(i+s)%26])/(sum(groupzmexist(lenkey,m))*sum(groupzmexist(lenkey,n)))#m中第t个字符和n中第t+s个字符
    return mic
#----------------最终计算和0.065相近的mic应该有lenkey+1个--------------------------#
count=0             #符合条件的mic个数
while (count<lenkey):
    for i in range(1,lenkey+1):         #1-lenkey个数组
        for j in range(1,lenkey+1):        #1-lenkey个数组
            if(i==j): break
            else:
                for s in range(0,26):
                    if(count_mic(i,j,s)>=judge):            #第i组和第j组相对位移为S成立
                        count=count+1
                        frame[j-1]=(frame[i-1]+s)%26
                        break

#已知密钥长度和相对偏移,列出26种可能

def decrypt(cipher,key):#解密函数
    message = ''
    non_alpha_count = 0
    for i in range (len(cipher)):#遍历
        if cipher[i].isalpha():
            if cipher[i].islower():
                offset = ord(key[(i - non_alpha_count) % len(key)]) - ord('a')
                message += chr((ord (cipher[i]) - ord('a') - offset) % 26 + ord('a'))
            else:
                offset = ord(key[(i - non_alpha_count) % len(key)]) - ord('a')
                message += chr((ord (cipher[i]) - ord('A') - offset) % 26 + ord('A'))
        else:
            message += cipher[i]
            non_alpha_count += 1
    return message


for i in range(0,26):   #26种密钥情况和对应明文
    key=['' for _ in range(0,lenkey)]
    for j in range(0,lenkey):
        key[j]=chr(97+(frame[j]+i)%26)
    print("密钥:",key)
    print("对应明文:")
    print(decrypt(ctext,key).lower())

解密函数参考了大佬的(小声说(。﹏。))

注释就是思路。先计算不同key长时的重合指数确定密钥长度,再计算同key长不同位移时重合互指数确定相对位移,最后列举选择正确明文。

重合互指数建议测试多个,可能有偶然情况。



版权声明:本文为qq_50998958原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。