C3 — Intégrité et authentificationDans le dialogue d’impression, choisissez « Enregistrer au format PDF » comme destination.
Retour

Master 1 · Cryptographie

Cours 3Intégrité et authentification

Garantir qu'un message n'a pas été modifié, et le faire en même temps qu'on le chiffre.

2 chapitres · 10 h de travail estimé

  1. 1. Fonctions de hachage5 h
  2. 2. MAC et chiffrement authentifié5 h

Chapitre 1 · 5 h

Fonctions de hachage

Préimage, seconde préimage, collision ; paradoxe des anniversaires ; Merkle-Damgård et SHA-2 ; éponge et SHA-3 ; extension de longueur.

Une fonction de hachage comprime un message de taille quelconque en une empreinte de taille fixe — 256 bits pour SHA-256. Elle n'a pas de clé, elle est publique, et pourtant elle est partout : signatures, mots de passe, intégrité des fichiers, blockchains, identifiants Git. Sa sécurité ne tient pas au secret mais à trois propriétés de résistance, qu'il faut distinguer avec soin car les attaques et les seuils ne sont pas les mêmes.

Trois résistances, trois seuils

Notons HH la fonction et nn la taille de l'empreinte.

Résistance à la préimage. Étant donné une empreinte yy, il doit être infaisable de trouver un message mm tel que H(m)=yH(m) = y. C'est l'irréversibilité : d'une empreinte, on ne remonte pas au message. Coût de l'attaque générique : 2n2^n.

Résistance à la seconde préimage. Étant donné un message mm, il doit être infaisable d'en trouver un autre mmm' \neq m avec H(m)=H(m)H(m') = H(m). Coût générique : 2n2^n.

Résistance aux collisions. Il doit être infaisable de trouver un couple mmm \neq m' tel que H(m)=H(m)H(m) = H(m'). Ici l'attaquant choisit les deux messages, et cette liberté change tout : coût générique 2n/22^{n/2} seulement.

Ce facteur deux dans l'exposant est le cœur du chapitre. La collision est quadratiquement plus facile que la préimage, et c'est ce qui fixe la taille des empreintes.

Le paradoxe des anniversaires

Dans un groupe de 23 personnes, la probabilité que deux partagent un anniversaire dépasse 50 %. L'intuition proteste — il faudrait sûrement approcher 183, la moitié de 365 — et l'intuition a tort. On ne compare pas une personne aux autres, mais toutes les paires : il y en a (232)=253\binom{23}{2} = 253, assez pour qu'une coïncidence devienne probable.

Le même calcul vaut pour les empreintes. Après environ N\sqrt{N} tirages dans un espace de NN valeurs, une collision devient probable. Pour N=2nN = 2^n, cela fait 2n/22^{n/2} — pas 2n2^n. Une empreinte de nn bits n'offre donc que n/2n/2 bits de résistance aux collisions, tout en gardant nn bits contre la préimage.

Cette asymétrie décide tout. SHA-256 rend 256 bits pour offrir 128 bits contre les collisions : le seuil de sécurité usuel. Un haché de 128 bits ne résisterait qu'à 2642^{64}, aujourd'hui atteignable — c'est ce qui a condamné MD5 (128 bits) et SHA-1 (160 bits, dont la première collision publique, SHAttered, a coûté environ 2632^{63} calculs en 2017).

Vous allez voir la première collision arriver de vos yeux, très en dessous de la taille de l'espace.

Exercice de code

Mesurez où tombe la première collision d'un haché de n bits, puis déduisez la taille de sortie nécessaire pour 128 bits de résistance aux collisions.

Point de départ

// Un haché jouet de n bits, pour observer où tombe la PREMIÈRE collision.
// On tire des messages au hasard, on hache, et on s'arrête à la première
// valeur déjà vue.

function hache(x, bits) {
  // Mélange déterministe, tronqué à 'bits' bits. La qualité importe peu :
  // seule compte la taille de sortie.
  let h = (x * 2654435761) >>> 0;
  h ^= h >>> 15; h = (h * 0x85ebca6b) >>> 0;
  h ^= h >>> 13;
  return h & ((1 << bits) - 1);
}

function premiereCollision(bits) {
  const vus = new Map();
  let essais = 0;
  while (true) {
    const m = (Math.random() * 1e9) | 0;
    const h = hache(m, bits);
    essais++;
    if (vus.has(h)) return essais;
    vus.set(h, m);
  }
}

// ── Observation ───────────────────────────────────────────────────────────
// Pour chaque taille de sortie, moyennez le nombre de tirages avant collision
// sur plusieurs répétitions, et comparez à 2^(bits/2).

console.log("bits | espace 2^bits | collision observée | ~1,25·2^(bits/2)");
for (const bits of [8, 12, 16, 20]) {
  let total = 0;
  const repet = 40;
  for (let i = 0; i < repet; i++) total += premiereCollision(bits);
  const moyenne = Math.round(total / repet);
  const attendu = Math.round(1.25 * Math.sqrt(2 ** bits));
  console.log(
    String(bits).padStart(4),
    String(2 ** bits).padStart(13),
    String(moyenne).padStart(18),
    String(attendu).padStart(17)
  );
}

// ── À COMPLÉTER ───────────────────────────────────────────────────────────
// La collision tombe vers √(espace), pas vers l'espace entier. Écrivez la
// taille de sortie MINIMALE (en bits) pour qu'une attaque par anniversaire
// coûte au moins 2^128, le seuil de sécurité usuel.

const bitsPourResister128 = 0; // à compléter
console.log("Pour 128 bits de résistance aux collisions, il faut une sortie de",
  bitsPourResister128, "bits.");

Solution

// Le nombre de tirages avant collision suit environ 1,25·2^(bits/2) : chaque
// fois qu'on ajoute 2 bits de sortie, il double. C'est le paradoxe des
// anniversaires — √N essais pour N valeurs possibles, pas N.

// Donc pour qu'une attaque coûte 2^128, il faut 2^(bits/2) = 2^128, soit :
const bitsPourResister128 = 256;
console.log("Pour 128 bits de résistance aux collisions, il faut une sortie de",
  bitsPourResister128, "bits.");

// C'est LA raison pour laquelle SHA-256 existe et pourquoi on ne se contente
// pas de SHA-128 : la résistance aux collisions d'un haché de n bits n'est que
// de n/2 bits. Un haché de 128 bits ne résiste qu'à 2^64 — atteignable — ce
// qui a scellé le sort de MD5 (128 bits) et de SHA-1 (160 bits, cassé à 2^63).
//
// Nuance importante : ce n/2 ne vaut QUE pour les collisions. La résistance à
// la préimage et à la seconde préimage reste, elle, de n bits complets — car
// on n'y a pas la liberté de choisir les DEUX messages. D'où l'asymétrie du
// chapitre : SHA-256 offre 128 bits contre les collisions mais 256 contre la
// préimage.

Quiz · 1 question

Une fonction de hachage rend des empreintes de 160 bits (comme SHA-1). Quel est le coût de la meilleure attaque GÉNÉRIQUE par collision ?

  • 2^160, soit la taille de l'empreintetaille pleine
  • 2^80, par le paradoxe des anniversairesracine de l'espace
  • 2^159, la moitié de l'espacemoitié de l'espace

Réponse : Trouver une collision revient à trouver deux tirages égaux parmi N = 2^160 valeurs ; le paradoxe des anniversaires les fait apparaître vers √N = 2^80. C'est pourquoi une empreinte de n bits n'offre que n/2 bits de résistance aux collisions. SHA-1 était donc théoriquement à 2^80, et une attaque dédiée l'a même ramené à 2^63 : la collision SHAttered de 2017. La préimage, elle, resterait à 2^160.

Merkle-Damgård : construire long à partir de court

Comment hacher un message de gigaoctets ? On part d'une fonction de compression ff qui mélange un bloc de message et un état interne, et on l'itère : l'empreinte d'un bloc devient l'état d'entrée du suivant, amorcé par une valeur initiale fixe.

h0=IV,hi=f(hi1,mi),H(m)=hth_0 = \text{IV}, \qquad h_i = f(h_{i-1}, m_i), \qquad H(m) = h_t

C'est la construction Merkle-Damgård, celle de MD5, SHA-1 et SHA-2. Son théorème fondateur est rassurant : si la fonction de compression ff résiste aux collisions, alors la fonction itérée HH y résiste aussi. On ramène la sécurité du tout à celle d'une brique petite et analysable.

Le message est d'abord complété par un rembourrage qui encode sa longueur (le « Merkle-Damgård strengthening ») — détail qui va se révéler à double tranchant.

La faille : l'extension de longueur

Merkle-Damgård a un défaut structurel qui n'est pas une faiblesse de collision mais une fuite d'usage. L'empreinte H(m)H(m) est l'état interne final. Quiconque la connaît peut reprendre le calcul là où il s'est arrêté et calculer H(mpaddingm)H(m \Vert \text{padding} \Vert m') pour un suffixe mm' de son choix — sans connaître mm.

La conséquence est concrète et a été exploitée en production. On croit parfois authentifier un message en publiant H(cleˊmessage)H(\text{clé} \Vert \text{message}) — un « MAC préfixe ». C'est cassé : l'extension de longueur permet de forger l'empreinte d'un message rallongé sans jamais connaître la clé. La leçon vaut d'être retenue avant le chapitre 8 : un haché n'est pas un MAC, et bricoler l'un pour obtenir l'autre échoue. Le chapitre 8 montrera la construction correcte, HMAC, dont la double application ferme précisément cette porte.

Quiz · 1 question

Pourquoi H(clé ‖ message) est-il un mauvais MAC avec une fonction Merkle-Damgård ?

  • Parce que la concaténation révèle la cléfuite de clé
  • Parce que l'attaque par extension de longueur permet de forger H(clé ‖ message ‖ suffixe) sans connaître la cléextension de longueur
  • Parce que la fonction de hachage n'est pas assez rapideperformance

Réponse : L'empreinte Merkle-Damgård EST l'état interne final. En la connaissant, on reprend le calcul et l'on obtient H(clé ‖ message ‖ padding ‖ suffixe) pour n'importe quel suffixe, sans jamais voir la clé : le MAC est forgé sur un message rallongé. C'est pourquoi le MAC correct est HMAC, dont l'imbrication de deux appels de hachage neutralise l'extension. Un haché n'est pas un MAC.

L'éponge : SHA-3, une autre architecture

Après les chutes de MD5 et SHA-1, toutes deux Merkle-Damgård, le NIST a voulu une construction de structure différente pour ne pas mettre tous ses œufs dans le même panier. SHA-3, issu de la fonction Keccak et normalisé en 2015, adopte la construction éponge.

Un grand état interne est divisé en deux parties : le débit rr, par lequel entre et sort le message, et la capacité cc, jamais exposée directement, qui porte la sécurité. On procède en deux temps : la phase d'absorption injecte les blocs du message dans le débit en permutant l'état à chaque fois ; la phase d'essorage en extrait l'empreinte. La sécurité aux collisions vaut c/2c/2.

Le gain est double. D'abord SHA-3 est immunisé contre l'extension de longueur : la capacité n'apparaît jamais dans la sortie, il n'y a donc pas d'état final à prolonger. Ensuite l'éponge est polyvalente — la même permutation produit des empreintes de taille variable (les fonctions extensibles SHAKE), des générateurs pseudo-aléatoires, et des schémas d'authentification.

Un point que la pratique dément souvent : SHA-3 n'a pas rendu SHA-2 obsolète. SHA-2 reste sûr, largement déployé, et souvent plus rapide en logiciel. SHA-3 est une alternative de secours d'architecture indépendante, pas un remplaçant imposé — la même logique d'agilité que le chapitre 14 généralisera.

Ce que la suite en fait

Les trois résistances de ce chapitre sont les hypothèses des chapitres suivants. Le chapitre 8 construit HMAC sur une fonction de hachage et referme l'extension de longueur ; la signature RSA-PSS au chapitre 9 et ECDSA au chapitre 11 hachent le message avant de le signer, et leur sécurité repose directement sur la résistance aux collisions — une collision sur le haché est une signature forgée. Le paradoxe des anniversaires, enfin, reviendra au chapitre 10 sous les traits du rho de Pollard, qui l'exploite pour le logarithme discret.

À retenir

Flashcards · 3 cartes

Pourquoi une empreinte de n bits n'offre-t-elle que n/2 bits de résistance aux collisions ?
Parce que l'attaquant choisit les DEUX messages : par le paradoxe des anniversaires, une collision apparaît après ~2^(n/2) tirages dans un espace de 2^n. La préimage et la seconde préimage, où l'on ne choisit qu'un message, restent à 2^n. D'où SHA-256 : 256 bits de sortie pour 128 bits de sécurité collision.
Qu'est-ce que l'attaque par extension de longueur, et que casse-t-elle ?
L'empreinte Merkle-Damgård est l'état interne final : en la connaissant, on calcule H(m ‖ padding ‖ suffixe) sans connaître m. Elle casse le MAC préfixe H(clé ‖ message), qu'on peut forger sur un message rallongé sans la clé. La parade est HMAC (chapitre 8) ; SHA-3, par construction éponge, y est immunisé.
Qu'apporte la construction éponge de SHA-3 par rapport à Merkle-Damgård ?
Un état séparé en débit r (exposé) et capacité c (secrète, jamais dans la sortie) : pas d'état final à prolonger, donc immunité native à l'extension de longueur, et sécurité collision de c/2. Elle est aussi polyvalente (SHAKE, PRNG). SHA-3 est une alternative d'architecture indépendante, pas un remplaçant de SHA-2, resté sûr.

Chapitre 2 · 5 h

MAC et chiffrement authentifié

HMAC, CMAC, Encrypt-then-MAC et ses alternatives, AEAD, dérivation de clés avec HKDF et Argon2.

Le chapitre 7 a fermé le hachage sur un avertissement : un haché n'est pas un MAC. Ce chapitre construit l'authentification qui manquait, puis la fond avec le chiffrement en un seul objet — le chiffrement authentifié, seul niveau auquel un praticien devrait avoir affaire. Il referme au passage l'oracle de padding du chapitre 4 et le nonce rejoué du chapitre 5.

Ce qu'un MAC garantit

Un code d'authentification de message est une fonction MAC(k,m)\text{MAC}(k, m) qui produit une étiquette courte. Bob, qui partage la clé kk, recalcule l'étiquette et n'accepte le message que si elle correspond. La garantie est l'inforgeabilité : sans la clé, un adversaire ne peut produire une étiquette valide pour un message qu'il n'a pas déjà vue authentifiée, même après en avoir observé beaucoup d'autres. C'est la propriété EUF-CMA que le chapitre 12 formalisera.

Deux limites, déjà posées au chapitre 1, méritent d'être rappelées. Un MAC ne chiffre pas : il protège l'intégrité, pas la confidentialité. Et il n'apporte pas la non-répudiation : la clé étant partagée, Bob peut fabriquer lui-même n'importe quelle étiquette, donc ne peut rien prouver à un tiers. Pour cela il faut une signature, au chapitre 9.

HMAC : le bon usage d'un haché

On a vu qu'assembler naïvement une clé et un haché échoue. HMAC, normalisé et omniprésent (TLS, IPsec, JWT), fait les choses correctement en imbriquant deux appels :

HMAC(k,m)=H((kopad)H((kipad)m))\text{HMAC}(k, m) = H\big((k \oplus \text{opad}) \,\Vert\, H((k \oplus \text{ipad}) \,\Vert\, m)\big)

La passe intérieure, scellée par la clé, produit un état que la passe extérieure hache à nouveau. Le résultat visible est la sortie de la passe extérieure, qui n'est l'état interne d'aucun calcul qu'un attaquant puisse prolonger : l'extension de longueur du chapitre 7 est neutralisée. HMAC a une preuve de sécurité — il est inforgeable dès que la fonction de compression sous-jacente est une bonne primitive — ce qui explique qu'il ait survécu à l'affaiblissement de MD5 et de SHA-1 mieux que ces fonctions elles-mêmes.

Vous allez d'abord forger un MAC préfixe, puis constater que HMAC ne se laisse pas faire.

Exercice de code

Forgez un MAC préfixe H(clé ‖ message) sur un message rallongé, sans connaître la clé, par extension de longueur. Puis constatez pourquoi HMAC résiste.

Point de départ

// Une fonction de hachage Merkle-Damgård jouet. Ce qui compte : son
// empreinte EST son état interne final, comme MD5, SHA-1, SHA-2.

function compression(etat, bloc) {
  let h = etat >>> 0;
  for (let i = 0; i < bloc.length; i++) {
    h = (h ^ bloc.charCodeAt(i)) >>> 0;
    h = (h * 16777619) >>> 0;   // mélange (FNV)
    h = ((h << 13) | (h >>> 19)) >>> 0;
  }
  return h >>> 0;
}
const IV = 0x811c9dc5;

function hache(message, etatInitial = IV) {
  let h = etatInitial;
  for (let i = 0; i < message.length; i += 4) {
    h = compression(h, message.slice(i, i + 4));
  }
  return h >>> 0;
}

// ── Le serveur ────────────────────────────────────────────────────────────
// Clé secrète, inconnue de l'attaquant. Le MAC « préfixe » est H(clé ‖ msg).
const CLE = "s3cr3t--";  // 8 octets, longueur connue de l'attaquant
const macPrefixe = (msg) => hache(CLE + msg);
const verifier = (msg, mac) => macPrefixe(msg) === mac;

// L'attaquant observe un message légitime et son MAC.
const msg = "montant=100&dest=alice";
const mac = macPrefixe(msg);
console.log("message légitime :", JSON.stringify(msg), "MAC =", mac);

// ── À VOUS ────────────────────────────────────────────────────────────────
// But : faire accepter un message RALLONGÉ, sans connaître CLE.
//
// Le MAC observé EST l'état interne après avoir haché (CLE + msg). Pour
// étendre, il suffit de REPRENDRE le hachage à partir de cet état, en y
// injectant votre suffixe. La clé n'intervient jamais.
//
// Ce haché jouet n'ajoute AUCUN rembourrage : il replie les octets un à un.
// L'extension est donc exacte sans rien reconstituer. Sur un vrai
// Merkle-Damgård, l'attaque exige en plus de deviner le « glue padding » que
// la fonction a inséré après (clé ‖ message) — une étape mécanique de plus,
// pas un obstacle, dès qu'on connaît la longueur de la clé.

const suffixe = "&dest=eve";

function forger(macObserve, suffixe) {
  // à compléter : repartir de l'état macObserve et hacher le suffixe
  return 0;
}

const macForge = forger(mac, suffixe);
const messageForge = msg + suffixe;
console.log("message forgé  :", JSON.stringify(messageForge));
console.log("accepté par le serveur ?", verifier(messageForge, macForge));

// ── HMAC résiste ──────────────────────────────────────────────────────────
function hmac(cle, msg) {
  const ipad = [...cle].map((c) => String.fromCharCode(c.charCodeAt(0) ^ 0x36)).join("");
  const opad = [...cle].map((c) => String.fromCharCode(c.charCodeAt(0) ^ 0x5c)).join("");
  return hache(opad + String(hache(ipad + msg)));
}
console.log("HMAC(clé, forgé) recalculé sans la clé ? Impossible : deux passes.");

Solution

function forger(macObserve, suffixe) {
  // macObserve est exactement l'état interne après H(CLE + msg).
  // On poursuit le hachage sur le suffixe, à partir de cet état.
  return hache(suffixe, macObserve);
}

// Le serveur accepte : true. Le message a été rallongé avec « &dest=eve »,
// et son MAC forgé sans jamais connaître CLE.
//
// C'est l'attaque par extension de longueur du chapitre 7, exploitée pour
// forger. Elle marche parce que l'empreinte Merkle-Damgård EST l'état interne,
// et qu'un MAC préfixe expose donc un point de reprise.
//
// HMAC ferme la porte : HMAC(k,m) = H(k⊕opad ‖ H(k⊕ipad ‖ m)). Le résultat
// visible est la sortie de la passe EXTÉRIEURE ; il n'est l'état interne
// d'aucun calcul qu'on puisse prolonger utilement, car étendre exigerait de
// repartir de la passe intérieure, elle-même scellée par la clé. Un haché
// n'est pas un MAC ; HMAC en est un.

CMAC est l'alternative bâtie sur un chiffrement par blocs plutôt que sur un haché : utile quand un composant matériel embarque déjà AES et non SHA-2. Même service, brique différente.

Quiz · 1 question

En quoi la structure imbriquée de HMAC neutralise-t-elle l'attaque par extension de longueur ?

  • Elle chiffre l'empreinte avec la cléchiffrement
  • La valeur publiée est la sortie de la passe extérieure, qui n'est l'état interne d'aucun calcul prolongeabledouble passe
  • Elle tronque l'empreinte pour cacher l'état internetroncature

Réponse : L'extension de longueur exploite le fait que l'empreinte Merkle-Damgård EST l'état interne final. HMAC hache une seconde fois : ce qu'on publie est la sortie de la passe extérieure, prolonger cela n'aide en rien puisqu'il faudrait repartir de la passe intérieure, elle-même scellée par la clé. C'est structurel, pas une troncature ni un chiffrement ajouté.

Assembler chiffrement et intégrité : l'ordre compte

Chiffrement et MAC protègent des choses différentes, et on les veut tous les deux. Reste à savoir dans quel ordre les combiner — trois choix, et un seul est sûr en général.

Encrypt-then-MAC. On chiffre, puis on authentifie le chiffré : MAC(km,c)\text{MAC}(k_m, c). À la réception, on vérifie le MAC avant de déchiffrer. Un chiffré modifié est rejeté immédiatement, sans qu'on regarde jamais son contenu ni son padding — l'oracle du chapitre 4 n'existe plus. C'est l'ordre correct, et c'est celui que TLS a fini par adopter.

MAC-then-Encrypt. On authentifie le clair, puis on chiffre l'ensemble. Le récepteur doit déchiffrer avant de pouvoir vérifier — donc il traite un chiffré potentiellement hostile, et son comportement pendant ce déchiffrement peut fuir. C'est l'ordre historique de TLS, et la porte par laquelle sont entrées les attaques par oracle de padding.

Encrypt-and-MAC. On chiffre le clair et on authentifie le clair séparément. Le MAC du clair peut trahir de l'information sur lui, et rien ne protège l'intégrité du chiffré. À éviter.

La règle tient en une phrase : authentifier le chiffré, et le vérifier avant tout déchiffrement. Elle referme à elle seule la faille du chapitre 4.

Deux clés distinctes, une pour chiffrer, une pour le MAC, sont requises — réutiliser la même clé pour deux usages est une source classique d'interactions imprévues. On les dérive d'un secret maître, comme la section suivante l'explique.

Quiz · 1 question

Quel ordre de composition referme l'attaque par oracle de padding du chapitre 4 ?

  • MAC-then-Encrypt : authentifier le clair puis chiffrerclair puis chiffrer
  • Encrypt-then-MAC : authentifier le chiffré et vérifier le MAC avant de déchiffrerchiffré puis vérifier avant
  • Encrypt-and-MAC : chiffrer et authentifier le clair séparémentles deux sur le clair

Réponse : Avec Encrypt-then-MAC, le récepteur vérifie le MAC du chiffré AVANT de déchiffrer. Un chiffré modifié échoue sur le MAC et n'est jamais déchiffré : le serveur ne révèle donc plus rien sur le padding, et l'oracle du chapitre 4 disparaît. MAC-then-Encrypt, l'ordre historique de TLS, obligeait au contraire à déchiffrer d'abord — c'est par là que l'attaque passait.

AEAD : ne plus jamais composer soi-même

L'expérience a montré qu'assembler chiffrement et MAC à la main est une source d'erreurs sans fin : mauvais ordre, clés partagées, vérification en temps non constant. La réponse moderne est de fournir un objet unique et déjà correct : le chiffrement authentifié avec données associées (AEAD).

Une interface AEAD prend une clé, un nonce, un message et des données associées — des métadonnées authentifiées mais non chiffrées, comme un en-tête de paquet. Elle rend un chiffré et une étiquette en un seul appel, et refuse de déchiffrer si quoi que ce soit a été altéré. Les deux standards sont AES-GCM (AES-CTR plus une authentification dans le corps de Galois) et ChaCha20-Poly1305. Ce sont les seules primitives de chiffrement que TLS 1.3 autorise encore.

L'avertissement du chapitre 5 revient ici avec une gravité accrue. GCM exige un nonce unique par clé, et sa réutilisation ne se contente pas de révéler les clairs comme un flot ordinaire : elle expose la clé d'authentification elle-même, ce qui permet de forger des messages valides, pas seulement de lire. La faute passe de la confidentialité à l'intégrité. C'est la raison des constructions « résistantes au nonce » comme AES-GCM-SIV, qui dégradent gracieusement au lieu de s'effondrer.

Dériver les clés : KDF, HKDF, Argon2

Il reste une question qu'on a repoussée : d'où viennent les clés ? Rarement de l'aléa pur. Souvent d'un secret déjà négocié — le secret partagé d'un Diffie-Hellman, au chapitre 10 — ou d'un mot de passe. Deux situations, deux outils.

À partir d'un secret cryptographique. Le secret d'un échange de clés est aléatoire mais pas directement utilisable : il faut en tirer plusieurs clés indépendantes, de longueur voulue. HKDF procède en deux temps — extract concentre l'entropie en une clé maîtresse uniforme, expand en dérive autant de sous-clés que nécessaire, étiquetées par un contexte. C'est le dériveur de TLS 1.3.

À partir d'un mot de passe. Ici le secret a peu d'entropie et un attaquant peut le deviner par énumération. Une fonction rapide serait un cadeau : elle testerait des milliards de candidats par seconde. On veut au contraire une fonction délibérément lente et coûteuse. Argon2, lauréat de la compétition de 2015, est à coût mémoire : chaque essai exige une grande quantité de RAM, ce qui neutralise l'avantage des GPU et des circuits dédiés, imbattables sur le calcul pur mais limités en mémoire.

Deux réflexes indissociables du stockage de mots de passe. Le sel — une valeur aléatoire unique par utilisateur, stockée en clair — garantit que deux mots de passe identiques ont des empreintes différentes, et surtout rend inutilisable toute table précalculée : c'est la parade au compromis temps-mémoire du chapitre 6. Le facteur de coût doit être réévalué avec le temps, à mesure que le matériel progresse. Ne jamais stocker un mot de passe avec un simple SHA-256 : c'est trop rapide, et c'est exactement l'erreur qu'Argon2 corrige.

Ce que la suite en fait

Le bloc symétrique est complet : on sait chiffrer, authentifier, et dériver des clés — à condition d'en partager déjà une. C'est la question laissée entière : comment deux personnes qui ne se sont jamais rencontrées établissent-elles un secret commun sur un canal public ? La cryptographie asymétrique y répond, et le chapitre 9 l'ouvre avec RSA. HKDF y retrouvera sa place, en aval de l'échange de clés du chapitre 10 et du protocole TLS du chapitre 13.

À retenir

Flashcards · 3 cartes

Pourquoi Encrypt-then-MAC est-il le bon ordre de composition ?
On authentifie le CHIFFRÉ et l'on vérifie le MAC AVANT de déchiffrer. Un chiffré altéré est rejeté sans être déchiffré, donc le serveur ne fuit rien sur son contenu ni son padding : l'oracle du chapitre 4 disparaît. MAC-then-Encrypt oblige à déchiffrer d'abord et a laissé passer les attaques par oracle de padding.
Qu'est-ce qu'un AEAD, et pourquoi la réutilisation de nonce y est-elle pire qu'en flot simple ?
Un chiffrement authentifié avec données associées : clé, nonce, message, métadonnées authentifiées non chiffrées, en un appel qui refuse tout déchiffrement altéré (AES-GCM, ChaCha20-Poly1305). Réutiliser un nonce en GCM n'expose pas que les clairs : la clé d'AUTHENTIFICATION tombe, permettant de forger. La faute passe de la confidentialité à l'intégrité.
Dériver une clé depuis un secret DH ou depuis un mot de passe : pourquoi deux outils différents ?
Un secret DH est de haute entropie mais brut : HKDF l'extrait puis l'étend en sous-clés indépendantes (rapide, c'est voulu). Un mot de passe est de basse entropie et devinable : il faut au contraire une fonction LENTE et à coût mémoire — Argon2 — plus un sel unique par utilisateur qui casse les tables précalculées. Jamais un simple SHA-256 pour un mot de passe.

QCM de synthèse — Bloc II — Intégrité et authentification

Le QCM ci-dessous porte sur l'ensemble du bloc : plusieurs questions relient les leçons entre elles. En cas d'erreur, le bilan indique le chapitre à revoir.

QCM de bloc · 5 questions

Bloc II — Intégrité et authentification

1. Une empreinte de n bits offre n bits contre la préimage mais seulement n/2 contre les collisions. D'où vient cette asymétrie ?

  • La préimage est un problème plus récent, moins étudié
  • Pour une collision, l'attaquant choisit les DEUX messages : le paradoxe des anniversaires les fait apparaître vers 2^(n/2) ; pour la préimage, un seul message est libre, donc 2^n
  • Les collisions ne concernent que Merkle-Damgård

Réponse : La liberté de choisir les deux messages change l'échelle : une collision parmi 2^n valeurs apparaît vers √(2^n) = 2^(n/2) (anniversaires), alors que trouver un antécédent d'une empreinte imposée reste à 2^n. D'où SHA-256 : 256 bits de sortie pour 128 bits de sécurité collision — et la chute de MD5 (128 bits) et SHA-1 (160 bits, collision à 2^63).

2. Pourquoi H(clé ‖ message) est-il un mauvais MAC avec une fonction Merkle-Damgård, et qu'est-ce qui le corrige ?

  • La concaténation révèle la clé ; il faut la chiffrer
  • L'empreinte EST l'état interne final : l'extension de longueur forge H(clé ‖ message ‖ suffixe) sans la clé ; HMAC, par sa double passe, referme la porte
  • La fonction est trop lente ; CMAC la remplace pour la vitesse

Réponse : L'empreinte Merkle-Damgård est l'état interne final : en la connaissant, on reprend le calcul et l'on forge H(clé ‖ message ‖ padding ‖ suffixe) sans jamais voir la clé. HMAC hache deux fois — la valeur publiée est la sortie de la passe extérieure, qu'on ne peut prolonger utilement. Un haché n'est pas un MAC ; SHA-3, par construction éponge, est immunisé nativement.

3. Encrypt-then-MAC est le bon ordre de composition. Quelle attaque d'un bloc PRÉCÉDENT referme-t-il, et comment ?

  • La rencontre au milieu, en doublant la clé du MAC
  • L'oracle de padding (bloc I) : on vérifie le MAC du chiffré AVANT de déchiffrer, donc un chiffré altéré est rejeté sans qu'on regarde son padding
  • Le nonce rejoué, en imposant un nonce aléatoire

Réponse : En authentifiant le chiffré et en vérifiant ce MAC avant tout déchiffrement, un chiffré modifié échoue sur le MAC et n'est jamais déchiffré : le serveur ne fuit plus rien sur le padding, et l'oracle du bloc I disparaît. MAC-then-Encrypt, l'ordre historique de TLS, obligeait à déchiffrer d'abord — c'est par là que l'attaque passait.

4. Réutiliser un nonce en mode GCM est plus grave qu'en chiffrement par flot simple. Pourquoi ?

  • GCM chiffre plus lentement, l'erreur coûte plus cher en temps
  • En flot, la réutilisation révèle les clairs ; en GCM elle expose aussi la CLÉ d'authentification, ce qui permet de FORGER des messages valides
  • GCM n'utilise pas de nonce, donc la question ne se pose pas

Réponse : Un nonce rejoué en flot redonne c₁ ⊕ c₂ = m₁ ⊕ m₂ : perte de confidentialité. En GCM, la même faute expose en plus la clé d'authentification du corps de Galois, permettant de forger des messages valides — la faute passe de la confidentialité à l'intégrité. D'où les modes résistants au nonce comme AES-GCM-SIV, qui dégradent au lieu de s'effondrer.

5. Pour stocker des mots de passe, pourquoi Argon2 avec un sel plutôt qu'un simple SHA-256 ?

  • SHA-256 n'est pas résistant aux collisions
  • Un mot de passe a peu d'entropie : il faut une fonction LENTE et à coût mémoire (Argon2), et un sel unique par utilisateur qui rend inutilisable toute table précalculée
  • SHA-256 ne peut pas hacher un mot de passe court

Réponse : SHA-256 est trop rapide : un attaquant teste des milliards de candidats par seconde. Un mot de passe étant devinable, on veut au contraire une fonction délibérément lente et à coût mémoire (Argon2, qui neutralise GPU et circuits dédiés), plus un sel unique par utilisateur — la parade au compromis temps-mémoire du bloc I, qui casse les tables arc-en-ciel.