diff --git a/.gitignore b/.gitignore index 15571e2..ee759a4 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,3 @@ venv.bak/ # pycharm .idea/ - -# Pipenv.lock -Pipfile.lock diff --git a/Pipfile b/Pipfile index 33efa86..fb2f2e1 100644 --- a/Pipfile +++ b/Pipfile @@ -1,12 +1,12 @@ [[source]] -name = "pypi" -verify_ssl = true url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" [packages] -pycrypto = "*" - -[requires] -python_version = "3.5" +pycryptodome = "*" [dev-packages] + +[requires] +python_version = "3.7" diff --git a/RFC8497.md b/RFC8497.md index b0bbb22..3689db2 100644 --- a/RFC8497.md +++ b/RFC8497.md @@ -250,7 +250,7 @@ Réponse du client à une requête de ping. Initialisation des connections ------------------------------ -### RSAGet ### +### RSASend ### > En clair @@ -270,7 +270,7 @@ Cette requête est utilisé pour initialiser la communication crypté entre deux ### Init ### -> Chiffré avec la clef RSA publique recue avec la requete RSAGet +> Chiffré avec la clef RSA publique recue avec la requete RSASend ###### En-tête ###### @@ -284,7 +284,11 @@ Cette requête est utilisé pour initialiser la communication crypté entre deux ###### Utilisation ###### -Requête envoyée en réponse à RSAGet pour initialiser la connection cryptée en AES. +Requête envoyée en réponse à RSASend pour initialiser la connection cryptée en AES. + +### Error ### + + Error Tables ------ diff --git a/client/log_config.json b/client/log_config.json index 4686e03..a39c479 100644 --- a/client/log_config.json +++ b/client/log_config.json @@ -36,7 +36,6 @@ "server": { "level": "DEBUG", "handlers": [ - "console", "info_file_handler", "error_file_handler" ] diff --git a/client/main.py b/client/main.py index 0142fd6..7d59c09 100644 --- a/client/main.py +++ b/client/main.py @@ -12,6 +12,9 @@ import socket # json decoder for int keys import threading +from Crypto.Cipher import PKCS1_OAEP +from Crypto.PublicKey import RSA + class Decoder(json.JSONDecoder): def decode(self, s, **kwargs): @@ -60,7 +63,7 @@ critical = log_server.critical #### Variables #### HOST = '127.0.0.1' PORT = 8888 -BUFFER_SIZE = 16384 +BUFFER_SIZE = 4096 clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) clientSocket.connect((HOST, PORT)) @@ -69,13 +72,50 @@ clientSocket.connect((HOST, PORT)) - - - - - - - +BEGIN_MESSAGE = bytes("debut", "ascii").ljust(BUFFER_SIZE, b";") +END_MESSAGE = bytes("fin", "ascii").ljust(BUFFER_SIZE, b";") +HEADER_TXT = """\ +EICP2P2 V1 +type: RSASend""" +HEADER = bytes(HEADER_TXT, "ascii").ljust(BUFFER_SIZE, b";") + +## création des clef RSA +print(1024) +key = RSA.generate(BUFFER_SIZE) +private_key = key.export_key() +file_out = open("private.pem", "wb") +file_out.write(private_key) + +public_key = key.publickey().export_key() + +file_out = open("receiver.pem", "wb") +file_out.write(public_key) +to_send = public_key.ljust(BUFFER_SIZE, b';') + +clientSocket.send(BEGIN_MESSAGE) +clientSocket.send(HEADER) +clientSocket.send(to_send) +clientSocket.send(END_MESSAGE) +print('ok') +# BEGIN +chunk = clientSocket.recv(BUFFER_SIZE) +print(chunk) +# HEADER +cry_header = clientSocket.recv(BUFFER_SIZE).rstrip(b';') +print(cry_header) +# AESKEY +cry_aeskey = clientSocket.recv(BUFFER_SIZE).rstrip(b";") +print(cry_aeskey) +# END +chunk = clientSocket.recv(BUFFER_SIZE) +print(chunk) + +# HEADER+AES key are encypted in same time, so decrypt thme at same time +cipher_rsa = PKCS1_OAEP.new(key) +t = cry_header+cry_aeskey +for to_decrypt in [t[i:i + int(len(public_key)/16)] for i in range(0, len(t), int(len(public_key)/16))]: + print(len(to_decrypt)) + print(cipher_rsa.decrypt(to_decrypt)) diff --git a/client/private.pem b/client/private.pem new file mode 100644 index 0000000..99dfd9c --- /dev/null +++ b/client/private.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/client/receiver.pem b/client/receiver.pem new file mode 100644 index 0000000..5e5e993 --- /dev/null +++ b/client/receiver.pem @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvlMf7Wn+JRaFR4ErqgpQ +A3m86J++XPRZrKK6UJtdUqGI3XugiqbYUSr2n5+LOlfPNDQ6okcqGX+uJFaetWii +JLqzYvl+UjXwDK/jvCwlHvnjmViUw0MDzKyVfiNfwWAsoQXuQqk+vJWwyFuskxXI +QDRlHoye6KGsciweDcJjqqwurw5EbrozOeuC8pkl4gxK8xQcc6sYxc8Rs5EjYug5 +qRbNw8FHiM6AIovYlrew2pzAyUDTPkOmmDZzESlmLWhTeS0GEaewvv+WX2yzE3yF +e9tSAO8SlBGaJ3LNpGIwDKgLH+9kFbQPkcLB0AnGnTAVvS/6nALWVYkXv98JacXV +GXBkWobn3IvWZ1djUXMpgs4haJfpCx5+KoRwkdBjQzPC/Ztx94lE9wd+3nNfusJV +IzZVcdfysbojbcNLnp77NYBFaAxw32U6m4jVYjAxr/NSw9VEcxiWshuv/UU3f9C1 +rA3yagYOhLGCxtMiNtyXtujmmT2eVVoCePLveOWzeV+gLWm2ISU1RJ78vOhMc6T5 +H9KJT4A50hI0LYa9fL141qOON3iwqzUT4dnMTfaXHXjTdybTku1es0GWkxorb2vl +I7AY9qPiuetrdW6EK5Xittc0gaeFSXwXoBAZStGk1rKy2HP1nMsfzv7MjMdqtPhI +CJ+LjgilL/ZhhfqNWwSWdIkCAwEAAQ== +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/server/log_config.json b/server/log_config.json index 4686e03..e1d4806 100644 --- a/server/log_config.json +++ b/server/log_config.json @@ -45,7 +45,6 @@ "root": { "level": "INFO", "handlers": [ - "console", "info_file_handler", "error_file_handler" ] diff --git a/server/main.py b/server/main.py index dcf8ab4..a650e64 100644 --- a/server/main.py +++ b/server/main.py @@ -6,11 +6,24 @@ import logging import logging.config import os import socket +import threading #### logging #### # json decoder for int keys -import threading +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): @@ -60,12 +73,21 @@ critical = log_server.critical #### Variables #### HOST = '' PORT = 8888 -BUFFER_SIZE = 16384 +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""" @@ -87,14 +109,86 @@ class clientThread(threading.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 + self.client.send(BEGIN_MESSAGE) + for to_send_text in [to_send[i:i + BUFFER_SIZE] for i in range(0, len(to_send), BUFFER_SIZE)]: + crypted = b"" + for to_send_text_ in [to_send_text[i:i+int(len(self.rsa_client)/16)] for i in range(0, len(to_send_text), int(len(self.rsa_client)/16))]: + print(len(to_send_text_)) + crypted += cipher_rsa.encrypt(to_send_text_) + self.client.send(crypted.ljust(BUFFER_SIZE, b';')) + self.client.send(END_MESSAGE) + + def send(self, to_send): + self.client.send(BEGIN_MESSAGE) + 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";")) + self.client.send(END_MESSAGE) + + def run(self): # main de la connection du client """Run thread mainloop :return: Nothing :rtype: NoneType""" - ### ICI ON MET LA BOUCLE PRINCIPALE DE CONNECTION + self.initialize() + print("done") self.client.close()