凯撒密码的加密强度是很低的,只需简单地统计字频就可以破译。人们在单一凯撒密码的基础上扩展出多表密码,称为“维吉尼亚”密码。
维吉尼亚密码引入了“密钥”的概念,即根据密钥来决定用哪一行的密码表来进行替换,以此来对抗字频统计。
假如以上面第一行代表明文字母,左面第一列代表密钥字母,对如下明文加密:
TO BE OR NOT TO BE THAT IS THE QUESTION
当选定RELATIONS作为密钥时,加密过程是:明文一个字母为T,第一个密钥字母为R,因此可以找到在R行中代替T的为K,依此类推,得出对应关系如下:
密钥: RE LA TI ONS RE LA TION SR ELA TIONSREL
明文: TO BE OR NOT TO BE THAT IS THE QUESTION
密文: KS ME HZ BBL KS ME MPOG AJ XSE JCSFLZSY
小写字母采用相同的加密表格和加密方法(将上述方法里的大写字母换为小写字母即可)。
遇到数字时,可将其密钥字母在密码表中的偏移量对10取模的结果作为在数字表格中的偏移量,例如:
“1”的密钥“R”在表格中的偏移量为“17”(A在字母表里的偏移量为0),偏移量对10取模结果为“7”,加密时,查表格中“1”对应的列“1 2 3 4 5 6 7 8 9 0”中序号为“7”的数字,得到加密结果应为8,“9”的密钥“E”的偏移量是“4”,在“9”对应的行中序号为“4”的数字是“3”。
密钥: RELA
明文: 1945
密文: 8355
解密方法与上述操作正好相反,先查出当前字符在密码表中偏移后的位置,再到初始字符集中查找对应的字符。
你的好朋友小明在星期三的早晨给你发了一封电子邮件,你看到的内容是“Km Ztftrs 4, 5723, sgd Tmesdc Rszsdo cqnoodc sdd bncd mzlac "khsskd akx" ne sgd zsklhb anlahjf ne Ghqnrdhlz, Izozm.”。
然后在你在QQ 收到小明发给你的这样一条消息:维吉尼亚问你今天是星期几? 聪明的你猜出来邮件内容是用维吉尼亚加密方法加密过的,密钥是星期三(收到消息的日期)的英文单词,写个程序解密小明的邮件并输出明文吧!
编写一个程序,根据密钥对密文解密后输出。
输入格式
输入为两行,第一行是密钥secret_key,第二行是密文cipher_text。
输出格式
输出为一行,是对输入密文cipher_text解密后的明文plain_text。
import string
def vigenere_decrypt(text, key):
"""接收密文字符串和密钥字符串为参数,返回解密后的字符串.
解密时字母和数字以外的其他字符原样输出。"""
lower_tab = string.ascii_lowercase # 小写字母
upper_tab = string.ascii_uppercase # 大写字母
digit_tab = string.digits
plain_text = ''
key_index = 0
for char in text:
if char.isupper():
offset = ord(key[key_index % len(key)].upper()) - ord('A')
plain_text += upper_tab[(upper_tab.index(char) - offset) % 26]
key_index += 1
elif char.islower():
offset = ord(key[key_index % len(key)].lower()) - ord('a')
plain_text += lower_tab[(lower_tab.index(char) - offset) % 26]
key_index += 1
elif char.isdigit():
offset = ord(key[key_index % len(key)].upper()) - ord('A')
plain_text += digit_tab[(digit_tab.index(char) - offset) % 10]
key_index += 1
else:
plain_text += char
return plain_text
if __name__ == '__main__':
secret_key = input()
cipher_text = input()
plain_text = vigenere_decrypt(cipher_text, secret_key)
print(f'解密后得到的明文是{plain_text}')