CIA/e-voting-system/tests/test_pqc.py
E-Voting Developer 6df490a7b1 Add post-quantum cryptography (FIPS 203/204)
- Add hybrid PQC using liboqs: ML-DSA-65 (Dilithium) + ML-KEM-768 (Kyber)
- Signatures: RSA-PSS + Dilithium (defense-in-depth)
- Encryption: ML-KEM-768 (Kyber) + ElGamal
- Tests for PQC hybrid operations
- Cleanup: remove non-essential scripts and docs
- Minimal, production-ready e-voting system
2025-11-05 17:49:29 +01:00

205 lines
7.2 KiB
Python

"""
Tests pour la cryptographie post-quantique hybride.
Valide les standards NIST FIPS 203/204/205.
"""
import pytest
from src.crypto.pqc_hybrid import PostQuantumCryptography
class TestPostQuantumCryptography:
"""Tests de la cryptographie post-quantique hybride"""
def test_hybrid_keypair_generation(self):
"""Tester la génération de paires de clés hybrides"""
keypair = PostQuantumCryptography.generate_hybrid_keypair()
# Vérifier présence de toutes les clés
assert "rsa_public_key" in keypair
assert "rsa_private_key" in keypair
assert "dilithium_public" in keypair
assert "dilithium_secret" in keypair
assert "kyber_public" in keypair
assert "kyber_secret" in keypair
assert "elgamal_public" in keypair
assert "elgamal_secret" in keypair
# Vérifier formats
assert b"-----BEGIN PUBLIC KEY-----" in keypair["rsa_public_key"]
assert b"-----BEGIN PRIVATE KEY-----" in keypair["rsa_private_key"]
assert len(keypair["dilithium_public"]) > 0
assert len(keypair["kyber_public"]) > 0
def test_hybrid_sign_and_verify(self):
"""Tester les signatures hybrides RSA-PSS + Dilithium"""
# Générer clés
keypair = PostQuantumCryptography.generate_hybrid_keypair()
# Message à signer
message = b"Vote securise avec cryptographie post-quantique"
# Signer
signatures = PostQuantumCryptography.hybrid_sign(
message,
keypair["rsa_private_key"],
keypair["dilithium_secret"]
)
# Vérifier les signatures
assert "rsa_signature" in signatures
assert "dilithium_signature" in signatures
assert len(signatures["rsa_signature"]) > 0
assert len(signatures["dilithium_signature"]) > 0
# Vérifier les deux signatures ensemble
is_valid = PostQuantumCryptography.hybrid_verify(
message,
signatures,
keypair["rsa_public_key"],
keypair["dilithium_public"]
)
assert is_valid
def test_hybrid_sign_invalid_message(self):
"""Tester que les signatures invalides sont rejetées"""
keypair = PostQuantumCryptography.generate_hybrid_keypair()
message = b"Message original"
signatures = PostQuantumCryptography.hybrid_sign(
message,
keypair["rsa_private_key"],
keypair["dilithium_secret"]
)
# Vérifier avec un message différent (doit échouer)
modified_message = b"Message modifie"
is_valid = PostQuantumCryptography.hybrid_verify(
modified_message,
signatures,
keypair["rsa_public_key"],
keypair["dilithium_public"]
)
assert not is_valid
def test_hybrid_encapsulate_decapsulate(self):
"""Tester l'encapsulation/décapsulation hybride"""
keypair = PostQuantumCryptography.generate_hybrid_keypair()
# Encapsuler un secret
result = PostQuantumCryptography.hybrid_encapsulate(
keypair["kyber_public"],
keypair["elgamal_public"]
)
assert "kyber_ciphertext" in result
assert "elgamal_ciphertext" in result
assert "combined_secret" in result
assert len(result["combined_secret"]) == 32 # 256-bit
# Décapsuler le secret
decapsulated_secret = PostQuantumCryptography.hybrid_decapsulate(
{
"kyber_ciphertext": result["kyber_ciphertext"],
"elgamal_ciphertext": result["elgamal_ciphertext"]
},
keypair["kyber_secret"],
keypair["elgamal_secret"]
)
# Les secrets doivent correspondre
assert decapsulated_secret == result["combined_secret"]
def test_algorithm_info(self):
"""Tester que les infos d'algorithmes sont correctes"""
info = PostQuantumCryptography.get_algorithm_info()
assert "signatures" in info
assert "encryption" in info
assert "hashing" in info
assert "ML-DSA-65" in info["signatures"]
assert "ML-KEM-768" in info["encryption"]
assert "SHA-256" in info["hashing"]
assert "FIPS 203" in info["encryption_status"]
assert "FIPS 204" in info["signatures_status"]
def test_multiple_signatures_different_messages(self):
"""Tester plusieurs signatures sur des messages différents"""
keypair = PostQuantumCryptography.generate_hybrid_keypair()
messages = [
b"Vote pour Alice",
b"Vote pour Bob",
b"Vote pour Charlie",
]
signatures_list = []
for msg in messages:
sig = PostQuantumCryptography.hybrid_sign(
msg,
keypair["rsa_private_key"],
keypair["dilithium_secret"]
)
signatures_list.append(sig)
# Vérifier chaque signature avec son message
for msg, sig in zip(messages, signatures_list):
is_valid = PostQuantumCryptography.hybrid_verify(
msg,
sig,
keypair["rsa_public_key"],
keypair["dilithium_public"]
)
assert is_valid
# Vérifier que les signatures ne sont pas valides avec d'autres messages
for i, (msg, sig) in enumerate(zip(messages, signatures_list)):
for j, other_msg in enumerate(messages):
if i != j:
is_valid = PostQuantumCryptography.hybrid_verify(
other_msg,
sig,
keypair["rsa_public_key"],
keypair["dilithium_public"]
)
assert not is_valid
def test_hybrid_encapsulate_multiple_times(self):
"""Tester que chaque encapsulation produit des ciphertexts différents"""
keypair = PostQuantumCryptography.generate_hybrid_keypair()
result1 = PostQuantumCryptography.hybrid_encapsulate(
keypair["kyber_public"],
keypair["elgamal_public"]
)
result2 = PostQuantumCryptography.hybrid_encapsulate(
keypair["kyber_public"],
keypair["elgamal_public"]
)
# Les ciphertexts doivent être différents (randomisés)
assert result1["kyber_ciphertext"] != result2["kyber_ciphertext"]
assert result1["combined_secret"] != result2["combined_secret"]
# Mais les deux doivent se décapsuler correctement
dec1 = PostQuantumCryptography.hybrid_decapsulate(
{
"kyber_ciphertext": result1["kyber_ciphertext"],
"elgamal_ciphertext": result1["elgamal_ciphertext"]
},
keypair["kyber_secret"],
keypair["elgamal_secret"]
)
dec2 = PostQuantumCryptography.hybrid_decapsulate(
{
"kyber_ciphertext": result2["kyber_ciphertext"],
"elgamal_ciphertext": result2["elgamal_ciphertext"]
},
keypair["kyber_secret"],
keypair["elgamal_secret"]
)
assert dec1 == result1["combined_secret"]
assert dec2 == result2["combined_secret"]