Fully implement the vote #8

Merged
faraphel merged 10 commits from base into main 2024-07-05 11:09:12 +02:00
2 changed files with 186 additions and 94 deletions
Showing only changes of commit e3015a5e81 - Show all commits

View file

@ -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

View file

@ -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.
"""
try:
return next(filter(
lambda elector: elector.public_key_elector == pubkey,
self.emerging_list
))
except StopIteration:
return None
next(filter(
lambda data: data["personne"][0] == and
self.emerging_list
))
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): cest 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 nest 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 lempreinte 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 lutilisateur est authentifiée.
print("Lélecteur nest 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