最近在备考软考信息安全工程师, 学习到密码学部分, 为了记忆更加深刻, 将已经掌握并且觉得比较有趣的密码算法用 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: mailto:f@tacgib.club
来源: http://www.jianshu.com/p/4f5ef21f3673