Skip to content

Commit 87ec604

Browse files
authored
Merge branch 'main' into feature/DetecteurCryptoOrchestrateur
2 parents 49082ed + 76baf3a commit 87ec604

8 files changed

Lines changed: 140 additions & 24 deletions

File tree

src/__init__.py

Whitespace-only changes.

src/analyzers/__init__.py

Whitespace-only changes.

src/analyzers/aes_cbc_analyzer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from ..crypto_analyzer import CryptoAnalyzer
2-
from ..utils import calculer_entropie
1+
from crypto_analyzer import CryptoAnalyzer
2+
from utils import calculer_entropie
33
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
44
from cryptography.hazmat.primitives import hashes
55
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
@@ -10,7 +10,7 @@ class Aes_Cbc_Analyzer(CryptoAnalyzer):
1010
1111
Cette classe a trois méthodes:
1212
- identifier_algo: Détermine si l'algo de chiffrement utilsé sur le fichier chiffré qui lui est passé en paramètre est l'aes_cbc.
13-
- generer_cles_candidates: Génère une liste de clés candidates pour le déchiffrement du fichier chiffré
13+
- generer_cles_candidates: Génère une liste de clés candidates pour le déchiffrement du fichier chiffré
1414
- dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées
1515
1616
Attributes:

src/analyzers/blowfish_analyzer.py

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from ..detecteur_crypto import CryptoAnalyzer
22
from ..utils import calculer_entropie
3-
3+
import hashlib
4+
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
5+
from cryptography.hazmat.primitives.padding import PKCS7
46
class Blowfish_Analyzer(CryptoAnalyzer):
57
'''Détermine si l'algo blowfish 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.
68
@@ -10,9 +12,14 @@ class Blowfish_Analyzer(CryptoAnalyzer):
1012
- dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées
1113
1214
Attributes:
13-
15+
__BLOWFISH_TAILLE_BLOC : taille à considérer pour les blocs de données chiffrés que le PKCS7 doit prendre en compte (8 bits)
16+
__BLOWFISH_TAILLE_IV : taille du vecteur d'initialisation en début de fichier (8 bits)
1417
1518
'''
19+
20+
__BLOWFISH_TAILLE_BLOC = 8
21+
__BLOWFISH_TAILLE_IV = 8
22+
1623
def identifier_algo(self, chemin_fichier_chiffre: str) -> float:
1724
'''
1825
Détermine la probabilité que l'algo de chiffrement utilisé soit blowfish en:
@@ -59,4 +66,115 @@ def identifier_algo(self, chemin_fichier_chiffre: str) -> float:
5966
except FileNotFoundError:
6067
return 0.0
6168

62-
return score
69+
return score
70+
71+
72+
def __filtrer_dictionnaire_par_indice(self, chemin_dictionnaire: str) -> list[str]:
73+
"""
74+
Filtre le dictionnaire en se basant sur les indices de la mission 3.
75+
L'indice pointe vers un format de clé "sha + nombre + chiffres simples".
76+
77+
Args:
78+
chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire.
79+
80+
Returns:
81+
list[str]: Une liste de mots de passe filtrés.
82+
"""
83+
mots_filtres: list[str] = []
84+
85+
# Indices pour le préfixe et le suffixe
86+
prefixes = ("sha256", "sha384", "sha512", "sha1")
87+
suffixes = ("123", "456", "789")
88+
89+
try:
90+
with open(chemin_dictionnaire, "r", encoding="utf-8") as f:
91+
for ligne in f:
92+
mot = ligne.strip()
93+
94+
# Vérifie si le mot commence par un préfixe et se termine par un suffixe
95+
if mot.startswith(prefixes) and mot.endswith(suffixes):
96+
mots_filtres.append(mot)
97+
98+
except FileNotFoundError:
99+
print(f"Erreur : Le fichier de dictionnaire '{chemin_dictionnaire}' est introuvable.")
100+
return []
101+
102+
return mots_filtres
103+
104+
def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]:
105+
"""
106+
Génère une liste de clés candidates pour le déchiffrement.
107+
Les candidats incluent les mots de passe directs, leur hash MD5 et leur hash SHA1.
108+
109+
Args:
110+
chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire.
111+
112+
Returns:
113+
list[bytes]: Une liste des clés candidates sous forme d'octets.
114+
"""
115+
cles_candidates: list[bytes] = []
116+
# Utilisation de la méthode privée pour filtrer les mots
117+
mots_de_passe_cible = self.__filtrer_dictionnaire_par_indice(chemin_dictionnaire)
118+
119+
for mot in mots_de_passe_cible:
120+
mot_en_bytes = mot.encode("utf-8")
121+
122+
# 1. Ajouter le mot de passe direct comme clé candidate
123+
cles_candidates.append(mot_en_bytes)
124+
125+
# 2. Hachage MD5 et ajout à la liste (en bytes)
126+
hash_md5 = hashlib.md5(mot_en_bytes).digest()
127+
cles_candidates.append(hash_md5)
128+
129+
# 3. Hachage SHA1 et ajout à la liste (en bytes)
130+
hash_sha1 = hashlib.sha1(mot_en_bytes).digest()
131+
cles_candidates.append(hash_sha1)
132+
133+
return cles_candidates
134+
135+
def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes):
136+
"""
137+
Déchiffre le fichier supposé crypté par l'algorithme blowfish avec la clé donnée en respectant les critères de
138+
- récupération de l'IV
139+
- suppression de padding
140+
141+
Args:
142+
chemin_fichier_chiffre (str): le chemin vers le fichier chiffré
143+
clee_donnee (bytes): La clé à utiliser pour le déchiffrement
144+
Returns:
145+
bytes: les données originales
146+
"""
147+
148+
#La taille de clé est dans l'intervalle 32-448bits et est multiple de 8
149+
if len(cle_donnee) not in range(32, 448, 8):
150+
return ValueError('Taille de clé invalide.')
151+
152+
try:
153+
154+
algorithm_blowfish = algorithms.Blowfish(cle_donnee)
155+
texte_chiffre = ''
156+
157+
#Récupération de l'IV et des texte chiffré das le fichier
158+
with open(chemin_fichier_chiffre, 'rb') as f:
159+
initialization_vector = f.read(self.__BLOWFISH_TAILLE_IV)
160+
texte_chiffre = f.read()
161+
f.close()
162+
163+
#Initialisation du cipher
164+
cipher = Cipher(algorithm_blowfish, modes.CBC(initialization_vector))
165+
decrypteur = cipher.decryptor()
166+
167+
#Suppresseur de padding
168+
supresseur_padding = PKCS7(self.__BLOWFISH_TAILLE_BLOC).unpadder()
169+
170+
#Décriptage des données avec le padding(remplissage aléatoire)
171+
donnees_chiffrees_avec_padding = decrypteur.update(texte_chiffre) + decrypteur.finalize()
172+
173+
#Suppression du padding et récupération de la donnée finale
174+
donnees_originales = supresseur_padding.update(donnees_chiffrees_avec_padding) + supresseur_padding.finalize()
175+
return donnees_originales
176+
177+
except (FileNotFoundError):
178+
raise
179+
180+

src/analyzers/chacha20_analyzer.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,9 @@ def dechiffrer(self,chemin_fichier_chiffer : str ,clef :bytes)->str:
174174
cipher = Cipher(algorithm_chacha20,mode=None)
175175
decrypteur = cipher.decryptor()
176176
return decrypteur.update(texte_chiffrer)
177-
178-
179-
180177
except Exception as e:
181178
print(f"Une erreur est survenu : {e}")
182179

183180

184181

185-
# print(ChaCha20_Analyzer().dechiffrer("mission2.enc",os.urandom(32)))
182+
print(ChaCha20_Analyzer().dechiffrer("mission2.enc",os.urandom(32)))

src/detecteur_crypto.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
from typing import List, Union
55

66
# Import des modules d'analyse
7-
from .analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer
8-
from .crypto_analyzer import CryptoAnalyzer
9-
10-
# Import de la classe abstraite
11-
from .analyzers.chacha20_analyzer import ChaCha20_Analyzer
7+
from analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer
8+
from crypto_analyzer import CryptoAnalyzer
9+
from analyzers.chacha20_analyzer import ChaCha20_Analyzer
10+
from analyzers.blowfish_analyzer import Blowfish_Analyzer
1211

1312
# Import des modules utilitaries
14-
from .utils import est_dechiffre
13+
from utils import est_dechiffre
1514

1615
class ResultatAnalyse:
1716
"""
@@ -35,11 +34,12 @@ class DetecteurCryptoOrchestrateur:
3534

3635
def __init__(self):
3736
"""
38-
Initialisation de tous les modules d'analyse disponibles (AES-CBC pour le moment)
37+
Initialisation de tous les modules d'analyse disponibles
3938
"""
4039
self.analyzers: dict[str, CryptoAnalyzer] = {
4140
"AES-CBC": Aes_Cbc_Analyzer(),
4241
"ChaCha20": ChaCha20_Analyzer(),
42+
"Blowfish": Blowfish_Analyzer()
4343
}
4444
self.missions_completees: list[dict[str, Union[str, list[ResultatAnalyse], float]]] = []
4545
self.statistiques_globales: dict[str, Union[int, float]] = {
@@ -118,7 +118,7 @@ def __tenter_dechiffrement_avec_dictionnaire(self, chemin_fichier: str, cles_can
118118
print(f" Clé trouvée après {j+1} tentatives!")
119119
break
120120
else:
121-
print(" Aucune clé valide trouvée")
121+
print("Aucune clé valide trouvée")
122122

123123
def mission_complete_automatique(self, dossier_chiffres: str, chemin_dictionnaire: str) -> List[ResultatAnalyse]:
124124
"""
@@ -249,5 +249,4 @@ def attaque_dictionnaire_manuelle(self, chemin_fichier: str, algorithme_choisi:
249249
print(f"Erreur lors de l'attaque: {str(e)}")
250250
temps_execution = time.time() - debut_attaque
251251
return ResultatAnalyse("", b"", 0.0, b"", temps_execution, 0)
252-
253-
# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc'))
252+
# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc'))

src/interface_console.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from rich.text import Text
66
from rich.prompt import Prompt
77
from rich.table import Table
8+
from pathlib import Path
89
# from detecteur_crypto import Analyser_fichier_uniquement
910
# from detecteur_crypto import Analyser_fichier_sequentiels
1011
from .detecteur_crypto import DetecteurCryptoOrchestrateur
@@ -55,7 +56,7 @@ def default_menu(self):
5556
self.console.print(menuTag,menuOption)
5657
time.sleep(0.02)
5758

58-
choix = self.prompt.ask("Veuillez choisir une option ",choices=["1","2","3","4","5","6"])
59+
choix = self.prompt.ask("Veuillez choisir une option ", choices=["1","2","3","4","5","6"])
5960
try:
6061
if choix == "1":
6162
self.menu_1()
@@ -163,7 +164,8 @@ def menu_5(self):
163164
mission_table.add_row("AES-256-GCM","mission4.enc","Acronyme d'une organisation internationale + année courante","Identifier le mode authentifié GCM et gérer l'authentification")
164165
mission_table.add_row("Fernet","mission5.enc","Phrase française simple encodée, liée à notre domaine d'étude","Reconnaître le format Fernet et sa structure particulière")
165166

166-
f = open("guideUtilisation.txt",'r')
167+
chemin = Path().cwd()/'guideUtilisation.txt'
168+
f = open(chemin,'r')
167169
algo_docs = Markdown(f.read())
168170
f.close()
169171

@@ -193,7 +195,7 @@ def menu_5(self):
193195

194196
for guide in guides:
195197
print(guide)
196-
print("\n")
198+
print("\n")
197199

198200
escape= input('')
199201
if escape != None:
@@ -205,4 +207,4 @@ def menu_6(self):
205207
time.sleep(2)
206208
self.console.clear()
207209

208-
consoleInterface()
210+
consoleInterface()

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)