Chiffrement symétrique
Introduction
Après avoir posé les bases de la cryptographie, entrons dans le vif du sujet avec la première grande famille de techniques de chiffrement : le chiffrement symétrique.
Le chiffrement symétrique est la forme la plus ancienne de chiffrement. C'est celle que l'on utilise intuitivement lorsque l'on pense à un code secret : une même clé sert à la fois à chiffrer et à déchiffrer le message.
Dans cette section, nous allons découvrir :
- Le principe du chiffrement symétrique.
- Ses avantages et ses inconvénients.
- Quelques algorithmes de chiffrement symétrique courants (DES, AES, etc.).
- Les modes opératoires, qui permettent de chiffrer des messages de taille variable.
- La problématique de la gestion des clés.
Commençons par le principe de base du chiffrement symétrique.
Principes et algorithmes (AES, DES)
Le chiffrement symétrique repose sur un principe simple : l'expéditeur et le destinataire partagent une même clé secrète, utilisée à la fois pour chiffrer et déchiffrer les messages.
Principe de base
- Chiffrement : L'expéditeur utilise l'algorithme de chiffrement et la clé secrète pour transformer le texte clair en texte chiffré.
- Transmission : Le texte chiffré est transmis au destinataire via un canal de communication (potentiellement non sécurisé).
- Déchiffrement : Le destinataire utilise le même algorithme de chiffrement et la même clé secrète pour retrouver le texte clair à partir du texte chiffré.
- Le "Texte clair" est chiffré à l'aide de la "Clé secrète" et de l'algorithme de chiffrement, ce qui produit le "Texte chiffré".
- Le "Texte chiffré" est transmis au destinataire.
- Le destinataire reçoit le "Texte chiffré" et le déchiffre en utilisant la même "Clé secrète" et le même algorithme de chiffrement, ce qui permet de retrouver le "Texte clair".
- Simplicité : Le principe est relativement simple à comprendre et à mettre en œuvre.
- Rapidité : Les algorithmes de chiffrement symétrique sont généralement très rapides, ce qui les rend adaptés au chiffrement de grandes quantités de données.
- Gestion des clés : Le principal inconvénient est la nécessité d'échanger la clé secrète de manière sécurisée entre l'expéditeur et le destinataire. Si la clé est interceptée, la confidentialité des communications est compromise.
Algorithmes de chiffrement symétrique courants
Il existe de nombreux algorithmes de chiffrement symétrique, avec des niveaux de sécurité et des performances variables. Voici deux exemples parmi les plus connus :
DES (Data Encryption Standard)
- Développé par : IBM, dans les années 1970.
- Adopté comme standard : Par le gouvernement américain en 1977.
- Taille de clé : 56 bits.
- Taille des blocs : 64 bits.
- Structure : Réseau de Feistel (combinaison de permutations et de substitutions, répétées sur plusieurs tours).
- Sécurité : DES est aujourd'hui considéré comme obsolète et non sécurisé. Sa clé de 56 bits est beaucoup trop courte face à la puissance des ordinateurs modernes (elle peut être cassée par force brute en quelques heures, voire quelques minutes).
DES n'est plus considéré comme sûr. Il ne doit plus être utilisé dans de nouvelles applications.
AES (Advanced Encryption Standard)
- Développé par : Joan Daemen et Vincent Rijmen (Belgique).
- Adopté comme standard : Par le gouvernement américain en 2001, pour remplacer DES.
- Taille de clé : 128, 192 ou 256 bits.
- Taille des blocs : 128 bits.
- Structure : Réseau de substitution-permutation (SPN) (combinaison de substitutions, de permutations et d'opérations XOR, répétées sur plusieurs tours).
- Sécurité : AES est aujourd'hui considéré comme très sûr. Il est largement utilisé dans le monde entier pour protéger les données sensibles.
AES est l'algorithme de chiffrement symétrique à privilégier aujourd'hui. Il offre un excellent niveau de sécurité et de bonnes performances.
Implémentation en Python (exemple avec AES)
Voici un exemple simple d'utilisation de l'algorithme AES en Python, avec la bibliothèque cryptography
:
from cryptography.fernet import Fernet
# Installation de la librairie cryptography (si nécessaire) :
# Ouvrez un terminal ou une invite de commande et tapez :
# pip install cryptography
# ou
# pip3 install cryptography (si vous avez plusieurs versions de Python installées)
# ou si vous êtes sur Linux (Debian/Ubuntu)
# sudo apt-get install python3-cryptography
#
# Si vous utilisez un environnement virtuel (recommandé), activez-le d'abord.
# Génération d'une clé (à faire une seule fois et à conserver précieusement)
key = Fernet.generate_key()
# Création d'un objet Fernet avec la clé
cipher_suite = Fernet(key)
# Texte clair à chiffrer
plaintext = b"Ceci est un message secret." # Le 'b' indique qu'il s'agit d'une chaîne d'octets (bytes)
# Chiffrement du texte clair
ciphertext = cipher_suite.encrypt(plaintext)
print(f"Texte chiffré : {ciphertext}")
# Déchiffrement du texte chiffré
decrypted_text = cipher_suite.decrypt(ciphertext)
print(f"Texte déchiffré : {decrypted_text}")
# Vérification que le texte déchiffré est identique au texte clair
assert decrypted_text == plaintext
Petit exercice:
Dans le code python, nous avons utilisé une méthode pour générer la clé.
- Quelle librairie est utilisée?
- Quelle méthode est utilisée?
- Est-ce une bonne pratique?
Solution
- La librairie cryptographique utilisée est
cryptography
. - La méthode pour générer une clé est
Fernet.generate_key()
. - Oui, c'est une bonne pratique d'utiliser
Fernet.generate_key()
de la librairiecryptography
pour générer une clé pour le chiffrement symétrique (comme avec Fernet).- Cryptographiquement sûre: La fonction
Fernet.generate_key()
est conçue pour générer des clés de manière aléatoire et sécurisée, en utilisant une source d'entropie appropriée fournie par le système d'exploitation. Cela garantit que la clé est imprévisible et difficile à deviner ou à reproduire.
- Cryptographiquement sûre: La fonction
La bibliothèque cryptography
est une bibliothèque Python robuste et facile à utiliser pour la cryptographie. Elle offre une interface de haut niveau (comme Fernet
pour le chiffrement symétrique) et des implémentations de bas niveau d'algorithmes cryptographiques courants.
Modes opératoires (ECB, CBC, CTR)
Les algorithmes de chiffrement symétrique comme AES et DES chiffrent des données par blocs de taille fixe (par exemple, 128 bits pour AES). Mais que se passe-t-il si l'on veut chiffrer un message plus long que la taille d'un bloc, ou de taille variable ? C'est là qu'interviennent les modes opératoires.
Un mode opératoire est une méthode qui permet d'utiliser un algorithme de chiffrement par blocs pour chiffrer des données de taille arbitraire, tout en garantissant la sécurité et en évitant certains problèmes liés à la répétition de blocs.
Un mode opératoire définit comment l'algorithme de chiffrement par blocs est appliqué de manière répétée pour chiffrer un message plus long qu'un seul bloc.
Voici quelques-uns des modes opératoires les plus courants :
ECB (Electronic Codebook)
- Principe : Le message est divisé en blocs de taille fixe, et chaque bloc est chiffré indépendamment avec la même clé.
-
Avantage : Simplicité.
-
Inconvénient majeur : Non sécurisé pour la plupart des applications. Si le même bloc de texte clair apparaît plusieurs fois dans le message, il sera chiffré de la même manière, ce qui révèle des informations sur le contenu du message.
Ne jamais utiliser ECB !Le mode ECB ne doit jamais être utilisé pour chiffrer des données sensibles, car il ne garantit pas une confidentialité suffisante.
- Exemple Prenons l'image d'un pingouin, chiffrons-la avec AES en mode ECB, et visualisons le résultat. Même si l'image est chiffrée, la structure de l'image originale reste visible, car les blocs identiques sont chiffrés de la même manière.

CBC (Cipher Block Chaining)
- Principe : Chaque bloc de texte clair est combiné (XOR) avec le bloc de texte chiffré précédent avant d'être chiffré. Cela introduit une dépendance entre les blocs, ce qui rend le chiffrement plus sûr que le mode ECB. Un vecteur d'initialisation aléatoire est utilisé pour le premier bloc. Le XOR est une opération logique simple mais puissante qui renvoie Vrai uniquement si ses deux entrées sont différentes.
-
Avantages :
- Plus sûr que ECB : les blocs identiques de texte clair ne sont pas chiffrés de la même manière.
- Relativement simple à mettre en œuvre.
-
Inconvénients :
- Le chiffrement est séquentiel (on ne peut pas chiffrer le bloc n avant d'avoir chiffré le bloc n-1), ce qui peut être un problème de performance pour les très grands messages.
- Une erreur dans un bloc chiffré se propage aux blocs suivants lors du déchiffrement.
-
Important
- Le vecteur d'initialisation doit être aléatoire et imprévisible
- Le vecteur d'initialisation n'a pas besoin d'être secret
CTR (Counter)
- Principe : Un compteur (un nombre qui s'incrémente à chaque bloc) est chiffré avec la clé, puis combiné (XOR) avec le bloc de texte clair. Cela transforme l'algorithme de chiffrement par blocs en un algorithme de chiffrement par flot (stream cipher).
-
Avantages :
- Très sûr.
- Parallélisable : on peut chiffrer ou déchiffrer les blocs dans n'importe quel ordre, ce qui permet d'optimiser les performances.
- Pas de propagation d'erreur : une erreur dans un bloc chiffré n'affecte pas les autres blocs.
-
Inconvénient : Nécessite une gestion rigoureuse du compteur (il ne doit jamais être réutilisé avec la même clé).
-
Important
- Le compteur (comme le vecteur d'initialisation dans le CBC) doit être unique pour chaque message chiffré avec la même clé, mais il n'a pas besoin d'être secret.
Le mode CTR est souvent recommandé pour sa sécurité et ses performances. Il est largement utilisé dans les protocoles de communication sécurisés (TLS/SSL, SSH, etc.).
Autres modes opératoires
Il existe de nombreux autres modes opératoires, avec des propriétés différentes :
- CFB (Cipher Feedback)
- OFB (Output Feedback)
- GCM (Galois/Counter Mode) : Un mode authentifié qui combine le chiffrement CTR avec un mécanisme d'authentification (GMAC). GCM est très sûr et performant, et il est de plus en plus utilisé.
Exercice (Python)
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
import os
# 1. Génération de la Clé (Key Generation)
# ----------------------------------------
key = os.urandom(32) # Clé de 256 bits pour AES-256 (32 bytes * 8 bits/byte = 256 bits)
# os.urandom() génère des octets aléatoires cryptographiquement sûrs.
# AES-256 est un algorithme de chiffrement symétrique très courant (la même clé sert à chiffrer et déchiffrer).
# Une clé de 256 bits est considérée comme très sûre.
# 2. Texte Clair (Plaintext)
# ---------------------------
plaintext = b"Ceci est un message secret assez long pour illustrer les modes operatoires."
# Le texte clair est représenté comme une chaîne d'octets (bytes) en Python (préfixe 'b').
# 3. Fonction de Chiffrement (Encryption Function)
# ------------------------------------------------
def encrypt(mode, iv=None):
"""
Chiffre le texte clair en utilisant l'algorithme AES avec un mode de chiffrement spécifié.
Args:
mode: Le mode opératoire (ECB, CBC, CTR, etc.) de la librairie cryptography.
iv: Le vecteur d'initialisation (IV) ou nonce. Si non fourni, il est généré aléatoirement.
Returns:
Un tuple (ciphertext, iv):
ciphertext: Le texte chiffré (bytes).
iv: Le vecteur d'initialisation ou nonce utilisé (bytes). Retourné même si fourni en entrée.
"""
if iv is None:
iv = os.urandom(16) # IV de 128 bits (16 bytes) pour AES. Important pour CBC, CTR; ignoré par ECB.
# L'IV doit être aléatoire et imprévisible pour CBC et CTR.
# 3.1. Création de l'Objet Cipher
cipher = Cipher(algorithms.AES(key), mode(iv), backend=default_backend())
# `Cipher` combine l'algorithme (AES), le mode opératoire, et le backend cryptographique.
# `default_backend()` choisit automatiquement un backend sûr disponible (souvent OpenSSL).
# 3.2. Création de l'Objet Encryptor
encryptor = cipher.encryptor()
# L'objet `encryptor` fournit les méthodes `update()` et `finalize()` pour le chiffrement.
# 3.3. Remplissage PKCS7 (Padding)
padder = padding.PKCS7(algorithms.AES.block_size).padder()
# AES est un chiffrement par blocs (128 bits = 16 octets pour AES).
# Le padding PKCS7 ajoute des octets supplémentaires pour que la longueur du texte clair
# soit un multiple de la taille du bloc. C'est *essentiel* pour ECB et CBC.
padded_data = padder.update(plaintext) + padder.finalize()
# `update()` traite les données, `finalize()` ajoute le padding final.
# 3.4. Chiffrement
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
# `update()` chiffre les données (déjà paddées), `finalize()` traite les derniers blocs.
return ciphertext, iv
# 4. Chiffrement avec Différents Modes
# ------------------------------------
# 4.1. Mode ECB (Electronic Codebook) - À ÉVITER
ciphertext_ecb, _ = encrypt(modes.ECB) # Pas d'IV nécessaire pour ECB (le '_' ignore la valeur de retour)
print(f"ECB: {ciphertext_ecb.hex()}")
# ECB chiffre chaque bloc de 16 octets *indépendamment*.
# C'est le GROS problème d'ECB: des blocs de texte clair identiques donnent des blocs chiffrés identiques.
# Cela révèle des motifs dans le texte clair et est très vulnérable.
# 4.2. Mode CBC (Cipher Block Chaining) - PLUS SÛR
ciphertext_cbc, iv_cbc = encrypt(modes.CBC, os.urandom(16)) # IV généré ici, mais pourrait être passé en argument.
print(f"CBC: {ciphertext_cbc.hex()}, IV: {iv_cbc.hex()}")
# CBC chaîne les blocs: Chaque bloc est XORé avec le bloc chiffré *précédent* avant d'être chiffré.
# L'IV est XORé avec le *premier* bloc.
# Cela cache les motifs et rend CBC beaucoup plus sûr qu'ECB.
# L'IV *doit* être différent à chaque chiffrement du même message avec la même clé.
# 4.3. Mode CTR (Counter) - STREAM CIPHER
ciphertext_ctr, iv_ctr = encrypt(modes.CTR, os.urandom(16)) # Le nonce (IV) est aussi généré ici
print(f"CTR: {ciphertext_ctr.hex()}, Nonce: {iv_ctr.hex()}")
# CTR est fondamentalement différent: il transforme AES en un chiffrement de flux (stream cipher).
# Un compteur (le nonce/IV + un compteur incrémenté) est chiffré avec AES.
# Le résultat est XORé avec le texte clair (pas besoin de padding!).
# Le nonce/IV *doit* être unique pour chaque message chiffré avec la même clé. Il ne doit *jamais* être réutilisé.
# CTR est très rapide et permet le chiffrement/déchiffrement parallèle.
Observez les résultats :
- ECB : Si vous exécutez le code plusieurs fois, vous obtiendrez toujours le même texte chiffré, car la même clé est utilisée pour chaque bloc, et il n'y a pas de vecteur d'initialisation. De plus, si le texte clair contenait des répétitions (par exemple, plusieurs espaces consécutifs), ces répétitions seraient visibles dans le texte chiffré.
- CBC : Chaque exécution produira un texte chiffré différent, même si le texte clair est le même, grâce au vecteur d'initialisation aléatoire.
- CTR : Chaque exécution produira un texte chiffré différent, grâce au compteur (qui est souvent combiné avec un nonce, comme dans l'exemple).
Gestion des clés
La gestion des clés est un aspect crucial de la cryptographie symétrique. C'est souvent le maillon faible des systèmes de chiffrement. Une clé bien protégée garantit la confidentialité des données, tandis qu'une clé compromise rend le chiffrement inutile.
La sécurité du chiffrement symétrique repose entièrement sur le secret de la clé. Si la clé est compromise (volée, divulguée, devinée, etc.), toutes les données chiffrées avec cette clé sont compromises.
Les défis de la gestion des clés
- Génération : Les clés doivent être générées de manière aléatoire et imprévisible, en utilisant une source d'entropie (hasard) de bonne qualité.
- Stockage : Les clés doivent être stockées de manière sécurisée, à l'abri des accès non autorisés.
- Distribution : Les clés doivent être échangées de manière sécurisée entre les parties qui souhaitent communiquer. C'est le problème le plus difficile à résoudre en cryptographie symétrique.
- Rotation : Les clés doivent être changées régulièrement (rotation des clés) pour limiter les risques en cas de compromission.
- Révocation : En cas de compromission (ou de suspicion de compromission) d'une clé, il doit exister un mécanisme pour la révoquer et la remplacer.
Bonnes pratiques pour la génération de clés
-
Utiliser un générateur de nombres aléatoires cryptographiquement sûr (CSPRNG) : Un CSPRNG est conçu pour produire des séquences de bits imprévisibles, adaptées à la génération de clés cryptographiques.
- Exemples (Python) :
os.urandom()
(sur les systèmes Unix-like)secrets.token_bytes()
(à partir de Python 3.6)cryptography.hazmat.primitives.ciphers.algorithms.AES.key_sizes
pour connaître la taille des clés.
- Exemples (Python) :
-
Utiliser une longueur de clé suffisante : Plus la clé est longue, plus elle est difficile à casser par force brute. Pour AES, utiliser des clés de 128, 192 ou 256 bits.
Bonnes pratiques pour le stockage des clés
- Ne jamais stocker les clés en clair dans le code source : Les clés ne doivent jamais être écrites en dur dans le code d'une application.
- Utiliser un système de gestion de clés (KMS) : Un KMS est un système sécurisé (logiciel ou matériel) conçu pour stocker et gérer les clés cryptographiques.
- Exemples :
- HSM (Hardware Security Module) : Un boîtier physique sécurisé qui protège les clés et effectue les opérations cryptographiques.
- Solutions logicielles : HashiCorp Vault, AWS KMS, Azure Key Vault, Google Cloud KMS, etc.
- Exemples :
- Chiffrer les clés : Si les clés doivent être stockées sur un disque, les chiffrer avec une autre clé (key wrapping).
- Contrôler strictement les accès aux clés : Seules les personnes ou les applications autorisées doivent pouvoir accéder aux clés.
Bonnes pratiques pour la distribution des clés
C'est le problème le plus délicat en cryptographie symétrique. Comment Alice et Bob peuvent-ils échanger une clé secrète sans qu'Eve (une personne malveillante) ne puisse l'intercepter ?
- Échange physique : Si Alice et Bob peuvent se rencontrer physiquement, ils peuvent échanger la clé en personne (par exemple, sur une clé USB). C'est la méthode la plus sûre, mais elle n'est pas toujours pratique.
- Utilisation d'un canal sécurisé existant : Si Alice et Bob disposent déjà d'un canal de communication sécurisé (par exemple, une connexion HTTPS), ils peuvent l'utiliser pour échanger la clé.
- Cryptographie asymétrique : Alice peut utiliser la clé publique de Bob pour chiffrer la clé secrète, puis envoyer le résultat à Bob. Seul Bob, qui possède la clé privée correspondante, pourra déchiffrer la clé secrète. C'est la méthode la plus couramment utilisée (nous verrons la cryptographie asymétrique plus loin).
- Échange de clés Diffie-Hellman : Un protocole qui permet à Alice et Bob de se mettre d'accord sur une clé secrète commune sans jamais l'échanger directement (nous verrons ce protocole plus loin).
Bonnes pratiques pour la rotation et la révocation des clés
- Changer les clés régulièrement : Définir une politique de rotation des clés (par exemple, tous les mois, tous les trimestres, etc.) en fonction de la sensibilité des données protégées et des exigences de sécurité.
- Utiliser des clés éphémères : Pour certaines applications (par exemple, les messageries sécurisées), il est possible d'utiliser des clés éphémères, qui ne sont utilisées que pour une seule session de communication.
- Avoir un plan de révocation : Prévoir une procédure pour révoquer une clé compromise et la remplacer par une nouvelle clé. Informer rapidement les parties concernées en cas de compromission.
La gestion des clés est un processus complexe et critique. Il est essentiel de suivre les bonnes pratiques et d'utiliser des outils et des systèmes adaptés pour garantir la sécurité des clés cryptographiques.