Skip to content

Commit 76baf3a

Browse files
Implémentation de la méthode déchiffrer et intégration dans le détecteur crypto (#31)
* Implementation de la fonction de validation du texte déchiffrer * Définition de la classe de gestion des rapports de ission et implémentatioon de la fonction de génération des rapport de synthèse * Implémentation de la fonction de recherche d'anciens rapports * merge réussi * Validation des tests et corrections du rapport mission * chekpoint: Blowfish _Analyzer.identifier_algo() * add: Intiialisation de Blowfish_Analyzer et implémentation de Blowfish_Analyzer.identifier_algo() * Implémentation de Blowfish_Analyzer.filtrer_dictionnaire_par_indice() * Correction de bug * Implementer de Blowfish déchiffrer * Integration de blowfish dans le detecteur crypto --------- Co-authored-by: Let Me Cook <badaroumouwafic@gmail.com>
1 parent b7e7fc7 commit 76baf3a

5 files changed

Lines changed: 103 additions & 51 deletions

File tree

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: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from ..detecteur_crypto import CryptoAnalyzer
22
from ..utils import calculer_entropie
33
import hashlib
4-
4+
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
5+
from cryptography.hazmat.primitives.padding import PKCS7
56
class Blowfish_Analyzer(CryptoAnalyzer):
67
'''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.
78
@@ -11,9 +12,14 @@ class Blowfish_Analyzer(CryptoAnalyzer):
1112
- dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées
1213
1314
Attributes:
14-
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)
1517
1618
'''
19+
20+
__BLOWFISH_TAILLE_BLOC = 8
21+
__BLOWFISH_TAILLE_IV = 8
22+
1723
def identifier_algo(self, chemin_fichier_chiffre: str) -> float:
1824
'''
1925
Détermine la probabilité que l'algo de chiffrement utilisé soit blowfish en:
@@ -96,32 +102,79 @@ def __filtrer_dictionnaire_par_indice(self, chemin_dictionnaire: str) -> list[st
96102
return mots_filtres
97103

98104
def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]:
99-
"""
100-
Génère une liste de clés candidates pour le déchiffrement.
101-
Les candidats incluent les mots de passe directs, leur hash MD5 et leur hash SHA1.
102-
103-
Args:
104-
chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire.
105-
106-
Returns:
107-
list[bytes]: Une liste des clés candidates sous forme d'octets.
108-
"""
109-
cles_candidates: list[bytes] = []
110-
# Utilisation de la méthode privée pour filtrer les mots
111-
mots_de_passe_cible = self.__filtrer_dictionnaire_par_indice(chemin_dictionnaire)
112-
113-
for mot in mots_de_passe_cible:
114-
mot_en_bytes = mot.encode("utf-8")
115-
116-
# 1. Ajouter le mot de passe direct comme clé candidate
117-
cles_candidates.append(mot_en_bytes)
118-
119-
# 2. Hachage MD5 et ajout à la liste (en bytes)
120-
hash_md5 = hashlib.md5(mot_en_bytes).digest()
121-
cles_candidates.append(hash_md5)
122-
123-
# 3. Hachage SHA1 et ajout à la liste (en bytes)
124-
hash_sha1 = hashlib.sha1(mot_en_bytes).digest()
125-
cles_candidates.append(hash_sha1)
126-
127-
return cles_candidates
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 & 9 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
"""
@@ -250,4 +250,4 @@ def attaque_dictionnaire_manuelle(self, chemin_fichier: str, algorithme_choisi:
250250
temps_execution = time.time() - debut_attaque
251251
return ResultatAnalyse("", b"", 0.0, b"", temps_execution, 0)
252252

253-
# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc'))
253+
print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\data\\mission2.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.04)
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()
@@ -145,7 +146,8 @@ def menu_5(self):
145146
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")
146147
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")
147148

148-
f = open("guideUtilisation.txt",'r')
149+
chemin = Path().cwd()/'guideUtilisation.txt'
150+
f = open(chemin,'r')
149151
algo_docs = Markdown(f.read())
150152
f.close()
151153

@@ -175,7 +177,7 @@ def menu_5(self):
175177

176178
for guide in guides:
177179
print(guide)
178-
print("\n")
180+
print("\n")
179181

180182
escape= input('')
181183
if escape != None:
@@ -187,4 +189,4 @@ def menu_6(self):
187189
time.sleep(2)
188190
self.console.clear()
189191

190-
consoleInterface()
192+
consoleInterface()

0 commit comments

Comments
 (0)