Compare commits

..

9 Commits

14 changed files with 931 additions and 114 deletions

12
.gitignore vendored
View File

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

11
Pipfile
View File

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

55
Pipfile.lock generated Normal file
View File

@ -0,0 +1,55 @@
{
"_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 ######
EICP2P2 V1
type: register
type: register_client
###### Contenu ######
@ -160,11 +160,11 @@ Cette requête est envoyée par un client pour s'enregistrer sur le réseau. Le
###### Contenu ######
id_noeud::id_client
id_noeud{%=&%&=%}id_client
###### Utilisation ######
Réponse à un `register`. Le noeud communique au client son id et l'id du noeud auquel il est connecté.
Réponse à un `register_client`. Le noeud communique au client son id et l'id du noeud auquel il est connecté.
### Send ###
@ -191,7 +191,7 @@ Cette requête est envoyé par un client enregistré à un noeud pour envoyer un
###### Contenu ######
Rien
Rien/Erreur client incunnu
###### Utilisation ######
@ -217,6 +217,28 @@ 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.
### Get users ###
###### En-tête ######
EICP2P2 V1
type: getUsers
###### Contenu ######
Rien
### Get User ACK ###
###### En-tête ######
EICP2P2 V1
type: getUsersACK
###### Contenu ######
Listedesutilisateurs
### Ping ###
###### En-tête ######
@ -250,14 +272,15 @@ Réponse du client à une requête de ping.
Initialisation des connections
------------------------------
### RSAGet ###
### RSASend ###
> En clair
###### En-tête ######
EICP2P2 V1
type: RSAget
type: RSASend
from: noeud/client
###### Contenu ######
@ -270,13 +293,12 @@ 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 ######
EICP2P2 V1
type: init
from: noeud/client
###### Contenu ######
@ -284,7 +306,13 @@ 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
------

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

@ -6,33 +6,51 @@ import logging
import logging.config
import os
import socket
#### logging ####
# json decoder for int keys
import threading
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
try:
# noinspection PyUnresolvedReferences
from Crypto.PublicKey import RSA as RSA
# noinspection PyUnresolvedReferences
from Crypto.Cipher import PKCS1_OAEP as PKCS1_OAEP
pycryptodome = False
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
pycryptodome = True
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)
class RsaGenThread(threading.Thread):
def _decode(self, o):
if isinstance(o, str):
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:
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
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'):
@ -64,8 +82,20 @@ critical = log_server.critical
HOST = '127.0.0.1'
PORT = 8888
BUFFER_SIZE = 4096
CHUNK_SIZE = int(BUFFER_SIZE/8)
NAME = 'default'
CHUNK_SIZE = int(BUFFER_SIZE / 8)
BEGIN_MESSAGE = bytes("debut".ljust(BUFFER_SIZE, ";"), "ascii")
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
@ -77,41 +107,210 @@ class MainThread(threading.Thread):
threading.Thread.__init__(self)
self.name = name
self.rsa = None
self.aes_key = None
self.clientSocket = None
self.users = {
# id: rsa
}
self.connected_users = {
# id: (rsa, aes, nick)
}
def run(self):
rsa = self.rsaGenThread(self)
rsa = RsaGenThread(self)
rsa.start()
rsa.join()
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect((HOST, PORT))
self.clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.clientSocket.connect((HOST, PORT))
self.initialisation()
self.register()
self.get_users()
print(self.users)
while True:
try:
type = bytes(input("Type: "), "ascii")
contenu = bytes(input("Contenu: "), "ascii")
self.send_aes(self.gen_header(type_=type) + contenu)
print(self.receive_aes())
except Exception as e:
print(e)
class rsaGenThread(threading.Thread):
def register(self):
self.send_aes(self.gen_header(type_=b"register_client"))
self.id_noeud, self.id_client = self.receive_aes()[BUFFER_SIZE:].split(b"{%=&%&=%}")
def __init__(self, client, difficulty=30, new=False):
threading.Thread.__init__(self)
self.client = client
self.difficulty = difficulty
def initialisation(self):
header = self.gen_header(b"RSASend", from_=b"client")
content = self.rsa.publickey().exportKey()
self.send(header + content)
print("oki1")
data = self.receive_rsa()
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
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())
if __name__ == "__main__":

57
client/private.pem Normal file
View File

@ -0,0 +1,57 @@
-----BEGIN RSA PRIVATE KEY-----
MIIKSQIBAAKCAkEAyCjkX4LpaXrvh8oeVq6rdNLNpVBUiJxSX8CJizqB6Z/m8/4Z
R69V0H/MzVjngnczA9Z2ITsIJ3ZLpGxL5TNC4Kv5q3LKsvhuSWMTq97q2bKaeCBr
ROOurG5FxWrTqLHbs5U47kJEDKH6Orn42l6tjvl/74qWTRarpZ4lbNfIkbM45rp1
0OhZNnjCsuxlcWEhGn5bp6IrSsQ0ZIYfwNLwsEDjkn/fCz9NY0ZouT8ua/RnEkW7
s6KOAdoaQi6LSADq9BXK+c4Zdfb5E7ScBzHMjl10AqyNSHZ3DnFL5AEdzC4ZbmXL
SbAKuglFnplKoXRZm6rUb2rWU3NDQ9LVIoUpOfHUD+ip6V9nuQHIS7KVHJ0hgu9s
3lRwN5YwnNz5OqcxWB2eLw8PLaH0WNRTmfbl9EEf2huhUpgXv/DI+7J0dfnSpxaG
O0YAZnjm0x+E/ryXq3vpGb3uErgJ8iuro6MFLE7u9iiAr8HQisGiVVIPgvmns3fq
HJq1tJ1p0GSjHN+Of2QQPx7TSpt/5Ew3Y/pZ/ho8vazIBe036v6NyENywrW+UWYW
dB6m9boEcg6GElSA0kVMw37syuRw7O6FhiOwJZNjAMA67siio1vJfHXrzLhFmlyU
zE07raMFpG4aKw2zwo4PKLSxIiU66i9/ECbJ+3yN7p+XXljCkni7KO9JSI64hETw
7BiY+S/+ZqaipnB3hWxQFsZn36RfeU/BIfGzkQ4+NdYZPgR4h64tcVv9BjZ8abqB
b5id1wFRpKVDeDpDAgMBAAECggJAIFA7CiZUG04YTxI0vVFmka4Z5VHSIS8nZ0OU
kPBpmmH7rYaR5eOVqtrZoTR0mjiMeQFNlzDKBguQIPkbdDhHLYaQqyVAObi8npwK
8sjCnlGPTsxhCkE9k6MbysgOZ+IKx3Opj2Fi+K0fp2JwR9oCvUhkkd3hmja05ZW3
PK/wtoDks0RakoF9gZCTp2yy4Hp0lyvbYnUzoFbg5HJOEa7xjMAfsn4dRS9mMBw6
T4m2gKwiBa5R+VP0BrLYtrgqjn3DcJNMw5u1EDkbs0WJmOm+YyS4KVmvrLP0pYAU
keMSQJfCovLLvleCwSTlDeUjyhaYBCGwjlTaSU+cMN4KauUXfOjLD6RukHlGq/Sb
NYlHjv6Ds06G2LUbXAX4Ts1Sblh2PZ3gjMRXs/MK78Ujv98dk+1sdCJYmqN+vfX0
54jYkwbR11VtIOdOVpQU4A2k2TS4akzVYuYA75lbt/cOX1Tfrspt4ro+YX0K2++o
8Adhe6pZJcZp4KOJ8MlP/1Mb0odVZn5NER7FUcczRzaTTgrb8Q151knxPhcA9Ulh
XFZV0YLp0Zs7+HLqYIWSX7XKCx6NdJy/D+NuzioV2yYq+acNasJkfcr6KcCkUbfK
VeOaT3/a40mFSTGBIDDPDQCXq3lwpSAsoOnyaOR4EzXlaBBD67ODYV39oetgIbf2
mmf2bWPq3I0nO1nXsPpdGvjxXJXK0lE/17mn6mlPD96tLibWrn8y8aQD1h1hAcVA
3VeZXMvKXa8x2fnnpPo1q0OhT5TVAoIBIQDg9ykNfPSWBUOilOvx4JhDKGZJt++V
YezjUAkJzgmkOkpgmmDGk0ec58myqR65W3mU0+fI+CYUWGB7xtIAbOFAaceuRQ9z
v9NN+NffXHbC4k5T6Uc8CgLCpeFAnWRKldPdHIqYJDlNrEYAwqDxcrLpSqYTNWSR
7IwORIbKc8C/YmPii5E6MQLFubopm9uXL0NzptPZO+1vCTy1/VcQPH4g3Puh89L1
CWMzNvQAwhmV/+j7LYjLdruVrbZ45XvHpnkhl+2GJvolpQowh9ELbhu1a9OYsRy7
l0pt8bzuXUsXwYcRiptElA4BgXzOxLoXVBRBEo42zMGYVxGKPAWZWYA5xW6tG2TK
NjzAo1cHQrTl+CuOYYB6/XC9wCzHcm6FgtUCggEhAOPFsmaJXJiy8QOLb9/94O3C
r50rfSD7d1z/A3DBSSdDooAU48685P8kq+bBCgS8zVhhF/czaxTr5UJ3XDLyerJ8
pU2SSRyIzVdvnmco4mHiHzkF8a/ibICLifMY4DcGcfLZEJzv9/9I+gJFKx0438ua
a4aTnNRj7l3WafoYsxwMbBBC4HhFyMkqF3bQ5mjCD8iyzAWUUPhlde0FqBM44lhG
VDPRlMgKaFdT+IwYy5HFQthqANPXj7IHe5tgkNY4PblqhWjz4Sf56QHfkwAUY4pb
UqVLUu+cXPja2XEM7gwYeT00mnK5TToluA4MK8/NxsmTyb9SiwME00dpZN3sClo+
R1h1d80pOn7azP7rIGTuyoMQ+YoMQh+9EcclAHrktwKCASEAzxvciJVkW4UHKnOt
8KWTqChWW0HiaQWZYAB8AbHVAIPFm8AknkxTHqnp7/hw17bWbOTVvBhwfkSKtwlo
pomWqoV4FwFvY2HTuDIDE5h9oZdVAz19nlGdDvRGNwVvopbjUOoI0l5u/wo9/E8y
enbdLZfS41ZBe3Jp0mzWJyZ/6fI8AQH6trcOVVhSgiIB/OK/V4bb/F+GjLXVVbqh
X8pBWCH567Scn4h/8lOCOfx4L7dFF5FpId/yfK9LkWu8FCc312yWeO4DV4rkoZ84
HizFh7V4PVe5Gx8Cn8tw44WyL3G01rpjjbQ8XLiIXZeRtw5qAyqBEQRaqtRlynzN
rstOGGGiLe5NUTizn6oA4idQgXODLfanoRMYqyh0UT4RcArtAoIBIQDcYwm/VOGX
jmzNdTmGjev5ogqyFMY6B5bzEHyPuTXDHBo7u/rAqt0YUq9R0y6Sbuxxu2Co+8N8
ttNZgIxhb2VxFlILwKOlTGkDVSj7v/9rnpN/ZVT5TiiWKG4OHd+03jObOpRshXR8
OmxNjgeter5wDrZDvMheaWLWwQRBzWxgk1RsV4lCVqN0oZmaiX6nlj4Xf4kRTPUb
o3B7KqH6F2xK5aHLkdpXxFo5RTKUu9kc7rVDGS47y7NqGvtq2ADMhhaTNZJofrE5
MQJXobBmv1OhJ8PL1BonZjA/SeJjFJOweG223xMiNlGXFbAFR5mMtBrIKIto58FB
5oVX7459fEp4DxKRcPe+N0o2PBdmALOTdcnVD7Oj80B33UU6X38bafkCggEgZkwG
O/QOZnIIfpB7e9n886J7VmseSZ7rh/mua0YO5jM3t0ELz5Ur+hAHhoFueItOsGSA
7TPCf2abMiUF+v3Y9zeQFz6gSVN8drmLABD7qo236xYNyuoo2ooki9heGBtmWG4q
g4Nd1v8t/0/ilOqRv/wUoZ5zCid+Y6pwTcU6hNX4GUh2hskTucg1EwJ5pv+XHm94
O6XCFTCV9E666fpf+jaeu5CJmDM+vIZyAFnXWt+vPOHtHNnoVoGedDL9ssiK5wQY
IAA/DHQW1i0xZ2aIF13LkWiNmimVu+obg6YqMU03K/YNYmMjPauRmaWqBkgWV6jr
KyQJMcVlp1UrsihOPjlk6iktwe/0dtZPyJYd38ZsCirx5lVIeH+QI4/+m5iA
-----END RSA PRIVATE KEY-----

15
client/public.pem Normal file
View File

@ -0,0 +1,15 @@
-----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-----

51
private.pem Normal file
View File

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

14
receiver.pem Normal file
View File

@ -0,0 +1,14 @@
-----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,6 +36,7 @@
"server": {
"level": "DEBUG",
"handlers": [
"console",
"info_file_handler",
"error_file_handler"
]
@ -44,7 +45,6 @@
"root": {
"level": "INFO",
"handlers": [
"console",
"info_file_handler",
"error_file_handler"
]

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

@ -6,30 +6,25 @@ import logging
import logging.config
import os
import socket
#### logging ####
# json decoder for int keys
import threading
try:
# noinspection PyUnresolvedReferences
from Crypto.PublicKey import RSA as RSA
# noinspection PyUnresolvedReferences
from Crypto.Cipher import PKCS1_OAEP as PKCS1_OAEP
from Crypto.Cipher import AES as AES
# noinspection PyUnresolvedReferences,PyProtectedMember
from Crypto.Random._UserFriendlyRNG import get_random_bytes as get_random_bytes
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)
pycryptodome = False
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
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
pycryptodome = True
def setup_logging(default_path='log_config.json', default_level=logging.INFO, env_key='LOG_CFG'):
@ -61,48 +56,392 @@ critical = log_server.critical
HOST = ''
PORT = 8888
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 ####
main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
main_socket.bind((HOST, PORT))
#### 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"""
def __init__(self, clientsocket, ip, port):
"""Create clientThread object
def __init__(self, clientsocket, ip_client, port, server):
"""Create ClientThread object
:param clentsocket: Client's socket
:param ip: Client's ip address
:param clientsocket: Client's socket
:param ip_client: Client's ip address
:param port: Client's connection PORT
:param server: Server thread
:type clientsocket: socket.socket
:type ip: str
:type ip_client: str
:type port: int
:type server: ServerThread
:return: Nothing
:rtype: NoneType"""
debug("Creation du thread pour %s" % ip)
debug("Creation du thread pour %s" % ip_client)
threading.Thread.__init__(self) # initialisation du thread
self.client = clientsocket
self.ip = ip
self.ip = ip_client
self.port = port
debug("Creation du thread pour %s reussie" % ip)
self.running = True
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
"""Run thread mainloop
:return: Nothing
:rtype: NoneType"""
### ICI ON MET LA BOUCLE PRINCIPALE DE CONNECTION
info(self.ip + "connected, initialize 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()
if __name__ == "__main__":
clients = []
server = ServerThread(main_socket, ip=HOST, port=PORT)
while True:
main_socket.listen(1) # ecoutes des connections entrantes
clientsocket, (ip, PORT) = main_socket.accept()
newClient = clientThread(clientsocket, ip, PORT)
main_socket.listen(1) # Waiting for incoming connections
client_socket, (ip, PORT) = main_socket.accept()
newClient = ClientThread(client_socket, ip, PORT, server)
newClient.start()
clients.append(newClient)

57
server/private.pem Normal file
View File

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

15
server/public.pem Normal file
View File

@ -0,0 +1,15 @@
-----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-----