赞
踩
大数据安全与隐私这门课的lab1,要求如下图:
采用的方案是RSA和AES相结合, 利用RSA来加密传输AES的密钥, 用AES的密钥来加密数据. 如果使用RSA加密数据, 虽然安全性会更高, 但效率低. AES加解密效率高, 但安全性会差一些, 所以采用RSA加密AES的密钥, 然后用AES加密数据, 这样既保证了效率也保证了安全性.
为了保证相同文件每次发送的加密文件不同, 将随机生成的秘钥与当前时间戳结合为随机AES秘钥. 注释写得很详细了, 有些细节的东西我就不解释了.
运行结果如下:
import sys import threading import socket import struct from Crypto.Cipher import AES import rsa import time iv = '1425374853627180' # 初始向量 BUFF = 1024 # 去除末尾填充字符 def unpadding(text): length = len(text) print(text[length - 1]) return text[0:length - text[length - 1]] def socket_service(): try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置socket可以重用已绑定地址 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('localhost', 9001)) # 绑定端口为9001 s.listen(10) # 设置监听数,最多允许10个客户端连接 except socket.error as msg: print(msg) sys.exit(1) print('等待连接...') while 1: # 调用accept阻塞: 等待请求并接受(程序会停留在这一旦收到连接请求即开启接受数据的线程) conn, addr = s.accept() # 接收数据 t = threading.Thread(target=deal_data, args=(conn, addr)) t.start() def deal_data(conn, addr): print('接收到来自 {0}的连接'.format(addr)) # 收到请求后的回复 conn.send('welcome!'.encode('utf-8')) key = "" while 1: if not key: s1_recv_data = conn.recv(BUFF) if s1_recv_data.decode('utf-8') == 'changekey': print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 开始交换秘钥!') # 使用RSA产生一对公钥和私钥 (pubkey, privkey) = rsa.newkeys(512, poolsize=8) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 创建RSA秘钥对!') # 将公钥模数和指数发送给客户端 modulus = pubkey.n exponent = pubkey.e conn.send(str(modulus).encode('utf-8')) conn.send(str(exponent).encode('utf-8')) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 发送RSA公钥') # 服务端收到消息 key = conn.recv(BUFF) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 接收加密后的AES秘钥:' + key.decode('utf8', 'ignore')) # 服务端用私钥进行解密,得到AES密钥 key = rsa.decrypt(key, privkey) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 解密AES秘钥中') key = key.decode() print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' AES秘钥:' + key) # 申请相同大小的空间存放发送过来的文件名与文件大小信息 fileinfo_size = struct.calcsize('128sl') # 接收文件名与文件大小信息 buf = conn.recv(fileinfo_size) # 判断是否接收到文件头信息 if buf: # 获取文件名和文件大小 filename, filesize = struct.unpack('128sl', buf) fn = filename.strip(b'\00') fn = fn.decode() print('文件名是 {0}, 文件大小是 {1}'.format(str(fn), filesize)) recvd_size = 0 # 定义已接收文件的大小 # 存储在该脚本所在目录下面 fp = open('./' + str(fn), 'wb') print('开始接收...') if not filesize % 16 == 0: filesize += 16 - filesize % 16 # 将分批次传输的二进制流依次写入到文件 while not recvd_size == filesize: if filesize - recvd_size > 1024: data = conn.recv(1024) recvd_size += len(data) else: data = conn.recv(filesize - recvd_size) recvd_size = filesize print(len(data)) print(data) # 将加密数据转换位bytes类型数据 cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, iv.encode('utf8')) text_decrypted = cipher.decrypt(data) print(len(text_decrypted)) print(text_decrypted) if len(text_decrypted) < 1024: text_decrypted = unpadding(text_decrypted) print(text_decrypted) fp.write(text_decrypted) fp.close() print('结束接收...') # 传输结束断开连接 conn.close() break if __name__ == "__main__": socket_service()
import socket import os import sys import struct from Crypto.Cipher import AES import time import rsa key0 = os.urandom(16).hex() # 随机生成秘钥,16位字符串 iv = '1425374853627180' # 初始向量 BUFF = 1024 def padding(text): bs = AES.block_size # 16字节 length = len(text) # 获取明文长度,字符 bytes_length = len(bytes(text, encoding='utf-8')) padding = length if (bytes_length == length) else bytes_length padding_size = bs - padding % bs padding_text = chr(padding_size) * padding_size # 按照PKCS7填充方式生成填充文本 return text + padding_text # 函数功能:对明文进行PKCS7填充 # 参数text:需要填充的明文 # 返回值:填充后的明文 def socket_client(): try: # 创建socket,ipv4+流 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', 9001)) except socket.error as msg: print(msg) sys.exit(1) print(s.recv(1024)) # 加上给密钥加上时间戳,保证相同的明文,每次发送的密文不同 t = time.time() t_str = str(int(t)) key = key0[0:8] + t_str[2:10] # 取key0前八位和时间戳中的后八位生成新key print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 开始交换秘钥!') s.send('changekey'.encode('utf-8')) modulus = int(s.recv(BUFF).decode('utf-8')) # 接收公钥模数 exponent = int(s.recv(BUFF).decode('utf-8')) # 接收公钥指数 print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 开始构建RSA公钥') pubkey = rsa.PublicKey(modulus, exponent) # 构建公钥 print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 加密AES秘钥') crypto = rsa.encrypt(key.encode('utf-8'), pubkey) # 用RSA公钥对AES密钥进行加密 print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 发送加密后的AES秘钥:' + crypto.decode( 'utf8', 'ignore')) s.send(crypto) # 发送加密后的AES密钥 # 需要传输的文件路径 filepath = 'C:/XingYan/1.png' # 判断是否为文件 if os.path.isfile(filepath): # 定义定义文件信息。128s表示文件名为128bytes长,l表示一个int或long,在此为文件大小 fileinfo_size = struct.calcsize('128sl') # 打包文件名和大小 filehead = struct.pack('128sl', os.path.basename(filepath).encode('utf-8'), os.stat(filepath).st_size) s.send(filehead) # 将传输文件以二进制的形式分多次上传至服务器 fp = open(filepath, 'rb') while 1: data = fp.read(1024) print(data) if not data: print('{0} 发送结束...'.format(os.path.basename(filepath))) break if len(data) < 1024: newdata = data.decode('utf8', 'ignore') print(len(newdata)) newdata = padding(newdata) print(len(newdata)) data = newdata.encode('utf8') cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, iv.encode('utf8')) # AES加密对象 encryptedbytes = cipher.encrypt(data) s.send(encryptedbytes) print(encryptedbytes) print(len(encryptedbytes)) s.close() if __name__ == '__main__': socket_client()
欢迎访问我的个人博客www.levitategu.cn
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。