python实现DES加密解密
使用python,从DES的各个函数开始实现DES加密解密。采用ECB方式加密,填充方式采用zeropadding
·
具体详细说明可以先参看参考资料,后面再补充详细的说明。
代码实现:
# 采用ECB方式加密,填充方式采用zeropadding
# 明文输入需要是ASCII在 0-255之间的字符,中文输入暂时不支持
# 密钥需要是8字节字符串
# IP置换表
IP_table=[58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7
]
# 扩展置换表
extend_table=[32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32,1
]
# S盒中的S1盒
S1 = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
[0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
[4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
[15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]
]
# S盒中的S2盒
S2 = [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],
[3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],
[0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],
[13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]
]
# S盒中的S3盒
S3 = [[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],
[13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],
[13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],
[1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]
]
# S盒中的S4盒
S4 = [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],
[13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],
[10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],
[3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]
]
# S盒中的S5盒
S5 = [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],
[14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],
[4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],
[11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]
]
# S盒中的S6盒
S6 = [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],
[10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],
[9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],
[4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]
]
# S盒中的S7盒
S7 = [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],
[13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],
[1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],
[6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]
]
# S盒中的S8盒
S8 = [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],
[1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],
[7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],
[2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]
]
S = [S1, S2, S3, S4, S5, S6, S7, S8]
# P盒
P_table = [16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25
]
# 压缩置换表1,不考虑每字节的第8位,将64位密钥减至56位。然后进行一次密钥置换。
PC_1=[ 57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4
]
# 压缩置换表2,用于将循环左移和右移后的56bit密钥压缩为48bit。
PC_2=[14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32
]
# 逆置换IP表
_IP_table=[40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25
]
# 循环移位位数表
moveNum=[1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]
# IP置换函数
def IP(message):
result = ''
# 用IP表进行置换即可
for i in IP_table:
result += message[i-1]
return result
# 扩展置换函数
def extend(R0):
result=''
# 用扩展置换表进行置换即可
for i in extend_table:
result += R0[i-1]
return result
# S盒子压缩函数
def sbox(afterRoundKey):
result = ''
for m in range(0,48,6):
# 通过第1位和第6位算出列号
i = int(afterRoundKey[m])*2+int(afterRoundKey[m+5])
# 通过第2、3、4、5位算出行号
j = int(afterRoundKey[m+1])*8+int(afterRoundKey[m+2])*4+int(afterRoundKey[m+3])*2+int(afterRoundKey[m+4])
result += str('{:04b}'.format(S[m//6][i][j]))
return result
# 轮密钥加函数
def addRoundKey(afterExtend,roundKey):
result = ''
for i in range(48):
# 进行按位异或运算
result += str(int(afterExtend[i])^int(roundKey[i]))
return result
# 线性置换P盒
def pbox(afterSbox):
result = ''
# 用P盒表进行置换即可
for i in range(32):
result += str(afterSbox[P_table[i]-1])
return result
# F函数
def F(R0,key):
# 扩展将32位扩展为48位
R0 = extend(R0)
# 与轮密钥进行按位异或
afterRoundKey = addRoundKey(R0,key)
# 放入S盒压缩
afterSbox = sbox(afterRoundKey)
# 放入P盒进行线性替换
result = pbox(afterSbox)
return result
#轮密钥生成
def generateKey(key):
result = ''
roundKey=[]
# 进行第一次压缩置换,将64位密钥减至56位,即去除8个校验位
for i in PC_1:
result += key[i-1]
# 分位左右两部分,每部分28位
C0=result[:28]
D0=result[28:]
for i in range(16):
# 按循环移位位数表进行移位操作
C0=C0[moveNum[i]:]+C0[:moveNum[i]]
D0=D0[moveNum[i]:]+D0[:moveNum[i]]
tmp=C0+D0
ret = ''
# 进行第二次压缩将56位压缩减至48位
for i in PC_2:
ret+=tmp[i-1]
# 生成轮密钥存储到列表中
roundKey.append(ret)
return roundKey
# IP逆置换
def inverseIP(afterF):
ciphertext=''
# 用逆IP表进行置换即可
for i in _IP_table:
ciphertext+=afterF[i-1]
return ciphertext
# 加密函数
def encrypt(plaintext,roundKey):
# 进行IP置换
result = IP(plaintext)
# 分左右32bit
L0=result[:32]
R0=result[32:]
# 进行16轮加密
for i in range(16):
tmp=R0
results = F(R0, roundKey[i])
# print(results)
# print(roundKey[0])
R0=''
for j in range(32):
R0+=str(int(L0[j])^int(results[j]))
L0=tmp
# print(R0)
# 最后一轮结束后结果要左右交换
afterF = R0+L0
# 进行逆IP置换得到密钥
ciphertext=inverseIP(afterF)
return ciphertext
# 解密函数
def decrypt(ciphertext, roundKey):
result = IP(ciphertext)
Li = result[:32]
Ri = result[32:]
# 解密函数对轮密钥使用要倒序使用
for i in range(15,-1,-1):
tmp=Ri
results = F(Ri,roundKey[i])
Ri = ''
for j in range(32):
Ri += str(int(Li[j])^int(results[j]))
Li = tmp
afterF = Ri+Li
plaintext = inverseIP(afterF)
return plaintext
# 0填充函数
def zeroPadding(message):
# UTF-8解码
message = list(bytes(message,'utf8'))
# 先填充一个0,这使得如果明文本来就是64位仍然要填充64个0到末尾
message.append(0)
# 填充0到8字节的整数倍
while len(message)%8!=0:
message.append(0)
ret = []
strs=''
# 分组,化为二进制串,然后没8字节分组放入ret列表中
for i in range(len(message)):
strs+=str('{:08b}'.format(message[i]))
if (i+1)%8==0:
ret.append(strs)
strs=''
return ret
# 处理密文函数
def progress(cipher):
lens=len(cipher)
# 因为密文输入是16进制,所以直接按没16个字符分一组即可,最后会被解释成16*4=64bit
m=lens//16
ret=[]
for i in range(m):
ret.append(cipher[i*16:(i+1)*16])
return ret
# 将16进制位串变为字符
def to_chr(text):
lens = len(text)
# 每两个个16进制数被解释成一个ASCII码字符,2**8=256
m = lens // 2
lists = []
for i in range(m):
lists.append(text[i * 2:(i + 1) * 2])
strs = ''
for s in lists:
tmp=int(s, 16)
# 因为ascii码0不会被输入,因此认为是补位值,当存在补位值,后继必为补位值,直接舍弃即可
# 对中文进行加解密时这里需要优化
if tmp==0:
break
strs += chr(tmp)
return strs
if __name__ == "__main__":
print("请选择1、加密,2、解密:")
choose = input()
if choose == '1':
message = input("请输入要加密的文本:")
key = input("请输入密钥:")
keylist = list(bytes(key, 'utf8')) # 将密钥变为ascii码
if len(keylist)!=8:# 密钥应该为8字节的整数倍
print("错误!请输入8字节密钥!")
else:
key=''
for i in keylist:
key += str('{:08b}'.format(i)) # 将密钥的ascii码转为2进制
roundKey = generateKey(key)# 生成轮密钥,用列表存储
lists=zeroPadding(message) # 进行明文0填充,并分组,每64位一组
cipher=''
for p in lists:
cipher+=encrypt(p, roundKey) # 每组分别加密,因为采用ECB方式,直接将各段加密结果链接即可
cipher=str(hex(int(cipher,2)))[2:] # 将结果2进制串转化为16进制串输出
print(cipher)
elif choose == '2':
text = input("请输入密文文本:")
key = input("请输入密钥:")
keylist = list(bytes(key, 'utf8'))
if len(keylist)!=8:
print("错误!请输入8字节密钥!")
else:
key = ''
for i in keylist:
key += str('{:08b}'.format(i))
roundKey = generateKey(key)
cipherlist=progress(text)
plaintext=''
for c in cipherlist:
message = str('{:064b}'.format(int(c, 16)))
tmp=decrypt(message, roundKey)
if c==cipherlist[-1] and int(tmp,2)==0: # 如果当前段位最后一段且当前段值为0,认为是补位段,直接舍弃
break
plaintext+=tmp
plaintext=str(hex(int(plaintext,2)))[2:]
plaintext = to_chr(plaintext) # 将解密结果化为字符输出
print(plaintext)
else:
print("错误输入!")
加解密结果经过在线加密验证正确:
加密:
验证结果:
解密:
更多推荐
已为社区贡献1条内容
所有评论(0)