凯撒密码是一种古老的加密算法,至今也被应用在某些加密算法的过程中。一般而言,破解凯撒密码需要密钥,但是由于加密空间太小,解密可以穷举进行。因此本文给出了一种基于统计的解密算法,这种算法思想也可以应用到其他场合。
凯撒加密算法是采取字母移位的思路进行,加密公式如下:
word = (word + x) mod 26
根据鸽巢原理可知,穷举26次必然能得到加密原文。
算法求解前提假设:加密原文符合英文字母自然统计规律。
首先列出英语字母自然频率分布表:
将频率分布表按照出现频率从高到低进行排序,得到:
statistics_list = [w1,w2, ... ,w25,w26 ]
随后,对于密文序列 words,也按照字母出现频率从高到低进行排序,得到:
candidate_list = [w1',w2', ... ,w25',w26']
采用欧几里得距离定义差异值 diffvalue,公式如下:
diffvalue = (x1-x1')^2 + (x2-x2')^2 + ... + (x26-x26')^2 //xi、xi'代表同一字母在不同列表中的位置
综上,算法思路:暴力枚举26种情况,并求得每种情况下的 diffvalue,最后选择 diffvalue 最小的答案作为加密原文输出。如果加密原文不符合英文字母统计规律(如一堆无意义的字母组合),则算法无法输出正确结果。在加密原文长度过小的情况下,同样不符合英文字母自然统计规律,也可能得到错误结果。综上,算法最终输出三种 diffvalue 最小的答案作为最可能的结果。
# statistical character list
sta_chs = ['e', 't', 'a', 'o', 'i', 'n', 's', 'h', 'r', 'd', 'l', 'c',
'u', 'm', 'w', 'f', 'g', 'y', 'p', 'b', 'v', 'k', 'j', 'x', 'q', 'z']
# before encrypt
original_text = ""
# encypted
encrypted_text = ""
# decrypt in force-enumeration way (without key)
force_list = []
# encrypt with caesar encryption method
def caesar_encrypt(key_num):
global encrypted_text
encrypted_text = ''
for ch in original_text:
if ch.isalpha():
num = ord(ch)
num += key_num
if ch.isupper():
if num > ord('Z'):
num -= 26
elif num < ord('A'):
num += 26
else:
if num > ord('z'):
num -= 26
elif num < ord('a'):
num += 26
encrypted_text += chr(num)
else:
encrypted_text += ch
print(encrypted_text)
def getkey(x):
return x[1]
# decrypt without key (force enumeration)
def statistics_decrypt():
global force_list
force_list.clear()
key = 1
while key <= 26:
temp = caesar_decrypt(key)
templist = []
templist.append(temp)
tlist = []
for i in range(26):
tlist1 = []
tlist1.append(i)
tlist1.append(0)
tlist.append(tlist1)
temp = temp.lower()
for tch in temp:
if tch.isalpha():
tlist[ord(tch)-ord('a')][1] += 1
tlist.sort(key=getkey, reverse=True)
cost = 0
idx = 0
while idx<26:
item=tlist[idx][0]
num=ord('a')+item
idy=0
while idy<26:
if num == ord(sta_chs[idy]):
cost+=(idy-idx)**2
break
idy+=1
idx+=1
templist.append(cost)
force_list.append(templist)
key += 1
force_list.sort(key=getkey)
print(force_list)
print(len(force_list))
def get_statistics_answer():
return force_list[0:3:1]
if __name__ == "__main__":
# global original_text
original_text = "ab AB hoW are you?I'm fine thank you.and you?"
caesar_encrypt(2)
statistics_decrypt()
print(get_statistics_answer())
最终加上了界面实现,效果如下:
解密后: