维吉尼亚密码(Vigenere)(二)

2022-03-09  本文已影响0人  金卫岩

上一篇文章介绍了维吉尼亚密码的加解密过程,下面针对解密问题附上完整代码。(由于在程序运行过程中我是分步进行以便查看结果,因此代码段会涉及多次调用密文文档文件,当然,也可以将几个代码块融合在一起形成一个完整的代码文件)

计算密钥长度

#-*- coding:utf-8 –*-
def c_alpha(cipher):   # 去掉非字母后的密文
    cipher_alpha = ''
    for i in range(len(cipher)):
        if (cipher[i].isalpha()):
            cipher_alpha += cipher[i]
    return cipher_alpha

# 计算cipher的重合指数
def count_CI(cipher):
    N = [0.0 for i in range(26)]
    cipher = c_alpha(cipher)
    L = len(cipher)
    if cipher == '':
        return 0
    else:
        for i in range(L):     #计算所有字母的频数,存在数组N当中
            if (cipher[i].islower()):
                 N[ord(cipher[i]) - ord('a')] += 1
            else:
                 N[ord(cipher[i]) - ord('A')] += 1
    CI_1 = 0
    for i in range(26):
        CI_1 += ((N[i] / L) * ((N[i]-1) / (L-1)))
    return CI_1

# 计算秘钥长度为 key_len 的重合指数
def count_key_len_CI(cipher,key_len):        
    un_cip = ['' for i in range(key_len)]    # un_cip 是分组 
    aver_CI = 0.0
    count = 0
    for i in range(len(cipher_alpha)):
        z = i % key_len
        un_cip[z] += cipher_alpha[i]
    for i in range(key_len):
        un_cip[i]= count_CI(un_cip[i])
        aver_CI += un_cip[i]
    aver_CI = aver_CI/len(un_cip)
    return aver_CI

## 找出最可能的前十个秘钥长度
def pre_10(cipher):
    M = [(1,count_CI(cipher))]+[(0,0.0) for i in range(49)]
    for i in range(2,50):
        M[i] = (i,abs(0.065 - count_key_len_CI(cipher,i)))
    M = sorted(M,key = lambda x:x[1])   #按照数组第二个元素排序
    for i in range(1,10):
        print (M[i])

F = [
0.0651738, 0.0124248, 0.0217339,
0.0349835, 0.1041442, 0.0197881,
0.0158610, 0.0492888, 0.0558094,
0.0009033, 0.0050529, 0.0331490,
0.0202124, 0.0564513, 0.0596302,
0.0137645, 0.0008606, 0.0497563,
0.0515760, 0.0729357, 0.0225134,
0.0082903, 0.0171272, 0.0013692,
0.0145984, 0.0007836
]       # 英文字符频率。
fp = open("F:\CTF\CTF资料\i春秋\代码\Crypto\Vigenere\Vigenere.txt","r")
cipher = '' 
for i in fp.readlines():
    cipher = cipher + i    
fp.close()
cipher_alpha = c_alpha(cipher)
print ("秘钥长度为:")
pre_10(cipher)

计算密钥

#-*- coding:utf-8 –*-
def c_alpha(cipher):   # 去掉非字母后的密文
    cipher_alpha = ''
    for i in range(len(cipher)):
        if (cipher[i].isalpha()):
            cipher_alpha += cipher[i]
    return cipher_alpha

# 计算cipher的重合指数
def count_CI(cipher):
    N = [0.0 for i in range(26)]
    cipher = c_alpha(cipher)
    L = len(cipher)
    if cipher == '':
        return 0
    else:
        for i in range(L):     #计算所有字母的频数,存在数组N当中
            if (cipher[i].islower()):
                 N[ord(cipher[i]) - ord('a')] += 1
            else:
                 N[ord(cipher[i]) - ord('A')] += 1
    CI_1 = 0
    for i in range(26):
        CI_1 += ((N[i] / L) * ((N[i]-1) / (L-1)))
    return CI_1

# 计算秘钥长度为 key_len 的重合指数
def count_key_len_CI(cipher,key_len):        
    un_cip = ['' for i in range(key_len)]    # un_cip 是分组 
    aver_CI = 0.0
    count = 0
    for i in range(len(cipher_alpha)):
        z = i % key_len
        un_cip[z] += cipher_alpha[i]
    for i in range(key_len):
        un_cip[i]= count_CI(un_cip[i])
        aver_CI += un_cip[i]
    aver_CI = aver_CI/len(un_cip)
    return aver_CI

## 找出最可能的前十个秘钥长度
def pre_10(cipher):
    M = [(1,count_CI(cipher))]+[(0,0.0) for i in range(49)]
    for i in range(2,50):
        M[i] = (i,abs(0.065 - count_key_len_CI(cipher,i)))
    M = sorted(M,key = lambda x:x[1])   #按照数组第二个元素排序
    for i in range(1,10):
        print (M[i])

F = [
0.0651738, 0.0124248, 0.0217339,
0.0349835, 0.1041442, 0.0197881,
0.0158610, 0.0492888, 0.0558094,
0.0009033, 0.0050529, 0.0331490,
0.0202124, 0.0564513, 0.0596302,
0.0137645, 0.0008606, 0.0497563,
0.0515760, 0.0729357, 0.0225134,
0.0082903, 0.0171272, 0.0013692,
0.0145984, 0.0007836
]       # 英文字符频率。
# 猜测单个秘钥得到的重合指数
def count_CI2(cipher,n):     # n 代表我们猜测的秘钥,也即偏移量
    N = [0.0 for i in range(26)]
    cipher = c_alpha(cipher)
    L = len(cipher)
    for i in range(L):     #计算所有字母的频数,存在数组N当中
        if (cipher[i].islower()):
            N[(ord(cipher[i]) - ord('a') - n)%26] += 1
        else:
            N[(ord(cipher[i]) - ord('A') - n)%26] += 1  
    CI_2 = 0
    for i in range(26):
        CI_2 += ((N[i] / L) * F[i])
    return CI_2

def one_key(cipher,key_len):
    un_cip = ['' for i in range(key_len)]   
    cipher_alpha = c_alpha(cipher)
    for i in range(len(cipher_alpha)):     # 完成分组工作
        z = i % key_len
        un_cip[z] += cipher_alpha[i]
    for i in range(key_len):
        print (i)
        pre_5_key(un_cip[i])     ####这里应该将5个分组的秘钥猜测全部打印出来

## 找出前5个最可能的单个秘钥
def pre_5_key(cipher):
    M = [(0,0.0) for i in range(26)]
    for i in range(26):
        M[i] = (chr(ord('a')+i),abs(0.065 - count_CI2(cipher,i)))
    M = sorted(M,key = lambda x:x[1])   #按照数组第二个元素排序

    for i in range(10):
        print (M[i])

key_len = 8   #输入猜测的秘钥长度
fp = open("F:\CTF\CTF资料\i春秋\代码\Crypto\Vigenere\Vigenere.txt","r")
cipher = '' 
for i in fp.readlines():
    cipher = cipher + i    
fp.close()
one_key(cipher,key_len)

破译密文

def decrypto (miwen,key):
    mingwen = [0]*(len(miwen))
    count = 0
    for i in range (len(miwen)):
        if(miwen[i].isalpha()):
            if(miwen[i].isupper()):
                offset1 = ord(key[(i-count)%len(key)])-ord('a')
                mingwen[i] = chr(((ord(miwen[i])+ord('A'))-offset1)%26+ord('A'))
            else:
                offset2 = ord(key[(i-count)%len(key)])-ord('a')
                mingwen[i] = chr(((ord(miwen[i])-ord('a'))-offset2)%26+ord('a'))                
        else:
            mingwen[i]=miwen[i]
            count = count + 1
    return mingwen

fp = open("F:\CTF\CTF资料\i春秋\代码\Crypto\Vigenere\Vigenere.txt","r")
cipher = '' 
for i in fp.readlines():
    cipher = cipher + i    
fp.close()
mingwen = decrypto(cipher,'asterism')
mingwen = [str(i) for i in mingwen]
mingwen = ''.join(mingwen)
print(mingwen)
上一篇 下一篇

猜你喜欢

热点阅读