Function to end election.

Convert type of pubkey from bytes to RSAPublicKey.
This commit is contained in:
biloute02 2024-07-04 19:31:20 +02:00
parent 096fc6637e
commit cc243e5163
5 changed files with 157 additions and 58 deletions

View file

@ -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()),

View file

@ -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 nest 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 lempreinte digitale.")
print(f"Erreur de reconnaissance de lempreinte 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
# Cest 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.
# Cest 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

View file

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

View file

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

View file

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