现代密码学基础技能
大数据安全与隐私这门课的lab1,要求如下图:

实现思路:
•	通过Socket实现文件传输,使用TCP协议确保数据传输的可靠性。
•	代码通过读取文件的二进制数据进行传输,支持任意类型的文件。
•	通过AES加密算法进行文件数据的加密和解密。
•	使用RSA加密算法对AES密钥进行加密,确保密钥的安全传输。
•	通过在AES密钥中加入时间戳的方式,确保每次生成不同的密钥,从而保证相同文件每次发送的加密结果不同。
具体实现:
客户端 (client.py)
- 连接服务器
o	创建Socket并连接到服务器的指定端口。 
- AES密钥生成与加密
o	生成16字节的随机AES密钥。
o	加入时间戳生成唯一的AES密钥。
o	使用RSA公钥加密AES密钥并发送给服务器。 
- 文件传输
o	读取文件信息(文件名和大小),发送给服务器。
o	分块读取文件数据,使用AES进行加密,发送加密数据到服务器。
服务端 (server.py) 
- 监听客户端连接
o	创建Socket,绑定指定端口,并设置监听队列。 
- 接收并解密AES密钥
o	生成RSA密钥对,并将公钥发送给客户端。
o	接收加密的AES密钥并使用RSA私钥解密。 
- 文件接收
o	接收文件信息(文件名和大小)。
o	分块接收加密文件数据,使用AES解密,写入到文件中。 
运行结果如下:


图中标黄的内容是RSA加密的AES秘钥, 标蓝色的是AES加密的密文, 标绿的是原文, 原文后面出现\x05的原因是客户端发送文件前对文件进行了PKCS7填充,  客户端这里打印出的是未经取消填充的内容
我们再来一次, 可以发现生成了不同的AES秘钥, 自然也就实现了相同文件每次发送的加密结果不同


服务端代码
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 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)                  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)         s.bind(('localhost', 9001))           s.listen(10)       except socket.error as msg:         print(msg)         sys.exit(1)     print('等待连接...')
      while 1:                  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())) + ' 开始交换秘钥!')                                  (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'))                                  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)
                                   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
   | import socket import os import sys import struct from Crypto.Cipher import AES import time import rsa
  key0 = os.urandom(16).hex()   iv = '1425374853627180'   BUFF = 1024
 
 
  def padding(text):     bs = AES.block_size       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        return text + padding_text
 
 
 
            def socket_client():     try:                  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]       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)  
      print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) + ' 发送加密后的AES秘钥:' + crypto.decode(         'utf8', 'ignore'))     s.send(crypto)  
           filepath = 'C:/XingYan/1.png'          if os.path.isfile(filepath):                  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'))               encryptedbytes = cipher.encrypt(data)             s.send(encryptedbytes)             print(encryptedbytes)             print(len(encryptedbytes))         s.close()
 
  if __name__ == '__main__':     socket_client()
   |