python实现DES,不引入任何库
为了便于理解,每一步都添加了详细的注释。
主算法
if __name__ == '__main__':
Path1 = input('输入 要分析的文件 的完整路径:')
Path2 = input('输入 导出文件 的完整路径:')
key = input('输入密钥key:')
while len(list(bytes(key, encoding="utf-8"))) > 8:
print("密钥长度应该小于8字节!")
key = input("请输入密钥key:")
choose = input('1文件加密 2文件解密 : ')
key = list(bytes(key, encoding="utf-8"))
with open(Path1, 'rb') as fp:
text = list(fp.read())
# 不满64位【8字节】的倍数补0
for i in range((8 - len(text) % 8)if (len(text) % 8!=0) else 0):
text.append(0) # 内容转换为2进制数据,64位的倍数
if len(key)==0:key.append(0)
for i in range((8 - len(key) % 8)if (len(key) % 8!=0) else 0):
key.append(0)
key_bin = bin_byte(key) # 密钥转换为2进制数据,64位
K = create_key(key_bin,choose) # 生成16组子密钥,48位
thetext = ''
for i in range(len(text) // 8): # 所有的字节序列每64位【8字节】加密
text_bin = bin_byte(text[i * 8:(i + 1) * 8]) # 转换为二进制数据,64位
init_data = RE(text_bin, init_table) # 初始置换后的二进制数据,64位
L, R = init_data[:32], init_data[32:] # 初始置换的数据切片为左右两半部分,各32位
for li in range(16): # 16次迭代
N = f(R, K[li]) # f的输出是32位
L, R = R, "".join([str(int(L[i]) ^ int(N[i])) for i in range(32)]) # 与左半部分异或形成新的右半部分, 32位
L,R=R,L # 最后一轮不做交换
thetext += RE(L + R, final_table) # 终止置换后的2进制数据,64位
sequence = byte_bin(thetext) # 将所有的 2进制数据 转换为字节序列
with open(Path2,"wb")as fp:
fp.write(bytes(sequence))
核心F函数,迭代使用
def f(text,key):
text=RE(text, expand_table) # 对数据扩展置换,48位
input = "".join([str(int(text[i]) ^ int(key[i])) for i in range(48)]) # 异或运算的结果作为输入块,48位
output=""
for i in range(8): # 等分8块,6位
data=input[i * 6:(i + 1) * 6]
row=int(data[0]+data[-1],2) # 第一位和最后一位变成行数
col=int(data[1:-1],2) # 中间四位变成列数
output+="{:04b}".format(sbox_table[i][row][col]) # 盒子中取出数变为2进制,4位
return RE(output,pbox_table) # 32位放到P盒置换后得到32位
生成16组子密钥
def create_key(key_bin,choose):
'16 次迭代生成 16组子密钥K'
key = RE(key_bin,key_table) # 对key密钥置换,56位
Lkey,Rkey=key[:28],key[28:] # 密钥置换的数据切片,各28位
K=[]
for index in range(16):
Lkey=left_move(Lkey, round_table[index])
Rkey=left_move(Rkey, round_table[index])
key_bin = Lkey + Rkey # 循环左移,56位
K.append(RE(key_bin, compress_table)) # 对密钥压缩置换,48位
if choose!='1':K.reverse() # 解密过程密钥反转
return K
一句话实现循环左移
def left_move(text,start):
'循环左移'
return text[start:]+text[0:start]
置换算法
def RE(text,theTable):
'置换算法'
str=""
for i in theTable:str+=text[i-1]
return str
二进制字符串转字节序列
def byte_bin(text):
'二进制字符串转字节序列'
return [int(text[i * 8:(i + 1) * 8],2) for i in range(len(text) // 8)]
将字节序列转换为64位二进制字符串
def bin_byte(text):
'将字节序列转换为64位二进制字符串'
binary=""
for i in range(len(text)):
binary+="{:08b}".format(text[i])
return binary
各种表:
# 初始置换表
init_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 ]
# 终止置换表
final_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 ]
# 扩展置换表
expand_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 ]
# 压缩置换表
compress_table=[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 ]
# 密钥置换表
key_table=[ 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 ]
# P盒置换表
pbox_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 ]
# 8个S盒置换表
sbox_table=[
# 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]],
# 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]],
# 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]],
# 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]],
# 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]],
# 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]],
# 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]],
# 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]]
]
# 轮转调度表
round_table=[1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
复制所有的代码,直接运行即可。加密解密的数据会导出到文件里。
存在的问题:
- 1、密钥应该在输入的时候就是64位,其中8位时奇偶校验码,但那是其他人员的工作了。在我处理的时候,不足64位会补0。运行中是没问图的,但不符实际要求。
- 2、主代码的16次迭代最后一次是不进行交换的,直接运算完得到数据即可。但我为了代码的美观简洁,会进行17次交换。这使得代码在运行时效率会降低。而使用对称加密算法就是图加密速度快,所以······
- 3、验收密码学的作业通过啦,C类课还要写这种代码······