在上一个例子里,我们实现了如下内容:
1,简单替换原则
2,把简单替换升级成了转子,每输入一个字母转子就转动一格
那么其实我们根本没有完成,因为我得到的密文,再输入恩格码机,无法反向解译
我们必须加一个关键的设置来实现反向解译,这个设备就是自反器!
自反器的工作原理还是很简单的,如下:
自反器其实就是成对成对出现的
如上图,如果你输入明文A,那么转子会加密为Q,然后找到自反器的Q,我们假设与Q成对出现的是Z,那么Z反向解转子,会得到密文T。
那么有了自反器,输入明文A,得到的是密文T
所以,同样的转子设置情况下,输入密文T,一定会反向得到明文A!,这就是恩格码的原理。
代码如下:
# -*- coding:utf-8 -*- # 本代码的目的是通过python实现德军二战时期的密码机:恩格玛 # 首先,第一步是定义一个简单的函数:简单字符替换 import re import string def simple_replace(password, replace_word): new_pass = '' # 设置一个空字符串准备接收密码 ori_table = 'abcdefghijklmnopqrstuvwxyz' # 原始的字符串,用来建立映射表 for obj in password: # 开始拆解原字符串 table = str.maketrans(ori_table, replace_word) # 建立映射表 new_obj = str.translate(obj, table) # 把obj通过映射表转换成new_obj new_obj = reverse_word(new_obj) # 进入自反队列,得到自反值 reverse_table = str.maketrans(replace_word, ori_table) # 增加自反出去的队列,反向解译 new_obj = str.translate(new_obj, reverse_table) # new_obj再赋值,把反向解译的结果赋予新值 new_pass += new_obj # 返回的密码增加一个new_obj replace_word = rotors(replace_word) # 转子转动 return new_pass # 返回新的已经被转子加密的密码 # 单独把判断写成一个函数吧,这样比较好区分 def is_str(password, replace_word): # 判断的函数 an = re.match('[a-z]+$', password) # 我没有考虑到的是,当时的enigma机是没有空格的,所以这里要求输入的明文也必须是小写字母 if not type(password) == type(replace_word) == type('a'): print('密码必须是字符串!') return False elif not an: print('字符串只能包含小写字母!') return False elif len(replace_word) != 26: print('替换码必须为26个字母!') return False else: return True # 修正了函数的写法,增加了一个返回true的选项 # 然而这并非一个完整版,因为转子还不会转动,我们下面让转子每输入一个字符就转动一次。 # 明显不能输入一次计算一次,所以让转子转动len(明文)次,然后依次处理每个字符就可以了 def rotors(replace_word): # 转子转动的函数,每调用一次,就把转子前面第一个字母移动到最后 return replace_word[1:] + replace_word[0] # 还没有自反器呢!加密之后无法解密,是何其的蛋疼! # 自反器很好设置的,只要设置一个字典,保证所有字母(26个)两两对应就可以了,怎么对应,你说了算! def reverse_word(word): dic = {'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q', 'e': 'r', 'f': 's', 'g': 't', 'h': 'u', 'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y', 'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c', 'q': 'd', 'r': 'e', 's': 'f', 't': 'g', 'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k', 'y': 'l', 'z': 'm'} return dic[word] while True: a_password = input('请输入明文:') r_password = 'qwertyuiopasdfghjklzxcvbnm' if is_str(a_password, r_password): print('密文如下:', simple_replace(a_password, r_password)) break else: pass
那么我们下面把一个转子增加到3个转子,这个并没有太大的问题,只不过有两点需要注意:
1,第一个转子每个字符转动一次,第二个转子当第一个转子转动一整圈的时候,转动一次,第三个转子,当第二个转子转动一整圈的时候,转动一次。
那么我们需要计数器。
2,从自反器里出来的密码,要反向通过转子,也就是1-2-3-自反-3-2-1的顺序,这个不要搞错。
上代码:
# -*- coding:utf-8 -*- # 本代码的目的是通过python实现德军二战时期的密码机:恩格玛 import re import string def simple_replace(password, replace_word1, replace_word2, replace_word3): # 加密的主函数 count = 0 # 设置计数器 new_pass = '' # 设置一个空字符串准备接收密码 ori_table = 'abcdefghijklmnopqrstuvwxyz' # 原始的字符串,用来建立映射表 for obj in password: # 开始拆解原字符串 table1 = str.maketrans(ori_table, replace_word1) # 建立转子1的映射表 table2 = str.maketrans(ori_table, replace_word2) # 建立转子2的映射表 table3 = str.maketrans(ori_table, replace_word3) # 建立转子3的映射表 new_obj = str.translate(obj, table1) # 把obj通过转子1转换 new_obj = str.translate(new_obj, table2) # obj通过转子2 new_obj = str.translate(new_obj, table3) # obj通过转子3 new_obj = reverse_word(new_obj) # 进入自反器,得到自反值 reverse_table1 = str.maketrans(replace_word1, ori_table) # 增加自反出去的对应表,反向解译 reverse_table2 = str.maketrans(replace_word2, ori_table) reverse_table3 = str.maketrans(replace_word3, ori_table) new_obj = str.translate(new_obj, reverse_table3) # new_obj再赋值,反向解译通过转子3 new_obj = str.translate(new_obj, reverse_table2) # 通过转子2 new_obj = str.translate(new_obj, reverse_table1) # 通过转子1 new_pass += new_obj # 返回的密码增加一个new_obj replace_word1 = rotors(replace_word1) # 转子1每个字符都转动一次 count += 1 # 计数器增加1 if count % 676 == 0: # 如果模676为0,那么转子3转动一次(因为转子2已经转动了一整圈) replace_word3 = rotors(replace_word3) elif count % 26 == 0: # 如果模26为0,那么转子2转动一次(因为转子1已经转动了一整圈) replace_word2 = rotors(replace_word2) return new_pass # 返回新的已经被转子加密的密码 # 单独把判断写成一个函数吧,这样比较好区分 def is_str(password, replace_word): # 判断的函数 an = re.match('[a-z]+$', password) # 我没有考虑到的是,当时的enigma机是没有空格的,所以这里要求输入的明文也必须是小写字母 if not type(password) == type(replace_word) == type('a'): print('密码必须是字符串!') return False elif not an: print('字符串只能包含小写字母!') return False elif len(replace_word) != 26: print('替换码必须为26个字母!') return False else: return True # 修正了函数的写法,增加了一个返回true的选项 # 然而这并非一个完整版,因为转子还不会转动,我们下面让转子每输入一个字符就转动一次。 # 明显不能输入一次计算一次,所以让转子转动len(明文)次,然后依次处理每个字符就可以了 def rotors(replace_word): # 转子转动的函数,每调用一次,就把转子前面第一个字母移动到最后 return replace_word[1:] + replace_word[0] # 还没有自反器呢!加密之后无法解密,是何其的蛋疼! # 自反器很好设置的,只要设置一个字典,保证所有字母(26个)两两对应就可以了,怎么对应,你说了算! def reverse_word(word): dic = {'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q', 'e': 'r', 'f': 's', 'g': 't', 'h': 'u', 'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y', 'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c', 'q': 'd', 'r': 'e', 's': 'f', 't': 'g', 'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k', 'y': 'l', 'z': 'm'} return dic[word] while True: a_password = input('请输入明文:') r_password1 = 'qwertyuiopasdfghjklzxcvbnm' r_password2 = 'asdfqwerzxcvtyuiopghjklbnm' r_password3 = 'poiuytrewqasdfghjklmnbvcxz' if is_str(a_password, r_password1): print('密文如下:', simple_replace(a_password, r_password1, r_password2, r_password3)) break else: pass