Projet Privalis

Système d'Enchères Sécurisé & Architecture Réflexive

Contexte : SAE-3 - Architecture Logicielle & Sécurité Product Owner : BAERT Thomas Équipe : BAERT Thomas, FUCHS Théo, LORENZO Eden, PESENTI Lillian, TRIOLEYRE Nathan Status : Phase 2 : Restructuration, Sécurité & Docker (En cours) Technologies : Java 21, Oracle SQL, Damgård-Jurik, Docker, JUnit, SSL/TLS, RSA, JSON-RPC

Vision & Problématique

Privalis est une plateforme distribuée d'enchères au second prix (Vickrey). Dans ce modèle "à plis fermés", l'anonymat des offres et l'intégrité du protocole sont critiques : les montants ne doivent être révélés qu'après la clôture, et aucun acteur (pas même le serveur) ne doit pouvoir altérer une offre sans être détecté.

Logique & Justification

Le choix de l'enchère de Vickrey impose une architecture où le Serveur est un pur relais de stockage (aveugle aux prix) tandis que l'Autorité est le seul tiers de confiance capable de lever le secret. Cette séparation des pouvoirs est la clé de la non-répudiation et de l'équité du système.

Analyse Fonctionnelle (DCU)

Diagramme de Cas d'Utilisation

Diagramme de Cas d'Utilisation (DCU) modélisant les interactions métiers et la frontière du système.

Le fonctionnement repose sur une orchestration précise entre les acteurs :

  • Enchérisseur : Il ne se contente pas d'envoyer un prix. Il doit générer une preuve cryptographique (chiffrement RSA pour l'Autorité) et signer le résultat pour garantir que l'offre émane bien de lui.
  • Vendeur (S) : Il prépare la session. Il reçoit les plis sans pouvoir les ouvrir, garantissant la règle du "pli fermé".
  • Autorité (A) : Elle n'intervient qu'à la fin pour le déchiffrement massif, le tri des deux meilleurs prix et la déclaration du vainqueur, empêchant toute fraude de la part du vendeur.

Développement Chronologique

Sprint 1 : Socle & Persistance

01 oct. — 16 oct.
  • Modélisation du domaine (Enchères, Utilisateurs, Objets Data).
  • Développement de l'ORM maison (MapperObjet) et Repository.
  • Initialisation de la base de données Oracle SQL.

Sprint 2 : Architecture Réseau

17 oct. — 13 nov.
  • Implémentation du Routeur Dynamique (dispatching JSON-RPC).
  • Gestion du multithreading serveur et BufferSortie thread-safe.
  • Mise en place des premiers contrôleurs métiers (Enchères, Utilisateurs).

Sprint 3 : Sécurité Fondamentale

14 nov. — 30 nov.
  • Configuration des Sockets SSL/TLS (Client & Serveur).
  • Gestionnaire de clés RSA-4096 avec stockage local sécurisé.
  • Définition du contrat de signature et de chiffrement hybride.

Sprint 4 : Protocole Vickrey

01 déc. — 17 déc.
  • Orchestration du protocole de soumission (Client side automate).
  • Implémentation du Broadcast Vérifié (tri lexicographique).
  • Calcul sécurisé du second prix par l'Autorité côté serveur.

Sprint 5 : Intégration & Audit

18 déc. — 13 janv.
  • Audit de sécurité : Simulation d'attaques sur le broadcast.
  • Gestion des cas d'erreurs critiques et signalement de fraude.
  • Finalisation des interfaces graphiques et tests d'intégration massifs.

Phase 2 : Restructuration & Industrialisation

La seconde phase du projet se concentre sur la robustesse du système et la facilité de déploiement.

1. Conception & Tests à Grande Échelle

L'application a été restructurée selon les meilleures pratiques de conception logicielle. Pour garantir la fiabilité du système sous charge, nous avons mis en œuvre une suite de tests unitaires massifs (JUnit) et des tests d'intégration simulant des centaines d'enchérisseurs simultanés.

2. Déploiement Conteneurisé (Docker)

Pour simplifier l'installation et assurer la reproductibilité de l'environnement, l'intégralité du système (Serveur, Client, Base de données Oracle) est désormais conteneurisée via Docker. Un simple docker-compose up permet de déployer l'infrastructure complète.

Architecture du Serveur

Le serveur est le pivot central du projet. J'en ai conçu l'intégralité du socle technique selon un modèle de haute performance et de sécurité.

1. Dispatching Dynamique & Routage

Le serveur reçoit des requêtes JSON-RPC. Pour éviter un code spaghetti de tests conditionnels (if/else), j'ai mis en place un Routeur Dynamique. Ce dernier identifie le contrôleur et l'action à exécuter à partir du JSON pour invoquer la logique associée via une référence de méthode.

Automatisation Quartz : Le serveur s'appuie depuis la Phase 1 sur le scheduler Quartz pour automatiser l'ouverture et la fermeture des sessions d'enchères à la milliseconde près, garantissant une intégrité temporelle absolue sans intervention humaine.

// Dans Routeur.java - Recherche dynamique de l'action
private static Function<JSONObject, JSONObject> getMethod(JSONObject json) {
    String action = json.get("action").toString();
    String nomController = json.get("controller").toString();

    for (AbstractController controller : controllers) {
        if (controller.getNom().equals(nomController)) {
            if (controller.contientAction(action)) {
                IMethodeControlleur methode = controller.getAction(action);
                return methode::action; // Dispatching via référence de méthode
            }
        }
    }
    return null;
}

Logique : Cette approche découple totalement la couche réseau des contrôleurs métiers. Ajouter une fonctionnalité consiste simplement à enregistrer une méthode dans un contrôleur ; le serveur la reconnaîtra automatiquement sans modification du code source de routage.

2. Gestion Multithread & BufferSortie

Dans un environnement socket, l'envoi de messages est une opération bloquante. J'ai créé la classe BufferSortie pour implémenter un modèle Producteur/Consommateur thread-safe s'appuyant sur des CompletableFuture.

// Dans BufferSortie.java - Synchronisation via Future
public class BufferSortie {
    private static final Map<String, CompletableFuture<JSONObject>> buffers = new ConcurrentHashMap<>();

    /** Appelé pour envoyer la réponse au bon client */
    public static void setBuffer(String id, JSONObject buffer) {
        CompletableFuture<JSONObject> future = buffers.get(id);
        if (future != null) {
            future.complete(buffer); // Produit et réveille le client
        }
    }

    /** Appelé pour attendre le résultat du contrôleur */
    public static JSONObject readBuffer(String id) {
        CompletableFuture<JSONObject> future = buffers.get(id);
        return future.get(); // Bloquant jusqu'au setBuffer
    }
}

Logique : Cette architecture garantit qu'un client avec une connexion lente n'impacte jamais les performances globales du serveur. Le thread métier "dépose" le message et repart immédiatement s'occuper des autres requêtes.

3. Le Moteur de Persistance (ORM)

Sans utiliser de bibliothèque externe, j'ai développé un ORM capable de mapper des graphes d'objets Java complexes vers du JSON, gérant automatiquement les clés primaires et les relations entre tables.

// Dans MapperObjet.java - Détection de cycles
public static TreeMap<String, Object> mapper(AbstractDataObject modele, ArrayList<Object> visites) {
    visites.add(modele);
    // ...
    for (Field champ : champs) {
        Object object = methode.invoke(modele);
        if (!visites.contains(object)) {
            // Sérialisation récursive si l'objet n'a pas été visité
            map.put(nomAttribut, MapperObjet.mapper((AbstractDataObject) object, visites));
        }
    }
    return map;
}

Défi technique : Gérer les cycles (ex: Vente -> Enchère -> Vente). Mon ORM maintient un registre d'objets déjà visités lors de la sérialisation récursive, injectant des références là où une boucle infinie se formerait normalement.

Conception du Client (Architecture Automate)

Abstraction du Protocole

Côté client, la gestion du protocole cryptographique complexe (Vickrey) est isolée dans une interface ProtocoleEnchere. Cette abstraction permet de définir des étapes de communication séquentielles et interchangeables pour la gestion des enchères.

// Dans ProtocoleEnchere.java - Orchestration des étapes
@Override
public void run() {
    // Phase 1 : Soumission de l'enchère
    EnvoiDeEnchere envoiDeEnchere = new EnvoiDeEnchere(prix);
    byte[] chiffreOriginal = envoiDeEnchere.executer(getClient());

    // Phase 2 : Réception du broadcast et vérification
    VerificationBroadcast verificationBroadcast = new VerificationBroadcast(chiffreOriginal, idEnchere);
    Boolean signatureCorrecte = verificationBroadcast.executer(getClient());

    if (!signatureCorrecte) {
        // Signalement d'une fraude détectée
        new ErreurSignatureBroadcast(idEnchere).executer(getClient());
    }
}

Le modèle synchrone du client : Le client suit un automate fini. Il envoie une donnée et attend *précisément* le type de réponse attendu par le protocole (ex: Signature z du serveur). Cette certitude facilite la vérification des preuves cryptographiques à chaque étape.

Comparaison : Sync (Client) vs Event (Serveur)

Le projet force une cohabitation entre deux paradigmes :

  • Client (Sync-like) : Précis, facile à vérifier cryptographiquement, assure que chaque phase est validée avant la suivante. Inconvénient : Moins souple.
  • Serveur (Event-driven) : Réagit aux messages sans connaître l'historique complet. Avantage : Supporte des milliers de connexions simultanées sans blocage.

Le Protocole Vickrey pas à pas (DSS)

Diagramme de Séquence Système du protocole Vickrey

Visualisation du nouveau protocole de sécurité homomorphe implémenté.

Phase 1 : Enchère Homomorphe

L'enchérisseur encode son prix bi et le chiffre via le protocole de Damgård-Jurik : ci = Enc(B^bi ; ri) mod N^s+1. Le serveur (S) recueille ces chiffrés sans pouvoir les lire et calcule le produit homomorphe c = Π ci. Cette propriété permet d'agréger les offres tout en préservant le secret total.

Phase 2 : Ouverture & Autorité

L'Autorité (A) reçoit le produit c, vérifie la signature globale du serveur, et utilise sa clé secrète pour déchiffrer. Grâce à la structure mathématique (1+N)^m du protocole Damgård-Jurik, l'Autorité peut extraire le second prix p2 sans jamais avoir eu accès aux offres individuelles originales.

Annexes Techniques

Le diagramme de classes suivant détaille l'organisation structurelle des objets métiers et de la couche de données.

Diagramme de Classes complet

Contribution & Leadership

Rôle : Product Owner & Lead Architecte.

Impact : Architecture du socle réseau (Sockets SSL/TLS), moteur JSON-RPC et coordination technique de l'équipe.

En tant que Lead Architecte, j'ai conçu le socle système du projet, notamment via la création de la classe Protocole côté client et le développement de la logique de diffusion thread-safe côté serveur. Au-delà de ces fondations réseau, j'ai participé activement à tous les niveaux du cycle de vie : du développement de l'interface utilisateur pour simplifier l'UX du protocole, jusqu'à la collaboration sur les couches de chiffrement RSA. Ma priorité a été d'assurer une intégration fluide entre la robustesse technique du backend et l'expérience utilisateur finale.

Compétences mobilisées

Hard Skills

  • Java & Réseaux : Sockets SSL/TLS, Multithreading, Réflexion.
  • Architectures : Design par automate, patterns Repository et Controller.
  • Cybersécurité : Chiffrement asymétrique RSA-4096 et Signatures numériques.

Soft Skills

  • Product Ownership : Vision long-terme et arbitrage de complexité.
  • Analyse de Risques : Identification des failles potentielles du protocole.
  • Leadership : Pilotage d'une équipe technique vers un objectif de sécurité critique.

Bilan & Perspectives

Privalis a été l'un des défis les plus stimulants de mon cursus, exigeant une rigueur absolue tant sur la théorie cryptographique que sur la pratique de l'architecture distribuée. Le succès de cette plateforme réside dans l'équilibre trouvé entre haute sécurité et fluidité d'utilisation.

Ce projet m'a non seulement permis de consolider mes compétences techniques en Java avancé et en cybersécurité, mais il a aussi renforcé ma capacité à piloter des projets complexes où chaque ligne de code impacte directement l'intégrité globale du système. C'est cette vision "Full-Stack Sécurité" que je souhaite continuer à explorer.