1+ from ..crypto_analyzer import CryptoAnalyzer
2+ from cryptography .hazmat .primitives .kdf .pbkdf2 import PBKDF2HMAC
3+ from cryptography .hazmat .primitives import hashes
4+ import re
5+
6+ class Aes_Gcm_Analyzer (CryptoAnalyzer ):
7+ '''Détermine si l'algo aes_gcm est utilisé, génère des clés et tente de de déchffrer un fichier chiffré en utilisant les clés générées.
8+
9+ Cette classe a trois méthodes principales:
10+ - identifier_algo: Détermine si l'algo de chiffrement utilsé sur le fichier chiffré qui lui est passé en paramètre est l'aes_gcm.
11+ - generer_cles_candidates: Génère une liste de clés candidates pour le déchiffrement du fichier chiffré
12+ - dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées
13+
14+ Attributes:
15+ _PBKDF2_SALT: le salt utilisé pour le chiffrement
16+ _PBKDF2_ITERATIONS: le nombre d'itérations faites au chiffrement
17+ _PBKDF2_LONGUEUR_CLE: la longueur en octets de la clé à utiliser
18+
19+ '''
20+
21+ _PBKDF2_SALT = b"AES_GCM_SALT_2024" #Fourni
22+ _PBKDF2_ITERATIONS = 10000 #Fourni
23+ _PBKDF2_LONGUEUR_CLE = 32 #Longueur de la clé
24+
25+ def __filtrer_dictionnaire_par_indice (self , chemin_dictionnaire : str ) -> list [str ]:
26+ """
27+ Filtre le dictionnaire en se basant sur les indices de la mission 4.
28+ L'indice pointe vers le format de clé "Acronyme en majuscules + 4 chiffres".
29+
30+ Args:
31+ chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire.
32+
33+ Returns:
34+ list[str]: Une liste de mots de passe filtrés.
35+ """
36+ mots_filtres : list [str ] = []
37+
38+ # L'année courante
39+ annee_courante = "2024" #Normalement 2025 mais on considère 2024 pour se conformer à la wordlist
40+
41+ # Définition du motif d'acronyme de 4 lettres en majuscules
42+ # On utilise une expression régulière pour plus de robustesse
43+ motif_acronyme = re .compile (r"^[A-Z]{4}$" )
44+
45+ try :
46+ with open (chemin_dictionnaire , "r" , encoding = "utf-8" ) as f :
47+ for ligne in f :
48+ mot = ligne .strip ()
49+
50+ # Vérifie si le mot de passe correspond au format de l'indice
51+ # ex: NATO2024, UN2024, etc.
52+ if mot .endswith (annee_courante ):
53+ acronyme = mot [:- 4 ] # Extrait la partie acronyme
54+ if motif_acronyme .match (acronyme ):
55+ mots_filtres .append (mot )
56+
57+ except FileNotFoundError :
58+ print (f"Erreur : Le fichier de dictionnaire '{ chemin_dictionnaire } ' est introuvable." )
59+ return []
60+
61+ return mots_filtres
62+
63+ def generer_cles_candidates (self , chemin_dictionnaire : str ) -> list [bytes ]:
64+ '''
65+ Génère les clées candidates pour déchiffrer le fichier à partir de la liste retournée par filtrer_dictionnaire_par_indices.
66+
67+ Args:
68+ chemin_dictionnaire(str): le chemin du dictionnaire de mots de passes pour l'attaque par dictionnaire.
69+
70+ Returns:
71+ list[bytes]: liste des clés candidates.
72+ '''
73+
74+ mots_de_passe_cible = self .__filtrer_dictionnaire_par_indice (chemin_dictionnaire )
75+
76+ clees_candidates : list [bytes ] = []
77+ kdf = PBKDF2HMAC (
78+ algorithm = hashes .SHA256 (),
79+ length = self ._PBKDF2_LONGUEUR_CLE ,
80+ iterations = self ._PBKDF2_ITERATIONS ,
81+ salt = self ._PBKDF2_SALT
82+ )
83+ for mot_de_passe in mots_de_passe_cible :
84+ mot_de_passe_en_octets : bytes = mot_de_passe .encode ('utf-8' )
85+ cle_derivee : bytes = kdf .derive (mot_de_passe_en_octets )
86+ clees_candidates .append (cle_derivee )
87+
88+ return clees_candidates
0 commit comments