【题目】
实现维吉尼亚密码算法,具体要求:
A. 实现维吉尼亚密码加密过程,由用户输入密钥,可以对任意输入的明文进行加密;
B. 根据用户输入的密钥,对密文进行解密;
C. 实现维吉尼亚密码的唯密文攻击破解(基于重合互指数方法)
【实现代码】
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 13 08:17:01 2017
@author: HP
"""
#!/usr/bin/env python
"维吉尼亚"
from string import ascii_lowercase as lowercase
#加密
def VigenereEncrypto (p , key) :
p = get_trim_text(p)
ptLen = len(p)
keyLen = len(key)
quotient = ptLen // keyLen #商
remainder = ptLen % keyLen #余
out = ""
for i in range (0 , quotient) :
for j in range (0 , keyLen) :
c = int((ord(p[i*keyLen+j]) - ord('a') + ord(key[j]) - ord('a')) % 26 + ord('a'))
#global output
out += chr (c)
for i in range (0 , remainder) :
c = int((ord(p[quotient*keyLen+i]) - ord('a') + ord(key[i]) - ord('a')) % 26 + ord('a'))
#global output
out += chr (c)
return out
#解密
def VigenereDecrypto (output , key) :
ptLen = len (output)
keyLen = len (key)
quotient = ptLen // keyLen
remainder = ptLen % keyLen
inp = ""
for i in range (0 , quotient) :
for j in range (0 , keyLen) :
c = int((ord(output[i*keyLen+j]) - ord('a') - (ord(key[j]) - ord('a'))) % 26 + ord('a'))
#global input
inp += chr (c)
for i in range (0 , remainder) :
c = int((ord(output[quotient*keyLen + i]) - ord('a') - (ord(key[i]) - ord('a'))) % 26 + ord('a'))
#global input
inp += chr (c)
return inp
def get_trim_text(text):
text = text.lower()
trim_text = ''
for l in text:
if lowercase.find(l) >= 0:
trim_text += l
return trim_text
#计算重合指数
def get_coincidence_index(text):
text = get_trim_text(text)
length = len(text)
letter_stats = []
for l in lowercase:
lt = {}
count = text.count(l)
lt[l] = count
letter_stats.append(lt)
index = 0
for d in letter_stats:
v = list(d.values())[0]
index += (float(v)/length) ** 2
return index
#计算和0.067的差距大小
def get_var(data, mean=0.067):
if not data:
return 0
var_sum = 0
for d in data:
var_sum += (d - mean) ** 2
return float(var_sum) / len(data)
#求秘钥长度
def get_key_length(text):
# assume text length less than 26
text = get_trim_text(text)
group = []
for n in range(1, len(text)+1):
group_str = ['' for i in range(n)]
for i in range(len(text)):
l = text[i]
for j in range(n):
if i % n == j:
group_str[j] += l
group.append(group_str)
var_list = []
length = 1
for tex in group:
data = []
for t in tex:
index = get_coincidence_index(t)
data.append(index)
var_list.append([length, get_var(data)])
length += 1
var_list = sorted(var_list, key=lambda x: x[1])
print(var_list)
return [v[0] for v in var_list[:int(n/2)+1]] #var_list[0][0]
# 统计字母频度
def countList(lis):
li = []
alphabet = [chr(i) for i in range(97,123)]
for c in alphabet:
count = 0
for ch in lis:
if ch == c:
count+=1
li.append(float(count)/len(lis))
return li
# 根据密钥长度将密文分组
def textToList(text,length):
text = get_trim_text(text)
textMatrix = []
row = []
index = 0
for ch in text:
row.append(ch)
index += 1
if index % length ==0:
textMatrix.append(row)
row = []
textMatrix.append(row)
return textMatrix
# 获取密钥
def getKey(text,length):
text = get_trim_text(text)
key = [] # 定义空白列表用来存密钥
alphaRate =[0.08167,0.01492,0.02782,0.04253,0.12705,0.02228,0.02015,0.06094,\
0.06996,0.00153,0.00772,0.04025,0.02406,0.06749,0.07507,0.01929,\
0.0009,0.05987,0.06327,0.09056,0.02758,0.00978,0.02360,0.0015,0.01974,0.00074]
matrix = textToList(text,length)
for i in range(length):
w = [row[i] for row in matrix if len(row) > i] #获取每组密文
li = countList(w)
powLi = [] #算乘积
for j in range(26):
Sum = 0.0
for k in range(26):
Sum += alphaRate[k]*li[k]
powLi.append(Sum)
li = li[1:]+li[:1]#循环移位
Abs = 100
ch = ''
for j in range(len(powLi)):
if abs(powLi[j] -0.065546)<Abs: # 找出最接近英文字母重合指数的项
Abs = abs(powLi[j] -0.065546) # 保存最接近的距离,作为下次比较的基准
ch = chr(j+97)
key.append(ch)
return key
if __name__ == '__main__':
prompt = """
(e)ncryption
(d)ecrypt
(c)rack
(q)uit
please enter your choice:
"""
while(True):
choice = input(prompt)
if choice == 'e':
p = input("please enter plaintext: ")
k = input("please enter key: ")
print("the ciphertext is: %s" %(VigenereEncrypto(p, k)))
elif choice == 'd':
c = input("please enter ciphertext: ")
k = input("please enter key: ")
print("the plaintext is: %s" %(VigenereDecrypto(c, k)))
elif choice == 'q':
break
elif choice == 'c':
key_lengths = []
c = input("please enter ciphertext: ")
key_lengths = get_key_length(c)
print(key_lengths)
for i in range(len(key_lengths)):
key = getKey(c, key_lengths[i])
print("the plaintext is %s, the length of key is %d, key is %s" \
% (VigenereDecrypto (c , key), key_lengths[i], key))
else:
print("valid input, please try again")