Fully implement the vote #8
2 changed files with 186 additions and 94 deletions
|
@ -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
|
||||
|
|
|
@ -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): 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
|
Loading…
Reference in a new issue