rewrote the base for the program
This commit is contained in:
parent
c8445c75b9
commit
74c29a5c93
9 changed files with 370 additions and 36 deletions
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
||||
if card_in_siging_list(card):
|
||||
print("déjà vôté")
|
||||
return False
|
||||
next(filter(
|
||||
lambda data: data["personne"][0] == and
|
||||
self.emerging_list
|
||||
))
|
||||
|
||||
vote = get_vote()
|
||||
generate_signature(vote, card)
|
||||
add_vote_to_urn(vote)
|
||||
print("Vote comptabilisé!")
|
||||
def check_fingerprint(self, empreinte: bytes) -> bool:
|
||||
"""
|
||||
|
||||
: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): c’est 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
23
source/Pki.py
Normal 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,
|
||||
)
|
|
@ -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
23
source/wtf/Machine2.py
Normal 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
0
source/wtf/__init__.py
Normal file
18
tests/exemple1.py
Normal file
18
tests/exemple1.py
Normal 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
27
tests/schema.md
Normal 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
|
||||
|
Loading…
Reference in a new issue