幾種古典密碼程式碼實現
最近在備考軟考資訊保安工程師,學習到密碼學部分,為了記憶更加深刻,將已經掌握並且覺得比較有趣的密碼演算法用Python來實現,簡單記錄一下。
古典密碼接觸到置換密碼、代替密碼和代數密碼三種,其中置換密碼相對簡單,靠眼睛就可以完成加解密,所以沒有必要實現了,代替密碼主要有加法密碼、乘法密碼和仿射密碼,仿射密碼研究的是Vigenre密碼,該密碼是16世紀法國密碼學家Vigenre使用過的密碼,代數密碼研究的是Vernam密碼,該密碼是美國電話電報公司的Gillbert Vernam在1917年為電報通訊設計的一種非常方便的密碼(我最喜歡這組密碼)。
加法密碼
# coding:utf-8 # 加法密碼實現 # 當前僅支援大寫字串加解密 # 秋風木葉 2019-3-10 # 字串轉單字元列表,再轉為數字序列便於計算 def stoc(str): ch_list = [] for i in str: ch_list.append(i) return [ord(i)-65 for i in ch_list] # Int to Chr # 將數字序列還原成大寫字母序列 def itoc(list_int): A = [chr(i+65) for i in list_int] ch = "" for i in A: ch += i return ch # 計算密文序列 def Encrypt(Message,k,n): print('>>>使用加法密碼演算法進行加密(k={}, n={})'.format(k,n)) return itoc([i+k%n for i in stoc(Message)]) # 計算明文序列 def Decrypt(Ciphertext,k,n): # 解密方式1:通過構建密碼錶進行查表解密 # 解密方式2:通過加密逆運算計算明文 DecryptionType = 2 if(DecryptionType == 1): print('>>>構建密碼錶:') A = [i for i in range(0,n)] print('>>>明文字母表:{}'.format(itoc(A))) B = Encrypt(itoc(A),k,n) print('>>>密文字母表:{}'.format(B)) CiphertextTables = dict(zip(B,A)) print('>>>構建密碼錶進行查表解密') return itoc([CiphertextTables[i] for i in Ciphertext]) else: print('>>>通過加密逆運算進行解密(k的逆元為:{})'.format(-k)) return itoc([c-k+n %n for c in stoc(Ciphertext)]) if __name__=='__main__': # 當前僅支援大寫字母串 A = ('ABCDEF') print('輸入的明文字串為:{}'.format(A)) B = Encrypt(A,7,26) print('加密後的密文:{}'.format(B)) C = Decrypt(B,7,26) print('解密後的明文:{}'.format(C))
以上程式碼的執行結果:
輸入的明文字串為:ABCDEF >>>使用加法密碼演算法進行加密(k=7, n=26) 加密後的密文:HIJKLM >>>通過加密逆運算進行解密(k的逆元為:-7) 解密後的明文:ABCDEF
加法密碼比較簡單,加解密過程既可以通過公式計算實現,也可以使用查表的方式獲得,程式碼中解密過程就分別使用了加密逆運算和查表兩種思路來實現。
乘法密碼
# coding:utf-8 # 乘法密碼計算實現程式碼 # 當前僅支援大寫字串加解密,引數k和n必須互質整數 # 秋風木葉 2019-3-9 # 字串轉單字元列表,再轉為數字序列便於計算 def stoc(str): ch_list = [] for i in str: ch_list.append(i) return [ord(i)-65 for i in ch_list] # Int to Chr # 將數字序列還原成大寫字母序列 def itoc(list_int): A = [chr(i+65) for i in list_int] ch = "" for i in A: ch += i return ch # 計算密文序列 def Encrypt(Message,k,n): print('>>>使用乘法密碼演算法進行加密(k={}, n={})'.format(k,n)) return itoc([i*k%n for i in stoc(Message)]) # 計算明文序列 def Decrypt(Ciphertext,k,n): # 解密方式1:通過構建密碼錶進行查表解密 # 解密方式2:通過加密逆運算計算明文 DecryptionType = 2 if(DecryptionType == 1): print('>>>構建密碼錶:') A = [i for i in range(0,n)] print('>>>明文字母表:{}'.format(itoc(A))) B = Encrypt(itoc(A),k,n) print('>>>密文字母表:{}'.format(B)) CiphertextTables = dict(zip(B,A)) print('>>>構建密碼錶進行查表解密') return itoc([CiphertextTables[i] for i in Ciphertext]) else: for k1 in range(0, n): if(k1 * k % n == 1): break print('>>>通過加密逆運算進行解密(k的逆元為:{})'.format(k1)) return itoc([c*k1%n for c in stoc(Ciphertext)]) if __name__=='__main__': # 當前僅支援大寫字母串 A = ('ABCDEF') print('輸入的明文字串為:{}'.format(A)) B = Encrypt(A,7,26) print('加密後的密文:{}'.format(B)) C = Decrypt(B,7,26) print('解密後的明文:{}'.format(C))
以上程式碼的執行結果:
輸入的明文字串為:ABCDEF >>>使用乘法密碼演算法進行加密(k=7, n=26) 加密後的密文:AHOVCJ >>>通過加密逆運算進行解密(k的逆元為:15) 解密後的明文:ABCDEF
乘法密碼要求k和n互質,否則不能正確求解,程式碼整體結構跟加法密碼相同,區別在於核心演算法更加複雜。
仿射密碼之Vigenre密碼
仿射密碼用到多個密文字母表,也成為多表代替密碼。
最著名的多表代替密碼要算16世紀法國學者Vigenre使用過的Vigenre密碼,我也正是通過Vigenre密碼來學習仿射密碼的。
# coding:utf-8 # Vigenre密碼實現程式碼 # 當前僅支援大寫字串加解密 # 秋風木葉 2019-3-10 # 字串轉單字元列表 def stoc(str): ch_list = [] for i in str: i = i.strip() if(i != ''): ch_list.append(i) return [i for i in ch_list] # 字元列表轉換為字串 def ctoc(list_ch): ch = "" for i in list_ch: ch += i return ch # 構建密碼字典 def GetM_C(): A = [] B = [] C = [] for i in range(0,26): A.append(chr(i+65)) B.append([chr(i+65)]) for j in range(1,26): B[i].append((chr((i+j)%26+65))) for i in A: C.append(dict(zip(A,B[ord(i)-65]))) return C # 計算密文序列 def Encrypt(Message,K): M_C = GetM_C() C = '' for i,k in zip(stoc(Message),stoc(K)): #print(i,k) C += M_C[ord(i)-65][k] print('>>>使用Vigenre密碼演算法進行加密') return C # 通過查密碼錶計算明文序列 def Decrypt(Ciphertext,K): M_C = GetM_C() M = '' for c,k in zip(stoc(Ciphertext),stoc(K)): M_Dict = M_C[ord(k)-65] #print(M_Dict) for m in M_Dict.keys(): if(M_Dict[m] == c): M += m #print(m) print('>>>使用Vigenre密碼演算法進行解密') return M if __name__=='__main__': # 當前僅支援大寫字母串 M = ('MING CHEN WU DIAN FA DONG FAN GONG') K = ('XING CHUI PING YE KUO YUE YONG DA JIANG LIU') print('輸入的明文字串為:{}'.format(M)) print('輸入的金鑰字串為:{}'.format(K)) C = Encrypt(M, K) print('加密後的密文:{}'.format(C)) M1 = Decrypt(C, K) print('解密後的明文:{}'.format(M1))
以上程式碼的執行效果:
輸入的明文字串為:MING CHEN WU DIAN FA DONG FAN GONG 輸入的金鑰字串為:XING CHUI PING YE KUO YUE YONG DA JIANG LIU >>>使用Vigenre密碼演算法進行加密 加密後的密文:JQAMEOYVLCQOYRPURMHKDOAMRNP >>>使用Vigenre密碼演算法進行解密 解密後的明文:MINGCHENWUDIANFADONGFANGONG
暫時僅通過構建密碼錶的方式來實現,加解密都通過查表來進行,密文和明文長度相等,金鑰尤為關鍵,金鑰長度必須大於明文,否則多出來的明文無法加密,同樣如果金鑰長度小於密文長度部分密文也無法解密。
代數密碼之Vernam密碼
Vernam密碼可謂是截至目前我覺得最有意思的密碼了,它通過對二進位制序列的異或運算來實現加解密,真是太神奇了,花時間用python對它進行了實現,雖然這組密碼的程式碼實現和前幾組一樣都是我自己花時間敲出來的,但是跟上面三種密碼的實現相比,我覺得這組密碼要更加高明一些。
# coding:utf-8 # 代數密碼(Vernam)實現程式碼 # 當前僅支援大寫字串加解密 # 秋風木葉 2019-3-11 # 字元轉二進位制 def CtoB(ch): OrdCh = ord(ch) BinarySequence = '' while(True): if(OrdCh % 2 == 0): BinarySequence += '0' else: BinarySequence += '1' OrdCh = OrdCh // 2 if(OrdCh == 1): break #print(OrdCh,BinarySequence) BinarySequence += '1' # 補齊8位 length = 8 - len(BinarySequence) while(length): BinarySequence += '0' length -= 1 #print('BinarySequence:{}'.format(BinarySequence)) return BinarySequence[::-1] # 二進位制轉字元 def BtoC(Bin): St = '' OrdCh = 0 length = 8 for i in Bin: length -= 1 OrdCh += (ord(i)-ord('0'))*(2**length) #print(length,i,OrdCh) if(length == 0): St += chr(OrdCh) length = 8 OrdCh = 0 return St # 核心演算法:二進位制異或運算(加解密通用) def Execute_Unit(m_c, k): result_unit = '' for i,j in zip(m_c, k): #print(i,j) if(i == j): result_unit += '0' else: result_unit += '1' #print('result_unit:{}'.format(result_unit)) return result_unit # 呼叫Vernam演算法進行加密 def Encrypt(Message,K): print('>>>呼叫Vernam演算法進行加密') result = '' for m,k in zip(Message, K): result += Execute_Unit(CtoB(m),CtoB(k)) return result # 呼叫Vernam演算法進行解密 def Decrypt(Ciphertext,K): print('>>>呼叫Vernam演算法進行解密') # Bk存放二進位制K值序列 BK = '' for k in K: BK += CtoB(k) # BM存放二進位制明文序列 BM = Execute_Unit(Ciphertext, BK[:len(Ciphertext)]) print('>>>二進位制金鑰序列:{}'.format(BK)) print('>>>二進位制明文序列:{}'.format(BM)) return BtoC(BM) if __name__=='__main__': # 當前僅支援大寫字母串 M = ('MING CHEN WU DIAN FA DONG FAN GONG') K = ('XING CHUI PING YE KUO YUE YONG DA JIANG LIU') print('輸入的明文字串為:{}'.format(M)) print('輸入的金鑰字串為:{}'.format(K)) C = Encrypt(M, K) print('加密後的密文:{}'.format(C)) M1 = Decrypt(C, K) print('解密後的明文:{}'.format(M1))
程式碼的執行效果如下:
輸入的明文字串為:MING CHEN WU DIAN FA DONG FAN GONG 輸入的金鑰字串為:XING CHUI PING YE KUO YUE YONG DA JIANG LIU >>>呼叫Vernam演算法進行加密 加密後的密文:00010101000000000000000000000000000000000000000000000000000100000000011100000000000001110001110001101110000000110110100100011000000010110000000000001101000101000110111101100100000101100001101100000010000000000001111100001110000000000110011101100111000010110000111101100111 >>>呼叫Vernam演算法進行解密 >>>二進位制金鑰序列: 01011000010010010100111001000111001000000100001101001000010101010100100100100000010100000100100101001110010001110010000001011001010001010010000001001011010101010100111100100000010110010101010101000101001000000101100101001111010011100100011100100000010001000100000100100000010010100100100101000001010011100100011100100000010011000100100101010101 >>>二進位制明文序列: 01001101010010010100111001000111001000000100001101001000010001010100111000100000010101110101010100100000010001000100100101000001010011100010000001000110010000010010000001000100010011110100111001000111001000000100011001000001010011100010000001000111010011110100111001000111 解密後的明文:MING CHEN WU DIAN FA DONG FAN GONG
作者:秋風木葉(frank1901s)
email:f@tacgib.club
原文地址 :https://tacgib.club/archives/276
不足之處望多多不吝賜教,轉載請註明出處並告知作者 ,謝謝!