11# Import des modules
22import hashlib
3- from cryptography .hazmat .primitives .ciphers import Cipher , algorithms , modes
3+ from cryptography .hazmat .primitives .ciphers import Cipher , algorithms
44from rich import print
5- import os , struct
6- import math
5+ import os
76import sys
7+ from typing import List
8+
89sys .path .append (os .path .join (os .path .dirname (__file__ ), '..' ))
910from crypto_analyzer import CryptoAnalyzer
1011from utils import calculer_entropie
@@ -26,12 +27,10 @@ class ChaCha20_Analyzer(CryptoAnalyzer):
2627 _CHACHA20_LONGUEUR_BLOC: la taille du bloc de chiffrement (64 bits)
2728 """
2829
29- _CHACHA20_LONGUEUR_CLE = 32
30- _CHACHA20_LONGUEUR_NONCE = 12 #fourni
31- _CHACHA20_LONGUEUR_TAG = 16
32- _CHACHA20_LONGUEUR_BLOC = 64
33-
34-
30+ _CHACHA20_LONGUEUR_CLE : int = 32
31+ _CHACHA20_LONGUEUR_NONCE : int = 12
32+ _CHACHA20_LONGUEUR_TAG : int = 16
33+ _CHACHA20_LONGUEUR_BLOC : int = 64
3534
3635 def identifier_algo (self , chemin_fichier_chiffre : str ) -> float :
3736 """
@@ -41,142 +40,104 @@ def identifier_algo(self, chemin_fichier_chiffre: str) -> float:
4140 - vérifiant l'absence de padding (pas de contrainte de taille)
4241 - vérifiant que la taille du fichier est suffisante pour contenir un nonce
4342
44- Retourne une probabilité entre 0 et 1(Pour connaitre la probabilité que l'algo de chiffrement utilisé soit l'ChaCha20).
43+ Retourne une probabilité entre 0 et 1 (Pour connaitre la probabilité que l'algo de chiffrement utilisé soit l'ChaCha20).
4544
4645 Args:
47- chemin_fichier_chiffre(str): le chemin du fichier chiffré à traiter .
46+ chemin_fichier_chiffre(str): le chemin du fichier chiffré à traiter.
4847
4948 Returns:
50- float: La probabilité que l'algo de chiffrement utilisé soit l'ChaCha20 apres le calcul.
49+ float: La probabilité que l'algo de chiffrement utilisé soit l'ChaCha20 après le calcul.
5150 """
5251 try :
5352 with open (chemin_fichier_chiffre , 'rb' ) as f :
54- donnees = f .read ()
53+ donnees : bytes = f .read ()
5554
5655 if len (donnees ) < self ._CHACHA20_LONGUEUR_NONCE :
57- return 0.0 # Fichier trop petit pour contenir un nonce
56+ return 0.0
5857
59- # Extraire le nonce présumé (12 premiers bytes)
60- nonce = donnees [:self ._CHACHA20_LONGUEUR_NONCE ]
61- donnees_chiffrees = donnees [self ._CHACHA20_LONGUEUR_NONCE :]
58+ nonce : bytes = donnees [:self ._CHACHA20_LONGUEUR_NONCE ]
59+ donnees_chiffrees : bytes = donnees [self ._CHACHA20_LONGUEUR_NONCE :]
6260
6361 if len (donnees_chiffrees ) == 0 :
64- return 0.0 # Pas de données chiffrées
62+ return 0.0
6563
66- # Critère 1: Vérifier la taille minimale
64+ taille_min : float = 0.0
6765 if len (donnees ) >= self ._CHACHA20_LONGUEUR_NONCE + 16 :
6866 taille_min = 1.0
69- else :
70- taille_min = 0.0
7167
72- # Critère 2: Vérifier l'entropie des données chiffrées (doit être très élevée)
73- entropie = calculer_entropie (donnees_chiffrees )
74- # L'entropie d'un chiffrement ChaCha20 devrait être proche de 8 bits/octet
75- if entropie / 8.0 > 1.0 :
76- entropie_max = 1.0
77- else :
78- entropie_max = entropie / 8.0
68+ entropie : float = calculer_entropie (donnees_chiffrees )
69+ entropie_max : float = min (entropie / 8.0 , 1.0 )
7970
80- # Critère 3: Vérifier l'absence de padding (pas de contrainte de taille)
81- # ChaCha20 est un chiffrement de flux, donc pas de padding
82- # On vérifie que la taille des données chiffrées n'est pas un multiple d'une taille de bloc commune
83- taille_donnees = len (donnees_chiffrees )
71+ padding_max : float = 1.0
72+ taille_donnees : int = len (donnees_chiffrees )
8473 if taille_donnees % 16 == 0 or taille_donnees % 8 == 0 :
8574 padding_max = 0.5
86- else :
87- padding_max = 1.0
8875
89- # Critère 4: Vérifier l'entropie du nonce (doit être élevée aussi)
90- entropie_nonce = calculer_entropie (nonce )
91- if entropie_nonce / 8.0 > 1.0 :
92- nonce_max = 1.0
93- else :
94- nonce_max = entropie_nonce / 8.0
76+ entropie_nonce : float = calculer_entropie (nonce )
77+ nonce_max : float = min (entropie_nonce / 8.0 , 1.0 )
9578
96- # Calcul de la probabilité finale (moyenne pondérée des scores)
97- probabilite = (taille_min * 0.1 +
79+ probabilite : float = (taille_min * 0.1 +
9880 entropie_max * 0.4 +
9981 padding_max * 0.3 +
10082 nonce_max * 0.2 )
10183
102- return min ( probabilite , 1.0 )
84+ return probabilite
10385
10486 except Exception as e :
10587 print (f"Erreur lors de l'identification de l'algorithme: { e } " )
10688 return 0.0
10789
90+ def filtrer_dictionnaire_par_indices (self , chemin_fichier_chiffre : str ) -> List [bytes ]:
91+ # En supposant qu'elle retourne une liste de bytes pour les clés.
92+ return []
10893
109- def filtrer_dictionnaire_par_indices (self , chemin_fichier_chiffre ):
110- pass
111-
112- def generer_cles_candidates (self , chemin_fichier_chiffre ):
113-
114- '''
115- Cette fonction se charge de générer les clés candidates pour le déchiffremment du fichier chiffré en utilisant
116- la dérivation sha256 pour renforcer les clées de chiffrement.
94+ def generer_cles_candidates (self , chemin_dictionnaire : str ) -> List [bytes ]:
95+ """
96+ Cette fonction se charge de générer les clés candidates pour le déchifremment du fichier chiffré en utilisant
97+ la dérivation sha256 pour renforcer les clées de chiffrement.
11798
118-
119- Args:
120- chemin_fichier_chiffre(str) : Le chemin vers le fichier chiffré
121-
122- Returns:
123- cles_candidates (list[bytes]) : Un tableau de clés, chaque clé étant une séquence d'octets
124- '''
99+ Args:
100+ chemin_dictionnaire(str) : Le chemin vers le dictionnaire.
125101
126- donnees_fichier_filtre = self .filtrer_dictionnaire_par_indices (chemin_fichier_chiffre )
127-
128- cle_candidates : list [bytes ] = []
102+ Returns:
103+ cles_candidates (List[bytes]) : Un tableau de clés, chaque clé étant une séquence d'octets.
104+ """
105+ donnees_fichier_filtre : List [bytes ] = self .filtrer_dictionnaire_par_indices (chemin_dictionnaire )
106+ cles_candidates : List [bytes ] = []
129107 for cle in donnees_fichier_filtre :
130- cle_candidates .append (hashlib .sha256 (cle ).digest ())
131-
132- return cle_candidates
108+ cles_candidates .append (hashlib .sha256 (cle ).digest ())
109+ return cles_candidates
133110
134111 def dechiffrer (self , chemin_fichier_chiffre : str , cle_donnee : bytes ) -> bytes :
135112 if len (cle_donnee ) != 32 :
136113 raise ValueError ("Erreur : La clé n'a pas la taille correcte" )
137- else :
138- try :
139- # Utiliser le chemin complet si c'est un chemin absolu, sinon ajouter le préfixe data/
140- if os .path .isabs (chemin_fichier_chiffre ):
141- fichier_path = chemin_fichier_chiffre
142- else :
143- fichier_path = f"data/{ chemin_fichier_chiffre } "
144-
145- with open (fichier_path , 'rb' ) as f :
146- nonce = f .read (self ._CHACHA20_LONGUEUR_NONCE )
147- texte_chiffre = f .read ()
148-
149- algorithm_chacha20 = algorithms .ChaCha20 (cle_donnee , nonce )
150- cipher = Cipher (algorithm_chacha20 , mode = None )
151- decrypteur = cipher .decryptor ()
152- resultat = decrypteur .update (texte_chiffre )
153-
154- # Retourner les bytes bruts comme attendu par l'interface
155- return resultat
156-
157- except Exception as e :
158- print (f"Une erreur est survenue : { e } " )
159- return b""
160- cle_candidates .append (hashlib .sha256 (cle ).encode (encoding = "utf-8" ))
161-
162- return cle_candidates
163-
164- def dechiffrer (self ,chemin_fichier_chiffer : str ,clef :bytes )-> str :
165- if len (clef ) != 32 : return ValueError ("Erreur : La clé a pas la taille correcte " )
166- else :
167- try :
168- with open (f"data/{ chemin_fichier_chiffer } " ,'rb' ) as f :
169- nonce = f .read (16 )
170- texte_chiffrer = f .read ()
171-
172- counter = 0
173- algorithm_chacha20 = algorithms .ChaCha20 (clef ,nonce )
174- cipher = Cipher (algorithm_chacha20 ,mode = None )
175- decrypteur = cipher .decryptor ()
176- return decrypteur .update (texte_chiffrer )
177- except Exception as e :
178- print (f"Une erreur est survenu : { e } " )
179-
180-
114+
115+ try :
116+ fichier_path : str = chemin_fichier_chiffre
117+ if not os .path .isabs (chemin_fichier_chiffre ):
118+ fichier_path = f"data/{ chemin_fichier_chiffre } "
119+
120+ with open (fichier_path , 'rb' ) as f :
121+ nonce : bytes = f .read (self ._CHACHA20_LONGUEUR_NONCE )
122+ texte_chiffre : bytes = f .read ()
123+
124+ algorithm_chacha20 = algorithms .ChaCha20 (cle_donnee , nonce )
125+ cipher = Cipher (algorithm_chacha20 , mode = None )
126+ decrypteur = cipher .decryptor ()
127+ resultat : bytes = decrypteur .update (texte_chiffre )
128+
129+ return resultat
181130
182- print (ChaCha20_Analyzer ().dechiffrer ("mission2.enc" ,os .urandom (32 )))
131+ except Exception as e :
132+ print (f"Une erreur est survenue : { e } " )
133+ return b""
134+
135+ # L'appel direct a été déplacé dans un bloc if __name__ == "__main__" pour de bonnes pratiques (Mouwafic)
136+ if __name__ == "__main__" :
137+ try :
138+ resultat_dechiffrement : bytes = ChaCha20_Analyzer ().dechiffrer ("mission2.enc" , os .urandom (32 ))
139+ print (f"Résultat du déchiffrement : { resultat_dechiffrement .decode ('utf-8' )} " )
140+ except ValueError as ve :
141+ print (ve )
142+ except FileNotFoundError :
143+ print ("Erreur: Le fichier 'mission2.enc' est introuvable." )
0 commit comments