当前位置:   article > 正文

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

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

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

大数据安全与隐私这门课的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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
客户端代码
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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

欢迎访问我的个人博客www.levitategu.cn

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/531750
推荐阅读
相关标签
  

闽ICP备14008679号