一、框架
实现文件安全传输的原型如下图所示,消息的哈希值用公钥加密算法和发送方的秘密钥签名后与消息链接,再对链接后的结果用单钥加密算法加密。
各模块使用的算法:
哈希算法使用MD5。
非对称密码算法使用RSA。
对称加密算法使用DES。
语言:
Python 3.7
二、MD5哈希算法
my_md5.py:
#-*-coding:UTF-8 -*-
from math import floor,sin
from bitarray import bitarray
from enum import Enum
import struct
#初始化MD5缓冲区
class Buffer(Enum):
A = 0x67452301
B = 0xEFCDAB89
C = 0x98BADCFE
D = 0x10325476
class MyMd5(object):
buffers = {Buffer.A: None,Buffer.B: None,
Buffer.C: None,Buffer.D: None,
}
@classmethod
#消息填充
def message_fill(cls):
bit = bitarray(endian="big")
bit.frombytes(cls.string_M.encode("utf-8"))
bit.append(1)
while bit.length() % 512 != 448: #如果mod512不等于448,填充0
bit.append(0)
return bitarray(bit, endian="little")#小端
@classmethod
#附加消息的长度
def additional_message_length(cls, message_fill_result):
length = (len(cls.string_M) * 8) % pow(2, 64)
#将length转成64bit的小端形式
message_length = bitarray(endian="little")
message_length.frombytes(struct.pack("<Q", length))
result = message_fill_result.copy()
result.extend(message_length)
return result
@classmethod
#对MD5缓冲区初始化
def buffer_initialize(cls):
for buffer_type in cls.buffers.keys():
cls.buffers[buffer_type] = buffer_type.value
A = cls.buffers[Buffer.A]
B = cls.buffers[Buffer.B]
C = cls.buffers[Buffer.C]
D = cls.buffers[Buffer.D]
@classmethod
#以分组为单位对消息进行处理
def message_handing(cls, additional_message_length_result):
#定义循环左移函数
ROL = lambda x, n: (x << n) | (x >> (32 - n))
#定义模加函数
mod_add = lambda a, b: (a + b) % pow(2, 32)
#定义逻辑函数
F = lambda x, y, z: (x & y) | (~x & z)
G = lambda x, y, z: (x & z) | (y & ~z)
H = lambda x, y, z: x ^ y ^ z
I = lambda x, y, z: y ^ (x | ~z)
#计算常数表T
T = [floor(pow(2, 32) * abs(sin(i + 1))) for i in range(64)]
#将附加后的明文长度分成32位的块
N = len(additional_message_length_result) // 32
for block in range(N // 16):
#在列表blocks中将明文分成16个32位的块
start = block * 512
blocks = [additional_message_length_result[start + (x * 32) :
start + (x * 32) + 32] for x in range(16)]
blocks = [int.from_bytes(word.tobytes(), byteorder="little") for word in blocks]
#定义缓冲区
A = cls.buffers[Buffer.A]
B = cls.buffers[Buffer.B]
C = cls.buffers[Buffer.C]
D = cls.buffers[Buffer.D]
#4轮处理
for i in range(4 * 16):
#1
if 0 <= i <= 15:
k = i
s = [7, 12, 17, 22]
temp = F(B, C, D)
#2
elif 16 <= i <= 31:
k = ((5 * i) + 1) % 16
s = [5, 9, 14, 20]
temp = G(B, C, D)
#3
elif 32 <= i <= 47:
k = ((3 * i) + 5) % 16
s = [4, 11, 16, 23]
temp = H(B, C, D)
#4
elif 48 <= i <= 63:
k = (7 * i) % 16
s = [6, 10, 15, 21]
temp = I(B, C, D)
#执行循环左移与模加
temp = mod_add(temp, blocks[k])
temp = mod_add(temp, T[i])
temp = mod_add(temp, A)
temp = ROL(temp, s[i % 4])
temp = mod_add(temp, B)
#下一轮操作
A = D
D = C
C = B
B = temp
#更新缓冲区
cls.buffers[Buffer.A] = mod_add(cls.buffers[Buffer.A], A)
cls.buffers[Buffer.B] = mod_add(cls.buffers[Buffer.B], B)
cls.buffers[Buffer.C] = mod_add(cls.buffers[Buffer.C], C)
cls.buffers[Buffer.D] = mod_add(cls.buffers[Buffer.D], D)
@classmethod
#输出
def Output(cls):
A = struct.unpack("<I", struct.pack(">I", cls.buffers[Buffer.A]))[0]
B = struct.unpack("<I", struct.pack(">I", cls.buffers[Buffer.B]))[0]
C = struct.unpack("<I", struct.pack(">I", cls.buffers[Buffer.C]))[0]
D = struct.unpack("<I", struct.pack(">I", cls.buffers[Buffer.D]))[0]
#输出缓冲区
return f"{format(A, '08x')}{format(B, '08x')}{format(C, '08x')}{format(D, '08x')}"
@classmethod
#压缩函数
def MyHash(cls, string_M):
cls.string_M = string_M
preprocessed_bit_array = cls.additional_message_length(cls.message_fill())
cls.buffer_initialize()
cls.message_handing(preprocessed_bit_array)
return cls.Output()
三、RSA签名
my_RSA.py:
# -- coding: gb2312 --
p = 106697219132480173106064317148705638676529121742557567770857687729397446898790451577487723991083173010242416863238099716044775658681981821407922722052778958942891831033512463262741053961681512908218003840408526915629689432111480588966800949428079015682624591636010678691927285321708935076221951173426894836169
q = 144819424465842307806353672547344125290716753535239658417883828941232509622838692761917211806963011168822281666033695157426515864265527046213326145174398018859056439431422867957079149967592078894410082695714160599647180947207504108618794637872261572262805565517756922288320779308895819726074229154002310375209
#扩展欧几里得算法
def extend_gcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, r = extend_gcd(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, r
#公钥
def generate_publickey():
n=p*q
e=65537 #e取固定值
return e,n
#私钥
def generate_privatekey():
ph_n=(p-1)*(q-1)
e=65537
(x, y, r) = extend_gcd(ph_n, e)
if y<0:
d = y + ph_n #直接用加法比%效率要高
else:
d = y
n=p*q
return d,n
#私钥签名
def signature(HM):
HM=int(HM,16)
d,n=generate_privatekey()
print('RSA私钥(d,n):\n'+str(d)+' , '+str(n)+'\n')
signature_HM=pow(HM,d,n)
signature_HM=hex(signature_HM)[2:]
return signature_HM
#公钥验证
def verify(signature_HM):
signature_HM=int(signature_HM,16)
e,n=generate_publickey()
print('RSA公钥(e,n):\n'+str(e)+' , '+str(n)+'\n')
HM=pow(signature_HM,e,n)
HM=hex(HM)[2:]
return HM
四、DES算法
my_DES.py:
# -- coding: gb2312 --
import re
#初始置换IP
IP = [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_reverse = [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
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
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盒
S =[
#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],
]
#置换选择1
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
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 str2bin(message):
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
#二进制转化为字符串
def bin2str(bin_str):
res = ""
tmp = re.findall(r'.{8}',bin_str)
for i in tmp:
res += chr(int(i,2))
return res
#IP盒处理
def ip_change(bin_str):
res = ""
for i in IP:
res += bin_str[i-1] #数组下标i-1
return res
#IP逆盒处理
def ip_re_change(bin_str):
res = ""
for i in IP_reverse:
res += bin_str[i-1]
return res
#E盒处理
def e_key(bin_str):
res = ""
for i in E:
res += bin_str[i-1]
return res
#字符串异或操作
def str_xor(my_str1,my_str2):
res = ""
for i in range(0,len(my_str1)):
#变成10进制是转化成字符串 2进制与10进制异或结果一样,都是1,0
xor_res = int(my_str1[i],10)^int(my_str2[i],10)
if xor_res == 1:
res += '1'
if xor_res == 0:
res += '0'
return res
#循环左移操作
def ROL(my_str,num):
left_res = my_str[num:len(my_str)]
left_res = my_str[0:num]+left_res
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
# S盒代换
def s_box(my_str):
res = ""
c = 0
for i in range(0,len(my_str),6):
now_str = my_str[i:i+6]
row = int(now_str[0]+now_str[5],2)
col = int(now_str[1:5],2)
#利用了bin输出有可能不是4位str类型的值,所以才有下面的循环并且加上字符0
num = bin(S[c][row*16 + col])[2:]
for gz in range(0,4-len(num)):
num = '0'+ num
res += num
c += 1
return res
#P盒置换
def p_box(bin_str):
res = ""
for i in P:
res += bin_str[i-1]
return res
#F函数
def fun_F(bin_str,key):
first_output = e_key(bin_str)
second_output = str_xor(first_output,key)
third_output = s_box(second_output)
last_output = p_box(third_output)
return last_output
#密钥产生
def generate_key(key):
key_list = []
divide_output = change_key1(key)
key_C0 = divide_output[0:28]
key_D0 = divide_output[28:]
for i in SHIFT:
key_c = ROL(key_C0,i)
key_d = ROL(key_D0,i)
key_output = change_key2(key_c + key_d)
key_list.append(key_output)
return key_list
#64位二进制加密
def des_encrypt_one(bin_message,bin_key):
mes_ip_bin = ip_change(bin_message)
key_lst = generate_key(bin_key)
mes_left = mes_ip_bin[0:32]
mes_right = mes_ip_bin[32:]
for i in range(0,15):
mes_tmp = mes_right
f_result = fun_F(mes_tmp,key_lst[i])
mes_right = str_xor(f_result,mes_left)
mes_left = mes_tmp
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)
return fin_message
#64位二进制解密
def des_decrypt_one(bin_mess,bin_key):
mes_ip_bin = ip_change(bin_mess)
key_lst = generate_key(bin_key)
lst = range(1,16)
cipher_left = mes_ip_bin[0:32]
cipher_right = mes_ip_bin[32:]
for i in lst[::-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
bin_plain = ip_re_change(fin_output)
res = bin2str(bin_plain)
return res
#简单判断以及处理信息分组
def deal_mess(bin_mess):
#param bin_mess: 二进制的信息流
ans = len(bin_mess)
if ans % 64 != 0:
for i in range( 64 - (ans%64)): #不够64位补充0
bin_mess += '0'
return bin_mess
#查看秘钥是否为64位
def input_key_judge(bin_key):
ans = len(bin_key)
if len(bin_key) < 64:
if ans % 64 != 0:
for i in range(64 - (ans % 64)): #不够64位补充0
bin_key += '0'
return bin_key
#加密
def DES_encrypt(message,key):
bin_mess = deal_mess(str2bin(message))
res = ""
bin_key = input_key_judge(str2bin(key))
tmp = re.findall(r'.{64}',bin_mess)
for i in tmp:
res += des_encrypt_one(i,bin_key)
return res
#解密
def DES_decrypt(message,key):
#bin_mess = deal_mess(str2bin(message))
bin_mess=message
res = ""
bin_key = input_key_judge(str2bin(key))
tmp = re.findall(r'.{64}',bin_mess)
for i in tmp:
res += des_decrypt_one(i,bin_key)
return res
五、文件安全传输实现
secure_file_transfer.py:
# -- coding: gb2312 --
from my_md5 import MyMd5
from my_RSA import *
from my_DES import *
M="zrx1102"
print("M: "+M+'\n')
len_M=len(M)
#对消息哈希
HM=MyMd5.MyHash(M)
print("Hash(M): "+HM+'\n')
#RSA私钥签名
signature_HM=signature(HM)
print('signature[H(M)]:\n'+signature_HM+'\n')
#消息与签名后的结果链接
link_message=M+'@'+signature_HM
print('M||signature[H(M)]:\n'+link_message+'\n')
#DES加密
key='12345678'
print('DES key: '+key+'\n')
s=DES_encrypt(link_message,key)
print('DES对M||signature[H(M)]加密后的16进制结果:\n'+hex(int(s,2))+'\n')
#DES解密
link_message=DES_decrypt(s,key)
print('DES解密得到M||signature[H(M)]:\n'+link_message+'\n')
#消息拆分
M=link_message[:len_M]
signature_HM=link_message[len_M+1:]
print("拆分后得到的消息M为: ",M,'\n')
print("拆分后得到的signature[H(M)]:\n",signature_HM,'\n')
#RSA公钥验证
HM=verify(signature_HM)
print("对拆分后的数字签名进行RSA公钥验证: "+HM+'\n')
#对拆分后的消息哈希
HM1=MyMd5.MyHash(M)
print("对拆分后的消息M哈希: "+HM1+'\n')
if(HM==HM1):
print("哈希值相同,文件安全传输成功!")
else:
print("文件安全传输失败!")