关于维吉尼亚密码破解
希望大家弄明白原理,不要只要代码
这里因为latex写的报告拷贝出现乱码,就把我们实验报告中的原理部分以图片形式分享出来,供大家学习。
import vigenerecipher import string import re def gcd(a,b): if a<b: a,b=b,a if a%b==0: return b else: return gcd(b,a%b) def findstr(Ctext,str_): interval_list=[] loc=0 array_locs=[] while loc<len(Ctext): loc=Ctext.find(str_,loc) if loc==-1: break array_locs.append(loc) loc=loc+1 index=0 while index+1<len(array_locs): interval=array_locs[index+1]-array_locs[index] print("间隔:",interval) interval_list.append(interval) index=index+1 interval_len=gcd(interval_list[0],interval_list[1]) print("当重复值为",str_,"时,两两之间距离的最大公因数:",interval_len,"\n") return interval_len def find_repeat(Ciphertext,repeat_list): while len(Ciphertext)>200: Ciphertext=list(Ciphertext) Ciphertext.pop(1) Ciphertext=''.join(Ciphertext) list1=re.findall(r'.{3}',Ciphertext) list2=[0]*len(list1) for i in range(len(list1)): for j in range(len(list1)): if(list1[i]==list1[j]): list2[i]=list2[i]+1 max_len=max(list2) a=list2.index(max(list2)) if list1[a] not in repeat_list: if max_len==3: repeat_list.append(list1[a]) print("重复次数次数:",max_len) print("重复值:",list1[a]) print("\n") def check_len(Ciphertext,interval_len): ListCiphertext=list(Ciphertext) Keylength=1 while Keylength<interval_len+1: #指数初始化为0 CoincidenceIndex = 0 #使用切片分组 for i in range(Keylength): Numerator = 0 PresentCipherList = ListCiphertext[i::Keylength] #使用集合去重,计算每一子密文组重合指数 for Letter in set(PresentCipherList): Numerator += PresentCipherList.count(Letter) * (PresentCipherList.count(Letter)-1) CoincidenceIndex += Numerator/(len(PresentCipherList) * (len(PresentCipherList)-1)) #求各子密文组的拟重合指数的平均值 Average=CoincidenceIndex / Keylength Keylength += 1 #均值>0.6即可退出循环 if Average > 0.06: break Keylength -= 1 print("经重合指数验证后,密钥长度最可能为:",Keylength,"\n") return Keylength def keyword(Ciphertext,keylength): ListCiphertext = list(Ciphertext) #标准数据来源于课本 Standard = {'A':0.082,'B':0.015,'C':0.028,'D':0.043,'E':0.127,'F':0.022,'G':0.020,'H':0.061,'I':0.070,'J':0.002,'K':0.008,'L':0.040,'M':0.024,'N':0.067,'O':0.075,'P':0.019,'Q':0.001,'R':0.060,'S':0.063,'T':0.091,'U':0.028,'V':0.010,'W':0.023,'X':0.001,'Y':0.020,'Z':0.001} while True: KeyResult = [] for i in range(keylength): # 使用切片分组 PresentCipherList = ListCiphertext[i::keylength] #初始化重合指数最大值为0,检验移动位数对应字符以*代替 QuCoincidenceMax = 0 KeyLetter = "*" #遍历移动的位数 #m是密钥对应的英文字母 for m in range(26): #初始化当前移动位数的重合互指数为0 QuCoincidencePresent = 0 #遍历计算重合指数:各个字符的频率*对应英文字符出现的标准频率---的和 for Letter in set(PresentCipherList): #fi/n LetterFrequency = PresentCipherList.count(Letter) / len(PresentCipherList) # 标准频率 #ord(Letter) - 65是将letter对应的字母化为26内的数值,然后与m运算,得到的k是对应的明文字母 k = chr( ( ord(Letter) - 65 - m ) % 26 + 65 ) StandardFrequency = Standard[k] #计算重合互指数,累加遍历26个英文字母 QuCoincidencePresent = QuCoincidencePresent + LetterFrequency * StandardFrequency #保存遍历过程中重合指数的最大值,同时保存对应应对的位数,即对应key的字符 if QuCoincidencePresent > QuCoincidenceMax: QuCoincidenceMax = QuCoincidencePresent #m是26个英文对应的位置,从0开始,+65是因为A在ascii中是65 KeyLetter = chr( m +65 ) print("第",i+1,"个密钥字母为:",KeyLetter,"对应的重合互指数为:",QuCoincidenceMax) #保存当前位置key的值,退出循环,进行下一组子密文移动位数的尝试 KeyResult.append( KeyLetter ) #列表转为字符串 Key = "".join(KeyResult) break return Key if __name__ == '__main__': Ciphertext = input("输入密文:").upper() repeat_list=[] find_repeat(Ciphertext,repeat_list) print("kasisiki测试法:\n重复列表",repeat_list) for m in repeat_list: interval_len=findstr(Ciphertext,m) key_len=check_len(Ciphertext,interval_len) KeyResult = keyword(Ciphertext,key_len) print("密钥最可能为:" , KeyResult,"\n") #已知秘钥可用python自带维吉尼亚解密 ClearText = vigenerecipher.decode( Ciphertext,KeyResult ) print("解密结果为:" , ClearText)