#!/usr/bin/env python3 # coding: utf8 import json import logging import logging.config import os import socket import threading #### logging #### # json decoder for int keys from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA from Crypto.Random import get_random_bytes def make_hashable(o): if isinstance(o, (tuple, list)): return tuple((make_hashable(e) for e in o)) elif isinstance(o, dict): return tuple(sorted((k, make_hashable(v)) for k, v in o.items())) elif isinstance(o, (set, frozenset)): return tuple(sorted(make_hashable(e) for e in o)) return o class Decoder(json.JSONDecoder): def decode(self, s, **kwargs): result = super().decode(s) # result = super(Decoder, self).decode(s) for Python 2.x return self._decode(result) def _decode(self, o): if isinstance(o, str): try: return int(o) except ValueError: return o elif isinstance(o, dict): return {k: self._decode(v) for k, v in o.items()} elif isinstance(o, list): return [self._decode(v) for v in o] else: return o def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'): """Setup logging configuration """ path = default_path value = os.getenv(env_key, None) if value: path = value if os.path.exists(path): with open(path, 'rt') as f: config = json.load(f) logging.config.dictConfig(config) else: logging.basicConfig(level=default_level) setup_logging() log_server = logging.getLogger('server') debug = log_server.debug info = log_server.info warning = log_server.warning error = log_server.error critical = log_server.critical #### Variables #### HOST = '' PORT = 8888 BUFFER_SIZE = 4096 BEGIN_MESSAGE = bytes("debut".ljust(BUFFER_SIZE, ";"), "ascii") END_MESSAGE = bytes("fin".ljust(BUFFER_SIZE, ";"), "ascii") VERSION = "EICP2P2 V1" DONE = 0 ERROR = 1 #### Socket #### main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) main_socket.bind((HOST, PORT)) #### Threads #### class clientThread(threading.Thread): """Main thread, for each client""" def __init__(self, clientsocket, ip, port): """Create clientThread object :param clentsocket: Client's socket :param ip: Client's ip address :param port: Client's connection PORT :type clientsocket: socket.socket :type ip: str :type port: int :return: Nothing :rtype: NoneType""" debug("Creation du thread pour %s" % ip) threading.Thread.__init__(self) # initialisation du thread self.client = clientsocket self.ip = ip self.port = port self.running = True self.status = None debug("Creation du thread pour %s reussie" % ip) def initialize(self): """Interpret request header""" # Receive message chunk = bytes("", "ascii") while chunk != BEGIN_MESSAGE: chunk = self.client.recv(BUFFER_SIZE) last_chunk = chunk while last_chunk != END_MESSAGE: last_chunk = self.client.recv(BUFFER_SIZE) chunk += last_chunk # Remove the begening and the end of chunk util_part = chunk[BUFFER_SIZE:-BUFFER_SIZE] print(util_part) header = util_part[:BUFFER_SIZE] print(header) content = util_part[BUFFER_SIZE:] header_txt = header.decode("ascii").rstrip(";") version = header_txt.split("\n")[0] # Extraction des champs du header if version != VERSION: debug("Pas la bonne version") self.send(b"Error".ljust(BUFFER_SIZE, b";")) champs = {l.split(": ")[0]: l.split(": ")[1] for l in header_txt.split('\n')[1:]} if champs.get("type", None) is None: debug("Le champ type n'est pas dans le header") self.send(b"Error".ljust(BUFFER_SIZE, b";")) return if self.status is None and champs["type"] != "RSASend": debug("Requête différente de RASSend avec une connection non initialisée") self.send(b"Error".ljust(BUFFER_SIZE, b";")) return if champs["type"] == "RSASend": debug("Réception de la clef RSA de %s", self.ip) self.rsa_client = content.rstrip(b";").rstrip(b' ') self.aes_key = get_random_bytes(64) header = bytes((VERSION+"\ntype: init").ljust(BUFFER_SIZE, ";"), 'ascii') content = self.aes_key.ljust(BUFFER_SIZE, b";") self.send_rsa(header+content) return def send_rsa(self, to_send): if self.rsa_client is None: debug("Clef RSA non recue") self.client.send(b"Error".ljust(BUFFER_SIZE)) return # Transform rsakey and generate sessionkey recipient_key = RSA.import_key(self.rsa_client) # RSA crypter object cipher_rsa = PKCS1_OAEP.new(recipient_key) # Encrypt session_key crypted = b"" for to_send_text in [to_send[i:i + 16] for i in range(0, len(to_send), 16)]: crypted += cipher_rsa.encrypt(to_send_text) self.send(crypted) def send(self, to_send): self.client.send(BEGIN_MESSAGE) i=0 for to_send_text in [to_send[i:i + BUFFER_SIZE] for i in range(0, len(to_send), BUFFER_SIZE)]: self.client.send(to_send_text.ljust(BUFFER_SIZE, b";")) i+=1 print(i) self.client.send(END_MESSAGE) def run(self): # main de la connection du client """Run thread mainloop :return: Nothing :rtype: NoneType""" self.initialize() print("done") self.client.close() if __name__ == "__main__": clients = [] while True: main_socket.listen(1) # ecoutes des connections entrantes clientsocket, (ip, PORT) = main_socket.accept() newClient = clientThread(clientsocket, ip, PORT) newClient.start() clients.append(newClient)