# 从文件中读取明文
# 对明文进行字符转换成比特流 每64位分一组 最后不足的用0补足
# 对每组的64位比特进行IP置换 分 L,R俩组
# 对L,R进行16轮的Feistel变换
# 使用IP-1(IP逆置换)函数将L,R合并为密文比特流
# 最后将密文比特流转换成密文字符保存
import re
import libnum
import os
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]
IP_re_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]
E = [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]
P = [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]
S = [
[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 ],
[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],
[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 ],
[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],
[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],
[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],
[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],
[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],
]
#子秘钥生成 置换选择PC_1盒和PC_2盒
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]
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]
#秘钥左移的位数
SHIFT = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]
def read_file():
try:
f = open(r"des.txt",'r',encoding = 'utf-8')
mess = f.read()
f.close()
print("文件读取成功")
return mess
except IOError:
print("文件读取失败")
def write_file(message):
try:
os.remove(r"des.txt")
f = open(r"des.txt",'w',encoding = 'utf-8')
f.write(message)
f.close()
print("文件写入成功")
except IOError:
print("文件写入失败")
#在分组加解密的时候 我们再bit级上进行操作 ,这里将字符ascii转bit流
def str2bin(message):
# 字符串转2进制(bit流) 每个字符8个bit 不够补0
res = ""
for i in message:
tmp = bin(ord(i))[2:]
for j in range(0,8-len(tmp)):
tmp = '0' + tmp
res += tmp
return res
#初始置换IP
def ip_change(bin_str):
#输入为64位明文消息 输出为经过初始置换IP的64位消息
res = ""
for i in IP_table:
res += bin_str[i-1]
return res
#逆初始置换Ip
def ip_re_change(bin_str):
#输入为经过合并的64位分组消息,输出为64位密文
res = ""
for i in IP_re_table:
res += bin_str[i-1]
return res
#循环左移操作
def left_turn(my_str,num):
# 左移 列表拼接
left_res = my_str[num:len(my_str)]
left_res = left_res + my_str[0:num]
return left_res
#密钥的PC-1置换
def change_key1(my_key):
res = ""
for i in PC_1:
res += my_key[i-1]
return res
#密钥的PC-2置换
def change_key2(my_key):
res = ""
for i in PC_2:
res += my_key[i-1]
return res
#E盒扩展置换 明文拓展
def e_str(bin_str):
#输入为32位的右分组消息,输出为48位的经过扩展置换的消息
res = ""
for i in E:
res += bin_str[i-1]
return res
#异或
def str_xor(str1,str2):
res = ""
for i in range(0,len(str1)):
xor_res = int(str1[i]) ^ int(str2[i]) #转int类型再异或
if xor_res == 1:
res += '1'
if xor_res == 0:
res += '0'
return res
#S盒非线性代换
def s_box(my_str):
# 异或运算结束后,我们需要将48bit缩减位32bit,分组使用S盒置换
res = ""
c = 0 # 第几个S盒 (S0-S7)
for i in range(0,len(my_str),6): # 6 * 8 6位一组,循环8次
now_str = my_str[i:i+6] # 第i个分组,切片
row = int(now_str[0]+now_str[5],2) #第一位和第六位行号
col = int(now_str[1:5],2) #第二为到第五位列号
num = bin(S[c][row * 16 + col])[2:] #一行16个元素 第 row * 16 +col个元素
for i in range(0,4-len(num)): #补全4位输出
num = '0' + num
res += num
c += 1
return res
# P盒线性置换
# P盒将32位输入经过P盒置换后再与最初的L分组进行异或,然后左右换位进行下一轮f
def p_box(bin_str):
res = ""
for i in P:
res += bin_str[i-1]
return res
#16轮变换后,最后一轮不交换左右分组,直接合并比特流,得到加密后的56位比特
#将密文bit流转为密文字符
def bin2str(message):
res = ""
tmp = re.findall(r'.{8}',message) #八位一字符
for i in tmp:
res += chr(int(i,2)) #二进制字符串转十进制ascii 再转字符
return res
#F轮函数实现 16轮 先将明文32bit拓展为48bit,然后与子密钥Ki进行按位模加运算(即异或),得到的结果按每组6位分为8组,再经过S盒,从每6位中选择出4位,得到32比特,经过P盒置换后,得到最终的32位结果
'''
1、扩展置换
2、与轮密钥按位异或
2、经过S盒将每组从48bit缩短到32bit
3、经过P盒置换得到32bit
'''
def fun_f(bin_str,key): #32位R分组 和 轮密钥
first_output = e_str(bin_str) #扩展置换
second_output = str_xor(first_output,key) #和轮密钥按位异或
third_output = s_box(second_output) #经过S盒 每组6位缩减到4位(48bit缩减位32bit)
last_output = p_box(third_output) #经过p盒线性置换(换位)
return last_output
# 轮密钥生成 16轮
'''
1、初始置换选择PC-1
2、循环移位(左移)运算 移位次序表中第LS1,LS2,LS9,LS16次是循环左移1位变换,其他为循环左移2为变换
3、置换选择PC-2 最终选择出48bit子密钥
'''
def gen_key(key):
key_list = []
divide_output = change_key1(key)
key_C0 = divide_output[0:28] # 分为左右俩部分 每部分占28bit
key_D0 = divide_output[28:]
# 经过循环左移 i是左移位数
for i in SHIFT:
key_C = left_turn(key_C0,i) # 左半部分循环左移
key_D = left_turn(key_D0,i) # 右半部分左移
key_output = change_key2(key_C + key_D) # 经过PC-2盒置换选择出48位子秘钥
key_list.append(key_output)
return key_list
# des加密
'''
1、初始置换
2、明文分L、R
3、轮函数加密 16轮 注意最后一次不用换位
4、左右部分合并
5、逆初始置换
6、返回并将密文写入文件
'''
def des_encrypto(bin_message,bin_key):
mes_ip_bin = ip_change(bin_message) # ip置换
key_lst = gen_key(bin_key) # 子秘钥生成
mes_left = mes_ip_bin[0:32] # 明文分组 L、R
mes_right = mes_ip_bin[32:]
for i in range(0,15): # 注意!!! 第16次不用换位
mes_tmp = mes_right
f_result = fun_f(mes_tmp,key_lst[i]) # R组32位与子密钥经过F函数后
mes_right = str_xor(f_result,mes_left) # F函数后的结果与L组 进行异或 结果赋予R组
mes_left = mes_tmp # 原R组直接赋值给L组
f_result = fun_f(mes_right,key_lst[15]) # 最后一次不用换位
mes_fin_left = str_xor(mes_left,f_result)
mes_fin_right = mes_right
fin_message = ip_re_change(mes_fin_left + mes_fin_right) # 合并后 进行逆IP置换
return fin_message
# 64位二进制解密的测试,注意秘钥反过来了,不要写错了
def des_decrypto(bin_mess,bin_key):
mes_ip_bin = ip_change(bin_mess)
#bin_key = input_key_judge(str2bin(key))
key_lst = gen_key(bin_key)
cipher_left = mes_ip_bin[0:32]
cipher_right = mes_ip_bin[32:]
for i in list(range(1,16))[::-1]: #表示逆转列表调用
mes_tmp = cipher_right
cipher_right = str_xor(cipher_left,fun_f(cipher_right,key_lst[i]))
cipher_left = mes_tmp
fin_left = str_xor(cipher_left,fun_f(cipher_right,key_lst[0]))
fin_right = cipher_right
fin_output = fin_left + fin_right
res = ip_re_change(fin_output)
return res
def deal_mess(bin_mess):
# 判断并补全64位bit流
ans = len(bin_mess)
if ans % 64 != 0:
for i in range(64 - (ans % 64)):
bin_mess += "0"
return bin_mess
def check_key(bin_key):
# 密钥不够64位补0
ans = len(bin_key)
if len(bin_key) < 64:
if ans % 64 != 0:
for i in range(64 - (ans % 64)):
bin_key += '0'
return bin_key
# 规范明文和密钥后完整DES加密
def encrypto(message,key):
bin_mess = deal_mess(str2bin(message)) # 明文的二进制bit流 判断是64的倍数 不够补全
res = ""
bin_key = check_key(str2bin(key)) # 得到密钥的二进制流 也是64的倍数
tmp = re.findall(r'.{64}',bin_mess) # 字符加密 只能64bit一组
for i in tmp:
res += des_encrypto(i,bin_key) # 分组加密后的字符连接
return res
def decrypto(message,key):
bin_mess = deal_mess(str2bin(message))
res = ""
bin_key = check_key(str2bin(key))
tmp = re.findall(r'.{64}',bin_mess)
for i in tmp:
res += des_decrypto(i,bin_key)
res = bin2str(res)
return res
def main():
print("请输入序号,选择对应的功能:")
print("--# 1.使用DES加密")
print("--# 2.使用DES解密")
mode = input()
if mode == '1':
print("--# 请输入信息输入字符串不能为空:")
message = input().replace(' ','')
print("--# 请输入你的秘钥:")
key = input().replace(' ','')
s = encrypto(message,key)
out_mess = bin2str(s)
print("--# 加密过后的内容:"+ out_mess)
write_file(out_mess)
elif mode == '2':
# print("--# 请输入信息输入字符串不能为空:")
# message = input().replace(' ', '')
print("--# 请输入你的秘钥:")
key = input().replace(' ', '')
message = read_file()
s = decrypto(message, key)
#out_mess = bin2str(s)
print("--# 解密后的信息:"+ s)
else:
print("--# 请重新输入!")
if __name__ == '__main__':
while True:
main()
python实现DES算法加解密
最新推荐文章于 2024-04-15 00:53:30 发布