【问题标题】:How do I achieve Python TCP Socket Client/Server with Communications Encrypted?如何实现通信加密的 Python TCP 套接字客户端/服务器?
【发布时间】:2022-01-26 06:50:25
【问题描述】:

背景故事:我做了什么

{Codes at the bottom}我已经在以下站点的帮助下使用 python 套接字编写了多线程客户端和服务器程序:

I. Echo Client and Server

II. Socket Server with Multiple Clients | Multithreading | Python

III. Python Socket Receive Large Amount of Data

关于加密和解密

(1) 我应该在我的代码中的哪些位置加密/解密我的消息? 做 我在用户输入后自己加密消息,还是在输入消息编码后加密字节流?

(2)以及我应该如何正确有效地加密/解密通信?(很高兴看到带有解释的代码解决方案,非常感谢)

我目前的代码

_server.py

import socket
import os
from _thread import *
import struct # Here to convert Python data types into byte streams (in string) and back

# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg):  # ---- Use this to send
    # Prefix each message with a 4-byte length (network byte order)
    msg = struct.pack('>I', len(msg)) + msg
    sock.sendall(msg)

def recv_msg(sock: socket):       # ---- Use this to receive
    # Read message length and unpack it into an integer
    raw_msglen = recvall(sock, 4)
    if not raw_msglen:
        return None
    msglen = struct.unpack('>I', raw_msglen)[0]
    # Read the message data
    return recvall(sock, msglen)

def recvall(sock: socket, n: int):
    # Helper function to receive n bytes or return None if EOF is hit
    data = bytearray()
    while len(data) < n:
        packet = sock.recv(n - len(data))
        if not packet:
            return None
        data.extend(packet)
    return data

# ---- Server Communication Setup

HOST = '127.0.0.1'  # Standard loopback interface address (localhost)
PORT = 65432        # Port to listen on (non-privileged ports are > 1023)
ThreadCount = 0

try: # create socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print ("Socket successfully created")
except socket.error as err:
    print ("socket creation failed with error %s" %(err))

try: # bind socket to an address
    s.bind((HOST, PORT))
except socket.error as e:
    print(str(e))

print('Waitiing for a Connection..')
s.listen(3)

def threaded_client(conn: socket):
    conn.send(str.encode('Welcome to the Server'))
    while True:
        # data = conn.recv(2048) # receive message from client
        data = recv_msg(conn)
        reply = 'Server Says: ' + data.decode('utf-8')
        if not data:
            break
        # conn.sendall(str.encode(reply))
        send_msg(conn, str.encode(reply))
    conn.close()

while True:
    Client, addr = s.accept()
    print('Connected to: ' + addr[0] + ':' + str(addr[1]))
    start_new_thread(threaded_client, (Client, )) # Calling threaded_client() on a new thread
    ThreadCount += 1
    print('Thread Number: ' + str(ThreadCount))
s.close()

_client.py

import socket
import struct # Here to convert Python data types into byte streams (in string) and back 

# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg):  # ---- Use this to send
    # Prefix each message with a 4-byte length (network byte order)
    msg = struct.pack('>I', len(msg)) + msg
    sock.sendall(msg)

def recv_msg(sock: socket):       # ---- Use this to receive
    # Read message length and unpack it into an integer
    raw_msglen = recvall(sock, 4)
    if not raw_msglen:
        return None
    msglen = struct.unpack('>I', raw_msglen)[0]
    # Read the message data
    return recvall(sock, msglen)

def recvall(sock: socket, n: int):
    # Helper function to receive n bytes or return None if EOF is hit
    data = bytearray()
    while len(data) < n:
        packet = sock.recv(n - len(data))
        if not packet:
            return None
        data.extend(packet)
    return data

# ---- Client Communication Setup ----

HOST = '127.0.0.1'  # The server's hostname or IP address
PORT = 65432        # The port used by the server

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print ("Socket successfully created")
except socket.error as err:
    print ("socket creation failed with error %s" %(err))

print('Waiting for connection')
try:
    s.connect((HOST, PORT))
except socket.error as e:
    print(str(e))

Response = s.recv(1024)
while True:
    Input = input('Say Something: ')
    # s.send(str.encode(Input))
    send_msg(s, str.encode(Input))
    # Response = s.recv(1024)
    Response = recv_msg(s)
    print(Response.decode('utf-8'))

s.close()

【问题讨论】:

  • 只要使用 TLS/SSL,本网站和documentation 中都有很多示例。

标签: python sockets encryption server cryptography


【解决方案1】:

您只需要加密消息本身。我会使用 RSA 来加密消息。 如果您打算使用多个服务器,您可以打开第二个端口,如果有人连接到它,则服务器/主机。将公钥发送给客户端。 之后,客户端将他的公钥发送给服务器。

现在服务器和客户端交换端口,并在那里通信,同时使用对方的公钥加密消息并使用他们的私钥解密。

如果您只有一个服务器和一个客户端,您也可以对公钥进行硬编码。

一个很好的 RSA 加密模块是 PyCrytodome。

以下是使用 PyCrytodome 加密消息的示例。

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

def encrypt(pk_receiver, message):
    key = RSA.import_key(pk_receiver)
    cipher = PKCS1_OAEP.new(key)
    c = cipher.encrypt(message.encode())
    return c

def decrypt(sk, c):
    key = RSA.import_key(sk)
    cipher = PKCS1_OAEP.new(key)
    m = cipher.decrypt(c)
    return m

def generate_sk(key_length):
    key = RSA.generate(key_length)
    with open('./secret_key.pem', 'wb') as f:
        f.write(key.export_key(format='PEM'))
    return key


def generate_pk(sk):
    pk = sk.public_key()
    with open('./public_key.pem', 'wb') as f:
        f.write(pk.export_key(format='PEM'))
    return

【讨论】:

  • 这种方法有多个漏洞(中间人攻击、密钥管理等)。在保护传输中的数据时,通常 TLS/SSL/HTTPS 是更好的选择。
猜你喜欢
  • 2012-11-15
  • 2016-08-03
  • 2012-08-30
  • 2012-11-02
  • 1970-01-01
  • 2013-03-24
  • 2015-09-16
  • 2017-08-23
  • 1970-01-01
相关资源
最近更新 更多