Plateforme de Cryptographie Par Kaci AMAOUCHE

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

Objectifs
  • 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

  1. Comment les résultats du benchmark correspondent-ils à la théorie ? Quels algorithmes sont significativement plus rapides que d'autres et pourquoi ?
  2. 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 ?
  3. Quelles sont les trois commandes OpenSSL que vous trouvez les plus utiles pour des tâches cryptographiques courantes ? Expliquez pourquoi.
  4. 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é

Objectifs
  • 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

  1. 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.
  2. Quelles sont les vulnérabilités potentielles du système de chiffrement hybride que vous avez implémenté ? Comment pourriez-vous l'améliorer ?
  3. 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.
  4. Comparez les performances de AES-GCM et ChaCha20-Poly1305. Dans quels contextes privilégieriez-vous l'un plutôt que l'autre ?
  5. 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

Objectifs
  • 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

  1. Sur la base des résultats des tests de hachage, quel algorithme offre le meilleur compromis entre performance et sécurité ? Justifiez votre choix.
  2. 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é ?
  3. 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é ?
  4. 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é ?
  5. 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

Objectifs
  • 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.

Spécifications du service
  1. 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
  2. Envoi de messages
    • Chiffrement hybride (RSA/AES-GCM ou ECDH/ChaCha20-Poly1305)
    • Signature numérique du message
    • Horodatage des messages
  3. Réception de messages
    • Déchiffrement du message
    • Vérification de la signature et de l'intégrité
    • Stockage sécurisé des messages
  4. Interface utilisateur
    • Interface en ligne de commande simple mais complète
    • Affichage des informations de sécurité pertinentes

Architecture proposée

Gestion des utilisateurs Génération de clés Stockage sécurisé Envoi de messages Chiffrement hybride Signature numérique Annuaire de clés Stockage des clés publiques Vérification d'identité Réception de messages Déchiffrement Vérification de signature Interface Utilisateur

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 :

  1. Le code source complet de votre système de messagerie sécurisée.
  2. Un rapport détaillant vos choix d'implémentation, les algorithmes utilisés et les mesures de sécurité mises en place.
  3. Une analyse des forces et faiblesses de votre système, et des propositions d'amélioration.
  4. Un guide d'utilisation pour les utilisateurs finaux.

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