破解维吉尼亚密码
题目
密文为:
KCCPKBGUFDPHQTYAVINRRTMVGRKDNBVFDETDGILTXRGUD DKOTFMBPVGEGLTGCKQRACQCWDNAWCRXIZAKFTLEWRPTYC QKYVXCHKFTPONCQQRHJVAJUWETMCMSPKQDYHJVDAHCTRL SVSKCGCZQQDZXGSFRLSWCWSJTBHAFSIASPRJAHKJRJUMV GKMITZHFPDISPZLVLGWTFPLKKEBDPGCEBSHCTJRWXBAFS PEZQNRWXCVYCGAONWDDKACKAWBBIKFTIOVKCGGHJVLNHI FFSQESVYCLACNVRWBBIREPBBVFEXOSCDYGZWPFDTKFQIY CWHJVLNHIQIBTKHJVNPIST
1、Kasiski 测试法
首先我们用Kasiski 测试法确定密钥字的长度。密文串KC 在密文中的三处出现,起始位置在1,139,260,这三个数互素,所以未得到有效的信息
2、计算重合指数确定密钥长度
对该问题,使用如下代码计算其重合指数:
cipher = 'KCCPKBGUFDPHQTYAVINRRTMVGRKDNBVFDETDGILTXRGUD\
DKOTFMBPVGEGLTGCKQRACQCWDNAWCRXIZAKFTLEWRPTYC\
QKYVXCHKFTPONCQQRHJVAJUWETMCMSPKQDYHJVDAHCTRL\
SVSKCGCZQQDZXGSFRLSWCWSJTBHAFSIASPRJAHKJRJUMV\
GKMITZHFPDISPZLVLGWTFPLKKEBDPGCEBSHCTJRWXBAFS\
PEZQNRWXCVYCGAONWDDKACKAWBBIKFTIOVKCGGHJVLNHI\
FFSQESVYCLACNVRWBBIREPBBVFEXOSCDYGZWPFDTKFQIY\
CWHJVLNHIQIBTKHJVNPIST'
# print(len(cipher))
n = len(cipher)
def getNum(code):
#统计各字符出现频率
count={}
length = len(code)
for i in range(len(code)):
count[code[i]] = 0
for i in range(len(code)):
count[code[i]] += 1
#print(count)
#计算
sum = 0
for i in count:
sum += count[i]*(count[i]-1)
I = sum / (length*(length-1))
# print(sum)
# print((length*(length-1)))
return I
# print(getNum(cipher))
def searchResult(code, k):
print(k, "的结果:")
step = int(n/k)
sp = []
for i in range(k):
c = []
for j in range(0, n, k):
if j+i < n:
c.append(code[j+i])
c = ''.join(c)
sp.append(c)
for s in sp:
if len(s) > 5:
I = getNum(s)
print(I)
if I > 0.06:
print('****************************************************')
for i in range(1, 10):
searchResult(cipher, i)
输出结果为:
1 的结果:
0.040871838349583155
2 的结果:
0.038461538461538464
0.04712004562303963
3 的结果:
0.055941845764854614
0.048101673101673105
0.04826254826254826
4 的结果:
0.03725490196078431
0.04274239816408491
0.037578886976477335
0.04905335628227195
5 的结果:
0.04258121158911326
0.04302019315188762
0.032564450474898234
0.035278154681139755
0.04296698326549073
6 的结果:
0.06265664160401002
****************************************************
0.08376623376623377
****************************************************
0.04935064935064935
0.06493506493506493
****************************************************
0.04285714285714286
0.07337662337662337
****************************************************
7 的结果:
0.030612244897959183
0.044326241134751775
0.04343971631205674
0.040780141843971635
0.044326241134751775
0.044326241134751775
0.040780141843971635
8 的结果:
0.03322259136212625
0.04065040650406504
0.03368176538908246
0.04065040650406504
0.03948896631823461
0.04529616724738676
0.04065040650406504
0.0545876887340302
9 的结果:
0.051209103840682786
0.04267425320056899
0.06401137980085349
****************************************************
0.07539118065433854
****************************************************
0.04054054054054054
0.03453453453453453
0.04354354354354354
0.04804804804804805
0.042042042042042045
由此可以初步判断出密钥长度为6。
3、根据频率找到密钥字
这一步本想按照讲义上计算互重合指数的方法来做,但计算结果不是很尽人意,没有得到最终结果,使用代码如下:
n = len(cipher)
sp = []
for i in range(6):
c = []
for j in range(0, n, 6):
if j+i < n:
c.append(cipher[j+i])
c = ''.join(c)
sp.append(c)
#print(sp)
table = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
#计算两个字符串的重合互指数
def getNum(s1, s2):
count1 = getDict(s1)
count2 = getDict(s2)
sum = 0
for l in table:
sum += count1[l] * count2[l]
MI = sum/(len(s1)*len(s2))
return MI
def getDict(s):
count={}
for i in range(len(table)):
count[table[i]] = 0
for i in range(len(s)):
count[s[i]] += 1
return count
def houyi(s, g):
for i in range(len(s)):
s = s[:i] + chr((ord(s[i])-65+g)%26+65) + s[i+1:]
return s
for i in range(6):
for j in range(i+1, 6):
for g in range(26):
MI = getNum(sp[i], houyi(sp[j], g))
if MI > 0.06:
print(i, "and", j, "when", g, MI)
之后还是决定使用统计方法找出密钥字,得到统计结果:
{'A': 3, 'B': 0, 'C': 4, 'D': 0, 'E': 1, 'F': 2, 'G': 6, 'H': 2, 'I': 2, 'J': 6, 'K': 3, 'L': 0, 'M': 0, 'N': 4, 'O': 0, 'P': 4, 'Q': 7, 'R': 0, 'S': 0, 'T': 4,
'U': 0, 'V': 5, 'W': 4, 'X': 0, 'Y': 0, 'Z': 0}
{'A': 0, 'B': 0, 'C': 5, 'D': 2, 'E': 3, 'F': 8, 'G': 0, 'H': 0, 'I': 3, 'J': 1, 'K': 9, 'L': 0, 'M': 0, 'N': 1, 'O': 0, 'P': 0, 'Q': 0, 'R': 8, 'S': 1, 'T': 3,
'U': 2, 'V': 6, 'W': 1, 'X': 0, 'Y': 2, 'Z': 1}
{'A': 2, 'B': 3, 'C': 4, 'D': 5, 'E': 2, 'F': 5, 'G': 2, 'H': 0, 'I': 0, 'J': 3, 'K': 1, 'L': 6, 'M': 3, 'N': 1, 'O': 0, 'P': 2, 'Q': 3, 'R': 5, 'S': 3, 'T': 0,
'U': 0, 'V': 0, 'W': 1, 'X': 0, 'Y': 4, 'Z': 1}
{'A': 3, 'B': 1, 'C': 3, 'D': 8, 'E': 1, 'F': 0, 'G': 3, 'H': 0, 'I': 2, 'J': 1, 'K': 0, 'L': 2, 'M': 0, 'N': 2, 'O': 0, 'P': 5, 'Q': 2, 'R': 1, 'S': 3, 'T': 9,
'U': 1, 'V': 2, 'W': 4, 'X': 3, 'Y': 0, 'Z': 0}
{'A': 4, 'B': 4, 'C': 0, 'D': 0, 'E': 2, 'F': 0, 'G': 2, 'H': 5, 'I': 4, 'J': 0, 'K': 5, 'L': 3, 'M': 3, 'N': 2, 'O': 1, 'P': 4, 'Q': 0, 'R': 1, 'S': 0, 'T': 3,
'U': 1, 'V': 2, 'W': 2, 'X': 4, 'Y': 2, 'Z': 2}
{'A': 2, 'B': 6, 'C': 8, 'D': 1, 'E': 1, 'F': 1, 'G': 3, 'H': 7, 'I': 3, 'J': 0, 'K': 2, 'L': 0, 'M': 0, 'N': 0, 'O': 4, 'P': 0, 'Q': 1, 'R': 1, 'S': 8, 'T': 0,
'U': 0, 'V': 3, 'W': 2, 'X': 0, 'Y': 0, 'Z': 3}
利用课件中的频率表,经过尝试发现密钥字为crypto,解密结果为:
ILEARNEDHOWTOCALCULATETHEAMOUNTOFPAPERNEEDEDF ORAROOMWHENIWASATSCHOOLYOUMULTIPLYTHESQUAREFO OTAGEOFTHEWALLSBYTHECUBICCONTENTSOFTHEFLOORAN DCEILINGCOMBINEDANDDOUBLEITYOUTHENALLOWHALFTH ETOTALFOROPENINGSSUCHASWINDOWSANDDOORSTHENYOU ALLOWTHEOTHERHALFFORMATCHINGTHEPATTERNTHENYOU DOUBLETHEWHOLETHINGAGAINTOGIVEAMARGINOFERRORA NDTHENYOUORDERTHEPAPER