Aller au contenu principal

Sécurité appliquée · L3 · Section 2/5

Cryptographie de base

Progression

Points d’expérience : XPSérie de jours consécutifs : · —Progression du module : — / —compris

#Cryptographie de base

La cryptographie fournit des garanties mathématiques: confidentialité (chiffrement), intégrité et authenticité (MAC, signatures). Ses outils sont des primitives spécialisées; leur sécurité dépend du schéma qui les compose. Les pièges classiques (ECB, nonce réutilisé, clé dérivée d'un mot de passe) sont toujours des erreurs de composition, pas des failles des primitives.

Prérequis

  • Python: manipulation d'octets (bytes) et d'hexadécimal.
  • Notion de clé secrète partagée vs paire clé publique/privée.
  • Section « Principes et modèle de menace » du même module.

Objectifs d'apprentissage

  • Choisir la bonne primitive selon le besoin: hachage, MAC, chiffrement symétrique/asymétrique, signature.
  • Expliquer pourquoi un hachage seul n'authentifie pas, et pourquoi ECB et les nonces réutilisés cassent la confidentialité.
  • Utiliser une bibliothèque de haut niveau (Fernet, NaCl) plutôt que des primitives brutes.

#La bonne primitive pour le bon besoin

BesoinPrimitiveExemple standardCe que ça ne fait PAS
Empreinte détectant la modification accidentelle ou comparer des fichiersHachage (non clé)SHA-256, SHA-3, BLAKE2Authentifier un message, stocker un mot de passe tel quel
Détecter la modification malveillante avec un secret partagéMACHMAC-SHA-256Chiffrer, non-répudiation (le vérificateur peut aussi produire le MAC)
Confidentialité avec secret partagéChiffrement symétrique authentifié (AEAD)AES-GCM, ChaCha20-Poly1305 (via Fernet, NaCl)Distribution de la clé, authenticité de l'expéditeur avant échange
Confidentialité + échange de clés sans secret préalableAsymétriqueX25519, RSA-OAEPChiffrer de gros volumes (lent; on chiffre une clé de session)
Authenticité + non-répudiation avec clé privéeSignatureEd25519, ECDSA, RSA-PSSConfidentialité du message

La colonne de droite est la plus importante: la plupart des incidents viennent d'une primitive utilisée pour un besoin qu'elle ne couvre pas.

#Hachage: qu'est-ce qu'on obtient vraiment

Un hachage cryptographique transforme un message de taille quelconque en empreinte de taille fixe, calcul rapide, mais à sens unique (on ne remonte pas vers le message) et résistant aux collisions (deux messages distincts ont la même empreinte avec une probabilité négligeable).

Deux usages légitimes et un usage fautif:

  • Légitime: vérifier l'intégrité d'un téléchargement (l'empreinte est publiée sur un canal de confiance).
  • Légitime: dédupliquer des contenus, indexer sans stocker l'original.
  • Fautif: stocker des mots de passe avec SHA-256 seul. Un SHA rapide se force par milliards d'essais par seconde sur GPU; il faut un hachage adaptatif salé (Argon2id, bcrypt, scrypt) avec un facteur de travail réglé.

#Démonstration (Python)

Chargement de l’éditeur...

Vérification attendue: 'hello' et 'Hello' donnent des empreintes sans aucun rapport (avalanche), et la longueur de sortie est constante (64 caractères hexadécimaux, soit 256 bits).

#MAC: authentifier avec un secret partagé

Un hachage seul ne détecte que les modifications accidentelles: n'importe qui peut recalculer l'empreinte d'un message falsifié. Un MAC (Message Authentication Code) ajoute une clé secrète: sans elle, la falsification devient indétectable.

Chargement de l’éditeur...

Deux points à retenir du résultat: la vérification du message légitime réussit, celle du message falsifié échoue; et on utilise hmac.compare_digest plutôt que == pour éviter les attaques par mesures de temps.

#Chiffrement symétrique authentifié: Fernet

En pratique, on ne compose pas soi-même AES + mode + IV + MAC. On utilise une construction de haut niveau qui garantit chiffrement et authenticité ensemble. Fernet (bibliothèque cryptography) encapsule AES-128-CBC avec HMAC-SHA-256 sur les données et un vecteur d'initialisation aléatoire inclus dans le jeton.

L'exercice complet: générer une clé, chiffrer, déchiffrer, et observer les échecs (mauvaise clé, jeton altéré).

pythonpython

1from cryptography.fernet import Fernet2import os3 4def generer_cle():5    """Genere une cle Fernet (32 octets base64)."""6    return Fernet.generate_key()7 8def chiffrer_message(message: str, cle: bytes) -> bytes:9    """Chiffre un message avec la cle donnee. IV aleatoire inclus dans le jeton."""10    return Fernet(cle).encrypt(message.encode())11 12def dechiffrer_message(jeton: bytes, cle: bytes) -> str:13    """Dechiffre et verifie l'authenticite. Leve InvalidToken si echec."""14    return Fernet(cle).decrypt(jeton).decode()

Points d'observation: la modification d'un seul octet du jeton provoque un refus (le MAC intégré détecte l'altération), et deux chiffrements du même message produisent des jetons distincts grâce à l'IV aléatoire. C'est précisément ce qui manque aux bricolages maison.

Chargement de l’éditeur...

#Ce qui casse en pratique (et pourquoi)

ECB (Electronic Codebook) chiffre chaque bloc indépendamment avec la même clé: deux blocs clairs identiques donnent deux blocs chiffrés identiques, les motifs transparaissent. C'est le mode par défaut le plus dangereusement naïf; ne jamais l'utiliser pour des données structurées.

Nonce/IV réutilisé. En GCM ou CTR, réutiliser un nonce avec la même clé permet de retrouver le XOR de deux clairs, et en GCM cela divulgue la clé d'authentification. Un nonce de compteur strictement croissant, ou 96 bits aléatoires avec une limite d'usage, évite cela.

Clé dérivée d'un mot de passe avec un simple SHA-256: attaquable par dictionnaire sur GPU. Il faut une fonction de dérivation à facteur de travail (Argon2id, scrypt, PBKDF2 avec itérations élevées).

Chiffrement sans authentification (CBC sans MAC): un attaquant peut tronquer ou décaler des blocs (padding oracle). Toujours préférer un mode authentifié (AEAD: GCM, Poly1305) sauf besoin précis et documenté.

#Exercice corrigé: détecter ECB

On chiffre une image fortement redondante (grosse zone uniforme) en ECB et en mode authentifié. L'objectif: observer que ECB « laisse voir » les motifs, pas le mode sûr.

pythonpython

1# Demonstration: ECB laisse voir les motifs, un mode avec IV ne le permet pas.2# On utilise un chiffrement par bloc deterministe comme stand-in d'AES-ECB3# (meme propriete observable: blocs clairs identiques -> chiffres identiques).4 5def xor(a, b):6    return bytes(x ^ y for x, y in zip(a, b))7 8CLE = b"K" * 169 10def chiffre_bloc_deterministe(bloc):11    # rotation d'un octet puis XOR: fonction deterministe non involutive12    return xor(bloc[1:] + bloc[:1], CLE)13 14blocs_clairs = [b"AAAAAAAAAAAAAAAA"] * 6  # zone uniforme de l'image

La correction s'observe dans les deux booléens: ECB produit des blocs chiffrés identiques pour des blocs clairs identiques; un mode à IV aléatoire ne le permet pas. Transposé à une image, le résultat ECB ressemble à une version bruitée de l'original.

#Quiz

Vous devez garantir qu'un fichier n'a pas été modifié malveillamment, et vous disposez d'un secret partagé avec l'expéditeur. Que choisissez-vous ?
Vous devez garantir qu'un fichier n'a pas été modifié malveillamment, et vous disposez d'un secret partagé avec l'expéditeur. Que choisissez-vous ?