Fully implement the vote #8
5 changed files with 157 additions and 58 deletions
|
@ -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()),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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("<d...", self.date.timestamp(), self.public_key_votant, self.public_key_mandataire)
|
||||
|
||||
#bytes(str(ici), 'utf-8')
|
||||
bytes(self.date.timestamp())
|
||||
# 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
|
||||
|
|
|
@ -4,15 +4,58 @@ 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.models.Elector import Elector
|
||||
#from source.Certificate import Certificate
|
||||
from source.Machine import Machine
|
||||
|
||||
Alice_card = Card("Alice", 6060)
|
||||
# Création des cartes
|
||||
|
||||
Machine = Machine()
|
||||
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()
|
||||
|
||||
# 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.")
|
||||
|
||||
input()
|
||||
|
||||
# Création de la machine
|
||||
|
||||
machine = Machine(emerging_list)
|
||||
print(f"machine pubkey : {machine._public_key.public_bytes()}")
|
||||
print("Machine pour voter crée")
|
||||
|
||||
input()
|
||||
|
||||
|
||||
Machine.authenticate(Alice_card, 6060, "azerty")
|
||||
|
||||
# Authentification
|
||||
|
||||
# Vote
|
||||
|
||||
# Publication des résultats
|
||||
|
||||
#Machine.authenticate(Alice_card, 6060, "azerty")
|
||||
|
||||
|
||||
Machine.vote(Alice_card)
|
||||
#Machine.vote(Alice_card)
|
Loading…
Reference in a new issue