实验一 古典密码算法的实现

实验内容

  1. 根据实验原理部分对替代密码算法的介绍,实现以下替代密码算法的加密和解密操作,并完成明密文之间的频率统计分析。
    1. 凯撒密码
    2. 维吉尼亚密码 Vigenere
    3. PlayFair密码
    4. 一次一密 One-time Pad
  2. 根据实验原理部分对置换密码算法的介绍,自己创建明文信息,并选择一个密钥,编写置换密码算法的实现程序,实现加密和解密操作。

实验目的

通过编程实现替代密码算法和置换密码算法,加深对古典密码体制的了解,为深入学习密码学奠定基础。

实验原理

古典密码算法在历史上曾被广泛使用,大都比较简单,使用手工和机械操作来实现加密和解密。它的主要应用对象是文字信息,利用密码算法实现文字信息的加密和解密。下面介绍两种常见的具有代表性的古典密码算法,以帮助读者对古典密码算法建立一个初步的印象。

替代密码

替代密码算法的原理是使用替代法进行加密,就是将明文中的字符用其它字符替代后形成密文。例如明文字母 a,b,c,d 用 D,E,F,G 做对应替换后形成密文。

替代密码包括多种类型,如单表替代密码、多明码替代密码、多字母替代密码、多表替代密码。下面我们介绍一种典型的单表替代密码:恺撒(caesar)密码,又叫循环移位密码。它的加密方法就是将明文中的每个字母用此字符在字母表中后面第kk 个字母替代。它的加密过程可以表示为下面的函数:

E(m)=(m+k) mod nE(m)=(m+k)\ mod\ n

其中:mm 为明文字母在字母表中的位置数;nn 为字母表中的字母个数;kk 为密钥;E(m)E(m) 为密文字母在字母表中对应的位置数。

置换密码

置换密码算法的原理是不改变明文字符,只将字符在明文中的排列顺序改变,从而实现明文信息的加密。置换密码有时又称为换位密码。

矩阵换位法是实现置换密码的一种常用方法,它将明文中的字母按照给的顺序安排在一个矩阵中,然后根据密钥提供的顺序重新组合矩阵中字母,从而形成密文。例如明文为 attack begins at five,密钥为 cipher,将明文按照每行 6 列的形式排在矩阵中,形成如下形式:

[attackbeginsatfive]\left[ \begin{matrix} a&t&t&a&c&k\\ b&e&g&i&n&s\\ a&t&f&i&v&e \end{matrix} \right]

根据密钥 cipher 中各字母在字母表中出现的先后顺序,给定一个置换:

[123456154236]\left[ \begin{matrix} 1&2&3&4&5&6\\ 1&5&4&2&3&6 \end{matrix} \right]

根据上面的置换,原有矩阵中的字母排列为以下形式:

[acattkbniegsavitfe]\left[ \begin{matrix} a&c&a&t&t&k\\ b&n&i&e&g&s\\ a&v&i&t&f&e \end{matrix} \right]

从而得到密文:acattkbniegsavitfe

其解密的过程是根据密钥的字母数作为列数,将密文按照列、行的顺序写出,再根据由密钥给出的矩阵置换产生新的矩阵,从而恢复明文。

实验步骤

凯撒密码 Caser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def encrypt(message, key):
tmp_text = ''
tmp_key = key.upper()
for c in message:
if not c.isalpha():
tmp_text += c
else:
if c.isupper(): a = 'A'
else: a = 'a'
tmp_text += chr(ord(a)+((ord(c)-ord(a)) + (ord(tmp_key)-ord('A')))% 26)
return tmp_text

def decrypt(message, key):
tmp_text = ''
tmp_key = key.upper()
for c in message:
if not c.isalpha():
tmp_text += c
else:
if c.isupper(): a = 'A'
else: a = 'a'
tmp_text += chr(ord(a)+((ord(c)-ord(a)) - (ord(tmp_key)-ord('A')))% 26)
return tmp_text

def main():
message = 'Common sense is not so common.'
key = 'P'

cipher_text = encrypt(message, key)
decrypted_text = decrypt(cipher_text, key)

print("加解密方式: 凯撒密码 Caser")
print("加密前的文本是:", message)
print("加密密钥是:", key)
print("加密后的文本是:", cipher_text)
print("解密后的文本是:", decrypted_text)

if __name__ == '__main__':
main()
1
2
3
4
5
加解密方式: 凯撒密码 Caser
加密前的文本是: Common sense is not so common.
加密密钥是: P
加密后的文本是: Rdbbdc htcht xh cdi hd rdbbdc.
解密后的文本是: Common sense is not so common.

维吉尼亚密码 Vigenere

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def encrypt(message, key):
tmp_text = ''
keylen = len(key)
tmp_key = key.upper()
i = 0
for c in message:
if not c.isalpha():
tmp_text += c
else:
if c.isupper(): a = 'A'
else: a = 'a'
tmp_text += chr(ord(a)+((ord(c)-ord(a)) + (ord(tmp_key[i])-ord('A')))% 26)
i += 1
if i == keylen: i = 0
return tmp_text

def decrypt(message, key):
tmp_text = ''
keylen = len(key)
tmp_key = key.upper()
i = 0
for c in message:
if not c.isalpha():
tmp_text += c
else:
if c.isupper(): a = 'A'
else: a = 'a'
tmp_text += chr(ord(a)+((ord(c)-ord(a)) - (ord(tmp_key[i])-ord('A')))% 26)
i += 1
if i == keylen: i = 0
return tmp_text

def main():
message = 'Common sense is not so common.'
key = 'PIZZA'

cipher_text = encrypt(message, key)
decrypted_text = decrypt(cipher_text, key)

print("加解密方式: 维吉尼亚密码 Vigenere")
print("加密前的文本是:", message)
print("加密密钥是:", key)
print("加密后的文本是:", cipher_text)
print("解密后的文本是:", decrypted_text)

if __name__ == '__main__':
main()
1
2
3
4
5
加解密方式: 维吉尼亚密码 Vigenere
加密前的文本是: Common sense is not so common.
加密密钥是: PIZZA
加密后的文本是: Rwlloc admst qr moi an bobunm.
解密后的文本是: Common sense is not so common.

普莱费尔密码 playfair

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import numpy as np

def gen_keylist(key):
base = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'
tmp_key = key.upper().replace(' ','').replace('J','I')
keylist = ''
for c in tmp_key:
if c not in keylist: keylist += c
for c in base:
if c not in keylist: keylist += c

return(keylist)

def gen_keytab(keylist):
keytab = np.zeros((5,5),dtype=str)
for i in range(25):
j = i % 5
k = i // 5
keytab[j][k] = keylist[i]

return(keytab)

def gen_keydic(keylist):
keydic = dict()
for i in range(25):
keydic[keylist[i]] = [i % 5, i // 5]

return(keydic)

def encrypt(message, key):
tmp_text = ''
for c in message.upper():
if c.isalpha():
if c == 'J': tmp_text += 'I'
elif c == tmp_text[-1:]:
tmp_text += 'X'
tmp_text += c
else: tmp_text += c
if len(tmp_text) % 2 == 1: tmp_text += 'X'

keylist = gen_keylist(key)
keytab = gen_keytab(keylist)
keydic = gen_keydic(keylist)
# print(tmp_text)
# print(keytab)
tmpstr = ''
for i in range(len(tmp_text) // 2):
j = i * 2
a = tmp_text[j]
b = tmp_text[j+1]
# print(a,b)
# print(keydic[a],keydic[b])
if keydic[a][0] == keydic[b][0]:
tmp = keydic[a][0]
tmpa = keytab[tmp][(keydic[a][1]+1)%5]
tmpb = keytab[tmp][(keydic[b][1]+1)%5]
elif keydic[a][1] == keydic[b][1]:
tmp = keydic[a][1]
tmpa = keytab[(keydic[a][0]+1)%5][tmp]
tmpb = keytab[(keydic[b][0]+1)%5][tmp]
else:
tmpa = keytab[keydic[a][0]][keydic[b][1]]
tmpb = keytab[keydic[b][0]][keydic[a][1]]
tmpstr += tmpa
tmpstr += tmpb
# print(tmpstr)
encrypted_text = ''
for i in range(len(tmpstr)):
encrypted_text += tmpstr[i]
if i % 5 == 4: encrypted_text += ' '

return(encrypted_text)

def decrypt(message, key):
tmp_text = message.replace(' ','')

keylist = gen_keylist(key)
keytab = gen_keytab(keylist)
keydic = gen_keydic(keylist)

tmpstr = ''
for i in range(len(tmp_text)//2):
j = i * 2
a = tmp_text[j]
b = tmp_text[j+1]
if keydic[a][0] == keydic[b][0]:
tmp = keydic[a][0]
tmpa = keytab[tmp][(keydic[a][1]-1)%5]
tmpb = keytab[tmp][(keydic[b][1]-1)%5]
elif keydic[a][1] == keydic[b][1]:
tmp = keydic[a][1]
tmpa = keytab[(keydic[a][0]-1)%5][tmp]
tmpb = keytab[(keydic[b][0]-1)%5][tmp]
else:
tmpa = keytab[keydic[a][0]][keydic[b][1]]
tmpb = keytab[keydic[b][0]][keydic[a][1]]
tmpstr += tmpa
tmpstr += tmpb

decrypted_text = tmpstr[0]
for i in range(1, len(tmpstr)-1):
if (tmpstr[i] == 'X') and (tmpstr[i-1] == tmpstr[i+1]):
continue
else: decrypted_text += tmpstr[i]
if tmpstr[-1:] != 'X': decrypted_text += tmpstr[-1:]

return(decrypted_text)

def try_english(message):
with open('dictionary.txt','r') as f:
wordlist = f.readlines()
for i in range(len(wordlist)):
wordlist[i] = wordlist[i].rstrip('\n')

decrypted_text = ''
tmpword = ''
for c in message:
tmpword += c
if tmpword in wordlist:
decrypted_text += tmpword.lower()
decrypted_text += ' '
tmpword = ''
decrypted_text += tmpword.lower()

return(decrypted_text)

def main():
message = 'Common sense js not so common.'
key = 'Keep it Simple and Stupid.'

cipher_text = encrypt(message, key)
decrypted_text = decrypt(cipher_text, key)

print("加解密方式: 普莱费尔密码 playfair 按列填充密钥,横向替换密文,I替代J")
print("加密前的文本是:", message)
print("加密密钥是:", key)
print("加密后的文本是:", cipher_text)
print("解密后的文本是:", decrypted_text)
print("尝试解读:", try_english(decrypted_text))
# 暂时解决不了

if __name__ == '__main__':
main()
1
2
3
4
5
6
加解密方式: 普莱费尔密码 playfair 按列填充密钥,横向替换密文,I替代J
加密前的文本是: Common sense js not so common.
加密密钥是: Keep it Simple and Stupid.
加密后的文本是: QBVAG ASMMT KMAKQ ANKBQ AGAVA Q
解密后的文本是: COMMONSENSEISNOTSOCOMMON
尝试解读: common sense isnotsocommon

一次一密 One-time Pad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def encrypt(message, key):
list = [chr(ord(a)^ord(b)) for a,b in zip(message,key)]

return(bytes(''.join(list),encoding='utf-8'))

def decrypt(message, key):
tmp_message = message.decode()
list = [chr(ord(a)^ord(b)) for a,b in zip(tmp_message,key)]

return(''.join(list))

def main():
message = 'Common sense is not so common.'
key = message[::-1]

cipher_text = encrypt(message, key)
decrypted_text = decrypt(cipher_text, key)

print("加解密方式: 一次一密 One-time Pad")
print("加密前的文本是:", message)
print("加密密钥是:", key)
print("加密后的文本是:", cipher_text)
print("解密后的文本是:", decrypted_text)

if __name__ == '__main__':
main()
1
2
3
4
5
加解密方式: 一次一密 One-time Pad
加密前的文本是: Common sense is not so common.
加密密钥是: .nommoc os ton si esnes nommoC
加密后的文本是: b'm\x01\x02\x00\x02\x01CS\n\x1dS\x11O\x07SS\x07O\x11S\x1d\nSC\x01\x02\x00\x02\x01m'
解密后的文本是: Common sense is not so common.

置换密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import numpy as np

def gen_keylist(key):
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
keydic = dict()
tmp = 0
for c in key.upper():
if c not in keydic.keys():
tmp += 1
keydic[c] = tmp
keylist = []
for c in base:
if c in keydic.keys():
keylist.append(keydic[c])

return(keylist)

def encrypt(message, key):
keylist = gen_keylist(key)
tmp_text = ''
for c in message:
if c.isalpha(): tmp_text += c
length = len(tmp_text)
col = len(keylist)
row = (length-1) // col + 1
mess_tab = np.zeros((row, col), dtype=str)
for i in range(length):
mess_tab[i//col][i%col] = tmp_text[i]
tmp_tab = np.zeros((row, col), dtype=str)
for i in range(col):
for j in range(row):
tmp_tab[j][i] = mess_tab[j][keylist[i]-1]
encrypted_text = ''
for i in range(row):
for j in range(col):
encrypted_text += tmp_tab[i][j]

return(encrypted_text)


def decrypt(message, key):
keylist = gen_keylist(key)
tmp_text = message
length = len(tmp_text)
col = len(keylist)
row = (length-1) // col + 1
mess_tab = np.zeros((row, col), dtype=str)
for i in range(length):
mess_tab[i//col][i%col] = tmp_text[i]
tmp_tab = np.zeros((row, col), dtype=str)
for i in range(col):
for j in range(row):
tmp_tab[j][keylist[i]-1] = mess_tab[j][i]
decrypted_text = ''
for i in range(row):
for j in range(col):
decrypted_text += tmp_tab[i][j]

return(decrypted_text)

def main():
message = 'Attack begins at five.'
key = 'cipher'

cipher_text = encrypt(message, key)
decrypted_text = decrypt(cipher_text, key)

print("加解密方式: 置换密码")
print("加密前的文本是:", message)
print("加密密钥是:", key)
print("加密后的文本是:", cipher_text)
print("解密后的文本是:", decrypted_text)

if __name__ == '__main__':
main()
1
2
3
4
5
加解密方式: 置换密码
加密前的文本是: Attack begins at five.
加密密钥是: cipher
加密后的文本是: Acattkbniegsavitfe
解密后的文本是: Attackbeginsatfive

实验总结

关于字母频率分析,额外进行了kasiski试验实现对维吉尼亚密码的唯密文攻击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
import math
import vigenere

def pre_treatment(message):
# 提取字母
tmp_text = ''
for c in message:
if c.isalpha():
tmp_text += c
# 全员大写
return(tmp_text.upper())

def find_repeat_sequences_spacings(message):
# 预处理字符串
tmp_text = pre_treatment(message)
# 生成重复序列间隔字典
dic = dict()
# 查找3-5位字母长度的重复序列
for strlen in range(3,6):
for i in range(0,len(tmp_text)-2*strlen+1):
tmp_str = tmp_text[i:i+strlen]
tmp_count = tmp_text.count(tmp_str)
if tmp_count > 1:
if tmp_str not in dic.keys():
last = tmp_text.find(tmp_str)
find_list = [last]
for j in range(1,tmp_count):
now = tmp_text.find(tmp_str,last+strlen)
find_list.append(now)
last = now
spacing_list = []
listlen = len(find_list)
for j in range(0,listlen-1):
for k in range(j+1,listlen):
spacing_list.append(find_list[k]-find_list[j])
dic[tmp_str] = spacing_list

return(dic)

def get_useful_factors(num):
factors_list = []
for i in range(2,math.isqrt(num)+1):
if num % i == 0:
factors_list.append(i)
j = num//i
if i != j:
factors_list.append(j)
factors_list.sort()

return(factors_list)

def get_possible_keylen(message):
tmp_dic = find_repeat_sequences_spacings(message)
dic_fac = dict()
for i in tmp_dic:
for j in tmp_dic[i]:
tmp_fac = get_useful_factors(j)
for k in tmp_fac:
if k not in dic_fac:
dic_fac[k] = 1
else:
dic_fac[k] += 1
list_fac = []
for i in sorted(dic_fac.items(), key=lambda x:(-x[1],x[0])):
# print(i)
list_fac.append(i[0])

return(list_fac)

def get_nth_subkeys_letters(n, key_length, message):
# 预处理字符串
tmp_text = pre_treatment(message)
tmp_str = ''
i = 0
for c in tmp_text:
if i % key_length == n-1:
tmp_str += c
i += 1

return(tmp_str)

def freq_match_score(message):
ETAOIN = 'ETAOINSHRDLCUMWFGYPBVKJXQZ'
match_score = 0
tmp_text = pre_treatment(message)
# 初始化计数字典并计数
# base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# 上面这行注释绝妙,无意间解决了ETAOIN排序问题
dic_letter_freq = dict()
for c in ETAOIN:
dic_letter_freq[c] = 0
for c in tmp_text:
dic_letter_freq[c] += 1
# 生成频数字母列表字典
dic_freq_letter = dict()
for i in dic_letter_freq.items():
if i[1] not in dic_freq_letter.keys():
dic_freq_letter[i[1]] = [i[0]]
else:
dic_freq_letter[i[1]].append(i[0])
# 频数字典排序生成匹配串
freq_string = ''
for f in sorted(dic_freq_letter.items(),key=lambda x:(-x[0])):
for c in f[1]:
freq_string += c
# 累计频率匹配分数
for c in freq_string[:6]:
if c in ETAOIN[:6]:
match_score += 1
for c in freq_string[-6:]:
if c in ETAOIN[-6:]:
match_score += 1

return(match_score)

# 另一种字母频率分析
def freq_score(message):
tmp_text = pre_treatment(message)
dic_freq = dict()
dic_freq = {'A': 8.167, 'B': 1.492, 'C': 2.782, 'D': 4.253,
'E': 12.702, 'F': 2.228, 'G': 2.015, 'H': 6.094,
'I': 6.966, 'J': 0.153, 'K': 0.772, 'L': 4.025,
'M': 2.406, 'N': 6.749, 'O': 7.507, 'P': 1.929,
'Q': 0.095, 'R': 5.987, 'S': 6.327, 'T': 9.056,
'U': 2.758, 'V': 0.978, 'W': 2.360, 'X': 0.150,
'Y': 1.974, 'Z': 0.074}
count = 0
sum = 0
for c in tmp_text:
count += 1
sum += dic_freq[c]
return(sum/count)

def is_english(message, word_percentage=20, letter_percentage=85):
# 加载字典生成字典列表
with open('dictionary.txt', 'r') as f:
wordlist = f.readlines()
for i in range(0,len(wordlist)):
wordlist[i] = wordlist[i].rstrip('\n')
# 英文检测
tmp_text = message.upper()
tmp_wordlist = []
tmp_word = ''
sum_letter = 0
sum_word = 0
for c in tmp_text:
if c.isalpha():
tmp_word += c
sum_letter += 1
else:
if c.isspace():
sum_letter += 1
tmp_wordlist.append(tmp_word)
tmp_word = ''
for w in tmp_wordlist:
if w in wordlist:
sum_word += 1
freq_letter = sum_letter / len(tmp_text) * 100
freq_word = sum_word / len(tmp_wordlist) * 100
# print(freq_letter)
# print(freq_word)
if (freq_letter >= letter_percentage) and (freq_word >= word_percentage):
return(True)
else:
return(False)

def test():
ciphertext = 'Ppqca xqvekg ybnkmazu ybngbal jon i tszm jyim. Vrag voht vrau c tksg. Ddwuo xitlazu vavv raz c vkb qp iwpou.'

print(find_repeat_sequences_spacings(ciphertext))
print(get_useful_factors(24))

print(get_possible_keylen(ciphertext))

for i in range(1, 5):
print(get_nth_subkeys_letters(i, 4, ciphertext))

message = 'I rc ascwuiluhnviwuetnh,osgaa ice tipeeeee slnatsfietgi tittynecenisl. e fo f fnc isltn sn o a yrs sd onisli ,l erglei trhfmwfrogotn,l stcofiit.aea wesn,lnc ee w,l eIh eeehoer ros iol er snh nl oahsts ilasvih tvfeh rtira id thatnie.im ei-dlmf i thszonsisehroe, aiehcdsanahiec gv gyedsB affcahiecesd d lee onsdihsoc nin cethiTitx eRneahgin r e teom fbiotd n ntacscwevhtdhnhpiwru'
print(freq_match_score(message))

def kasiski(message):
flag = False
# 尝试最有可能的5种密钥长度
for keylen in get_possible_keylen(message)[:5]:
print('keylen = ', keylen)
dic_key = dict()
for i in range(0, keylen):
base_string = get_nth_subkeys_letters(i+1, keylen, message)
dic_score = dict()
top_guess = 3 # 每位密钥测试3个最有可能的字母
for j in range(0, 26):
tmp_string = ''
for c in base_string:
tmp_string += chr(ord('A')+(ord(c)-ord('A')-j) % 26)
dic_score[chr(ord('A')+j)] = freq_score(tmp_string)
dic_key[i] = ''
tmp_count = 0
for k in sorted(dic_score.items(),key=lambda x:-x[1]):
tmp_count += 1
dic_key[i] += k[0]
print(i,tmp_count, k)
if tmp_count == top_guess:
break
print(dic_key)
# 参考二进制思想生成可能密钥
for i in range(0, top_guess**keylen):
tmp_key = ''
if i == 0:
for j in range(0, keylen):
tmp_key += dic_key[j][0]
else:
tmp = i
dkey = -1
while tmp > 0:
dkey += 1
dvalue = tmp % top_guess
tmp_key += dic_key[dkey][dvalue]
tmp //= top_guess
for j in range(dkey+1, keylen):
tmp_key += dic_key[j][0]
# 尝试解密
decrypted_text = vigenere.decrypt(message, tmp_key)
if is_english(decrypted_text):
print(decrypted_text)
print('key =',tmp_key)
flag = True
break
if flag:
break

def main():
message = ''
with open('ciphertext_vigenere.txt','r') as f:
for i in f.readlines():
message += i

print(message)

kasiski(message)

if __name__ == '__main__':
# test()
main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Adiz Avtzqeci Tmzubb wsa m Pmilqev halpqavtakuoi, lgouqdaf, kdmktsvmztsl, izr xoexghzr kkusitaaf. Vz wsa twbhdg ubalmmzhdad qz hce vmhsgohuqbo ox kaakulmd gxiwvos, krgdurdny i rcmmstugvtawz ca tzm ocicwxfg jf "stscmilpy" oid "uwydptsbuci" wabt hce Lcdwig eiovdnw. Bgfdny qe kddwtk qjnkqpsmev ba pz tzm roohwz at xoexghzr kkusicw izr vrlqrwxist uboedtuuznum. Pimifo Icmlv Emf DI, Lcdwig owdyzd xwd hce Ywhsmnemzh Xovm mby Cqxtsm Supacg (GUKE) oo Bdmfqclwg Bomk, Tzuhvif'a ocyetzqofifo ositjm. Rcm a lqys ce oie vzav wr Vpt 8, lpq gzclqab mekxabnittq tjr Ymdavn fihog cjgbhvnstkgds. Zm psqikmp o iuejqf jf lmoviiicqg aoj jdsvkavs Uzreiz qdpzmdg, dnutgrdny bts helpar jf lpq pjmtm, mb zlwkffjmwktoiiuix avczqzs ohsb ocplv nuby swbfwigk naf ohw Mzwbms umqcifm. Mtoej bts raj pq kjrcmp oo tzm Zooigvmz Khqauqvl Dincmalwdm, rhwzq vz cjmmhzd gvq ca tzm rwmsl lqgdgfa rcm a kbafzd-hzaumae kaakulmd, hce SKQ. Wi 1948 Tmzubb jgqzsy Msf Zsrmsv'e Qjmhcfwig Dincmalwdm vt Eizqcekbqf Pnadqfnilg, ivzrw pq onsaafsy if bts yenmxckmwvf ca tzm Yoiczmehzr uwydptwze oid tmoohe avfsmekbqr dn eifvzmsbuqvl tqazjgq. Pq kmolm m dvpwz ab ohw ktshiuix pvsaa at hojxtcbefmewn, afl bfzdakfsy okkuzgalqzu xhwuuqvl jmmqoigve gpcz ie hce Tmxcpsgd-Lvvbgbubnkq zqoxtawz, kciup isme xqdgo otaqfqev qz hce 1960k. Bgfdny'a tchokmjivlabk fzsmtfsy if i ofdmavmz krgaqqptawz wi 1952, wzmz vjmgaqlpad iohn wwzq goidt uzgeyix wi tzm Gbdtwl Wwigvwy. Vz aukqdoev bdsvtemzh rilp rshadm tcmmgvqg (xhwuuqvl uiehmalqab) vs sv mzoejvmhdvw ba dmikwz. Hpravs rdev qz 1954, xpsl whsm tow iszkk jqtjrw pug 42id tqdhcdsg, rfjm ugmbddw xawnofqzu. Vn avcizsl lqhzreqzsy tzif vds vmmhc wsa eidcalq; vds ewfvzr svp gjmw wfvzrk jqzdenmp vds vmmhc wsa mqxivmzhvl. Gv 10 Esktwunsm 2009, fgtxcrifo mb Dnlmdbzt uiydviyv, Nfdtaat Dmiem Ywiikbqf Bojlab Wrgez avdw iz cafakuog pmjxwx ahwxcby gv nscadn at ohw Jdwoikp scqejvysit xwd "hce sxboglavs kvy zm ion tjmmhzd." Sa at Haq 2012 i bfdvsbq azmtmd'g widt ion bwnafz tzm Tcpsw wr Zjrva ivdcz eaigd yzmbo Tmzubb a kbmhptgzk dvrvwz wa efiohzd.
keylen = 3
0 1 ('A', 5.125612431444254)
0 2 ('M', 5.112906764168203)
0 3 ('Z', 4.292806215722134)
1 1 ('O', 5.333315018315032)
1 2 ('S', 5.273826007326018)
1 3 ('D', 4.486067765567781)
2 1 ('I', 5.830117216117233)
2 2 ('V', 5.392289377289392)
2 3 ('E', 4.267117216117228)
{0: 'AMZ', 1: 'OSD', 2: 'IVE'}
keylen = 2
0 1 ('I', 4.810197560975626)
0 2 ('O', 4.562274390243913)
0 3 ('A', 4.415186585365871)
1 1 ('M', 4.557256410256414)
1 2 ('V', 4.542681318681341)
1 3 ('I', 4.338537240537258)
{0: 'IOA', 1: 'MVI'}
keylen = 6
0 1 ('A', 6.367591240875909)
0 2 ('P', 5.041430656934308)
0 3 ('E', 4.885160583941612)
1 1 ('S', 6.245344322344322)
1 2 ('H', 4.7055934065934135)
1 3 ('W', 4.369351648351649)
2 1 ('I', 6.8673223443223455)
2 2 ('T', 4.873608058608065)
2 3 ('E', 4.650586080586077)
3 1 ('M', 6.306934065934067)
3 2 ('Z', 4.561073260073258)
3 3 ('Q', 4.492465201465203)
4 1 ('O', 6.575586080586089)
4 2 ('D', 4.607542124542126)
4 3 ('Z', 4.570794871794874)
5 1 ('V', 6.368021978021977)
5 2 ('I', 4.7929120879120966)
5 3 ('Z', 4.592890109890112)
{0: 'APE', 1: 'SHW', 2: 'ITE', 3: 'MZQ', 4: 'ODZ', 5: 'VIZ'}
Alan Mathison Turing was a British mathematician, logician, cryptanalyst, and computer scientist. He was highly influential in the development of computer science, providing a formalisation of the concepts of "algorithm" and "computation" with the Turing machine. Turing is widely considered to be the father of computer science and artificial intelligence. During World War II, Turing worked for the Government Code and Cypher School (GCCS) at Bletchley Park, Britain's codebreaking centre. For a time he was head of Hut 8, the section responsible for German naval cryptanalysis. He devised a number of techniques for breaking German ciphers, including the method of the bombe, an electromechanical machine that could find settings for the Enigma machine. After the war he worked at the National Physical Laboratory, where he created one of the first designs for a stored-program computer, the ACE. In 1948 Turing joined Max Newman's Computing Laboratory at Manchester University, where he assisted in the development of the Manchester computers and became interested in mathematical biology. He wrote a paper on the chemical basis of morphogenesis, and predicted oscillating chemical reactions such as the Belousov-Zhabotinsky reaction, which were first observed in the 1960s. Turing's homosexuality resulted in a criminal prosecution in 1952, when homosexual acts were still illegal in the United Kingdom. He accepted treatment with female hormones (chemical castration) as an alternative to prison. Turing died in 1954, just over two weeks before his 42nd birthday, from cyanide poisoning. An inquest determined that his death was suicide; his mother and some others believed his death was accidental. On 10 September 2009, following an Internet campaign, British Prime Minister Gordon Brown made an official public apology on behalf of the British government for "the appalling way he was treated." As of May 2012 a private member's bill was before the House of Lords which would grant Turing a statutory pardon if enacted.
key = ASIMOV

详见Vigenere维吉尼亚密码加解密及唯密文攻击

通过亲自实现一系列古典密码算法,深入理解了这几种古典密码的加解密过程。