代換密碼的密碼分析
使用單表代換密碼,對於給出的密文進行分析並得到結果,瞭解加密解密過程
密文信息如下:AHNFCROACOAHNISEFLCIASFVCNWOSEAHNWSRLDWCAHCEIRNTONDATRCFFOSEOANNLTEDTLUMCEUMFRSMAHNNUITETDTTEDJTPTEAHNUOWCNLDOCAOATRCFFBTASETGTCEOACAOARTDCACSETLTLLCNOTAAHNOTMNACMNCACODNMTEDCEGAHTATFRCITEISUEARCNOOUIHTORWTEDTTEDUGTEDTRNMSVNCMPSRAATRCFFOSEONISEDHTEDILSAHNOFRSMAHNUOAHTAVCNWSEAHNWSRLDCOKESWETOTMNRCITFCROATEDCAMNTEOAHTATEYSENONNETOHTVCEGMSVNDTMNRCITOIHNNONBNCATETLLYSRESACOPUECOHNDBYISEARTOAIHCETONNOCAORNLTACSEOWCAHAHNWSRLDTOBTONDSEMUAUTLRNOPNIAFTCRENOOJUOACINTEDWCEWCEISSPNRTACSETEDTCMOASOTFNGUTRDWSRLDPNTINTEDPRSMSANISMMSEDNVNLSPMNEACACOWCLLCEGASWSRKWCAHAHNRNOASFAHNWSRLDASMTKNAHNCEANRETACSETLGSVNRETEINOYOANMFTCRNRTEDMSRNRNTOSETBLNTEDBUCLDTENWAYPNSFCEANRETACSETLRNLTACSEOTEDTISMMUECAYWCAHTOHTRNDFUAURNFSRMTEKCED
對上面密碼使用各種方法進行解密,得到明文信息
解密原理:
替代密碼是指先建立一個替換表,加密時將需要加密的明文依次通過查表,替換爲相應的字符,明文字符被逐個替換後,生成無任何意義的字符串,即密文,替代密碼的密鑰就是其替換表。根據密碼算法加解密時使用替換表多少的不同,替代密碼又可分爲單表替代密碼和多表替代密碼。單表替代密碼的密碼算法加解密時使用一個固定的替換表。單表替代密碼又可分爲一般單表替代密碼、移位密碼、仿射密碼、密鑰短語密碼。
思路步驟:
-
嘗試使用窮舉法獲得明文。程序a:字母代換程序
-
程序實現統計密文中的英文字母頻率。 程序b:字母統計程序
-
根據統計結果和常用字母頻率表,假設字母代換的規則(1-1代換),用密文來驗證假設的正確與否,若不成立,則繼續假設,一直到找到明文爲止。 程序a:字母代換程序
-
給出明文及密鑰(字母代換規則表)。
在進行實驗的過程之中,我將會使用2種不同的方法來對這次實驗的內容分別進行驗證和解決,分別爲通過大量測試的聚合算法和分別進行頻率分析來對這個實驗進行解決。
一、使用頻率分析法進行密文分析:
頻率法就是我們對密文進行分析,只要這個內容不是特殊的內容,他固定單詞的頻率會出現多次,這個方法主要基於密文的量多,量多固定使用的單詞頻率也就會多。比如說the、and、for這些英文在英文文章中出現的頻率會很多。
頻率分析法主要思路:
-
第一步:統計出密文字母出現的各個頻次;
-
第二步:根據密文字母出現的頻次統計,確定出某些密文字母對應的明文字母是否可能是單個字母頻率統計表之中的哪類字母;
-
第三步是利用自然語言的文字結合規律進行猜測分析,對各類單詞之中字母出現的頻率進行對應猜測,同時也需要利用雙字母、三字母統計特性以及元音輔音的拼寫知識進行猜測。
-
第四步就是整理我們進行猜測的明文字母,對恢復得到的明文進行整理分析。
對文本詞頻分析.py
# 統計頻率
def getLetterList():
c_file = open('c_text.txt') # 讀取文件
c_text = c_file.read() # 讀取文本
char_list = list(c_text) # 轉化爲列表,每個字母爲一個元素
# 統計加密字符串中各個字母的出現次數
# Q X Z
tempSet = set(char_list) # 抓轉爲集合去重
# 保存爲字典,key:字母,value:出現次數
tempDict = {}
for i in tempSet:
tempDict[i] = char_list.count(i)
# 列表排序, 以元組形式
dict_sorted = sorted(tempDict.items(), key=lambda x: x[1], reverse=True)
# print(dict_sorted)
frequency_list = []
print("字母", "出現次數", "頻率")
for i in dict_sorted:
print(i[0], "\t", i[1], "\t", i[1] / len(c_text))
frequency_list.append(i[0]) # 按照出現頻率寫入到列表
return frequency_list
getLetterList()
對二元英文進行詞頻分析.py
# 統計頻率
def get2WordList():
c_file = open('c_text.txt') # 讀取文件
c_text = c_file.read() # 讀取文本
char_list = list(c_text) # 轉化爲列表,每個字母爲一個元素
word_list2 = []
temp_list = []
try:
for i in range(0, len(char_list)-1):
temp_list.append(char_list[i])
temp_list.append(char_list[i + 1])
temp_str = "".join(temp_list)
word_list2.append(temp_str)
temp_list = []
except StopIteration:
print()
# 統計加密字符串中各個二元字母的出現次數
tempSet = set(word_list2) # 抓轉爲集合去重
# 保存爲字典,key:字母,value:出現次數
tempDict = {}
for i in tempSet:
tempDict[i] = word_list2.count(i)
# 列表排序, 以元組形式
dict_sorted = sorted(tempDict.items(), key=lambda x: x[1], reverse=True)
# print(dict_sorted)
frequency_list = []
print("2元字母", "出現次數", "\t頻率")
for i in dict_sorted:
print(i[0], "\t\t", i[1], "\t\t", i[1] / len(c_text))
frequency_list.append(i[0]) # 按照出現頻率寫入到列表
return frequency_list
get2WordList()
對三元英文進行詞頻分析.py
# 統計頻率
def get3WordList():
c_file = open('c_text.txt') # 讀取文件
c_text = c_file.read() # 讀取文本
char_list = list(c_text) # 轉化爲列表,每個字母爲一個元素
word_list3 = []
temp_list = []
try:
for i in range(0, len(char_list)-2):
temp_list.append(char_list[i])
temp_list.append(char_list[i + 1])
temp_list.append(char_list[i + 2])
temp_str = "".join(temp_list)
word_list3.append(temp_str)
temp_list = []
except StopIteration:
print()
# 統計加密字符串中各個二元字母的出現次數
tempSet = set(word_list3) # 抓轉爲集合去重
# 保存爲字典,key:字母,value:出現次數
tempDict = {}
for i in tempSet:
tempDict[i] = word_list3.count(i)
# 列表排序, 以元組形式
dict_sorted = sorted(tempDict.items(), key=lambda x: x[1], reverse=True)
# print(dict_sorted)
frequency_list = []
print("3元字母", "出現次數", "\t頻率")
for i in dict_sorted:
print(i[0], "\t\t", i[1], "\t\t", i[1] / len(c_text))
frequency_list.append(i[0]) # 按照出現頻率寫入到列表
return frequency_list
get3WordList()
通過使用上述一元、二元、三元對密文之中的英文字母出現頻次進行分析,我們可以得到下面的結果,分別是單字母、雙字母、三字母進行統計得到的頻率:
在上面分別對各個代碼算法得到的字母頻率進行統計,得到的結果值得我們進行分析並進行字母猜測,在下面我們對得到的信息進行合理化猜測並進行驗證。由此可以得到三元之中密文TED對應着英文中的and、AHN對應着the、ACS對應着tio、CSE對應着ion、SET對應着ona,繼續細細向下進行分析。
經過對詞典以及各類單詞進行詳細的猜測分析,以及出現的頻率進行統計分析,我們逐漸接近明文,因爲有一些詞彙爲低頻詞彙,上面不少的詞彙並未作出改變,原字母保持不變,因此,我們並未對其進行代換變化,經過分析如下所示,得到明文結果。
二、使用算法大量聚合進行密文分析
這個方法的原理就是選擇不同的解密密鑰進行破解嘗試,然後通過計算每一個解密得到的明文的適應度,也就是符合英文單詞語法的程度,如果解密得到的明文越接近我們日常使用的英語文章,它的那個適應度的值就會越高,如果大多數單詞不對,那麼適應度就會越低。
主要思路步驟:
-
第一步,我們隨機生成一個密鑰,用它來進行代換解密,解出得到的明文m1,對明文進行適應度計算,第一個適應度爲d1。
-
第二步,隨機交換之前生成的密鑰之中的兩個字符,我們得到子密鑰child,解密出對應的明文m2,同時計算適應度d2。
-
第三步,對d1、d2進行比較,如果d1 < d2,那麼child成爲新的密鑰。
-
第四步,對第二步、第三步進行多次循環1000次,直到無法生成得到更高的適應度,此時得到的密鑰最有可能就是我們密文的解密密鑰。
-
第五步,通過設置一個標誌量flag來對循環進行終止操作,如果當最高值不進行滿足的話,我們就跳出循環,防止陷入局部最優的困境,對於生成明文的適應度主要就是對不同解密密鑰進行比較,解密出來得到的明文適應度越高,密鑰就越好,適應度的計算方法我們通過使用quadgram statistics來進行計算。
# -*- coding: utf-8 -*-
# __author__ = "蘇柳欣" [email protected]
# Date: 2019-11-29 Python: 2.7.16
import random
import sys
sys.path.append('/Users/Iro/code/CodeSupport/ngram_score.py')
from ngram_score import *
from math import *
# 1.隨機生成一個key,稱爲parentkey,用它解密得對應的明文m1,對明文計算適應度d1
# 2.隨機交換parentkey中的兩個字符得到子密鑰child,解密出對應的明文m2並計算適應度d2
# 3.若d1<d2,則child成爲新的parentkey
# 4.不斷循環進行步驟2、3直到最後的1000次循環中不再有更高的適應度生成
# 5.回到1重新生成parentkey繼續迭代尋找,或者由操作者終止程序
# 重新執行1,是爲了防止2、3的操作使結果陷入局部最優的困境。對於生成的明文的適應度的比較
# 其實可以看作是對不同解密密鑰的比較,解密出來的明文的適應度越高,對應的密鑰就更好。
# quadgram statistics的適應度計算方法
ciphertext = 'AHNFCROACOAHNISEFLCIASFVCNWOSEAHNWSRLDWCAHCEIRNTONDATRCFFOSEOANNLTEDTLUMCEUMFRSMAHNNUITETDTTEDJTPTEAHNUOWCNLDOCAOATRCFFBTASETGTCEOACAOARTDCACSETLTLLCNOTAAHNOTMNACMNCACODNMTEDCEGAHTATFRCITEISUEARCNOOUIHTORWTEDTTEDUGTEDTRNMSVNCMPSRAATRCFFOSEONISEDHTEDILSAHNOFRSMAHNUOAHTAVCNWSEAHNWSRLDCOKESWETOTMNRCITFCROATEDCAMNTEOAHTATEYSENONNETOHTVCEGMSVNDTMNRCITOIHNNONBNCATETLLYSRESACOPUECOHNDBYISEARTOAIHCETONNOCAORNLTACSEOWCAHAHNWSRLDTOBTONDSEMUAUTLRNOPNIAFTCRENOOJUOACINTEDWCEWCEISSPNRTACSETEDTCMOASOTFNGUTRDWSRLDPNTINTEDPRSMSANISMMSEDNVNLSPMNEACACOWCLLCEGASWSRKWCAHAHNRNOASFAHNWSRLDASMTKNAHNCEANRETACSETLGSVNRETEINOYOANMFTCRNRTEDMSRNRNTOSETBLNTEDBUCLDTENWAYPNSFCEANRETACSETLRNLTACSEOTEDTISMMUECAYWCAHTOHTRNDFUAURNFSRMTEKCED'
parentkey = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
sss = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# 上面將密文存入變量中,在設定一個目前的字符替換標準
# 下面的key就是用來聲明字典key
key = {'A':'A'}
# 導入quadgrams.txt文本來進行適應度分析計算
fitness = ngram_score('/Users/Iro/code/CodeSupport/quadgrams.txt')
parentscore = -99e9
maxscore = -99e9
j = 0
flag = 1
print('開始進行密文分析 QAQ ')
while flag:
j = j + 1
random.shuffle(parentkey) # 進行隨機打亂
for i in range(len(parentkey)):
key[parentkey[i]] = chr(ord('A') + i)
decipher = ciphertext
for i in range(len(decipher)):
decipher = decipher[:i] + key[decipher[i]] + decipher[i + 1:]
parentscore = fitness.score(decipher)
count = 0
while count < 1000: # 進行1000次的適應度計算,預計會達到峯值
''' 下面是進行適應度的計算的比較 '''
a = random.randint(0,25) # 適應度的計算與比較
b = random.randint(0,25)
child = parentkey[:]
child[a], child[b] = child[b], child[a]
childkey = {'A':'A'}
for i in range(len(child)):
childkey[child[i]] = chr(ord('A') + i)
decipher = ciphertext
for i in range(len(decipher)):
decipher = decipher[:i] + childkey[decipher[i]] + decipher[i+1:]
score = fitness.score(decipher)
if score > parentscore: # 當此時的適應度大於之前適應度,我們就進行賦值操作
parentscore = score
parentkey = child[:]
count = 0
count = count + 1
if parentscore > maxscore: # 這裏對最大的適應度的值進行輸出,當適應度不再
maxscore = parentscore # 進行增長的時候,我們將標誌符號flag設置爲0,結束
maxkey = parentkey[:]
for i in range(len(maxkey)):
key[maxkey[i]] = chr(ord('A') + i)
decipher = ciphertext
for i in range(len(decipher)):
decipher = decipher[:i] + key[decipher[i]] + decipher[i+1:]
print("目前使用密鑰: " + ''.join(maxkey))
print(" " + sss)
print("\n")
print("明 文: " + decipher.lower())
print("\n")
else:
flag = 0
ss = decipher.lower()
'''
下面的操作是導入英文段的分割的語料庫,對上面得到的明文段進行添加空格分割
'''
words = open("/Users/Iro/code/CodeSupport/words-by-frequency.txt").read().split() # 有特殊字符的話直接在其中添加
wordcost = dict((k, log((i+1)*log(len(words)))) for i,k in enumerate(words))
maxword = max(len(x) for x in words)
def infer_spaces(s):
def best_match(i):
candidates = enumerate(reversed(cost[max(0, i-maxword):i]))
return min((c + wordcost.get(s[i-k-1:i], 9e999), k+1) for k,c in candidates)
cost = [0]
for i in range(1,len(s)+1):
c,k = best_match(i)
cost.append(c)
out = []
i = len(s)
while i>0:
c,k = best_match(i)
assert c == cost[i]
out.append(s[i-k:i])
i -= k
return " ".join(reversed(out))
print("添加空格後明文爲:" + infer_spaces(ss))
經過上面代碼的分析計算,我們得到的結果如下,我的代碼在後面還運用了NLP自然語言處理的方式,對生成的代碼進行分詞,最後自動得到符合語法的英文明文,但是還是有一些小錯誤,需要手動進行合理更改。
對了對了,上面代碼不能直接跑,還需要導入一些支持包,我已經上傳CSDN下載了,可以在這裏下載