From c8445c75b9627281a080337a48f1ab7d3c74e0dc Mon Sep 17 00:00:00 2001 From: Faraphel Date: Wed, 3 Jul 2024 00:29:14 +0200 Subject: [PATCH 01/10] WIP: base for the project --- source/Card.py | 2 ++ source/Certificate.py | 6 +++++ source/Machine.py | 62 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 source/Card.py create mode 100644 source/Certificate.py create mode 100644 source/Machine.py diff --git a/source/Card.py b/source/Card.py new file mode 100644 index 0000000..6b981bf --- /dev/null +++ b/source/Card.py @@ -0,0 +1,2 @@ +class Card: + ... diff --git a/source/Certificate.py b/source/Certificate.py new file mode 100644 index 0000000..703fac3 --- /dev/null +++ b/source/Certificate.py @@ -0,0 +1,6 @@ +class Certificate: + """ + A certificate. + Wrapper around cryptography.x509.Certificate. + """ + diff --git a/source/Machine.py b/source/Machine.py new file mode 100644 index 0000000..7f87505 --- /dev/null +++ b/source/Machine.py @@ -0,0 +1,62 @@ +class Machine: + """ + + """ + + def __init__(self): + # First DB: list of people authorized to vote on this machine. + # Public (que name et procuration pas empreinte) ? + self.emerging_list = [ + { + "name": "Bob", + "personne": (pub_key_bob, Enc(empreinte_bob)), + "procuration": "vide", + }, + { + "name": "Alice", + "personne": (pub_key_alice, Enc(empreinte_alice)), + "procuration": (pub_key_Eve, Enc(empreinte_eve)), # Eve peut voter pour Alice. + } + ] + + # Second DB: list of people who voted. + # - public + self.signing_list = [ + ("pub_key_Alice", "pub_key_Eve", "date", signature("message")), + ("pub_key_Bob", "pub_key_Bob", "date", signature("message")), + ] + + # Third DB: votes (shuffle when vote is inserted). + # - private + self._vote_list = ["A", "B", "C"] + + def authenticate(self): + pass + + def vote(self, card: Card) -> bool: + if not authenticate(card): + print("la carte peut pas voter dans cette machine") + return False + + if card_in_siging_list(card): + print("déjà vôté") + return False + + vote = get_vote() + generate_signature(vote, card) + add_vote_to_urn(vote) + print("Vote comptabilisé!") + return True + + def print_signing_list(self) -> None: + ... + + def print_emerging_list(self) -> None: + ... + + def cloture_du_vote(self) -> tuple[list[vote], signature]: + ... + + +machine = Machine() +machine.emerging_list \ No newline at end of file From 74c29a5c935e84af20343c8a68058c73fb1eeb28 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Wed, 3 Jul 2024 23:41:29 +0200 Subject: [PATCH 02/10] rewrote the base for the program --- source/Card.py | 53 ++++++++++++- source/Certificate.py | 50 ++++++++++++ source/Machine.py | 168 +++++++++++++++++++++++++++++++++-------- source/Pki.py | 23 ++++++ source/__main__.py | 44 +++++++++-- source/wtf/Machine2.py | 23 ++++++ source/wtf/__init__.py | 0 tests/exemple1.py | 18 +++++ tests/schema.md | 27 +++++++ 9 files changed, 370 insertions(+), 36 deletions(-) create mode 100644 source/Pki.py create mode 100644 source/wtf/Machine2.py create mode 100644 source/wtf/__init__.py create mode 100644 tests/exemple1.py create mode 100644 tests/schema.md diff --git a/source/Card.py b/source/Card.py index 6b981bf..dd6b828 100644 --- a/source/Card.py +++ b/source/Card.py @@ -1,2 +1,53 @@ +import hashlib +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric import padding + + class Card: - ... + """ + Represent the card of an elector. + """ + + def __init__(self, name: str, pin: int): + self.name = name + + self.private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + self._public_key = self.private_key.public_key() + + digest = hashes.Hash(hashes.SHA256()) + digest.update(pin.to_bytes()) + self.hashed_pin = digest.finalize() + # self.activee = False + + @property + def public_key(self): + return self._public_key + + def check_pin(self, hashed_pin: bytes) -> bool: + """ + Check if the card is valid by comparing hashed PIN. + :param pin_hash: The PIN to check. + :return: True if the received hash PIN matches the stored hashed PIN, False otherwise. + """ + return self.hashed_pin == hashed_pin + + # NOTE(Faraphel): a PKI or a banlist / whitelist shall be checked with self.public_key + + def reply_challenge(self, data: bytes = "encrypted data") -> bytes: + """ + :param data: The challeng sent by the terminal to sign. + :return: The signed challenge. + """ + signature = self.private_key.sign( + data, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() + ) + return signature diff --git a/source/Certificate.py b/source/Certificate.py index 703fac3..2e11446 100644 --- a/source/Certificate.py +++ b/source/Certificate.py @@ -1,6 +1,56 @@ +from datetime import datetime + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import rsa + + class Certificate: """ A certificate. Wrapper around cryptography.x509.Certificate. """ + def __init__( + self, + issuer: str, + issuer_private_key: bytes = None, + subject: str, + valid_start: datetime, + valid_end: datetime + ): + # generate a private key for the certificate + self._private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + # get the public key from it + self.public_key = self._private_key.public_key() + + # if the issuer private key is not specified, consider it a self-signed certificate + if issuer_private_key is None: + issuer_private_key = self._private_key + + # create a builder for the certificate + builder = x509.CertificateBuilder( + issuer_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, issuer)]), + subject_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, subject)]), + serial_number=x509.random_serial_number(), + public_key=self.public_key, + not_valid_before=valid_start, + not_valid_after=valid_end, + ) + + # create the certificate by signing it + self._certificate = builder.sign(issuer_private_key, algorithm=hashes.SHA256()) + + def is_valid(self, date: datetime, issuer_public_key: bytes) -> bool: + return ( + # check if the date is valid + self._certificate.not_valid_before <= date <= self._certificate.not_valid_after and + # check the signature of the certificate + self._certificate.verify_directly_issued_by() + ) + + + +# Exemple d'utilisation +if __name__ == "__main__": + certificate = Certificate("Example Subject") diff --git a/source/Machine.py b/source/Machine.py index 7f87505..5ff0d9f 100644 --- a/source/Machine.py +++ b/source/Machine.py @@ -1,3 +1,13 @@ +import os +from typing import Optional + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import padding + +from .Card import Card + + class Machine: """ @@ -6,48 +16,146 @@ class Machine: def __init__(self): # First DB: list of people authorized to vote on this machine. # Public (que name et procuration pas empreinte) ? - self.emerging_list = [ - { - "name": "Bob", - "personne": (pub_key_bob, Enc(empreinte_bob)), - "procuration": "vide", - }, - { - "name": "Alice", - "personne": (pub_key_alice, Enc(empreinte_alice)), - "procuration": (pub_key_Eve, Enc(empreinte_eve)), # Eve peut voter pour Alice. - } - ] + + # fonction insérer élément + # fonction check + self.emerging_list = {} + #[ + # { + # "name": "Bob", + # "personne": (pub_key_bob, Hash(empreinte_bob)), + # "procuration": None, + # }, + # { + # "name": "Alice", + # "personne": (pub_key_alice, Hash(empreinte_alice)), + # "procuration": (pub_key_Eve, Hash(empreinte_eve)), # Eve peut voter pour Alice. + # } + # { + # "name": "Eve", + # "personne": (pub_key_eve, Hash(empreinte_eve)), + # "procuration": None + # } + # ] # Second DB: list of people who voted. # - public - self.signing_list = [ - ("pub_key_Alice", "pub_key_Eve", "date", signature("message")), - ("pub_key_Bob", "pub_key_Bob", "date", signature("message")), - ] + self.signing_list = {} + # [ + # ("pub_key_Alice", "pub_key_Eve", "date", signature("message")), + # ("pub_key_Bob", "pub_key_Bob", "date", signature("message")), + # ] # Third DB: votes (shuffle when vote is inserted). # - private - self._vote_list = ["A", "B", "C"] + self._vote_list = [] + # ["A", "B", "C"] - def authenticate(self): - pass + # If details during the simulation. + #def send_challenge(self) -> bytes: + # pass + #def check_challenge(self, hash_rand: bytes) -> bool: + # pass - def vote(self, card: Card) -> bool: - if not authenticate(card): - print("la carte peut pas voter dans cette machine") - return False + def search_pubkey(self, pubkey: bytes) -> list[tuple[bytes, bytes]]: + """ + Search pubkey in emerging list. + :param pubkey: Public key to search in the emerging list. + :return: All entries. + """ + + next(filter( + lambda data: data["personne"][0] == and + self.emerging_list + )) - if card_in_siging_list(card): - print("déjà vôté") - return False + def check_fingerprint(self, empreinte: bytes) -> bool: + """ - vote = get_vote() - generate_signature(vote, card) - add_vote_to_urn(vote) - print("Vote comptabilisé!") + :return: + """ return True + + def check_card(self, card: Card, pin: int) -> bool: + """ + Check if the card is valid. + :param card: + :param pin: + :return: + """ + # Public key. + public_key = card.public_key() + + # Challenge to verify public key. + challenge = os.urandom(128) + signature = card.reply_challenge(challenge) + + try: + public_key.verify( + signature, + challenge, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() + ) + except InvalidSignature: + return False + + # Pin + # CHECK(biloute02,faraphel): c’est bon comme ça le digest ? + digest = hashes.Hash(hashes.SHA256()) + digest.update(pin.as_bytes()) + hashed_pin = digest.finalize() + if not card.check_pin(hashed_pin): + return False + + # Is in emerging list? + + return True + + def authenticate(self, card: Card, pin: int, empreinte: bytes) -> bool: + # Check if card is v + if not self.check_card(card, pin): + print("") + return False + + pubkey = card.public_key + # Check pubkey + entries = self.search_pubkey(pubkey) + if not entry: + return False + + # Check fingerprint + if + return True + + def vote(self, card: Card, vote: str) -> bool: + public_key = card.public_key + + # Chercher si public_key in signing_list for person. + personne = self.search_personne(public_key) + if personne is not None: + print("La personne peut voter pour elle-même") + return True + + # Chercher si public_key in signing_list for procuration. + mandataire = self.search_procuration(public_key) + if mandataire is not None: + print("La personne a une procuration") + return True + + print("La personne peut plus voter") + return False + + # vote = get_vote() + # generate_signature(vote, card) + # add_vote_to_urn(vote) + # print("Vote comptabilisé!") + # return True + def print_signing_list(self) -> None: ... diff --git a/source/Pki.py b/source/Pki.py new file mode 100644 index 0000000..4d2b586 --- /dev/null +++ b/source/Pki.py @@ -0,0 +1,23 @@ +class Pki: + """ + Represent a Public Key Infrastructure + """ + + def __init__(self): + pass + +class Certificate: + """ + Represent a Certificate + """ + + def __init__(self): + # create a builder for the certificate + builder = x509.CertificateBuilder( + issuer_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, issuer)]), + subject_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, subject)]), + serial_number=x509.random_serial_number(), + public_key=self.public_key, + not_valid_before=valid_start, + not_valid_after=valid_end, + ) diff --git a/source/__main__.py b/source/__main__.py index 7fa7189..f9663f5 100644 --- a/source/__main__.py +++ b/source/__main__.py @@ -4,23 +4,57 @@ from cryptography import x509 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import rsa + +# ETAT + + # generate a private key for the certificate -private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) +admin_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096) # get the public key from it -public_key = private_key.public_key() +admin_public_key = admin_private_key.public_key() # create a builder for the certificate builder = x509.CertificateBuilder( issuer_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "vote.gouv.fr")]), subject_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "vote.gouv.fr")]), serial_number=x509.random_serial_number(), - public_key=public_key, + public_key=admin_public_key, not_valid_before=datetime.now(), not_valid_after=datetime.now() + timedelta(weeks=1), ) # create the certificate by signing it -certificate = builder.sign(private_key, algorithm=hashes.SHA256()) +admin_certificate = builder.sign(admin_private_key, algorithm=hashes.SHA256()) -print(certificate) +print(admin_certificate) + + +# BUREAU + + +# generate a private key for the certificate +machine_private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) +# get the public key from it +machine_public_key = machine_private_key.public_key() + +# create a builder for the certificate +builder = x509.CertificateBuilder( + issuer_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "vote.gouv.fr")]), + subject_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, "machine.vote.gouv.fr")]), + serial_number=x509.random_serial_number(), + public_key=machine_public_key, + not_valid_before=datetime.now(), + not_valid_after=datetime.now() + timedelta(weeks=1), +) + +# create the certificate by signing it +machine_certificate = builder.sign(admin_private_key, algorithm=hashes.SHA256()) + + +print(machine_certificate) +# check that the machine +machine_certificate.verify_directly_issued_by(admin_certificate) + + +# diff --git a/source/wtf/Machine2.py b/source/wtf/Machine2.py new file mode 100644 index 0000000..fc4c70f --- /dev/null +++ b/source/wtf/Machine2.py @@ -0,0 +1,23 @@ +class Machine2: + def __init__(self, certificat): + self.certificat = certificat + self.liste_electorale = {} + self.bdd_votes = [] + self.bdd_preuves = [] + + def charger_liste_electorale(self, liste_electorale): + self.liste_electorale = liste_electorale + + def authentifier_electeur(self, electeur): + return electeur.authentifier() and electeur.carte_election.cle_publique in self.liste_electorale + + def enregistrer_vote(self, preuve_vote): + self.bdd_votes.append(preuve_vote['vote']) + self.bdd_preuves.append(preuve_vote) + + def publier_resultats(self): + return self.bdd_votes + + def fin_de_vote(self): + # Bloquer les nouveaux votes + self.bloque = True diff --git a/source/wtf/__init__.py b/source/wtf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/exemple1.py b/tests/exemple1.py new file mode 100644 index 0000000..e285edb --- /dev/null +++ b/tests/exemple1.py @@ -0,0 +1,18 @@ +import hashlib +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric import padding + +from source.Card import Card +from source.Certificate import Certificate +from source.Machine import Machine + +Alice_card = Card("Alice", 6060) + +Machine = Machine() + + +Machine.authenticate(Alice_card, 6060, azerty) + + +Machine.vote(Alice_card) \ No newline at end of file diff --git a/tests/schema.md b/tests/schema.md new file mode 100644 index 0000000..ff92dec --- /dev/null +++ b/tests/schema.md @@ -0,0 +1,27 @@ +# Initialisation + +Il à été distribué dans chaque bureau de votes une machine qui servira d'urne + +L'Administrateur à son propre certificat admin +L'administrateur crée un certificat pour chaque machine dans les bureaux de votes + +Tout le monde récupère une carte leur permettant de voter dans leur bureau de vote respectif avec +un code pin et leurs empreinte digitale + +# Voter + +L'électeur ou son représentant se présente au bureau de vote avec la carte + +Il s'authentifie auprès de la machine + +Il choisi son candidat +La machine enregistre son choix et le fait qu'il à voter de manière indépendante. + +# Publication + +A la fin du vote, les votes sont publiés et visible par tous. + +# Difference avec le vote electronique + +On etabli la connexion TLS au debut avant de realiser l'authentification + From 8202d75e48214622e5e94656d8bd070bd8bda44c Mon Sep 17 00:00:00 2001 From: Faraphel Date: Wed, 3 Jul 2024 23:42:05 +0200 Subject: [PATCH 03/10] Changes by AYMAN --- source/wtf/Electeur.py | 16 ++++++++++++ source/wtf/ExempleAutiliser.py | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 source/wtf/Electeur.py create mode 100644 source/wtf/ExempleAutiliser.py diff --git a/source/wtf/Electeur.py b/source/wtf/Electeur.py new file mode 100644 index 0000000..1352c99 --- /dev/null +++ b/source/wtf/Electeur.py @@ -0,0 +1,16 @@ +class Electeur: + def __init__(self, nom, prenom, empreinte_digitale): + self.nom = nom + self.prenom = prenom + self.empreinte_digitale = empreinte_digitale + self.carte_election = None + self.code_pin = None + + def recevoir_carte_election(self, carte_election): + self.carte_election = carte_election + + def definir_code_pin(self, code_pin): + self.code_pin = code_pin + + def authentifier(self): + return self.carte_election.est_authentique(self.empreinte_digitale, self.code_pin) diff --git a/source/wtf/ExempleAutiliser.py b/source/wtf/ExempleAutiliser.py new file mode 100644 index 0000000..8cdc0d2 --- /dev/null +++ b/source/wtf/ExempleAutiliser.py @@ -0,0 +1,48 @@ +from source.Card import Card +from source.wtf.Electeur import Electeur +from source.wtf.Machine2 import Machine2 + +if __name__ == "__main__": + # Création d'un électeur + electeur1 = Electeur("Alice", "Dupont", "empreinte_alice123") + electeur2 = Electeur("Bob", "Martin", "empreinte_bob456") + + # Création de cartes d'élection pour les électeurs + carte1 = Card(electeur1, "cle_publique_alice") + carte2 = Card(electeur2, "cle_publique_bob") + + # Activation des cartes avec un code PIN + carte1.activer("cle_privee_chiffree_alice", "code_pin_chiffre_alice") + carte2.activer("cle_privee_chiffree_bob", "code_pin_chiffre_bob") + + # Attribution des cartes aux électeurs + electeur1.recevoir_carte_election(carte1) + electeur2.recevoir_carte_election(carte2) + + # Définition des codes PIN + electeur1.definir_code_pin("1234") + electeur2.definir_code_pin("5678") + + # Création d'une machine à voter avec un certificat + certificat_machine = "certificat_de_la_machine" + machine = Machine2(certificat_machine) + + # Chargement de la liste électorale dans la machine + liste_electorale = { + "cle_publique_alice": electeur1.nom, + "cle_publique_bob": electeur2.nom + } + machine.charger_liste_electorale(liste_electorale) + + # Authentification et vote d'un électeur + if machine.authentifier_electeur(electeur1): + preuve_vote = { + "vote": "Choix d'Alice", + "preuve": "Preuve de vote d'Alice" + } + machine.enregistrer_vote(preuve_vote) + + # Fin du vote et publication des résultats + machine.fin_de_vote() + resultats = machine.publier_resultats() + print("Résultats publiés:", resultats) From 00bb7493c8ad6aecb409ded2153df529eac8a794 Mon Sep 17 00:00:00 2001 From: biloute02 Date: Thu, 4 Jul 2024 12:35:01 +0200 Subject: [PATCH 04/10] New models Proof and Elector use by emerging_list and proof_list. --- source/models/Elector.py | 27 +++++++++++++++++++++++++++ source/models/Proof.py | 19 +++++++++++++++++++ source/models/__init__.py | 0 3 files changed, 46 insertions(+) create mode 100644 source/models/Elector.py create mode 100644 source/models/Proof.py create mode 100644 source/models/__init__.py diff --git a/source/models/Elector.py b/source/models/Elector.py new file mode 100644 index 0000000..eaa412e --- /dev/null +++ b/source/models/Elector.py @@ -0,0 +1,27 @@ +from dataclasses import dataclass + + +@dataclass +class Elector: + # [ + # { + # "name": "Bob", + # "votant": (pub_key_bob, Hash(empreinte_bob)), + # "mandataire": None, + # }, + # { + # "name": "Alice", + # "votant": (pub_key_alice, Hash(empreinte_alice)), + # "mandataire": (pub_key_Eve, Hash(empreinte_eve)), # Eve peut voter pour Alice. + # } + # ] + + name: str + public_key_elector: bytes + hashed_fingerprint_elector: bytes + public_key_mandataire: bytes = b"" + hashed_fingerprint_mandataire: bytes = b"" + + def set_mandataire(self, public_key: bytes, hashed_fingerprint: bytes): + self.public_key_mandataire = public_key + self.hashed_fingerprint_mandataire = hashed_fingerprint diff --git a/source/models/Proof.py b/source/models/Proof.py new file mode 100644 index 0000000..38699ae --- /dev/null +++ b/source/models/Proof.py @@ -0,0 +1,19 @@ +from dataclasses import dataclass +from datetime import datetime + +import struct + + +@dataclass +class Proof: + + date: datetime + public_key_votant: bytes + public_key_mandataire: bytes + proof_signature: bytes + + def to_bytes(self): + struct.pack(" Date: Thu, 4 Jul 2024 12:36:14 +0200 Subject: [PATCH 05/10] Authentication and vote implemented along with the voting databases. --- source/Card.py | 2 +- source/Machine.py | 278 ++++++++++++++++++++++++++++++---------------- 2 files changed, 186 insertions(+), 94 deletions(-) diff --git a/source/Card.py b/source/Card.py index dd6b828..2687892 100644 --- a/source/Card.py +++ b/source/Card.py @@ -30,7 +30,7 @@ class Card: def check_pin(self, hashed_pin: bytes) -> bool: """ Check if the card is valid by comparing hashed PIN. - :param pin_hash: The PIN to check. + :param hashed_pin: The PIN to check. :return: True if the received hash PIN matches the stored hashed PIN, False otherwise. """ return self.hashed_pin == hashed_pin diff --git a/source/Machine.py b/source/Machine.py index 5ff0d9f..6841eb7 100644 --- a/source/Machine.py +++ b/source/Machine.py @@ -1,81 +1,104 @@ +import datetime import os from typing import Optional from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import padding from .Card import Card +from .models.Elector import Elector +from .models.Proof import Proof class Machine: """ - + Represent a machine used to vote """ - def __init__(self): - # First DB: list of people authorized to vote on this machine. + def __init__(self, emerging_list: list[Proof]): + # First model: list of people authorized to vote on this machine. # Public (que name et procuration pas empreinte) ? - # fonction insérer élément - # fonction check - self.emerging_list = {} - #[ - # { - # "name": "Bob", - # "personne": (pub_key_bob, Hash(empreinte_bob)), - # "procuration": None, - # }, - # { - # "name": "Alice", - # "personne": (pub_key_alice, Hash(empreinte_alice)), - # "procuration": (pub_key_Eve, Hash(empreinte_eve)), # Eve peut voter pour Alice. - # } - # { - # "name": "Eve", - # "personne": (pub_key_eve, Hash(empreinte_eve)), - # "procuration": None - # } - # ] + self.private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + self._public_key = self.private_key.public_key() - # Second DB: list of people who voted. - # - public - self.signing_list = {} - # [ - # ("pub_key_Alice", "pub_key_Eve", "date", signature("message")), - # ("pub_key_Bob", "pub_key_Bob", "date", signature("message")), - # ] + # List of electors who can vote on this machine. + self.emerging_list: list[Elector] = emerging_list - # Third DB: votes (shuffle when vote is inserted). - # - private - self._vote_list = [] + # List of people who voted. + self.proof_list: list[Proof] = [] + + # Private votes (shuffle when a vote is inserted). # ["A", "B", "C"] + # NOTE(Faraphel): rename candidates ? + self._vote_list: list[str] = [] - # If details during the simulation. - #def send_challenge(self) -> bytes: - # pass - #def check_challenge(self, hash_rand: bytes) -> bool: - # pass + self.end_of_election: bool = False - def search_pubkey(self, pubkey: bytes) -> list[tuple[bytes, bytes]]: + def search_elector(self, pubkey: bytes) -> Optional[Elector]: """ - Search pubkey in emerging list. - :param pubkey: Public key to search in the emerging list. - :return: All entries. + Search public key of elector in the emerging list. + :param pubkey: Public key of elector to search in the emerging list. + :return: The first elector who matches or None. """ - - next(filter( - lambda data: data["personne"][0] == and - self.emerging_list - )) + try: + return next(filter( + lambda elector: elector.public_key_elector == pubkey, + self.emerging_list + )) + except StopIteration: + return None - def check_fingerprint(self, empreinte: bytes) -> bool: + def search_proxy_vote(self, pubkey: bytes) -> Optional[Elector]: """ - - :return: + Search the elector with the public key registered as the proxy vote. + :param pubkey: Public key of the mandataire who can proxy vote. + :return: The elector with the proxy vote pubkey registered. """ - return True + try: + return next(filter( + lambda elector: elector.public_key_mandataire == pubkey, + self.emerging_list + )) + except StopIteration: + return None + def search_proof(self, pubkey: bytes) -> Optional[Proof]: + """ + Search pubkey in the signature list + :param pubkey: Public to search in the signature list. + :return: The first elector with pubkey which voted or None. + """ + try: + return next(filter( + lambda proof: proof.public_key_elector == pubkey, + self.proof_list + )) + except StopIteration: + return None + + def check_fingerprint(self, elector: Elector, fingerprint: str) -> bool: + """ + Hash the fingerprint and check if it authenticates the elector. + :param elector: Elector to authenticate. + :param fingerprint: Fingerprint to check. + :return: True if the fingerprint authenticates the mandataire or the voter else False. + """ + # Is the fingerprint matches? + digest = hashes.Hash(hashes.SHA256()) + digest.update(bytes(fingerprint, 'utf-8')) + hashed_fingerprint = digest.finalize() + + if (hashed_fingerprint == elector.hashed_fingerprint_mandataire or + hashed_fingerprint == elector.hashed_fingerprint_elector): + return True + else: + return False def check_card(self, card: Card, pin: int) -> bool: """ @@ -84,7 +107,7 @@ class Machine: :param pin: :return: """ - # Public key. + # Public key transmitted by the card. public_key = card.public_key() # Challenge to verify public key. @@ -102,59 +125,134 @@ class Machine: hashes.SHA256() ) except InvalidSignature: + print("Carte invalide : échec du challenge.") return False - # Pin - # CHECK(biloute02,faraphel): c’est bon comme ça le digest ? + # Pin verification. digest = hashes.Hash(hashes.SHA256()) - digest.update(pin.as_bytes()) + digest.update(pin.to_bytes()) hashed_pin = digest.finalize() if not card.check_pin(hashed_pin): + print("Mot de passe de la carte refusé.") + return False + + # Card has been verified. + return True + + def authenticate(self, card: Card, pin: int, fingerprint: str) -> bool: + """ + Authenticate a person with its card and its fingerprint. + :param card: Elector card. + :param pin: Elector card pin. + :param fingerprint: Elector fingerprint associated with its card public key. + :return: True if the elector is registered in the emerging list, else False. + """ + # Check if election is not ended. + if self.end_of_election: + print("L’élection est terminée") + return False + + # Check if card is valid. + if not self.check_card(card, pin): + print("Carte de l’électeur invalide.") return False # Is in emerging list? + elector = self.search_elector(card.public_key) + if elector is None: + elector = self.search_proxy_vote(card.public_key) + if elector is None: + print("L’électeur n’est pas inscrit dans la liste électorale.") + return False + print("L’électeur peut voter") - return True - - def authenticate(self, card: Card, pin: int, empreinte: bytes) -> bool: - # Check if card is v - if not self.check_card(card, pin): - print("") + # Is the fingerprint matching? + if not self.check_fingerprint(elector, fingerprint): + print("Erreur de reconnaissance de l’empreinte digitale.") return False - pubkey = card.public_key - # Check pubkey - entries = self.search_pubkey(pubkey) - if not entry: - return False - - # Check fingerprint - if + # L’électeur est authentifié. return True def vote(self, card: Card, vote: str) -> bool: - public_key = card.public_key + """ + Vote with the card (user must have been authenticated previously). + :param card: Elector card + :param vote: Elector vote or proxy vote + :return: True if the vote has been inserted else False. + """ + # Check if election is not ended. + if self.end_of_election: + print("L’élection est terminée") + return False - # Chercher si public_key in signing_list for person. - personne = self.search_personne(public_key) - if personne is not None: - print("La personne peut voter pour elle-même") - return True + # Vérification si l’électeur peut voter pour lui. + elector = self.search_elector(card.public_key) + if elector is None: - # Chercher si public_key in signing_list for procuration. - mandataire = self.search_procuration(public_key) - if mandataire is not None: - print("La personne a une procuration") - return True + # Vérification si l’électeur est un mandataire. + elector = self.search_proxy_vote(card.public_key) + if elector is None: + # Ne devrait pas arriver si l’utilisateur est authentifiée. + print("L’électeur n’est pas inscrit dans la liste électorale.") + return False - print("La personne peut plus voter") - return False + else: + # Vérification si le mandataire a déjà voté pour l’électeur. + proof = self.search_proof(elector.public_key) + if proof is not None: + print("L’électeur a déjà voté par procuration pour ...") + return False - # vote = get_vote() - # generate_signature(vote, card) - # add_vote_to_urn(vote) - # print("Vote comptabilisé!") - # return True + else: + # Vérification si l’électeur a déjà voté pour lui. + proof = self.search_proof(elector.public_key) + if proof is not None: + print("L’électeur ... a déjà voté pour lui") + return False + + # Create proof of voting. + date = datetime.datetime.now() + data = bytes(str(date), 'utf-8') + elector.public_key_elector + elector.public_key_mandataire + proof_signature = self.private_key.sign( + data, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() + ) + proof = Proof(date, + elector.public_key_elector, + elector.public_key_mandataire, + proof_signature) + + # Append proof and vote to the databases. + self.proof_list.append(proof) + # TODO(biloute02): shuffle when vote is inserted. + self._vote_list.append(vote) + + print("Vote comptabilisé!") + return True + + def cloture_du_vote(self) -> tuple[list[str], bytes]: + """ + End of the elction, publishes the voting results. + :return: The list of votes and its signature by the voting machine. + """ + self.end_of_election = True + + # TODO(biloute02): Binariser la base de vote pour la signature. + data = ... + vote_list_signature = self.private_key.sign( + data, + padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA256() + ) + return self._vote_list, vote_list_signature def print_signing_list(self) -> None: ... @@ -162,9 +260,3 @@ class Machine: def print_emerging_list(self) -> None: ... - def cloture_du_vote(self) -> tuple[list[vote], signature]: - ... - - -machine = Machine() -machine.emerging_list \ No newline at end of file From 096fc6637e6f949d1381faada522653208df93ed Mon Sep 17 00:00:00 2001 From: biloute02 Date: Thu, 4 Jul 2024 12:37:01 +0200 Subject: [PATCH 06/10] String must be quoted. --- tests/exemple1.ipynb | 37 +++++++++++++++++++++++++++++++++++++ tests/exemple1.py | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/exemple1.ipynb diff --git a/tests/exemple1.ipynb b/tests/exemple1.ipynb new file mode 100644 index 0000000..54f657b --- /dev/null +++ b/tests/exemple1.ipynb @@ -0,0 +1,37 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "initial_id", + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/exemple1.py b/tests/exemple1.py index e285edb..5c37d4e 100644 --- a/tests/exemple1.py +++ b/tests/exemple1.py @@ -12,7 +12,7 @@ Alice_card = Card("Alice", 6060) Machine = Machine() -Machine.authenticate(Alice_card, 6060, azerty) +Machine.authenticate(Alice_card, 6060, "azerty") Machine.vote(Alice_card) \ No newline at end of file From cc243e516334dd4e7a52e97017e446705258631c Mon Sep 17 00:00:00 2001 From: biloute02 Date: Thu, 4 Jul 2024 19:31:20 +0200 Subject: [PATCH 07/10] Function to end election. Convert type of pubkey from bytes to RSAPublicKey. --- source/Card.py | 15 +++---- source/Machine.py | 90 +++++++++++++++++++++++++++------------- source/models/Elector.py | 36 ++++++++++++---- source/models/Proof.py | 21 ++++++---- tests/exemple1.py | 53 ++++++++++++++++++++--- 5 files changed, 157 insertions(+), 58 deletions(-) diff --git a/source/Card.py b/source/Card.py index 2687892..a261724 100644 --- a/source/Card.py +++ b/source/Card.py @@ -1,6 +1,7 @@ import hashlib from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey from cryptography.hazmat.primitives.asymmetric import padding @@ -9,24 +10,20 @@ class Card: Represent the card of an elector. """ - def __init__(self, name: str, pin: int): + def __init__(self, name: str, pin: str): self.name = name - self.private_key = rsa.generate_private_key( + self._private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, ) - self._public_key = self.private_key.public_key() + self.public_key: RSAPublicKey = self._private_key.public_key() digest = hashes.Hash(hashes.SHA256()) - digest.update(pin.to_bytes()) + digest.update(bytes(pin, 'utf-8')) self.hashed_pin = digest.finalize() # self.activee = False - @property - def public_key(self): - return self._public_key - def check_pin(self, hashed_pin: bytes) -> bool: """ Check if the card is valid by comparing hashed PIN. @@ -42,7 +39,7 @@ class Card: :param data: The challeng sent by the terminal to sign. :return: The signed challenge. """ - signature = self.private_key.sign( + signature = self._private_key.sign( data, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), diff --git a/source/Machine.py b/source/Machine.py index 6841eb7..32690e2 100644 --- a/source/Machine.py +++ b/source/Machine.py @@ -1,10 +1,13 @@ import datetime import os +import random from typing import Optional from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey, RSAPrivateKey from cryptography.hazmat.primitives.asymmetric import padding from .Card import Card @@ -17,15 +20,15 @@ class Machine: Represent a machine used to vote """ - def __init__(self, emerging_list: list[Proof]): + def __init__(self, emerging_list: list[Elector]): # First model: list of people authorized to vote on this machine. # Public (que name et procuration pas empreinte) ? - self.private_key = rsa.generate_private_key( + self._private_key: RSAPrivateKey = rsa.generate_private_key( public_exponent=65537, key_size=2048, ) - self._public_key = self.private_key.public_key() + self.public_key: RSAPublicKey = self._private_key.public_key() # List of electors who can vote on this machine. self.emerging_list: list[Elector] = emerging_list @@ -40,7 +43,7 @@ class Machine: self.end_of_election: bool = False - def search_elector(self, pubkey: bytes) -> Optional[Elector]: + def search_elector(self, pubkey: RSAPublicKey) -> Optional[Elector]: """ Search public key of elector in the emerging list. :param pubkey: Public key of elector to search in the emerging list. @@ -54,7 +57,7 @@ class Machine: except StopIteration: return None - def search_proxy_vote(self, pubkey: bytes) -> Optional[Elector]: + def search_proxy_vote(self, pubkey: RSAPublicKey) -> Optional[Elector]: """ Search the elector with the public key registered as the proxy vote. :param pubkey: Public key of the mandataire who can proxy vote. @@ -68,7 +71,7 @@ class Machine: except StopIteration: return None - def search_proof(self, pubkey: bytes) -> Optional[Proof]: + def search_proof(self, pubkey: RSAPublicKey) -> Optional[Proof]: """ Search pubkey in the signature list :param pubkey: Public to search in the signature list. @@ -100,7 +103,7 @@ class Machine: else: return False - def check_card(self, card: Card, pin: int) -> bool: + def check_card(self, card: Card, pin: str) -> bool: """ Check if the card is valid. :param card: @@ -108,7 +111,7 @@ class Machine: :return: """ # Public key transmitted by the card. - public_key = card.public_key() + public_key = card.public_key # Challenge to verify public key. challenge = os.urandom(128) @@ -130,7 +133,7 @@ class Machine: # Pin verification. digest = hashes.Hash(hashes.SHA256()) - digest.update(pin.to_bytes()) + digest.update(bytes(pin, 'utf-8')) hashed_pin = digest.finalize() if not card.check_pin(hashed_pin): print("Mot de passe de la carte refusé.") @@ -139,7 +142,7 @@ class Machine: # Card has been verified. return True - def authenticate(self, card: Card, pin: int, fingerprint: str) -> bool: + def authenticate(self, card: Card, pin: str, fingerprint: str) -> bool: """ Authenticate a person with its card and its fingerprint. :param card: Elector card. @@ -149,7 +152,7 @@ class Machine: """ # Check if election is not ended. if self.end_of_election: - print("L’élection est terminée") + print("L’élection est terminée.") return False # Check if card is valid. @@ -164,14 +167,16 @@ class Machine: if elector is None: print("L’électeur n’est pas inscrit dans la liste électorale.") return False - print("L’électeur peut voter") + print(f"L’électeur {elector.name} vote par procuration.") + print(f"L’électeur {elector.name} peut voter.") # Is the fingerprint matching? if not self.check_fingerprint(elector, fingerprint): - print("Erreur de reconnaissance de l’empreinte digitale.") + print(f"Erreur de reconnaissance de l’empreinte digitale de {elector.name}.") return False # L’électeur est authentifié. + print(f"Électeur {elector.name} authentifié") return True def vote(self, card: Card, vote: str) -> bool: @@ -183,9 +188,11 @@ class Machine: """ # Check if election is not ended. if self.end_of_election: - print("L’élection est terminée") + print("L’élection est terminée.") return False + # Check if elector can vote and has not vot. + # Vérification si l’électeur peut voter pour lui. elector = self.search_elector(card.public_key) if elector is None: @@ -199,23 +206,39 @@ class Machine: else: # Vérification si le mandataire a déjà voté pour l’électeur. - proof = self.search_proof(elector.public_key) + proof = self.search_proof(elector.public_key_elector) if proof is not None: - print("L’électeur a déjà voté par procuration pour ...") + print(f"L’électeur {elector.name} a déjà voté.") return False + # C’est ok + print(f"L’électeur {elector.name} vote par procuration.") + else: # Vérification si l’électeur a déjà voté pour lui. - proof = self.search_proof(elector.public_key) + proof = self.search_proof(elector.public_key_elector) if proof is not None: - print("L’électeur ... a déjà voté pour lui") + print(f"L’électeur {elector.name} a déjà voté.") return False - # Create proof of voting. + # C’est ok + print(f"L’électeur {elector.name} peut voter.") + + # Create proof of voting: date + pubkey elector + pubkey mandataire. date = datetime.datetime.now() - data = bytes(str(date), 'utf-8') + elector.public_key_elector + elector.public_key_mandataire - proof_signature = self.private_key.sign( - data, + pem_votant: bytes = elector.public_key_elector.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.PKCS1, + ) + pem_mandataire: bytes = elector.public_key_mandataire.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.PKCS1, + ) + concatenation: bytes = bytes(str(date), 'utf-8') + pem_votant + pem_mandataire + + # Create proof signature. + proof_signature = self._private_key.sign( + concatenation, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH @@ -226,25 +249,26 @@ class Machine: elector.public_key_elector, elector.public_key_mandataire, proof_signature) + print(f"Preuve de vote de {elector.name} ajoutée.") # Append proof and vote to the databases. self.proof_list.append(proof) - # TODO(biloute02): shuffle when vote is inserted. self._vote_list.append(vote) + random.shuffle(self._vote_list) - print("Vote comptabilisé!") + print(f"Vote de {elector.name} comptabilisé!") return True def cloture_du_vote(self) -> tuple[list[str], bytes]: """ - End of the elction, publishes the voting results. + End of the election, publishes the voting results. :return: The list of votes and its signature by the voting machine. """ + # Election is closed self.end_of_election = True - # TODO(biloute02): Binariser la base de vote pour la signature. - data = ... - vote_list_signature = self.private_key.sign( + data = bytes("".join(self._vote_list), 'utf-8') + vote_list_signature = self._private_key.sign( data, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), @@ -260,3 +284,13 @@ class Machine: def print_emerging_list(self) -> None: ... + # def to_bytes(public_key_votant, public): + # pem_votant: bytes = self.public_key_votant.public_bytes( + # encoding=serialization.Encoding.PEM, + # format=serialization.PublicFormat.PKCS1, + # ) + # pem_mandataire: bytes = self.public_key_mandataire.public_bytes( + # encoding=serialization.Encoding.PEM, + # format=serialization.PublicFormat.PKCS1, + # ) + # return bytes(str(self.date), 'utf-8') + pem_votant + pem_mandataire diff --git a/source/models/Elector.py b/source/models/Elector.py index eaa412e..0fec163 100644 --- a/source/models/Elector.py +++ b/source/models/Elector.py @@ -1,13 +1,14 @@ -from dataclasses import dataclass +from typing import Optional +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey -@dataclass class Elector: # [ # { # "name": "Bob", # "votant": (pub_key_bob, Hash(empreinte_bob)), - # "mandataire": None, + # "mandataire": (b"", b"") # }, # { # "name": "Alice", @@ -16,11 +17,30 @@ class Elector: # } # ] - name: str - public_key_elector: bytes - hashed_fingerprint_elector: bytes - public_key_mandataire: bytes = b"" - hashed_fingerprint_mandataire: bytes = b"" + def __init__(self, + name: str, + public_key_elector: RSAPublicKey, + fingerprint_elector: str, + public_key_mandataire: Optional[RSAPublicKey] = None, + fingerprint_mandataire: Optional[str] = None): + self.name = name + self.public_key_elector = public_key_elector + + if public_key_mandataire is None: + self.public_key_mandataire = public_key_elector + else: + self.public_key_mandataire = public_key_mandataire + + digest = hashes.Hash(hashes.SHA256()) + digest.update(bytes(fingerprint_elector, 'utf-8')) + self.hashed_fingerprint_elector: bytes = digest.finalize() + + if fingerprint_mandataire is None: + self.hashed_fingerprint_mandataire = self.hashed_fingerprint_elector + else: + digest = hashes.Hash(hashes.SHA256()) + digest.update(bytes(fingerprint_mandataire, 'utf-8')) + self.hashed_fingerprint_mandataire: bytes = digest.finalize() def set_mandataire(self, public_key: bytes, hashed_fingerprint: bytes): self.public_key_mandataire = public_key diff --git a/source/models/Proof.py b/source/models/Proof.py index 38699ae..16a4772 100644 --- a/source/models/Proof.py +++ b/source/models/Proof.py @@ -1,19 +1,24 @@ from dataclasses import dataclass from datetime import datetime +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey -import struct @dataclass class Proof: date: datetime - public_key_votant: bytes - public_key_mandataire: bytes + public_key_votant: RSAPublicKey + public_key_mandataire: RSAPublicKey proof_signature: bytes - def to_bytes(self): - struct.pack(" Date: Thu, 4 Jul 2024 19:31:36 +0200 Subject: [PATCH 08/10] Server client --- mains/__init__.py | 0 mains/client.py | 21 +++++++++++++++++++++ mains/server.py | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 mains/__init__.py create mode 100644 mains/client.py create mode 100644 mains/server.py diff --git a/mains/__init__.py b/mains/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mains/client.py b/mains/client.py new file mode 100644 index 0000000..8074602 --- /dev/null +++ b/mains/client.py @@ -0,0 +1,21 @@ +import argparse + + +arg_parser = argparse.ArgumentParser() + +arg_parser.add_argument("-H", "--host", dest="hostname", type=str, default="127.0.0.1") +arg_parser.add_argument("-p", "--port", dest="port", type=int, default=57823) + +arguments = arg_parser.parse_args() + + +if arguments: + import ssl + import socket + + context = ssl.create_default_context() + + with socket.create_connection((arguments.hostname, 443)) as sock_client: + with context.wrap_socket(sock_client, server_hostname=arguments.hostname) as ssl_sock_client: + print(ssl_sock_client.version()) + ssl_sock_client.send(b"Hello World!") diff --git a/mains/server.py b/mains/server.py new file mode 100644 index 0000000..2c5977d --- /dev/null +++ b/mains/server.py @@ -0,0 +1,24 @@ +import argparse + + +arg_parser = argparse.ArgumentParser() + +arg_parser.add_argument("-H", "--host", dest="hostname", type=str, default="0.0.0.0") +arg_parser.add_argument("-p", "--port", dest="port", type=int, default=57823) + +arguments = arg_parser.parse_args() + + +if arguments: + import ssl + import socket + + context = ssl.create_default_context() + + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock_server: + sock_server.bind((arguments.hostname, arguments.port)) + sock_server.listen(5) + + with context.wrap_socket(sock_server, server_side=True) as ssl_sock_server: + data = ssl_sock_server.recv() + print(data) From 8ebb40c0f6e8ef3369df8cc61e57e309f392d7f8 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 5 Jul 2024 00:23:26 +0200 Subject: [PATCH 09/10] wrote example for our algorithm and tried to add a cli --- assets/admin/certificate.pem | 20 ++++ assets/admin/private.key | 27 +++++ assets/machine/Beauvais/certificate.pem | 20 ++++ assets/machine/Beauvais/private.key | 27 +++++ mains/__main__.py | 31 ++++++ mains/client.py | 21 ---- mains/role/__init__.py | 3 + mains/role/admin/__init__.py | 2 + mains/role/admin/action/__init__.py | 2 + mains/role/admin/action/create/__init__.py | 2 + mains/role/admin/action/create/argparse.py | 11 ++ .../action/create/create_role/__init__.py | 2 + .../create/create_role/client/__init__.py | 2 + .../create/create_role/client/argparse.py | 8 ++ .../action/create/create_role/client/run.py | 38 +++++++ .../create/create_role/machine/__init__.py | 2 + .../create/create_role/machine/argparse.py | 7 ++ .../action/create/create_role/machine/run.py | 67 ++++++++++++ mains/role/admin/action/create/run.py | 15 +++ mains/role/admin/action/init/__init__.py | 2 + mains/role/admin/action/init/argparse.py | 5 + mains/role/admin/action/init/run.py | 53 +++++++++ mains/role/admin/argparse.py | 11 ++ mains/role/admin/run.py | 15 +++ mains/role/client/__init__.py | 2 + mains/role/client/action/__init__.py | 2 + mains/role/client/action/argparse.py | 9 ++ mains/role/client/action/vote.py | 23 ++++ mains/role/client/argparse.py | 15 +++ mains/role/client/run.py | 13 +++ mains/role/machine/__init__.py | 2 + mains/role/machine/argparse.py | 11 ++ mains/role/machine/run.py | 23 ++++ mains/server.py | 24 ----- requirements.txt | 2 +- source/Card.py | 4 +- source/Machine.py | 9 +- source/__main__.py | 3 - source/models/Proof.py | 2 +- source/wtf/Electeur.py | 16 --- source/wtf/ExempleAutiliser.py | 48 --------- source/wtf/Machine2.py | 23 ---- source/wtf/__init__.py | 0 tests/exemple1.ipynb | 37 ------- tests/exemple1.py | 101 +++++++++++------- tests/exemple2.py | 2 + 46 files changed, 543 insertions(+), 221 deletions(-) create mode 100644 assets/admin/certificate.pem create mode 100644 assets/admin/private.key create mode 100644 assets/machine/Beauvais/certificate.pem create mode 100644 assets/machine/Beauvais/private.key create mode 100644 mains/__main__.py delete mode 100644 mains/client.py create mode 100644 mains/role/__init__.py create mode 100644 mains/role/admin/__init__.py create mode 100644 mains/role/admin/action/__init__.py create mode 100644 mains/role/admin/action/create/__init__.py create mode 100644 mains/role/admin/action/create/argparse.py create mode 100644 mains/role/admin/action/create/create_role/__init__.py create mode 100644 mains/role/admin/action/create/create_role/client/__init__.py create mode 100644 mains/role/admin/action/create/create_role/client/argparse.py create mode 100644 mains/role/admin/action/create/create_role/client/run.py create mode 100644 mains/role/admin/action/create/create_role/machine/__init__.py create mode 100644 mains/role/admin/action/create/create_role/machine/argparse.py create mode 100644 mains/role/admin/action/create/create_role/machine/run.py create mode 100644 mains/role/admin/action/create/run.py create mode 100644 mains/role/admin/action/init/__init__.py create mode 100644 mains/role/admin/action/init/argparse.py create mode 100644 mains/role/admin/action/init/run.py create mode 100644 mains/role/admin/argparse.py create mode 100644 mains/role/admin/run.py create mode 100644 mains/role/client/__init__.py create mode 100644 mains/role/client/action/__init__.py create mode 100644 mains/role/client/action/argparse.py create mode 100644 mains/role/client/action/vote.py create mode 100644 mains/role/client/argparse.py create mode 100644 mains/role/client/run.py create mode 100644 mains/role/machine/__init__.py create mode 100644 mains/role/machine/argparse.py create mode 100644 mains/role/machine/run.py delete mode 100644 mains/server.py delete mode 100644 source/wtf/Electeur.py delete mode 100644 source/wtf/ExempleAutiliser.py delete mode 100644 source/wtf/Machine2.py delete mode 100644 source/wtf/__init__.py delete mode 100644 tests/exemple1.ipynb create mode 100644 tests/exemple2.py diff --git a/assets/admin/certificate.pem b/assets/admin/certificate.pem new file mode 100644 index 0000000..3fdf400 --- /dev/null +++ b/assets/admin/certificate.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIUFiOqi4pgJB9drME4SMSjaF+PoyMwDQYJKoZIhvcNAQEL +BQAwXzELMAkGA1UEBhMCRlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhM +b2NhbGl0eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4u +Y29tMB4XDTI0MDcwNDAwMDI1MVoXDTI1MDcwNTAwMDI1MVowXzELMAkGA1UEBhMC +RlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhMb2NhbGl0eTEVMBMGA1UE +CgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4uY29tMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEApvut4HKl4ZyECZFgL8DGnsr8UJmT7MYwReWJ +Q6nuAucUD8lkWWikYwoSiz57ptpYXLMRLWzOot0h3GBWHB6zcMgFOfTXjrd8heN5 +pknbNQYywVUFJsdN3GXJ1IjSDFNSlsBmDh1mvVmVqWNeGv2rpJSxC6hV0iLMRXYK +J9dLM4IIH2zLUdSkpmzxzOejTH1SYAiqyk91eJvikA0SjlwUC8gRe71HSVIuNqyQ +wVCv/00wjIg6A8Q2fOhFlfvp4IoKCtTviKuDnXIK7Tn02dICHcDeNWis7G8NNosU +nRTbG9UH62eJ0g5IW3e/3ZA4peX20rGwPf599VlFLzGxnW35CwIDAQABMA0GCSqG +SIb3DQEBCwUAA4IBAQCmH/UHxIcVDjNFQDAQuWe6+UEfOq97qgd4D3j/igAmbfvx +6puPKuCFZKWCeNMb3B9+rFRDHq4NJgbPL22iGUPdZwBjdjt8HZhrheQ+/TEy4Zcf +I6NvuTVAjJmijfHTDQ14koWIrvznlKBNTX1cPtUQnyCrhKpzUUXp9kpuwVlRt5JQ +WpYCJw5XycJiW52vXyZsCd2S1xecD0Pwq5u6+25jM/yblx3s2C2ezcNhIzBufG2i +xz8TSykG+NjhzHfvg8M5eln05kTaf9wHvwkyuH9+WHQUZFeauUzOFX/E6SEJ74s9 +vYssU5Rue2tBOZhuSkqRgE2FsVGJ0ccZQWVfZ6X3 +-----END CERTIFICATE----- diff --git a/assets/admin/private.key b/assets/admin/private.key new file mode 100644 index 0000000..7a9d89c --- /dev/null +++ b/assets/admin/private.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEApvut4HKl4ZyECZFgL8DGnsr8UJmT7MYwReWJQ6nuAucUD8lk +WWikYwoSiz57ptpYXLMRLWzOot0h3GBWHB6zcMgFOfTXjrd8heN5pknbNQYywVUF +JsdN3GXJ1IjSDFNSlsBmDh1mvVmVqWNeGv2rpJSxC6hV0iLMRXYKJ9dLM4IIH2zL +UdSkpmzxzOejTH1SYAiqyk91eJvikA0SjlwUC8gRe71HSVIuNqyQwVCv/00wjIg6 +A8Q2fOhFlfvp4IoKCtTviKuDnXIK7Tn02dICHcDeNWis7G8NNosUnRTbG9UH62eJ +0g5IW3e/3ZA4peX20rGwPf599VlFLzGxnW35CwIDAQABAoIBAEuzh9VcRIWunlF0 +HaYogCMXJSIpLd3Gz7WwZPVPAX9BYV/yzlKWVQgtVdDYp9gx3qNP7vaoAFnnZGVz +KzaeWH1FwNDQhjTGTGaqhMj1bLJyN+pb7/TvoAXOA50d1hQOZj+/w8ScYapwBaCA +UvZrkDgRzN3bF+UnL3JCHEKJoScdDCGZGlvM/c7hQZYyZ94MuUT9+njkymGXm/H2 +Xkyf1AWnXMeQRs1vBLwtNxshQzfpoEAuYQ01mNjaHNyyW8/VYXzY+cUUDjuQMoxR +0VT/3N7IJFrdQdw2d5nfae59iX+mJM3dZ5hsSNimN9p4Q+5jG6uDOJP6QC/TKkDm +gYLFf/ECgYEA63q9cJuQ4CYbCRllyR/JhjeczT87D9wCE4/TxPLHIRbYXUTwvVbd +tII4lHR4mnsJUVK+cDhXzPWtgLhFZ3oY7tjv89Nj8SMAZA+gh7XLS8mYuvG8OjgJ +TZoJbSOGR5RJDV5BLxaR2czC+si/IsDn2rEjuAeBzu7cdBd6yq7EUjMCgYEAtYje +kn62UQjqCPcprA5Zumki8zBJfQlHXOPJh58hczla+T+wyFCMA4e3rE2ZYUUeCUZu +fM+qbqAP7CQW2lY7msidtlH+uhutgjCmJ9mHFpFS9bN7iRX7t6oGfnQJ13nvoaF0 +7D8ebxVnn5paCeu4vUBQ2mYKxjhJdnTx/3yH1ckCgYBG0OG5xL77+dm1kdK/enTD +jWP1gaeEbHifY2ifWRezhshIvFvdxQrlpyfW1XQTmR7DOywUWY1mERg9lq0gomJv +KgR3gkITGaCbduujBHP/9b+dsOcXZxS9Jq7hCIbwbdLOV2MpAxOXuXGFs+tvSy4u +4YjJZlCOZ90aeJkv7QETawKBgEmzQqF5Hi2yD8oKBnoa7WTX8F+JGBzSWo2k0Rnl +iiAMhhmxOOVqhh2cyP4EFyQ9el9Ln+m+KbR1+WDmmfyUi+hgUF9H1MHcIMo9VAfT +sZuA7oxgDORv71z2g2JtW92GXLpjIWQUkBeLOiG6+ZkTgVIcPXcdfHxTN8gG3ITc +Gw25AoGAcdR8DNJO/Oo7BlZKV/g5nUSzbdgIrT2gtT6ZUBaQZw3mLjiMHFfihtPn +hXfmXZ+ymaXxm6IRGcz9c28V0a9M+q29P1hWfQQVCk7yEdMHxlE4FBVg7ejIhw07 +8dgM9v8tg6Nf3b0KGWrgnD87ds3uR6D536Bhh3jmhq27U8k45OY= +-----END RSA PRIVATE KEY----- diff --git a/assets/machine/Beauvais/certificate.pem b/assets/machine/Beauvais/certificate.pem new file mode 100644 index 0000000..cbbf9de --- /dev/null +++ b/assets/machine/Beauvais/certificate.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIUaZDZAVUe0kK/3m6RxCg44Rv8ToswDQYJKoZIhvcNAQEL +BQAwXzELMAkGA1UEBhMCRlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhM +b2NhbGl0eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4u +Y29tMB4XDTI0MDcwNDAwMDI1NVoXDTI1MDcwNTAwMDI1NVowXzELMAkGA1UEBhMC +RlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhMb2NhbGl0eTEVMBMGA1UE +CgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4uY29tMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0xfSOKdy/FKvLsNatkdg22vbwgKHjHeS0kXu +k+MVHvbp+r2uwwhbYilhLWBk6OM94ftVJh0441bkCnoPACMd1goqxvUkP4m+4uaX ++lVup5JHAre5YXher3rX5K1Jyd7Rns7V0q01y6J7LnjRSMY2hZIgrQEoVc+HXVqS +idPaOl30W4U12UQv405y+yAHCjqWZEp9ZNO7cg6zMQCGyTs+u9/4wyqXIrXly0Br +R/MV1VyCvBSpT0913WksRXb2xJvPSwsiRGzgKJ0/LtiFC3hfNZWkfi4FVRazYO69 +OPiXw+MbmodI9ie2TNvmk7TuxFPntrm9P0YqsOacymOYXS05uwIDAQABMA0GCSqG +SIb3DQEBCwUAA4IBAQBaNv/xmhRBmBfJQXnA8N03xg9vYlC0VyHQzhYRQ3kE9wb7 +j4/lzbDgqRb5ok2zIrPPewcwZ4yM5tIyi78I0dYPtlCSLEyEqQJ2kNfYHWnKvC5D +ipDeJrymCz0VGNAAqH9Ib18HoxrLM2+tQtavs6p0Iu9V14H3D/ouJhdfQV04PvgC +8QFFCmrvqw8WSAzhoXaD9pAxCQc4fJIDrMUN45nOjIUjSdi4vGClIryJ2Fmz7LP+ +a/ZqciybqgybLz5pGp9gPFL7FKhw/sgypP7HqvUEyw+mejLNxcDXbmk+01Wjspfj +VAi/u0nCupYv5UfBVyPG6vBZ4qcOcX89qkHv4xl9 +-----END CERTIFICATE----- diff --git a/assets/machine/Beauvais/private.key b/assets/machine/Beauvais/private.key new file mode 100644 index 0000000..3f4bc26 --- /dev/null +++ b/assets/machine/Beauvais/private.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA0xfSOKdy/FKvLsNatkdg22vbwgKHjHeS0kXuk+MVHvbp+r2u +wwhbYilhLWBk6OM94ftVJh0441bkCnoPACMd1goqxvUkP4m+4uaX+lVup5JHAre5 +YXher3rX5K1Jyd7Rns7V0q01y6J7LnjRSMY2hZIgrQEoVc+HXVqSidPaOl30W4U1 +2UQv405y+yAHCjqWZEp9ZNO7cg6zMQCGyTs+u9/4wyqXIrXly0BrR/MV1VyCvBSp +T0913WksRXb2xJvPSwsiRGzgKJ0/LtiFC3hfNZWkfi4FVRazYO69OPiXw+MbmodI +9ie2TNvmk7TuxFPntrm9P0YqsOacymOYXS05uwIDAQABAoIBABjvZ+w8T3dh1wK5 +ndYJUXYp5AAjZ1qe50+CZj++48hQF2yAiovMSWsrgyimidT+vtkaZMEHU6h7I53f +NDVqcIRPmCT/YSRGQ6+u2IYAIH2X6F54UGQkoV6uLqF7HMvFT9KoERb9Uez3iQCA +0gv8KgWWMNju2ZJlXNKYt9WjGlSpfIVbAxdGlFNWGKwWvAypfXMfdJY5P5U+Lk1Q +CqNZ/U1B5uaqbVbd9RfQJYtZny3h2OQGf4nSDXE2Gq63fOIbPdISjhaYCnHWBoBD +HzaO14tbz7hGeHLmNLB8p5SeoY1ZOA10YTdF1jtH+4gloKEwf1vcxUEXf3novn1X +f8NB620CgYEA9y+3wAx91c2sK57HVJEuicp9xmtXNjKVeoPnuk50DGjL4D/V3C1r +eM7hGfbD/98euSMkNs0F7zIkqXiBC45U4wOIaQHgVZbJM5Mhdvh4S7pZstETUA7k +XrN+c71ktms8fg7EjiBRfzi3wULWk5bmjKsc+sTlPACCFUt4zYe6zS0CgYEA2p6m +AtxYLkWA0Ci6xho4xU0iKCmGHeR+R4YuLd60/L7PHAySMCBzrha8jx9PpAppi27M +DaOu9H9VpNnApGBJVuHDTRq672ZPpPQ8Rbj8ZvCQ6TlsoMJuEO4kcTBfccYVCNS+ +wYbRWpteK7GfL6YXC5HdxL9vFV2hpK0IFmuBg4cCgYEAyOddv5fnhqidsO5iMFe3 +rYKI64Y+4ewHFgazhvdQ1u0uF1uK5GN+IDh1OHcaIpMkE3F+c5P7qMfmiF9K8yuB +zukGK+K8hJQDgAmrf1i/3TzevrmzqrQP5PCabFOY0bMi/YnfM20NEAv3PfqnEFnr +lJVW/nKdpkD7eXdX/iS9LRkCgYEAhzv0PXjII3djA2DuiHTYAVSBeI6XJA6f/uaF +0mIdWus9eoBcPeEVLe9qnK4lubenKlVTbGyAYUYTWHJKtGPLei8VfLC4SjbjtYpP +bmHL4HGXcm3PQHKFW3u0lz/xCpQZlujjRxt6ja3mRukNK5B2WPXWVUqGEJVm1FMk +2ZmO+CkCgYA6X1eHTPfY9Wy7uQEyamA6H/nUGFyKM85tGYU0D7xdU9ls0VFTuME4 +0FAq8k1k9BbSAhrpsyYp/eIAHJ3gF88w/NyP/1HO1RTzpLcXiI/fzGb59i4hY6Gg +g7AyGGe62nfVhAD/WaMp+0iidXtd/ZwR09PaECUuU+UJ91BojlbwzA== +-----END RSA PRIVATE KEY----- diff --git a/mains/__main__.py b/mains/__main__.py new file mode 100644 index 0000000..fd1afd0 --- /dev/null +++ b/mains/__main__.py @@ -0,0 +1,31 @@ +import argparse + +from mains import role + +parser = argparse.ArgumentParser() +subparsers = parser.add_subparsers(dest="role") + +role.admin.load_parse(subparsers) +role.client.load_parse(subparsers) +role.machine.load_parse(subparsers) + + +arguments = parser.parse_args() + + +if not arguments: + parser.print_help() + exit(1) + + +match arguments.role: + case "admin": + role.admin.run(parser, arguments) + case "machine": + role.machine.run(parser, arguments) + case "client": + role.client.run(parser, arguments) + + # if the role is unknown, show the usage + case _: + parser.print_usage() diff --git a/mains/client.py b/mains/client.py deleted file mode 100644 index 8074602..0000000 --- a/mains/client.py +++ /dev/null @@ -1,21 +0,0 @@ -import argparse - - -arg_parser = argparse.ArgumentParser() - -arg_parser.add_argument("-H", "--host", dest="hostname", type=str, default="127.0.0.1") -arg_parser.add_argument("-p", "--port", dest="port", type=int, default=57823) - -arguments = arg_parser.parse_args() - - -if arguments: - import ssl - import socket - - context = ssl.create_default_context() - - with socket.create_connection((arguments.hostname, 443)) as sock_client: - with context.wrap_socket(sock_client, server_hostname=arguments.hostname) as ssl_sock_client: - print(ssl_sock_client.version()) - ssl_sock_client.send(b"Hello World!") diff --git a/mains/role/__init__.py b/mains/role/__init__.py new file mode 100644 index 0000000..f9891e8 --- /dev/null +++ b/mains/role/__init__.py @@ -0,0 +1,3 @@ +from . import admin +from . import client +from . import machine diff --git a/mains/role/admin/__init__.py b/mains/role/admin/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/admin/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/admin/action/__init__.py b/mains/role/admin/action/__init__.py new file mode 100644 index 0000000..3726bb0 --- /dev/null +++ b/mains/role/admin/action/__init__.py @@ -0,0 +1,2 @@ +from . import create +from . import init diff --git a/mains/role/admin/action/create/__init__.py b/mains/role/admin/action/create/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/admin/action/create/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/admin/action/create/argparse.py b/mains/role/admin/action/create/argparse.py new file mode 100644 index 0000000..ce16f6c --- /dev/null +++ b/mains/role/admin/action/create/argparse.py @@ -0,0 +1,11 @@ +import argparse + +from . import create_role + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("create") + + subsubparsers = subparser.add_subparsers(dest="create_role") + create_role.client.load_parse(subsubparsers) + create_role.machine.load_parse(subsubparsers) diff --git a/mains/role/admin/action/create/create_role/__init__.py b/mains/role/admin/action/create/create_role/__init__.py new file mode 100644 index 0000000..9bfc5e8 --- /dev/null +++ b/mains/role/admin/action/create/create_role/__init__.py @@ -0,0 +1,2 @@ +from . import machine +from . import client diff --git a/mains/role/admin/action/create/create_role/client/__init__.py b/mains/role/admin/action/create/create_role/client/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/admin/action/create/create_role/client/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/admin/action/create/create_role/client/argparse.py b/mains/role/admin/action/create/create_role/client/argparse.py new file mode 100644 index 0000000..168f567 --- /dev/null +++ b/mains/role/admin/action/create/create_role/client/argparse.py @@ -0,0 +1,8 @@ +import argparse + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("client") + + subparser.add_argument("-u", "--username", dest="username", type=str, required=True) + subparser.add_argument("-p", "--password", dest="password", type=str, required=True) diff --git a/mains/role/admin/action/create/create_role/client/run.py b/mains/role/admin/action/create/create_role/client/run.py new file mode 100644 index 0000000..2240bbf --- /dev/null +++ b/mains/role/admin/action/create/create_role/client/run.py @@ -0,0 +1,38 @@ +import argparse +from pathlib import Path + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + # TODO(Faraphel): should NOT be named "client" + print("creating new client...") + + directory_client = Path(f"./assets/client/{arguments.username}/") + if directory_client.exists(): + raise ValueError("This client already exists !") + + directory_client.mkdir(parents=True) + + # Generate a private key + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + backend=default_backend(), + ) + + (directory_client / "private.key").write_bytes( + private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.OpenSSH, + encryption_algorithm=serialization.BestAvailableEncryption(arguments.password.encode()), + ) + ) + (directory_client / "public.key").write_bytes( + private_key.public_key().public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.OpenSSH, + ) + ) diff --git a/mains/role/admin/action/create/create_role/machine/__init__.py b/mains/role/admin/action/create/create_role/machine/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/admin/action/create/create_role/machine/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/admin/action/create/create_role/machine/argparse.py b/mains/role/admin/action/create/create_role/machine/argparse.py new file mode 100644 index 0000000..12dc002 --- /dev/null +++ b/mains/role/admin/action/create/create_role/machine/argparse.py @@ -0,0 +1,7 @@ +import argparse + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("machine") + + subparser.add_argument("-n", "--name", dest="name", type=str, required=True) diff --git a/mains/role/admin/action/create/create_role/machine/run.py b/mains/role/admin/action/create/create_role/machine/run.py new file mode 100644 index 0000000..01bc329 --- /dev/null +++ b/mains/role/admin/action/create/create_role/machine/run.py @@ -0,0 +1,67 @@ +import argparse +from datetime import datetime, timedelta +from pathlib import Path + +from cryptography import x509 +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.hazmat.primitives.asymmetric import rsa + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + print("creating a new machine...") + + directory_admin = Path("./assets/admin/") + if not directory_admin.exists(): + raise ValueError("Can't find the admin. Have you initialized it ?") + + directory_machine = Path(f"./assets/machine/{arguments.name}/") + if directory_machine.exists(): + raise ValueError("This machine already exists !") + + directory_machine.mkdir(parents=True) + + # Generate a private key + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + + (directory_machine / "private.key").write_bytes( + private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + ) + + certificate_admin = x509.load_pem_x509_certificate( + (directory_admin / "certificate.pem").read_bytes() + ) + private_key_admin = serialization.load_pem_private_key( + (directory_admin / "private.key").read_bytes(), + password=None + ) + + # Generate a self-signed root certificate + subject = x509.Name([ + x509.NameAttribute(x509.NameOID.COUNTRY_NAME, "FR"), + x509.NameAttribute(x509.NameOID.STATE_OR_PROVINCE_NAME, "Province"), + x509.NameAttribute(x509.NameOID.LOCALITY_NAME, "Locality"), + x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, "Organization"), + x509.NameAttribute(x509.NameOID.COMMON_NAME, "domain.com"), + ]) + certificate = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(certificate_admin.subject) + .public_key(private_key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(datetime.now() - timedelta(days=1)) # TODO(Faraphel): settings + .not_valid_after(datetime.now() + timedelta(days=365)) # TODO(Faraphel): settings + .sign(private_key_admin, hashes.SHA256()) + ) + + # Save the root certificate to a file + (directory_machine / "certificate.pem").write_bytes(certificate.public_bytes(serialization.Encoding.PEM)) + + print("machine created !") diff --git a/mains/role/admin/action/create/run.py b/mains/role/admin/action/create/run.py new file mode 100644 index 0000000..0539d0c --- /dev/null +++ b/mains/role/admin/action/create/run.py @@ -0,0 +1,15 @@ +import argparse + +from . import create_role + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + match arguments.create_role: + case "client": + create_role.client.run(parser, arguments) + case "machine": + create_role.machine.run(parser, arguments) + + # if the subcommand is not known, show the help + case _: + parser.print_usage() diff --git a/mains/role/admin/action/init/__init__.py b/mains/role/admin/action/init/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/admin/action/init/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/admin/action/init/argparse.py b/mains/role/admin/action/init/argparse.py new file mode 100644 index 0000000..1e1498b --- /dev/null +++ b/mains/role/admin/action/init/argparse.py @@ -0,0 +1,5 @@ +import argparse + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("init") diff --git a/mains/role/admin/action/init/run.py b/mains/role/admin/action/init/run.py new file mode 100644 index 0000000..deb3ea0 --- /dev/null +++ b/mains/role/admin/action/init/run.py @@ -0,0 +1,53 @@ +import argparse +from datetime import datetime, timedelta +from pathlib import Path + +from cryptography import x509 +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.hazmat.primitives.asymmetric import rsa + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + print("initializing the admin...") + + directory = Path(f"./assets/admin/") + if directory.exists(): + raise ValueError("The admin already exists !") + + directory.mkdir(parents=True) + + # Generate a private key + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=4096, + ) + + (directory / "private.key").write_bytes( + private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + ) + + # Generate a self-signed root certificate + subject = x509.Name([ + x509.NameAttribute(x509.NameOID.COUNTRY_NAME, "FR"), + x509.NameAttribute(x509.NameOID.STATE_OR_PROVINCE_NAME, "Province"), + x509.NameAttribute(x509.NameOID.LOCALITY_NAME, "Locality"), + x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, "Organization"), + x509.NameAttribute(x509.NameOID.COMMON_NAME, "domain.com"), + ]) + certificate = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(subject) + .public_key(private_key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(datetime.now() - timedelta(days=1)) # TODO(Faraphel): settings + .not_valid_after(datetime.now() + timedelta(days=365)) # TODO(Faraphel): settings + .sign(private_key, hashes.SHA256()) + ) + + # Save the root certificate to a file + (directory / "certificate.pem").write_bytes(certificate.public_bytes(serialization.Encoding.PEM)) diff --git a/mains/role/admin/argparse.py b/mains/role/admin/argparse.py new file mode 100644 index 0000000..9b2f141 --- /dev/null +++ b/mains/role/admin/argparse.py @@ -0,0 +1,11 @@ +import argparse + +from . import action + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("admin") + + subsubparsers = subparser.add_subparsers(dest="action") + action.create.load_parse(subsubparsers) + action.init.load_parse(subsubparsers) diff --git a/mains/role/admin/run.py b/mains/role/admin/run.py new file mode 100644 index 0000000..19ce0fd --- /dev/null +++ b/mains/role/admin/run.py @@ -0,0 +1,15 @@ +import argparse + +from . import action + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + match arguments.action: + case "create": + action.create.run(parser, arguments) + case "init": + action.init.run(parser, arguments) + + # if the subcommand is not known, show the help + case _: + parser.print_usage() diff --git a/mains/role/client/__init__.py b/mains/role/client/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/client/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/client/action/__init__.py b/mains/role/client/action/__init__.py new file mode 100644 index 0000000..363a3a9 --- /dev/null +++ b/mains/role/client/action/__init__.py @@ -0,0 +1,2 @@ +from . import vote +from .argparse import load_parse diff --git a/mains/role/client/action/argparse.py b/mains/role/client/action/argparse.py new file mode 100644 index 0000000..b839c64 --- /dev/null +++ b/mains/role/client/action/argparse.py @@ -0,0 +1,9 @@ +import argparse + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("vote") + + subparser.add_argument("-u", "--username", dest="username", type=str, required=True) + subparser.add_argument("-p", "--password", dest="password", type=str, required=True) + subparser.add_argument("-v", "--vote", dest="vote", type=str, required=True) diff --git a/mains/role/client/action/vote.py b/mains/role/client/action/vote.py new file mode 100644 index 0000000..fa8eebe --- /dev/null +++ b/mains/role/client/action/vote.py @@ -0,0 +1,23 @@ +import argparse +import json +import ssl +import socket + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT) + context.load_verify_locations(arguments.certificate) + context.check_hostname = False + + with ( + socket.create_connection((arguments.hostname, arguments.port)) as sock_client, + context.wrap_socket(sock_client, server_hostname=arguments.hostname) as ssl_sock_client + ): + data = { + "username": arguments.username, + "password": arguments.password, + "vote": arguments.vote, + } + + ssl_sock_client.send(json.dumps(data).encode()) + print("message sent.") diff --git a/mains/role/client/argparse.py b/mains/role/client/argparse.py new file mode 100644 index 0000000..65e5b7a --- /dev/null +++ b/mains/role/client/argparse.py @@ -0,0 +1,15 @@ +import argparse +from pathlib import Path + +from . import action + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("client") + + subparser.add_argument("-H", "--host", dest="hostname", type=str, default="127.0.0.1") + subparser.add_argument("-P", "--port", dest="port", type=int, default=57823) + subparser.add_argument("-cc", "--certificate", dest="certificate", type=Path, required=False) + + subsubparsers = subparser.add_subparsers(dest="action") + action.load_parse(subsubparsers) diff --git a/mains/role/client/run.py b/mains/role/client/run.py new file mode 100644 index 0000000..ce781da --- /dev/null +++ b/mains/role/client/run.py @@ -0,0 +1,13 @@ +import argparse + +from . import action + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + match arguments.action: + case "vote": + action.vote.run(parser, arguments) + + # if the subcommand is not known, show the help + case _: + parser.print_usage() diff --git a/mains/role/machine/__init__.py b/mains/role/machine/__init__.py new file mode 100644 index 0000000..05e733e --- /dev/null +++ b/mains/role/machine/__init__.py @@ -0,0 +1,2 @@ +from .argparse import load_parse +from .run import run diff --git a/mains/role/machine/argparse.py b/mains/role/machine/argparse.py new file mode 100644 index 0000000..b193ea2 --- /dev/null +++ b/mains/role/machine/argparse.py @@ -0,0 +1,11 @@ +import argparse +from pathlib import Path + + +def load_parse(subparsers): + subparser: argparse.ArgumentParser = subparsers.add_parser("machine") + + subparser.add_argument("-H", "--host", dest="hostname", type=str, default="0.0.0.0") + subparser.add_argument("-p", "--port", dest="port", type=int, default=57823) + subparser.add_argument("-cc", "--certificate", dest="certificate", type=Path, required=True) + subparser.add_argument("-ck", "--private-key", dest="private_key", type=Path, required=True) diff --git a/mains/role/machine/run.py b/mains/role/machine/run.py new file mode 100644 index 0000000..2c8f6b5 --- /dev/null +++ b/mains/role/machine/run.py @@ -0,0 +1,23 @@ +import argparse +import json + + +def run(parser: argparse.ArgumentParser, arguments: argparse.Namespace): + import ssl + import socket + + context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_SERVER) + context.load_cert_chain(arguments.certificate, arguments.private_key) + + with ( + socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock_server, + context.wrap_socket(sock_server, server_side=True) as ssl_sock_server + ): + ssl_sock_server.bind((arguments.hostname, arguments.port)) + ssl_sock_server.listen(5) + + while True: + print("waiting for a connection...") + connect, address = ssl_sock_server.accept() + data = json.loads(connect.recv()) + print(data) diff --git a/mains/server.py b/mains/server.py deleted file mode 100644 index 2c5977d..0000000 --- a/mains/server.py +++ /dev/null @@ -1,24 +0,0 @@ -import argparse - - -arg_parser = argparse.ArgumentParser() - -arg_parser.add_argument("-H", "--host", dest="hostname", type=str, default="0.0.0.0") -arg_parser.add_argument("-p", "--port", dest="port", type=int, default=57823) - -arguments = arg_parser.parse_args() - - -if arguments: - import ssl - import socket - - context = ssl.create_default_context() - - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock_server: - sock_server.bind((arguments.hostname, arguments.port)) - sock_server.listen(5) - - with context.wrap_socket(sock_server, server_side=True) as ssl_sock_server: - data = ssl_sock_server.recv() - print(data) diff --git a/requirements.txt b/requirements.txt index 0d38bc5..488c3aa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -cryptography +cryptography \ No newline at end of file diff --git a/source/Card.py b/source/Card.py index a261724..5a7dad7 100644 --- a/source/Card.py +++ b/source/Card.py @@ -10,9 +10,7 @@ class Card: Represent the card of an elector. """ - def __init__(self, name: str, pin: str): - self.name = name - + def __init__(self, pin: str): self._private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, diff --git a/source/Machine.py b/source/Machine.py index 32690e2..9a27699 100644 --- a/source/Machine.py +++ b/source/Machine.py @@ -167,8 +167,9 @@ class Machine: if elector is None: print("L’électeur n’est pas inscrit dans la liste électorale.") return False - print(f"L’électeur {elector.name} vote par procuration.") - print(f"L’électeur {elector.name} peut voter.") + print(f"L’électeur {elector.name} est sur la liste électorale et vote par procuration.") + else: + print(f"L’électeur {elector.name} est sur la liste électorale.") # Is the fingerprint matching? if not self.check_fingerprint(elector, fingerprint): @@ -176,7 +177,7 @@ class Machine: return False # L’électeur est authentifié. - print(f"Électeur {elector.name} authentifié") + print(f"L’électeur {elector.name} est authentifié") return True def vote(self, card: Card, vote: str) -> bool: @@ -256,7 +257,7 @@ class Machine: self._vote_list.append(vote) random.shuffle(self._vote_list) - print(f"Vote de {elector.name} comptabilisé!") + print(f"Vote de {elector.name} comptabilisé(e)!") return True def cloture_du_vote(self) -> tuple[list[str], bytes]: diff --git a/source/__main__.py b/source/__main__.py index f9663f5..c31659b 100644 --- a/source/__main__.py +++ b/source/__main__.py @@ -55,6 +55,3 @@ machine_certificate = builder.sign(admin_private_key, algorithm=hashes.SHA256()) print(machine_certificate) # check that the machine machine_certificate.verify_directly_issued_by(admin_certificate) - - -# diff --git a/source/models/Proof.py b/source/models/Proof.py index 16a4772..e111da9 100644 --- a/source/models/Proof.py +++ b/source/models/Proof.py @@ -8,7 +8,7 @@ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey class Proof: date: datetime - public_key_votant: RSAPublicKey + public_key_elector: RSAPublicKey public_key_mandataire: RSAPublicKey proof_signature: bytes diff --git a/source/wtf/Electeur.py b/source/wtf/Electeur.py deleted file mode 100644 index 1352c99..0000000 --- a/source/wtf/Electeur.py +++ /dev/null @@ -1,16 +0,0 @@ -class Electeur: - def __init__(self, nom, prenom, empreinte_digitale): - self.nom = nom - self.prenom = prenom - self.empreinte_digitale = empreinte_digitale - self.carte_election = None - self.code_pin = None - - def recevoir_carte_election(self, carte_election): - self.carte_election = carte_election - - def definir_code_pin(self, code_pin): - self.code_pin = code_pin - - def authentifier(self): - return self.carte_election.est_authentique(self.empreinte_digitale, self.code_pin) diff --git a/source/wtf/ExempleAutiliser.py b/source/wtf/ExempleAutiliser.py deleted file mode 100644 index 8cdc0d2..0000000 --- a/source/wtf/ExempleAutiliser.py +++ /dev/null @@ -1,48 +0,0 @@ -from source.Card import Card -from source.wtf.Electeur import Electeur -from source.wtf.Machine2 import Machine2 - -if __name__ == "__main__": - # Création d'un électeur - electeur1 = Electeur("Alice", "Dupont", "empreinte_alice123") - electeur2 = Electeur("Bob", "Martin", "empreinte_bob456") - - # Création de cartes d'élection pour les électeurs - carte1 = Card(electeur1, "cle_publique_alice") - carte2 = Card(electeur2, "cle_publique_bob") - - # Activation des cartes avec un code PIN - carte1.activer("cle_privee_chiffree_alice", "code_pin_chiffre_alice") - carte2.activer("cle_privee_chiffree_bob", "code_pin_chiffre_bob") - - # Attribution des cartes aux électeurs - electeur1.recevoir_carte_election(carte1) - electeur2.recevoir_carte_election(carte2) - - # Définition des codes PIN - electeur1.definir_code_pin("1234") - electeur2.definir_code_pin("5678") - - # Création d'une machine à voter avec un certificat - certificat_machine = "certificat_de_la_machine" - machine = Machine2(certificat_machine) - - # Chargement de la liste électorale dans la machine - liste_electorale = { - "cle_publique_alice": electeur1.nom, - "cle_publique_bob": electeur2.nom - } - machine.charger_liste_electorale(liste_electorale) - - # Authentification et vote d'un électeur - if machine.authentifier_electeur(electeur1): - preuve_vote = { - "vote": "Choix d'Alice", - "preuve": "Preuve de vote d'Alice" - } - machine.enregistrer_vote(preuve_vote) - - # Fin du vote et publication des résultats - machine.fin_de_vote() - resultats = machine.publier_resultats() - print("Résultats publiés:", resultats) diff --git a/source/wtf/Machine2.py b/source/wtf/Machine2.py deleted file mode 100644 index fc4c70f..0000000 --- a/source/wtf/Machine2.py +++ /dev/null @@ -1,23 +0,0 @@ -class Machine2: - def __init__(self, certificat): - self.certificat = certificat - self.liste_electorale = {} - self.bdd_votes = [] - self.bdd_preuves = [] - - def charger_liste_electorale(self, liste_electorale): - self.liste_electorale = liste_electorale - - def authentifier_electeur(self, electeur): - return electeur.authentifier() and electeur.carte_election.cle_publique in self.liste_electorale - - def enregistrer_vote(self, preuve_vote): - self.bdd_votes.append(preuve_vote['vote']) - self.bdd_preuves.append(preuve_vote) - - def publier_resultats(self): - return self.bdd_votes - - def fin_de_vote(self): - # Bloquer les nouveaux votes - self.bloque = True diff --git a/source/wtf/__init__.py b/source/wtf/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/exemple1.ipynb b/tests/exemple1.ipynb deleted file mode 100644 index 54f657b..0000000 --- a/tests/exemple1.ipynb +++ /dev/null @@ -1,37 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "initial_id", - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/tests/exemple1.py b/tests/exemple1.py index 1182254..0face7b 100644 --- a/tests/exemple1.py +++ b/tests/exemple1.py @@ -1,61 +1,82 @@ -import hashlib -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives.asymmetric import padding - from source.Card import Card from source.models.Elector import Elector -#from source.Certificate import Certificate from source.Machine import Machine +# Vote électronique + +# 3 personnes + +alice = { + "name": "Alice", + "password": "6060", + "empreinte": "empreinteA", + "vote": "Riri", +} + +bob = { + "name": "Bob", + "password": "0100", + "empreinte": "empreinteB", + "vote": "Toto", +} + +eve = { + "name": "Eve", + "password": "008", + "empreinte": "empreinteE", + "vote": "Jack", +} + +personnes = [alice, bob, eve] + # Création des cartes -alice_card = Card("Alice", "6060") -bob_card = Card("Bob", "0100") -eve_card = Card("Eve", "0008") -print(f"carte alice pubkey: {alice_card.public_key}") -print("Cartes d’élections créent") - -input() +alice["card"] = Card(alice["password"]) +bob["card"] = Card(bob["password"]) +eve["card"] = Card(eve["password"]) +print(f"Liste de cartes : {[personne['card'] for personne in personnes]}") +print("Cartes d’élections créées.") +print() # Création de la liste électorale # Eve peut voter pour Alice -alice_elector = Elector(name="Alice", - public_key_elector=alice_card.public_key, - fingerprint_elector="empreinteA", - public_key_mandataire=eve_card.public_key, - fingerprint_mandataire="empreinteE") -bob_elector = Elector("Bob", bob_card.public_key, "empreinteB") -eve_elector = Elector("Eve", eve_card.public_key, "empreinteE") -emerging_list = [alice_elector, bob_elector, eve_elector] -print(f"alice name: {alice_elector.name}") -print(f"alice pubkey: {alice_elector.public_key_elector}") -print(f"alice pubkey mandataire: {alice_elector.public_key_mandataire}") -print(f"alice empreinte: {alice_elector.hashed_fingerprint_elector}") -print(f"alice empreinte mandataire: {alice_elector.hashed_fingerprint_mandataire}") -print(f"liste d’émargement: {emerging_list}") -print("Liste électorale crée.") +alice_elector = Elector(name=alice["name"], + public_key_elector=alice["card"].public_key, fingerprint_elector=alice["empreinte"], + public_key_mandataire=eve["card"].public_key, fingerprint_mandataire=eve["empreinte"]) +bob_elector = Elector(name=bob["name"], + public_key_elector=bob["card"].public_key, fingerprint_elector=bob["empreinte"]) -input() +emerging_list = [alice_elector, bob_elector] +print(f"Liste d’émargement: {emerging_list}") +print("Liste électorale créée.") +print() # Création de la machine machine = Machine(emerging_list) -print(f"machine pubkey : {machine._public_key.public_bytes()}") -print("Machine pour voter crée") +print(f"Machine pubkey : {machine.public_key}") +print("Machine pour voter créée") +print() -input() +# Votes des personnes +alice["password"] = "fleur" +for personne in personnes: + # Authentification + print() + print(f"La personne {personne["name"]} s’authentifie avec le mdp {personne["password"]} et l’empreinte {personne["empreinte"]}.") + if not machine.authenticate(personne["card"], personne["password"], personne["empreinte"]): + continue - -# Authentification - -# Vote + # Vote + print() + print(f"La personne {personne["name"]} va voter pour {personne["vote"]}") + if not machine.vote(personne["card"], personne["vote"]): + continue # Publication des résultats -#Machine.authenticate(Alice_card, 6060, "azerty") - - -#Machine.vote(Alice_card) \ No newline at end of file +votes, sig_votes = machine.cloture_du_vote() +print() +print(votes) diff --git a/tests/exemple2.py b/tests/exemple2.py new file mode 100644 index 0000000..1fe31b7 --- /dev/null +++ b/tests/exemple2.py @@ -0,0 +1,2 @@ + +# Vote à distance From c8b7a42d0dd1e53916f1d27ed146afcd40368b2e Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 5 Jul 2024 09:48:07 +0200 Subject: [PATCH 10/10] renamed mains to cli, removed unused classes --- .gitignore | 2 ++ assets/admin/certificate.pem | 20 -------------- assets/admin/private.key | 27 ------------------- assets/machine/Beauvais/certificate.pem | 20 -------------- assets/machine/Beauvais/private.key | 27 ------------------- {mains => cli}/__init__.py | 0 {mains => cli}/__main__.py | 2 +- {mains => cli}/role/__init__.py | 0 {mains => cli}/role/admin/__init__.py | 0 {mains => cli}/role/admin/action/__init__.py | 0 .../role/admin/action/create/__init__.py | 0 .../role/admin/action/create/argparse.py | 0 .../action/create/create_role/__init__.py | 0 .../create/create_role/client/__init__.py | 0 .../create/create_role/client/argparse.py | 0 .../action/create/create_role/client/run.py | 1 + .../create/create_role/machine/__init__.py | 0 .../create/create_role/machine/argparse.py | 0 .../action/create/create_role/machine/run.py | 0 .../role/admin/action/create/run.py | 0 .../role/admin/action/init/__init__.py | 0 .../role/admin/action/init/argparse.py | 0 {mains => cli}/role/admin/action/init/run.py | 0 {mains => cli}/role/admin/argparse.py | 0 {mains => cli}/role/admin/run.py | 0 {mains => cli}/role/client/__init__.py | 0 {mains => cli}/role/client/action/__init__.py | 0 {mains => cli}/role/client/action/argparse.py | 0 {mains => cli}/role/client/action/vote.py | 0 {mains => cli}/role/client/argparse.py | 0 {mains => cli}/role/client/run.py | 0 {mains => cli}/role/machine/__init__.py | 0 {mains => cli}/role/machine/argparse.py | 0 {mains => cli}/role/machine/run.py | 0 source/Pki.py | 23 ---------------- 35 files changed, 4 insertions(+), 118 deletions(-) delete mode 100644 assets/admin/certificate.pem delete mode 100644 assets/admin/private.key delete mode 100644 assets/machine/Beauvais/certificate.pem delete mode 100644 assets/machine/Beauvais/private.key rename {mains => cli}/__init__.py (100%) rename {mains => cli}/__main__.py (96%) rename {mains => cli}/role/__init__.py (100%) rename {mains => cli}/role/admin/__init__.py (100%) rename {mains => cli}/role/admin/action/__init__.py (100%) rename {mains => cli}/role/admin/action/create/__init__.py (100%) rename {mains => cli}/role/admin/action/create/argparse.py (100%) rename {mains => cli}/role/admin/action/create/create_role/__init__.py (100%) rename {mains => cli}/role/admin/action/create/create_role/client/__init__.py (100%) rename {mains => cli}/role/admin/action/create/create_role/client/argparse.py (100%) rename {mains => cli}/role/admin/action/create/create_role/client/run.py (98%) rename {mains => cli}/role/admin/action/create/create_role/machine/__init__.py (100%) rename {mains => cli}/role/admin/action/create/create_role/machine/argparse.py (100%) rename {mains => cli}/role/admin/action/create/create_role/machine/run.py (100%) rename {mains => cli}/role/admin/action/create/run.py (100%) rename {mains => cli}/role/admin/action/init/__init__.py (100%) rename {mains => cli}/role/admin/action/init/argparse.py (100%) rename {mains => cli}/role/admin/action/init/run.py (100%) rename {mains => cli}/role/admin/argparse.py (100%) rename {mains => cli}/role/admin/run.py (100%) rename {mains => cli}/role/client/__init__.py (100%) rename {mains => cli}/role/client/action/__init__.py (100%) rename {mains => cli}/role/client/action/argparse.py (100%) rename {mains => cli}/role/client/action/vote.py (100%) rename {mains => cli}/role/client/argparse.py (100%) rename {mains => cli}/role/client/run.py (100%) rename {mains => cli}/role/machine/__init__.py (100%) rename {mains => cli}/role/machine/argparse.py (100%) rename {mains => cli}/role/machine/run.py (100%) delete mode 100644 source/Pki.py diff --git a/.gitignore b/.gitignore index 9672ada..f0e6044 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ # IDE .idea/ !.idea/runConfigurations/ + +subject.pdf diff --git a/assets/admin/certificate.pem b/assets/admin/certificate.pem deleted file mode 100644 index 3fdf400..0000000 --- a/assets/admin/certificate.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIUFiOqi4pgJB9drME4SMSjaF+PoyMwDQYJKoZIhvcNAQEL -BQAwXzELMAkGA1UEBhMCRlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhM -b2NhbGl0eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4u -Y29tMB4XDTI0MDcwNDAwMDI1MVoXDTI1MDcwNTAwMDI1MVowXzELMAkGA1UEBhMC -RlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhMb2NhbGl0eTEVMBMGA1UE -CgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4uY29tMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEApvut4HKl4ZyECZFgL8DGnsr8UJmT7MYwReWJ -Q6nuAucUD8lkWWikYwoSiz57ptpYXLMRLWzOot0h3GBWHB6zcMgFOfTXjrd8heN5 -pknbNQYywVUFJsdN3GXJ1IjSDFNSlsBmDh1mvVmVqWNeGv2rpJSxC6hV0iLMRXYK -J9dLM4IIH2zLUdSkpmzxzOejTH1SYAiqyk91eJvikA0SjlwUC8gRe71HSVIuNqyQ -wVCv/00wjIg6A8Q2fOhFlfvp4IoKCtTviKuDnXIK7Tn02dICHcDeNWis7G8NNosU -nRTbG9UH62eJ0g5IW3e/3ZA4peX20rGwPf599VlFLzGxnW35CwIDAQABMA0GCSqG -SIb3DQEBCwUAA4IBAQCmH/UHxIcVDjNFQDAQuWe6+UEfOq97qgd4D3j/igAmbfvx -6puPKuCFZKWCeNMb3B9+rFRDHq4NJgbPL22iGUPdZwBjdjt8HZhrheQ+/TEy4Zcf -I6NvuTVAjJmijfHTDQ14koWIrvznlKBNTX1cPtUQnyCrhKpzUUXp9kpuwVlRt5JQ -WpYCJw5XycJiW52vXyZsCd2S1xecD0Pwq5u6+25jM/yblx3s2C2ezcNhIzBufG2i -xz8TSykG+NjhzHfvg8M5eln05kTaf9wHvwkyuH9+WHQUZFeauUzOFX/E6SEJ74s9 -vYssU5Rue2tBOZhuSkqRgE2FsVGJ0ccZQWVfZ6X3 ------END CERTIFICATE----- diff --git a/assets/admin/private.key b/assets/admin/private.key deleted file mode 100644 index 7a9d89c..0000000 --- a/assets/admin/private.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEApvut4HKl4ZyECZFgL8DGnsr8UJmT7MYwReWJQ6nuAucUD8lk -WWikYwoSiz57ptpYXLMRLWzOot0h3GBWHB6zcMgFOfTXjrd8heN5pknbNQYywVUF -JsdN3GXJ1IjSDFNSlsBmDh1mvVmVqWNeGv2rpJSxC6hV0iLMRXYKJ9dLM4IIH2zL -UdSkpmzxzOejTH1SYAiqyk91eJvikA0SjlwUC8gRe71HSVIuNqyQwVCv/00wjIg6 -A8Q2fOhFlfvp4IoKCtTviKuDnXIK7Tn02dICHcDeNWis7G8NNosUnRTbG9UH62eJ -0g5IW3e/3ZA4peX20rGwPf599VlFLzGxnW35CwIDAQABAoIBAEuzh9VcRIWunlF0 -HaYogCMXJSIpLd3Gz7WwZPVPAX9BYV/yzlKWVQgtVdDYp9gx3qNP7vaoAFnnZGVz -KzaeWH1FwNDQhjTGTGaqhMj1bLJyN+pb7/TvoAXOA50d1hQOZj+/w8ScYapwBaCA -UvZrkDgRzN3bF+UnL3JCHEKJoScdDCGZGlvM/c7hQZYyZ94MuUT9+njkymGXm/H2 -Xkyf1AWnXMeQRs1vBLwtNxshQzfpoEAuYQ01mNjaHNyyW8/VYXzY+cUUDjuQMoxR -0VT/3N7IJFrdQdw2d5nfae59iX+mJM3dZ5hsSNimN9p4Q+5jG6uDOJP6QC/TKkDm -gYLFf/ECgYEA63q9cJuQ4CYbCRllyR/JhjeczT87D9wCE4/TxPLHIRbYXUTwvVbd -tII4lHR4mnsJUVK+cDhXzPWtgLhFZ3oY7tjv89Nj8SMAZA+gh7XLS8mYuvG8OjgJ -TZoJbSOGR5RJDV5BLxaR2czC+si/IsDn2rEjuAeBzu7cdBd6yq7EUjMCgYEAtYje -kn62UQjqCPcprA5Zumki8zBJfQlHXOPJh58hczla+T+wyFCMA4e3rE2ZYUUeCUZu -fM+qbqAP7CQW2lY7msidtlH+uhutgjCmJ9mHFpFS9bN7iRX7t6oGfnQJ13nvoaF0 -7D8ebxVnn5paCeu4vUBQ2mYKxjhJdnTx/3yH1ckCgYBG0OG5xL77+dm1kdK/enTD -jWP1gaeEbHifY2ifWRezhshIvFvdxQrlpyfW1XQTmR7DOywUWY1mERg9lq0gomJv -KgR3gkITGaCbduujBHP/9b+dsOcXZxS9Jq7hCIbwbdLOV2MpAxOXuXGFs+tvSy4u -4YjJZlCOZ90aeJkv7QETawKBgEmzQqF5Hi2yD8oKBnoa7WTX8F+JGBzSWo2k0Rnl -iiAMhhmxOOVqhh2cyP4EFyQ9el9Ln+m+KbR1+WDmmfyUi+hgUF9H1MHcIMo9VAfT -sZuA7oxgDORv71z2g2JtW92GXLpjIWQUkBeLOiG6+ZkTgVIcPXcdfHxTN8gG3ITc -Gw25AoGAcdR8DNJO/Oo7BlZKV/g5nUSzbdgIrT2gtT6ZUBaQZw3mLjiMHFfihtPn -hXfmXZ+ymaXxm6IRGcz9c28V0a9M+q29P1hWfQQVCk7yEdMHxlE4FBVg7ejIhw07 -8dgM9v8tg6Nf3b0KGWrgnD87ds3uR6D536Bhh3jmhq27U8k45OY= ------END RSA PRIVATE KEY----- diff --git a/assets/machine/Beauvais/certificate.pem b/assets/machine/Beauvais/certificate.pem deleted file mode 100644 index cbbf9de..0000000 --- a/assets/machine/Beauvais/certificate.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIUaZDZAVUe0kK/3m6RxCg44Rv8ToswDQYJKoZIhvcNAQEL -BQAwXzELMAkGA1UEBhMCRlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhM -b2NhbGl0eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4u -Y29tMB4XDTI0MDcwNDAwMDI1NVoXDTI1MDcwNTAwMDI1NVowXzELMAkGA1UEBhMC -RlIxETAPBgNVBAgMCFByb3ZpbmNlMREwDwYDVQQHDAhMb2NhbGl0eTEVMBMGA1UE -CgwMT3JnYW5pemF0aW9uMRMwEQYDVQQDDApkb21haW4uY29tMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0xfSOKdy/FKvLsNatkdg22vbwgKHjHeS0kXu -k+MVHvbp+r2uwwhbYilhLWBk6OM94ftVJh0441bkCnoPACMd1goqxvUkP4m+4uaX -+lVup5JHAre5YXher3rX5K1Jyd7Rns7V0q01y6J7LnjRSMY2hZIgrQEoVc+HXVqS -idPaOl30W4U12UQv405y+yAHCjqWZEp9ZNO7cg6zMQCGyTs+u9/4wyqXIrXly0Br -R/MV1VyCvBSpT0913WksRXb2xJvPSwsiRGzgKJ0/LtiFC3hfNZWkfi4FVRazYO69 -OPiXw+MbmodI9ie2TNvmk7TuxFPntrm9P0YqsOacymOYXS05uwIDAQABMA0GCSqG -SIb3DQEBCwUAA4IBAQBaNv/xmhRBmBfJQXnA8N03xg9vYlC0VyHQzhYRQ3kE9wb7 -j4/lzbDgqRb5ok2zIrPPewcwZ4yM5tIyi78I0dYPtlCSLEyEqQJ2kNfYHWnKvC5D -ipDeJrymCz0VGNAAqH9Ib18HoxrLM2+tQtavs6p0Iu9V14H3D/ouJhdfQV04PvgC -8QFFCmrvqw8WSAzhoXaD9pAxCQc4fJIDrMUN45nOjIUjSdi4vGClIryJ2Fmz7LP+ -a/ZqciybqgybLz5pGp9gPFL7FKhw/sgypP7HqvUEyw+mejLNxcDXbmk+01Wjspfj -VAi/u0nCupYv5UfBVyPG6vBZ4qcOcX89qkHv4xl9 ------END CERTIFICATE----- diff --git a/assets/machine/Beauvais/private.key b/assets/machine/Beauvais/private.key deleted file mode 100644 index 3f4bc26..0000000 --- a/assets/machine/Beauvais/private.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA0xfSOKdy/FKvLsNatkdg22vbwgKHjHeS0kXuk+MVHvbp+r2u -wwhbYilhLWBk6OM94ftVJh0441bkCnoPACMd1goqxvUkP4m+4uaX+lVup5JHAre5 -YXher3rX5K1Jyd7Rns7V0q01y6J7LnjRSMY2hZIgrQEoVc+HXVqSidPaOl30W4U1 -2UQv405y+yAHCjqWZEp9ZNO7cg6zMQCGyTs+u9/4wyqXIrXly0BrR/MV1VyCvBSp -T0913WksRXb2xJvPSwsiRGzgKJ0/LtiFC3hfNZWkfi4FVRazYO69OPiXw+MbmodI -9ie2TNvmk7TuxFPntrm9P0YqsOacymOYXS05uwIDAQABAoIBABjvZ+w8T3dh1wK5 -ndYJUXYp5AAjZ1qe50+CZj++48hQF2yAiovMSWsrgyimidT+vtkaZMEHU6h7I53f -NDVqcIRPmCT/YSRGQ6+u2IYAIH2X6F54UGQkoV6uLqF7HMvFT9KoERb9Uez3iQCA -0gv8KgWWMNju2ZJlXNKYt9WjGlSpfIVbAxdGlFNWGKwWvAypfXMfdJY5P5U+Lk1Q -CqNZ/U1B5uaqbVbd9RfQJYtZny3h2OQGf4nSDXE2Gq63fOIbPdISjhaYCnHWBoBD -HzaO14tbz7hGeHLmNLB8p5SeoY1ZOA10YTdF1jtH+4gloKEwf1vcxUEXf3novn1X -f8NB620CgYEA9y+3wAx91c2sK57HVJEuicp9xmtXNjKVeoPnuk50DGjL4D/V3C1r -eM7hGfbD/98euSMkNs0F7zIkqXiBC45U4wOIaQHgVZbJM5Mhdvh4S7pZstETUA7k -XrN+c71ktms8fg7EjiBRfzi3wULWk5bmjKsc+sTlPACCFUt4zYe6zS0CgYEA2p6m -AtxYLkWA0Ci6xho4xU0iKCmGHeR+R4YuLd60/L7PHAySMCBzrha8jx9PpAppi27M -DaOu9H9VpNnApGBJVuHDTRq672ZPpPQ8Rbj8ZvCQ6TlsoMJuEO4kcTBfccYVCNS+ -wYbRWpteK7GfL6YXC5HdxL9vFV2hpK0IFmuBg4cCgYEAyOddv5fnhqidsO5iMFe3 -rYKI64Y+4ewHFgazhvdQ1u0uF1uK5GN+IDh1OHcaIpMkE3F+c5P7qMfmiF9K8yuB -zukGK+K8hJQDgAmrf1i/3TzevrmzqrQP5PCabFOY0bMi/YnfM20NEAv3PfqnEFnr -lJVW/nKdpkD7eXdX/iS9LRkCgYEAhzv0PXjII3djA2DuiHTYAVSBeI6XJA6f/uaF -0mIdWus9eoBcPeEVLe9qnK4lubenKlVTbGyAYUYTWHJKtGPLei8VfLC4SjbjtYpP -bmHL4HGXcm3PQHKFW3u0lz/xCpQZlujjRxt6ja3mRukNK5B2WPXWVUqGEJVm1FMk -2ZmO+CkCgYA6X1eHTPfY9Wy7uQEyamA6H/nUGFyKM85tGYU0D7xdU9ls0VFTuME4 -0FAq8k1k9BbSAhrpsyYp/eIAHJ3gF88w/NyP/1HO1RTzpLcXiI/fzGb59i4hY6Gg -g7AyGGe62nfVhAD/WaMp+0iidXtd/ZwR09PaECUuU+UJ91BojlbwzA== ------END RSA PRIVATE KEY----- diff --git a/mains/__init__.py b/cli/__init__.py similarity index 100% rename from mains/__init__.py rename to cli/__init__.py diff --git a/mains/__main__.py b/cli/__main__.py similarity index 96% rename from mains/__main__.py rename to cli/__main__.py index fd1afd0..5289847 100644 --- a/mains/__main__.py +++ b/cli/__main__.py @@ -1,6 +1,6 @@ import argparse -from mains import role +from cli import role parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest="role") diff --git a/mains/role/__init__.py b/cli/role/__init__.py similarity index 100% rename from mains/role/__init__.py rename to cli/role/__init__.py diff --git a/mains/role/admin/__init__.py b/cli/role/admin/__init__.py similarity index 100% rename from mains/role/admin/__init__.py rename to cli/role/admin/__init__.py diff --git a/mains/role/admin/action/__init__.py b/cli/role/admin/action/__init__.py similarity index 100% rename from mains/role/admin/action/__init__.py rename to cli/role/admin/action/__init__.py diff --git a/mains/role/admin/action/create/__init__.py b/cli/role/admin/action/create/__init__.py similarity index 100% rename from mains/role/admin/action/create/__init__.py rename to cli/role/admin/action/create/__init__.py diff --git a/mains/role/admin/action/create/argparse.py b/cli/role/admin/action/create/argparse.py similarity index 100% rename from mains/role/admin/action/create/argparse.py rename to cli/role/admin/action/create/argparse.py diff --git a/mains/role/admin/action/create/create_role/__init__.py b/cli/role/admin/action/create/create_role/__init__.py similarity index 100% rename from mains/role/admin/action/create/create_role/__init__.py rename to cli/role/admin/action/create/create_role/__init__.py diff --git a/mains/role/admin/action/create/create_role/client/__init__.py b/cli/role/admin/action/create/create_role/client/__init__.py similarity index 100% rename from mains/role/admin/action/create/create_role/client/__init__.py rename to cli/role/admin/action/create/create_role/client/__init__.py diff --git a/mains/role/admin/action/create/create_role/client/argparse.py b/cli/role/admin/action/create/create_role/client/argparse.py similarity index 100% rename from mains/role/admin/action/create/create_role/client/argparse.py rename to cli/role/admin/action/create/create_role/client/argparse.py diff --git a/mains/role/admin/action/create/create_role/client/run.py b/cli/role/admin/action/create/create_role/client/run.py similarity index 98% rename from mains/role/admin/action/create/create_role/client/run.py rename to cli/role/admin/action/create/create_role/client/run.py index 2240bbf..5391e74 100644 --- a/mains/role/admin/action/create/create_role/client/run.py +++ b/cli/role/admin/action/create/create_role/client/run.py @@ -1,6 +1,7 @@ import argparse from pathlib import Path +import bcrypt from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa diff --git a/mains/role/admin/action/create/create_role/machine/__init__.py b/cli/role/admin/action/create/create_role/machine/__init__.py similarity index 100% rename from mains/role/admin/action/create/create_role/machine/__init__.py rename to cli/role/admin/action/create/create_role/machine/__init__.py diff --git a/mains/role/admin/action/create/create_role/machine/argparse.py b/cli/role/admin/action/create/create_role/machine/argparse.py similarity index 100% rename from mains/role/admin/action/create/create_role/machine/argparse.py rename to cli/role/admin/action/create/create_role/machine/argparse.py diff --git a/mains/role/admin/action/create/create_role/machine/run.py b/cli/role/admin/action/create/create_role/machine/run.py similarity index 100% rename from mains/role/admin/action/create/create_role/machine/run.py rename to cli/role/admin/action/create/create_role/machine/run.py diff --git a/mains/role/admin/action/create/run.py b/cli/role/admin/action/create/run.py similarity index 100% rename from mains/role/admin/action/create/run.py rename to cli/role/admin/action/create/run.py diff --git a/mains/role/admin/action/init/__init__.py b/cli/role/admin/action/init/__init__.py similarity index 100% rename from mains/role/admin/action/init/__init__.py rename to cli/role/admin/action/init/__init__.py diff --git a/mains/role/admin/action/init/argparse.py b/cli/role/admin/action/init/argparse.py similarity index 100% rename from mains/role/admin/action/init/argparse.py rename to cli/role/admin/action/init/argparse.py diff --git a/mains/role/admin/action/init/run.py b/cli/role/admin/action/init/run.py similarity index 100% rename from mains/role/admin/action/init/run.py rename to cli/role/admin/action/init/run.py diff --git a/mains/role/admin/argparse.py b/cli/role/admin/argparse.py similarity index 100% rename from mains/role/admin/argparse.py rename to cli/role/admin/argparse.py diff --git a/mains/role/admin/run.py b/cli/role/admin/run.py similarity index 100% rename from mains/role/admin/run.py rename to cli/role/admin/run.py diff --git a/mains/role/client/__init__.py b/cli/role/client/__init__.py similarity index 100% rename from mains/role/client/__init__.py rename to cli/role/client/__init__.py diff --git a/mains/role/client/action/__init__.py b/cli/role/client/action/__init__.py similarity index 100% rename from mains/role/client/action/__init__.py rename to cli/role/client/action/__init__.py diff --git a/mains/role/client/action/argparse.py b/cli/role/client/action/argparse.py similarity index 100% rename from mains/role/client/action/argparse.py rename to cli/role/client/action/argparse.py diff --git a/mains/role/client/action/vote.py b/cli/role/client/action/vote.py similarity index 100% rename from mains/role/client/action/vote.py rename to cli/role/client/action/vote.py diff --git a/mains/role/client/argparse.py b/cli/role/client/argparse.py similarity index 100% rename from mains/role/client/argparse.py rename to cli/role/client/argparse.py diff --git a/mains/role/client/run.py b/cli/role/client/run.py similarity index 100% rename from mains/role/client/run.py rename to cli/role/client/run.py diff --git a/mains/role/machine/__init__.py b/cli/role/machine/__init__.py similarity index 100% rename from mains/role/machine/__init__.py rename to cli/role/machine/__init__.py diff --git a/mains/role/machine/argparse.py b/cli/role/machine/argparse.py similarity index 100% rename from mains/role/machine/argparse.py rename to cli/role/machine/argparse.py diff --git a/mains/role/machine/run.py b/cli/role/machine/run.py similarity index 100% rename from mains/role/machine/run.py rename to cli/role/machine/run.py diff --git a/source/Pki.py b/source/Pki.py deleted file mode 100644 index 4d2b586..0000000 --- a/source/Pki.py +++ /dev/null @@ -1,23 +0,0 @@ -class Pki: - """ - Represent a Public Key Infrastructure - """ - - def __init__(self): - pass - -class Certificate: - """ - Represent a Certificate - """ - - def __init__(self): - # create a builder for the certificate - builder = x509.CertificateBuilder( - issuer_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, issuer)]), - subject_name=x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, subject)]), - serial_number=x509.random_serial_number(), - public_key=self.public_key, - not_valid_before=valid_start, - not_valid_after=valid_end, - )