Compare commits

..

3 Commits

Author SHA1 Message Date
ddf2a49780 [client] Added RSA Key generation 2018-11-18 00:03:51 +01:00
3e11fec257 .gitignore update 2018-11-17 14:03:43 +01:00
5d6519c57a chmod +x 2018-11-17 13:57:55 +01:00
14 changed files with 114 additions and 931 deletions

12
.gitignore vendored
View File

@ -105,3 +105,15 @@ venv.bak/
# pycharm # pycharm
.idea/ .idea/
# Pipenv.lock
Pipfile.lock
# Dolphin
*.directory
# Private keys
*.pem
# Kate
*.kate-swp

11
Pipfile
View File

@ -1,12 +1,13 @@
[[source]] [[source]]
name = "pypi"
url = "https://pypi.org/simple" url = "https://pypi.org/simple"
verify_ssl = true verify_ssl = true
name = "pypi"
[packages]
pycryptodomex = "*"
[dev-packages] [dev-packages]
[packages]
pycryptodome = "*"
pycrypto = "*"
[requires] [requires]
python_version = "3.7" python_version = "3.6"

55
Pipfile.lock generated
View File

@ -1,55 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "ea1158d96215416c8146e8deedecea8da28400d9f80633238e5816576965f13e"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"pycryptodomex": {
"hashes": [
"sha256:02c358fa2445821d110857266e4e400f110054694636efe678dc60ba22a1aaef",
"sha256:09989c8a1b83e576d02ad77b9b019648648c569febca41f58fa04b9d9fdd1e8f",
"sha256:0f8fe28aec591d1b86af596c9fc5f75fc0204fb1026188a44e5e1b199780f1e5",
"sha256:0fb58c2065030a5381f3c466aaa7c4de707901badad0d6a0575952bb10e6c35f",
"sha256:0fb9f3e6b28a280436afe9192a9957c7f56e20ceecb73f2d7db807368fdf3aaf",
"sha256:12ff38a68bbd743407018f9dd87d4cc21f9cb28fe2d8ba93beca004ada9a09ff",
"sha256:1650143106383bae79cbbda3701fd9979d0a624dba2ec2fa63f88cae29dd7174",
"sha256:20a646cd0e690b07b7da619bc5b3ee1467243b2e32dfff579825c3ad5d7637ab",
"sha256:284779f0908682657adb8c60d8484174baa0d2620fb1df49183be6e2e06e73ce",
"sha256:2f3ce5bfe81d975c45e4a3cbe2bef15b809acc24f952f5f6aa67c2ae3c1a6808",
"sha256:30ac12f0c9ac8332cc76832fea88a547b49ef60c31f74697ee2584f215723d4f",
"sha256:4f038b815d66dea0b1d4286515d96474204e137eb5d883229616781865902789",
"sha256:57199a867b9991b1950f438b788e818338cee8ed8698e2eebdc5664521ad92a9",
"sha256:5c5349385e9863e3bba6804899f4125c8335f66d090e892d6a5bb915f5c89d4c",
"sha256:5d546fac597b5007d5ff38c50c9031945057a6a6fa1ab7585058165d370ea202",
"sha256:614eddfa0cf325e49b5b803fcb41c9334de79c4b18bf8de07e7737e1efc1d2b9",
"sha256:82ae66244824d50b2b657c32e5912fde70a6e36f41e61f2869151f226204430d",
"sha256:96a733f3be325fb17c2ba79648e85ab446767af3dc3b396f1404b9397aa28fe5",
"sha256:9c3834d27c1cff84e2a5c218e373d80ebbb3edca81912656f16137f7f97e58e0",
"sha256:9f11823636128acbe4e17c35ff668f4d0a9f3133450753a0675525b6413aa1b0",
"sha256:a3f9ad4e3f90f14707776f13b886fbac491ebe65d96a64f3ce0b378e167c3bbf",
"sha256:a89dee72a0f5024cc1cbaf85535eee8d14e891384513145d2f368b5c481dcd54",
"sha256:ccadde651e712093052286ad9ee27f5aa5f657ca688a1bf6d5c41ade709467f3",
"sha256:ced9ea10977dd52cb1b936a92119fc38fcdc5eaa4148f925ef22bbf0f0d4a5bd",
"sha256:eb0c6d3b91d55e3481158ecf77f3963c1725454fdcf5b79302c27c1c9c0d2c2a",
"sha256:f6714569a4039287972c672a8bd4b8d7dc78a601def8b31ffa39cd2fec00cb4b",
"sha256:fa4036582c8755259d4b8f4fe203ae534b7b187dcea143ab53a24e0f3931d547",
"sha256:fb31bb0c8301e5a43d8d7aad22acabef65f28f7ab057eaeb2c21433309cc41e8"
],
"index": "pypi",
"version": "==3.7.0"
}
},
"develop": {}
}

View File

@ -141,7 +141,7 @@ Communication entre un client et un noeud
###### En-tête ###### ###### En-tête ######
EICP2P2 V1 EICP2P2 V1
type: register_client type: register
###### Contenu ###### ###### Contenu ######
@ -160,11 +160,11 @@ Cette requête est envoyée par un client pour s'enregistrer sur le réseau. Le
###### Contenu ###### ###### Contenu ######
id_noeud{%=&%&=%}id_client id_noeud::id_client
###### Utilisation ###### ###### Utilisation ######
Réponse à un `register_client`. Le noeud communique au client son id et l'id du noeud auquel il est connecté. Réponse à un `register`. Le noeud communique au client son id et l'id du noeud auquel il est connecté.
### Send ### ### Send ###
@ -191,7 +191,7 @@ Cette requête est envoyé par un client enregistré à un noeud pour envoyer un
###### Contenu ###### ###### Contenu ######
Rien/Erreur client incunnu Rien
###### Utilisation ###### ###### Utilisation ######
@ -217,28 +217,6 @@ Cette requête est envoyée par le destinataire d'une requête `send` après avo
Envoyé par le client pour se déconnecter du réseau. Ne demande aucune réponse de la part du noeud. Envoyé par le client pour se déconnecter du réseau. Ne demande aucune réponse de la part du noeud.
### Get users ###
###### En-tête ######
EICP2P2 V1
type: getUsers
###### Contenu ######
Rien
### Get User ACK ###
###### En-tête ######
EICP2P2 V1
type: getUsersACK
###### Contenu ######
Listedesutilisateurs
### Ping ### ### Ping ###
###### En-tête ###### ###### En-tête ######
@ -272,15 +250,14 @@ Réponse du client à une requête de ping.
Initialisation des connections Initialisation des connections
------------------------------ ------------------------------
### RSASend ### ### RSAGet ###
> En clair > En clair
###### En-tête ###### ###### En-tête ######
EICP2P2 V1 EICP2P2 V1
type: RSASend type: RSAget
from: noeud/client
###### Contenu ###### ###### Contenu ######
@ -293,12 +270,13 @@ Cette requête est utilisé pour initialiser la communication crypté entre deux
### Init ### ### Init ###
> Chiffré avec la clef RSA publique recue avec la requete RSASend > Chiffré avec la clef RSA publique recue avec la requete RSAGet
###### En-tête ###### ###### En-tête ######
EICP2P2 V1 EICP2P2 V1
type: init type: init
from: noeud/client
###### Contenu ###### ###### Contenu ######
@ -306,13 +284,7 @@ Cette requête est utilisé pour initialiser la communication crypté entre deux
###### Utilisation ###### ###### Utilisation ######
Requête envoyée en réponse à RSASend pour initialiser la connection cryptée en AES. Requête envoyée en réponse à RSAGet pour initialiser la connection cryptée en AES.
### Error ###
Error
Tables Tables
------ ------

309
client/main.py Normal file → Executable file
View File

@ -6,51 +6,33 @@ import logging
import logging.config import logging.config
import os import os
import socket import socket
#### logging ####
# json decoder for int keys
import threading import threading
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
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: try:
# noinspection PyUnresolvedReferences return int(o)
from Crypto.PublicKey import RSA as RSA except ValueError:
# noinspection PyUnresolvedReferences return o
from Crypto.Cipher import PKCS1_OAEP as PKCS1_OAEP elif isinstance(o, dict):
return {k: self._decode(v) for k, v in o.items()}
pycryptodome = False elif isinstance(o, list):
except ModuleNotFoundError: # Pycryptodomex return [self._decode(v) for v in o]
from Cryptodome.PublicKey import RSA as RSA else:
from Cryptodome.Cipher import PKCS1_OAEP as PKCS1_OAEP return o
from Cryptodome.Cipher import AES as AES
pycryptodome = True
class RsaGenThread(threading.Thread):
def __init__(self, client_, difficulty=2):
threading.Thread.__init__(self)
self.client = client_
self.difficulty = difficulty
def run(self):
if os.path.isfile("private.pem"):
try:
with open("private.pem", "rb") as keyfile:
rsa = RSA.importKey(keyfile.read())
if not rsa.has_private():
warning("Le fichier clef ne contient pas de clef privée")
raise ValueError
self.client.rsa = rsa
except (IndexError, ValueError):
warning("Fichier clef corrompu")
debug("Suppression du fichier clef corromu")
os.remove("private.pem")
if not os.path.isfile("private.pem"): # We're not using if/else because we may delete the file in the
# previous if statement
debug("Génération de la clef RSA pour %s" % self.client.name)
self.client.rsa = RSA.generate(BUFFER_SIZE + 256 * self.difficulty)
with open("private.pem", "wb") as keyfile:
keyfile.write(self.client.rsa.exportKey())
with open("public.pem", "wb") as keyfile:
keyfile.write(self.client.rsa.publickey().exportKey())
def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'): def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'):
@ -83,19 +65,7 @@ HOST = '127.0.0.1'
PORT = 8888 PORT = 8888
BUFFER_SIZE = 4096 BUFFER_SIZE = 4096
CHUNK_SIZE = int(BUFFER_SIZE/8) CHUNK_SIZE = int(BUFFER_SIZE/8)
BEGIN_MESSAGE = bytes("debut".ljust(BUFFER_SIZE, ";"), "ascii") NAME = 'default'
END_MESSAGE = bytes("fin".ljust(BUFFER_SIZE, ";"), "ascii")
NAME = b"client1"
VERSION = b"EICP2P2 V1"
REQUEST_TYPE = [
b'ping', b'pingACK', b'updateAsk', b'updateBack', b'transfer', b'register_client', b'registerACK', b'send',
b'sendACK',
b'exit', b'RSASend', b'init', b'getUsers', b'getUsersACK',
]
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect((HOST, PORT))
# ET ICI ON MET LE CLIENT # ET ICI ON MET LE CLIENT
@ -107,210 +77,41 @@ class MainThread(threading.Thread):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.name = name self.name = name
self.rsa = None self.rsa = None
self.aes_key = None
self.clientSocket = None
self.users = {
# id: rsa
}
self.connected_users = {
# id: (rsa, aes, nick)
}
def run(self): def run(self):
rsa = RsaGenThread(self) rsa = self.rsaGenThread(self)
rsa.start() rsa.start()
rsa.join() rsa.join()
self.clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clientSocket.connect((HOST, PORT)) clientSocket.connect((HOST, PORT))
self.initialisation()
self.register() class rsaGenThread(threading.Thread):
self.get_users()
print(self.users) def __init__(self, client, difficulty=30, new=False):
while True: threading.Thread.__init__(self)
self.client = client
self.difficulty = difficulty
def run(self):
if os.path.isfile("private.pem"):
try: try:
type = bytes(input("Type: "), "ascii") with open("private.pem", "rb") as keyfile:
contenu = bytes(input("Contenu: "), "ascii") rsa = RSA.importKey(keyfile.read())
self.send_aes(self.gen_header(type_=type) + contenu) if not rsa.has_private():
print(self.receive_aes()) warning("Le fichier clef ne contient pas de clef privée")
except Exception as e: raise ValueError
print(e) self.client.rsa = rsa
except (IndexError, ValueError):
def register(self): warning("Fichier clef corrompu")
self.send_aes(self.gen_header(type_=b"register_client")) debug("Suppression du fichier clef corromu")
self.id_noeud, self.id_client = self.receive_aes()[BUFFER_SIZE:].split(b"{%=&%&=%}") os.remove("private.pem")
if not os.path.isfile("private.pem"): # We're not using if/else because we may delete the file in the previous if statement
def initialisation(self): debug("Génération de la clef RSA pour %s" % self.client.name)
header = self.gen_header(b"RSASend", from_=b"client") self.client.rsa = RSA.generate(BUFFER_SIZE + 256*self.difficulty)
content = self.rsa.publickey().exportKey() with open("private.pem", "wb") as keyfile:
self.send(header + content) keyfile.write(self.client.rsa.exportKey())
print("oki1") with open("public.pem", "wb") as keyfile:
data = self.receive_rsa() keyfile.write(self.client.rsa.publickey().exportKey())
print("oki2")
header = self.extract_header(data[:BUFFER_SIZE])
if header[b"type"] != b"init":
debug("Incorrect request type, end of connection")
return
self.aes_key = data[BUFFER_SIZE:]
debug("End of initialisation")
@staticmethod
def extract_header(data):
"""Extract header from data
:param data: Data to extract header
:type data: bytes
:return: Dictionary with header datas
:rtype: dict{bytes: bytes}"""
if len(data) > BUFFER_SIZE:
debug("Header too long")
data = data[:BUFFER_SIZE]
data_lines = data.split(b'\n')
if data_lines[0] != VERSION:
raise ValueError("Version is incorrect.")
return {
l.split(b": ")[0]: l.split(b": ")[1].rstrip(b";") for l in data_lines[1:]
}
@staticmethod
def gen_header(type_, to_=None, from_=None):
"""Generate header
:param type_: Request type
:param to_: `to` field in header, cf ../RFC8497.md
:param from_: `from` field in header, cf ../RFC8497.md
:type type_: bytes
:type to_: bytes
:type from_: bytes
:return: header
:rtype: bytes"""
if type_ not in REQUEST_TYPE:
raise ValueError("Unknown request type")
header = VERSION + b"\ntype: " + type_
if to_:
header += b"\nto: " + to_
if from_:
header += b"\nfrom: " + from_
return header.ljust(BUFFER_SIZE, b';')
def get_users(self):
self.send_aes(self.gen_header(type_=b'getUsers'))
back = self.receive_aes()
print(back)
header = self.extract_header(back)
contenu = back[BUFFER_SIZE:]
if header[b"type"] == b"getUsersACK":
self.users = {i: contenu.split(b"%!!%")[i] for i in range(len(contenu.split(b"%!!%")))}
################################################ COMMUNICATION WITH AES ############################################
def send_aes(self, to_send, key=None):
"""Send message with aes encryption
:param to_send: Message to send
:type to_send: bytes
:param key: key to replace self.aes_key
:type key: bytes
:rtype: NoneType
:return: Nothing"""
debug(b"Send with AES encryption: " + to_send)
if key is None:
key = self.aes_key
if key is None:
info("AES key not generated, connection failure.")
self.client.send(b"Error")
return
# Get RSA key
aes_object = AES.new(key, AES.MODE_ECB)
encrypted = b""
for to_send_text in [to_send[i:i + 32] for i in range(0, len(to_send), 32)]:
encrypted += aes_object.encrypt(to_send_text.ljust(32, b"\x00"))
self.send(encrypted)
return None
def receive_aes(self, key=None):
"""Receive message with aes encryption
:param key: key to replace self.aes_key
:type key: bytes
"""
to_decrypt = self.receive()
debug(b"Received in aes " + to_decrypt)
if key is None:
key = self.aes_key
if key is None:
info("AES key not generated, connection failure.")
self.client.send(b"Error")
return
aes_object = AES.new(key, AES.MODE_ECB)
decrypted = b""
for block in [to_decrypt[i:i + 32] for i in range(0, len(to_decrypt), 32)]:
print(len(block))
decrypted += aes_object.decrypt(block)
return decrypted.rstrip(b"\x00")
################################################ COMMUNICATION WITH RSA ############################################
def receive_rsa(self, rsa_key=None):
if rsa_key is None:
rsa_key = self.rsa.exportKey()
if rsa_key is None:
info("RSA key not generated, connection failure.")
return
recipient_key = RSA.importKey(rsa_key)
cipher_rsa = PKCS1_OAEP.new(recipient_key)
raw = self.receive()
content = b""
for to_decrypt in [raw[i:i + self.rsa.publickey().size_in_bytes()] for i in
range(0, len(raw), self.rsa.publickey().size_in_bytes())]:
content += cipher_rsa.decrypt(to_decrypt)
return content
############################################ COMMUNICATION WITHOUT CRYPTING ############################################
def receive(self):
"""Receive message from connection
:rtype: bytes
:return: Message's content"""
chunk = bytes("", "ascii") # Temp variable to store received datas
while chunk != BEGIN_MESSAGE:
chunk = self.clientSocket.recv(BUFFER_SIZE)
content = b''
while chunk != END_MESSAGE:
chunk = self.clientSocket.recv(BUFFER_SIZE)
# Get only interesting chucks
if chunk != END_MESSAGE:
# Get content part
# int.from_bytes(chunk[:2], byteorder='big') == Get content size
content += chunk[2:int.from_bytes(chunk[:2], byteorder='big') + 2]
debug(b"Received: " + content)
return content
def send(self, to_send):
"""Send message to connection
:param to_send: message to send
:type to_send: bytes
:return: Nothing
:rtype: NoneType"""
debug(b"Send " + to_send)
# Sending the message start
self.clientSocket.send(BEGIN_MESSAGE)
i = 0
for to_send_text in [to_send[i:i + BUFFER_SIZE - 2] for i in range(0, len(to_send), BUFFER_SIZE - 2)]:
self.clientSocket.send(
(len(to_send_text)).to_bytes(2, byteorder='big') # Size of the message contained by the chunk
+ to_send_text.ljust(BUFFER_SIZE - 2, bytes(1)) # Content of the chunk
)
i += 1
# Sending the message stop
self.clientSocket.send(END_MESSAGE)
return None
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,57 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1,15 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIICYjANBgkqhkiG9w0BAQEFAAOCAk8AMIICSgKCAkEAyCjkX4LpaXrvh8oeVq6r
dNLNpVBUiJxSX8CJizqB6Z/m8/4ZR69V0H/MzVjngnczA9Z2ITsIJ3ZLpGxL5TNC
4Kv5q3LKsvhuSWMTq97q2bKaeCBrROOurG5FxWrTqLHbs5U47kJEDKH6Orn42l6t
jvl/74qWTRarpZ4lbNfIkbM45rp10OhZNnjCsuxlcWEhGn5bp6IrSsQ0ZIYfwNLw
sEDjkn/fCz9NY0ZouT8ua/RnEkW7s6KOAdoaQi6LSADq9BXK+c4Zdfb5E7ScBzHM
jl10AqyNSHZ3DnFL5AEdzC4ZbmXLSbAKuglFnplKoXRZm6rUb2rWU3NDQ9LVIoUp
OfHUD+ip6V9nuQHIS7KVHJ0hgu9s3lRwN5YwnNz5OqcxWB2eLw8PLaH0WNRTmfbl
9EEf2huhUpgXv/DI+7J0dfnSpxaGO0YAZnjm0x+E/ryXq3vpGb3uErgJ8iuro6MF
LE7u9iiAr8HQisGiVVIPgvmns3fqHJq1tJ1p0GSjHN+Of2QQPx7TSpt/5Ew3Y/pZ
/ho8vazIBe036v6NyENywrW+UWYWdB6m9boEcg6GElSA0kVMw37syuRw7O6FhiOw
JZNjAMA67siio1vJfHXrzLhFmlyUzE07raMFpG4aKw2zwo4PKLSxIiU66i9/ECbJ
+3yN7p+XXljCkni7KO9JSI64hETw7BiY+S/+ZqaipnB3hWxQFsZn36RfeU/BIfGz
kQ4+NdYZPgR4h64tcVv9BjZ8abqBb5id1wFRpKVDeDpDAgMBAAE=
-----END PUBLIC KEY-----

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1,14 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnyiVFNxPTuctHL12pPcB
zumJnSiA7CZtbUbgozPjuVuJJQcf8FPZEQWFphtUujZVMRi6PX3szkKhOb08pl75
yzoA9H1ql5UoutuGExc0PVzaTY5BtnU38q6XvyWTYz5TNaG2bhd9DuNv9JrMn+/y
dClxOGvTd4Y+7VI8RG8HHnwMrwRcLzQ2FSJD9mVSopFn+5Z0j0idog2O/SsZJM3c
8ieLoOHO9vxQO8xVaUIF74nVoNiLz/YrcAhU9N3y2KcjpAsQBbFznKeQ6AcW5WjC
9zZBVLElP2PAVd6EFKY9C6nuodsaICqgWZnyCh+tEI8i+IQq2RN1YySv+6Cn929w
VM2tDPxaYfziSLkW5Pk9oPJ43xHsjb8yFUKsoChPmo4Qe4AVkIIbxwVWG0wymWqE
uWeiKlc32badxf38dAm9TvgAApZ05cSIV6ieYP+ixjMFa2rrjkPtfcXey6O05D8u
TMQx9GPZRNezceRWI89Lip83raWqjhw+hUvbGaUL0B/z7XD1zskmQ9n+RnhYRVZr
YOTw2BWoGoMBC13/g7qG2RR+qrJFs1PLTbUgrzP5HkVpKzBvi2G3BxXGr0aflOtL
rOU275LjdkkJrOiNMdPrGsUe9S9XPK5irHampxnJOv5oOCQZ0m/bzKXJykZAJF9f
X8caOE++kTH0DSqsapE0fC8CAwEAAQ==
-----END PUBLIC KEY-----

View File

@ -36,7 +36,6 @@
"server": { "server": {
"level": "DEBUG", "level": "DEBUG",
"handlers": [ "handlers": [
"console",
"info_file_handler", "info_file_handler",
"error_file_handler" "error_file_handler"
] ]
@ -45,6 +44,7 @@
"root": { "root": {
"level": "INFO", "level": "INFO",
"handlers": [ "handlers": [
"console",
"info_file_handler", "info_file_handler",
"error_file_handler" "error_file_handler"
] ]

407
server/main.py Normal file → Executable file
View File

@ -6,25 +6,30 @@ import logging
import logging.config import logging.config
import os import os
import socket import socket
#### logging ####
# json decoder for int keys
import threading import threading
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: try:
# noinspection PyUnresolvedReferences return int(o)
from Crypto.PublicKey import RSA as RSA except ValueError:
# noinspection PyUnresolvedReferences return o
from Crypto.Cipher import PKCS1_OAEP as PKCS1_OAEP elif isinstance(o, dict):
from Crypto.Cipher import AES as AES return {k: self._decode(v) for k, v in o.items()}
# noinspection PyUnresolvedReferences,PyProtectedMember elif isinstance(o, list):
from Crypto.Random._UserFriendlyRNG import get_random_bytes as get_random_bytes return [self._decode(v) for v in o]
else:
pycryptodome = False return o
except ModuleNotFoundError: # Pycryptodomex
from Cryptodome.PublicKey import RSA as RSA
from Cryptodome.Cipher import PKCS1_OAEP as PKCS1_OAEP
from Cryptodome.Cipher import AES as AES
from Cryptodome.Random import get_random_bytes as get_random_bytes
pycryptodome = True
def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'): def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'):
@ -56,392 +61,48 @@ critical = log_server.critical
HOST = '' HOST = ''
PORT = 8888 PORT = 8888
BUFFER_SIZE = 4096 BUFFER_SIZE = 4096
CHUNK_SIZE = int(BUFFER_SIZE / 8)
BEGIN_MESSAGE = bytes("debut".ljust(BUFFER_SIZE, ";"), "ascii")
END_MESSAGE = bytes("fin".ljust(BUFFER_SIZE, ";"), "ascii")
VERSION = b"EICP2P2 V1"
REQUEST_TYPE = [
b'ping', b'pingACK', b'updateAsk', b'updateBack', b'transfer', b'register_client', b'registerACK', b'send', b'sendACK',
b'exit', b'RSASend', b'init', b'getUsers', b'getUsersACK',
]
DONE = 0
ERROR = 1
T_NONE = 0b0000000000
T_NODE = 0b0000000001
T_CLIENT = 0b00000010
#### Socket #### #### Socket ####
main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
main_socket.bind((HOST, PORT)) main_socket.bind((HOST, PORT))
#### Threads #### #### Threads ####
class clientThread(threading.Thread):
class RsaGenThread(threading.Thread):
def __init__(self, difficulty=2):
threading.Thread.__init__(self)
self.difficulty = difficulty
def run(self):
rsa = None
if os.path.isfile("private.pem"):
try:
with open("private.pem", "rb") as keyfile:
rsa = RSA.importKey(keyfile.read())
if not rsa.has_private():
warning("Le fichier clef ne contient pas de clef privée")
raise ValueError
except (IndexError, ValueError):
warning("Fichier clef corrompu")
debug("Suppression du fichier clef corromu")
os.remove("private.pem")
if not os.path.isfile("private.pem"): # We're not using if/else because we may delete the file in the
# previous if statement
rsa = RSA.generate(BUFFER_SIZE + 256 * self.difficulty)
with open("private.pem", "wb") as keyfile:
keyfile.write(rsa.exportKey())
with open("public.pem", "wb") as keyfile:
keyfile.write(rsa.publickey().exportKey())
return rsa
class ServerThread(threading.Thread):
"""Main tread for server"""
def __init__(self, socket, ip, port):
threading.Thread.__init__(self) # initialisation du thread
self.socket = socket
self.ip = ip
self.port = port
t = RsaGenThread()
self.rsa_key = None
if os.path.isfile("private.pem"):
try:
with open("private.pem", "rb") as keyfile:
self.rsa_key = RSA.importKey(keyfile.read())
if not self.rsa_key.has_private():
warning("Le fichier clef ne contient pas de clef privée")
raise ValueError
except (IndexError, ValueError):
warning("Fichier clef corrompu")
debug("Suppression du fichier clef corromu")
os.remove("private.pem")
if not os.path.isfile("private.pem"): # We're not using if/else because we may delete the file in the
# previous if statement
debug("Generate new rsa key")
self.rsa_key = RSA.generate(BUFFER_SIZE + 256 * self.difficulty)
with open("private.pem", "wb") as keyfile:
keyfile.write(self.rsa_key.exportKey())
with open("public.pem", "wb") as keyfile:
keyfile.write(self.rsa_key.publickey().exportKey())
debug("RSA key loaded")
self.clients = {}
self.nodes = {
self.rsa_key.publickey().exportKey(): None,
}
def register_client(self, rsa_client, client_thread):
self.clients.update({rsa_client: (self.rsa_key, client_thread)})
return self.rsa_key.publickey().exportKey(), rsa_client
def send_to(self, id_dest, to_send):
if id_dest not in self.clients.keys():
return b"Erreur client inconnu"
if self.clients[id_dest][0] is None:
return self.clients[id_dest].send_to_me(to_send)
else:
return self.nodes[self.clients[id_dest]].transfer(id_dest, to_send)
class ClientThread(threading.Thread):
"""Main thread, for each client""" """Main thread, for each client"""
def __init__(self, clientsocket, ip_client, port, server): def __init__(self, clientsocket, ip, port):
"""Create ClientThread object """Create clientThread object
:param clientsocket: Client's socket :param clentsocket: Client's socket
:param ip_client: Client's ip address :param ip: Client's ip address
:param port: Client's connection PORT :param port: Client's connection PORT
:param server: Server thread
:type clientsocket: socket.socket :type clientsocket: socket.socket
:type ip_client: str :type ip: str
:type port: int :type port: int
:type server: ServerThread
:return: Nothing :return: Nothing
:rtype: NoneType""" :rtype: NoneType"""
debug("Creation du thread pour %s" % ip_client) debug("Creation du thread pour %s" % ip)
threading.Thread.__init__(self) # initialisation du thread threading.Thread.__init__(self) # initialisation du thread
self.client = clientsocket self.client = clientsocket
self.ip = ip_client self.ip = ip
self.port = port self.port = port
self.running = True debug("Creation du thread pour %s reussie" % ip)
self.status = None
self.rsa_client = None
self.aes_key = get_random_bytes(32)
self.type = T_NONE
self.server = server
debug("Creation du thread pour %s reussie" % ip_client)
def initialize(self):
"""Initialize connection with client
:rtype: NoneType
:return: Nothing"""
# Receive message
message = self.receive()
header = self.extract_header(message)
content = message[BUFFER_SIZE:]
if header.get(b"type", None) is None:
debug("The type field is not in the header")
self.send(b"Error")
return
if header.get(b"from", None) is None:
debug("The from field is not in the header")
self.send(b"error")
return
if self.status is None and header[b"type"] != b"RSASend":
debug("Requête différente de RSASend avec une connection non initialisée")
self.send(b"Error")
return
if header[b"type"] == b"RSASend":
self.type = T_CLIENT if header[b"from"] == b"client" else T_NODE
debug("Réception de la clef RSA de %s", self.ip)
self.rsa_client = content
header = self.gen_header(b"init")
content = self.aes_key
self.send_rsa(header + content)
return
@staticmethod
def extract_header(data):
"""Extract header from data
:param data: Data to extract header
:type data: bytes
:return: Dictionary with header datas
:rtype: dict{bytes: bytes}"""
if len(data) > BUFFER_SIZE:
debug("Header too long")
data = data[:BUFFER_SIZE]
data_lines = data.split(b'\n')
if data_lines[0] != VERSION:
raise ValueError("Version is incorrect.")
return {
l.split(b": ")[0]: l.split(b": ")[1].rstrip(b";") for l in data_lines[1:]
}
@staticmethod
def gen_header(type_, to_=None, from_=None):
"""Generate header
:param type_: Request type
:param to_: `to` field in header, cf ../RFC8497.md
:param from_: `from` field in header, cf ../RFC8497.md
:type type_: bytes
:type to_: bytes
:type from_: bytes
:raise ValueError: `type_` is not a valid request type
:return: header
:rtype: bytes"""
if type_ not in REQUEST_TYPE:
raise ValueError("Unknown request type")
header = VERSION + b"\ntype: " + type_
if to_:
header += b"\nto: " + to_
if from_:
header += b"\nfrom: " + from_,
return header.ljust(BUFFER_SIZE, b';')
################################################ COMMUNICATION WITH AES ############################################
def send_aes(self, to_send, key=None):
"""Send message with aes encryption
:param to_send: Message to send
:type to_send: bytes
:param key: key to replace self.aes_key
:type key: bytes
:rtype: NoneType
:return: Nothing"""
debug(b"Send with AES encryption: " + to_send + bytes(str(self.ip), "ascii"))
if key is None:
key = self.aes_key
if key is None:
info("AES key not generated, connection failure.")
self.client.send(b"Error")
return
# Get RSA key
aes_object = AES.new(key, AES.MODE_ECB)
encrypted = b""
for to_send_text in [to_send[i:i + 32] for i in range(0, len(to_send), 32)]:
encrypted += aes_object.encrypt(to_send_text.ljust(32, b"\x00"))
self.send(encrypted)
return None
def receive_aes(self, key=None):
"""Receive message with aes encryption
:param key: key to replace self.aes_key
:type key: bytes
"""
to_decrypt = self.receive()
if key is None:
key = self.aes_key
if key is None:
info("AES key not generated, connection failure.")
self.client.send(b"Error")
return
aes_object = AES.new(key, AES.MODE_ECB)
decrypted = b""
for block in [to_decrypt[i:i + 32] for i in range(0, len(to_decrypt), 32)]:
decrypted += aes_object.decrypt(block)
return decrypted.rstrip(b"\x00")
################################################ COMMUNICATION WITH RSA ############################################
def send_rsa(self, to_send, key=None):
"""Send message with rsa encryption
:param to_send: Message to send
:type to_send: bytes
:param key: key to replace self.client_key
:type key: bytes
:rtype: NoneType
:return: Nothing"""
debug(b"Send with RSA encryption: " + to_send + bytes(str(self.ip), "ascii"))
if key is None:
key = self.rsa_client
if key is None:
info("RSA key not received, connection failure.")
self.client.send(b"Error")
return
# Get RSA key
recipient_key = RSA.importKey(key)
# RSA encryption object
cipher_rsa = PKCS1_OAEP.new(recipient_key)
encrypted = b""
for to_send_text in [to_send[i:i + CHUNK_SIZE] for i in range(0, len(to_send), CHUNK_SIZE)]:
encrypted += cipher_rsa.encrypt(to_send_text)
self.send(encrypted)
return None
############################################ COMMUNICATION WITHOUT CRYPTING ########################################
def receive(self):
"""Receive message from connection
:rtype: bytes
:return: Message's content"""
chunk = bytes("", "ascii") # Temp variable to store received datas
while chunk != BEGIN_MESSAGE:
chunk = self.client.recv(BUFFER_SIZE)
content = b''
while chunk != END_MESSAGE:
chunk = self.client.recv(BUFFER_SIZE)
# Get only interesting chucks
if chunk != END_MESSAGE:
# Get content part
# int.from_bytes(chunk[:2], byteorder='big') == Get content size
content += chunk[2:int.from_bytes(chunk[:2], byteorder='big') + 2]
debug(b"Received from" + bytes(str(self.ip), 'ascii') + b" : " + content)
return content
def send(self, to_send):
"""Send message to connection
:param to_send: message to send
:type to_send: bytes
:return: Nothing
:rtype: NoneType"""
debug(b"Send " + to_send + b" to " + bytes(str(self.ip), "ascii"))
# Sending the message start
self.client.send(BEGIN_MESSAGE)
i = 0
for to_send_text in [to_send[i:i + BUFFER_SIZE - 2] for i in range(0, len(to_send), BUFFER_SIZE - 2)]:
self.client.send(
(len(to_send_text)).to_bytes(2, byteorder='big') # Size of the message contained by the chunk
+ to_send_text.ljust(BUFFER_SIZE - 2, bytes(1)) # Content of the chunk
)
i += 1
# Sending the message stop
self.client.send(END_MESSAGE)
return None
def send_users(self):
self.send_aes(self.gen_header(type_=b"getUsersACK")+b"%!!%".join(list(self.server.clients.keys())))
def register_client(self):
"""Register client
:rtype: NoneType
:return: Nothing"""
self.server.register_client(self.rsa_client, self)
id_noeud, id_client = self.server.rsa_key.publickey().exportKey(), self.rsa_client
self.send_aes(self.gen_header(type_=b"registerACK") + id_noeud + b"{%=&%&=%}" + id_client)
def send_to_me(self, to_send):
"""Receive message from other poeple
:param to_send: Message to send to client
:type to_send: bytes
:rtype: NoneType
:return: Nothing"""
self.send(self.gen_header(type_=b"send", to_=self.rsa_client) + to_send)
return
def send_to_other(self, id_dest, to_send):
"""Send message to other client
:param id_dest: id of receiver
:param to_send: Message to send
:return: Nothing
:rtype: NoneType"""
server_response = self.server.send_to(id_dest, to_send)
self.send(self.gen_header(type_=b"sendACK"), server_response)
return
def run(self): # main de la connection du client def run(self): # main de la connection du client
"""Run thread mainloop """Run thread mainloop
:return: Nothing :return: Nothing
:rtype: NoneType""" :rtype: NoneType"""
info(self.ip + "connected, initialize connection...") ### ICI ON MET LA BOUCLE PRINCIPALE DE CONNECTION
self.initialize()
info(self.ip + "connection initialized.")
while self.running:
data = self.receive_aes()
header = self.extract_header(data)
print(header)
print(data)
print(self.rsa_client)
if header[b"type"] == b"register_client":
self.register_client()
elif header[b"type"] == b"getUsers":
self.send_users()
elif
self.client.close() self.client.close()
if __name__ == "__main__": if __name__ == "__main__":
clients = [] clients = []
server = ServerThread(main_socket, ip=HOST, port=PORT)
while True: while True:
main_socket.listen(1) # Waiting for incoming connections main_socket.listen(1) # ecoutes des connections entrantes
client_socket, (ip, PORT) = main_socket.accept() clientsocket, (ip, PORT) = main_socket.accept()
newClient = ClientThread(client_socket, ip, PORT, server) newClient = clientThread(clientsocket, ip, PORT)
newClient.start() newClient.start()
clients.append(newClient) clients.append(newClient)

View File

@ -1,57 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1,15 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIICYjANBgkqhkiG9w0BAQEFAAOCAk8AMIICSgKCAkEAlmEl3vGDG4qxqPvO98zC
pDbrFrNeTbwThiqCnuu0Cp5h/ejNeSChnRkmyOffMtvmBCmCJNw0vR9/Cpatzx9T
XekXUWRjXbUfR1ECQ2Fo0xqS3GE58F8HYnhra9+i3xJXSJRpk7P1FaKGakie0GGo
MCcImGZyWuSjNbUa4hj+I+Nlgf3rwQfll/06Wy7YLWXCXnNCTnirVYJooPphy3Qq
tNj+clwCvoY8F7Tz5PDfffiDPjxb+uOWwtfi0LecL5YqZC8aed/70WcujItkGQ2Y
hReYV+jsXvj1DTA0VB/RdrzRYeTNqYSoS7t8+cmWM27syEPb+11JLQZB4kPUB4yY
Ffk/a1ffkmEZYtqRdbndM20Loksr3C/jHRrmqfCjRVmL2wHK64wUUbGLKcSMLHkA
UR1HaeZ+PJ2qXX7ed4MBDRQDaMM7JGrkwz3hyBq2fblUT+OarHnlwRDvLL+XlACr
NJ7yvnigwCkx7MVwakhr0yWc0o9QHEmA2DnibE4JCrNfyAwV+hKs9p+F0XjbbutO
USXFxKdImKzf4NG1eNtMKFeIKZgtzm/JVhvlSC4p6ko+szBd89A11K1oHKRVNC64
rnNH89o2qdT495HRfnFoEHgxA0nQH85QlCajOT0R122ha5ksJxXgj+HzTXiKa4Lt
TXy5kWWkYGMGxK6Xmxn32QPZHCgZA1L99uvZjr1hgkqxrI8p1wBPABN3vdr1CLwq
4kp0g+BOsFAb7X9rWn6xW9wTY8QmFW9Ze+K3Fn7aYg41AgMBAAE=
-----END PUBLIC KEY-----