Tchat crypté en python

oakthunder Messages postés 19 Date d'inscription dimanche 10 juillet 2022 Statut Membre Dernière intervention 26 mars 2024 - 23 mars 2024 à 18:24
mamiemando Messages postés 33113 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 15 mai 2024 - 27 mars 2024 à 10:42

Bonjour,

Je souhaite créer un tchat crypté en python (3.11) en utilisant les sockets et pycryptodome pour un chiffrement asymétrique avec des clés publiques et privées.

J'hébergerai un serveur et les clients se connecteront dessus.

J'aimerai qu'il y ait une interface graphique avec tkinter.

Je ne sais pas trop par quoi et comment commencer.

Merci de votre aide

4 réponses

oakthunder Messages postés 19 Date d'inscription dimanche 10 juillet 2022 Statut Membre Dernière intervention 26 mars 2024 1
26 mars 2024 à 12:12

J'ai écris le code du serveur et du client (multi clients possible).

Voici les codes :

# server.py
import socket
from threading import Thread
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import datetime

# Dictionnaire pour mapper les sockets des clients à leurs adresses
client_sockets = {}

# Générer une paire de clés RSA pour le serveur
key = RSA.generate(2048)
public_key = key.publickey().export_key()
private_key = key.export_key()

# Sauvegarder la clé publique pour que les clients puissent la récupérer
with open('public_key.pem', 'wb') as f:
    f.write(public_key)

with open('private_key.pem', 'wb') as f:
    f.write(private_key)

# Créer un chiffreur/déchiffreur avec la clé privée du serveur
cipher_rsa = PKCS1_OAEP.new(key)

def log(message):
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open("server_log.txt", "a") as f:
        f.write(f"[{timestamp}] {message}\n")

def broadcast_message(sender_socket, message):
    for client_socket in client_sockets.values():
        if client_socket != sender_socket:
            client_socket.sendall(message)

def client_handler(client_socket, client_address):
    log(f"Nouvelle connexion de {client_address}")
    print(f"Connexion établie avec {client_address}")
    while True:
        data = client_socket.recv(4096)
        if not data:
            log(f"Déconnexion de {client_address}")
            print(f"Déconnexion de {client_address}")
            client_socket.close()
            del client_sockets[client_address]
            broadcast_message(client_socket, f"{client_address} s'est déconnecté.\n".encode())
            break
        # Déchiffrer les données reçues
        decrypted_data = cipher_rsa.decrypt(data)
        decrypted_message = decrypted_data.decode()
        log(f"Message de {client_address}: {decrypted_message}")
        print(f"Message reçu de {client_address}: {decrypted_message}")

        # Rediffuser le message aux autres clients
        broadcast_message(client_socket, data)

# Configurer le serveur
HOST = '127.0.0.1'
PORT = 12345

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(5)

print(f"Serveur en attente de connexion sur {HOST}:{PORT}")

while True:
    client_socket, client_address = server_socket.accept()
    client_sockets[client_address] = client_socket
    client_thread = Thread(target=client_handler, args=(client_socket, client_address))
    client_thread.start()

et celui du client :

# client.py
import socket
import threading
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

# Charger la clé privée du client
with open('private_key.pem', 'rb') as f:
    client_private_key = RSA.import_key(f.read())

cipher_rsa = PKCS1_OAEP.new(client_private_key)

# Fonction pour envoyer des messages chiffrés au serveur
def send_message(sock, message):
    encrypted_message = cipher_rsa.encrypt(message.encode())
    sock.sendall(encrypted_message)

# Fonction pour recevoir et déchiffrer les messages du serveur
def receive_message(sock):
    data = sock.recv(4096)
    decrypted_data = cipher_rsa.decrypt(data)
    return decrypted_data.decode()

# Fonction pour gérer la réception des messages du serveur
def receive_thread(sock):
    while True:
        try:
            received_message = receive_message(sock)
            sender_address = sock.getpeername()[0]  # Obtenir l'adresse IP de l'expéditeur
            print(f"\nMessage de {sender_address}: {received_message}")
        except Exception as e:
            print("Erreur lors de la réception du message:", e)
            break

# Configurer le client
HOST = '127.0.0.1'
PORT = 12345

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

# Démarrer le thread de réception des messages
receive_thread = threading.Thread(target=receive_thread, args=(client_socket,))
receive_thread.daemon = True
receive_thread.start()

while True:
    message = input("")
    send_message(client_socket, message)
    print("Message envoyé.")

Je pense que je vais partir sur une interface tkinter, puis peut-être sur une interface web avec flask.

1
yg_be Messages postés 22792 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 18 mai 2024 1 467
23 mars 2024 à 18:49

bonjour,

pour moi, le point de départ, c'est de se former.

0
mamiemando Messages postés 33113 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 15 mai 2024 7 753
Modifié le 26 mars 2024 à 11:55

Bonjour,

Voici comment tu peux diviser le travail :

1) Pars de ce tutoriel :

1.a) Écris un serveur TCP qui se lance (cherche par exemple TCP echo serveur python)

1.b) Écris un client TCP qui se lance et qui se connecte à ton serveur avec succès.

2) Étends cet exemple pour plusieurs clients. Il faut alors que ton serveur broadcast le message émis par un client à tous ses clients.

3) Ajoute l'éventuelle couche de sécurité

4) Une fois que tout fonctionne correctement en mode texte, ajoute ton interface graphique.

Bonne chance

0
mamiemando Messages postés 33113 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 15 mai 2024 7 753
Modifié le 27 mars 2024 à 10:44

Bonjour,

C'est un bon départ. Concernant le choix de l'interface utilisateur (UI), ça n'a pas vraiment d'importance. Si ton code est bien conçu, quelle soit graphique ou non, ton UI ne fait qu'appeler certaines primitives de base (par exemple, envoyer un message, bannir un utilisateur, rendre muet un utilisateur, rejoindre un canal, quitter un canal, etc...).

Si on remonte dans tes temps reculés avec IRC, les messages pouvaient commencer par un mot clé commençant par un / (par exemple /join canal), et du coup le client comprenait qu'il ne fallait pas envoyer un message, mais exécuter une autre primitive. Cette idée à depuis été repris dans la plupart des logiciels de chat. Cela signifie qu'une UI, quelle qu'elle soit, peut se contenter d'envoyer un message, éventuellement précédé d'un mot clé, pour déclencher une action côté serveur et/ou client.

Une interface web a le mérite d'être utilisable par tout un chacun sans installation, donc c'est assez pratique. Ensuite le choix d'appartient, pourquoi pas flask qui est effectivement très utilisé. Personnellement j'utilise souvent cherrypy.

Si tu pars sur un client lourd, choisis plutôt une bibliothèque qui marche sur plusieurs systèmes d'exploitation (typiquement parmi GTK, Qt, Tk). Je pense que ce qui guidera ton choix et la documentation, le nombre d'exemples disponibles sur Internet, etc.

Personnellement, je trouve tkinter (par exemple comparé à pyQt) assez mal documenté, mais il est très utilisé et donc on peut s'en sortir en cherchant des exemples.

À toi de faire ton état de l'art pour choisir la technologie qui te paraît la plus appropriée....

Bonne chance

0