最近在备考软考信息安全工程师,学习到密码学部分,为了记忆更加深刻,将已经掌握并且觉得比较有趣的密码算法用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互质,否则不能正确求解,代码整体结构跟加法密码相同,区别在于核心算法更加复杂。
仿射密码用到多个密文字母表,也成为多表代替密码。
最著名的多表代替密码要算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密码可谓是截至目前我觉得最有意思的密码了,它通过对二进制序列的异或运算来实现加解密,真是太神奇了,花时间用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: [email protected]
原文地址:https://tacgib.club/archives/276
不足之处望多多不吝赐教,转载请注明出处并告知作者,谢谢!