前情在:https://www.jianshu.com/p/1aa778f3ea33
网鼎杯一开始误以为密文是单字母替换密码(老师你好意思吗),解了很久解不出来,昨天虽然知道是凯撒……但这个坑留在心中耿耿于怀。于是基于词典对单字母替换密码进行了破解。分为手动辅助和一键猜解两个作业。
1.首先介绍下如何判断单词是否有可能相同,主要是基于单词内重复字母来自定义。
'001': ['EEL'], '0012': ['EELS', 'OOZE'], '00120': ['EERIE']
2.下载个英文词典,将常见的英文单词转换成pattern集合
3.通过不停的匹配迭代去缩小可选项
4.将剩余可能性取个笛卡儿积出来,遍历解密结果。
交作业1:基于词典的单字母替换密码破解(需要手动辅助)
花了一天终于写完了,但是有的解不出来……实在没招。发现这段文字还少个了Q,那么Q一定对应是Z了!()
四个字母没跑出来 没关系我们可以手动出来!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ReplaceDecode by Yunkai.He
import WordPatternDict,GetWordPattern,re,pprint,ReplaceEncode
def LetterReference(WordRefer,WordDict): #将新单词的预测字典加入字典WordDict中,重复key的value作交集处理
for letter in WordRefer:
if letter in WordDict:#交集
for i in WordDict[letter]:
if i not in WordRefer[letter]:
WordDict[letter].remove(i)
else:
WordDict[letter] = WordRefer[letter]
def WordReference(word,Candidate): #将单词字符串与预测列表新生成无空value的字典WordRefer,重复key的value作并集处理
WordRefer ={}
for i in range(len(word)): #依次读取密文字符串每个字母word[i]
WordRefer[word[i]] =[]
for j in range(len(Candidate)): #依次读取可能对应的明文Candidate[j]
if Candidate[j][i] not in WordRefer[word[i]]: #并集
WordRefer[word[i]].append(Candidate[j][i])
return WordRefer
def Simple(WordDict,SimpleDict): #根据可选数为1的预测进行一轮排除简化,已测试功能无误
for letter in WordDict:
if len(WordDict[letter]) == 1:
SimpleDict[letter] = (WordDict[letter][0]) #只有一个则输出到SimpleDict中
for i in WordDict:
for j in WordDict[i]:
if j == SimpleDict[letter]:
WordDict[i].remove(SimpleDict[letter]) #list赋值是动态链接,注意remove的效果影响
def main():
EncodedString = '''bvgk mrclrscv bzeuivu, tzmzc lerczverscv nv, ivuivjj lertbefncvuxvu yzj aluztzrip wfid vrty mrclrscv, nyvivsp czxyk yzkyvi nrxzex mfztv vevdzvj nrievu efn efn wzid mrclrscv erkzmv rjjvek nzkyze zj letfdwfikrscv nzkyflk svevwzkj fggivjjzfej drecp svtfdv uvizmzex lewzk hlrikvizex zejkzklkv lewzk tfejkirzevu jtritvcp mrclrscv bvgk uztkrkv vetflirxv ilcvi jvtliv, czsvikp jkrxv wleurdvekrccp tfddzk grikj crixv srisriflj sfuzvj vrk yrmv yzjkfip uzjrmfn ilcv lkkvicp zddvuzrkv fli treuzu tfejvek bzeuivu gligfjv fw nrekzex kzcc evn hlrikvizex urexvij aljkztv urexvij befne zejkzklkv czxyk tilvckp, aljk, rckvi, tyrexvu rggvrczex hlrikvizex xfmviedvekj nrievu sv yrirjj trgkzmv drecp sizex, aljk, czxyk jkrkvj, hlrikvizex yzjkfip fgvirkzfe ivjk jyrcc votzkvu evn, ivwljvu jvek kizrc uzjjfcmv xzmzex srisriflj vrty erkzmv kilkyj, jlsdzkkvu uzjkiztkj xzmzex uvjkifpvu dvitzcvjj lertbefncvuxvu vjkrsczjyvu ivjk yzxy dlckzkluv bzeuivu grpdvek erkzmv kylj wlcc bvgk mfztv xfmviedvek wzid aluztzrip hlrikvizex riv kizvu zevjkzdrscv fmvi dliuvi fev nzkyflk gvkzkzfevu vetflirxv ivwljvu zdgfjzex cvk aljk nyvivsp dliuvi uvtcriv efn dvitverizvj mfztv rggvrcvu fi, vmvip aljk, xzmzex gizetzgcvj, yfljvj cvxzjcrkliv kyifn kyre xlriuj zeuvgveuvek jlwwviretv ivczretv bvgk fw xfmviedvek, czsvikp kyv glsczt zj fww, dvitverizvj ivjgvtk xzmzex hlrikvizex hlrikvizex xfmviedvekj glsczjy hlrikvizex, czmvj yrj bzeuivu, mrclrscv lerczverscv evn dvrekzdv trjvj wfi, grikj vecrixzex reu hlrikvizex, wfiszuuve letfdwfikrscv jvgrirkv wrtkj aljkztv uzjrmfn fi trccvu bzeuivu alizjuztkzfe hlrikvizex, rnrp rjjldv sv, svve, glsczt aluxvj yfljvj xfmviedvekj wzid mfztv evxcvtkvu svknvve zdgfjzex jvcw kzvj wifd mfztv, leljlrc riv kizvu, rdflek cvxzjcrkv izxykj drep, zdgfjzex givjvek.
'''
CipherList = re.split('[^A-Z]+', EncodedString.upper()) #通过正则匹配,分成大写字符单词列表
Reference,WordDict,SimpleDict = {},{},{}
for word in CipherList:#调用GetWordPattern.py中的函数获取WordPattern,调用WordDict.py中的变量生成word-candidate的字典Reference
WordPattern = GetWordPattern.GetWordPattern(word)
if WordPattern in WordPatternDict.AllPattern:
Reference[word] = WordPatternDict.AllPattern[WordPattern]
#print(Reference)
for word in Reference: #调用本地函数获取字母预测表refer,通过增加单词,不断简化和补充WordDict。
refer = WordReference(word,Reference[word])
LetterReference(refer,WordDict)
#print('*******************************')
#print(WordDict)
i = 0
while len(SimpleDict) != len(WordDict) :#破解的标志设置为密文中所有字母都有了确定解or实在破解不了时break,人工介入
Simple(WordDict,SimpleDict)
i += 1
if i == 999:
break
#print(WordDict)
if i == 999:
print('fail to crack.the possible reference might be this:\n')
print(WordDict)
key,value='',''
for i in sorted(SimpleDict):
key += i
value += SimpleDict[i]
for i in WordDict:
if WordDict[i]:
key += i
value += ' '
print(key+key.lower(),value+value.lower(),sep='\n')
else :
print('Cracked!the cipher text"%s" might means:\n%s'%(EncodedString,ReplaceEncode.Encode(SimpleDict,EncodedString)))
print(WordDict)
print('Done.')
if __name__=='__main__':
main()
谢谢观赏,整个代码贼长……只贴出来破解的地方说明下思路……还是没有完美的解决方案,不过可以凑合大部分了(),现在还没有搞定在多个可选项里直接全跑出来给人选的方案……以后再说把!
交作业2:一键暴力猜解
写不完睡不着!想不到吧这么快就更新了!行不通的时候用回1
一键暴力猜解
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ReplaceDecode by Yunkai.He
import WordPatternDict,GetWordPattern,re,pprint,ReplaceEncode,itertools
def LetterReference(WordRefer,WordDict): #将新单词的预测字典加入字典WordDict中,重复key的value作交集处理
for letter in WordRefer:
if letter in WordDict:#交集
for i in WordDict[letter]:
if i not in WordRefer[letter]:
WordDict[letter].remove(i)
else:
WordDict[letter] = WordRefer[letter]
def WordReference(word,Candidate): #将单词字符串与预测列表新生成无空value的字典WordRefer,重复key的value作并集处理
WordRefer ={}
for i in range(len(word)): #依次读取密文字符串每个字母word[i]
WordRefer[word[i]] =[]
for j in range(len(Candidate)): #依次读取可能对应的明文Candidate[j]
if Candidate[j][i] not in WordRefer[word[i]]: #并集
WordRefer[word[i]].append(Candidate[j][i])
return WordRefer
def Simple(WordDict,SimpleDict): #根据可选数为1的预测进行一轮排除简化,已测试功能无误
for letter in WordDict:
if len(WordDict[letter]) == 1:
SimpleDict[letter] = (WordDict[letter][0]) #只有一个则输出到SimpleDict中
for i in WordDict:
for j in WordDict[i]:
if j == SimpleDict[letter]:
WordDict[i].remove(SimpleDict[letter]) #list赋值是动态链接,注意remove的效果影响
def iter(all,ini_str,shared_str,pos=0): #二维数组笛卡尔
tmp_list = ini_str[pos]
for i in tmp_list:
shared_str[pos] = i
if len(ini_str)==(pos+1):
if len(shared_str) == len(set(shared_str)):#用来去掉内容有重复的组合,平时可注释掉
all.append(shared_str.copy())
else:
iter(all,ini_str,shared_str,pos+1)
def main():
EncodedString = '''
bvgk mrclrscv bzeuivu, tzmzc lerczverscv nv, ivuivjj lertbefncvuxvu yzj aluztzrip wfid vrty mrclrscv, nyvivsp czxyk yzkyvi nrxzex mfztv vevdzvj nrievu efn efn wzid mrclrscv erkzmv rjjvek nzkyze zj letfdwfikrscv nzkyflk svevwzkj fggivjjzfej drecp svtfdv uvizmzex lewzk hlrikvizex zejkzklkv lewzk tfejkirzevu jtritvcp mrclrscv bvgk uztkrkv vetflirxv ilcvi jvtliv, czsvikp jkrxv wleurdvekrccp tfddzk grikj crixv srisriflj sfuzvj vrk yrmv yzjkfip uzjrmfn ilcv lkkvicp zddvuzrkv fli treuzu tfejvek bzeuivu gligfjv fw nrekzex kzcc evn hlrikvizex urexvij aljkztv urexvij befne zejkzklkv czxyk tilvckp, aljk, rckvi, tyrexvu rggvrczex hlrikvizex xfmviedvekj nrievu sv yrirjj trgkzmv drecp sizex, aljk, czxyk jkrkvj, hlrikvizex yzjkfip fgvirkzfe ivjk jyrcc votzkvu evn, ivwljvu jvek kizrc uzjjfcmv xzmzex srisriflj vrty erkzmv kilkyj, jlsdzkkvu uzjkiztkj xzmzex uvjkifpvu dvitzcvjj lertbefncvuxvu vjkrsczjyvu ivjk yzxy dlckzkluv bzeuivu grpdvek erkzmv kylj wlcc bvgk mfztv xfmviedvek wzid aluztzrip hlrikvizex riv kizvu zevjkzdrscv fmvi dliuvi fev nzkyflk gvkzkzfevu vetflirxv ivwljvu zdgfjzex cvk aljk nyvivsp dliuvi uvtcriv efn dvitverizvj mfztv rggvrcvu fi, vmvip aljk, xzmzex gizetzgcvj, yfljvj cvxzjcrkliv kyifn kyre xlriuj zeuvgveuvek jlwwviretv ivczretv bvgk fw xfmviedvek, czsvikp kyv glsczt zj fww, dvitverizvj ivjgvtk xzmzex hlrikvizex hlrikvizex xfmviedvekj glsczjy hlrikvizex, czmvj yrj bzeuivu, mrclrscv lerczverscv evn dvrekzdv trjvj wfi, grikj vecrixzex reu hlrikvizex, wfiszuuve letfdwfikrscv jvgrirkv wrtkj aljkztv uzjrmfn fi trccvu bzeuivu alizjuztkzfe hlrikvizex, rnrp rjjldv sv, svve, glsczt aluxvj yfljvj xfmviedvekj wzid mfztv evxcvtkvu svknvve zdgfjzex jvcw kzvj wifd mfztv, leljlrc riv kizvu, rdflek cvxzjcrkv izxykj drep, zdgfjzex givjvek.
'''
CipherList = re.split('[^A-Z]+', EncodedString.upper()) #通过正则匹配,分成大写字符单词列表
Reference,WordDict,SimpleDict = {},{},{}
for word in CipherList:#调用GetWordPattern.py中的函数获取WordPattern,调用WordDict.py中的变量生成word-candidate的字典Reference
WordPattern = GetWordPattern.GetWordPattern(word)
if WordPattern in WordPatternDict.AllPattern:
Reference[word] = WordPatternDict.AllPattern[WordPattern]
#print(Reference)
for word in Reference: #调用本地函数获取字母预测表refer,通过增加单词,不断简化和补充WordDict。
refer = WordReference(word,Reference[word])
LetterReference(refer,WordDict)
i = 0
while len(SimpleDict) != len(WordDict) :#破解的标志设置为密文中所有字母都有了确定解or实在破解不了时break,人工介入
Simple(WordDict,SimpleDict)
i += 1
if i == 999:
break
if i == 999:
key,value,flagindex='','',''
WordDictLess = []
tryall = []#tryall存放全部可能性
for i in sorted(SimpleDict):
key += i
value += SimpleDict[i]
for i in WordDict:
if WordDict[i]:
key += i
value += ' '
flagindex += i
WordDictLess.append(list(WordDict[i]))
#print(key+key.lower(),value+value.lower(),sep='\n')#手动破解
shared_str = [0 for i in range(len(WordDictLess))]
iter(tryall,WordDictLess,shared_str) #二维数组排列组合
print('fail to crack.the possible reference might be these %s:\n'%(len(tryall)))
for m in tryall:
for i in range(len(flagindex)):
SimpleDict[flagindex[i]] = m[i]
print(tryall.index(m),ReplaceEncode.Encode(SimpleDict,EncodedString))
else :
print('Cracked!the cipher text"%s" might means:\n%s'%(EncodedString,ReplaceEncode.Encode(SimpleDict,EncodedString)))
print(WordDict)
print('Done.')
if __name__=='__main__':
main()
开心!可能是这周最开心的一个晚上!好久没写这么多行代码了!我把相关代码一起附一下,自己用个词典,调用getwordpattern生成allpattern,然后一起import就可以了。
def GetWordPattern(string): #输入字符串,输出该字符串的单词模式类型(从0开始的数字字符串)
Letters='abcdefghijklmnopqrstuvwxyz'
LetterDict = {}
WordPattern = ''
i = 0
string = string.lower()
for letter in string:
if letter not in Letters:
return None
elif letter not in LetterDict:
LetterDict[letter] = str(i)
i += 1
WordPattern += LetterDict[letter]
return WordPattern
def Encode(Reference,string):
Encoded = ''
Letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in string:
if i in Letters:
Encoded += Reference[i]
elif i in Letters.lower():
Encoded += Reference[i.upper()].lower()
else:
Encoded += i
return Encoded
顺便纪念下过程中的各种错误
直接append相当于引用该地址,需通过copy来复制列表此刻的值 测试的时候只用2位的数组,看起来是可行了……后来跑得惨不忍睹
总结
现在被迭代搞得有点头晕……写到后面不记得前面要干嘛,改都不敢改()
真是辛苦了!
网友评论