Attaques cryptographiques
Introduction
Après avoir exploré les mécanismes de protection offerts par la cryptographie, il est temps de se pencher sur l'autre côté du miroir : les attaques cryptographiques. Comprendre comment les systèmes cryptographiques peuvent être attaqués est essentiel pour concevoir des systèmes plus sûrs et pour utiliser la cryptographie de manière appropriée.
La cryptographie n'est pas une solution miracle qui garantit une sécurité absolue. Tout système cryptographique peut être attaqué, avec plus ou moins de succès. La sécurité d'un système cryptographique dépend de la qualité de l'algorithme, de la longueur des clés, de la mise en œuvre, et de la gestion des clés.
Dans cette section, nous allons découvrir :
- Les différents types d'attaques cryptographiques (attaque par force brute, attaque à texte clair connu, etc.).
- Ce qu'est la cryptanalyse.
- Les facteurs qui influencent la réussite d'une attaque.
Préparez-vous à entrer dans la peau d'un "casseur de codes" ! Mais rassurez-vous, l'objectif est de mieux comprendre les menaces pour mieux s'en protéger.
Types d'attaques
Il existe de nombreux types d'attaques cryptographiques, qui varient en fonction du système ciblé, des informations dont dispose l'attaquant, et des objectifs de l'attaque. Voici quelques exemples, en excluant l'attaque de l'homme du milieu (MitM) que nous avons déjà couverte :
Attaques contre le chiffrement
-
Attaque par force brute :
- Principe : L'attaquant essaie toutes les clés possibles jusqu'à trouver la bonne (celle qui permet de déchiffrer le message).
- Efficacité : Dépend de la longueur de la clé. Plus la clé est courte, plus l'attaque est rapide. Une clé de 56 bits (comme pour DES) peut être cassée en quelques heures, voire quelques minutes, avec des ordinateurs modernes. Une clé de 128 bits (comme pour AES) est hors de portée de la force brute avec la technologie actuelle (et future, selon nos connaissances actuelles).
- Contre-mesures : Utiliser des clés suffisamment longues.
-
Attaque à texte clair connu :
- Principe : L'attaquant dispose d'une ou plusieurs paires de texte clair et de texte chiffré correspondant (obtenues par espionnage, par exemple). Il essaie de trouver la clé (ou des informations sur la clé) à partir de ces paires.
- Efficacité : Dépend de l'algorithme de chiffrement. Certains algorithmes sont plus vulnérables que d'autres à ce type d'attaque.
- Exemple : Pendant la Seconde Guerre mondiale, les cryptanalystes alliés utilisaient des attaques à texte clair connu pour casser les codes générés par la machine Enigma. Ils exploitaient des messages dont ils connaissaient (ou devinaient) une partie du contenu (par exemple, les bulletins météorologiques allemands).
-
Attaque à texte clair choisi :
- Principe : L'attaquant a la possibilité de choisir des textes clairs et d'obtenir les textes chiffrés correspondants (par exemple, s'il a un accès temporaire au système de chiffrement). Il essaie de trouver la clé (ou des informations sur la clé) à partir de ces paires.
- Efficacité : Plus puissante que l'attaque à texte clair connu, car l'attaquant peut choisir des textes clairs spécialement conçus pour faciliter l'analyse.
- Exemple d'attaques à texte clair choisi:
- Attaque par rebond (Related-key attack)
- Attaque par clé choisie
-
Attaque à texte chiffré seulement :
- Principe : L'attaquant ne dispose que de textes chiffrés (interceptés, par exemple). Il essaie de déchiffrer les messages ou de trouver la clé.
- Efficacité : C'est le type d'attaque le plus difficile, mais aussi le plus courant en pratique (car c'est souvent la seule information dont dispose un attaquant).
- Techniques : Analyse statistique, recherche de motifs, exploitation de faiblesses dans l'algorithme ou dans son implémentation.
-
Attaque par canaux auxiliaires (side-channel attack) :
- Principe : L'attaquant n'attaque pas directement l'algorithme de chiffrement, mais son implémentation physique. Il exploite des informations "fuites" par le système pendant le chiffrement ou le déchiffrement :
- Consommation électrique : La consommation électrique d'un processeur varie en fonction des opérations qu'il effectue. En analysant ces variations, un attaquant peut déduire des informations sur la clé ou sur les données traitées.
- Temps d'exécution : Le temps que met un algorithme pour chiffrer ou déchiffrer peut dépendre de la clé ou des données.
- Émissions électromagnétiques : Les composants électroniques émettent des ondes électromagnétiques qui peuvent être captées et analysées.
- Bruit : Dans de rares cas on peut analyser le bruit.
- Efficacité : Ces attaques peuvent être très puissantes, car elles contournent complètement la sécurité théorique de l'algorithme.
- Contre-mesures : Implémentations matérielles et logicielles spécifiques pour réduire les fuites d'informations, techniques de masquage, etc.
- Principe : L'attaquant n'attaque pas directement l'algorithme de chiffrement, mais son implémentation physique. Il exploite des informations "fuites" par le système pendant le chiffrement ou le déchiffrement :
Attaques contre les fonctions de hachage
-
Attaque par force brute (pré-image) :
- Principe : Étant donné un haché , l'attaquant essaie de trouver une entrée telle que .
- Efficacité : Pour une fonction de hachage idéale de bits, la complexité est de opérations. Cela signifie qu'il faut essayer en moyenne entrées différentes avant de trouver une pré-image. Pour SHA-256 (), cette attaque est totalement infaisable avec la technologie actuelle.
-
Recherche de collisions :
- Principe : L'attaquant essaie de trouver deux entrées différentes et telles que .
- Efficacité : Plus facile que l'attaque par force brute (pré-image) grâce au paradoxe des anniversaires.
-
Attaque anniversaire :
- Principe : Exploite le paradoxe des anniversaires : dans un groupe de 23 personnes, il y a plus de 50% de chances que deux personnes aient la même date d'anniversaire. De même, pour une fonction de hachage de bits, il y a une probabilité élevée de trouver une collision après avoir essayé environ entrées.
- Exemple : Si on prend l'exemple d'un haché de 64 bits, il faudra opérations en moyenne pour trouver une collision.
- Efficacité : Permet de trouver des collisions beaucoup plus rapidement qu'avec une attaque par force brute "classique" (qui chercherait une pré-image). Pour une fonction de hachage idéale de bits, la complexité d'une attaque par force brute pour trouver une collision est d'environ opérations (à comparer à pour une attaque par pré-image). Pour SHA-256, la complexité théorique d'une attaque anniversaire est donc de opérations, ce qui reste infaisable en pratique, mais beaucoup plus faible que .
Mots de passe, rainbow tables, et salt
La cryptographie joue un rôle essentiel dans la protection des mots de passe, l'un des mécanismes d'authentification les plus répandus (mais aussi l'un des plus faibles si mal mis en œuvre).
Le problème des mots de passe en clair
Stocker les mots de passe en clair (c'est-à-dire tels quels, sans aucune transformation) dans une base de données est une très mauvaise pratique. En cas de compromission de la base de données (par vol, piratage, fuite, etc.), tous les mots de passe seraient immédiatement exposés, permettant aux attaquants de se connecter aux comptes des utilisateurs.
C'est une règle fondamentale de sécurité.
Hachage des mots de passe
La solution standard est de stocker non pas les mots de passe eux-mêmes, mais leur haché.
-
Principe :
- Lorsqu'un utilisateur crée un compte (ou modifie son mot de passe), le système calcule le haché de son mot de passe en utilisant une fonction de hachage cryptographique (par exemple, SHA-256).
- Seul le haché est stocké dans la base de données. Le mot de passe en clair n'est jamais stocké.
- Lorsqu'un utilisateur se connecte, le système calcule le haché du mot de passe qu'il a saisi et le compare au haché stocké dans la base de données. Si les hachés correspondent, l'utilisateur est authentifié.
-
Avantages :
- Si la base de données est compromise, les mots de passe ne sont pas directement lisibles (car les fonctions de hachage sont à sens unique : il est impossible de retrouver le mot de passe à partir du haché).
- Le système n'a jamais besoin de stocker ou de manipuler les mots de passe en clair.
Attaques par dictionnaire
Même avec le hachage, les mots de passe restent vulnérables à certaines attaques, en particulier si les utilisateurs choisissent des mots de passe faibles (courts, prévisibles, présents dans des dictionnaires de mots de passe courants).
- Principe :
- L'attaquant dispose d'un dictionnaire de mots de passe courants (par exemple, "password", "123456", "azerty", etc.) ou de mots de passe provenant de fuites de données antérieures.
- L'attaquant calcule le haché de chaque mot de passe du dictionnaire avec la même fonction de hachage que celle utilisée par le système ciblé.
- L'attaquant compare les hachés obtenus avec les hachés des mots de passe présents dans la base de données compromise. S'il trouve une correspondance, il a trouvé le mot de passe en clair.
Rainbow tables (tables arc-en-ciel)
Les rainbow tables sont une optimisation des attaques par dictionnaire. Elles permettent de gagner du temps de calcul au prix d'un espace de stockage important.
-
Principe :
- Précalcul : Au lieu de calculer les hachés à la volée lors de l'attaque, l'attaquant précalcule les hachés d'un grand nombre de mots de passe possibles et les stocke dans une table (la "rainbow table").
- Structure de la table : La table est organisée de manière astucieuse pour optimiser la recherche et réduire l'espace de stockage (utilisation de chaînes de hachage et de fonctions de réduction).
- Attaque : Lorsque l'attaquant veut trouver le mot de passe correspondant à un haché donné, il effectue une recherche dans la rainbow table. Cette recherche est beaucoup plus rapide qu'un calcul de haché à la volée.
-
Efficacité : Les rainbow tables peuvent être très efficaces contre les mots de passe faibles et les fonctions de hachage rapides (comme MD5 ou SHA-1). Elles le sont moins contre les fonctions de hachage lentes (comme bcrypt, scrypt, Argon2) et les mots de passe longs et complexes.
Salage (salting)
Le salage (salting) est une technique essentielle pour renforcer la sécurité des mots de passe hachés et contrer les attaques par dictionnaire et par rainbow tables.
-
Principe :
- Lorsqu'un utilisateur crée un compte (ou modifie son mot de passe), le système génère une chaîne de caractères aléatoire, appelée le sel (salt).
- Le sel est concaténé au mot de passe. L'ordre (sel + mot de passe, ou mot de passe + sel) n'a pas d'importance tant qu'il est constant. On peut aussi utiliser une fonction plus complexe qu'une simple concaténation (par exemple, une fonction HMAC).
- Le haché de la combinaison (mot de passe + sel) est calculé et stocké dans la base de données, ainsi que le sel lui-même (en clair). On stocke donc généralement une paire
(sel, haché)
pour chaque utilisateur. - Lors de l'authentification, le système récupère le sel stocké pour cet utilisateur, le concatène au mot de passe saisi par l'utilisateur, calcule le haché de l'ensemble, et compare le résultat au haché stocké.
-
Avantages :
- Unicité : Même si deux utilisateurs choisissent le même mot de passe, leurs hachés seront différents grâce au sel. Cela empêche les attaques par force brute simultanées sur plusieurs comptes.
- Protection contre les attaques par dictionnaire précalculé : Les rainbow tables (ou les simples tables de hachés) précalculées ne sont plus utilisables, car elles ne contiennent pas les hachés des mots de passe combinés avec les sels (qui sont uniques pour chaque mot de passe).
- Ralentissement des attaques par force brute : L'attaquant doit calculer un haché différent pour chaque sel, ce qui ralentit considérablement l'attaque, surtout si la fonction de hachage est lente (comme bcrypt, scrypt ou Argon2).
-
Bonnes pratiques :
- Le sel doit être suffisamment long (au moins 128 bits, idéalement 256 bits ou plus). Plus le sel est long, plus il est difficile pour un attaquant de précalculer des tables.
- Le sel doit être généré par un générateur de nombres aléatoires cryptographiquement sûr (CSPRNG).
- Un sel unique doit être utilisé pour chaque mot de passe. Il ne faut jamais réutiliser le même sel pour plusieurs mots de passe.
-
Exemple (conceptuel) :
Sans salage :
Utilisateur 1 :
Mot de passe : "password"
Haché (SHA-256) : 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
Utilisateur 2 :
Mot de passe : "password"
Haché (SHA-256) : 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8Les deux utilisateurs ont le même haché, ce qui révèle qu'ils ont le même mot de passe. Une attaque par dictionnaire ou par rainbow table trouverait immédiatement le mot de passe "password".
Avec salage :
Utilisateur 1 :
Mot de passe : "password"
Sel : "a1b2c3d4e5f6" (aléatoire)
Haché (SHA-256("a1b2c3d4e5f6" + "password")) : 82633c7439... (différent du haché sans sel)
Utilisateur 2 :
Mot de passe : "password"
Sel : "f6e5d4c3b2a1" (aléatoire, différent du sel de l'utilisateur 1)
Haché (SHA-256("f6e5d4c3b2a1" + "password")) : 39a77b215c... (différent du haché sans sel et du haché de l'utilisateur 1)Même si les deux utilisateurs ont le même mot de passe, leurs hachés sont différents grâce aux sels différents. Une attaque par dictionnaire ou par rainbow table devrait calculer le haché de "password" combiné avec chaque sel possible, ce qui est beaucoup plus coûteux.
-
Exemple (Python avec
bcrypt
, qui gère automatiquement le sel) :
import bcrypt
# Hachage d'un mot de passe avec bcrypt (et génération automatique du sel)
password = b"motdepassesupersecret"
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
print(f"Haché (avec sel) : {hashed_password}")
# bcrypt stocke le sel avec le hash. Le format est:
# $2b$[cost]$[salt][hash]
# Vérification d'un mot de passe
entered_password = b"motdepassesupersecret"
if bcrypt.checkpw(entered_password, hashed_password):
print("Mot de passe correct !")
else:
print("Mot de passe incorrect.")
-
Dans cet exemple,
bcrypt.gensalt()
génère un sel aléatoire.bcrypt.hashpw()
combine le sel avec le mot de passe et calcule le haché. Le sel est inclus dans le résultat (dans le haché lui-même).bcrypt.checkpw()
extrait le sel du haché stocké, le combine avec le mot de passe saisi, calcule le haché et compare. Vous n'avez pas besoin de gérer le sel manuellement,bcrypt
le fait pour vous. -
Exemple Python:
import os
import hashlib
def hash_password(password):
"""Hachage d'un mot de passe avec un sel (exemple à but pédagogique)."""
salt = os.urandom(32) # Génère un sel aléatoire de 32 octets (256 bits)
salted_password = salt + password.encode('utf-8') # Concatène le sel et le mot de passe
hashed_password = hashlib.sha256(salted_password).hexdigest()
return (salt, hashed_password) # Retourne le sel et le haché
def check_password(password, salt, stored_hash):
"""Vérifie un mot de passe par rapport à un sel et un haché stocké."""
salted_password = salt + password.encode('utf-8')
hashed_password = hashlib.sha256(salted_password).hexdigest()
return hashed_password == stored_hash
# Exemple d'utilisation
password = "monmotdepasse"
salt, hashed_password = hash_password(password)
print(f"Sel : {salt.hex()}")
print(f"Haché : {hashed_password}")
# Vérification
if check_password("monmotdepasse", salt, hashed_password):
print("Mot de passe correct !")
else:
print("Mot de passe incorrect.")
if check_password("mauvaismotdepasse", salt, hashed_password):
print("Mot de passe correct !")
else:
print("Mot de passe incorrect.")
-
Dans cet exemple manuel, on génère un sel aléatoire avec
os.urandom()
, on le concatène au mot de passe, puis on calcule le haché avec SHA-256. On retourne à la fois le sel et le haché. Pour vérifier le mot de passe, on refait le même processus (concaténation du sel et calcul du haché) et on compare les hachés. -
Important : Cet exemple manuel est à but pédagogique pour illustrer le principe du salage. Il ne faut pas l'utiliser en production. Utilisez toujours des bibliothèques éprouvées comme
bcrypt
,scrypt
ouArgon2
pour la gestion des mots de passe. Elles implémentent le salage et d'autres mécanismes de sécurité de manière correcte et optimisée.