用Python復現二戰德軍enigma密碼機
前言
我們知道,enigma機是德軍二戰中重要的情報加密機器,其有許多特點。
首先,它是一臺加解密一體機
其次,它有排己性,雖然多次輸入同一明文可能得到不同的密文,但明文a永遠不可能加密為其本身。這樣完美掩蓋本身明文的性質是由反射板造成的,但也最終在圖靈的利用下給瞭enigma機致命一擊。
enigma機先後有多種不同的型號,如3轉輪型,5轉輪型,5轉輪選3轉輪型等等。本人對三轉輪enigma機進行的程序復現。需要說明的是,由於enigma機的精華部分是轉子和反射板,所以代碼中也著重復現瞭這一過程,而對接線板進行瞭省略。畢竟,enigma機的厲害之處在於其瘋狂到近乎變態的做到瞭幾乎“一字一換表”,而接線板隻是做簡單的字母替換,本身並無新意。
代碼
話不多說,直接上代碼:(一些使用說明見文末)
# -*- coding: utf-8 -*- """ Created on Tue Jan 4 09:40:42 2022 @author: burger """ from numpy import random import numpy as np import time arr = np.array(['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']) #輸入一個批次號 num = input('請輸入您要使用的enigma機批次號XXX-XXX-XXX(示例:123-456-789)\n') filename = 'enigma_code_book.txt' with open(filename) as file_object: context = file_object.read() if num in context: number = context.find(num) arr_a=context[(number+12):(number+38)] #一號轉輪 arr_b=context[(number+39):(number+65)] #二號轉輪 arr_c=context[(number+66):(number+92)] #三號轉輪 arr_d=context[(number+93):(number+119)] #反射板 else: arr_a=random.permutation(arr) arr_b=random.permutation(arr) arr_c=random.permutation(arr) arr_d=random.permutation(arr) with open(filename,'a') as file_object: str_1='\n' str_1=str_1+num str_1+=' ' for i in range(len(arr_a)): str_1+=arr_a[i] str_1+=' ' for i in range(len(arr_b)): str_1+=arr_b[i] str_1+=' ' for i in range(len(arr_c)): str_1+=arr_c[i] str_1+=' ' for i in range(len(arr_d)): str_1+=arr_d[i] str_1+=' ' file_object.write(str_1) zzwz=input('請輸入初始轉子位置(規范為三個英文字母中間加兩個英文逗號)\n eg: a,b,c\n')#zzwz即轉子位置 zz_1=list(zzwz)[0] zz_2=list(zzwz)[2] zz_3=list(zzwz)[4] num_zz_1=ord(zz_1)-97 num_zz_2=ord(zz_2)-97 num_zz_3=ord(zz_3)-97 def main(): global num_zz_1 global num_zz_2 global num_zz_3 text=input('請輸入加密內容\n') for n in range(len(text)): string=list(text)[n] print(zhuanhuan(string),end='') num_zz_1+=1 if num_zz_1 == 26: num_zz_1 = 0 num_zz_2+=1 if num_zz_2 == 26: num_zz_2=0 num_zz_3+=1 if num_zz_3 == 26: num_zz_3 = 0 def zhuanhuan(letter): #a號轉輪 #右側有26個觸點 #生成a輪的隨機連線方式 a_1_1=False a_1_2=False a_1_3=False a_1_4=False a_1_5=False a_1_6=False a_1_7=False a_1_8=False a_1_9=False a_1_10=False a_1_11=False a_1_12=False a_1_13=False a_1_14=False a_1_15=False a_1_16=False a_1_17=False a_1_18=False a_1_19=False a_1_20=False a_1_21=False a_1_22=False a_1_23=False a_1_24=False a_1_25=False a_1_26=False if letter == 'a': a_1_1 = True if letter == 'b': a_1_2 = True elif letter == 'c': a_1_3 = True elif letter == 'd': a_1_4 = True elif letter == 'e': a_1_5 = True elif letter == 'f': a_1_6 = True elif letter == 'g': a_1_7 = True elif letter == 'h': a_1_8 = True elif letter == 'i': a_1_9 = True elif letter == 'j': a_1_10 = True elif letter == 'k': a_1_11 = True elif letter == 'l': a_1_12 = True elif letter == 'm': a_1_13 = True elif letter == 'n': a_1_14 = True elif letter == 'o': a_1_15 = True elif letter == 'p': a_1_16 = True elif letter == 'q': a_1_17 = True elif letter == 'r': a_1_18 = True elif letter == 's': a_1_19 = True elif letter == 't': a_1_20 = True elif letter == 'u': a_1_21 = True elif letter == 'v': a_1_22 = True elif letter == 'w': a_1_23 = True elif letter == 'x': a_1_24 = True elif letter == 'y': a_1_25 = True elif letter == 'z': a_1_26 = True a_1_first=[a_1_1,a_1_2,a_1_3,a_1_4,a_1_5,a_1_6,a_1_7,a_1_8,a_1_9,a_1_10,a_1_11,a_1_12,a_1_13,a_1_14,a_1_15,a_1_16,a_1_17,a_1_18,a_1_19,a_1_20,a_1_21,a_1_22,a_1_23,a_1_24,a_1_25,a_1_26] # print(a_1_first) a_1=[False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False] for i in range(26): global num_zz_1 a_1[i]=a_1_first[(num_zz_1-26)+i] # print(a_1) #左側有26個觸點 a_2_1=False a_2_2=False a_2_3=False a_2_4=False a_2_5=False a_2_6=False a_2_7=False a_2_8=False a_2_9=False a_2_10=False a_2_11=False a_2_12=False a_2_13=False a_2_14=False a_2_15=False a_2_16=False a_2_17=False a_2_18=False a_2_19=False a_2_20=False a_2_21=False a_2_22=False a_2_23=False a_2_24=False a_2_25=False a_2_26=False a_2=[a_2_1,a_2_2,a_2_3,a_2_4,a_2_5,a_2_6,a_2_7,a_2_8,a_2_9,a_2_10,a_2_11,a_2_12,a_2_13,a_2_14,a_2_15,a_2_16,a_2_17,a_2_18,a_2_19,a_2_20,a_2_21,a_2_22,a_2_23,a_2_24,a_2_25,a_2_26] #構建a號轉輪左右對應關系 for i in range(26): a_2[i]=a_1[ord(arr_a[i])-97] # print(a_2) #此時,a號轉輪建模成功 #b號轉輪 #右側有26個觸點 b_1_1=False b_1_2=False b_1_3=False b_1_4=False b_1_5=False b_1_6=False b_1_7=False b_1_8=False b_1_9=False b_1_10=False b_1_11=False b_1_12=False b_1_13=False b_1_14=False b_1_15=False b_1_16=False b_1_17=False b_1_18=False b_1_19=False b_1_20=False b_1_21=False b_1_22=False b_1_23=False b_1_24=False b_1_25=False b_1_26=False b_1=[b_1_1,b_1_2,b_1_3,b_1_4,b_1_5,b_1_6,b_1_7,b_1_8,b_1_9,b_1_10,b_1_11,b_1_12,b_1_13,b_1_14,b_1_15,b_1_16,b_1_17,b_1_18,b_1_19,b_1_20,b_1_21,b_1_22,b_1_23,b_1_24,b_1_25,b_1_26] #a輪傳給b輪 for i in range(26): global num_zz_2 b_1[i]=a_2[((num_zz_2)-26)+i] # print(b_1) #左側有26個觸點 b_2_1=False b_2_2=False b_2_3=False b_2_4=False b_2_5=False b_2_6=False b_2_7=False b_2_8=False b_2_9=False b_2_10=False b_2_11=False b_2_12=False b_2_13=False b_2_14=False b_2_15=False b_2_16=False b_2_17=False b_2_18=False b_2_19=False b_2_20=False b_2_21=False b_2_22=False b_2_23=False b_2_24=False b_2_25=False b_2_26=False b_2=[b_2_1,b_2_2,b_2_3,b_2_4,b_2_5,b_2_6,b_2_7,b_2_8,b_2_9,b_2_10,b_2_11,b_2_12,b_2_13,b_2_14,b_2_15,b_2_16,b_2_17,b_2_18,b_2_19,b_2_20,b_2_21,b_2_22,b_2_23,b_2_24,b_2_25,b_2_26] #構建b號轉輪左右對應關系 for i in range(26): b_2[i]=b_1[ord(arr_b[i])-97] # print(b_2) #此時,b號轉輪建模成功 #c號轉輪 #右側有26個觸點 c_1_1=False c_1_2=False c_1_3=False c_1_4=False c_1_5=False c_1_6=False c_1_7=False c_1_8=False c_1_9=False c_1_10=False c_1_11=False c_1_12=False c_1_13=False c_1_14=False c_1_15=False c_1_16=False c_1_17=False c_1_18=False c_1_19=False c_1_20=False c_1_21=False c_1_22=False c_1_23=False c_1_24=False c_1_25=False c_1_26=False c_1=[c_1_1,c_1_2,c_1_3,c_1_4,c_1_5,c_1_6,c_1_7,c_1_8,c_1_9,c_1_10,c_1_11,c_1_12,c_1_13,c_1_14,c_1_15,c_1_16,c_1_17,c_1_18,c_1_19,c_1_20,c_1_21,c_1_22,c_1_23,c_1_24,c_1_25,c_1_26] #b輪傳給c輪 for i in range(26): global num_zz_3 c_1[i]=b_2[((num_zz_3)-26)+i] # print(c_1) #左側有26個觸點 c_2_1=False c_2_2=False c_2_3=False c_2_4=False c_2_5=False c_2_6=False c_2_7=False c_2_8=False c_2_9=False c_2_10=False c_2_11=False c_2_12=False c_2_13=False c_2_14=False c_2_15=False c_2_16=False c_2_17=False c_2_18=False c_2_19=False c_2_20=False c_2_21=False c_2_22=False c_2_23=False c_2_24=False c_2_25=False c_2_26=False c_2=[c_2_1,c_2_2,c_2_3,c_2_4,c_2_5,c_2_6,c_2_7,c_2_8,c_2_9,c_2_10,c_2_11,c_2_12,c_2_13,c_2_14,c_2_15,c_2_16,c_2_17,c_2_18,c_2_19,c_2_20,c_2_21,c_2_22,c_2_23,c_2_24,c_2_25,c_2_26] #構建c號轉輪左右對應關系 for i in range(26): c_2[i]=c_1[ord(arr_c[i])-97] # print(c_2) #此時,c號轉輪建模成功 #c號轉輪反射板 for i in range(0,26,2): c_2[ord(arr_d[i])-97],c_2[ord(arr_d[i+1])-97]=c_2[ord(arr_d[i+1])-97],c_2[ord(arr_d[i])-97] #反向傳播 arr_c_2=[] arr_b_2=[] arr_a_2=[] arr_c_1=[] arr_b_1=[] arr_a_1=[] for i in range(26): arr_c_2.append(ord(arr_c[i])-97) arr_b_2.append(ord(arr_b[i])-97) arr_a_2.append(ord(arr_a[i])-97) arr_c_0=sorted(arr_c_2) arr_b_0=sorted(arr_b_2) arr_a_0=sorted(arr_a_2) for i in range(26): arr_c_1.append(arr_c_2.index(arr_c_0[i])) arr_b_1.append(arr_b_2.index(arr_c_0[i])) arr_a_1.append(arr_a_2.index(arr_c_0[i])) #c號轉輪反向傳播 c_3_1=False c_3_2=False c_3_3=False c_3_4=False c_3_5=False c_3_6=False c_3_7=False c_3_8=False c_3_9=False c_3_10=False c_3_11=False c_3_12=False c_3_13=False c_3_14=False c_3_15=False c_3_16=False c_3_17=False c_3_18=False c_3_19=False c_3_20=False c_3_21=False c_3_22=False c_3_23=False c_3_24=False c_3_25=False c_3_26=False c_3=[c_3_1,c_3_2,c_3_3,c_3_4,c_3_5,c_3_6,c_3_7,c_3_8,c_3_9,c_3_10,c_3_11,c_3_12,c_3_13,c_3_14,c_3_15,c_3_16,c_3_17,c_3_18,c_3_19,c_3_20,c_3_21,c_3_22,c_3_23,c_3_24,c_3_25,c_3_26] for i in range(26): c_3[i]=c_2[arr_c_1[i]] # print(c_3) #c輪傳給b輪 b_3_1=False b_3_2=False b_3_3=False b_3_4=False b_3_5=False b_3_6=False b_3_7=False b_3_8=False b_3_9=False b_3_10=False b_3_11=False b_3_12=False b_3_13=False b_3_14=False b_3_15=False b_3_16=False b_3_17=False b_3_18=False b_3_19=False b_3_20=False b_3_21=False b_3_22=False b_3_23=False b_3_24=False b_3_25=False b_3_26=False b_3=[b_3_1,b_3_2,b_3_3,b_3_4,b_3_5,b_3_6,b_3_7,b_3_8,b_3_9,b_3_10,b_3_11,b_3_12,b_3_13,b_3_14,b_3_15,b_3_16,b_3_17,b_3_18,b_3_19,b_3_20,b_3_21,b_3_22,b_3_23,b_3_24,b_3_25,b_3_26] for i in range(26): # global num_zz_3 b_3[i]=c_3[-(num_zz_3)+i]#左側有26個觸點 # print(b_3) #b號轉輪反向傳播 b_4_1=False b_4_2=False b_4_3=False b_4_4=False b_4_5=False b_4_6=False b_4_7=False b_4_8=False b_4_9=False b_4_10=False b_4_11=False b_4_12=False b_4_13=False b_4_14=False b_4_15=False b_4_16=False b_4_17=False b_4_18=False b_4_19=False b_4_20=False b_4_21=False b_4_22=False b_4_23=False b_4_24=False b_4_25=False b_4_26=False b_4=[b_4_1,b_4_2,b_4_3,b_4_4,b_4_5,b_4_6,b_4_7,b_4_8,b_4_9,b_4_10,b_4_11,b_4_12,b_4_13,b_4_14,b_4_15,b_4_16,b_4_17,b_4_18,b_4_19,b_4_20,b_4_21,b_4_22,b_4_23,b_4_24,b_4_25,b_4_26] for i in range(26): b_4[i]=b_3[arr_b_1[i]] # print(b_4) #b輪傳給a輪 a_3_1=False a_3_2=False a_3_3=False a_3_4=False a_3_5=False a_3_6=False a_3_7=False a_3_8=False a_3_9=False a_3_10=False a_3_11=False a_3_12=False a_3_13=False a_3_14=False a_3_15=False a_3_16=False a_3_17=False a_3_18=False a_3_19=False a_3_20=False a_3_21=False a_3_22=False a_3_23=False a_3_24=False a_3_25=False a_3_26=False a_3=[a_3_1,a_3_2,a_3_3,a_3_4,a_3_5,a_3_6,a_3_7,a_3_8,a_3_9,a_3_10,a_3_11,a_3_12,a_3_13,a_3_14,a_3_15,a_3_16,a_3_17,a_3_18,a_3_19,a_3_20,a_3_21,a_3_22,a_3_23,a_3_24,a_3_25,a_3_26] for i in range(26): # global num_zz_2 a_3[i]=b_4[-(num_zz_2)+i]#左側有26個觸點 # print(a_3) #a號轉輪反向傳播 a_4_1=False a_4_2=False a_4_3=False a_4_4=False a_4_5=False a_4_6=False a_4_7=False a_4_8=False a_4_9=False a_4_10=False a_4_11=False a_4_12=False a_4_13=False a_4_14=False a_4_15=False a_4_16=False a_4_17=False a_4_18=False a_4_19=False a_4_20=False a_4_21=False a_4_22=False a_4_23=False a_4_24=False a_4_25=False a_4_26=False a_4=[a_4_1,a_4_2,a_4_3,a_4_4,a_4_5,a_4_6,a_4_7,a_4_8,a_4_9,a_4_10,a_4_11,a_4_12,a_4_13,a_4_14,a_4_15,a_4_16,a_4_17,a_4_18,a_4_19,a_4_20,a_4_21,a_4_22,a_4_23,a_4_24,a_4_25,a_4_26] for i in range(26): a_4[i]=a_3[arr_a_1[i]] # print(a_4) #a輪傳回 z_3_1=False z_3_2=False z_3_3=False z_3_4=False z_3_5=False z_3_6=False z_3_7=False z_3_8=False z_3_9=False z_3_10=False z_3_11=False z_3_12=False z_3_13=False z_3_14=False z_3_15=False z_3_16=False z_3_17=False z_3_18=False z_3_19=False z_3_20=False z_3_21=False z_3_22=False z_3_23=False z_3_24=False z_3_25=False z_3_26=False z_3=[z_3_1,z_3_2,z_3_3,z_3_4,z_3_5,z_3_6,z_3_7,z_3_8,z_3_9,z_3_10,z_3_11,z_3_12,z_3_13,z_3_14,z_3_15,z_3_16,z_3_17,z_3_18,z_3_19,z_3_20,z_3_21,z_3_22,z_3_23,z_3_24,z_3_25,z_3_26] for i in range(26): # global num_zz_1 z_3[i]=a_4[-(num_zz_1)+i] # print(z_3) for i in range(26): if z_3[i]==True: return(chr(i+97)) if __name__ == '__main__': main()
簡單解釋一下代碼,大體思路是用boolean類型的列表來表示每組26個觸頭的有電無電情況,在復現過程中用到瞭後來圖靈在破解enigma機的時候用到的一種思想:將兩個接線情況完全對稱的enigma機並排放置。其中對True傳遞的處理方法和反射板的模擬方法是本人較為滿意的地方。
反射過程中,有一個較有意思的東西。上圖:
以四個觸點為例,在正向傳播時,我們以左面觸點為基準,讀取右面觸點的序號為3 4 1 2,在反向傳播時,我們以右面觸點為基準,讀取左面觸點序號為2 4 1 3。如何根據3412來構建出2413是一個關鍵。筆者的一個朋友提供瞭一個很好的思路。假設3412儲存在列表A中,對列表A進行從小到大的排序,儲存在列表B中。將列表B中每一個元素在列表A中的下標記錄到列表C中,列表C即為我們所求。
之後仿照正向傳播,進行反向傳播即可。
說一下代碼的使用方法吧,在源碼同一目錄下建立一個名為enigma_code_book.txt文件,用於粗存enigma機型號,三個轉輪和一個反射板的接線方式。
點擊運行代碼,隨便輸入由3組分別3個阿拉伯數字組成的enigma機批次號,如:123-456-789,點回車。此時程序會自動生成該批次號enigma機的接線方法。如果曾經使用過該批次enigma機,則在enigma_code_book中自動找到所需的接線方式。
再輸入初始轉輪位置,要求為三個小寫英文字母,中間由逗號隔開,如:a,b,c。回車,再輸入所需加密的明文內容,回車,即可生成密文。
如果想進行解密,則要求輸入同一批次號,同一初始轉子位置,輸入密文,則可解密出明文。
需要註意的是,這裡仿照歷史中enigma機,隻做瞭26個小寫英文字母的加密,而沒有數字,大寫英文字母以及標點符號等的加密。因為這些隻是在其基礎上根據應用需求不同做的一些添磚加瓦的工作。筆者也同時考慮到,如果想加密漢語,可以首先將enigma機擴充進大寫字母和阿拉伯數字,再結合base64的值即可。
總結
到此這篇關於用Python復現二戰德軍enigma密碼機的文章就介紹到這瞭,更多相關Python enigma密碼機內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!