rewrote the base for the program

This commit is contained in:
Faraphel 2024-07-03 23:41:29 +02:00
parent c8445c75b9
commit 74c29a5c93
9 changed files with 370 additions and 36 deletions

View file

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

View file

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

View file

@ -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): cest 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:
...

23
source/Pki.py Normal file
View file

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

View file

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

23
source/wtf/Machine2.py Normal file
View file

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

0
source/wtf/__init__.py Normal file
View file

18
tests/exemple1.py Normal file
View file

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

27
tests/schema.md Normal file
View file

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