西电大数据安全与隐私(现代密码学基础技能)

西电大数据安全与隐私(现代密码学基础技能)

大数据安全与隐私这门课的lab1,要求如下图:

采用的方案是RSA和AES相结合, 利用RSA来加密传输AES的密钥, 用AES的密钥来加密数据. 如果使用RSA加密数据, 虽然安全性会更高, 但效率低. AES加解密效率高, 但安全性会差一些, 所以采用RSA加密AES的密钥, 然后用AES加密数据, 这样既保证了效率也保证了安全性.

为了保证相同文件每次发送的加密文件不同, 将随机生成的秘钥与当前时间戳结合为随机AES秘钥. 注释写得很详细了, 有些细节的东西我就不解释了.

运行结果如下:

服务端代码
python 复制代码
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()
客户端代码
python 复制代码
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

相关推荐
用户962377954485 小时前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机9 小时前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机9 小时前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户9623779544810 小时前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star10 小时前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
字节跳动数据平台12 小时前
代码量减少 70%、GPU 利用率达 95%:火山引擎多模态数据湖如何释放模思智能的算法生产力
大数据
得物技术13 小时前
深入剖析Spark UI界面:参数与界面详解|得物技术
大数据·后端·spark
用户9623779544814 小时前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
武子康15 小时前
大数据-238 离线数仓 - 广告业务 Hive分析实战:ADS 点击率、购买率与 Top100 排名避坑
大数据·后端·apache hive
武子康2 天前
大数据-237 离线数仓 - Hive 广告业务实战:ODS→DWD 事件解析、广告明细与转化分析落地
大数据·后端·apache hive