From f40bb5916365fd5459b8293ca627d506c85d3c14 Mon Sep 17 00:00:00 2001 From: e-mandy Date: Sat, 2 Aug 2025 15:40:23 +0100 Subject: [PATCH 01/27] Documentation de la fonction d'entropie --- src/utils.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils.py b/src/utils.py index 62ab214..92f5308 100644 --- a/src/utils.py +++ b/src/utils.py @@ -3,7 +3,16 @@ def valider_texte_dechiffre(texte): pass -def calculer_entropie(bytes): +def calculer_entropie(bytes) -> float: + ''' + Calcul l'entropie (le désordre dans une suite de données) afin de déterminer le degré d'improbabilité d'une chaine de données. + + Args: + bytes(bytes): La donnée brute contenue dans le fichier crypté. + + Returns: + float: l'entropie calculée. + ''' entropie = 0 proba_byte = 0 for specifique_byte in bytes: From 8f0dbfce701e060940317e458cb7a3e353c3da4d Mon Sep 17 00:00:00 2001 From: e-mandy Date: Sat, 2 Aug 2025 16:04:26 +0100 Subject: [PATCH 02/27] Essai de fusion (1/2) --- src/utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/utils.py b/src/utils.py index 997098b..3d2bfdb 100644 --- a/src/utils.py +++ b/src/utils.py @@ -45,7 +45,7 @@ def verifier_texte_dechiffre(texte: str): #Statistiques sur le texte - stats={ + stats={ 'imprimable':0, 'nombre_mots':0, 'p_mots_valide':0, @@ -55,9 +55,9 @@ def verifier_texte_dechiffre(texte: str): #Verifier le pourcentage de caractères imprimables. - for lettre in texte: - if lettre.isprintable(): - stats['imprimable']+= 100/len(texte) + for lettre in texte: + if lettre.isprintab:le(): + stats['imprimable']+= 100/len(texte) # Traitement du texte brut pour obtenir une séquence distinct de pseudo-mot à cette étape séparé par des espaces @@ -126,9 +126,9 @@ def verifier_texte_dechiffre(texte: str): def rangerDico(): - """ - Fonction utilitaire de rangement du dictionnaire anglais téléchargé - """ + """ + Fonction utilitaire de rangement du dictionnaire anglais téléchargé + """ i=0 compte = 0 # Ouverture du grand dictionnaire. From 2a008e249fc446ede2439ea4c7c5d0da47250e07 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Sun, 3 Aug 2025 11:54:01 +0100 Subject: [PATCH 03/27] =?UTF-8?q?Implementation=20de=20la=20fonction=20de?= =?UTF-8?q?=20validation=20du=20texte=20d=C3=A9chiffrer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/utils.py b/src/utils.py index 61804a4..5f4a4bd 100644 --- a/src/utils.py +++ b/src/utils.py @@ -12,11 +12,40 @@ def calculer_entropie(bytes: bytes) -> float: if(chaque_byte == specifique_byte): i += 1 proba_byte = 1 / i - entropie += (proba_byte) * math.log(1/proba_byte, 8) + entropie += (proba_byte) * math.log(1/proba_byte, 8) return entropie -def verifier_texte_dechiffre(texte: str): +def est_dechiffre(texte:str) -> bool: + """ + Détermine si oui ou non une chaine a été déchiffrée + + Args: + texte(str): la chaine en supposée déchiffrée + Returns: + bool: déchiffrée ou non + """ + stats:dict=verifier_texte_dechiffre(texte) + pourcent=0 + + # Les caractères imprimables constituent 50% de la validation du déchiffrement + if stats['imprimable'] > 70 : + pourcent += 50 + + # Le pourcentage de mots validés par les dictionnaires en constitue 30% + if stats['p_mots_valide'] > 50 : + pourcent += 30 + + # Le respect de la ponctuation, les 20% restants + if stats['ponctuation'] > 50 : + pourcent += 20 + + return True if pourcent > 70 else False + + + + +def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: """ Verifie que le dechiffrement d'un message a bien été effectué sur la base de certains critères. @@ -34,7 +63,7 @@ def verifier_texte_dechiffre(texte: str): #Statistiques sur le texte - stats={ + stats: dict = { 'imprimable':0, 'nombre_mots':0, 'p_mots_valide':0, @@ -111,7 +140,6 @@ def verifier_texte_dechiffre(texte: str): stats[key]=round(stats[key], 2) return stats - def rangerDico(): From b638a494081c7c90f6a181e936b3f81cc7476416 Mon Sep 17 00:00:00 2001 From: e-mandy Date: Sun, 3 Aug 2025 17:55:15 +0100 Subject: [PATCH 04/27] =?UTF-8?q?R=C3=A9cup=C3=A9ration=20du=20main=20(1/2?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/detecteur_crypto.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/detecteur_crypto.py b/src/detecteur_crypto.py index 45c6775..153e418 100644 --- a/src/detecteur_crypto.py +++ b/src/detecteur_crypto.py @@ -12,6 +12,4 @@ class DetecteurCryptoOrchestrateur: Initialisation de l'analyseur AES-CBC """ def __init__(self): - self.aes_cbc_analyzer = AesCbcAnalyzer() - - + self.aes_cbc_analyzer = AesCbcAnalyzer() \ No newline at end of file From e96580101f4ddcd0030487efcd4cc0b081672910 Mon Sep 17 00:00:00 2001 From: e-mandy Date: Sun, 3 Aug 2025 21:37:00 +0100 Subject: [PATCH 05/27] Mise en place des tests unitaires (1/4) --- src/utils.py | 29 +++++++---------------------- tests/test_global.py | 13 +++++++++++++ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/utils.py b/src/utils.py index 0804109..5919cf4 100644 --- a/src/utils.py +++ b/src/utils.py @@ -21,15 +21,11 @@ def calculer_entropie(bytes) -> float: for chaque_byte in bytes: if(chaque_byte == specifique_byte): i += 1 -<<<<<<< HEAD + proba_byte = 1 / i entropie += (proba_byte) * math.log(1/proba_byte, 8) return entropie -======= - proba_byte = 1 / i - entropie += (proba_byte) * math.log(1/proba_byte, 8) - return entropie ->>>>>>> 267a282fa6e0765b0437b0aa3ef6139dc3453987 + def est_dechiffre(texte:str) -> bool: @@ -79,15 +75,6 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: #Statistiques sur le texte -<<<<<<< HEAD - stats={ - 'imprimable':0, - 'nombre_mots':0, - 'p_mots_valide':0, - 'non_mots':[], - 'ponctuation_valide':0 - } -======= stats: dict = { 'imprimable':0, 'nombre_mots':0, @@ -95,7 +82,6 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: 'non_mots':[], 'ponctuation_valide':0 } ->>>>>>> 267a282fa6e0765b0437b0aa3ef6139dc3453987 #Verifier le pourcentage de caractères imprimables. @@ -105,7 +91,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: # Traitement du texte brut pour obtenir une séquence distinct de pseudo-mot à cette étape séparé par des espaces - tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@' + tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@?' copy=texte for lettre in tab: copy=copy.replace(lettre, ' ') @@ -119,9 +105,9 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: trouve=False if mot == '': continue for syl in ['Fr', 'En']: - chemin=f"{os.curdir}\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" - - with open(chemin, 'r') as f: + chemin=f"{os.curdir}.\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" + exit + with open(chemin, 'r') as f: ligne=f.readline() ligne=ligne.removesuffix('\n') @@ -129,7 +115,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: if ligne == mot: stats['p_mots_valide']+=100/len(copy) - print(stats['p_mots_valide'], mot) + print('\n', stats['p_mots_valide'], mot,) trouve=True break @@ -196,4 +182,3 @@ def rangerDico(): # rangerDico() -print(verifier_texte_dechiffre('neither#nor avec, ded_caractère a')) diff --git a/tests/test_global.py b/tests/test_global.py index e5e65e5..19dcc5a 100644 --- a/tests/test_global.py +++ b/tests/test_global.py @@ -1,5 +1,9 @@ # import de la library pour les tests from unittest import TestCase, main +import sys +sys.path.append('.') +sys.path.append('..') +from src.utils import verifier_texte_dechiffre, calculer_entropie """ Ici le TestCase pour le regroupement des Cas de figures de Tests et le main pour l'exécution automatique des tests définis dans la classe ci-dessous @@ -16,6 +20,15 @@ def test_addition(self): self.assertEqual(add(5,5),10) + def test_verification_texte_dechiffre(self): + self.assertDictEqual(verifier_texte_dechiffre("je talk !a mamamia:?"), {"imprimable": 100, "nombre_mots": 4, "p_mots_valide": 3, "nom_mots": ["mamamia"], "ponctuation_valide": 1}) + + def test_calcul_entropie(self): + self.assertGreater(calculer_entropie("aaaaaaaa"), 0) + + + + """ # La fonction doit être préfixé du mot test pour que le TestCase puisse le l'identifier en tant que méthode à tester (le snake_case ici devra être appliqué ici) From e119f5dc57f198d6c8978647a8b907ce0656ce73 Mon Sep 17 00:00:00 2001 From: e-mandy Date: Sun, 3 Aug 2025 21:41:06 +0100 Subject: [PATCH 06/27] Revert "Mise en place des tests unitaires (1/4)" This reverts commit e96580101f4ddcd0030487efcd4cc0b081672910. --- src/utils.py | 29 ++++++++++++++++++++++------- tests/test_global.py | 13 ------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/utils.py b/src/utils.py index 5919cf4..0804109 100644 --- a/src/utils.py +++ b/src/utils.py @@ -21,11 +21,15 @@ def calculer_entropie(bytes) -> float: for chaque_byte in bytes: if(chaque_byte == specifique_byte): i += 1 - +<<<<<<< HEAD proba_byte = 1 / i entropie += (proba_byte) * math.log(1/proba_byte, 8) return entropie - +======= + proba_byte = 1 / i + entropie += (proba_byte) * math.log(1/proba_byte, 8) + return entropie +>>>>>>> 267a282fa6e0765b0437b0aa3ef6139dc3453987 def est_dechiffre(texte:str) -> bool: @@ -75,6 +79,15 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: #Statistiques sur le texte +<<<<<<< HEAD + stats={ + 'imprimable':0, + 'nombre_mots':0, + 'p_mots_valide':0, + 'non_mots':[], + 'ponctuation_valide':0 + } +======= stats: dict = { 'imprimable':0, 'nombre_mots':0, @@ -82,6 +95,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: 'non_mots':[], 'ponctuation_valide':0 } +>>>>>>> 267a282fa6e0765b0437b0aa3ef6139dc3453987 #Verifier le pourcentage de caractères imprimables. @@ -91,7 +105,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: # Traitement du texte brut pour obtenir une séquence distinct de pseudo-mot à cette étape séparé par des espaces - tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@?' + tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@' copy=texte for lettre in tab: copy=copy.replace(lettre, ' ') @@ -105,9 +119,9 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: trouve=False if mot == '': continue for syl in ['Fr', 'En']: - chemin=f"{os.curdir}.\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" - exit - with open(chemin, 'r') as f: + chemin=f"{os.curdir}\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" + + with open(chemin, 'r') as f: ligne=f.readline() ligne=ligne.removesuffix('\n') @@ -115,7 +129,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: if ligne == mot: stats['p_mots_valide']+=100/len(copy) - print('\n', stats['p_mots_valide'], mot,) + print(stats['p_mots_valide'], mot) trouve=True break @@ -182,3 +196,4 @@ def rangerDico(): # rangerDico() +print(verifier_texte_dechiffre('neither#nor avec, ded_caractère a')) diff --git a/tests/test_global.py b/tests/test_global.py index 19dcc5a..e5e65e5 100644 --- a/tests/test_global.py +++ b/tests/test_global.py @@ -1,9 +1,5 @@ # import de la library pour les tests from unittest import TestCase, main -import sys -sys.path.append('.') -sys.path.append('..') -from src.utils import verifier_texte_dechiffre, calculer_entropie """ Ici le TestCase pour le regroupement des Cas de figures de Tests et le main pour l'exécution automatique des tests définis dans la classe ci-dessous @@ -20,15 +16,6 @@ def test_addition(self): self.assertEqual(add(5,5),10) - def test_verification_texte_dechiffre(self): - self.assertDictEqual(verifier_texte_dechiffre("je talk !a mamamia:?"), {"imprimable": 100, "nombre_mots": 4, "p_mots_valide": 3, "nom_mots": ["mamamia"], "ponctuation_valide": 1}) - - def test_calcul_entropie(self): - self.assertGreater(calculer_entropie("aaaaaaaa"), 0) - - - - """ # La fonction doit être préfixé du mot test pour que le TestCase puisse le l'identifier en tant que méthode à tester (le snake_case ici devra être appliqué ici) From 14e759db98c3a4dbf914719981fb1e327b7dee03 Mon Sep 17 00:00:00 2001 From: e-mandy Date: Sun, 3 Aug 2025 21:54:35 +0100 Subject: [PATCH 07/27] Mise en place des tests unitaires (1/4) --- src/utils.py | 29 +++++++---------------------- tests/test_global.py | 13 +++++++++++++ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/utils.py b/src/utils.py index 0804109..5919cf4 100644 --- a/src/utils.py +++ b/src/utils.py @@ -21,15 +21,11 @@ def calculer_entropie(bytes) -> float: for chaque_byte in bytes: if(chaque_byte == specifique_byte): i += 1 -<<<<<<< HEAD + proba_byte = 1 / i entropie += (proba_byte) * math.log(1/proba_byte, 8) return entropie -======= - proba_byte = 1 / i - entropie += (proba_byte) * math.log(1/proba_byte, 8) - return entropie ->>>>>>> 267a282fa6e0765b0437b0aa3ef6139dc3453987 + def est_dechiffre(texte:str) -> bool: @@ -79,15 +75,6 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: #Statistiques sur le texte -<<<<<<< HEAD - stats={ - 'imprimable':0, - 'nombre_mots':0, - 'p_mots_valide':0, - 'non_mots':[], - 'ponctuation_valide':0 - } -======= stats: dict = { 'imprimable':0, 'nombre_mots':0, @@ -95,7 +82,6 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: 'non_mots':[], 'ponctuation_valide':0 } ->>>>>>> 267a282fa6e0765b0437b0aa3ef6139dc3453987 #Verifier le pourcentage de caractères imprimables. @@ -105,7 +91,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: # Traitement du texte brut pour obtenir une séquence distinct de pseudo-mot à cette étape séparé par des espaces - tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@' + tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@?' copy=texte for lettre in tab: copy=copy.replace(lettre, ' ') @@ -119,9 +105,9 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: trouve=False if mot == '': continue for syl in ['Fr', 'En']: - chemin=f"{os.curdir}\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" - - with open(chemin, 'r') as f: + chemin=f"{os.curdir}.\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" + exit + with open(chemin, 'r') as f: ligne=f.readline() ligne=ligne.removesuffix('\n') @@ -129,7 +115,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: if ligne == mot: stats['p_mots_valide']+=100/len(copy) - print(stats['p_mots_valide'], mot) + print('\n', stats['p_mots_valide'], mot,) trouve=True break @@ -196,4 +182,3 @@ def rangerDico(): # rangerDico() -print(verifier_texte_dechiffre('neither#nor avec, ded_caractère a')) diff --git a/tests/test_global.py b/tests/test_global.py index e5e65e5..19dcc5a 100644 --- a/tests/test_global.py +++ b/tests/test_global.py @@ -1,5 +1,9 @@ # import de la library pour les tests from unittest import TestCase, main +import sys +sys.path.append('.') +sys.path.append('..') +from src.utils import verifier_texte_dechiffre, calculer_entropie """ Ici le TestCase pour le regroupement des Cas de figures de Tests et le main pour l'exécution automatique des tests définis dans la classe ci-dessous @@ -16,6 +20,15 @@ def test_addition(self): self.assertEqual(add(5,5),10) + def test_verification_texte_dechiffre(self): + self.assertDictEqual(verifier_texte_dechiffre("je talk !a mamamia:?"), {"imprimable": 100, "nombre_mots": 4, "p_mots_valide": 3, "nom_mots": ["mamamia"], "ponctuation_valide": 1}) + + def test_calcul_entropie(self): + self.assertGreater(calculer_entropie("aaaaaaaa"), 0) + + + + """ # La fonction doit être préfixé du mot test pour que le TestCase puisse le l'identifier en tant que méthode à tester (le snake_case ici devra être appliqué ici) From 01800d8a23abff6a814e21363b90e05088fd0091 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Mon, 4 Aug 2025 00:30:11 +0100 Subject: [PATCH 08/27] =?UTF-8?q?D=C3=A9finition=20de=20la=20classe=20de?= =?UTF-8?q?=20gestion=20des=20rapports=20de=20ission=20et=20impl=C3=A9ment?= =?UTF-8?q?atioon=20de=20la=20fonction=20de=20g=C3=A9n=C3=A9ration=20des?= =?UTF-8?q?=20rapport=20de=20synth=C3=A8se?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rapport_mission.py | 42 ++++++++++++++++++++++++++++++++++++++++ src/utils.py | 44 ++++++++++++++++++++++-------------------- 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/src/rapport_mission.py b/src/rapport_mission.py index e69de29..ea79e4e 100644 --- a/src/rapport_mission.py +++ b/src/rapport_mission.py @@ -0,0 +1,42 @@ +from datetime import date +import os + +class generer_rapport_mission(): + + def __init__(self): + pass + + def generer_rapport_synthese(self, resultats_de_mission:dict)->None: + """ + Retourne le rapport de mission effectué. + Args: + resultats_de_mission(dict): les résultats de l'opération de déchiffrement du fichier + Returns: + str: le rapport + """ + + equivalence=['AES-CBC-256', 'CHACHA20', 'BLOWFISH', 'AES-GCM', 'FERNET'] + + try : + rapport= f"RAPPORT DE SYNTHESE DU {date.today().strftime("%d/%m/%y")}\n " + + f"Mission {equivalence.index(resultats_de_mission['algorithme'].toupper()) + 1}: {resultats_de_mission['algorithme'].toupper()} \n" + + "I - Statistiques relatives à l'analyse du fichier\n" + + f"Fichier crypté par cet algorithme: {resultats_de_mission['fichier']}\n" + + f"Clé de déchiffrement identifiée: {resultats_de_mission['cle']} \n" + + f"Nombre de tentatives: {resultats_de_mission['tentatives']} \n" + + f"Temps d'exécution: {resultats_de_mission["temps_execution"]} \n" + + "II - Résultats obtenus" + + f"Taux réussite du déchiffrement: {resultats_de_mission['taux_succes']}({resultats_de_mission['statut_succes']})\n" + + f"Texte déchiffré: {resultats_de_mission['texte_dechiffre']} \n" + + # Ecriture du rapport dans le fichier rapport.txt pour les affichage ultérieurs + with open(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\rapport_mission.txt", 'a') as f: + f.write(rapport.replace('\n', '~')) + f.close() + + return rapport + except (KeyError, ValueError): + print("Une erreur s'est produite.") + + return rapport + diff --git a/src/utils.py b/src/utils.py index 5f4a4bd..bac1b0d 100644 --- a/src/utils.py +++ b/src/utils.py @@ -77,7 +77,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: if lettre.isprintable(): stats['imprimable']+= 100/len(texte) - # Traitement du texte brut pour obtenir une séquence distinct de pseudo-mot à cette étape séparé par des espaces + # Traitement du texte brut pour obtenir une séquence distincte de pseudo-mot à cette étape séparé par des espaces tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@' copy=texte @@ -86,7 +86,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: copy=copy.strip().split(' ') stats['nombre_mots']=len(copy) - # Verifier que le texte est un mot anglais/francais + # Verifier que le chaque mot du texte est un mot anglais/francais try: for mot in copy: @@ -149,25 +149,27 @@ def rangerDico(): i=0 compte = 0 # Ouverture du grand dictionnaire. - with open(f"{os.path.abspath(os.curdir)}\\words_alpha.txt",'r') as f: - while i<26: - # Définition du chemin vers le fichier de chaque mot en fonction de l'alphabet. - chemin=f"{os.curdir}\\CryptoForensic-Python\\dicoEn\\{string.ascii_lowercase[i]}.txt" - with open(chemin, 'a') as fichier: - #Ecriture dans le fichier. - fichier.write(string.ascii_lowercase[i]+'\n') - while 1 : - ligne=f.readline() - if ligne.startswith(string.ascii_lowercase[i]) or ligne.startswith('y'): - fichier.write(ligne) - compte += 1 - else : - break - # Fermeture du fichier apres écriture du dernier mot. - fichier.close() - i+=1 - print(compte) - + try : + with open(f"{os.path.abspath(os.curdir)}\\words_alpha.txt",'r') as f: + while i<26: + # Définition du chemin vers le fichier de chaque mot en fonction de l'alphabet. + chemin=f"{os.curdir}\\dicoEn\\{string.ascii_lowercase[i]}.txt" + with open(chemin, 'a') as fichier: + #Ecriture dans le fichier. + fichier.write(string.ascii_lowercase[i]+'\n') + while 1 : + ligne=f.readline() + if ligne.startswith(string.ascii_lowercase[i]) or ligne.startswith('y'): + fichier.write(ligne) + compte += 1 + else : + break + # Fermeture du fichier apres écriture du dernier mot. + fichier.close() + i+=1 + print(compte) + except FileNotFoundError: + raise FileNotFoundError.__call__() # rangerDico() print(verifier_texte_dechiffre('neither#nor avec, ded_caractère a')) From e3f5efabc63a20275ce5afa0f9a4296ef39d03f9 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Mon, 4 Aug 2025 01:15:57 +0100 Subject: [PATCH 09/27] =?UTF-8?q?Impl=C3=A9mentation=20de=20la=20fonction?= =?UTF-8?q?=20de=20recherche=20d'anciens=20rapports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rapport_mission.py | 28 ++++++++++++++++++++++++++-- src/utils.py | 3 ++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/rapport_mission.py b/src/rapport_mission.py index ea79e4e..df7184f 100644 --- a/src/rapport_mission.py +++ b/src/rapport_mission.py @@ -1,4 +1,4 @@ -from datetime import date +from datetime import date, datetime import os class generer_rapport_mission(): @@ -18,7 +18,7 @@ def generer_rapport_synthese(self, resultats_de_mission:dict)->None: equivalence=['AES-CBC-256', 'CHACHA20', 'BLOWFISH', 'AES-GCM', 'FERNET'] try : - rapport= f"RAPPORT DE SYNTHESE DU {date.today().strftime("%d/%m/%y")}\n " + rapport= f"RAPPORT DE SYNTHESE DU {date.today().strftime("%d/%m/%y")} à {str(datetime.now().time()).split('.')[0]}\n " + f"Mission {equivalence.index(resultats_de_mission['algorithme'].toupper()) + 1}: {resultats_de_mission['algorithme'].toupper()} \n" + "I - Statistiques relatives à l'analyse du fichier\n" + f"Fichier crypté par cet algorithme: {resultats_de_mission['fichier']}\n" @@ -40,3 +40,27 @@ def generer_rapport_synthese(self, resultats_de_mission:dict)->None: return rapport + + def recuperer_ancien_rapport(self, base_date:str)->list|str: + """ + Récupère un/les ancien(s) rapport(s) dans le fichier rapport.txt + + Args: + base_date(str): la date à laquelle le/les rapport(s) a/ont été émis + Returns: + list|str: les rapports s'ils existent. + + + """ + rapport=[] + try: + with open(f"{os.path.abspath(os.curdir)}\\rapport.txt", 'r') as f: + line=f.readline() + while line != "" : + if line.find(base_date) != -1: + rapport.append(line) + f.close() + return rapport if rapport.count() > 0 else 'Aucun rapport trouvé à cette date.' + except FileNotFoundError: + print('Fichier non trouvé') + diff --git a/src/utils.py b/src/utils.py index bac1b0d..57cb610 100644 --- a/src/utils.py +++ b/src/utils.py @@ -145,6 +145,7 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: def rangerDico(): """ Fonction utilitaire de rangement du dictionnaire anglais téléchargé + Pour effectuer des tests """ i=0 compte = 0 @@ -169,7 +170,7 @@ def rangerDico(): i+=1 print(compte) except FileNotFoundError: - raise FileNotFoundError.__call__() + print('Fichier non trouvé.') # rangerDico() print(verifier_texte_dechiffre('neither#nor avec, ded_caractère a')) From 52433f75af6b71f7fcf1ff444b64437e2c8da27f Mon Sep 17 00:00:00 2001 From: e-mandy Date: Mon, 4 Aug 2025 17:12:44 +0100 Subject: [PATCH 10/27] =?UTF-8?q?Mise=20en=20place=20des=20tests=20li?= =?UTF-8?q?=C3=A9s=20=C3=A0=20l'analyzer=20aes=20cbc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/analyzers/aes_cbc_analyzer.py | 2 +- src/utils.py | 1 - tests/test_analyzers.py | 33 +++++++++++++++++++++++++++++++ tests/test_global.py | 30 +++++++++++++--------------- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/analyzers/aes_cbc_analyzer.py b/src/analyzers/aes_cbc_analyzer.py index d1b07f5..c11b365 100644 --- a/src/analyzers/aes_cbc_analyzer.py +++ b/src/analyzers/aes_cbc_analyzer.py @@ -99,7 +99,7 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]: chemin_dictionnaire(str): le chemin du dictionnaire de mots de passes pour l'attaque par dictionnaire. Returns: - list[bytes]: liste des clés candidates. + list[bytes]: liste des clés candidates. ''' mots_de_passe_cible = self.filtrer_dictionnaire_par_indices(chemin_dictionnaire) diff --git a/src/utils.py b/src/utils.py index ede0a54..280a45d 100644 --- a/src/utils.py +++ b/src/utils.py @@ -3,7 +3,6 @@ import sys import os - def calculer_entropie(bytes) -> float: ''' Calcul l'entropie (le désordre dans une suite de données) afin de déterminer le degré d'improbabilité d'une chaine de données. diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py index e69de29..28a22ce 100644 --- a/tests/test_analyzers.py +++ b/tests/test_analyzers.py @@ -0,0 +1,33 @@ +from unittest import TestCase, main +import sys +sys.path.append('.') +sys.path.append('..') +from src.analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer + +class AnalyzersTester(TestCase): + + """ + Cette classe est principalement destinée à recueillir toutes les fonctions de test des analyseurs d'algorithme + de chiffrement. + """ + + def setUp(self): + self.chemin_fichier_chiffre = "data/mission1.enc" + self.wordlist = "keys/wordlist.txt" + self.analyser = Aes_Cbc_Analyzer() + + + def test_aes_cbc_identifier_algo(self): + self.assertAlmostEqual(self.analyser.identifier_algo(self.chemin_fichier_chiffre), 1) + + def test_aes_cbc_filtrage_dict(self): + self.assertIsInstance(self.analyser.filtrer_dictionnaire_par_indices(self.wordlist), list) + + def test_generation_cles_candidate(self): + self.assertIsInstance(self.analyser.generer_cles_candidates(self.wordlist), list) + + def test_exception_dechiffrer(self): + with self.assertRaises(FileNotFoundError): + self.analyser.dechiffrer("no_file_dohi.txt", self.analyser.generer_cles_candidates(self.wordlist)) + +main() \ No newline at end of file diff --git a/tests/test_global.py b/tests/test_global.py index 19dcc5a..67d0c42 100644 --- a/tests/test_global.py +++ b/tests/test_global.py @@ -15,6 +15,20 @@ def add(a,b): class BetaTester(TestCase): #Définition de la méthode de test + """ + # La fonction doit être préfixé du mot test pour que le TestCase puisse le l'identifier en tant que méthode à tester (le snake_case ici devra être appliqué ici) + + # En fonction du type de vérification que vous souhaitez effectué par rapport aux test les méthodes assert devront variés. + ex : * assertEqual() pour vérifier l'égalité. Dans le cas utilisé cette fonction vérifie si le retour de la fonction add correspond à la valeur 10 + * assertIn() pour vérifier si une variable est dans une iterable + * assertIsInstance() pour vérifier le type de retour d'une variable ou fonction etc... (description des méthodes à l'appui) + + NB : Pour tester sa fonction chacun devra faire un import pour éviter la redondance. + Chaque fonction à tester devra se retrouver dans la class BetaTester avec un nom clair et propre à sa fonctionnalité précédé du mot "test" + + command : pyhton test_global.py [-v (-- verbose)] (verbose pour un test avec plus de précision) + + """ def test_addition(self): self.assertEqual(add(5,5),10) @@ -27,20 +41,4 @@ def test_calcul_entropie(self): self.assertGreater(calculer_entropie("aaaaaaaa"), 0) - - -""" - # La fonction doit être préfixé du mot test pour que le TestCase puisse le l'identifier en tant que méthode à tester (le snake_case ici devra être appliqué ici) - - # En fonction du type de vérification que vous souhaitez effectué par rapport aux test les méthodes assert devront variés. - ex : * assertEqual() pour vérifier l'égalité. Dans le cas utilisé cette fonction vérifie si le retour de la fonction add correspond à la valeur 10 - * assertIn() pour vérifier si une variable est dans une iterable - * assertIsInstance() pour vérifier le type de retour d'une variable ou fonction etc... (description des méthodes à l'appui) - - NB : Pour tester sa fonction chacun devra faire un import pour éviter la redondance. - Chaque fonction à tester devra se retrouver dans la class BetaTester avec un nom clair et propre à sa fonctionnalité précédé du mot "test" - - command : pyhton test_global.py [-v (-- verbose)] (verbose pour un test avec plus de précision) - -""" main() \ No newline at end of file From af85ee29c6e700e3b6d6e5ae2c9498a397f043ad Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Mon, 4 Aug 2025 21:55:10 +0100 Subject: [PATCH 11/27] Corrections de typage et de logique --- src/utils.py | 133 ++++++++++++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/src/utils.py b/src/utils.py index 280a45d..e49fb1a 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,29 +1,36 @@ import math import string import sys -import os +from typing import Any, Dict, List, TypedDict -def calculer_entropie(bytes) -> float: - ''' - Calcul l'entropie (le désordre dans une suite de données) afin de déterminer le degré d'improbabilité d'une chaine de données. +class StatsDict(TypedDict): + imprimable: float + nombre_mots: int + p_mots_valide: float + non_mots: List[str] + ponctuation_valide: int - Args: - bytes(bytes): La donnée brute contenue dans le fichier crypté. +def calculer_entropie(bytes: bytes) -> float: + ''' + Calcul l'entropie (le désordre dans une suite de données) afin de déterminer le degré d'improbabilité d'une chaine de données. + + Args: + bytes(bytes): La donnée brute contenue dans le fichier crypté. - Returns: - float: l'entropie calculée. + Returns: + float: l'entropie calculée. ''' - entropie = 0 - proba_byte = 0 - for specifique_byte in bytes: - i = 1 - for chaque_byte in bytes: - if(chaque_byte == specifique_byte): - i += 1 + entropie = 0 + proba_byte = 0 + for specifique_byte in bytes: + i = 1 + for chaque_byte in bytes: + if(chaque_byte == specifique_byte): + i += 1 - proba_byte = 1 / i - entropie += (proba_byte) * math.log(1/proba_byte, 8) - return entropie + proba_byte = 1 / i + entropie += (proba_byte) * math.log(1/proba_byte, 8) + return entropie @@ -52,11 +59,10 @@ def est_dechiffre(texte:str) -> bool: pourcent += 20 return True if pourcent > 70 else False - - - -def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: + + +def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: """ Verifie que le dechiffrement d'un message a bien été effectué sur la base de certains critères. @@ -82,51 +88,51 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: 'ponctuation_valide':0 } + if not texte: + return stats + #Verifier le pourcentage de caractères imprimables. - - for lettre in texte: - if lettre.isprintable(): - stats['imprimable']+= 100/len(texte) - + stats['imprimable'] = int(sum(1 for char in texte if char.isprintable()) / len(texte) * 100) + # Traitement du texte brut pour obtenir une séquence distincte de pseudo-mot à cette étape séparé par des espaces tab='./:!\\}{_%*$£&#;,~"()[]=§|`^@?' copy=texte for lettre in tab: copy=copy.replace(lettre, ' ') - copy=copy.strip().split(' ') - stats['nombre_mots']=len(copy) + mots = [mot for mot in copy.strip().split(' ') if mot] + stats['nombre_mots']=len(mots) # Verifier que le chaque mot du texte est un mot anglais/francais try: - for mot in copy: + mots_valides = 0 + for mot in mots: trouve=False - if mot == '': continue + if not mot: continue + + first_char = mot[0].lower() + for syl in ['Fr', 'En']: - chemin=f"{os.curdir}.\\CryptoForensic-Python\\dico{syl}\\{mot[0]}.txt" - exit - with open(chemin, 'r') as f: - ligne=f.readline() - ligne=ligne.removesuffix('\n') - - while not trouve and ligne != "": - - if ligne == mot: - stats['p_mots_valide']+=100/len(copy) - print('\n', stats['p_mots_valide'], mot,) - trouve=True - break - - ligne=f.readline() - ligne=ligne.removesuffix('\n') - - f.close() + chemin=f"dico{syl}/{first_char}.txt" + try: + with open(chemin, 'r', encoding='latin-1') as f: + for ligne in f: + if ligne.strip() == mot: + mots_valides += 1 + trouve=True + break + except FileNotFoundError: + continue if trouve : break if not trouve : stats['non_mots'].append(mot) + if mots: + stats['p_mots_valide'] = round((mots_valides / len(mots)) * 100, 2) + else: + stats['p_mots_valide'] = 0.0 except Exception: tb=sys.exception().__traceback__ @@ -136,24 +142,17 @@ def verifier_texte_dechiffre(texte: str) -> dict[int, int, int, list, int]: #Verifier la structure de ponctuation. points='.?!;,' - nbr_ponct=0 - for point in points : - nbr_ponct+=texte.count(point) - for point in points : - partition= texte.partition(point) - if partition[2].startswith(' ') : - if (point in '?!.' and partition[2].lstrip()[0].isupper()) or (point in ';,' and partition[2].lstrip()[0].islower()): - stats['ponctuation_valide']+=100/nbr_ponct - - for key in stats: - print(key) - if isinstance(stats[key], float): - stats[key]=round(stats[key], 2) + count = 0 + for i, char in enumerate(texte): + if char in points: + if (i == len(texte) - 1) or (texte[i+1] == ' '): + count += 1 + stats['ponctuation_valide'] = count return stats -def rangerDico(): +def rangerDico() -> None: """ Fonction utilitaire de rangement du dictionnaire anglais téléchargé Pour effectuer des tests @@ -162,11 +161,13 @@ def rangerDico(): compte = 0 # Ouverture du grand dictionnaire. try : - with open(f"{os.path.abspath(os.curdir)}\\words_alpha.txt",'r') as f: + # Utilisation de Path pour un chemin portable + words_path = Path.cwd() / "words_alpha.txt" + with open(words_path,'r') as f: while i<26: # Définition du chemin vers le fichier de chaque mot en fonction de l'alphabet. - chemin=f"{os.curdir}\\dicoEn\\{string.ascii_lowercase[i]}.txt" - with open(chemin, 'a') as fichier: + dico_path = Path.cwd() / "dicoEn" / f"{string.ascii_lowercase[i]}.txt" + with open(dico_path, 'a') as fichier: #Ecriture dans le fichier. fichier.write(string.ascii_lowercase[i]+'\n') while 1 : From 896696aac1ce9f707ac3bb7b66dc54182a010b12 Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Mon, 4 Aug 2025 21:55:32 +0100 Subject: [PATCH 12/27] =?UTF-8?q?Correction=20du=20comportement=20=C3=A0?= =?UTF-8?q?=20la=20lev=C3=A9e=20de=20l'exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/analyzers/aes_cbc_analyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyzers/aes_cbc_analyzer.py b/src/analyzers/aes_cbc_analyzer.py index c11b365..719381e 100644 --- a/src/analyzers/aes_cbc_analyzer.py +++ b/src/analyzers/aes_cbc_analyzer.py @@ -155,4 +155,4 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes: return b"" except FileNotFoundError: - return b"" \ No newline at end of file + raise \ No newline at end of file From 339140377e7d4e921e35558ffc8e024f751f202f Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Mon, 4 Aug 2025 21:56:28 +0100 Subject: [PATCH 13/27] =?UTF-8?q?Correction=20de=20la=20lgoque=20de=20test?= =?UTF-8?q?=20de=20test=5Fexception=5Fd=C3=A9chiffrer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_analyzers.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py index 28a22ce..8129c39 100644 --- a/tests/test_analyzers.py +++ b/tests/test_analyzers.py @@ -27,7 +27,15 @@ def test_generation_cles_candidate(self): self.assertIsInstance(self.analyser.generer_cles_candidates(self.wordlist), list) def test_exception_dechiffrer(self): + cles_candidates = self.analyser.generer_cles_candidates(self.wordlist) + + if not cles_candidates: + self.fail("La liste des clés candidates ne devrait pas être vide.") + + premiere_cle = cles_candidates[0] + with self.assertRaises(FileNotFoundError): - self.analyser.dechiffrer("no_file_dohi.txt", self.analyser.generer_cles_candidates(self.wordlist)) + self.analyser.dechiffrer("no_file_dohi.txt", premiere_cle) -main() \ No newline at end of file +if __name__ == '__main__': + main() \ No newline at end of file From 9b38d2763331de5def4a5b6db0e6dde9ac98f1cf Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Mon, 4 Aug 2025 21:57:36 +0100 Subject: [PATCH 14/27] Corection de la logique de test_verification_texte_dechiffre --- tests/test_global.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/test_global.py b/tests/test_global.py index 67d0c42..f59e2cd 100644 --- a/tests/test_global.py +++ b/tests/test_global.py @@ -35,10 +35,16 @@ def test_addition(self): def test_verification_texte_dechiffre(self): - self.assertDictEqual(verifier_texte_dechiffre("je talk !a mamamia:?"), {"imprimable": 100, "nombre_mots": 4, "p_mots_valide": 3, "nom_mots": ["mamamia"], "ponctuation_valide": 1}) - - def test_calcul_entropie(self): + resultat = verifier_texte_dechiffre("je talk !a mamamia:?") + self.assertAlmostEqual(resultat['imprimable'], 100.0) + self.assertEqual(resultat['nombre_mots'], 4) + self.assertAlmostEqual(resultat['p_mots_valide'], 75.0) + self.assertEqual(resultat['non_mots'], ["mamamia"]) + self.assertEqual(resultat['ponctuation_valide'], 1) + + def test_calcul_entropie(self) -> None: self.assertGreater(calculer_entropie("aaaaaaaa"), 0) -main() \ No newline at end of file +if __name__ == '__main__': + main() \ No newline at end of file From 275b47adab2fa97fe1fab2f216c70271d4fd5b5c Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Mon, 4 Aug 2025 22:05:41 +0100 Subject: [PATCH 15/27] fix: Utilisation de pathlib pour une gestion portable des chemins. --- src/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.py b/src/utils.py index e49fb1a..40b05f4 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,6 +1,7 @@ import math import string import sys +from pathlib import Path from typing import Any, Dict, List, TypedDict class StatsDict(TypedDict): @@ -114,7 +115,7 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: first_char = mot[0].lower() for syl in ['Fr', 'En']: - chemin=f"dico{syl}/{first_char}.txt" + chemin = Path(f"dico{syl}") / f"{first_char}.txt" try: with open(chemin, 'r', encoding='latin-1') as f: for ligne in f: From ae4cfb024d04af635e6bb09a89a25829754b911b Mon Sep 17 00:00:00 2001 From: Seathiel Date: Mon, 4 Aug 2025 22:14:11 +0100 Subject: [PATCH 16/27] =?UTF-8?q?merge=20r=C3=A9ussi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.py b/src/utils.py index 40778c6..4e33074 100644 --- a/src/utils.py +++ b/src/utils.py @@ -116,7 +116,7 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: for syl in ['Fr', 'En']: - chemin = Path(f"dico{syl}") / f"{first_char}.txt" + chemin = Path(f"dico{syl}")/f"{first_char}.txt" try: with open(chemin, 'r', encoding='latin-1') as f: for ligne in f: @@ -187,3 +187,4 @@ def rangerDico() -> None: print('Fichier non trouvé.') # rangerDico() +print(verifier_texte_dechiffre('neither#nor, and .this.')) \ No newline at end of file From a2c05c595d206fd42a30bf9b80513482e03e6a2d Mon Sep 17 00:00:00 2001 From: Seathiel Date: Tue, 5 Aug 2025 00:11:26 +0100 Subject: [PATCH 17/27] Validation des tests et corrections du rapport mission --- dicoEn/i.txt | 1148 --------------------------------------- dicoEn/y.txt | 1148 +++++++++++++++++++++++++++++++++++++++ rapport_mission.txt | 1 + src/detecteur_crypto.py | 4 +- src/rapport_mission.py | 40 +- src/utils.py | 8 +- tests/test_global.py | 2 +- 7 files changed, 1179 insertions(+), 1172 deletions(-) create mode 100644 rapport_mission.txt diff --git a/dicoEn/i.txt b/dicoEn/i.txt index 4b45b4c..178a54d 100644 --- a/dicoEn/i.txt +++ b/dicoEn/i.txt @@ -1,152 +1,5 @@ i -y ia -ya -yaba -yabber -yabbered -yabbering -yabbers -yabbi -yabby -yabbie -yabble -yaboo -yabu -yacal -yacare -yacata -yacca -iacchic -iacchos -iacchus -yachan -iachimo -yacht -yachtdom -yachted -yachter -yachters -yachty -yachting -yachtings -yachtist -yachtman -yachtmanship -yachtmen -yachts -yachtsman -yachtsmanlike -yachtsmanship -yachtsmen -yachtswoman -yachtswomen -yack -yacked -yacking -yacks -yad -yadayim -yadava -yade -yadim -yaff -yaffed -yaffil -yaffing -yaffingale -yaffle -yaffler -yaffs -yager -yagers -yagger -yaghourt -yagi -yagis -yagnob -iago -yagourundi -yagua -yaguarundi -yaguas -yaguaza -yah -yahan -yahgan -yahganan -yahoo -yahoodom -yahooish -yahooism -yahooisms -yahoos -yahrzeit -yahrzeits -yahuna -yahuskin -yahveh -yahweh -yahwism -yahwist -yahwistic -yay -yaya -yair -yaird -yairds -yaje -yajein -yajeine -yajenin -yajenine -yajna -yajnavalkya -yajnopavita -yak -yaka -yakala -yakalo -yakamik -yakan -yakattalo -yakima -yakin -yakitori -yakitoris -yakka -yakked -yakker -yakkers -yakking -yakmak -yakman -yakona -yakonan -yaks -yaksha -yakshi -yakut -yakutat -yalb -yald -yale -yalensian -yali -yalla -yallaer -yallock -yallow -yam -yamacraw -yamalka -yamalkas -yamamadi -yamamai -yamanai -yamaskite -yamassee -yamato iamatology iamb iambe @@ -162,211 +15,21 @@ iambographer iambs iambus iambuses -yamel -yamen -yamens -yameo -yamilke -yammadji -yammer -yammered -yammerer -yammerers -yammering -yammerly -yammers -yamp -yampa -yampee -yamph -yams -yamshik -yamstchick -yamstchik -yamulka -yamulkas -yamun -yamuns ian -yan -yana -yanacona -yanan -yancopin -yander -yang -yanggona -yangs -yangtao -yangtze -yank -yanked -yankee -yankeedom -yankeefy -yankeeism -yankeeist -yankeeize -yankeeland -yankeeness -yankees -yanker -yanky -yanking -yanks -yankton -yanktonai -yannam -yannigan -yanolite -yanqui -yanquis ianthina ianthine ianthinite -yantra -yantras ianus iao -yao -yaoort -yaourt -yaourti -yap -yapa iapetus iapyges iapygian iapygii -yaply -yapman -yapness -yapock -yapocks -yapok -yapoks -yapon -yapons -yapp -yapped -yapper -yappers -yappy -yappiness -yapping -yappingly -yappish -yaps -yapster -yaqona -yaqui -yaquina -yar -yaray -yarak -yarb -yarborough -yard -yardage -yardages -yardang -yardarm -yardarms -yardbird -yardbirds -yarded -yarder -yardful -yardgrass -yarding -yardkeep -yardland -yardlands -yardman -yardmaster -yardmasters -yardmen -yards -yardsman -yardstick -yardsticks -yardwand -yardwands -yardwork -yardworks iare -yare -yarely -yarer -yarest -yareta -yariyari -yark -yarkand -yarke -yarkee -yarl -yarly -yarm -yarmalke -yarmelke -yarmelkes -yarmouth -yarmulka -yarmulke -yarmulkes -yarn -yarned -yarnen -yarner -yarners -yarning -yarns -yarnwindle iarovization -yarovization iarovize -yarovize iarovized -yarovized iarovizing -yarovizing -yarpha -yarr -yarraman -yarramen -yarran -yarry -yarringle -yarrow -yarrows -yarth -yarthen -yaru -yarura -yaruran -yaruro -yarwhelp -yarwhip -yas -yashiro -yashmac -yashmacs -yashmak -yashmaks -yasht -yasmak -yasmaks -yasna -yat -yatagan -yatagans -yataghan -yataghans -yatalite -yate -yati -yatigan iatraliptic iatraliptics iatric @@ -390,70 +53,6 @@ iatrophysical iatrophysicist iatrophysics iatrotechnics -yatter -yattered -yattering -yatters -yatvyag -yauapery -yaud -yauds -yauld -yaup -yauped -yauper -yaupers -yauping -yaupon -yaupons -yaups -yautia -yautias -yava -yavapai -yaw -yawed -yawey -yawy -yawing -yawl -yawled -yawler -yawling -yawls -yawlsman -yawmeter -yawmeters -yawn -yawned -yawney -yawner -yawners -yawnful -yawnfully -yawny -yawnily -yawniness -yawning -yawningly -yawnproof -yawns -yawnups -yawp -yawped -yawper -yawpers -yawping -yawpings -yawps -yawroot -yaws -yawshrub -yawweed -yaxche -yazata -yazdegerdian -yazoo ib iba ibad @@ -484,7 +83,6 @@ ibilao ibis ibisbill ibises -yblent ibm ibo ibolium @@ -705,7 +303,6 @@ icica icicle icicled icicles -ycie icier iciest icily @@ -719,10 +316,6 @@ icky ickier ickiest ickle -yclad -ycleped -ycleping -yclept icod icon icones @@ -824,14 +417,12 @@ ictuate ictus ictuses id -yd ida idaean idaein idaho idahoan idahoans -yday idaic idalia idalian @@ -1234,301 +825,13 @@ idrisid idrisite idrosis ids -yds idumaean ie -ye -yea -yeah -yealing -yealings -yean -yeaned -yeaning -yeanling -yeanlings -yeans -yeaoman -year -yeara -yearbird -yearbook -yearbooks -yeard -yearday -yeared -yearend -yearends -yearful -yearly -yearlies -yearling -yearlings -yearlong -yearn -yearned -yearner -yearners -yearnful -yearnfully -yearnfulness -yearning -yearningly -yearnings -yearnling -yearns -yearock -years -yearth -yeas -yeasayer -yeasayers -yeast -yeasted -yeasty -yeastier -yeastiest -yeastily -yeastiness -yeasting -yeastless -yeastlike -yeasts -yeat -yeather -yecch -yecchy -yecchs -yech -yechy -yechs -yed -yedding -yede -yederly -yee -yeech ieee -yeel -yeelaman -yeelin -yeelins -yees -yeeuch -yeeuck -yegg -yeggman -yeggmen -yeggs -yeguita -yeh -yeld -yeldrin -yeldrine -yeldring -yeldrock -yelek -yelk -yelks -yell -yelled -yeller -yellers -yelling -yelloch -yellow -yellowammer -yellowback -yellowbark -yellowbelly -yellowbellied -yellowbellies -yellowberry -yellowberries -yellowbill -yellowbird -yellowcake -yellowcrown -yellowcup -yellowed -yellower -yellowest -yellowfin -yellowfish -yellowhammer -yellowhead -yellowy -yellowing -yellowish -yellowishness -yellowknife -yellowlegs -yellowly -yellowman -yellowness -yellowroot -yellowrump -yellows -yellowseed -yellowshank -yellowshanks -yellowshins -yellowstone -yellowtail -yellowtails -yellowthorn -yellowthroat -yellowtop -yellowware -yellowweed -yellowwood -yellowwort -yells -yelm -yelmer -yelp -yelped -yelper -yelpers -yelping -yelps -yelt -yelver -yemeless -yemen -yemeni -yemenic -yemenite -yemenites -yeming -yemschik -yemsel -yen -yender -yengee -yengees -yengeese -yeni -yenisei -yeniseian -yenite -yenned -yenning -yens -yenta -yentas -yente -yentes -yentnite -yeo -yeom -yeoman -yeomaness -yeomanette -yeomanhood -yeomanly -yeomanlike -yeomanry -yeomanries -yeomanwise -yeomen -yeorling -yeowoman -yeowomen -yep -yepeleic -yepely -yephede -yeply -yer -yerava -yeraver -yerb -yerba -yerbal -yerbales -yerbas -yercum -yerd -yere -yerga -yerk -yerked -yerking -yerks -yern ierne -yertchuk -yerth -yerva -yes -yese -yeses -yeshibah -yeshiva -yeshivah -yeshivahs -yeshivas -yeshivot -yeshivoth -yeso -yessed -yesses -yessing -yesso -yest -yester -yesterday -yesterdayness -yesterdays -yestereve -yestereven -yesterevening -yesteryear -yesteryears -yestermorn -yestermorning -yestern -yesternight -yesternoon -yesterweek -yesty -yestreen -yestreens -yet -yeta -yetapa -yeth -yether -yethhounds -yeti -yetis -yetlin -yetling -yett -yetter -yetts -yetzer -yeuk -yeuked -yeuky -yeukieness -yeuking -yeuks -yeven -yew -yews -yex -yez -yezdi -yezidi -yezzy if -yfacks ife ifecks -yfere -yferre iff iffy iffier @@ -1542,7 +845,6 @@ ifrit ifs ifugao igad -ygapo igara igarape igasuric @@ -1550,8 +852,6 @@ igbira igdyr igdrasil igelstromite -ygerne -yggdrasil ighly igitur iglesia @@ -1664,69 +964,12 @@ ihp ihram ihrams ihs -yhwh ii -yi iyar iiasa -yid -yiddish -yiddisher -yiddishism -yiddishist -yids -yield -yieldable -yieldableness -yieldance -yielded -yielden -yielder -yielders -yieldy -yielding -yieldingly -yieldingness -yields -yigh iii -yike -yikes -yikirgaulit -yildun -yill -yills -yilt -yin -yince -yins -yinst iyo -yip -yipe -yipes -yipped -yippee -yippie -yippies -yipping -yips -yird -yirds -yirk -yirm -yirmilik -yirn -yirr -yirred -yirring -yirrs -yirth -yirths -yis -yite iiwi -yizkor ijithad ijma ijmaa @@ -1750,7 +993,6 @@ ikons ikra il ila -ylahayll ilama ile ilea @@ -1759,8 +1001,6 @@ ileal ileectomy ileitides ileitis -ylem -ylems ileocaecal ileocaecum ileocecal @@ -2110,7 +1350,6 @@ ilpirra ilth ilvaite im -ym ima image imageable @@ -2325,7 +1564,6 @@ imbursed imbursement imbursing imbute -ymca imcnt imdtly imelle @@ -3857,7 +3095,6 @@ imsonic imu imvia in -yn inability inabilities inable @@ -3969,7 +3206,6 @@ inalterability inalterable inalterableness inalterably -ynambu inamia inamissibility inamissible @@ -11949,23 +11185,7 @@ inwrit inwritten inwrought io -yo -yob -yobbo -yobboes -yobbos -yobi -yobs -yocco -yochel -yock -yocked -yockel -yockernut -yocking -yocks iocs -yod iodal iodamoeba iodate @@ -11975,23 +11195,9 @@ iodating iodation iodations iode -yode -yodel -yodeled -yodeler -yodelers -yodeling -yodelist -yodelled -yodeller -yodellers -yodelling -yodels -yodh iodhydrate iodhydric iodhydrin -yodhs iodic iodid iodide @@ -12026,12 +11232,6 @@ iodizer iodizers iodizes iodizing -yodle -yodled -yodler -yodlers -yodles -yodling iodo iodobehenate iodobenzene @@ -12073,110 +11273,14 @@ iodothyrin iodous iodoxy iodoxybenzene -yods -yoe iof -yoga -yogas -yogasana -yogee -yogeeism -yogees -yogh -yoghourt -yoghourts -yoghs -yoghurt -yoghurts -yogi -yogic -yogin -yogini -yoginis -yogins -yogis -yogism -yogist -yogoite -yogurt -yogurts -yohimbe -yohimbenine -yohimbi -yohimbin -yohimbine -yohimbinization -yohimbinize -yoho -yohourt -yoi -yoy -yoick -yoicks -yoyo -yojan -yojana -yojuane -yok -yokage -yoke -yokeable -yokeableness -yokeage -yoked -yokefellow -yokel -yokeldom -yokeless -yokelish -yokelism -yokelry -yokels -yokemate -yokemates -yokemating -yoker -yokes -yokewise -yokewood -yoky -yoking -yokohama -yokozuna -yokozunas -yoks -yokuts -yolden -yoldia -yoldring iolite iolites -yolk -yolked -yolky -yolkier -yolkiest -yolkiness -yolkless -yolks -yom -yomer -yomim -yomin -yomud ion -yon -yoncopin -yond -yonder -yondmost -yondward ione ioni -yoni ionian ionic -yonic ionical ionicism ionicity @@ -12185,7 +11289,6 @@ ionicization ionicize ionics ionidium -yonis ionisable ionisation ionise @@ -12206,11 +11309,6 @@ ionizer ionizers ionizes ionizing -yonkalla -yonker -yonkers -yonner -yonnie ionogen ionogenic ionomer @@ -12226,148 +11324,31 @@ ionospheric ionospherically ionoxalis ions -yonside -yont iontophoresis -yook -yoop ioparameters -yor -yore -yores -yoretime -york -yorker -yorkers -yorkish -yorkist -yorkshire -yorkshireism -yorkshireman -yorlin iortn -yoruba -yoruban ios -yosemite ioskeha -yot iota iotacism -yotacism iotacisms iotacismus iotacist -yotacize iotas -yote iotization iotize iotized iotizing iou -you -youd -youden -youdendrift -youdith -youff -youl -young -youngberry -youngberries -younger -youngers -youngest -younghearted -youngish -younglet -youngly -youngling -younglings -youngness -youngs -youngster -youngsters -youngstown -youngth -youngun -younker -younkers -youp -youpon -youpons -your -youre -yourn -yours -yoursel -yourself -yourselves -yourt -yous -youse -youstir -youth -youthen -youthened -youthening -youthens -youthes -youthful -youthfully -youthfullity -youthfulness -youthhead -youthheid -youthhood -youthy -youthily -youthiness -youthless -youthlessness -youthly -youthlike -youthlikeness -youths -youthsome -youthtide -youthwort -youve -youward -youwards -youze -yoven -yow iowa iowan iowans -yowden -yowe -yowed -yowes -yowie -yowies -yowing -yowl -yowled -yowley -yowler -yowlers -yowling -yowlring -yowls -yows iowt -yowt -yox ipalnemohuani ipecac ipecacs ipecacuanha ipecacuanhic -yperite -yperites iph iphigenia iphimedia @@ -12379,14 +11360,10 @@ ipilipil ipl ipm ipocras -ypocras ipomea ipomoea ipomoeas ipomoein -yponomeuta -yponomeutid -yponomeutidae ipr iproniazid ips @@ -12398,15 +11375,10 @@ ipsedixitist ipseity ipsilateral ipsilaterally -ypsiliform -ypsiloid ipso -ypurinan iq iqs -yquem ir -yr ira iracund iracundity @@ -12436,7 +11408,6 @@ irateness irater iratest irbis -yrbk irchin ire ired @@ -13059,7 +12030,6 @@ irruptive irruptively irrupts irs -yrs irvin irving irvingesque @@ -13068,7 +12038,6 @@ irvingism irvingite irwin is -ys isaac isabel isabelina @@ -13968,7 +12937,6 @@ isurus iswara isz it -yt ita itabirite itacism @@ -14136,130 +13104,17 @@ itoubou its itself itsy -ytter -ytterbia -ytterbias -ytterbic -ytterbite -ytterbium -ytterbous -ytterite ittria -yttria -yttrialite -yttrias -yttric -yttriferous -yttrious -yttrium -yttriums -yttrocerite -yttrocolumbite -yttrocrasite -yttrofluorite -yttrogummite -yttrotantalite ituraean iturite itza itzebu -yuan -yuans -yuapin -yuca -yucatec -yucatecan -yucateco -yucca -yuccas -yucch -yuch -yuchi -yuck -yucked -yuckel -yucker -yucky -yuckier -yuckiest -yucking -yuckle -yucks iud iuds -yuechi -yuft -yug -yuga -yugada -yugas -yugoslav -yugoslavia -yugoslavian -yugoslavians -yugoslavic -yugoslavs -yuh -yuit -yuk -yukaghir -yukata -yuke -yuki -yukian -yukked -yukkel -yukking -yukon -yuks -yulan -yulans -yule -yuleblock -yules -yuletide -yuletides iulidan iulus -yum -yuma -yuman -yummy -yummier -yummies -yummiest -yun -yunca -yuncan -yungan -yunker -yunnanese -yup -yupon -yupons -yuppie -yuquilla -yuquillas -yurak iurant -yurok -yurt -yurta -yurts -yurucare -yurucarean -yurucari -yurujure -yuruk -yuruna -yurupary -yus -yusdrum -yustaga -yutu iuus -yuzlik -yuzluk iv iva ivan @@ -14276,7 +13131,6 @@ ivin ivyweed ivywood ivywort -yvonne ivory ivorybill ivoried @@ -14294,11 +13148,9 @@ iwa iwaiwa iwbells iwberry -ywca iwearth iwflower iwis -ywis iworth iwound iwurche diff --git a/dicoEn/y.txt b/dicoEn/y.txt index 975fbec..f60a064 100644 --- a/dicoEn/y.txt +++ b/dicoEn/y.txt @@ -1 +1,1149 @@ y +ya +yaba +yabber +yabbered +yabbering +yabbers +yabbi +yabby +yabbie +yabble +yaboo +yabu +yacal +yacare +yacata +yacca +iacchic +iacchos +iacchus +yachan +iachimo +yacht +yachtdom +yachted +yachter +yachters +yachty +yachting +yachtings +yachtist +yachtman +yachtmanship +yachtmen +yachts +yachtsman +yachtsmanlike +yachtsmanship +yachtsmen +yachtswoman +yachtswomen +yack +yacked +yacking +yacks +yad +yadayim +yadava +yade +yadim +yaff +yaffed +yaffil +yaffing +yaffingale +yaffle +yaffler +yaffs +yager +yagers +yagger +yaghourt +yagi +yagis +yagnob +iago +yagourundi +yagua +yaguarundi +yaguas +yaguaza +yah +yahan +yahgan +yahganan +yahoo +yahoodom +yahooish +yahooism +yahooisms +yahoos +yahrzeit +yahrzeits +yahuna +yahuskin +yahveh +yahweh +yahwism +yahwist +yahwistic +yay +yaya +yair +yaird +yairds +yaje +yajein +yajeine +yajenin +yajenine +yajna +yajnavalkya +yajnopavita +yak +yaka +yakala +yakalo +yakamik +yakan +yakattalo +yakima +yakin +yakitori +yakitoris +yakka +yakked +yakker +yakkers +yakking +yakmak +yakman +yakona +yakonan +yaks +yaksha +yakshi +yakut +yakutat +yalb +yald +yale +yalensian +yali +yalla +yallaer +yallock +yallow +yam +yamacraw +yamalka +yamalkas +yamamadi +yamamai +yamanai +yamaskite +yamassee +yamato +y +yamel +yamen +yamens +yameo +yamilke +yammadji +yammer +yammered +yammerer +yammerers +yammering +yammerly +yammers +yamp +yampa +yampee +yamph +yams +yamshik +yamstchick +yamstchik +yamulka +yamulkas +yamun +yamuns +yan +yana +yanacona +yanan +yancopin +yander +yang +yanggona +yangs +yangtao +yangtze +yank +yanked +yankee +yankeedom +yankeefy +yankeeism +yankeeist +yankeeize +yankeeland +yankeeness +yankees +yanker +yanky +yanking +yanks +yankton +yanktonai +yannam +yannigan +yanolite +yanqui +yanquis +yantra +yantras +yao +yaoort +yaourt +yaourti +yap +yapa +yaply +yapman +yapness +yapock +yapocks +yapok +yapoks +yapon +yapons +yapp +yapped +yapper +yappers +yappy +yappiness +yapping +yappingly +yappish +yaps +yapster +yaqona +yaqui +yaquina +yar +yaray +yarak +yarb +yarborough +yard +yardage +yardages +yardang +yardarm +yardarms +yardbird +yardbirds +yarded +yarder +yardful +yardgrass +yarding +yardkeep +yardland +yardlands +yardman +yardmaster +yardmasters +yardmen +yards +yardsman +yardstick +yardsticks +yardwand +yardwands +yardwork +yardworks +yare +yarely +yarer +yarest +yareta +yariyari +yark +yarkand +yarke +yarkee +yarl +yarly +yarm +yarmalke +yarmelke +yarmelkes +yarmouth +yarmulka +yarmulke +yarmulkes +yarn +yarned +yarnen +yarner +yarners +yarning +yarns +yarnwindle +yarovization +yarovize +yarovized +yarovizing +yarpha +yarr +yarraman +yarramen +yarran +yarry +yarringle +yarrow +yarrows +yarth +yarthen +yaru +yarura +yaruran +yaruro +yarwhelp +yarwhip +yas +yashiro +yashmac +yashmacs +yashmak +yashmaks +yasht +yasmak +yasmaks +yasna +yat +yatagan +yatagans +yataghan +yataghans +yatalite +yate +yati +yatigan +yatter +yattered +yattering +yatters +yatvyag +yauapery +yaud +yauds +yauld +yaup +yauped +yauper +yaupers +yauping +yaupon +yaupons +yaups +yautia +yautias +yava +yavapai +yaw +yawed +yawey +yawy +yawing +yawl +yawled +yawler +yawling +yawls +yawlsman +yawmeter +yawmeters +yawn +yawned +yawney +yawner +yawners +yawnful +yawnfully +yawny +yawnily +yawniness +yawning +yawningly +yawnproof +yawns +yawnups +yawp +yawped +yawper +yawpers +yawping +yawpings +yawps +yawroot +yaws +yawshrub +yawweed +yaxche +yazata +yazdegerdian +yazoo +yblent +ycie +yclad +ycleped +ycleping +yclept +yd +yday +yds +ye +yea +yeah +yealing +yealings +yean +yeaned +yeaning +yeanling +yeanlings +yeans +yeaoman +year +yeara +yearbird +yearbook +yearbooks +yeard +yearday +yeared +yearend +yearends +yearful +yearly +yearlies +yearling +yearlings +yearlong +yearn +yearned +yearner +yearners +yearnful +yearnfully +yearnfulness +yearning +yearningly +yearnings +yearnling +yearns +yearock +years +yearth +yeas +yeasayer +yeasayers +yeast +yeasted +yeasty +yeastier +yeastiest +yeastily +yeastiness +yeasting +yeastless +yeastlike +yeasts +yeat +yeather +yecch +yecchy +yecchs +yech +yechy +yechs +yed +yedding +yede +yederly +yee +yeech +yeel +yeelaman +yeelin +yeelins +yees +yeeuch +yeeuck +yegg +yeggman +yeggmen +yeggs +yeguita +yeh +yeld +yeldrin +yeldrine +yeldring +yeldrock +yelek +yelk +yelks +yell +yelled +yeller +yellers +yelling +yelloch +yellow +yellowammer +yellowback +yellowbark +yellowbelly +yellowbellied +yellowbellies +yellowberry +yellowberries +yellowbill +yellowbird +yellowcake +yellowcrown +yellowcup +yellowed +yellower +yellowest +yellowfin +yellowfish +yellowhammer +yellowhead +yellowy +yellowing +yellowish +yellowishness +yellowknife +yellowlegs +yellowly +yellowman +yellowness +yellowroot +yellowrump +yellows +yellowseed +yellowshank +yellowshanks +yellowshins +yellowstone +yellowtail +yellowtails +yellowthorn +yellowthroat +yellowtop +yellowware +yellowweed +yellowwood +yellowwort +yells +yelm +yelmer +yelp +yelped +yelper +yelpers +yelping +yelps +yelt +yelver +yemeless +yemen +yemeni +yemenic +yemenite +yemenites +yeming +yemschik +yemsel +yen +yender +yengee +yengees +yengeese +yeni +yenisei +yeniseian +yenite +yenned +yenning +yens +yenta +yentas +yente +yentes +yentnite +yeo +yeom +yeoman +yeomaness +yeomanette +yeomanhood +yeomanly +yeomanlike +yeomanry +yeomanries +yeomanwise +yeomen +yeorling +yeowoman +yeowomen +yep +yepeleic +yepely +yephede +yeply +yer +yerava +yeraver +yerb +yerba +yerbal +yerbales +yerbas +yercum +yerd +yere +yerga +yerk +yerked +yerking +yerks +yern +yertchuk +yerth +yerva +yes +yese +yeses +yeshibah +yeshiva +yeshivah +yeshivahs +yeshivas +yeshivot +yeshivoth +yeso +yessed +yesses +yessing +yesso +yest +yester +yesterday +yesterdayness +yesterdays +yestereve +yestereven +yesterevening +yesteryear +yesteryears +yestermorn +yestermorning +yestern +yesternight +yesternoon +yesterweek +yesty +yestreen +yestreens +yet +yeta +yetapa +yeth +yether +yethhounds +yeti +yetis +yetlin +yetling +yett +yetter +yetts +yetzer +yeuk +yeuked +yeuky +yeukieness +yeuking +yeuks +yeven +yew +yews +yex +yez +yezdi +yezidi +yezzy +yfacks +yfere +yferre +ygapo +ygerne +yggdrasil +yhwh +yi +yid +yiddish +yiddisher +yiddishism +yiddishist +yids +yield +yieldable +yieldableness +yieldance +yielded +yielden +yielder +yielders +yieldy +yielding +yieldingly +yieldingness +yields +yigh +yike +yikes +yikirgaulit +yildun +yill +yills +yilt +yin +yince +yins +yinst +yip +yipe +yipes +yipped +yippee +yippie +yippies +yipping +yips +yird +yirds +yirk +yirm +yirmilik +yirn +yirr +yirred +yirring +yirrs +yirth +yirths +yis +yite +yizkor +ylahayll +ylem +ylems +ym +ymca +yn +ynambu +yo +yob +yobbo +yobboes +yobbos +yobi +yobs +yocco +yochel +yock +yocked +yockel +yockernut +yocking +yocks +yod +yode +yodel +yodeled +yodeler +yodelers +yodeling +yodelist +yodelled +yodeller +yodellers +yodelling +yodels +yodh +yodhs +yodle +yodled +yodler +yodlers +yodles +yodling +yods +yoe +yoga +yogas +yogasana +yogee +yogeeism +yogees +yogh +yoghourt +yoghourts +yoghs +yoghurt +yoghurts +yogi +yogic +yogin +yogini +yoginis +yogins +yogis +yogism +yogist +yogoite +yogurt +yogurts +yohimbe +yohimbenine +yohimbi +yohimbin +yohimbine +yohimbinization +yohimbinize +yoho +yohourt +yoi +yoy +yoick +yoicks +yoyo +yojan +yojana +yojuane +yok +yokage +yoke +yokeable +yokeableness +yokeage +yoked +yokefellow +yokel +yokeldom +yokeless +yokelish +yokelism +yokelry +yokels +yokemate +yokemates +yokemating +yoker +yokes +yokewise +yokewood +yoky +yoking +yokohama +yokozuna +yokozunas +yoks +yokuts +yolden +yoldia +yoldring +yolk +yolked +yolky +yolkier +yolkiest +yolkiness +yolkless +yolks +yom +yomer +yomim +yomin +yomud +yon +yoncopin +yond +yonder +yondmost +yondward +yoni +yonic +yonis +yonkalla +yonker +yonkers +yonner +yonnie +yonside +yont +yook +yoop +yor +yore +yores +yoretime +york +yorker +yorkers +yorkish +yorkist +yorkshire +yorkshireism +yorkshireman +yorlin +yoruba +yoruban +yosemite +yot +yotacism +yotacize +yote +you +youd +youden +youdendrift +youdith +youff +youl +young +youngberry +youngberries +younger +youngers +youngest +younghearted +youngish +younglet +youngly +youngling +younglings +youngness +youngs +youngster +youngsters +youngstown +youngth +youngun +younker +younkers +youp +youpon +youpons +your +youre +yourn +yours +yoursel +yourself +yourselves +yourt +yous +youse +youstir +youth +youthen +youthened +youthening +youthens +youthes +youthful +youthfully +youthfullity +youthfulness +youthhead +youthheid +youthhood +youthy +youthily +youthiness +youthless +youthlessness +youthly +youthlike +youthlikeness +youths +youthsome +youthtide +youthwort +youve +youward +youwards +youze +yoven +yow +yowden +yowe +yowed +yowes +yowie +yowies +yowing +yowl +yowled +yowley +yowler +yowlers +yowling +yowlring +yowls +yows +yowt +yox +yperite +yperites +ypocras +yponomeuta +yponomeutid +yponomeutidae +ypsiliform +ypsiloid +ypurinan +yquem +yr +yrbk +yrs +ys +yt +ytter +ytterbia +ytterbias +ytterbic +ytterbite +ytterbium +ytterbous +ytterite +yttria +yttrialite +yttrias +yttric +yttriferous +yttrious +yttrium +yttriums +yttrocerite +yttrocolumbite +yttrocrasite +yttrofluorite +yttrogummite +yttrotantalite +yuan +yuans +yuapin +yuca +yucatec +yucatecan +yucateco +yucca +yuccas +yucch +yuch +yuchi +yuck +yucked +yuckel +yucker +yucky +yuckier +yuckiest +yucking +yuckle +yucks +yuechi +yuft +yug +yuga +yugada +yugas +yugoslav +yugoslavia +yugoslavian +yugoslavians +yugoslavic +yugoslavs +yuh +yuit +yuk +yukaghir +yukata +yuke +yuki +yukian +yukked +yukkel +yukking +yukon +yuks +yulan +yulans +yule +yuleblock +yules +yuletide +yuletides +yum +yuma +yuman +yummy +yummier +yummies +yummiest +yun +yunca +yuncan +yungan +yunker +yunnanese +yup +yupon +yupons +yuppie +yuquilla +yuquillas +yurak +yurok +yurt +yurta +yurts +yurucare +yurucarean +yurucari +yurujure +yuruk +yuruna +yurupary +yus +yusdrum +yustaga +yutu +yuzlik +yuzluk +yvonne +ywca +ywis diff --git a/rapport_mission.txt b/rapport_mission.txt new file mode 100644 index 0000000..5024c14 --- /dev/null +++ b/rapport_mission.txt @@ -0,0 +1 @@ +RAPPORT DE SYNTHESE DU 05/08/25 00:01:06~ Mission 2: CHACHA20 ~ I - Statistiques relatives l'analyse du fichier~Fichier crypt par cet algorithme: mission1.enc~Cl de dchiffrement identifie: PK7 ~Nombre de tentatives: 127 ~Temps d'excution: 368s ~ II - Rsultats obtenusTaux russite du dchiffrement: 97%(Succs)~Texte dchiffr: Je suis l! ~ \ No newline at end of file diff --git a/src/detecteur_crypto.py b/src/detecteur_crypto.py index 153e418..8f988cf 100644 --- a/src/detecteur_crypto.py +++ b/src/detecteur_crypto.py @@ -1,4 +1,4 @@ -import AesCbcAnalyzer +from analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer from crypto_analyzer import identifier_algo """ @@ -12,4 +12,4 @@ class DetecteurCryptoOrchestrateur: Initialisation de l'analyseur AES-CBC """ def __init__(self): - self.aes_cbc_analyzer = AesCbcAnalyzer() \ No newline at end of file + self.aes_cbc_analyzer = Aes_Cbc_Analyzer() \ No newline at end of file diff --git a/src/rapport_mission.py b/src/rapport_mission.py index df7184f..dac91b9 100644 --- a/src/rapport_mission.py +++ b/src/rapport_mission.py @@ -1,6 +1,6 @@ from datetime import date, datetime import os - +from pathlib import Path class generer_rapport_mission(): def __init__(self): @@ -10,7 +10,7 @@ def generer_rapport_synthese(self, resultats_de_mission:dict)->None: """ Retourne le rapport de mission effectué. Args: - resultats_de_mission(dict): les résultats de l'opération de déchiffrement du fichier + resultats_de_mission(dict{algorithme, fichier, cle, tentatives, temps_execution, taux_succes, texte_dechiffre}): les résultats de l'opération de déchiffrement du fichier Returns: str: le rapport """ @@ -18,19 +18,11 @@ def generer_rapport_synthese(self, resultats_de_mission:dict)->None: equivalence=['AES-CBC-256', 'CHACHA20', 'BLOWFISH', 'AES-GCM', 'FERNET'] try : - rapport= f"RAPPORT DE SYNTHESE DU {date.today().strftime("%d/%m/%y")} à {str(datetime.now().time()).split('.')[0]}\n " - + f"Mission {equivalence.index(resultats_de_mission['algorithme'].toupper()) + 1}: {resultats_de_mission['algorithme'].toupper()} \n" - + "I - Statistiques relatives à l'analyse du fichier\n" - + f"Fichier crypté par cet algorithme: {resultats_de_mission['fichier']}\n" - + f"Clé de déchiffrement identifiée: {resultats_de_mission['cle']} \n" - + f"Nombre de tentatives: {resultats_de_mission['tentatives']} \n" - + f"Temps d'exécution: {resultats_de_mission["temps_execution"]} \n" - + "II - Résultats obtenus" - + f"Taux réussite du déchiffrement: {resultats_de_mission['taux_succes']}({resultats_de_mission['statut_succes']})\n" - + f"Texte déchiffré: {resultats_de_mission['texte_dechiffre']} \n" + rapport= f"RAPPORT DE SYNTHESE DU {date.today().strftime("%d/%m/%y")} à {str(datetime.now().time()).split('.')[0]}\n " f"Mission {equivalence.index(resultats_de_mission['algorithme'].upper()) + 1}: {resultats_de_mission['algorithme'].upper()} \n I - Statistiques relatives à l'analyse du fichier\n" f"Fichier crypté par cet algorithme: {resultats_de_mission['fichier']}\n" f"Clé de déchiffrement identifiée: {resultats_de_mission['cle']} \n" f"Nombre de tentatives: {resultats_de_mission['tentatives']} \n" f"Temps d'exécution: {resultats_de_mission["temps_execution"]} \n II - Résultats obtenus" f"Taux réussite du déchiffrement: {resultats_de_mission['taux_succes']}({resultats_de_mission['statut_succes']})\n" f"Texte déchiffré: {resultats_de_mission['texte_dechiffre']} \n" # Ecriture du rapport dans le fichier rapport.txt pour les affichage ultérieurs - with open(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\rapport_mission.txt", 'a') as f: + chemin = Path(f"rapport_mission.txt") + with open(chemin, 'a') as f: f.write(rapport.replace('\n', '~')) f.close() @@ -54,13 +46,25 @@ def recuperer_ancien_rapport(self, base_date:str)->list|str: """ rapport=[] try: - with open(f"{os.path.abspath(os.curdir)}\\rapport.txt", 'r') as f: - line=f.readline() - while line != "" : + chemin = Path(f"rapport_mission.txt") + with open(chemin, 'r') as f: + for line in f: if line.find(base_date) != -1: - rapport.append(line) + rapport.append(line.replace('~', '\n')) f.close() - return rapport if rapport.count() > 0 else 'Aucun rapport trouvé à cette date.' + return rapport if rapport else 'Aucun rapport trouvé à cette date.' except FileNotFoundError: print('Fichier non trouvé') +print(generer_rapport_mission().generer_rapport_synthese({ + 'algorithme':'CHACHA20', + 'fichier': 'mission1.enc', + 'cle':'PK7', + 'tentatives':'127', + 'temps_execution':"368s", + 'taux_succes': "97%", + 'statut_succes':'Succès', + 'texte_dechiffre':'Je suis là!' +})) + +print(generer_rapport_mission().recuperer_ancien_rapport("05/08/25")[0]) \ No newline at end of file diff --git a/src/utils.py b/src/utils.py index 4e33074..599e7a9 100644 --- a/src/utils.py +++ b/src/utils.py @@ -145,11 +145,15 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: points='.?!;,' count = 0 + nbr_points = 0 for i, char in enumerate(texte): if char in points: + nbr_points += 1 if (i == len(texte) - 1) or (texte[i+1] == ' '): count += 1 - stats['ponctuation_valide'] = count + + if not nbr_points: nbr_points=1 + stats['ponctuation_valide'] = round(count*100/nbr_points, 2) return stats @@ -186,5 +190,3 @@ def rangerDico() -> None: except FileNotFoundError: print('Fichier non trouvé.') # rangerDico() - -print(verifier_texte_dechiffre('neither#nor, and .this.')) \ No newline at end of file diff --git a/tests/test_global.py b/tests/test_global.py index f59e2cd..a7b55fa 100644 --- a/tests/test_global.py +++ b/tests/test_global.py @@ -40,7 +40,7 @@ def test_verification_texte_dechiffre(self): self.assertEqual(resultat['nombre_mots'], 4) self.assertAlmostEqual(resultat['p_mots_valide'], 75.0) self.assertEqual(resultat['non_mots'], ["mamamia"]) - self.assertEqual(resultat['ponctuation_valide'], 1) + self.assertEqual(resultat['ponctuation_valide'], 50.0) def test_calcul_entropie(self) -> None: self.assertGreater(calculer_entropie("aaaaaaaa"), 0) From 7c1e4b451e621cfe220b6de4ccf1afb78745bd8a Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Thu, 7 Aug 2025 03:35:37 +0100 Subject: [PATCH 18/27] chekpoint: Blowfish _Analyzer.identifier_algo() --- src/analyzers/blowfish_analyzer.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/analyzers/blowfish_analyzer.py b/src/analyzers/blowfish_analyzer.py index e69de29..9a92eb9 100644 --- a/src/analyzers/blowfish_analyzer.py +++ b/src/analyzers/blowfish_analyzer.py @@ -0,0 +1,28 @@ +from ..detecteur_crypto import CryptoAnalyzer + +class Blowfish_Analyzer(CryptoAnalyzer): + '''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. + + Cette classe a trois méthodes: + - identifier_algo: Détermine si l'algo de chiffrement utilsé sur le fichier chiffré qui lui est passé en paramètre est blowfish. + - generer_cles_candidates: Génère une liste de clés candidates pour le déchiffrement du fichier chiffré + - dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées + + Attributes: + + + ''' + def identifier_algo(self, chemin_fichier_chiffre: str) -> float: + ''' + Détermine la probabilité que l'algo de chiffrement utilisé soit blowfish en: + + - + + Args: + chemin_fichier_chiffre(str): Le chemin du fichier chiffré à traiter (mission1.enc). + + Returns: + float: probabilité calculée. + ''' + + \ No newline at end of file From 6bb778006b45eae2ea887aa92a2c988c7ea798f5 Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Thu, 7 Aug 2025 13:13:55 +0100 Subject: [PATCH 19/27] =?UTF-8?q?add:=20Intiialisation=20de=20Blowfish=5FA?= =?UTF-8?q?nalyzer=20et=20impl=C3=A9mentation=20de=20Blowfish=5FAnalyzer.i?= =?UTF-8?q?dentifier=5Falgo()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/analyzers/blowfish_analyzer.py | 38 ++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/analyzers/blowfish_analyzer.py b/src/analyzers/blowfish_analyzer.py index 9a92eb9..7908118 100644 --- a/src/analyzers/blowfish_analyzer.py +++ b/src/analyzers/blowfish_analyzer.py @@ -1,4 +1,5 @@ from ..detecteur_crypto import CryptoAnalyzer +from ..utils import calculer_entropie class Blowfish_Analyzer(CryptoAnalyzer): '''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. @@ -16,7 +17,9 @@ def identifier_algo(self, chemin_fichier_chiffre: str) -> float: ''' Détermine la probabilité que l'algo de chiffrement utilisé soit blowfish en: - - + - vérifiant la présence d'un IV à l'en-tête (taille fichier > 8 octets) et que la taille du fichier est un multiple de 8 (blocs de 8 octets pour l'algo blowfish) + - calculant l'entropie des données chiffrées + - calculant l'entropie des sous blocs Args: chemin_fichier_chiffre(str): Le chemin du fichier chiffré à traiter (mission1.enc). @@ -25,4 +28,35 @@ def identifier_algo(self, chemin_fichier_chiffre: str) -> float: float: probabilité calculée. ''' - \ No newline at end of file + score = 0.0 + try: + with open(chemin_fichier_chiffre, "rb") as f: + contenu_fichier: bytes = f.read() + taille_totale = len(contenu_fichier) + TAILLE_IV = 8 + + # Heuristique 1 : Vérification de la taille (le critère le plus important) + if taille_totale > TAILLE_IV and taille_totale % 8 == 0: + score += 0.4 + + donnees_chiffrees = contenu_fichier[TAILLE_IV:] + + # Heuristique 2 : Vérification de l'entropie globale + entropie_globale = calculer_entropie(donnees_chiffrees) + if entropie_globale > 7.5: + score += 0.3 + + # Heuristique 3 : Vérification du "pattern Blowfish" (entropie par sous-blocs) + taille_donnees = len(donnees_chiffrees) + moitie = taille_donnees // 2 + + entropie_moitie1 = calculer_entropie(donnees_chiffrees[:moitie]) + entropie_moitie2 = calculer_entropie(donnees_chiffrees[moitie:]) + + if entropie_moitie1 > 7.5 and entropie_moitie2 > 7.5: + score += 0.3 + + except FileNotFoundError: + return 0.0 + + return score \ No newline at end of file From da7935e66647ff0050701ded4b11ed81c31f2bb5 Mon Sep 17 00:00:00 2001 From: mouwaficbdr Date: Thu, 7 Aug 2025 20:16:35 +0100 Subject: [PATCH 20/27] =?UTF-8?q?Impl=C3=A9mentation=20de=20Blowfish=5FAna?= =?UTF-8?q?lyzer.filtrer=5Fdictionnaire=5Fpar=5Findice()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/analyzers/blowfish_analyzer.py | 67 +++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/analyzers/blowfish_analyzer.py b/src/analyzers/blowfish_analyzer.py index 7908118..ec1b37f 100644 --- a/src/analyzers/blowfish_analyzer.py +++ b/src/analyzers/blowfish_analyzer.py @@ -1,5 +1,6 @@ from ..detecteur_crypto import CryptoAnalyzer from ..utils import calculer_entropie +import hashlib class Blowfish_Analyzer(CryptoAnalyzer): '''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. @@ -59,4 +60,68 @@ def identifier_algo(self, chemin_fichier_chiffre: str) -> float: except FileNotFoundError: return 0.0 - return score \ No newline at end of file + return score + + + def __filtrer_dictionnaire_par_indice(self, chemin_dictionnaire: str) -> list[str]: + """ + Filtre le dictionnaire en se basant sur les indices de la mission 3. + L'indice pointe vers un format de clé "sha + nombre + chiffres simples". + + Args: + chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire. + + Returns: + list[str]: Une liste de mots de passe filtrés. + """ + mots_filtres: list[str] = [] + + # Indices pour le préfixe et le suffixe + prefixes = ("sha256", "sha384", "sha512", "sha1") + suffixes = ("123", "456", "789") + + try: + with open(chemin_dictionnaire, "r", encoding="utf-8") as f: + for ligne in f: + mot = ligne.strip() + + # Vérifie si le mot commence par un préfixe et se termine par un suffixe + if mot.startswith(prefixes) and mot.endswith(suffixes): + mots_filtres.append(mot) + + except FileNotFoundError: + print(f"Erreur : Le fichier de dictionnaire '{chemin_dictionnaire}' est introuvable.") + return [] + + return mots_filtres + + def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]: + """ + Génère une liste de clés candidates pour le déchiffrement. + Les candidats incluent les mots de passe directs, leur hash MD5 et leur hash SHA1. + + Args: + chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire. + + Returns: + list[bytes]: Une liste des clés candidates sous forme d'octets. + """ + cles_candidates: list[bytes] = [] + # Utilisation de la méthode privée pour filtrer les mots + mots_de_passe_cible = self.__filtrer_dictionnaire_par_indice(chemin_dictionnaire) + + for mot in mots_de_passe_cible: + mot_en_bytes = mot.encode("utf-8") + + # 1. Ajouter le mot de passe direct comme clé candidate + cles_candidates.append(mot_en_bytes) + + # 2. Hachage MD5 et ajout à la liste (en bytes) + hash_md5 = hashlib.md5(mot_en_bytes).digest() + cles_candidates.append(hash_md5) + + # 3. Hachage SHA1 et ajout à la liste (en bytes) + hash_sha1 = hashlib.sha1(mot_en_bytes).digest() + cles_candidates.append(hash_sha1) + + return cles_candidates \ No newline at end of file From 746d05935bbbab92c2f27046763d733cf542f7af Mon Sep 17 00:00:00 2001 From: Seathiel Date: Thu, 7 Aug 2025 20:57:58 +0100 Subject: [PATCH 21/27] Correction de bug --- src/analyzers/aes_cbc_analyzer.py | 6 +++--- src/analyzers/chacha20_analyzer.py | 3 --- src/detecteur_crypto.py | 9 +++++---- src/interface_console.py | 10 ++++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/analyzers/aes_cbc_analyzer.py b/src/analyzers/aes_cbc_analyzer.py index 719381e..22bd935 100644 --- a/src/analyzers/aes_cbc_analyzer.py +++ b/src/analyzers/aes_cbc_analyzer.py @@ -1,5 +1,5 @@ -from ..crypto_analyzer import CryptoAnalyzer -from ..utils import calculer_entropie +from crypto_analyzer import CryptoAnalyzer +from utils import calculer_entropie from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes @@ -10,7 +10,7 @@ class Aes_Cbc_Analyzer(CryptoAnalyzer): Cette classe a trois méthodes: - 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. - - generer_cles_candidates: Génère une liste de clés candidates pour le déchiffrement du fichier chiffré + - generer_cles_candidates: Génère une liste de clés candidates pour le déchiffrement du fichier chiffré - dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées Attributes: diff --git a/src/analyzers/chacha20_analyzer.py b/src/analyzers/chacha20_analyzer.py index 715ddbe..0d5d91d 100644 --- a/src/analyzers/chacha20_analyzer.py +++ b/src/analyzers/chacha20_analyzer.py @@ -45,9 +45,6 @@ def dechiffrer(self,chemin_fichier_chiffer : str ,clef :bytes)->str: cipher = Cipher(algorithm_chacha20,mode=None) decrypteur = cipher.decryptor() return decrypteur.update(texte_chiffrer) - - - except Exception as e: print(f"Une erreur est survenu : {e}") diff --git a/src/detecteur_crypto.py b/src/detecteur_crypto.py index 93fb35d..f67f1c0 100644 --- a/src/detecteur_crypto.py +++ b/src/detecteur_crypto.py @@ -4,14 +4,14 @@ from typing import List, Union # Import des modules d'analyse -from .analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer -from .crypto_analyzer import CryptoAnalyzer +from analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer +from crypto_analyzer import CryptoAnalyzer # Import de la classe abstraite -from .analyzers.chacha20_analyzer import ChaCha20_Analyzer +from analyzers.chacha20_analyzer import ChaCha20_Analyzer # Import des modules utilitaries -from .utils import est_dechiffre +from utils import est_dechiffre class ResultatAnalyse: """ @@ -250,3 +250,4 @@ def attaque_dictionnaire_manuelle(self, chemin_fichier: str, algorithme_choisi: temps_execution = time.time() - debut_attaque return ResultatAnalyse("", b"", 0.0, b"", temps_execution, 0) +print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\data\\mission2.enc")) \ No newline at end of file diff --git a/src/interface_console.py b/src/interface_console.py index 205140b..130a49e 100644 --- a/src/interface_console.py +++ b/src/interface_console.py @@ -5,6 +5,7 @@ from rich.text import Text from rich.prompt import Prompt from rich.table import Table +from pathlib import Path # from detecteur_crypto import Analyser_fichier_uniquement # from detecteur_crypto import Analyser_fichier_sequentiels import time, os @@ -54,7 +55,7 @@ def default_menu(self): self.console.print(menuTag,menuOption) time.sleep(0.04) - choix = self.prompt.ask("Veuillez choisir une option ",choices=["1","2","3","4","5","6"]) + choix = self.prompt.ask("Veuillez choisir une option ", choices=["1","2","3","4","5","6"]) try: if choix == "1": self.menu_1() @@ -142,7 +143,8 @@ def menu_5(self): 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") 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") - f = open("guideUtilisation.txt",'r') + chemin = Path().cwd()/'guideUtilisation.txt' + f = open(chemin,'r') algo_docs = Markdown(f.read()) f.close() @@ -172,7 +174,7 @@ def menu_5(self): for guide in guides: print(guide) - print("\n") + print("\n") escape= input('') if escape != None: @@ -184,4 +186,4 @@ def menu_6(self): time.sleep(2) self.console.clear() -consoleInterface() \ No newline at end of file +consoleInterface() From 4eba401aeb945b79ae8a7c89e0e5504a2391e848 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Fri, 8 Aug 2025 00:05:18 +0100 Subject: [PATCH 22/27] =?UTF-8?q?Implementer=20de=20Blowfish=20d=C3=A9chif?= =?UTF-8?q?frer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/analyzers/blowfish_analyzer.py | 107 +++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 30 deletions(-) diff --git a/src/analyzers/blowfish_analyzer.py b/src/analyzers/blowfish_analyzer.py index ec1b37f..aa130f6 100644 --- a/src/analyzers/blowfish_analyzer.py +++ b/src/analyzers/blowfish_analyzer.py @@ -1,7 +1,8 @@ from ..detecteur_crypto import CryptoAnalyzer from ..utils import calculer_entropie import hashlib - +from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes +from cryptography.hazmat.primitives.padding import PKCS7 class Blowfish_Analyzer(CryptoAnalyzer): '''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. @@ -96,32 +97,78 @@ def __filtrer_dictionnaire_par_indice(self, chemin_dictionnaire: str) -> list[st return mots_filtres def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]: - """ - Génère une liste de clés candidates pour le déchiffrement. - Les candidats incluent les mots de passe directs, leur hash MD5 et leur hash SHA1. - - Args: - chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire. - - Returns: - list[bytes]: Une liste des clés candidates sous forme d'octets. - """ - cles_candidates: list[bytes] = [] - # Utilisation de la méthode privée pour filtrer les mots - mots_de_passe_cible = self.__filtrer_dictionnaire_par_indice(chemin_dictionnaire) - - for mot in mots_de_passe_cible: - mot_en_bytes = mot.encode("utf-8") - - # 1. Ajouter le mot de passe direct comme clé candidate - cles_candidates.append(mot_en_bytes) - - # 2. Hachage MD5 et ajout à la liste (en bytes) - hash_md5 = hashlib.md5(mot_en_bytes).digest() - cles_candidates.append(hash_md5) - - # 3. Hachage SHA1 et ajout à la liste (en bytes) - hash_sha1 = hashlib.sha1(mot_en_bytes).digest() - cles_candidates.append(hash_sha1) - - return cles_candidates \ No newline at end of file + """ + Génère une liste de clés candidates pour le déchiffrement. + Les candidats incluent les mots de passe directs, leur hash MD5 et leur hash SHA1. + + Args: + chemin_dictionnaire(str): Le chemin vers le fichier de dictionnaire. + + Returns: + list[bytes]: Une liste des clés candidates sous forme d'octets. + """ + cles_candidates: list[bytes] = [] + # Utilisation de la méthode privée pour filtrer les mots + mots_de_passe_cible = self.__filtrer_dictionnaire_par_indice(chemin_dictionnaire) + + for mot in mots_de_passe_cible: + mot_en_bytes = mot.encode("utf-8") + + # 1. Ajouter le mot de passe direct comme clé candidate + cles_candidates.append(mot_en_bytes) + + # 2. Hachage MD5 et ajout à la liste (en bytes) + hash_md5 = hashlib.md5(mot_en_bytes).digest() + cles_candidates.append(hash_md5) + + # 3. Hachage SHA1 et ajout à la liste (en bytes) + hash_sha1 = hashlib.sha1(mot_en_bytes).digest() + cles_candidates.append(hash_sha1) + + return cles_candidates + + def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes): + """ + Déchiffre le fichier supposé crypté par l'algorithme blowfish avec la clé donnée en respectant les critères de + - récupération de l'IV + - suppression de padding + + Args: + chemin_fichier_chiffre (str): le chemin vers le fichier chiffré + clee_donnee (bytes): La clé à utiliser pour le déchiffrement + Returns: + bytes: les données originales + """ + + #La taille de clé est dans l'intervalle 32-448bits et est multiple de 8 + if len(cle_donnee) not in range(32, 448, 8): + return ValueError('Taille de clé invalide.') + + try: + + algorithm_blowfish = algorithms.Blowfish(cle_donnee) + texte_chiffre = '' + + #Récupération de l'IV et des texte chiffré das le fichier + with open(chemin_fichier_chiffre, 'rb') as f: + initialization_vector = f.read(8) + texte_chiffre = f.read() + f.close() + + #Initialisation du cipher + cipher = Cipher(algorithm_blowfish, modes.CBC(initialization_vector)) + decrypteur = cipher.decryptor() + + #Suppresseur de padding + supresseur_padding = PKCS7(8).unpadder() + + #Décriptage des données avec le padding(remplissage aléatoire) + donnees_chiffrees_avec_padding = decrypteur.update(texte_chiffre) + decrypteur.finalize() + + #Suppression du padding et récupération de la donnée finale + donnees_originales = supresseur_padding.update(donnees_chiffrees_avec_padding) + supresseur_padding.finalize() + return donnees_originales + + except (FileNotFoundError): + raise + From 778632b0ce8702bb3c0039fe5239c09ed9959dac Mon Sep 17 00:00:00 2001 From: Seathiel Date: Fri, 8 Aug 2025 00:28:08 +0100 Subject: [PATCH 23/27] Integration de blowfish dans le detecteur crypto --- src/analyzers/blowfish_analyzer.py | 11 ++++++++--- src/detecteur_crypto.py | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/analyzers/blowfish_analyzer.py b/src/analyzers/blowfish_analyzer.py index 0e5ff10..8f3d47d 100644 --- a/src/analyzers/blowfish_analyzer.py +++ b/src/analyzers/blowfish_analyzer.py @@ -12,9 +12,14 @@ class Blowfish_Analyzer(CryptoAnalyzer): - dechiffrer: fait le déchiffrement proprement dit sur la base de la liste des clés générées Attributes: - + __BLOWFISH_TAILLE_BLOC : taille à considérer pour les blocs de données chiffrés que le PKCS7 doit prendre en compte (8 bits) + __BLOWFISH_TAILLE_IV : taille du vecteur d'initialisation en début de fichier (8 bits) ''' + + __BLOWFISH_TAILLE_BLOC = 8 + __BLOWFISH_TAILLE_IV = 8 + def identifier_algo(self, chemin_fichier_chiffre: str) -> float: ''' Détermine la probabilité que l'algo de chiffrement utilisé soit blowfish en: @@ -151,7 +156,7 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes): #Récupération de l'IV et des texte chiffré das le fichier with open(chemin_fichier_chiffre, 'rb') as f: - initialization_vector = f.read(8) + initialization_vector = f.read(self.__BLOWFISH_TAILLE_IV) texte_chiffre = f.read() f.close() @@ -160,7 +165,7 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes): decrypteur = cipher.decryptor() #Suppresseur de padding - supresseur_padding = PKCS7(8).unpadder() + supresseur_padding = PKCS7(self.__BLOWFISH_TAILLE_BLOC).unpadder() #Décriptage des données avec le padding(remplissage aléatoire) donnees_chiffrees_avec_padding = decrypteur.update(texte_chiffre) + decrypteur.finalize() diff --git a/src/detecteur_crypto.py b/src/detecteur_crypto.py index 62a44ee..4e21e4d 100644 --- a/src/detecteur_crypto.py +++ b/src/detecteur_crypto.py @@ -6,9 +6,8 @@ # Import des modules d'analyse from analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer from crypto_analyzer import CryptoAnalyzer - -# Import de la classe abstraite from analyzers.chacha20_analyzer import ChaCha20_Analyzer +from analyzers.blowfish_analyzer import Blowfish_Analyzer # Import des modules utilitaries from utils import est_dechiffre @@ -35,11 +34,12 @@ class DetecteurCryptoOrchestrateur: def __init__(self): """ - Initialisation de tous les modules d'analyse disponibles (AES-CBC pour le moment) + Initialisation de tous les modules d'analyse disponibles """ self.analyzers: dict[str, CryptoAnalyzer] = { "AES-CBC": Aes_Cbc_Analyzer(), "ChaCha20": ChaCha20_Analyzer(), + "Blowfish": Blowfish_Analyzer() } self.missions_completees: list[dict[str, Union[str, list[ResultatAnalyse], float]]] = [] self.statistiques_globales: dict[str, Union[int, float]] = { @@ -118,7 +118,7 @@ def __tenter_dechiffrement_avec_dictionnaire(self, chemin_fichier: str, cles_can print(f" Clé trouvée après {j+1} tentatives!") break else: - print(" Aucune clé valide trouvée") + print("Aucune clé valide trouvée") def mission_complete_automatique(self, dossier_chiffres: str, chemin_dictionnaire: str) -> List[ResultatAnalyse]: """ From 97432a628afed5cc57280d586654c4146b813958 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Sun, 10 Aug 2025 15:11:28 +0100 Subject: [PATCH 24/27] Gestion des bugs de chemin et d'import --- main.py | 16 ++++++++++- requirements.txt | 2 +- resultat.txt | Bin 0 -> 160 bytes src/analyzers/aes_gcm_analyzer.py | 10 +++++-- src/analyzers/blowfish_analyzer.py | 43 +++++++++++++++++++++++------ src/analyzers/chacha20_analyzer.py | 12 +++++--- src/detecteur_crypto.py | 21 +++++++------- src/interface_console.py | 20 ++++++++++---- src/rapport_mission.py | 22 +++++++-------- src/utils.py | 4 +-- 10 files changed, 106 insertions(+), 44 deletions(-) create mode 100644 resultat.txt diff --git a/main.py b/main.py index e548258..0324145 100644 --- a/main.py +++ b/main.py @@ -1,2 +1,16 @@ from src.detecteur_crypto import DetecteurCryptoOrchestrateur -print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc')) \ No newline at end of file +from src.analyzers.blowfish_analyzer import Blowfish_Analyzer +from src.analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer +from src.interface_console import consoleInterface +import os +# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique('data/mission1.enc')) + +# try: +# resultat_dechiffrement: bytes = Blowfish_Analyzer().dechiffrer("data/mission3.enc", Blowfish_Analyzer().generer_cles_candidates('keys/wordlist.txt')[2]) +# print(f"Résultat du déchiffrement : {resultat_dechiffrement.decode('utf-8')}") +# except ValueError as ve: +# print(ve) +# except FileNotFoundError: +# print("Erreur: Le fichier 'mission3.enc' est introuvable.") + +consoleInterface() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e688a26..07328da 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ cffi==1.17.1 -cryptography==45.0.5 +cryptography==43.0.0 pycparser==2.22 pycryptodome==3.23.0 rich==14.1.0 \ No newline at end of file diff --git a/resultat.txt b/resultat.txt new file mode 100644 index 0000000000000000000000000000000000000000..90e1ab6b3dd12c342de27940378e9fc51b9d0c42 GIT binary patch literal 160 zcmXYrF$#lF5JX=c@D5^=$`~{RJwhriEN%RLBSHv*LG$d%s;4u0WdjivwfUUfc%?u5&DfC|of=|F(=DyhbJvxC6A#`jN?(k4LMCai8I=$6 Nj*X9+XZ`cv{{d~I92@`u literal 0 HcmV?d00001 diff --git a/src/analyzers/aes_gcm_analyzer.py b/src/analyzers/aes_gcm_analyzer.py index 460f376..48f9544 100644 --- a/src/analyzers/aes_gcm_analyzer.py +++ b/src/analyzers/aes_gcm_analyzer.py @@ -1,4 +1,4 @@ -from ..crypto_analyzer import CryptoAnalyzer +from crypto_analyzer import CryptoAnalyzer from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives import hashes import re @@ -85,4 +85,10 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]: cle_derivee: bytes = kdf.derive(mot_de_passe_en_octets) clees_candidates.append(cle_derivee) - return clees_candidates \ No newline at end of file + return clees_candidates + + def identifier_algo(self, chemin_fichier_chiffre): + return super().identifier_algo(chemin_fichier_chiffre) + + def dechiffrer(self, chemin_fichier_chiffre, cle_donnee): + return super().dechiffrer(chemin_fichier_chiffre, cle_donnee) \ No newline at end of file diff --git a/src/analyzers/blowfish_analyzer.py b/src/analyzers/blowfish_analyzer.py index 8188db5..1a95e4b 100644 --- a/src/analyzers/blowfish_analyzer.py +++ b/src/analyzers/blowfish_analyzer.py @@ -1,8 +1,12 @@ +import base64 +import os from ..detecteur_crypto import CryptoAnalyzer from ..utils import calculer_entropie import hashlib -from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes +import re +from cryptography.hazmat.primitives.ciphers import Cipher, modes from cryptography.hazmat.primitives.padding import PKCS7 +from cryptography.hazmat.decrepit.ciphers.algorithms import Blowfish class Blowfish_Analyzer(CryptoAnalyzer): '''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. @@ -17,7 +21,7 @@ class Blowfish_Analyzer(CryptoAnalyzer): ''' - __BLOWFISH_TAILLE_BLOC = 8 + __BLOWFISH_TAILLE_BLOC = 64 __BLOWFISH_TAILLE_IV = 8 def identifier_algo(self, chemin_fichier_chiffre: str) -> float: @@ -132,6 +136,18 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> list[bytes]: return cles_candidates + def decode_base64(self, encoded_bytes, altchars=b'+/'): + encoded_bytes = re.sub( + rb'[^a-zA-Z0-9%s]+' % + altchars, b'', encoded_bytes) + + missing_padding_length = len(encoded_bytes) % 4 + + if missing_padding_length: + encoded_bytes += b'=' * (4 - missing_padding_length) + + return base64.b64decode(encoded_bytes, altchars) + def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes: """ Déchiffre le fichier supposé crypté par l'algorithme blowfish avec la clé donnée en respectant les critères de @@ -146,19 +162,22 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes: """ #La taille de clé est dans l'intervalle 32-448bits et est multiple de 8 - if len(cle_donnee) not in range(32, 448, 8): + print(cle_donnee) + if len(cle_donnee) not in range(4, 55, 8): + print(len(cle_donnee)) raise ValueError('Taille de clé invalide.') try: - - algorithm_blowfish = algorithms.Blowfish(cle_donnee) + + algorithm_blowfish = Blowfish(self.decode_base64(cle_donnee)) texte_chiffre = '' - #Récupération de l'IV et des texte chiffré das le fichier + #Récupération de l'IV et du texte chiffré dans le fichier with open(chemin_fichier_chiffre, 'rb') as f: - initialization_vector = f.read(self.__BLOWFISH_TAILLE_IV) - texte_chiffre = f.read() + donnees = f.read() f.close() + initialization_vector = donnees[:self.__BLOWFISH_TAILLE_IV] + texte_chiffre = donnees[self.__BLOWFISH_TAILLE_IV:] #Initialisation du cipher cipher = Cipher(algorithm_blowfish, modes.CBC(initialization_vector)) @@ -178,3 +197,11 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes: raise +# if __name__ == "__main__": +# try: +# resultat_dechiffrement: bytes = Blowfish_Analyzer().dechiffrer("CryptoForensic-Python/data/mission3.enc", os.urandom(32)) +# print(f"Résultat du déchiffrement : {resultat_dechiffrement.decode('utf-8')}") +# except ValueError as ve: +# print(ve) +# except FileNotFoundError: +# print("Erreur: Le fichier 'mission2.enc' est introuvable.") \ No newline at end of file diff --git a/src/analyzers/chacha20_analyzer.py b/src/analyzers/chacha20_analyzer.py index 725e0dc..7b60bfe 100644 --- a/src/analyzers/chacha20_analyzer.py +++ b/src/analyzers/chacha20_analyzer.py @@ -8,8 +8,8 @@ from typing import List sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -from crypto_analyzer import CryptoAnalyzer -from utils import calculer_entropie +from ..crypto_analyzer import CryptoAnalyzer +from ..utils import calculer_entropie # Définition de la classe ChaCha20_Analyzer class ChaCha20_Analyzer(CryptoAnalyzer): @@ -101,7 +101,10 @@ def filtrer_dictionnaire_par_indices(self, chemin_dictionnaire: str) -> List[byt Returns: list[bytes]: La liste de tous les mots susceptibles d'être des clés adéquates. """ - return [] + f = open('keys/wordlist.txt', 'rb') + cle = f.readlines() + f.close() + return cle def generer_cles_candidates(self, chemin_dictionnaire: str) -> List[bytes]: """ @@ -118,6 +121,7 @@ def generer_cles_candidates(self, chemin_dictionnaire: str) -> List[bytes]: cles_candidates: List[bytes] = [] for cle in donnees_fichier_filtre: cles_candidates.append(hashlib.sha256(cle).digest()) + print(cles_candidates) return cles_candidates def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes: @@ -154,7 +158,7 @@ def dechiffrer(self, chemin_fichier_chiffre: str, cle_donnee: bytes) -> bytes: # L'appel direct a été déplacé dans un bloc if __name__ == "__main__" pour de bonnes pratiques (Mouwafic) if __name__ == "__main__": try: - resultat_dechiffrement: bytes = ChaCha20_Analyzer().dechiffrer("mission2.enc", os.urandom(32)) + resultat_dechiffrement: bytes = ChaCha20_Analyzer().dechiffrer("data/mission2.enc", os.urandom(32)) print(f"Résultat du déchiffrement : {resultat_dechiffrement.decode('utf-8')}") except ValueError as ve: print(ve) diff --git a/src/detecteur_crypto.py b/src/detecteur_crypto.py index df8bfca..c3377c6 100644 --- a/src/detecteur_crypto.py +++ b/src/detecteur_crypto.py @@ -2,13 +2,14 @@ import os import time from typing import List, Union - +from pathlib import Path # Import des modules d'analyse -from analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer -from crypto_analyzer import CryptoAnalyzer -from analyzers.chacha20_analyzer import ChaCha20_Analyzer -from analyzers.blowfish_analyzer import Blowfish_Analyzer -from analyzers.aes_gcm_analyzer import Aes_Gcm_Analyzer +from .analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer +from .crypto_analyzer import CryptoAnalyzer +from .analyzers.chacha20_analyzer import ChaCha20_Analyzer +from .analyzers.blowfish_analyzer import Blowfish_Analyzer +from .analyzers.aes_gcm_analyzer import Aes_Gcm_Analyzer +from .rapport_mission import generer_rapport_mission # Import des modules utilitaries from utils import est_dechiffre @@ -68,7 +69,7 @@ def analyser_fichier_specifique(self, chemin_fichier_chiffre: str) -> ResultatAn try: # Vérification de l'existence du fichier - if not os.path.exists(f"data/{chemin_fichier_chiffre}"): + if not os.path.isfile(Path('data')/f"{chemin_fichier_chiffre}"): print("Erreur: Fichier non trouvé") return ResultatAnalyse("", b"", 0.0, b"", 0.0, 0) @@ -156,7 +157,7 @@ def mission_complete_automatique(self, dossier_chiffres: str, chemin_dictionnair chemin_fichier = os.path.join(dossier_chiffres, fichier) # Analyse du fichier - resultat = self.analyser_fichier_specifique(chemin_fichier) + resultat = self.analyser_fichier_specifique(fichier) # Tentative de déchiffrement si algorithme détecté if resultat.algo: @@ -181,7 +182,7 @@ def mission_complete_automatique(self, dossier_chiffres: str, chemin_dictionnair print(f"{fichier}: Aucun algorithme détecté") # Rapport de synthèse final - self.generer_rapport_synthese(resultats, time.time() - debut_mission) + generer_rapport_mission().generer_rapport_synthese(resultats, time.time() - debut_mission) # Mise à jour des statistiques globales self.missions_completees.append({ @@ -252,4 +253,4 @@ def attaque_dictionnaire_manuelle(self, chemin_fichier: str, algorithme_choisi: temps_execution = time.time() - debut_attaque return ResultatAnalyse("", b"", 0.0, b"", temps_execution, 0) -print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\data\\mission2.enc")) +# print(DetecteurCryptoOrchestrateur().analyser_fichier_specifique(f"{os.path.abspath(os.curdir)}\\CryptoForensic-Python\\data\\mission2.enc")) diff --git a/src/interface_console.py b/src/interface_console.py index 99446b7..dfd3be3 100644 --- a/src/interface_console.py +++ b/src/interface_console.py @@ -94,7 +94,7 @@ def menu_1(self): print(f"\n[bold]Score de probabilité[/bold] : [green]{data.score_probabilite}[/green]") # print(data.texte_dechiffre) print(f"\n[bold]Temps d'éxécution[/bold] : [green]{round(data.temps_execution,4)}[/green] s") - esc=input("Veuillez appuyer sur la touche entrer pour retrouner au menu principal") + esc=input("Veuillez appuyer sur la touche entrer pour retourner au menu principal") if esc=="": self.default_menu() else : self.default_menu() @@ -107,14 +107,24 @@ def menu_2(self): self.dynamiqueText("Mission complète automatique","green") self.dynamiqueText("Veuillez entrer le chemin du dossier :","white") time.sleep(0.02) - # chemin_dossier = self.prompt.ask("Veuillez entrer le chemin du dossier : ") - self.console.clear() + + chemin_dossier = self.prompt.ask("Veuillez entrer le chemin du dossier : ") + resultat = DetecteurCryptoOrchestrateur().mission_complete_automatique(chemin_dossier, "keys/wordlist.txt") + print(line for line in resultat) + # self.console.clear() self.dynamiqueText("Mission en cours...","green") time.sleep(0.02) - self.console.clear() + # self.console.clear() self.dynamiqueText("Mission terminée","green") + + esc=input("Veuillez appuyer sur la touche entrer pour retourner au menu principal") time.sleep(0.02) - self.default_menu() + + if esc=="": + self.default_menu() + else : self.default_menu() + + # self.default_menu() def menu_3(self): self.console.clear() diff --git a/src/rapport_mission.py b/src/rapport_mission.py index af005b9..ba9b589 100644 --- a/src/rapport_mission.py +++ b/src/rapport_mission.py @@ -56,15 +56,15 @@ def recuperer_ancien_rapport(self, base_date:str)->list|str: except FileNotFoundError: print('Fichier non trouvé') -print(generer_rapport_mission().generer_rapport_synthese({ - 'algorithme':'CHACHA20', - 'fichier': 'mission1.enc', - 'cle':'PK7', - 'tentatives':'127', - 'temps_execution':"368s", - 'taux_succes': "97%", - 'statut_succes':'Succès', - 'texte_dechiffre':'Je suis là!' -})) +# print(generer_rapport_mission().generer_rapport_synthese({ +# 'algorithme':'CHACHA20', +# 'fichier': 'mission1.enc', +# 'cle':'PK7', +# 'tentatives':'127', +# 'temps_execution':"368s", +# 'taux_succes': "97%", +# 'statut_succes':'Succès', +# 'texte_dechiffre':'Je suis là!' +# })) -print(generer_rapport_mission().recuperer_ancien_rapport("05/08/25")[0]) +# print(generer_rapport_mission().recuperer_ancien_rapport("05/08/25")[0]) diff --git a/src/utils.py b/src/utils.py index 0e481e6..e567408 100644 --- a/src/utils.py +++ b/src/utils.py @@ -55,7 +55,7 @@ def est_dechiffre(texte:str) -> bool: pourcent += 30 # Le respect de la ponctuation, les 20% restants - if stats['ponctuation'] > 50 : + if stats['ponctuation_valide'] > 50 : pourcent += 20 return True if pourcent > 70 else False @@ -100,7 +100,7 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: copy=texte for lettre in tab: copy=copy.replace(lettre, ' ') - mots = [mot for mot in copy.strip().split(' ') if mot] + mots = [mot.removesuffix('\n').removeprefix('\n') for mot in copy.strip().split(' ') if mot != '\n'] stats['nombre_mots']=len(mots) # Verifier que le chaque mot du texte est un mot anglais/francais From 2513ebddf68c1ad9a418ac58a3566c32ebe426e9 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Sun, 10 Aug 2025 17:33:26 +0100 Subject: [PATCH 25/27] tests aes_gcm --- src/detecteur_crypto.py | 5 ++- src/utils.py | 5 ++- .../fichiers_pour_tests/aes_gcm_invalide.enc | 1 + tests/test_analyzers.py | 42 ++++++++++++++++++- 4 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests/fichiers_pour_tests/aes_gcm_invalide.enc diff --git a/src/detecteur_crypto.py b/src/detecteur_crypto.py index c3377c6..2c58cd0 100644 --- a/src/detecteur_crypto.py +++ b/src/detecteur_crypto.py @@ -10,7 +10,7 @@ from .analyzers.blowfish_analyzer import Blowfish_Analyzer from .analyzers.aes_gcm_analyzer import Aes_Gcm_Analyzer from .rapport_mission import generer_rapport_mission - +from .analyzers.fernet_analyzer import FernetAnalyzer # Import des modules utilitaries from utils import est_dechiffre @@ -42,7 +42,8 @@ def __init__(self): "AES-CBC": Aes_Cbc_Analyzer(), "ChaCha20": ChaCha20_Analyzer(), "Blowfish": Blowfish_Analyzer(), - "AES-GCM": Aes_Gcm_Analyzer() + "AES-GCM": Aes_Gcm_Analyzer(), + "Fernet": FernetAnalyzer(), } self.missions_completees: list[dict[str, Union[str, list[ResultatAnalyse], float]]] = [] self.statistiques_globales: dict[str, Union[int, float]] = { diff --git a/src/utils.py b/src/utils.py index e567408..e16dde6 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,4 +1,5 @@ import math +import re import string from pathlib import Path from typing import Any, Dict, List, TypedDict @@ -58,7 +59,7 @@ def est_dechiffre(texte:str) -> bool: if stats['ponctuation_valide'] > 50 : pourcent += 20 - return True if pourcent > 70 else False + return True if pourcent > 80 else False @@ -119,7 +120,7 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: try: with open(chemin, 'r', encoding='latin-1') as f: for ligne in f: - if ligne.strip() == mot: + if re.match(ligne.strip().removesuffix('\n'), mot, re.I): mots_valides += 1 trouve=True break diff --git a/tests/fichiers_pour_tests/aes_gcm_invalide.enc b/tests/fichiers_pour_tests/aes_gcm_invalide.enc new file mode 100644 index 0000000..5e3c49c --- /dev/null +++ b/tests/fichiers_pour_tests/aes_gcm_invalide.enc @@ -0,0 +1 @@ +_ ̎~lY{攳FyxFNfYk]8]0ވM[DW&WZ3A p~uV \ No newline at end of file diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py index a7f5379..9e0ca15 100644 --- a/tests/test_analyzers.py +++ b/tests/test_analyzers.py @@ -3,12 +3,14 @@ import sys import hashlib from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 - +from cryptography.hazmat.primitives.ciphers.aead import AESGCM +from pathlib import Path sys.path.append(os.path.join(os.path.dirname(__file__), '..')) sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) from src.analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer from src.analyzers.chacha20_analyzer import ChaCha20_Analyzer +from src.analyzers.aes_gcm_analyzer import Aes_Gcm_Analyzer class AesCbcAnalyzerTester(TestCase): @@ -104,6 +106,42 @@ def test_chacha20_dechiffrer_fichier_non_existant(self): with self.assertRaises(FileNotFoundError): self.analyser_chacha.dechiffrer("chemin_invalide.enc", cle_valide) - +class AesGcmTester(TestCase) : + _wordlist = "keys/wordlist.txt" + _analyzer=Aes_Gcm_Analyzer() + _fichier="data/mission3.enc" + _fichier_test = Path('tests/fichiers_pour_tests') / 'aes_gcm_invalide.enc' + _texte_test = b"Test effectue pour AesGcm, encore. Nous en sommes a la.fin" + + + def setUp(self): + """ + Crée un fchier de test crypté en AESGCM pour les tests unitaires + """ + key = AESGCM.generate_key(128) + nonce = os.urandom(12) + aad = os.urandom(16) + texte_chiffre = AESGCM(key).encrypt(nonce, self._texte_test, aad) + with open(self._fichier_test, '+wb') as f: + f.write(nonce) + f.write(texte_chiffre) + f.close() + + def test_aesgcm_generer_cles_candidates(self): + #Vérifie que les clés candidates générés par cet algorithme sont une liste de bytes + with self.assertRaises(ValueError): + self.assertIsInstance(self._analyzer.generer_cles_candidates(self._wordlist), list[bytes]) + + def test_aes_gcm_identifier_algo(self): + #Vérifie que la probabilité retournée pour le fichier mission3.enc est un float et élevée + with self.assertRaises(ValueError): + self.assertIsInstance(self._analyzer.identifier_algo(self._fichier_test), float) + self.assertAlmostEqual(self._analyzer.identifier_algo(self._fichier_test, 0)) + + def test_aes_gcm_dechiffrer(self): + self.assertIsInstance(self._analyzer.dechiffrer(self._fichier_test), bytes) + + + if __name__ == '__main__': main() \ No newline at end of file From 8f20bfccc6db2433cdd5e2eab62ab2476822d553 Mon Sep 17 00:00:00 2001 From: Seathiel Date: Sun, 10 Aug 2025 20:42:36 +0100 Subject: [PATCH 26/27] merged --- src/utils.py | 6 +++++- tests/fichiers_pour_tests/aes_gcm_invalide.enc | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/utils.py b/src/utils.py index 84c480a..425da97 100644 --- a/src/utils.py +++ b/src/utils.py @@ -101,7 +101,9 @@ def verifier_texte_dechiffre(texte: str) -> Dict[str, Any]: copy=texte for lettre in tab: copy=copy.replace(lettre, ' ') - mots = [mot.removesuffix('\n').removeprefix('\n') for mot in copy.strip().split(' ') if mot != '\n'] + + # Diviser par espaces et filtrer les mots vides + mots = [mot.strip() for mot in copy.split(' ') if mot.strip()] stats['nombre_mots']=len(mots) # Verifier que le chaque mot du texte est un mot anglais/francais @@ -191,3 +193,5 @@ def rangerDico() -> None: except FileNotFoundError: print('Fichier non trouvé.') # rangerDico() + +print(verifier_texte_dechiffre("je talk !a mamamia:?\n")) \ No newline at end of file diff --git a/tests/fichiers_pour_tests/aes_gcm_invalide.enc b/tests/fichiers_pour_tests/aes_gcm_invalide.enc index 0e5652f..3065b54 100644 --- a/tests/fichiers_pour_tests/aes_gcm_invalide.enc +++ b/tests/fichiers_pour_tests/aes_gcm_invalide.enc @@ -1 +1 @@ -g6o@ABLH]WYhm<+&?M# (ivk! w4N Date: Sun, 10 Aug 2025 22:39:25 +0100 Subject: [PATCH 27/27] test de l'analyzer Fernet --- src/utils.py | 2 +- .../fichiers_pour_tests/aes_gcm_invalide.enc | Bin 86 -> 86 bytes tests/fichiers_pour_tests/fernet_invalide.enc | 1 + tests/test_analyzers.py | 51 +++++++++++++++++- 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 tests/fichiers_pour_tests/fernet_invalide.enc diff --git a/src/utils.py b/src/utils.py index 425da97..bc2718e 100644 --- a/src/utils.py +++ b/src/utils.py @@ -194,4 +194,4 @@ def rangerDico() -> None: print('Fichier non trouvé.') # rangerDico() -print(verifier_texte_dechiffre("je talk !a mamamia:?\n")) \ No newline at end of file +# print(verifier_texte_dechiffre("je talk !a mamamia:?\n")) \ No newline at end of file diff --git a/tests/fichiers_pour_tests/aes_gcm_invalide.enc b/tests/fichiers_pour_tests/aes_gcm_invalide.enc index 3065b54e00f05471c0c8d2833cff4743b0a1dd3e..4bfe63fa5f30bb106a9fa807c5c0607c968341c1 100644 GIT binary patch literal 86 zcmV-c0IC1@r{MH%Bjl0*P*^^%J&AqutWOn<$FuNygE>~u686L#ucR$k{#*W9#aIrQ s1$i(M1(s`i_U)DoWUnKfqdo2{3IR=ecsh2*Y~t!{hl+sCeGFNe(QET6d;kCd literal 86 zcmV-c0IC18u?(Avj-&F3XgBejRrx5*^L#dPNz;=}*0%WVeK&r54=*_AiDz0HEb3Sf s{>ZNlx~T)VlHe++lp~6Z-FCcH6&HY_%(Q^ZGdrrZ@m60Mf`^v*Ek^lez diff --git a/tests/fichiers_pour_tests/fernet_invalide.enc b/tests/fichiers_pour_tests/fernet_invalide.enc new file mode 100644 index 0000000..82604d0 --- /dev/null +++ b/tests/fichiers_pour_tests/fernet_invalide.enc @@ -0,0 +1 @@ +gAAAAABomRFQlKp52Rye3Z1vgFS_n2BOoG4C9eY2kCSga8HN_OLs7PcjvvAfbLk1WXOwgk0bs8iUzvOSCmiqKRVeintPVEhQNEEUUU1gcCvaS3QOqdIi2dlFcLruMjlXZ0-bWanXro2HI0813g4NArEggiWYE_si-w== \ No newline at end of file diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py index 037901e..813be54 100644 --- a/tests/test_analyzers.py +++ b/tests/test_analyzers.py @@ -1,15 +1,19 @@ +import base64 from unittest import TestCase, main import os import sys import hashlib from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 from cryptography.hazmat.primitives.ciphers.aead import AESGCM +from cryptography.fernet import Fernet from pathlib import Path sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from src.analyzers.aes_cbc_analyzer import Aes_Cbc_Analyzer from src.analyzers.chacha20_analyzer import ChaCha20_Analyzer from src.analyzers.aes_gcm_analyzer import Aes_Gcm_Analyzer +from src.analyzers.fernet_analyzer import FernetAnalyzer + class AesCbcAnalyzerTester(TestCase): @@ -146,7 +150,50 @@ def test_aes_gcm_dechiffrer(self): resultat = self._analyzer.dechiffrer(self._fichier_test, cle_test) self.assertIsInstance(resultat, bytes) - +class FernetTester(TestCase) : + _wordlist = "keys/wordlist.txt" + _analyzer=FernetAnalyzer() + _fichier_test = Path('tests/fichiers_pour_tests') / 'fernet_invalide.enc' + _texte_test = b"Test effectue pour Fernet, encore. Nous en sommes a la.fin" + _key = os.urandom(32) + def setUp(self): + """ + Crée un fichier pour les tests relatifs à Fernet + """ + try : + with open(self._fichier_test, 'wb') as f: + texte_chiffre = Fernet(base64.urlsafe_b64encode(self._key)).encrypt(self._texte_test) + f.write(texte_chiffre) + f.close() + except FileNotFoundError : + raise + + def test_fernet_gk(self): + resultat = self._analyzer.generer_cles_candidates(self._wordlist) + self.assertIsInstance(resultat, list) + # Vérifier que tous les éléments sont des bytes + for cle in resultat: + self.assertIsInstance(cle, bytes) + + def test_fernet_id_algo(self): + #Vérifier que seul le fichier mission 5 a plus de 0.8 de score pour l'identification de Fernet + for i in range(5) : + if i+1 != 5 and self._analyzer.identifier_algo(f"mission{i+1}.enc") >= 0.8: + raise Exception('Non correspondance entre probabilité et algorithme.') + + def test_dechiffrer(self) : + #Vérifie que le déchiffrement de fernet est opérationnel + resultat = self._analyzer.dechiffrer + self.assertEqual(resultat(self._fichier_test, self._key), self._texte_test) + + #Vérifie le cas de clé non correspondante + with self.assertRaises(ValueError) : + self.assertIsInstance(resultat(self._fichier_test, os.urandom(16)), ValueError) + + #Vérifie le cas de fichier non trouvé + with self.assertRaises(FileNotFoundError): + self.assertIsInstance(resultat('dohi.txt', os.urandom(32)), FileNotFoundError) + if __name__ == '__main__': - main() \ No newline at end of file + main()