Exercices - Cryptosystèmes avancés
Applications pratiques des systèmes RSA, DH et ECC
Exercice 1: Génération et analyse de clés RSA
- Générer des clés RSA de différentes tailles
- Analyser leurs structures et propriétés
- Évaluer l'impact de la taille des clés sur les performances
Partie 1: Génération de clés RSA
Utilisez OpenSSL pour générer des clés RSA de 1024, 2048, 3072 et 4096 bits :
openssl genrsa -out rsa_1024.pem 1024
openssl genrsa -out rsa_2048.pem 2048
openssl genrsa -out rsa_3072.pem 3072
openssl genrsa -out rsa_4096.pem 4096
Examinez chaque clé avec la commande :
openssl rsa -in rsa_2048.pem -text -noout
Partie 2: Questions d'analyse
- Identifiez dans l'output de la commande
openssl rsa -text
les valeurs den
,e
,d
,p
etq
. Vérifiez quen = p × q
. - Qu'est-ce que les valeurs
exponent1
,exponent2
etcoefficient
représentent dans la sortie ? Pourquoi sont-elles stockées ? - Mesurez le temps nécessaire pour générer chacune des clés. Comment évolue ce temps en fonction de la taille des clés ?
Partie 3: Benchmark de performances
Évaluez l'impact de la taille des clés sur les performances de chiffrement et de déchiffrement :
# Créez un fichier de test
dd if=/dev/urandom of=testfile bs=1M count=1
# Mesurez le temps pour les opérations avec différentes tailles de clés
time openssl pkeyutl -encrypt -in testfile -inkey rsa_1024.pem -out enc_1024
time openssl pkeyutl -decrypt -in enc_1024 -inkey rsa_1024.pem -out dec_1024
# Répétez avec les autres tailles de clés
Question : Analysez les résultats et expliquez pourquoi RSA est généralement utilisé pour chiffrer de petites quantités de données (comme des clés symétriques) plutôt que des fichiers entiers.
Exercice 2: Implémentation de RSA-OAEP
- Comprendre le schéma de rembourrage OAEP (Optimal Asymmetric Encryption Padding)
- Implémenter le chiffrement et déchiffrement RSA avec OAEP
- Comparer avec RSA "brut" pour identifier les avantages de sécurité
Partie 1: Utilisation de RSA-OAEP avec OpenSSL
Générez une paire de clés RSA et utilisez le schéma OAEP pour chiffrer un message :
# Générer une clé RSA de 2048 bits
openssl genrsa -out private_key.pem 2048
# Extraire la clé publique
openssl rsa -in private_key.pem -pubout -out public_key.pem
# Créer un message test
echo "Message secret à chiffrer avec RSA-OAEP" > message.txt
# Chiffrer avec RSA-OAEP (utilisant SHA-256)
openssl pkeyutl -encrypt -in message.txt -out message.enc \
-inkey public_key.pem -pubin \
-pkeyopt rsa_padding_mode:oaep \
-pkeyopt rsa_oaep_md:sha256
# Déchiffrer avec RSA-OAEP
openssl pkeyutl -decrypt -in message.enc -out message.dec \
-inkey private_key.pem \
-pkeyopt rsa_padding_mode:oaep \
-pkeyopt rsa_oaep_md:sha256
Partie 2: Comparaison avec RSA PKCS#1 v1.5
Répétez l'exercice en utilisant le rembourrage PKCS#1 v1.5 :
# Chiffrer avec PKCS#1 v1.5
openssl pkeyutl -encrypt -in message.txt -out message_pkcs1.enc \
-inkey public_key.pem -pubin \
-pkeyopt rsa_padding_mode:pkcs1
# Déchiffrer avec PKCS#1 v1.5
openssl pkeyutl -decrypt -in message_pkcs1.enc -out message_pkcs1.dec \
-inkey private_key.pem \
-pkeyopt rsa_padding_mode:pkcs1
Partie 3: Questions d'analyse
- Observez et comparez les tailles des fichiers chiffrés avec les deux méthodes. Pourquoi diffèrent-elles ?
- Recherchez et expliquez l'attaque de Bleichenbacher contre PKCS#1 v1.5. Pourquoi OAEP est-il considéré comme plus sûr ?
- Essayez de chiffrer un fichier plus grand que la taille maximale autorisée (environ 190 octets pour RSA-2048 avec OAEP-SHA256). Que se passe-t-il et comment contourner cette limitation dans une application réelle ?
Exercice 3: Mise en œuvre de l'échange de clés Diffie-Hellman
- Comprendre et implémenter l'échange de clés Diffie-Hellman
- Générer et utiliser des paramètres DH
- Établir une clé partagée entre deux parties
Partie 1: Génération des paramètres DH
Générez un ensemble de paramètres Diffie-Hellman (p, g) :
# Générer des paramètres DH (2048 bits)
openssl dhparam -out dhparams.pem 2048
# Examiner les paramètres
openssl dhparam -in dhparams.pem -text -noout
Partie 2: Simulation d'un échange DH
Nous allons simuler l'échange de clés entre Alice et Bob :
# Alice génère sa clé privée et sa clé publique
openssl genpkey -paramfile dhparams.pem -out alice_private.pem
openssl pkey -in alice_private.pem -pubout -out alice_public.pem
# Bob génère sa clé privée et sa clé publique
openssl genpkey -paramfile dhparams.pem -out bob_private.pem
openssl pkey -in bob_private.pem -pubout -out bob_public.pem
# Alice calcule la clé partagée en utilisant sa clé privée et la clé publique de Bob
openssl pkeyutl -derive -inkey alice_private.pem -peerkey bob_public.pem -out alice_shared_secret.bin
# Bob calcule la clé partagée en utilisant sa clé privée et la clé publique d'Alice
openssl pkeyutl -derive -inkey bob_private.pem -peerkey alice_public.pem -out bob_shared_secret.bin
# Vérifier que les secrets partagés sont identiques
cmp alice_shared_secret.bin bob_shared_secret.bin
# Afficher un hachage des secrets pour confirmer visuellement
sha256sum alice_shared_secret.bin bob_shared_secret.bin
Partie 3: Application pratique
Utilisez la clé partagée pour chiffrer un message avec AES-256-CBC :
# Créer un IV (vecteur d'initialisation) aléatoire
openssl rand -out iv.bin 16
# Créer une clé de chiffrement à partir du secret partagé (en prenant les 32 premiers octets)
head -c 32 alice_shared_secret.bin > aes_key.bin
# Alice chiffre un message
echo "Message secret chiffré avec une clé dérivée de DH" > message.txt
openssl enc -aes-256-cbc -in message.txt -out message.enc -K $(xxd -p -c 32 aes_key.bin) -iv $(xxd -p -c 16 iv.bin)
# Bob déchiffre le message
openssl enc -d -aes-256-cbc -in message.enc -out message.dec -K $(xxd -p -c 32 aes_key.bin) -iv $(xxd -p -c 16 iv.bin)
# Vérifier que le message déchiffré correspond à l'original
cat message.dec
Partie 4: Questions d'analyse
- Pourquoi l'échange DH fournit-il une clé partagée sécurisée même sur un canal non sécurisé où un attaquant peut voir toutes les communications ?
- Que se passerait-il si un attaquant pouvait modifier les messages échangés (attaque de l'homme du milieu) ? Comment pourrait-on protéger l'échange DH contre cette attaque ?
- Dans l'exemple ci-dessus, nous avons utilisé directement la clé partagée pour le chiffrement AES. Dans la pratique, pourquoi est-il préférable d'utiliser une fonction de dérivation de clé (KDF) sur le secret partagé ?
Exercice 4: Exploration de la cryptographie sur courbes elliptiques
- Générer et manipuler des clés basées sur les courbes elliptiques
- Utiliser ECDH (Elliptic Curve Diffie-Hellman) pour établir une clé partagée
- Comparer les performances et la taille des clés entre ECC et RSA
Partie 1: Exploration des courbes disponibles
Commencez par explorer les courbes elliptiques disponibles dans OpenSSL :
# Liste des courbes elliptiques supportées
openssl ecparam -list_curves
Partie 2: Génération et analyse de clés EC
Générez des clés pour différentes courbes elliptiques :
# Générer des paramètres et des clés pour secp256r1 (P-256)
openssl ecparam -name prime256v1 -out ec_p256.pem
openssl ecparam -in ec_p256.pem -genkey -noout -out ec_p256_key.pem
openssl ec -in ec_p256_key.pem -text -noout
# Générer des paramètres et des clés pour secp384r1 (P-384)
openssl ecparam -name secp384r1 -out ec_p384.pem
openssl ecparam -in ec_p384.pem -genkey -noout -out ec_p384_key.pem
openssl ec -in ec_p384_key.pem -text -noout
Partie 3: Mise en œuvre d'ECDH
Implémentez un échange de clés ECDH entre Alice et Bob :
# Alice génère sa paire de clés
openssl ecparam -name prime256v1 -genkey -noout -out alice_ec_key.pem
openssl ec -in alice_ec_key.pem -pubout -out alice_ec_pub.pem
# Bob génère sa paire de clés
openssl ecparam -name prime256v1 -genkey -noout -out bob_ec_key.pem
openssl ec -in bob_ec_key.pem -pubout -out bob_ec_pub.pem
# Alice calcule la clé partagée
openssl pkeyutl -derive -inkey alice_ec_key.pem -peerkey bob_ec_pub.pem -out alice_ec_shared.bin
# Bob calcule la clé partagée
openssl pkeyutl -derive -inkey bob_ec_key.pem -peerkey alice_ec_pub.pem -out bob_ec_shared.bin
# Vérifier que les clés partagées sont identiques
cmp alice_ec_shared.bin bob_ec_shared.bin
sha256sum alice_ec_shared.bin bob_ec_shared.bin
Partie 4: Comparaison avec RSA
Comparez les performances et les tailles des clés entre ECC et RSA :
# Générer une clé RSA de 2048 bits (niveau de sécurité ~112 bits)
openssl genrsa -out rsa_2048.pem 2048
# Mesurer le temps pour différentes opérations
time openssl speed rsa2048
time openssl speed ecdhp256
# Comparer les tailles des clés
ls -l *_key.pem
Partie 5: Questions d'analyse
- Comparez la taille des fichiers contenant les clés privées RSA et ECC. Quelle est la différence approximative ?
- Sur la base des résultats du benchmark, comparez les performances des opérations cryptographiques entre RSA et ECC. Quels avantages voyez-vous pour chaque approche ?
- Identifiez au moins trois applications ou protocoles qui utilisent les courbes elliptiques et expliquez pourquoi ECC a été choisi plutôt que RSA dans ces cas.
Exercice 5: Attaques et limitations des cryptosystèmes
- Comprendre les vulnérabilités potentielles des cryptosystèmes
- Simuler et analyser des attaques simplifiées
- Développer des bonnes pratiques pour l'implémentation sécurisée
Partie 1: Attaque par exposant faible sur RSA
Simulez une attaque sur RSA lorsqu'un petit exposant public est utilisé sans rembourrage approprié :
# Générer une clé RSA avec un exposant e=3 (normalement déconseillé)
openssl genrsa -3 -out rsa_weak_exp.pem 1024
# Extraire la clé publique et l'examiner pour vérifier l'exposant
openssl rsa -in rsa_weak_exp.pem -pubout -out rsa_weak_exp_pub.pem
openssl rsa -pubin -in rsa_weak_exp_pub.pem -text -noout
Pour cet exercice, nous allons utiliser Python pour simuler l'attaque. Créez un script rsa_cube_root_attack.py
:
#!/usr/bin/env python3
import math
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import load_pem_public_key
# Charger la clé publique
with open('rsa_weak_exp_pub.pem', 'rb') as f:
public_key = load_pem_public_key(f.read())
# Récupérer le module n et l'exposant e
n = public_key.public_numbers().n
e = public_key.public_numbers().e
print(f"Module n: {n}")
print(f"Exposant e: {e}")
# Message à chiffrer (un petit nombre pour faciliter l'attaque)
m = 42
print(f"Message original: {m}")
# Chiffrement RSA direct (sans rembourrage)
c = pow(m, e, n)
print(f"Message chiffré: {c}")
# Attaque par racine cubique (si e=3)
if e == 3:
# Calcul de la racine cubique de c
m_recovered = round(c ** (1/3))
print(f"Message récupéré par attaque de racine cubique: {m_recovered}")
# Vérification
if pow(m_recovered, e, n) == c:
print("Attaque réussie!")
else:
print("Attaque échouée.")
else:
print(f"Cette attaque ne fonctionne que pour e=3 (actuel: {e})")
Exécutez le script et analysez les résultats :
python3 rsa_cube_root_attack.py
Partie 2: Démonstration de l'attaque de l'homme du milieu
Simulez une attaque de l'homme du milieu sur l'échange Diffie-Hellman :
# Script simulant une attaque MITM sur DH
cat > dh_mitm.sh << 'EOF'
#!/bin/bash
echo "=== Simulation d'une attaque de l'homme du milieu sur Diffie-Hellman ==="
# Générer les paramètres DH
openssl dhparam -out dhparams.pem 2048
echo "Paramètres DH générés"
# Alice génère sa paire de clés
openssl genpkey -paramfile dhparams.pem -out alice_private.pem
openssl pkey -in alice_private.pem -pubout -out alice_public.pem
echo "Alice a généré sa paire de clés"
# Bob génère sa paire de clés
openssl genpkey -paramfile dhparams.pem -out bob_private.pem
openssl pkey -in bob_private.pem -pubout -out bob_public.pem
echo "Bob a généré sa paire de clés"
# Mallory (l'attaquant) génère sa propre paire de clés
openssl genpkey -paramfile dhparams.pem -out mallory_private.pem
openssl pkey -in mallory_private.pem -pubout -out mallory_public.pem
echo "Mallory (attaquant) a généré sa paire de clés"
echo -e "\n=== COMMUNICATION NORMALE (sans attaque) ==="
# Alice et Bob calculent leur clé partagée
openssl pkeyutl -derive -inkey alice_private.pem -peerkey bob_public.pem -out alice_shared_key.bin
openssl pkeyutl -derive -inkey bob_private.pem -peerkey alice_public.pem -out bob_shared_key.bin
# Vérifier que les clés sont identiques
echo "Clés partagées en hexadécimal :"
xxd -p alice_shared_key.bin | head -c 32
echo
xxd -p bob_shared_key.bin | head -c 32
echo
cmp alice_shared_key.bin bob_shared_key.bin &> /dev/null
if [ $? -eq 0 ]; then
echo "Communication sécurisée: Alice et Bob ont la même clé partagée"
else
echo "ERREUR: Les clés partagées diffèrent"
fi
echo -e "\n=== AVEC ATTAQUE DE L'HOMME DU MILIEU ==="
# Mallory intercepte les clés publiques et les remplace par la sienne
echo "Mallory intercepte les communications et substitue sa propre clé publique"
# Alice calcule une clé partagée avec Mallory (croyant communiquer avec Bob)
openssl pkeyutl -derive -inkey alice_private.pem -peerkey mallory_public.pem -out alice_compromised_key.bin
echo "Alice a calculé une clé partagée (avec Mallory)"
# Bob calcule une clé partagée avec Mallory (croyant communiquer avec Alice)
openssl pkeyutl -derive -inkey bob_private.pem -peerkey mallory_public.pem -out bob_compromised_key.bin
echo "Bob a calculé une clé partagée (avec Mallory)"
# Mallory calcule des clés partagées avec Alice et Bob
openssl pkeyutl -derive -inkey mallory_private.pem -peerkey alice_public.pem -out mallory_alice_key.bin
openssl pkeyutl -derive -inkey mallory_private.pem -peerkey bob_public.pem -out mallory_bob_key.bin
echo "Mallory a calculé des clés partagées avec Alice et Bob"
# Vérifier l'attaque
echo "Clés compromises en hexadécimal :"
echo "Alice-Mallory: $(xxd -p alice_compromised_key.bin | head -c 32)"
echo "Mallory-Alice: $(xxd -p mallory_alice_key.bin | head -c 32)"
echo "Bob-Mallory: $(xxd -p bob_compromised_key.bin | head -c 32)"
echo "Mallory-Bob: $(xxd -p mallory_bob_key.bin | head -c 32)"
# Vérifier que Mallory peut décoder les communications
cmp alice_compromised_key.bin mallory_alice_key.bin &> /dev/null
cmp bob_compromised_key.bin mallory_bob_key.bin &> /dev/null
if [ $? -eq 0 ]; then
echo "ATTAQUE RÉUSSIE: Mallory peut intercepter et décoder toutes les communications"
echo "Alice et Bob ont des clés différentes et ne peuvent pas communiquer directement"
cmp alice_compromised_key.bin bob_compromised_key.bin &> /dev/null
if [ $? -ne 0 ]; then
echo "Confirmation: La clé d'Alice ($(xxd -p alice_compromised_key.bin | head -c 8)...) ≠ La clé de Bob ($(xxd -p bob_compromised_key.bin | head -c 8)...)"
fi
else
echo "L'attaque a échoué"
fi
echo -e "\n=== SOLUTION: Authentification des clés publiques ==="
echo "Pour prévenir cette attaque, les clés publiques doivent être authentifiées, par exemple via:"
echo "- Signatures numériques (protocole 'Station-to-Station')"
echo "- Certificats numériques (infrastructure à clé publique)"
echo "- Vérification hors bande (comparaison manuelle d'empreintes)"
EOF
chmod +x dh_mitm.sh
./dh_mitm.sh
Partie 3: Questions d'analyse
- Dans l'attaque par exposant faible, pourquoi un message court peut-il être récupéré alors qu'un message long ne le pourrait pas ? Comment le rembourrage protège-t-il contre cette attaque ?
- Dans l'attaque de l'homme du milieu, comment Mallory parvient-elle à compromettre l'échange de clés sans que Alice et Bob ne s'en aperçoivent ? Comment une authentification mutuelle résolverait-elle ce problème ?
- Décrivez deux autres attaques potentielles contre les cryptosystèmes étudiés dans ce chapitre et leurs contre-mesures respectives.
Navigation
Ressources pour les exercices
Outils nécessaires
- OpenSSL (version 1.1.1 ou supérieure)
- Python 3 avec les packages
cryptography
etgmpy2
- Bash ou tout autre interpréteur de commandes Unix
Documentation utile
Conseils pour les exercices
- Si vous rencontrez des problèmes avec OpenSSL, consultez les messages d'erreur détaillés avec l'option
-text
. - Pour les exercices d'attaque, travaillez avec des valeurs petites et contrôlées pour mieux comprendre les concepts.
- N'hésitez pas à consulter les RFC et standards correspondants pour des détails supplémentaires sur les algorithmes.
- Utilisez des fonctions de hachage cryptographiques pour vérifier l'intégrité des données entre les différentes étapes des exercices.