Travaux Pratiques - Services de sécurité et OpenSSL
Mise en œuvre pratique des services cryptographiques avec OpenSSL
TP 1: Exploration d'OpenSSL en ligne de commande
- Se familiariser avec les commandes de base d'OpenSSL
- Explorer les capacités cryptographiques d'OpenSSL
- Comprendre l'organisation de la bibliothèque
Partie 1: Découverte de l'environnement
Commencez par explorer les fonctionnalités disponibles dans votre installation d'OpenSSL :
# Vérifier la version d'OpenSSL installée
openssl version -a
# Afficher l'aide générale
openssl help
# Lister les commandes disponibles
openssl list -commands
# Lister les algorithmes de chiffrement supportés
openssl list -cipher-algorithms
# Lister les fonctions de hachage supportées
openssl list -digest-algorithms
# Lister les courbes elliptiques disponibles
openssl list -curves
Partie 2: Manipulation de données en ligne de commande
Testez les opérations de base avec différents formats de données :
# Encodage/décodage Base64
echo "Hello, OpenSSL!" > test.txt
openssl base64 -in test.txt -out test.b64
cat test.b64
openssl base64 -d -in test.b64 -out test_decoded.txt
diff test.txt test_decoded.txt # Vérifier que les fichiers sont identiques
# Génération de nombres aléatoires
openssl rand -hex 16 # Génère 16 octets aléatoires en format hexadécimal
openssl rand -base64 32 # Génère 32 octets aléatoires en format base64
openssl rand -out random.bin 64 # Génère 64 octets aléatoires dans un fichier binaire
# Manipulation de clés
# Générer une clé RSA et l'extraire dans différents formats
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -in key.pem -text -noout # Afficher les composants de la clé
openssl rsa -in key.pem -pubout -out pubkey.pem # Extraire la clé publique
openssl pkey -in key.pem -outform DER -out key.der # Convertir en format DER
Partie 3: Analysez l'entropie et la qualité des nombres aléatoires
Créez un script pour analyser la qualité des nombres aléatoires générés par OpenSSL :
#!/usr/bin/env python3
import subprocess
import matplotlib.pyplot as plt
import numpy as np
from collections import Counter
import os
# Générer des données aléatoires avec OpenSSL
def generate_random_data(size_kb):
"""Génère des données aléatoires avec OpenSSL"""
output_file = f"random_{size_kb}kb.bin"
subprocess.run(["openssl", "rand", "-out", output_file, str(size_kb*1024)])
return output_file
# Analyser les données aléatoires
def analyze_random_data(file_path):
"""Analyse de base des données aléatoires"""
with open(file_path, "rb") as f:
data = f.read()
# Convertir en tableau de bytes
bytes_array = np.frombuffer(data, dtype=np.uint8)
# Statistiques de base
mean = np.mean(bytes_array)
std_dev = np.std(bytes_array)
min_val = np.min(bytes_array)
max_val = np.max(bytes_array)
# Compter la fréquence de chaque valeur (0-255)
counts = Counter(bytes_array)
expected_count = len(bytes_array) / 256 # Valeur attendue pour une distribution uniforme
# Calculer le chi-carré pour tester l'uniformité
chi_square = sum((counts[i] - expected_count)**2 / expected_count for i in range(256))
# Calculer l'entropie de Shannon
probabilities = [count / len(bytes_array) for count in counts.values()]
entropy = -sum(p * np.log2(p) for p in probabilities if p > 0)
max_entropy = np.log2(256) # Entropie maximale pour une distribution uniforme (8 bits)
entropy_percentage = (entropy / max_entropy) * 100
return {
"mean": mean,
"std_dev": std_dev,
"min": min_val,
"max": max_val,
"chi_square": chi_square,
"entropy": entropy,
"entropy_percentage": entropy_percentage,
"counts": counts,
"bytes_array": bytes_array
}
def plot_distribution(counts, title):
"""Trace la distribution des valeurs de bytes"""
plt.figure(figsize=(12, 6))
# Préparer les données
x = list(range(256))
y = [counts[i] for i in range(256)]
# Tracer l'histogramme
plt.bar(x, y, width=1.0, color='skyblue')
plt.axhline(y=sum(y)/256, color='red', linestyle='-', label="Valeur attendue")
plt.title(title)
plt.xlabel("Valeur de l'octet (0-255)")
plt.ylabel("Fréquence")
plt.legend()
plt.grid(alpha=0.3)
plt.savefig(f"{title.replace(' ', '_')}.png")
plt.close()
def main():
# Générer et analyser des données de différentes tailles
sizes = [1, 10, 100] # en KB
results = []
for size in sizes:
print(f"Génération et analyse de {size} KB de données aléatoires...")
file_path = generate_random_data(size)
analysis = analyze_random_data(file_path)
results.append((size, analysis))
# Tracer la distribution
plot_distribution(analysis["counts"], f"Distribution des octets - {size} KB")
# Nettoyage
os.remove(file_path)
# Afficher les résultats
print("\nRésultats de l'analyse:")
print("-" * 80)
print(f"{'Taille (KB)':<12} {'Moyenne':<10} {'Écart-type':<12} {'Chi²':<15} {'Entropie':<10} {'% Entropie':<10}")
print("-" * 80)
for size, analysis in results:
print(f"{size:<12} {analysis['mean']:<10.2f} {analysis['std_dev']:<12.2f} {analysis['chi_square']:<15.2f} {analysis['entropy']:<10.4f} {analysis['entropy_percentage']:<10.2f}%")
print("\nLes résultats détaillés et les graphiques ont été sauvegardés.")
if __name__ == "__main__":
main()
Partie 4: Comparaison des performances des algorithmes
Utilisez l'outil de benchmark intégré dans OpenSSL pour comparer les performances des différents algorithmes :
# Benchmark des fonctions de hachage
openssl speed sha1 sha256 sha512 md5
# Benchmark des algorithmes de chiffrement symétrique
openssl speed -evp aes-128-cbc -evp aes-256-cbc -evp aes-256-gcm -evp chacha20-poly1305
# Benchmark des algorithmes asymétriques
openssl speed rsa2048 rsa4096 ecdsap256 ed25519
Partie 5: Questions d'analyse
- Comment les résultats du benchmark correspondent-ils à la théorie ? Quels algorithmes sont significativement plus rapides que d'autres et pourquoi ?
- Sur la base de l'analyse des données aléatoires, quelle est la qualité du générateur de nombres aléatoires d'OpenSSL ? L'entropie est-elle proche du maximum théorique ?
- Quelles sont les trois commandes OpenSSL que vous trouvez les plus utiles pour des tâches cryptographiques courantes ? Expliquez pourquoi.
- Comparez les performances des algorithmes de chiffrement asymétrique (RSA vs ECC). Quel est le facteur d'accélération approximatif lors de l'utilisation de courbes elliptiques par rapport à RSA pour une sécurité équivalente ?
TP 2: Implémentation de la confidentialité
- Maîtriser les techniques de chiffrement pour garantir la confidentialité
- Comparer différents modes opératoires et leurs propriétés
- Mettre en œuvre un système de chiffrement hybride complet
Partie 1: Chiffrement symétrique avec différents modes opératoires
Testez et comparez différents algorithmes et modes opératoires :
#!/bin/bash
# Ce script teste différents modes de chiffrement symétrique
# Créer un fichier de test
echo "Ce fichier contient des informations confidentielles qui doivent être protégées par chiffrement." > test_file.txt
cat /etc/passwd >> test_file.txt # Ajouter du contenu pour avoir plus de données
# Générer une clé AES-256
openssl rand -out secret.key 32
# Fonction pour chiffrer/déchiffrer avec différents modes
test_cipher_mode() {
local mode=$1
local ivsize=$2
echo "===== Test de $mode ====="
# Générer un IV aléatoire de la taille appropriée
openssl rand -out iv.bin $ivsize
# Chiffrer
time openssl enc -$mode -in test_file.txt -out test_file.$mode \
-K $(xxd -p -c 64 secret.key) \
-iv $(xxd -p -c $(($ivsize * 2)) iv.bin)
# Afficher taille
echo "Taille du fichier chiffré: $(wc -c < test_file.$mode) octets"
# Déchiffrer
time openssl enc -d -$mode -in test_file.$mode -out test_file.$mode.dec \
-K $(xxd -p -c 64 secret.key) \
-iv $(xxd -p -c $(($ivsize * 2)) iv.bin)
# Vérifier que le fichier déchiffré correspond à l'original
if cmp -s test_file.txt test_file.$mode.dec; then
echo "Vérification réussie: Les fichiers sont identiques"
else
echo "ERREUR: Les fichiers diffèrent!"
fi
echo ""
}
# Tester différents modes opératoires
test_cipher_mode "aes-256-cbc" 16
test_cipher_mode "aes-256-ctr" 16
test_cipher_mode "aes-256-ofb" 16
test_cipher_mode "aes-256-gcm" 12 # GCM utilise un nonce de 12 octets
# Test de l'effet d'une modification du fichier chiffré
echo "===== Test de modification du fichier chiffré ====="
# Modifier un bit dans le fichier chiffré CBC
cp test_file.aes-256-cbc test_file.aes-256-cbc.mod
# Modifier l'octet à la position 100
printf '\\x00' | dd of=test_file.aes-256-cbc.mod bs=1 seek=100 count=1 conv=notrunc 2>/dev/null
# Essayer de déchiffrer
echo "Déchiffrement du fichier CBC modifié:"
if openssl enc -d -aes-256-cbc -in test_file.aes-256-cbc.mod -out test_file.aes-256-cbc.mod.dec \
-K $(xxd -p -c 64 secret.key) \
-iv $(xxd -p -c 32 iv.bin) 2>/dev/null; then
echo "Déchiffrement réussi, mais le fichier est probablement corrompu"
# Comparer avec l'original
if cmp -s test_file.txt test_file.aes-256-cbc.mod.dec; then
echo "Étrange: Les fichiers sont identiques malgré la modification"
else
echo "Les fichiers diffèrent, comme prévu"
# Afficher la différence de taille
echo "Taille originale: $(wc -c < test_file.txt) octets"
echo "Taille déchiffrée: $(wc -c < test_file.aes-256-cbc.mod.dec) octets"
fi
else
echo "Déchiffrement échoué - Le mode détecte les modifications"
fi
# Faire de même avec GCM qui a l'authentification intégrée
echo -e "\nDéchiffrement du fichier GCM modifié:"
cp test_file.aes-256-gcm test_file.aes-256-gcm.mod
printf '\\x00' | dd of=test_file.aes-256-gcm.mod bs=1 seek=100 count=1 conv=notrunc 2>/dev/null
# Essayer de déchiffrer
if openssl enc -d -aes-256-gcm -in test_file.aes-256-gcm.mod -out test_file.aes-256-gcm.mod.dec \
-K $(xxd -p -c 64 secret.key) \
-iv $(xxd -p -c 24 iv.bin) 2>/dev/null; then
echo "Déchiffrement réussi (inattendu)"
else
echo "Déchiffrement échoué - Authentification échouée (attendu pour GCM)"
fi
# Nettoyer
rm -f test_file.* secret.key iv.bin
Partie 2: Mise en œuvre d'un chiffrement hybride pour le partage de fichiers
Créez un système complet de chiffrement hybride pour le partage sécurisé de fichiers entre utilisateurs :
#!/bin/bash
# hybridenc.sh - Système de chiffrement hybride pour le partage de fichiers
# Usage
if [ $# -lt 3 ]; then
echo "Usage:"
echo " $0 encrypt file.txt recipient1_pubkey.pem [recipient2_pubkey.pem ...]"
echo " $0 decrypt file.txt.enc private_key.pem"
exit 1
fi
action=$1
file=$2
# Fonction de chiffrement
encrypt_file() {
local input_file=$1
local output_file="${input_file}.enc"
shift
local recipient_keys=("$@")
# 1. Générer une clé AES aléatoire pour le chiffrement du fichier
echo "[+] Génération d'une clé de session AES-256..."
openssl rand -out session.key 32
# 2. Générer un nonce pour ChaCha20-Poly1305
echo "[+] Génération d'un nonce pour ChaCha20-Poly1305..."
openssl rand -out nonce.bin 12
# 3. Chiffrer le fichier avec ChaCha20-Poly1305
echo "[+] Chiffrement du fichier avec ChaCha20-Poly1305..."
openssl enc -chacha20-poly1305 -in "$input_file" -out "$input_file.chacha" \
-K $(xxd -p -c 64 session.key) \
-iv $(xxd -p -c 24 nonce.bin)
# 4. Pour chaque destinataire, chiffrer la clé de session avec sa clé publique
echo "[+] Chiffrement de la clé de session pour chaque destinataire..."
recipient_count=${#recipient_keys[@]}
# Créer un en-tête pour le fichier final
cat > header.txt << EOL
HYBRIDENC-1.0
Recipients: $recipient_count
Cipher: ChaCha20-Poly1305
KeyEnc: RSA-OAEP-SHA256
EOL
# 5. Préparer le fichier final avec l'en-tête
cat header.txt > "$output_file"
echo "" >> "$output_file" # Ligne vide après l'en-tête
# 6. Ajouter le nonce en base64
echo "Nonce: $(base64 -w 0 nonce.bin)" >> "$output_file"
echo "" >> "$output_file"
# 7. Pour chaque destinataire, chiffrer la clé et l'ajouter au fichier
for ((i=0; i/dev/null)
if [ $? -eq 0 ]; then
# C'est un certificat X.509, extraire la clé publique
openssl x509 -in "$recipient" -pubkey -noout > temp_pubkey.pem
pubkey="temp_pubkey.pem"
id_string="$subject"
else
# Supposons que c'est directement une clé publique
pubkey="$recipient"
id_string="Public Key $((i+1))"
fi
# Chiffrer la clé de session avec la clé publique du destinataire
openssl pkeyutl -encrypt -pubin -inkey "$pubkey" \
-in session.key -out "session_key_$i.enc" \
-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256
# Ajouter l'identifiant et la clé chiffrée au fichier
echo "Recipient-$i: $id_string" >> "$output_file"
echo "Key-$i: $(base64 -w 0 "session_key_$i.enc")" >> "$output_file"
echo "" >> "$output_file"
# Nettoyage
[ -f "temp_pubkey.pem" ] && rm -f "temp_pubkey.pem"
done
# 8. Ajouter les données chiffrées en base64
echo "Data:" >> "$output_file"
base64 -w 76 "$input_file.chacha" >> "$output_file"
# 9. Nettoyage
rm -f session.key nonce.bin "$input_file.chacha" header.txt session_key_*.enc
echo "[+] Fichier chiffré créé: $output_file"
}
# Fonction de déchiffrement
decrypt_file() {
local input_file=$1
local output_file="${input_file%.enc}" # Enlever l'extension .enc
local private_key=$2
echo "[+] Analyse du fichier chiffré..."
# 1. Vérifier le format du fichier
local header=$(head -n 1 "$input_file")
if [[ "$header" != "HYBRIDENC-1.0" ]]; then
echo "[-] Format de fichier non reconnu!"
exit 1
fi
# 2. Extraire le nonce
local nonce_line=$(grep -A 1 "Nonce:" "$input_file" | tail -n 1)
echo "$nonce_line" | base64 -d > nonce.bin
# 3. Trouver et essayer de déchiffrer les clés de session
local key_lines=$(grep -n "Key-" "$input_file")
local data_line=$(grep -n "Data:" "$input_file" | cut -d: -f1)
# 4. Extraire et déchiffrer les données
tail -n +$((data_line + 1)) "$input_file" | base64 -d > data.chacha
# 5. Essayer chaque clé de session chiffrée
local success=0
local key_id=0
while IFS= read -r line; do
if [[ "$line" =~ Key-([0-9]+):\ (.*) ]]; then
key_id=${BASH_REMATCH[1]}
key_data=${BASH_REMATCH[2]}
echo "[+] Essai de déchiffrement avec la clé $key_id..."
echo "$key_data" | base64 -d > session_key.enc
if openssl pkeyutl -decrypt -inkey "$private_key" \
-in session_key.enc -out session.key \
-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 2>/dev/null; then
echo "[+] Clé de session déchiffrée avec succès!"
# 6. Déchiffrer les données avec la clé de session
if openssl enc -d -chacha20-poly1305 -in data.chacha -out "$output_file" \
-K $(xxd -p -c 64 session.key) \
-iv $(xxd -p -c 24 nonce.bin) 2>/dev/null; then
echo "[+] Fichier déchiffré avec succès: $output_file"
success=1
break
else
echo "[-] Échec du déchiffrement des données. La clé de session peut être correcte, mais le fichier est corrompu."
fi
fi
fi
done < <(grep "Key-" "$input_file")
# 7. Vérifier si le déchiffrement a réussi
if [ $success -eq 0 ]; then
echo "[-] Échec du déchiffrement. Aucune des clés de session n'a pu être déchiffrée avec la clé privée fournie."
echo "[-] Assurez-vous d'utiliser la bonne clé privée."
rm -f "$output_file" 2>/dev/null
fi
# 8. Nettoyage
rm -f nonce.bin session_key.enc session.key data.chacha 2>/dev/null
return $((1 - success))
}
# Exécuter l'action appropriée
case "$action" in
encrypt)
shift 2 # Ignorer les deux premiers arguments (action et fichier)
encrypt_file "$file" "$@"
;;
decrypt)
private_key=$3
decrypt_file "$file" "$private_key"
;;
*)
echo "Action non reconnue. Utilisez 'encrypt' ou 'decrypt'."
exit 1
;;
esac
Pour tester ce script, créez des clés pour différents utilisateurs :
# Générer des clés pour Alice
openssl genpkey -algorithm RSA -out alice_private.pem -pkeyopt rsa_keygen_bits:2048
openssl pkey -in alice_private.pem -pubout -out alice_public.pem
# Générer des clés pour Bob
openssl genpkey -algorithm RSA -out bob_private.pem -pkeyopt rsa_keygen_bits:2048
openssl pkey -in bob_private.pem -pubout -out bob_public.pem
# Créer un fichier de test
echo "Ce message est destiné à Alice et Bob." > secret_message.txt
# Chiffrer pour Alice et Bob
./hybridenc.sh encrypt secret_message.txt alice_public.pem bob_public.pem
# Alice déchiffre le message
./hybridenc.sh decrypt secret_message.txt.enc alice_private.pem
# Bob déchiffre le message
./hybridenc.sh decrypt secret_message.txt.enc bob_private.pem
Partie 3: Benchmark du chiffrement pour différentes tailles de fichiers
Créez un script pour évaluer les performances de différents algorithmes de chiffrement selon la taille des données :
#!/bin/bash
# benchmark_crypto.sh - Compare les performances de différents algorithmes
# Liste des algorithmes à tester
ALGORITHMS=(
"aes-128-cbc"
"aes-256-cbc"
"aes-128-gcm"
"aes-256-gcm"
"chacha20"
"chacha20-poly1305"
)
# Tailles de fichiers à tester (en Mo)
SIZES=(1 10 50 100)
# Générer une clé et un IV pour tous les tests
openssl rand -out test.key 32
openssl rand -out test.iv 16
# Créer un répertoire pour les résultats
mkdir -p benchmark_results
# Fonction pour créer un fichier de test de taille spécifiée
create_test_file() {
local size_mb=$1
local output_file="test_${size_mb}MB.dat"
# Créer un fichier avec des données aléatoires
dd if=/dev/urandom of="$output_file" bs=1M count="$size_mb" 2>/dev/null
echo "$output_file"
}
# Fonction pour exécuter le benchmark d'un algorithme
benchmark_algorithm() {
local algorithm=$1
local input_file=$2
local output_file="${input_file}.${algorithm}"
local iv_size=16
# Ajuster la taille d'IV pour GCM (qui utilise un nonce de 12 octets)
if [[ "$algorithm" == *"-gcm" || "$algorithm" == *"-poly1305" ]]; then
iv_size=12
fi
# Mesurer le temps de chiffrement
local start_time=$(date +%s.%N)
openssl enc -"$algorithm" -in "$input_file" -out "$output_file" \
-K $(xxd -p -c 64 test.key) \
-iv $(xxd -p -c $((iv_size * 2)) test.iv) 2>/dev/null
local end_time=$(date +%s.%N)
local encrypt_time=$(echo "$end_time - $start_time" | bc)
# Mesurer le temps de déchiffrement
start_time=$(date +%s.%N)
openssl enc -d -"$algorithm" -in "$output_file" -out "$output_file.dec" \
-K $(xxd -p -c 64 test.key) \
-iv $(xxd -p -c $((iv_size * 2)) test.iv) 2>/dev/null
end_time=$(date +%s.%N)
local decrypt_time=$(echo "$end_time - $start_time" | bc)
# Vérifier l'intégrité
if cmp -s "$input_file" "$output_file.dec"; then
local integrity="OK"
else
local integrity="FAILED"
fi
# Nettoyer
rm -f "$output_file" "$output_file.dec"
# Retourner les résultats
echo "$algorithm,$encrypt_time,$decrypt_time,$integrity"
}
# Fonction principale
main() {
# Créer un fichier CSV pour les résultats
echo "size_mb,algorithm,encrypt_time,decrypt_time,integrity" > benchmark_results/results.csv
# Exécuter les benchmarks pour chaque taille
for size in "${SIZES[@]}"; do
echo "Testing file size: $size MB"
# Créer un fichier de test
test_file=$(create_test_file "$size")
# Tester chaque algorithme
for algorithm in "${ALGORITHMS[@]}"; do
echo " Benchmarking $algorithm..."
result=$(benchmark_algorithm "$algorithm" "$test_file")
echo "$size,$result" >> benchmark_results/results.csv
done
# Nettoyer
rm -f "$test_file"
done
echo "Benchmark complete. Results saved to benchmark_results/results.csv"
# Si Python est disponible, générer un graphique
if command -v python3 &> /dev/null; then
echo "Generating plots with Python..."
python3 - <<PYTHON_EOF
import pandas as pd
import matplotlib.pyplot as plt
import os
# Lire les résultats
df = pd.read_csv('benchmark_results/results.csv')
# Créer un dossier pour les graphiques
os.makedirs('benchmark_results/plots', exist_ok=True)
# Graphique pour le temps de chiffrement
plt.figure(figsize=(12, 6))
for algo in df['algorithm'].unique():
data = df[df['algorithm'] == algo]
plt.plot(data['size_mb'], data['encrypt_time'], marker='o', label=algo)
plt.title('Temps de chiffrement selon la taille du fichier')
plt.xlabel('Taille du fichier (Mo)')
plt.ylabel('Temps (secondes)')
plt.grid(True, alpha=0.3)
plt.legend()
plt.savefig('benchmark_results/plots/encrypt_time.png')
# Graphique pour le temps de déchiffrement
plt.figure(figsize=(12, 6))
for algo in df['algorithm'].unique():
data = df[df['algorithm'] == algo]
plt.plot(data['size_mb'], data['decrypt_time'], marker='o', label=algo)
plt.title('Temps de déchiffrement selon la taille du fichier')
plt.xlabel('Taille du fichier (Mo)')
plt.ylabel('Temps (secondes)')
plt.grid(True, alpha=0.3)
plt.legend()
plt.savefig('benchmark_results/plots/decrypt_time.png')
plt.close()
# Calcul du débit en Mo/s
df['encrypt_throughput'] = df['size_mb'] / df['encrypt_time']
df['decrypt_throughput'] = df['size_mb'] / df['decrypt_time']
# Graphique pour le débit de chiffrement
plt.figure(figsize=(12, 6))
for algo in df['algorithm'].unique():
data = df[df['algorithm'] == algo]
plt.plot(data['size_mb'], data['encrypt_throughput'], marker='o', label=algo)
plt.title('Débit de chiffrement selon la taille du fichier')
plt.xlabel('Taille du fichier (Mo)')
plt.ylabel('Débit (Mo/s)')
plt.grid(True, alpha=0.3)
plt.legend()
plt.savefig('benchmark_results/plots/encrypt_throughput.png')
print("Graphiques générés avec succès!")
PYTHON_EOF
fi
# Nettoyer
rm -f test.key test.iv
}
# Exécuter le script
main
Partie 4: Questions d'analyse
- Parmi les modes opératoires testés, lequel offre le meilleur compromis entre sécurité et performance pour le chiffrement de grands fichiers (>100 Mo) ? Justifiez votre réponse.
- Quelles sont les vulnérabilités potentielles du système de chiffrement hybride que vous avez implémenté ? Comment pourriez-vous l'améliorer ?
- Sur la base des résultats des benchmarks, existe-t-il une corrélation linéaire entre la taille des données et le temps de chiffrement/déchiffrement ? Expliquez ce phénomène.
- Comparez les performances de AES-GCM et ChaCha20-Poly1305. Dans quels contextes privilégieriez-vous l'un plutôt que l'autre ?
- Comment la gestion des clés pourrait-elle être améliorée dans votre système de chiffrement hybride pour le rendre plus sécurisé et plus facile à utiliser ?
TP 3: Intégrité et authentification avec OpenSSL
- Maîtriser les techniques d'authentification et de vérification d'intégrité
- Implémenter et comparer différents mécanismes de signature numérique
- Créer un système d'authentification mutuelle
Partie 1: Comparaison des fonctions de hachage et HMAC
Réalisez des tests de performance et d'intégrité avec différentes fonctions de hachage :
#!/bin/bash
# hash_compare.sh - Compare les fonctions de hachage et HMAC
# Liste des algorithmes de hachage à tester
HASH_ALGORITHMS=(
"md5"
"sha1"
"sha256"
"sha384"
"sha512"
"sha3-256"
"blake2b512"
)
# Créer quelques fichiers de test
create_test_files() {
echo "Création des fichiers de test..."
# Petit fichier (1 Ko)
dd if=/dev/urandom of=test_small.dat bs=1K count=1 2>/dev/null
# Fichier moyen (1 Mo)
dd if=/dev/urandom of=test_medium.dat bs=1M count=1 2>/dev/null
# Grand fichier (10 Mo)
dd if=/dev/urandom of=test_large.dat bs=1M count=10 2>/dev/null
}
# Fonction pour tester les hachages simples
test_hash_performance() {
local file=$1
local filesize=$(stat -c%s "$file")
echo "Test de hachage sur $(basename $file) ($(numfmt --to=iec $filesize))"
printf "%-10s %-16s %-10s\n" "Algorithme" "Temps (ms)" "Taille (octets)"
for algo in "${HASH_ALGORITHMS[@]}"; do
# Mesurer le temps
local start_time=$(date +%s.%N)
local hash_output=$(openssl dgst -$algo "$file")
local end_time=$(date +%s.%N)
local time_ms=$(echo "($end_time - $start_time) * 1000" | bc)
# Calculer la taille du hash
local hash_hex=$(echo "$hash_output" | awk '{print $NF}')
local hash_size=$((${#hash_hex} / 2))
printf "%-10s %-16.4f %-10d\n" "$algo" "$time_ms" "$hash_size"
done
echo ""
}
# Fonction pour tester HMAC
test_hmac_performance() {
local file=$1
local filesize=$(stat -c%s "$file")
# Créer une clé secrète pour HMAC
openssl rand -out hmac.key 32
echo "Test de HMAC sur $(basename $file) ($(numfmt --to=iec $filesize))"
printf "%-10s %-16s %-10s\n" "Algorithme" "Temps (ms)" "Taille (octets)"
for algo in "${HASH_ALGORITHMS[@]}"; do
# Mesurer le temps
local start_time=$(date +%s.%N)
local hmac_output=$(openssl dgst -$algo -hmac "$(cat hmac.key)" "$file")
local end_time=$(date +%s.%N)
local time_ms=$(echo "($end_time - $start_time) * 1000" | bc)
# Calculer la taille du HMAC
local hmac_hex=$(echo "$hmac_output" | awk '{print $NF}')
local hmac_size=$((${#hmac_hex} / 2))
printf "%-10s %-16.4f %-10d\n" "$algo" "$time_ms" "$hmac_size"
done
echo ""
# Nettoyer
rm -f hmac.key
}
# Fonction pour tester l'effet d'avalanche
test_avalanche_effect() {
echo "Test de l'effet d'avalanche"
echo "Création de deux fichiers différant d'un seul bit..."
# Créer deux fichiers différant d'un seul bit
echo "Original file content" > file1.txt
cp file1.txt file2.txt
# Modifier un seul bit dans le second fichier
printf '\\x41' | dd of=file2.txt bs=1 seek=0 count=1 conv=notrunc 2>/dev/null
printf "%-10s %-20s %-20s %-15s\n" "Algorithme" "Hash fichier 1" "Hash fichier 2" "Bits différents"
for algo in "${HASH_ALGORITHMS[@]}"; do
# Calculer les hashes
hash1=$(openssl dgst -$algo file1.txt | awk '{print $NF}')
hash2=$(openssl dgst -$algo file2.txt | awk '{print $NF}')
# Convertir en binaire et compter les bits différents
bin1=$(echo "ibase=16; obase=2; ${hash1^^}" | bc | tr -d '\\n')
bin2=$(echo "ibase=16; obase=2; ${hash2^^}" | bc | tr -d '\\n')
# Assurer que les chaînes binaires ont la même longueur
while [ ${#bin1} -lt ${#bin2} ]; do
bin1="0$bin1"
done
while [ ${#bin2} -lt ${#bin1} ]; do
bin2="0$bin2"
done
# Compter les bits différents
local diff_count=0
for ((i=0; i<${#bin1}; i++)); do
if [ "${bin1:$i:1}" != "${bin2:$i:1}" ]; then
((diff_count++))
fi
done
# Calculer le pourcentage
local total_bits=${#bin1}
local diff_percent=$(echo "scale=2; $diff_count * 100 / $total_bits" | bc)
printf "%-10s %-20s %-20s %-15s\n" "$algo" "${hash1:0:16}..." "${hash2:0:16}..." "$diff_count/$total_bits ($diff_percent%)"
done
# Nettoyer
rm -f file1.txt file2.txt
}
# Test de collision sur MD5 (démonstration éducative)
demonstrate_md5_weakness() {
echo -e "\nDémonstration de la faiblesse de MD5 (collisions partielles)"
echo "Recherche de chaînes aléatoires produisant les mêmes premiers caractères de hachage..."
# Générer des chaînes aléatoires et rechercher des collisions partielles
prefix_length=4 # Les 4 premiers caractères du hash (16 bits)
found_collision=0
attempts=0
max_attempts=100000
declare -A hash_map
while [ $attempts -lt $max_attempts ] && [ $found_collision -eq 0 ]; do
((attempts++))
# Générer une chaîne aléatoire
random_string=$(openssl rand -hex 8)
# Calculer le hash MD5
md5_hash=$(echo -n "$random_string" | openssl dgst -md5 | awk '{print $NF}')
hash_prefix=${md5_hash:0:$prefix_length}
# Vérifier si nous avons déjà vu ce préfixe
if [ -n "${hash_map[$hash_prefix]}" ]; then
echo "Collision partielle trouvée après $attempts tentatives!"
echo "Chaîne 1: ${hash_map[$hash_prefix]}"
echo "Hash 1 : $(echo -n "${hash_map[$hash_prefix]}" | openssl dgst -md5 | awk '{print $NF}')"
echo "Chaîne 2: $random_string"
echo "Hash 2 : $md5_hash"
found_collision=1
else
hash_map[$hash_prefix]=$random_string
fi
# Afficher la progression
if [ $((attempts % 10000)) -eq 0 ]; then
echo -n "."
fi
done
if [ $found_collision -eq 0 ]; then
echo "Aucune collision trouvée après $max_attempts tentatives."
fi
echo -e "\nCette démonstration illustre la vulnérabilité des fonctions de hachage aux attaques"
echo "par collision, en particulier MD5 qui n'est plus considéré comme sécurisé."
}
# Fonction principale
main() {
echo "===== Test des fonctions de hachage et HMAC ====="
# Créer les fichiers de test
create_test_files
# Tester les performances de hachage
for file in test_small.dat test_medium.dat test_large.dat; do
test_hash_performance "$file"
done
# Tester les performances de HMAC
for file in test_small.dat test_medium.dat; do
test_hmac_performance "$file"
done
# Tester l'effet d'avalanche
test_avalanche_effect
# Démontrer la faiblesse de MD5
demonstrate_md5_weakness
# Nettoyer
echo "Nettoyage..."
rm -f test_*.dat
echo "Tests terminés."
}
# Exécuter le script
main
Partie 2: Implémentation d'un système de signature numérique
Créez un système complet de signature numérique pour l'authentification de documents :
#!/bin/bash
# document_signer.sh - Système de signature numérique pour documents
if [ $# -lt 2 ]; then
echo "Usage:"
echo " $0 sign document.txt [private_key.pem]"
echo " $0 verify document.txt.signed [public_key.pem]"
echo " $0 keygen [username]"
exit 1
fi
action=$1
document=$2
# Fonction pour générer une paire de clés
generate_keys() {
local username=$1
if [ -z "$username" ]; then
username=$(whoami)
fi
local key_dir="signatures/keys"
mkdir -p "$key_dir"
echo "[+] Génération d'une paire de clés Ed25519 pour $username..."
openssl genpkey -algorithm ED25519 -out "$key_dir/${username}_private.pem"
openssl pkey -in "$key_dir/${username}_private.pem" -pubout -out "$key_dir/${username}_public.pem"
# Définir les permissions appropriées
chmod 600 "$key_dir/${username}_private.pem"
chmod 644 "$key_dir/${username}_public.pem"
echo "[+] Clés générées :"
echo " Clé privée : $key_dir/${username}_private.pem"
echo " Clé publique : $key_dir/${username}_public.pem"
echo "[!] IMPORTANT : Protégez votre clé privée et ne la partagez jamais !"
}
# Fonction pour signer un document
sign_document() {
local document=$1
local private_key=$2
# Vérifier que le document existe
if [ ! -f "$document" ]; then
echo "[-] Erreur : Le document '$document' n'existe pas."
exit 1
fi
# Si aucune clé privée n'est spécifiée, chercher la clé par défaut
if [ -z "$private_key" ]; then
username=$(whoami)
private_key="signatures/keys/${username}_private.pem"
if [ ! -f "$private_key" ]; then
echo "[-] Erreur : Aucune clé privée spécifiée et pas de clé par défaut trouvée."
echo " Utilisez '$0 keygen' pour générer une paire de clés."
exit 1
fi
fi
# Vérifier que la clé privée existe
if [ ! -f "$private_key" ]; then
echo "[-] Erreur : La clé privée '$private_key' n'existe pas."
exit 1
fi
# Créer le répertoire de signatures s'il n'existe pas
mkdir -p signatures
# Calculer l'empreinte du document (SHA-256)
local document_hash=$(openssl dgst -sha256 -binary "$document" | xxd -p -c 64)
# Obtenir des informations sur le signataire
local signer_info=""
if openssl pkey -in "$private_key" -noout -text | grep -q "ED25519"; then
signer_algo="ED25519"
elif openssl pkey -in "$private_key" -noout -text | grep -q "RSA"; then
signer_algo="RSA"
else
signer_algo="UNKNOWN"
fi
# Créer les métadonnées de la signature
local metadata_file="signatures/${document}.meta"
cat > "$metadata_file" << EOL
Document: $(basename "$document")
Hash-Algorithm: SHA-256
Document-Hash: $document_hash
Signature-Algorithm: $signer_algo
Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
Signer: $(whoami)@$(hostname)
EOL
# Signer le document (en réalité, son empreinte)
local signature_file="signatures/${document}.sig"
if ! openssl pkeyutl -sign -inkey "$private_key" -rawin \
-in <(echo -n "$document_hash") -out "$signature_file"; then
echo "[-] Erreur lors de la signature du document."
rm -f "$metadata_file" "$signature_file"
exit 1
fi
# Créer le fichier de signature complet
local output_file="${document}.signed"
(
echo "-----BEGIN SIGNED DOCUMENT-----"
cat "$metadata_file"
echo "Signature: $(base64 -w 76 "$signature_file")"
echo "-----BEGIN DOCUMENT CONTENT-----"
cat "$document"
echo "-----END DOCUMENT CONTENT-----"
) > "$output_file"
# Nettoyer les fichiers temporaires
rm -f "$metadata_file" "$signature_file"
echo "[+] Document signé avec succès : $output_file"
}
# Fonction pour vérifier un document signé
verify_document() {
local signed_file=$1
local public_key=$2
# Vérifier que le fichier signé existe
if [ ! -f "$signed_file" ]; then
echo "[-] Erreur : Le fichier signé '$signed_file' n'existe pas."
exit 1
fi
# Extraire les métadonnées, la signature et le contenu du document
if ! grep -q "^-----BEGIN SIGNED DOCUMENT-----$" "$signed_file"; then
echo "[-] Erreur : Format de fichier signé non reconnu."
exit 1
fi
# Extraire les métadonnées
local metadata_block=$(sed -n '/^-----BEGIN SIGNED DOCUMENT-----$/,/^Signature: /p' "$signed_file" | grep -v "^-----BEGIN SIGNED DOCUMENT-----$")
local doc_hash=$(echo "$metadata_block" | grep "^Document-Hash: " | cut -d ' ' -f 2-)
local hash_algo=$(echo "$metadata_block" | grep "^Hash-Algorithm: " | cut -d ' ' -f 2-)
local sig_algo=$(echo "$metadata_block" | grep "^Signature-Algorithm: " | cut -d ' ' -f 2-)
local signer=$(echo "$metadata_block" | grep "^Signer: " | cut -d ' ' -f 2-)
local timestamp=$(echo "$metadata_block" | grep "^Timestamp: " | cut -d ' ' -f 2-)
# Extraire la signature
local sig_base64=$(grep "^Signature: " "$signed_file" | cut -d ' ' -f 2-)
echo "$sig_base64" | base64 -d > temp_signature.bin
# Extraire le contenu du document
local doc_content=$(sed -n '/^-----BEGIN DOCUMENT CONTENT-----$/,/^-----END DOCUMENT CONTENT-----$/p' "$signed_file" | grep -v "^-----BEGIN DOCUMENT CONTENT-----$" | grep -v "^-----END DOCUMENT CONTENT-----$")
echo "$doc_content" > temp_document.txt
# Vérifier l'intégrité du document
local calculated_hash=$(openssl dgst -$hash_algo -binary temp_document.txt | xxd -p -c 64)
if [ "$calculated_hash" != "$doc_hash" ]; then
echo "[-] ERREUR : Le contenu du document a été modifié après la signature!"
echo " Hash attendu : $doc_hash"
echo " Hash calculé : $calculated_hash"
rm -f temp_signature.bin temp_document.txt
exit 1
fi
# Si aucune clé publique n'est spécifiée, tenter de trouver une clé correspondante
if [ -z "$public_key" ]; then
# Extraire le nom d'utilisateur du signataire
local signer_username=$(echo "$signer" | cut -d '@' -f 1)
public_key="signatures/keys/${signer_username}_public.pem"
if [ ! -f "$public_key" ]; then
echo "[-] Aucune clé publique spécifiée et impossible de trouver une clé pour $signer_username."
echo " Veuillez spécifier explicitement une clé publique."
rm -f temp_signature.bin temp_document.txt
exit 1
fi
fi
# Vérifier que la clé publique existe
if [ ! -f "$public_key" ]; then
echo "[-] Erreur : La clé publique '$public_key' n'existe pas."
rm -f temp_signature.bin temp_document.txt
exit 1
fi
# Vérifier la signature
if openssl pkeyutl -verify -pubin -inkey "$public_key" -rawin \
-in <(echo -n "$doc_hash") -sigfile temp_signature.bin 2>/dev/null; then
echo "[+] Signature vérifiée avec succès!"
echo " Document : $(basename "$signed_file")"
echo " Signataire : $signer"
echo " Date/Heure : $timestamp"
echo " Algorithme : $sig_algo avec $hash_algo"
# Option pour extraire le contenu original
read -p "Extraire le contenu original du document ? (o/n) " extract_choice
if [[ "$extract_choice" =~ ^[Oo]$ ]]; then
output_file="${signed_file%.signed}.verified"
cp temp_document.txt "$output_file"
echo "[+] Contenu extrait dans : $output_file"
fi
else
echo "[-] ERREUR : Signature invalide!"
echo " La signature n'a pas pu être vérifiée avec la clé publique fournie."
echo " Cela peut indiquer une tentative de falsification ou l'utilisation d'une clé incorrecte."
fi
# Nettoyer les fichiers temporaires
rm -f temp_signature.bin temp_document.txt
}
# Exécuter l'action appropriée
case "$action" in
keygen)
generate_keys "$document" # Dans ce cas, le deuxième argument est le nom d'utilisateur
;;
sign)
private_key=$3
sign_document "$document" "$private_key"
;;
verify)
public_key=$3
verify_document "$document" "$public_key"
;;
*)
echo "Action non reconnue. Utilisez 'keygen', 'sign' ou 'verify'."
exit 1
;;
esac
Pour tester ce système :
# Générer des clés
./document_signer.sh keygen alice
./document_signer.sh keygen bob
# Créer un document
echo "Contrat important entre Alice et Bob.
Les parties conviennent de ce qui suit:
1. Alice fournira les services spécifiés dans l'annexe A.
2. Bob paiera la somme convenue avant le 30 juin.
3. Toute violation des termes entraînera des pénalités.
Fait le 30/03/2025.
" > contract.txt
# Alice signe le document
./document_signer.sh sign contract.txt signatures/keys/alice_private.pem
# Bob vérifie la signature d'Alice
./document_signer.sh verify contract.txt.signed signatures/keys/alice_public.pem
# Test de falsification
cp contract.txt.signed contract_modified.txt.signed
sed -i 's/30 juin/31 décembre/' contract_modified.txt.signed
# Bob vérifie le document falsifié
./document_signer.sh verify contract_modified.txt.signed signatures/keys/alice_public.pem
Partie 3: Signature avec différents algorithmes
Comparez les performances et les caractéristiques de différents algorithmes de signature :
#!/bin/bash
# signature_benchmark.sh - Compare différents algorithmes de signature
# Algorithmes à tester
SIGNATURE_ALGORITHMS=(
"rsa:2048"
"rsa:4096"
"ec:prime256v1"
"ec:secp384r1"
"ed25519"
)
# Tailles de fichier à tester
FILE_SIZES=(
"10K"
"100K"
"1M"
"10M"
)
# Créer un répertoire pour les résultats
mkdir -p signature_benchmark
# Fonction pour générer une paire de clés
generate_keys() {
local algo=$1
local output_prefix="signature_benchmark/key_$algo"
echo "Génération de clés pour $algo..."
case "$algo" in
"rsa:"*)
local bits=$(echo "$algo" | cut -d':' -f2)
openssl genpkey -algorithm RSA -out "${output_prefix}_private.pem" -pkeyopt "rsa_keygen_bits:$bits"
;;
"ec:"*)
local curve=$(echo "$algo" | cut -d':' -f2)
openssl genpkey -algorithm EC -out "${output_prefix}_private.pem" -pkeyopt "ec_paramgen_curve:$curve"
;;
"ed25519")
openssl genpkey -algorithm ED25519 -out "${output_prefix}_private.pem"
;;
*)
echo "Algorithme non reconnu: $algo"
return 1
;;
esac
# Extraire la clé publique
openssl pkey -in "${output_prefix}_private.pem" -pubout -out "${output_prefix}_public.pem"
echo "Clés générées dans ${output_prefix}_private.pem et ${output_prefix}_public.pem"
}
# Fonction pour créer un fichier de test
create_test_file() {
local size=$1
local output_file="signature_benchmark/test_${size}.dat"
echo "Création d'un fichier de test de $size..."
dd if=/dev/urandom of="$output_file" bs="$size" count=1 2>/dev/null
echo "$output_file"
}
# Fonction pour tester la signature et la vérification
benchmark_signature() {
local algo=$1
local file=$2
local filesize=$(stat -c%s "$file")
local key_prefix="signature_benchmark/key_$algo"
echo "Test de signature pour $algo sur $(basename "$file") ($(numfmt --to=iec $filesize))..."
# Variables pour les résultats
local sign_time=""
local verify_time=""
local signature_size=""
# Mesurer le temps de signature
local start_time=$(date +%s.%N)
local signature_file="${file}.${algo}.sig"
case "$algo" in
"rsa:"*)
# Utiliser RSA-PSS pour la signature
openssl pkeyutl -sign -inkey "${key_prefix}_private.pem" -rawin \
-in <(openssl dgst -sha256 -binary "$file") \
-out "$signature_file" \
-pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha256
;;
"ec:"*)
# Signature ECDSA
openssl pkeyutl -sign -inkey "${key_prefix}_private.pem" -rawin \
-in <(openssl dgst -sha256 -binary "$file") \
-out "$signature_file"
;;
"ed25519")
# Signature Ed25519
openssl pkeyutl -sign -inkey "${key_prefix}_private.pem" -rawin \
-in <(openssl dgst -sha256 -binary "$file") \
-out "$signature_file"
;;
esac
local end_time=$(date +%s.%N)
sign_time=$(echo "$end_time - $start_time" | bc)
# Mesurer la taille de la signature
signature_size=$(stat -c%s "$signature_file")
# Mesurer le temps de vérification
start_time=$(date +%s.%N)
case "$algo" in
"rsa:"*)
# Vérification RSA-PSS
openssl pkeyutl -verify -pubin -inkey "${key_prefix}_public.pem" -rawin \
-in <(openssl dgst -sha256 -binary "$file") \
-sigfile "$signature_file" \
-pkeyopt rsa_padding_mode:pss -pkeyopt digest:sha256 >/dev/null
;;
"ec:"*)
# Vérification ECDSA
openssl pkeyutl -verify -pubin -inkey "${key_prefix}_public.pem" -rawin \
-in <(openssl dgst -sha256 -binary "$file") \
-sigfile "$signature_file" >/dev/null
;;
"ed25519")
# Vérification Ed25519
openssl pkeyutl -verify -pubin -inkey "${key_prefix}_public.pem" -rawin \
-in <(openssl dgst -sha256 -binary "$file") \
-sigfile "$signature_file" >/dev/null
;;
esac
end_time=$(date +%s.%N)
verify_time=$(echo "$end_time - $start_time" | bc)
# Afficher les résultats
echo " Taille de la signature: $(numfmt --to=iec $signature_size)"
echo " Temps de signature: ${sign_time} secondes"
echo " Temps de vérification: ${verify_time} secondes"
echo " Débit de signature: $(echo "scale=2; $filesize / $sign_time / 1024 / 1024" | bc) Mo/s"
echo " Débit de vérification: $(echo "scale=2; $filesize / $verify_time / 1024 / 1024" | bc) Mo/s"
# Nettoyer
rm -f "$signature_file"
# Retourner les résultats au format CSV
echo "$algo,$(basename "$file"),$filesize,$signature_size,$sign_time,$verify_time"
}
# Fonction principale
main() {
echo "===== Benchmark des algorithmes de signature ====="
# Créer un fichier CSV pour les résultats
echo "algorithm,file,filesize,signature_size,sign_time,verify_time" > signature_benchmark/results.csv
# Générer les clés pour chaque algorithme
for algo in "${SIGNATURE_ALGORITHMS[@]}"; do
generate_keys "$algo"
done
# Créer les fichiers de test
test_files=()
for size in "${FILE_SIZES[@]}"; do
test_files+=("$(create_test_file $size)")
done
# Exécuter les benchmarks
for file in "${test_files[@]}"; do
for algo in "${SIGNATURE_ALGORITHMS[@]}"; do
result=$(benchmark_signature "$algo" "$file")
echo "$result" >> signature_benchmark/results.csv
done
done
echo "Benchmark terminé. Résultats sauvegardés dans signature_benchmark/results.csv"
# Si Python est disponible, générer des graphiques
if command -v python3 &> /dev/null; then
echo "Génération de graphiques avec Python..."
python3 - <<PYTHON_EOF
import pandas as pd
import matplotlib.pyplot as plt
import os
# Lire les résultats
df = pd.read_csv('signature_benchmark/results.csv')
# Ajouter des colonnes dérivées
df['sign_speed_mbps'] = df['filesize'] / df['sign_time'] / 1024 / 1024
df['verify_speed_mbps'] = df['filesize'] / df['verify_time'] / 1024 / 1024
df['filesize_mb'] = df['filesize'] / 1024 / 1024
df['signature_size_bytes'] = df['signature_size']
# Créer un dossier pour les graphiques
os.makedirs('signature_benchmark/plots', exist_ok=True)
# Graphique pour la taille des signatures
plt.figure(figsize=(10, 6))
algos = df['algorithm'].unique()
sizes = [df[df['algorithm'] == algo]['signature_size_bytes'].iloc[0] for algo in algos]
plt.bar(algos, sizes, color='skyblue')
plt.title('Taille des signatures par algorithme')
plt.xlabel('Algorithme')
plt.ylabel('Taille (octets)')
plt.xticks(rotation=45)
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('signature_benchmark/plots/signature_sizes.png')
plt.close()
# Graphique pour la vitesse de signature
plt.figure(figsize=(12, 6))
for algo in df['algorithm'].unique():
data = df[df['algorithm'] == algo]
plt.plot(data['filesize_mb'], data['sign_speed_mbps'], marker='o', label=algo)
plt.title('Vitesse de signature par taille de fichier')
plt.xlabel('Taille du fichier (Mo)')
plt.ylabel('Débit (Mo/s)')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.savefig('signature_benchmark/plots/sign_speed.png')
# Graphique pour la vitesse de vérification
plt.figure(figsize=(12, 6))
for algo in df['algorithm'].unique():
data = df[df['algorithm'] == algo]
plt.plot(data['filesize_mb'], data['verify_speed_mbps'], marker='o', label=algo)
plt.title('Vitesse de vérification par taille de fichier')
plt.xlabel('Taille du fichier (Mo)')
plt.ylabel('Débit (Mo/s)')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.savefig('signature_benchmark/plots/verify_speed.png')
plt.close()
print("Graphiques générés avec succès!")
PYTHON_EOF
fi
}
# Exécuter le script
main
Partie 4: Questions d'analyse
- Sur la base des résultats des tests de hachage, quel algorithme offre le meilleur compromis entre performance et sécurité ? Justifiez votre choix.
- Comparez les tailles de signature et les performances entre RSA, ECDSA et Ed25519. Pour quels types d'applications chacun de ces algorithmes serait-il le plus approprié ?
- Analysez le système de signature de documents que vous avez implémenté. Quelles sont ses forces et ses faiblesses en termes de sécurité ? Comment pourrait-il être amélioré ?
- L'effet d'avalanche est-il plus prononcé dans certaines fonctions de hachage que dans d'autres ? Que signifie un effet d'avalanche plus fort en termes de sécurité ?
- Comment les performances de HMAC se comparent-elles aux fonctions de hachage simples ? Dans quelles situations est-il préférable d'utiliser HMAC plutôt qu'une simple fonction de hachage ?
TP 4: Implémentation d'un service de sécurité complet
- Concevoir et implémenter un service combinant tous les aspects de la sécurité cryptographique
- Mettre en œuvre un système complet d'échange sécurisé de messages
- Intégrer confidentialité, intégrité, authentification et non-répudiation
Description du projet
Dans ce TP, vous allez concevoir et implémenter un service de messagerie sécurisée qui combine tous les aspects de la sécurité cryptographique étudiés dans ce chapitre. Le service devra permettre l'échange de messages confidentiels entre utilisateurs, avec garantie d'intégrité, d'authentification et de non-répudiation.
- Gestion des utilisateurs
- Création de comptes utilisateur avec génération de paires de clés
- Stockage sécurisé des clés privées (chiffrées avec un mot de passe)
- Annuaire de clés publiques accessible
- Envoi de messages
- Chiffrement hybride (RSA/AES-GCM ou ECDH/ChaCha20-Poly1305)
- Signature numérique du message
- Horodatage des messages
- Réception de messages
- Déchiffrement du message
- Vérification de la signature et de l'intégrité
- Stockage sécurisé des messages
- Interface utilisateur
- Interface en ligne de commande simple mais complète
- Affichage des informations de sécurité pertinentes
Architecture proposée
Implémentation suggérée
Voici la structure de base du système de messagerie sécurisée à implémenter :
#!/bin/bash
# securemsg.sh - Système de messagerie sécurisée
# Configuration
DATA_DIR="$HOME/.securemsg"
USERS_DIR="$DATA_DIR/users"
MESSAGES_DIR="$DATA_DIR/messages"
PUBLIC_KEYS_DIR="$DATA_DIR/public_keys"
# Fonction principale
main() {
if [ $# -lt 1 ]; then
show_help
exit 1
fi
# Créer les répertoires nécessaires
mkdir -p "$USERS_DIR" "$MESSAGES_DIR" "$PUBLIC_KEYS_DIR"
# Traiter les commandes
command=$1
shift
case "$command" in
init)
# Initialize user account
init_user "$@"
;;
send)
# Send a secure message
send_message "$@"
;;
read)
# Read a received message
read_message "$@"
;;
list)
# List received messages
list_messages "$@"
;;
users)
# List registered users
list_users
;;
help)
show_help
;;
*)
echo "Commande inconnue: $command"
show_help
exit 1
;;
esac
}
# Afficher l'aide
show_help() {
echo "Usage: securemsg.sh COMMAND [OPTIONS]"
echo ""
echo "Commands:"
echo " init USERNAME PASSWORD Créer un nouvel utilisateur"
echo " send RECIPIENT MESSAGE Envoyer un message à un destinataire"
echo " read MESSAGE_ID Lire un message reçu"
echo " list Lister les messages reçus"
echo " users Lister les utilisateurs enregistrés"
echo " help Afficher cette aide"
echo ""
echo "Examples:"
echo " securemsg.sh init alice MonMotDePasse123"
echo " securemsg.sh send bob \"Message secret pour Bob\""
echo " securemsg.sh read 1"
}
# Initialiser un nouvel utilisateur
init_user() {
# TODO: Implement user initialization
# 1. Generate RSA or ECC keys for the user
# 2. Encrypt the private key with the user's password
# 3. Store the user's information and public key
}
# Envoyer un message sécurisé
send_message() {
# TODO: Implement secure message sending
# 1. Retrieve recipient's public key
# 2. Generate a random symmetric key
# 3. Encrypt the message with the symmetric key
# 4. Encrypt the symmetric key with the recipient's public key
# 5. Sign the encrypted message
# 6. Store the message for the recipient
}
# Lire un message reçu
read_message() {
# TODO: Implement message reading
# 1. Retrieve the encrypted message
# 2. Decrypt the symmetric key with the user's private key
# 3. Decrypt the message with the symmetric key
# 4. Verify the sender's signature
# 5. Display the message and security information
}
# Lister les messages reçus
list_messages() {
# TODO: Implement message listing
# List all messages for the current user
}
# Lister les utilisateurs enregistrés
list_users() {
# TODO: Implement user listing
# List all registered users with their public keys
}
# Exécuter le script
main "$@"
Consignes et outils nécessaires
- Implémentez les fonctions manquantes du script ci-dessus pour créer un système de messagerie sécurisée fonctionnel.
- Utilisez OpenSSL pour toutes les opérations cryptographiques.
- Assurez-vous que votre implémentation respecte les principes de sécurité vus dans ce chapitre.
- Documentez votre code et expliquez vos choix d'implémentation.
- Testez votre système avec plusieurs utilisateurs et différents types de messages.
Remise du travail
Pour ce TP, vous devrez remettre :
- Le code source complet de votre système de messagerie sécurisée.
- Un rapport détaillant vos choix d'implémentation, les algorithmes utilisés et les mesures de sécurité mises en place.
- Une analyse des forces et faiblesses de votre système, et des propositions d'amélioration.
- Un guide d'utilisation pour les utilisateurs finaux.
Navigation
Outils requis
- OpenSSL (version 1.1.1g ou supérieure)
# Vérifier la version openssl version
- Bash (version 4.0 ou supérieure)
# Vérifier la version bash --version
- Python (pour les analyses et visualisations)
# Installer les packages nécessaires pip install matplotlib numpy pandas
Ressources complémentaires
- OpenSSL Cookbook par Ivan Ristić
- Wiki OpenSSL: Utilitaires en ligne de commande
- OWASP: Cryptographic Storage Cheat Sheet
- Practical Cryptography for Developers par Svetlin Nakov