Skip to content

Commit a83ae94

Browse files
mouwaficbdre-mandyseathiel-12
authored
Feature/tests unitaires (#42)
* Documentation de la fonction d'entropie * Essai de fusion (1/2) * Implementation de la fonction de validation du texte déchiffrer * Récupération du main (1/2) * Mise en place des tests unitaires (1/4) * Revert "Mise en place des tests unitaires (1/4)" This reverts commit e965801. * Mise en place des tests unitaires (1/4) * 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 * Mise en place des tests liés à l'analyzer aes cbc * Corrections de typage et de logique * Correction du comportement à la levée de l'exception * Correction de la lgoque de test de test_exception_déchiffrer * Corection de la logique de test_verification_texte_dechiffre * fix: Utilisation de pathlib pour une gestion portable des chemins. * 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 * Gestion des bugs de chemin et d'import * tests aes_gcm --------- Co-authored-by: e-mandy <andymfrd02@gmail.com> Co-authored-by: Seathiel <ogoudedjimonde@gmail.com>
1 parent 0690e7c commit a83ae94

File tree

12 files changed

+145
-41
lines changed

12 files changed

+145
-41
lines changed

main.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
11
from src.detecteur_crypto import DetecteurCryptoOrchestrateur
2-
print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc'))
2+
from src.analyzers.blowfish_analyzer import Blowfish_Analyzer
3+
from src.analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer
4+
from src.interface_console import consoleInterface
5+
import os
6+
# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc'))
7+
8+
# try:
9+
# resultat_dechiffrement: bytes = Blowfish_Analyzer().dechiffrer("data/mission3.enc", Blowfish_Analyzer().generer_cles_candidates('keys/wordlist.txt')[2])
10+
# print(f"Résultat du déchiffrement : {resultat_dechiffrement.decode('utf-8')}")
11+
# except ValueError as ve:
12+
# print(ve)
13+
# except FileNotFoundError:
14+
# print("Erreur: Le fichier 'mission3.enc' est introuvable.")
15+
16+
consoleInterface()

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cffi==1.17.1
2-
cryptography==45.0.5
2+
cryptography==43.0.0
33
pycparser==2.22
44
pycryptodome==3.23.0
55
rich==14.1.0

resultat.txt

160 Bytes
Binary file not shown.

src/analyzers/aes_gcm_analyzer.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,10 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]:
8585
cle_derivee: bytes = kdf.derive(mot_de_passe_en_octets)
8686
clees_candidates.append(cle_derivee)
8787

88-
return clees_candidates
88+
return clees_candidates
89+
90+
def identifier_algo(self, chemin_fichier_chiffre):
91+
return super().identifier_algo(chemin_fichier_chiffre)
92+
93+
def dechiffrer(self, chemin_fichier_chiffre, cle_donnee):
94+
return super().dechiffrer(chemin_fichier_chiffre, cle_donnee)

src/analyzers/blowfish_analyzer.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from src.crypto_analyzer import CryptoAnalyzer
22
from src.utils import calculer_entropie
33
import hashlib
4-
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
4+
import base64
5+
import re
6+
from cryptography.hazmat.primitives.ciphers import Cipher, modes
57
from cryptography.hazmat.primitives.padding import PKCS7
8+
from cryptography.hazmat.decrepit.ciphers.algorithms import Blowfish
69
class Blowfish_Analyzer(CryptoAnalyzer):
710
'''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.
811
@@ -17,7 +20,7 @@ class Blowfish_Analyzer(CryptoAnalyzer):
1720
1821
'''
1922

20-
__BLOWFISH_TAILLE_BLOC = 8
23+
__BLOWFISH_TAILLE_BLOC = 64
2124
__BLOWFISH_TAILLE_IV = 8
2225

2326
def identifier_algo(self, chemin_fichier_chiffre: str) -> float:
@@ -132,6 +135,18 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]:
132135

133136
return cles_candidates
134137

138+
def decode_base64(self, encoded_bytes, altchars=b'+/'):
139+
encoded_bytes = re.sub(
140+
rb'[^a-zA-Z0-9%s]+' %
141+
altchars, b'', encoded_bytes)
142+
143+
missing_padding_length = len(encoded_bytes) % 4
144+
145+
if missing_padding_length:
146+
encoded_bytes += b'=' * (4 - missing_padding_length)
147+
148+
return base64.b64decode(encoded_bytes, altchars)
149+
135150
def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes:
136151
"""
137152
Déchiffre le fichier supposé crypté par l'algorithme blowfish avec la clé donnée en respectant les critères de
@@ -146,19 +161,22 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes:
146161
"""
147162

148163
#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):
164+
print(cle_donnee)
165+
if len(cle_donnee) not in range(4, 55, 8):
166+
print(len(cle_donnee))
150167
raise ValueError('Taille de clé invalide.')
151168

152169
try:
153-
154-
algorithm_blowfish = algorithms.Blowfish(cle_donnee)
170+
171+
algorithm_blowfish = Blowfish(self.decode_base64(cle_donnee))
155172
texte_chiffre = ''
156173

157-
#Récupération de l'IV et des texte chiffré das le fichier
174+
#Récupération de l'IV et du texte chiffré dans le fichier
158175
with open(chemin_fichier_chiffre, 'rb') as f:
159-
initialization_vector = f.read(self.__BLOWFISH_TAILLE_IV)
160-
texte_chiffre = f.read()
176+
donnees = f.read()
161177
f.close()
178+
initialization_vector = donnees[:self.__BLOWFISH_TAILLE_IV]
179+
texte_chiffre = donnees[self.__BLOWFISH_TAILLE_IV:]
162180

163181
#Initialisation du cipher
164182
cipher = Cipher(algorithm_blowfish, modes.CBC(initialization_vector))
@@ -178,3 +196,11 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes:
178196
raise
179197

180198

199+
# if __name__ == "__main__":
200+
# try:
201+
# resultat_dechiffrement: bytes = Blowfish_Analyzer().dechiffrer("CryptoForensic-Python/data/mission3.enc", os.urandom(32))
202+
# print(f"Résultat du déchiffrement : {resultat_dechiffrement.decode('utf-8')}")
203+
# except ValueError as ve:
204+
# print(ve)
205+
# except FileNotFoundError:
206+
# print("Erreur: Le fichier 'mission2.enc' est introuvable.")

src/analyzers/chacha20_analyzer.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ def filtrer_dictionnaire_par_indices(self, chemin_dictionnaire: str) -> List[byt
100100
Returns:
101101
list[bytes]: La liste de tous les mots susceptibles d'être des clés adéquates.
102102
"""
103-
return []
103+
f = open('keys/wordlist.txt', 'rb')
104+
cle = f.readlines()
105+
f.close()
106+
return cle
104107

105108
def generer_cles_candidates(self, chemin_dictionnaire: str) -> List[bytes]:
106109
"""
@@ -117,6 +120,7 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> List[bytes]:
117120
cles_candidates: List[bytes] = []
118121
for cle in donnees_fichier_filtre:
119122
cles_candidates.append(hashlib.sha256(cle).digest())
123+
print(cles_candidates)
120124
return cles_candidates
121125

122126
def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes:
@@ -153,7 +157,7 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes:
153157
# L'appel direct a été déplacé dans un bloc if __name__ == "__main__" pour de bonnes pratiques (Mouwafic)
154158
if __name__ == "__main__":
155159
try:
156-
resultat_dechiffrement: bytes = ChaCha20_Analyzer().dechiffrer("mission2.enc", os.urandom(32))
160+
resultat_dechiffrement: bytes = ChaCha20_Analyzer().dechiffrer("data/mission2.enc", os.urandom(32))
157161
print(f"Résultat du déchiffrement : {resultat_dechiffrement.decode('utf-8')}")
158162
except ValueError as ve:
159163
print(ve)

src/detecteur_crypto.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
import os
33
import time
44
from typing import List, Union
5-
5+
from pathlib import Path
66
# Import des modules d'analyse
77
from src.analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer
88
from src.crypto_analyzer import CryptoAnalyzer
99
from src.analyzers.chacha20_analyzer import ChaCha20_Analyzer
1010
from src.analyzers.blowfish_analyzer import Blowfish_Analyzer
1111
from src.analyzers.aes_gcm_analyzer import Aes_Gcm_Analyzer
12+
from src.analyzers.fernet_analyzer import FernetAnalyzer
13+
from src.rapport_mission import generer_rapport_mission
1214

1315
# Import des modules utilitaries
1416
from src.utils import est_dechiffre
@@ -41,7 +43,8 @@ def __init__(self):
4143
"AES-CBC": Aes_Cbc_Analyzer(),
4244
"ChaCha20": ChaCha20_Analyzer(),
4345
"Blowfish": Blowfish_Analyzer(),
44-
"AES-GCM": Aes_Gcm_Analyzer()
46+
"AES-GCM": Aes_Gcm_Analyzer(),
47+
"Fernet": FernetAnalyzer(),
4548
}
4649
self.missions_completees: list[dict[str, Union[str, list[ResultatAnalyse], float]]] = []
4750
self.statistiques_globales: dict[str, Union[int, float]] = {
@@ -68,7 +71,7 @@ def analyser_fichier_specifique(self, chemin_fichier_chiffre: str) -> ResultatAn
6871

6972
try:
7073
# Vérification de l'existence du fichier
71-
if not os.path.exists(f"data/{chemin_fichier_chiffre}"):
74+
if not os.path.isfile(Path('data')/f"{chemin_fichier_chiffre}"):
7275
print("Erreur: Fichier non trouvé")
7376
return ResultatAnalyse("", b"", 0.0, b"", 0.0, 0)
7477

@@ -156,7 +159,7 @@ def mission_complete_automatique(self, dossier_chiffres: str, chemin_dictionnair
156159
chemin_fichier = os.path.join(dossier_chiffres, fichier)
157160

158161
# Analyse du fichier
159-
resultat = self.analyser_fichier_specifique(chemin_fichier)
162+
resultat = self.analyser_fichier_specifique(fichier)
160163

161164
# Tentative de déchiffrement si algorithme détecté
162165
if resultat.algo:
@@ -181,7 +184,7 @@ def mission_complete_automatique(self, dossier_chiffres: str, chemin_dictionnair
181184
print(f"{fichier}: Aucun algorithme détecté")
182185

183186
# Rapport de synthèse final
184-
self.generer_rapport_synthese(resultats, time.time() - debut_mission)
187+
generer_rapport_mission().generer_rapport_synthese(resultats, time.time() - debut_mission)
185188

186189
# Mise à jour des statistiques globales
187190
self.missions_completees.append({
@@ -251,4 +254,5 @@ def attaque_dictionnaire_manuelle(self, chemin_fichier: str, algorithme_choisi:
251254
print(f"Erreur lors de l'attaque: {str(e)}")
252255
temps_execution = time.time() - debut_attaque
253256
return ResultatAnalyse("", b"", 0.0, b"", temps_execution, 0)
254-
# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc'))
257+
258+
# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\data\\mission2.enc"))

src/interface_console.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def menu_1(self):
9494
print(f"\n[bold]Score de probabilité[/bold] : [green]{data.score_probabilite}[/green]")
9595
# print(data.texte_dechiffre)
9696
print(f"\n[bold]Temps d'éxécution[/bold] : [green]{round(data.temps_execution,4)}[/green] s")
97-
esc=input("Veuillez appuyer sur la touche entrer pour retrouner au menu principal")
97+
esc=input("Veuillez appuyer sur la touche entrer pour retourner au menu principal")
9898
if esc=="":
9999
self.default_menu()
100100
else : self.default_menu()
@@ -107,14 +107,24 @@ def menu_2(self):
107107
self.dynamiqueText("Mission complète automatique","green")
108108
self.dynamiqueText("Veuillez entrer le chemin du dossier :","white")
109109
time.sleep(0.02)
110-
# chemin_dossier = self.prompt.ask("Veuillez entrer le chemin du dossier : ")
111-
self.console.clear()
110+
111+
chemin_dossier = self.prompt.ask("Veuillez entrer le chemin du dossier : ")
112+
resultat = DetecteurCryptoOrchestrateur().mission_complete_automatique(chemin_dossier, "keys/wordlist.txt")
113+
print(line for line in resultat)
114+
# self.console.clear()
112115
self.dynamiqueText("Mission en cours...","green")
113116
time.sleep(0.02)
114-
self.console.clear()
117+
# self.console.clear()
115118
self.dynamiqueText("Mission terminée","green")
119+
120+
esc=input("Veuillez appuyer sur la touche entrer pour retourner au menu principal")
116121
time.sleep(0.02)
117-
self.default_menu()
122+
123+
if esc=="":
124+
self.default_menu()
125+
else : self.default_menu()
126+
127+
# self.default_menu()
118128

119129
def menu_3(self):
120130
self.console.clear()

src/rapport_mission.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ def recuperer_ancien_rapport(self, base_date:str)->list|str:
5656
except FileNotFoundError:
5757
print('Fichier non trouvé')
5858

59-
print(generer_rapport_mission().generer_rapport_synthese({
60-
'algorithme':'CHACHA20',
61-
'fichier': 'mission1.enc',
62-
'cle':'PK7',
63-
'tentatives':'127',
64-
'temps_execution':"368s",
65-
'taux_succes': "97%",
66-
'statut_succes':'Succès',
67-
'texte_dechiffre':'Je suis là!'
68-
}))
59+
# print(generer_rapport_mission().generer_rapport_synthese({
60+
# 'algorithme':'CHACHA20',
61+
# 'fichier': 'mission1.enc',
62+
# 'cle':'PK7',
63+
# 'tentatives':'127',
64+
# 'temps_execution':"368s",
65+
# 'taux_succes': "97%",
66+
# 'statut_succes':'Succès',
67+
# 'texte_dechiffre':'Je suis là!'
68+
# }))
6969

70-
print(generer_rapport_mission().recuperer_ancien_rapport("05/08/25")[0])
70+
# print(generer_rapport_mission().recuperer_ancien_rapport("05/08/25")[0])

src/utils.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import math
2+
import re
23
import string
34
from pathlib import Path
45
from typing import Any, Dict, List, TypedDict
@@ -55,10 +56,10 @@ def est_dechiffre(texte:str) -> bool:
5556
pourcent += 30
5657

5758
# Le respect de la ponctuation, les 20% restants
58-
if stats['ponctuation'] > 50 :
59+
if stats['ponctuation_valide'] > 50 :
5960
pourcent += 20
6061

61-
return True if pourcent > 70 else False
62+
return True if pourcent > 80 else False
6263

6364

6465

@@ -100,7 +101,7 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]:
100101
copy=texte
101102
for lettre in tab:
102103
copy=copy.replace(lettre, ' ')
103-
mots = [mot for mot in copy.strip().split(' ') if mot]
104+
mots = [mot.removesuffix('\n').removeprefix('\n') for mot in copy.strip().split(' ') if mot != '\n']
104105
stats['nombre_mots']=len(mots)
105106

106107
# Verifier que le chaque mot du texte est un mot anglais/francais
@@ -119,7 +120,7 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]:
119120
try:
120121
with open(chemin, 'r', encoding='latin-1') as f:
121122
for ligne in f:
122-
if ligne.strip() == mot:
123+
if re.match(ligne.strip().removesuffix('\n'), mot, re.I):
123124
mots_valides += 1
124125
trouve=True
125126
break

0 commit comments

Comments
 (0)