ECB (Electronic Code Book) est le premier mode d'opération défini pour les algorithmes de chiffrement par blocs (AES, 3DES, DES) et le seul à proscrire absolument dans tout déploiement moderne. Sa faille fondamentale : chaque bloc de plaintext est chiffré indépendamment avec la même clé, produisant un ciphertext déterministe qui préserve la structure des données d'entrée. Deux blocs plaintext identiques produisent deux blocs ciphertext identiques — ce qui fuit l'information statistique, permet l'attaque cut-and-paste, rend possible le clustering d'utilisateurs en cas de mots de passe réutilisés (cas emblématique Adobe 2013 : 153 millions de passwords 3DES-ECB exposés). L'illustration canonique est l'image du pingouin Tux chiffrée en ECB qui reste visuellement reconnaissable après chiffrement — démonstration pédagogique reprise dans tous les cours de crypto modernes. Les normes de référence NIST SP 800-38A, FIPS 140-3, ANSSI RGS v2.0, OWASP A02:2021 Cryptographic Failures interdisent ECB pour tout usage applicatif dépassant un bloc unique et imprévisible. Les alternatives correctes 2025 sont les modes AEAD (Authenticated Encryption with Associated Data) : AES-GCM (standard TLS 1.3, NIST SP 800-38D), ChaCha20-Poly1305 (RFC 8439, préféré sur mobile sans accélération hardware), XChaCha20-Poly1305 (nonce 192 bits, adapté aux contextes longue durée). Cet article détaille les 4 failles structurelles d'ECB avec exemples concrets, les cas réels d'exploitation (Adobe 2013, 3DES-ECB banking legacy), les alternatives AEAD recommandées, la détection dans un codebase existant (SAST + analyse ciphertext + entropy), et le plan de migration 2025 pour éliminer ECB sans casser la production. Pour le contexte général du chiffrement symétrique, voir Chiffrement symétrique expliqué et Qu'est-ce que la cryptographie.
1. Qu'est-ce qu'ECB : définition précise
1.1 Le mode de base des block ciphers
Les algorithmes de chiffrement par blocs (AES, 3DES, Blowfish, Twofish) opèrent sur des blocs de taille fixe — 16 octets pour AES, 8 octets pour 3DES et Blowfish. Ils prennent un bloc en entrée + une clé, produisent un bloc de même taille en sortie.
Pour chiffrer un message plus long qu'un bloc, il faut un mode d'opération. ECB est le premier défini par NIST FIPS 81 (1980), aujourd'hui dépublié dans NIST SP 800-38A (2001) qui le décrit avec avertissement.
1.2 Fonctionnement
Fonctionnement ECB — chaque bloc indépendant
─────────────────────────────────────────────
Plaintext : │ P1 │ P2 │ P3 │ P4 │ ...
▼ ▼ ▼ ▼
AES_K AES_K AES_K AES_K ← même clé, même fonction
▼ ▼ ▼ ▼
Ciphertext : │ C1 │ C2 │ C3 │ C4 │ ...
Propriété : C_i = AES_K(P_i) pour tout i
Conséquence : si P_i == P_j alors C_i == C_j
aucun couplage entre les blocsCette structure ultra-simple est précisément le problème.
2. Faille n°1 : leak de structure (le pingouin Tux)
L'illustration la plus célèbre de la faille ECB : chiffrer une image bitmap en ECB.
Expérience reproductible avec Python + Pillow (~30 lignes)
──────────────────────────────────────────────────────────
1. Charger une image PNG/BMP (chaque pixel = quelques octets)
2. Lire les données raw pixel-par-pixel
3. Chiffrer en AES-128-ECB avec une clé random
4. Écrire les ciphertext bytes dans un nouveau bitmap
5. Ouvrir le bitmap résultant
Résultat observé : l'image source reste reconnaissable.
Les zones uniformes (fond noir, fond blanc) produisent des
blocs ciphertext identiques, préservant les contours.
La raison : une image pixel-art de Tux contient des milliers
de blocs de 16 octets identiques (zones noires, zones blanches).
ECB produit des ciphertexts identiques pour ces blocs.
La structure géométrique est préservée.Implication pratique : tout fichier structuré (image, PDF, executable, archive, base de données tabulaire) chiffré en ECB fuite sa structure macro. Un attaquant peut identifier des régions répétées (logos, headers, séparateurs), extraire des patterns statistiques, segmenter le contenu.
3. Faille n°2 : deterministic encryption
Pour une clé donnée, ECB produit toujours le même ciphertext pour un même plaintext. Ce déterminisme est catastrophique dans deux contextes.
3.1 Le leak sur les bases de données
Si tu chiffres les mots de passe d'une base utilisateur en ECB sans salt, deux utilisateurs avec le même mot de passe auront le même ciphertext. Un attaquant voit immédiatement quels comptes partagent un mot de passe — même sans pouvoir les déchiffrer. Combiné à des indices (Adobe 2013 avait des password hints en clair), cela mène à la récupération massive de mots de passe.
Base utilisateur — tableau illustratif
───────────────────────────────────────
user_id | email | password_ciphertext (AES-ECB, base64)
123 | alice@example.com | a8B2Cq... ← même ciphertext
456 | bob@example.com | a8B2Cq... ← = même mot de passe
789 | carol@example.com | ZpLm9r... ← différent
901 | dave@example.com | a8B2Cq... ← encore même mdp
...
Attaquant : "ces 3 comptes utilisent le même mot de passe,
cluster autour du plus faible, cracker un = cracker les trois"3.2 Le leak sur les protocoles réseau
Si un protocole envoie des messages répétés (heartbeats, keep-alive, commands standardisées), ECB produit des ciphertexts identiques. Un attaquant sur le réseau observe les patterns et déduit les commandes échangées.
Exemple concret : SSH avant RFC 4253 (2006) utilisait CBC avec IV prévisible — les patterns facilitent des attaques chosen-plaintext.
4. Faille n°3 : cut-and-paste attacks
ECB n'offre aucune intégrité ni ordre. Un attaquant peut réarranger, dupliquer ou supprimer des blocs ciphertext sans que le déchiffrement ne détecte la manipulation.
4.1 Scénario d'attaque cut-and-paste
Exemple : transfert bancaire chiffré en ECB
────────────────────────────────────────────
Plaintext original (16 blocs) :
[00] FROM_ACCOUNT_____ ← "FROM_ACCOUNT____"
[01] 1234567890_______ ← compte émetteur
[02] TO_ACCOUNT_______ ← "TO_ACCOUNT______"
[03] 9876543210_______ ← compte destinataire
[04] AMOUNT_EUR_______ ← "AMOUNT_EUR______"
[05] 00000000500______ ← 500 €
...
Attaquant observe plusieurs transferts chiffrés en ECB avec
la même clé. Il collecte des ciphertexts.
Manipulation : remplacer le bloc [05] (500 €) par le bloc [05]
d'un autre transfert légitime qui encode 50000 €.
Résultat : le serveur déchiffre un transfert de 50000 € vers le
compte original, car aucun MAC ne valide le lien entre blocs.
Pas de détection possible.L'absence d'authentification est la deuxième couche de faille structurelle d'ECB (partagée avec CBC et CTR sans HMAC). Tout message chiffré sans MAC est malléable.
5. Faille n°4 : pas d'authentification intégrée
Même si on ignorait les failles 1-3, ECB ne garantit que la confidentialité — pas l'intégrité. Un MAC séparé (HMAC-SHA256) doit être appliqué, ce qui introduit :
- Composition risquée : encrypt-then-MAC, MAC-then-encrypt, encrypt-and-MAC ont des propriétés différentes. Les choix mal faits créent des failles (l'ancienne combo SSL/TLS MAC-then-encrypt a été à l'origine de Lucky 13 et BEAST).
- Deux clés à gérer : clé chiffrement + clé HMAC, avec rotation indépendante.
- Double passage : encrypt puis MAC, coûteux en performance.
Les modes AEAD (Authenticated Encryption with Associated Data) règlent ce problème en combinant chiffrement + authentification en un seul passage avec une seule clé.
6. Cas réels documentés d'exploitation ECB
6.1 Adobe 2013 — 153 millions de mots de passe
Octobre 2013. Adobe subit une intrusion qui exfiltre la base utilisateurs. Les mots de passe sont stockés chiffrés en 3DES-ECB (non salés, non hashés) avec une clé partagée. La fuite révèle :
- Clustering direct des comptes avec mots de passe identiques via les ciphertexts identiques.
- Exploitation des password hints (indices) stockés en clair : une fois un cluster identifié, les indices donnent le mot de passe.
- Rétro-analyse : en quelques jours, des millions de mots de passe récupérés par la communauté.
Fuite datée du 3 octobre 2013, confirmée publiquement par Adobe le 4 novembre. Impact durable : les listes de mots de passe Adobe restent citées dans toutes les études password cracking 2014-2024.
6.2 3DES-ECB bancaire legacy
Certains systèmes bancaires historiques (POS terminals, ATM protocols, paiement legacy) utilisent 3DES-ECB pour des PIN blocks. PCI-DSS v4.0 (mars 2025) exige la migration vers AES, avec fin de tolérance 3DES-ECB programmée.
6.3 SSH historique et autres legacy
Plusieurs protocoles réseau ont utilisé ECB dans leurs versions initiales avant corrections : DVB content protection, certains firmwares embedded pre-2010, systèmes SCADA legacy.
7. Les alternatives correctes 2025 — AEAD
Les modes AEAD (Authenticated Encryption with Associated Data) règlent tous les problèmes d'ECB en un seul passage. Trois constructions dominantes.
7.1 AES-GCM (Galois/Counter Mode)
NIST SP 800-38D (2007), standardisé dans TLS 1.3 (RFC 8446, 2018). Propriétés :
- Chiffrement : AES en mode CTR avec un compteur (nonce + counter).
- Authentification : GHASH (multiplication dans GF(2^128)) produit un tag MAC.
- AEAD : plaintext chiffré, plaintext + additional data authentifiés, un tag de 16 octets.
- Nonce unique par message obligatoire — répétition = désastre (key leak possible).
- Performance excellente avec instructions AES-NI (hardware Intel/AMD depuis 2010).
7.2 ChaCha20-Poly1305
RFC 8439 (2018), standardisé TLS 1.3. Propriétés :
- Chiffrement : ChaCha20 stream cipher (Bernstein 2008).
- Authentification : Poly1305 MAC.
- AEAD intégré.
- Performance constante sans hardware AES — préféré sur mobile ARM sans AES-NI, IoT, embedded.
- Résistant aux attaques timing par conception (constant-time implementation naturelle).
7.3 XChaCha20-Poly1305
Extension ChaCha20-Poly1305 avec nonce de 24 octets (192 bits) au lieu de 12.
- Nonce assez large pour permettre la génération aléatoire sans coordination — simplifie massivement la conception d'un schéma applicatif.
- Pas standardisé NIST (utilisé par libsodium, NaCl).
- Recommandé par défaut pour les applications qui n'ont pas besoin de compatibilité TLS stricte.
7.4 Comparaison synthétique
| Mode | AEAD | Nonce | Perf HW | Perf SW | Recommandation 2025 |
|---|---|---|---|---|---|
| ECB | ❌ | Aucun | OK | OK | ❌ Interdit |
| CBC sans HMAC | ❌ | 16 octets | OK | OK | ❌ Déprécié |
| CBC + HMAC-SHA256 | Partiel | 16 octets | Moyen | Moyen | ⚠️ Legacy uniquement |
| CTR sans MAC | ❌ | 16 octets | Excellent | Excellent | ❌ Déprécié |
| AES-GCM | ✅ | 12 octets | Excellent (AES-NI) | Moyen | ✅ Standard TLS 1.3 |
| ChaCha20-Poly1305 | ✅ | 12 octets | N/A | Excellent | ✅ Standard TLS 1.3 mobile |
| XChaCha20-Poly1305 | ✅ | 24 octets | N/A | Excellent | ✅ Recommandé usage applicatif |
8. Code : migration ECB → AEAD
8.1 Python — cryptography (pyca)
# ❌ Code vulnérable à éviter absolument
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
def encrypt_bad(plaintext: bytes, key: bytes) -> bytes:
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
# Note: ECB required padding, pas d'IV — typique pattern vulnérable
padded = plaintext + b"\x00" * (16 - len(plaintext) % 16)
return encryptor.update(padded) + encryptor.finalize()
# ✅ Version correcte 2025 : AES-GCM via cryptography
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
def encrypt_good(plaintext: bytes, key: bytes, associated_data: bytes = b"") -> bytes:
"""Chiffre avec AES-256-GCM. Key = 32 octets, nonce = 12 octets."""
aesgcm = AESGCM(key)
nonce = os.urandom(12) # nonce unique par message
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
return nonce + ciphertext # prépend nonce pour permettre déchiffrement
def decrypt_good(blob: bytes, key: bytes, associated_data: bytes = b"") -> bytes:
aesgcm = AESGCM(key)
nonce = blob[:12]
ciphertext = blob[12:]
return aesgcm.decrypt(nonce, ciphertext, associated_data)8.2 Python — libsodium (PyNaCl) — recommandé
API haute niveau avec XChaCha20-Poly1305 en interne (SecretBox) :
# ✅ Pattern recommandé pour 90% des cas applicatifs — libsodium
from nacl.secret import SecretBox
from nacl.utils import random as nacl_random
# Clé 32 octets, générée via CSPRNG ou lue depuis secrets manager
key = nacl_random(SecretBox.KEY_SIZE)
box = SecretBox(key)
# Chiffrement : nonce auto-généré, tag auth intégré
ciphertext = box.encrypt(b"donnee sensible")
# Déchiffrement : lève CryptoError si tampered
plaintext = box.decrypt(ciphertext)Pas de nonce à gérer manuellement, pas de composition de HMAC. L'API ne laisse aucune place à l'erreur du développeur.
8.3 Go — crypto/cipher standard lib
// ❌ ECB à éviter — Go n'a même pas d'ECB en stdlib (bon signe)
// Les dev qui veulent ECB doivent l'implémenter manuellement :
// https://github.com/golang/go/issues/5597 — refusé par la team Go
// ✅ Version correcte : AES-GCM
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
)
func encrypt(plaintext, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, aesgcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
ciphertext := aesgcm.Seal(nonce, nonce, plaintext, nil)
return ciphertext, nil
}
func decrypt(blob, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(blob) < aesgcm.NonceSize() {
return nil, errors.New("ciphertext too short")
}
nonce, ct := blob[:aesgcm.NonceSize()], blob[aesgcm.NonceSize():]
return aesgcm.Open(nil, nonce, ct, nil)
}La stdlib Go refuse volontairement l'implémentation d'ECB — signal fort de la communauté. Pour la discussion technique, voir issue golang.org/issues/5597.
9. Détection d'ECB dans un codebase existant
9.1 SAST rules Semgrep
# semgrep rule — détection AES-ECB Python/Java/JS
rules:
- id: crypto-ecb-mode-detected
pattern-either:
- pattern: modes.ECB()
- pattern: Cipher.getInstance("AES/ECB/...")
- pattern: crypto.createCipheriv("aes-256-ecb", ...)
- pattern: crypto.createCipheriv("aes-128-ecb", ...)
message: >
Mode ECB détecté. ECB est interdit par OWASP A02:2021, NIST SP 800-38A,
ANSSI RGS v2.0. Migrer vers AES-GCM ou ChaCha20-Poly1305.
Voir /ressources/cryptographie-appliquee/pourquoi-ecb-est-mauvais
severity: ERROR
languages: [python, java, javascript, typescript]
metadata:
cwe: CWE-327
owasp: A02:20219.2 Analyse de ciphertext
Si tu n'as pas accès au code source mais à des ciphertexts, script Python pour détecter les duplications de blocs :
def detect_ecb(ciphertext_b64: str, block_size: int = 16) -> bool:
"""Retourne True si le ciphertext présente des blocs dupliqués suspects."""
import base64
data = base64.b64decode(ciphertext_b64)
blocks = [data[i:i+block_size] for i in range(0, len(data), block_size)]
unique = set(blocks)
# Si duplication > 1% des blocs, ECB fortement suspecté sur données
# avec structure (plaintext non-aléatoire)
duplication_rate = 1 - (len(unique) / len(blocks))
return duplication_rate > 0.01
# Usage : si detect_ecb(ct) == True sur 1000+ ciphertexts variés, ECB confirmé9.3 Outils disponibles
- Semgrep avec règles crypto (communauté + custom).
- CodeQL queries
cryptographic-algorithm-configurationGitHub Security Lab. - Snyk Code, SonarQube Security Hotspots — détection native ECB.
- Trivy misconfig sur IaC (rare mais Kubernetes configs peuvent contenir ECB flags).
10. Plan de migration production — 4 étapes
Pour une organisation avec ECB détecté en prod :
Plan de migration ECB → AEAD — 4 étapes
────────────────────────────────────────
1. AUDIT (1-2 semaines)
├─ SAST scan complet codebase (Semgrep crypto rules)
├─ Analyse ciphertext sur échantillons production
├─ Inventaire des données chiffrées : volume, sensibilité, régulation
└─ Livrable : rapport avec prioritisation P1/P2/P3
2. PRÉPARATION (2-4 semaines)
├─ Génération nouvelles clés AES-256-GCM ou ChaCha20-Poly1305
├─ Provisioning stockage clés (Secrets Manager / KMS cloud)
├─ Implémentation helper lib unifié encrypt/decrypt AEAD
└─ Tests unitaires + intégration
3. MIGRATION DONNÉES (1-8 semaines selon volume)
├─ Stratégie A : re-chiffrer en place (downtime ou write lock)
├─ Stratégie B : dual-read + background migration (online, préféré)
├─ Validation par sampling
└─ Supprimer anciennes clés ECB après migration validée
4. VALIDATION (1-2 semaines)
├─ Audit final : plus aucun ECB dans code + en base
├─ Tests régression fonctionnels
├─ Update documentation sécurité
└─ Post-mortem + lessons learned partagé équipePour le contexte des patterns de secure coding crypto, voir Principes de secure coding (principe #6 Cryptographie haute-niveau). Pour la gestion des clés rotationnées, Secrets management dans le cloud.
Points clés à retenir
- ECB interdit par NIST SP 800-38A, FIPS 140-3, ANSSI RGS v2.0, OWASP A02:2021, PCI-DSS v4.0 pour tout usage applicatif dépassant un bloc unique imprévisible.
- 4 failles structurelles : leak de structure (Tux penguin), deterministic encryption (clustering), cut-and-paste attacks (pas d'ordre), pas d'authentification (malléabilité).
- Cas emblématique : Adobe 2013 — 153M mots de passe 3DES-ECB exposés, récupération massive via clustering + password hints.
- Alternatives AEAD 2025 : AES-GCM (TLS 1.3 standard, excellent avec AES-NI), ChaCha20-Poly1305 (mobile/ARM sans AES-NI), XChaCha20-Poly1305 (nonce 192 bits pour usage applicatif).
- API haute niveau recommandée : libsodium / PyNaCl (SecretBox) qui gère nonce + auth tag automatiquement, élimine les erreurs développeur.
- Détection : SAST Semgrep/CodeQL sur patterns
ECB, analyse ciphertext (duplication rate > 1 %), CodeQLcryptographic-algorithm-configurationqueries. - Impact légal 2025 : RGPD considère ECB = données non-chiffrées (décisions CNIL 2022-2024), notification 72h obligatoire, amendes jusqu'à 4 % CA mondial.
- Migration en 4 étapes : audit → préparation → migration données (dual-read préféré) → validation.
Pour approfondir les primitives cryptographiques, voir Chiffrement symétrique expliqué, Chiffrement asymétrique expliqué, Différence hash vs HMAC vs signature. Pour le contexte TLS qui utilise AEAD en pratique, TLS expliqué simplement. Pour les patterns de secure coding autour de la crypto, Principes de secure coding.







