Eklablog Tous les blogs
Editer l'article Suivre ce blog Administration + Créer mon blog
MENU

Blog traitant d'informatique, de programmation, de python, de golang, de linux...

Publicité

Un peu de chiffrement avec pyFC

Bref, en chiffrant vos fichiers avec le script pyFC, ces divers fournisseurs pourront toujours les consulter (en utilisant un éditeur hexadécimal, par exemple), mais de là à en tirer quelque chose, c'est une autre histoire...

...enfin revenons à nos moutons : le masque jetable, vous connaissez ? Voici la définition de wikipedia :

“Le masque jetable, également appelé chiffre de Vernam, est un algorithme de cryptographie inventé par Gilbert Vernam en 1917 et perfectionné par Joseph Mauborgne, qui rajouta la notion de clé aléatoire....
...
....tant pour le codage que pour le décodage, ce chiffrement est théoriquement impossible à casser,....”

 

Le principe de ce chiffrement est de crypter tous les caractères du message ou du fichier à protéger, et ce de manière unique et aléatoire. La clé de cryptage devra donc être de longueur au moins équivalente au message d'origine, ne devra être utilisée qu'une seule fois, et être générée aléatoirement.

L'implémentation de ce script respecte en outre le principe de Kerckhoffs (reformulé par Claude Shannon), qui stipule que « l'adversaire connaît le système ». Ce système de chiffrement et son implémentation n'auront donc rien de secret, la sécurité reposant essentiellement sur le secret des clés.

Le système de chiffrement dont il est question ici est un système à clé symétrique : une même clé sert à la fois au chiffrement et au déchiffrement.

 

Le script pyFC :

Pour rappel, le but de pyFC est de chiffrer vos fichiers pour votre utilisation personnelle essentiellement. Il n'est pas question ici pour le moment de transmettre des clés à un éventuel correspondant (voir la section "Évolutions futures" pour ce point) afin qu'il déchiffre les fichiers transmis. Cela reste possible, mais il vous faudra alors transmettre vos clés de chiffrement par un autre moyen (clé usb essentiellement...).

 

1ère étape : Génération des clés :

Pour générer les clés de chiffrement, placez-vous dans le répertoire du script puis dans une console entrez:

 you@yourComputer:~/pyFC$ python3 pyFC.py -init

Le script vous demande alors confirmation comme quoi vous souhaitez bien générer un nouveau jeu de clés, entrez 'OK'.

Je parle ici de clés au pluriel, ou de jeu de clés. En fait, le script va générer 5 fichiers remplis d'octets aléatoires dont les tailles feront respectivement 100MBytes, 200MBytes, 300MBytes, 400MBytes et 500MBytes. Ces fichiers seront créés chacun dans une arborescence de répertoires contenant 28 niveaux, et seront stockés au 'dernier étage' (ou bien dernier sous-sol, selon la manière dont on visualise cela) de cette arborescence. Les noms de chacun de ses répertoires seront générés aléatoirement (sur 3 lettres et/ou chiffres) et précédés d'un point ('.') permettant ainsi de cacher chaque niveau de ces arborescences. Les noms des fichiers clés seront respectivement  '.key1', '.key2', '.key3', '.key4', '.key5'.

Une fois ces fichiers clés générés, le script vous demandera d'entrer l'emplacement (répertoire) où vous souhaitez stocker ces arborescences de clés. Il est préférable de les placer ailleurs que dans le répertoire du script, pour des raisons évidentes de sécurité. Si vous n'entrez rien, les clés resteront dans ce répertoire courant.

J'ai choisi volontairement des clés relativement volumineuses afin qu'elle ne puissent pas être facilement transmises par le réseau. La sécurité de ce système est assuré tant que le secret des clés l'est, ce qui est vrai pour n'importe quel système de chiffrement. 

La liste des emplacement de ces 5 arborescences de clés sera sauvée dans votre dossier utilisateur dans le fichier de configuration :

/home/user/.pyFC/.pyFC.conf

Ce fichier de configuration ainsi que toutes les arborescences où sont stockées les clés verront tous leurs droits d'accès mis à 0 (chmod 0o000). Il ne seront ainsi plus lisibles directement (même si l'utilisateur courant peut changer ces droits). Les droits seront gérés par le script selon les besoins, mais seront toujours remis à 0o000 après toute opération de chiffrement ou déchiffrement. Seule l'option "-showconf" passée en paramètre (voir plus bas son utilisation) permet de dévérouiller la sécurité, jusqu'au prochain lancement du script.

 

2ème étape : Chiffrement d'un fichier ou d'un répertoire :

Dans la console, entrez :

 you@yourComputer:~/pyFC$ python3 /cheminvers/pyFC.py -e /chemindufichier/oudurépertoire/àchiffrer

Par exemple :

 you@yourComputer:~/pyFC$ python3 /home/adam/pyFC/pyFC.py -e /DataDisk2/mesPhotos/390485.mov

Ici, le paramètre -e indique que l'on souhaite chiffrer le fichier 390485.mov. pyFC va alors créer une archive zip temporaire nommée crypted.zip. Cela permettra à la fois de ne travailler que sur cette seule archive (donc process identique que l'on ait à chiffrer un simple fichier ou un répertoire complet), et en même temps de ne pas avoir à se préoccuper du stockage du nom de fichier/répertoire d'origine puisque celui-ci sera contenu dans cette archive. Ensuite, pyFC va générer 5 nombres aléatoires (1 par fichier clé, chaque nombre étant >=0 et < (à la taille de clé - la taille de l'archive précédemment créée). Ce nombre indique l'offset dans chaque fichier clé à partir duquel on va lire une série de N bytes, N étant la taille de l'archive zip. On a maintenant 5 bytearray(s) avec lesquels on va chiffrer (par opération XOR) notre archive. Pour chaque byte 'en clair' de l'archive, on obtient le byte chiffré par l'opération suivante :

 

byteChiffré = byteClair^byteSérie1^byteSérie2^byteSérie3^byteSérie4^byteSérie5

 

Il ne nous reste plus qu'à stocker notre nouveau tableau de bytes chiffrés dans un fichier, sans oublier d'y placer en entête les 5 offsets utilisés qui seront nécessaires au déchiffrage. On peut considérer ces offsets comme une partie de la clé, aussi pour ne pas dévoiler une partie du secret trop facilement, on va coder ces informations. Dans un premier temps, on va encoder chaque offset sur 4 octets (format integer 32 bits), 'mélanger' l'ordre de leurs octets [Byte3 Byte2 Byte1 Byte0] devient [Byte0 Byte2 Byte3 Byte1], puis les combiner par opération XOR chacun avec 2 séries de 4 octets pris dans les fichiers clés, l'offset choisi pour chaque série dépendant de la taille de l'archive à chiffrer passée par une opération modulo. Vous pouvez voir les détails de ce process directement dans le code source plus bas.

De manière totalement subjective, j'ai choisi de nommer les fichiers chiffrés à partir de la valeur 'Unix timestamp' relevée juste après la création de l'archive. L'extension par défaut est ".000".

 

Cas de fichier d'archive >100MBytes :

Tel que défini plus haut, on peut voir qu'il n'est pas prévu de chiffrer des fichiers de taille > 100MBytes (puisque 100MBytes est la taille de la plus petite clé). Cela est résolu en découpant l'archive en 'tranches' plus petites. Après quelques séries de tests, je me suis aperçu que chiffrer des fichiers de quelques dizaines de mégabytes était de toute façon une opération assez longue. Aussi, j'ai choisi de découper les fichiers selon la formule suivante afin de gagner en temps, ou tout au moins avoir une meilleure visibilité de ce qui se passe lors du chiffrement/déchiffrement : 

Taille_Tranche_Max = 3MBytes + 1MByte*[(Taille de l'archive en clair(en MBytes)) / 15]

Pour un fichier de 5MBytes, vous obtiendrez Taille_Tranche_Max = 3 MBytes                                                                          --> soit 2 tranches de 2.5 MBytes

Pour un fichier de 33MBytes, vous obtiendrez Taille_Tranche_Max = 5 MBytes                                                                         --> soit 7 tranches de 4.7 MBytes

Pour un fichier de 189MBytes, vous obtiendrez Taille_Tranche_Max = 15 MBytes                                                                       --> soit 13 tranches de 14.5 MBytes

 

La limite haute de Taille_Tranche_Max est de 50MBytes. Le nombre de fichiers résultant(s) est calculé automatiquement, et pour savoir qu'un ensemble de fichiers fait référence à une même archive, ceux-ci porteront tous le même nom (le 'Unix timestamp'). Seule l'extension changera : le 1er fichier portant l'extension ".000", le suivant ".001", le suivant ".002", etc... selon le nombre de fichiers nécessaire(s)...

 

3ème étape : Déchiffrement d'un fichier "crypté" :

Dans la console, entrez :

 you@yourComputer:~/pyFC$ python3 /cheminvers/pyFC.py -d /chemindufichier/oudurépertoire/àdéchiffrer

Par exemple :

 you@yourComputer:~/pyFC$ python3 /home/adam/pyFC/pyFC.py -d /DataDisk2/mesPhotos/1561243871.000

Ici, le paramètre -d indique que l'on souhaite déchiffrer le fichier "1561243871.000". Dans le principe, si d'autres fichiers dans le même répertoire portant le même nom avec d'autres extensions (".001", ".002", etc) existent, ils seront pris en compte comme faisant partie d'un même ensemble de fichiers à déchiffrer. Le fichier ou répertoire d'origine sera alors extrait / recréé à partir de l'ensemble des fichiers chiffrés. Attention, le nom du fichier passé en paramètre pour déchiffrement doit forcément avoir une extension en ".000" ! N'essayez pas de déchiffrer un fichier avec extension ".001", ".002" ou autres extension, cela ne fonctionnera pas ! 

 

Autres options du script :

Pour obtenir de l'aide :

 you@yourComputer:~/pyFC$ python3 pyFC.py -help

Pour accéder au fichier de configuration ainsi qu'aux clés (ré-autorise les accès en lecture/écriture aux fichiers et répertoires de clés) :

 you@yourComputer:~/pyFC$ python3 pyFC.py -showconf

Pour interdire les accès au fichier de configuration ainsi qu'aux clés (interdit les accès en lecture/écriture) :

 you@yourComputer:~/pyFC$ python3 pyFC.py -hideconf

L'option -showconf peut-être utilisée si vous souhaitez (dé)placer vos clés dans des répertoires de base différents. Pourquoi pas dans ce cas en placer une ou deux sur clé(s) USB, qui servirai(en)t de dongle de sécurité, par exemple? Dans ce cas, il vous faudra modifier à la mano les chemins vers les clés dans le fichier /home/user/.pyFC/.pyFC.conf

 

Évolutions futures :

Une première évolution utile serait de pouvoir produire plusieurs jeux de clés et de les nommer afin de pouvoir les utiliser en tant que clés partagées avec divers correspondants. Une autre possible serait de pouvoir choisir la taille ainsi que le nombre de clés à utiliser, même si cela me parait moins utile pour le moment... Disons que le script est déjà assez long (je l'imaginais plus court au début de ce projet), et me parait tout à fait utilisable et cohérent pour une première version...

Je reconnais aussi qu'utiliser un script en ligne de commande, c'est parfois un peu lourd, ça peut freiner un peu l'envie d'essayer... Pour ce point, j'écrirai un prochain article où j'explique comment je l'utilise directement à partir des options disponibles en clic droit dans mon navigateur de fichiers (caja). 

Vous trouverez le code de ce script juste ci-après, et vous pouvez le télécharger ici. C'est un fichier zip qui contient un répertoire /pyFC qui contient lui-même le fichier pyFC.py ainsi qu'un fichier secrets.py. Ce dernier fichier (secrets.py) fait partie de la librairie standard de python3.6, mais n'est pas fourni dans les versions précédentes. Le fait de l'avoir directement dans /pyFC permet de faire fonctionner pyFC.py sous python3.5 sans problème, mais je n'ai pas pu tester l'ensemble sous une version encore antérieure... Le script a été testé sous LinuxMint 19.1 et Debian 9.9.

Si vous avez d'autres idées, des questions ou des suggestions, n'hésitez pas à m'en faire part dans vos commentaires. En attendant, prenez bien soin de votre vie privée :-)

PS : Au passage, un grand merci à mon beta-testeur préféré qui m'a permis de constater cette différence entre les versions de python3.5 et 3.6 :-)

 

Script pyFC.py :

    1 #!/usr/bin/env python3
    2 # -*- coding: utf-8 -*-
    3 # V0.1 du 24/06/2019
    4 
    5 
    6 
    7 ####
    8 #    pyFC est le diminutif de pyFileCrypter (qui était le nom originel de ce projet). Trouvant 'pyFileCrypter' un 
    9 #    peu long, j'ai préféré le raccourcir un peu pour gagner en concision...
   10 #
   11 #    NB : Ce script est prévu pour fonctionner sous Linux essentiellement (mais si vous êtes motivé(s), il devrait
   12 #    être adaptable assez facilement pour d'autres OS...)
   13 #
   14 #    Ce script à pour but de chiffrer/déchiffrer des fichiers ou répertoires en utilisant l'algorithme
   15 #    du masque jetable, ou chiffre de Vernam.
   16 #    
   17 #    INITIALISATION:
   18 #    Au 1er lancement du script, il faudra lui passer l'argument '-init' (puis valider cette opération par 'OK'),
   19 #    afin que le jeu de clés de chiffrement soit créé.
   20 #    Ce jeu consiste en 5 fichiers respectivement de 100, 200, 300, 400 et 500 Mega-Octets, contenant
   21 #    chacun un ensemble d'octets générés aléatoirement. Les grandes tailles de ces fichiers limitent les risques
   22 #    de copie, mais surtout d'upload par un "processus pirate" (un upload d'~ 1.5 Giga Octets prendrait beaucoup
   23 #    de temps !). Chaque fichier clé sera généré dans une nouvelle arborescence de répertoires de 28 'étages'
   24 #    Une fois ces fichiers clés générés, le script va vous demander d'entrer le répertoire dans lequel vous
   25 #    souhaitez stoker ces clés.
   26 #    La console vous indique la marche à suivre.
   27 #    Après validation (entrée de 'OK' dans la console), le fichier pyFC.conf sera créé dans votre 
   28 #    /home, placé dans un nouveau répertoire caché /.pyFC, puis renommé .pyFC.conf de manière
   29 #    à devenir un fichier caché lui aussi.
   30 #    Les droits du répertoire /.pyFC et du fichier .pyFC.conf vont être mis à 0o000 afin d'
   31 #    améliorer un peu la sécurité (ils deviennent donc illisible tant que les droits de lecture n'auront pas 
   32 #    été réactivés.)
   33 #    Ces droits de lecture seront réactivés temporairement au prochain lancement du script pyFC.py (par
   34 #    le script lui-même afin que celui-ci puisse accéder aux clés), puis re-désactivés.
   35 #    Ce système de protection est aussi appliqué à toute l'arborescence des clés.
   36 #
   37 #    Pour le cas où vous souhaitez pouvoir chiffrer/déchiffrer vos fichiers sur une autre machine avec le même
   38 #    jeu de clés, il suffira de recopier l'arborescence des clés ainsi que le fichier de configuration sur
   39 #    ladite machine aux endroits choisis.
   40 #    Il ne faudra en aucun cas relancer le script avec l'argument '-init', sinon celui-ci écraserait la 
   41 #    configuration du le jeu de clés actuel avec une nouvelle configuration (les clés elles-même ne seront pas
   42 #    effacées)! Dans une version future, si le besoin s'en fait sentir, j'implémenterai probablement la
   43 #    possibilité d'avoir plusieurs jeux de clés (ce qui permettrait par exemple d'avoir des jeux de clés
   44 #    partagés avec différents correspondants...)
   45 #
   46 #    FONCTIONNEMENT & UTILISATION :
   47 #    Pour chaque fichier à chiffrer, le script va générer aléatoirement 5 offsets différents (1 pour chaque fichier
   48 #    clé), puis dans chaque fichier clé aller chercher à partir de cet offset un nombre d'octets équivalent à la
   49 #    taille du fichier à chiffrer. Ensuite, le chiffrement va s'effectuer par un XOR octet par octet comme suit :
   50 #    temp1 = fichier_à_chiffrer ^ fichier_clé1[offset1, size]
   51 #    temp2 = temp1 ^ fichier_clé2[offset2, size]
   52 #    temp3 = temp2 ^ fichier_clé3[offset3, size]
   53 #    temp4 = temp3 ^ fichier_clé4[offset4, size]
   54 #    temp5 = temp4 ^ fichier_clé5[offset5, size]
   55 #
   56 #
   57 #    Il est aussi nécessaire de stocker les offsets utilisés au sein de chaque fichier chiffré. Ces offsets
   58 #    sont codés sur 4 octets (nombre hexa 32bits).
   59 #    A partir de ces données, le script va créer le header du fichier une fois chiffré :
   60 #
   61 #    XXXX -> 4 octets representant l'offset1 : offset1 ^ fichier_clé1 [10000 +  29*(TailleFichier % 9999), 4]
   62 #                                                      ^ fichier_clé2 [20000 + 113*(TailleFichier % 8888), 4]
   63 #                                                        -> Poids des octets dans le codage : 0231
   64 #    XXXX -> 4 octets representant l'offset2 : offset2 ^ fichier_clé2 [30000 + 229*(TailleFichier % 7777), 4]
   65 #                                                      ^ fichier_clé3 [40000 + 349*(TailleFichier % 6666), 4]
   66 #                                                        -> Poids des octets dans le codage : 0231
   67 #    XXXX -> 4 octets representant l'offset3 : offset3 ^ fichier_clé3 [50000 + 463*(TailleFichier % 5555), 4]
   68 #                                                      ^ fichier_clé4 [60000 + 601*(TailleFichier % 4444), 4]
   69 #                                                        -> Poids des octets dans le codage : 0231
   70 #    XXXX -> 4 octets representant l'offset4 : offset4 ^ fichier_clé4 [70000 + 733*(TailleFichier % 3333), 4]
   71 #                                                      ^ fichier_clé5 [80000 + 863*(TailleFichier % 2222), 4]
   72 #                                                        -> Poids des octets dans le codage : 0231
   73 #    XXXX -> 4 octets representant l'offset5 : offset5 ^ fichier_clé5 [90000 + 1013*(TailleFichier % 1111), 4]
   74 #                                                      ^ fichier_clé1 [100000 + 1151*(TailleFichier % 5432), 4]
   75 #                                                        -> Poids des octets dans le codage : 0231
   76 #    
   77 #    Une fois ce header généré, il sera mis en entête de temp5 (voir plus haut), puis le fichier sera sauvegardé
   78 #    sous le nom int([time]).EXT ([time] étant le nombre de secondes écoulées depuis le 01/01/1970
   79 #    EXT aura pour valeur l'index '000', '001', '002' selon le rang du fichier compressé correspondant à
   80 #    un même fichier non compressé d'origine (cas des fichiers > 100MBytes)
   81 #    Dans le cas d'une compression en plusieurs 'volumes' (.000, .001, etc...), le time servant à définir
   82 #    le nom de fichier devra être le même.
   83 #
   84 #
   85 #    CAS DU CHIFFREMENT D'UN REPERTOIRE :
   86 #    Plutôt qu'un simple fichier, pyFC peut chiffrer un répertoire complet en y incluant tous ses
   87 #    fichiers et sous-répertoires. Pour cela, le répertoire à chiffrer sera dans un premier temps
   88 #    compressé en fichier zip, puis ensuite traité comme un simple fichier normal.
   89 #    NB : Il en est de même maintenant pour le chiffrement d'un fichier 'simple'. Celui-ci sera
   90 #    préalablement archivé dans un zip, avant que ce zip soit chiffré. Cela présente l'avantage de
   91 #    ne pas avoir à stocker le nom d'origine du fichier (puisqu'il figurera dans l'archive zip).
   92 #
   93 #
   94 #    ARGUMENTS :
   95 #    Pour chiffrer un fichier / répertoire : --> python3 pyFC.py -e [chemin complet vers le fichier
   96 #                                                                         ou répertoire à chiffrer]
   97 #    Pour déchiffrer un fichier            : --> python3 pyFC.py -d [chemin complet vers le fichier
   98 #                                                                             chiffré à déchiffrer]
   99 #
  100 #
  101 #
  102 ####
  103 
  104 
  105 
  106 
  107 import os
  108 import sys
  109 import shutil
  110 import secrets
  111 import time
  112 import random
  113 import string
  114 import zipfile
  115 
  116 
  117 
  118 
  119 
  120 def setConfFileAccess(accessibility):
  121     ''' Permet de rendre /home/user/.pyFC/.pyFC.conf visible et accessible ou non selon les besoins'''
  122     if accessibility:
  123         os.chmod(pfcDir, 0o774) # On met les droits de lecture/écriture sur le répertoire
  124         os.chmod(pfcConfFile, 0o774) # On met les droits de lecture/écriture sur le fichier conf
  125         #todo : gérer le attrib sous win
  126     else:
  127         os.chmod(pfcDir, 0o774) # On met les droits de lecture/écriture sur le répertoire
  128         try:
  129             os.chmod(pfcConfFile, 0o000)# On supprime les droits de lecture/écriture sur le répertoire
  130             os.chmod(pfcDir, 0o000)# On supprime les droits de lecture/écriture sur le répertoire
  131             #todo : gérer le attrib sous win
  132         except PermissionError:
  133             pass
  134 
  135 
  136 
  137 def setKeyfilesAccess(accessibility):
  138     ''' Permet de rendre les 5 fichiers clé keyFilePath visibles et accessibles ou non selon les besoins.'''
  139     nindex = 0
  140     for fullPath in keyFilepathList:
  141         if accessibility:  # On rend les clés accessibles
  142             fullPath = fullPath[0:len(fullPath)-145]
  143             for n in range(29):
  144                 dirStr = keyFilepathList[nindex][0:len(fullPath)+(n+1)*5]
  145                 os.chmod(dirStr, 0o774)
  146                 #todo : gérer le attrib sous win
  147         else:  # On rend les clés inaccessibles
  148             for n in range(29):
  149                 dirStr = keyFilepathList[nindex][0:len(fullPath)-n*5]
  150                 try:
  151                     os.chmod(dirStr, 0o000)
  152                     #todo : gérer le attrib sous win
  153                 except PermissionError:
  154                     pass
  155         nindex += 1
  156 
  157 
  158 
  159 def removeRNFromListe(listName):
  160     ''' Enlève les caractères \r ou \r\n en fin de ligne pour chaque string contenue dans listName '''
  161     newList = []
  162     for oneLine in listName:
  163         if oneLine.endswith("\r\n"):
  164             oneLine = oneLine[0:(len(oneLine)-2)]
  165         if oneLine.endswith("\n"):
  166             oneLine = oneLine[0:(len(oneLine)-1)]
  167         if len(oneLine) >0:
  168             newList.append(oneLine)
  169     return newList
  170 
  171 
  172 
  173 def readFileLines(filename):
  174     ''' Lit le fichier filename (fichier texte), et stocke chacune de ses lignes dans la <list> newList ''' 
  175     if os.path.exists(filename):
  176         oneStringList = []
  177         with open(filename, 'r') as myFile:
  178             oneStringList = myFile.readlines()
  179         newList = removeRNFromListe(oneStringList)
  180         return newList
  181     else:
  182         return ("Le fichier "+filename+" n'existe pas!")
  183 
  184 
  185 
  186 def readConfFile():
  187     ''' Lit le fichier /home/user/.pyFC/.pyFC.conf et 
  188         stocke son contenu ligne par ligne dans keyFilepathList '''
  189     global keyFilepathList
  190     setConfFileAccess(True)
  191     keyFilepathList = readFileLines(pfcConfFile)
  192     setConfFileAccess(False)
  193 
  194 
  195 
  196 def print4(message):
  197     ''' Simple fonction print() affichant une ligne avant le message et deux lignes après '''
  198     print()
  199     print(message)
  200     print()
  201     print()
  202 
  203 
  204 
  205 def createKeyFiles():
  206     ''' Permet de créer les 5 fichiers clés (fichiers 'binaires') contenant nbBytes générés aléatoirement. '''
  207     global pfcConfFile
  208     global pfcDir
  209     global keyFilepathList
  210     print("Création d'un nouveau jeu de clés de chiffrement. Cela peut prendre un moment...")
  211     pathToScript = os.path.dirname(os.path.realpath(sys.argv[0]))
  212 
  213     # Création de 5 arborescences contenant 28 niveaux de répertoires
  214     # Chaque fichier clé sera généré dans le répertoire le plus loin de la racine (niveau 28)
  215     for keyIndex in range(5):
  216         for rep in range(28):
  217             newrepName = '/.'
  218             rangeSize = 3
  219             if rep == 0:
  220                 newrepName += str(keyIndex+1)
  221                 rangeSize = 2;
  222             for _ in range(rangeSize):
  223                 newrepName += random.choice(string.digits+string.ascii_letters)
  224             pathToScript += newrepName
  225             os.mkdir(pathToScript)
  226             os.chmod(pathToScript, 0o774)
  227         nbBytes = 100*(keyIndex+1)*(2**20)
  228         myBytes = os.urandom(nbBytes)
  229         oneFileName = pathToScript+'/.key'+str(keyIndex+1)
  230         with open(oneFileName, 'wb') as keyFile:  # On écrit les 5 fichiers 'clé'
  231             keyFile.write(myBytes)
  232         print("Fichier key"+str(keyIndex+1), "créé")
  233         pathToScript = os.path.dirname(os.path.realpath(sys.argv[0]))
  234         keyFilepathList.append(oneFileName)  # On mémorise le chemin vers chaque clé
  235     
  236     print()
  237     print("Les 5 nouvelles clés de chiffrement ont été créées. Pour des raisons de sécurité, il est")
  238     print("préférable de placer ces fichiers clés ailleurs que dans le répertoire .../pyFile")
  239     print("Néanmoins, le programme fonctionnera correctement si vous n'entrez rien (simple appui sur [ENTER].")
  240     print("Dans ce cas, les fichiers clés resteront simplement dans .../pyFile")
  241     print()
  242     print("Pour la ligne ci-dessous, si vous êtes sous Windows, veillez à")
  243     print("remplacer les \ par des / dans la définition du chemin.")
  244     print()
  245     
  246     newPathStr = input("Entrez le chemin où sera installé le nouveau jeu de clés : ")
  247     if len(newPathStr) > 0:
  248         while not os.path.exists(newPathStr):
  249             print(newPathStr,"n'est pas un répertoire valide !")
  250             newPathStr = input("Entrez le chemin où sera installé le nouveau jeu de clé : ")
  251             print()
  252         if '/' in newPathStr[-1]:  # Pour éliminer le / final si présent
  253             newPathStr = newPathStr[0:len(newPathStr)-1]
  254 
  255         # Déplacement des clés vers leur nouveau répertoire et M.A.J de keyFilepathList
  256         for nindex in range(5):
  257             end = len(keyFilepathList[nindex])-141
  258             print(keyFilepathList[nindex][0:end])
  259             print()
  260             print("Déplacement du fichier key"+str(nindex))
  261             shutil.move(keyFilepathList[nindex][0:end], newPathStr)
  262             keyFilepathList[nindex] = newPathStr+keyFilepathList[nindex][end-5:-1]+str(nindex+1)
  263         print()
  264 
  265     # Création de /home/user/.pyFC si nécessaire & gestion des droits...
  266     if not os.path.exists(pfcDir):
  267         os.mkdir(pfcDir)
  268     os.chmod(pfcDir, 0o774) # On met les droits de lecture/écriture sur le répertoire
  269     if os.path.exists(pfcConfFile):
  270         os.chmod(pfcConfFile, 0o774) # On met les droits de lecture/écriture sur le fichier conf
  271         os.remove(pfcConfFile)  # Puis on efface le fichier existant (obsolète)
  272 
  273     for nindex in range(5):
  274         with open(pfcConfFile, 'a') as confFile:  # On reporte keyFilepathList dans pyFC.conf
  275             confFile.write(keyFilepathList[nindex]+'\r\n')
  276 
  277     # La configuration est maintenant écrite dans /home/user/.pyFC/.pyFC.conf,
  278     # On va lire la configuration pour protéger les répertoires qui contiennent les clés
  279     readConfFile()
  280     # on protège les répertoires des clés en supprimant les droits de lecture de ces répertoires
  281     setKeyfilesAccess(False)
  282     print4("Le nouveau jeu de clés est maintenant activé")
  283 
  284 
  285 def printUsage():
  286     ''' Affiche l'aide, le 'mode d'emploi' de pyFC '''
  287     print()
  288     print("Utilisation :")
  289     print("pyFC.py              --> affiche ce mode d'emploi")
  290     print("pyFC.py -help        --> affiche ce mode d'emploi")
  291     print("pyFC.py -init        --> pour initialiser pyFC avec un nouveau jeu de clé de chiffrement")
  292     print("pyFC.py -e filename  --> pour chiffrer (-e --> encrypt) le fichier nommé 'filename'")
  293     print("pyFC.py -e dirname   --> pour chiffrer (-e --> encrypt) le répertoire nommé 'dirname'")
  294     print("pyFC.py -d filename  --> pour déchiffrer (-d --> decrypt) le fichier nommé 'filename'. Ici, l'")
  295     print("                         argument filename peut désigner soit un fichier, soit un répertoire")
  296     print("                         contenant d'autres fichiers ou répertoires")
  297     print("pyFC.py -showconf    --> change les droits sur ~/.pyFC/.pyFC.conf pour le rendre accessible") 
  298     print("                         --> os.chmod(0o774)") 
  299     print("pyFC.py -hideconf    --> change les droits sur ~/.pyFC/.pyFC.conf pour le rendre inaccessible") 
  300     print("                         --> os.chmod(0o000)") 
  301     print("                     Attention, les arguments -showconf et -hideconf ne doivent être")
  302     print("                     utilisés qu'après la mise en place d'un jeu de clé valide !")
  303     print()
  304     print()
  305 
  306 
  307 
  308 def XOR2Arrays(bytesArray1, bytesArray2):    
  309     ''' Effectue un XOR byte à byte sur les 2 tableaux de bytes transmis,
  310         puis retourne le bytearray qui en resulte '''
  311     return bytearray(map(ord, ''.join(chr(a ^ b) for a,b in zip(bytesArray1, bytesArray2))))
  312 
  313 
  314 
  315 def setCryptoBytes(mode, fileLength, offsetIntArray):
  316     ''' Cette fonction permet de créer un tableau de bytes qui sera utilisé pour
  317         le chiffrement/déchiffrement du fichier à traiter '''
  318     cryptoArray = []
  319     with open(keyFilepathList[0], 'rb') as currentKeyFile1:
  320         if not 'decryptData' in mode:
  321             currentKeyFile1.seek(10000 + 29*(fileLength % 9999))
  322             byteArrayOff11 = currentKeyFile1.read(4)
  323             currentKeyFile1.seek(100000 + 1151*(fileLength % 5432))
  324             byteArrayOff52 = currentKeyFile1.read(4)
  325         if not 'decryptOffset' in mode:
  326             currentKeyFile1.seek(offsetIntArray[0])
  327             byteArrayData1 = currentKeyFile1.read(fileLength)
  328     with open(keyFilepathList[1], 'rb') as currentKeyFile2:
  329         if not 'decryptData' in mode:
  330             currentKeyFile2.seek(20000 + 113*(fileLength % 8888))
  331             byteArrayOff12 = currentKeyFile2.read(4)
  332             currentKeyFile2.seek(30000 + 229*(fileLength % 7777))
  333             byteArrayOff21 = currentKeyFile2.read(4)
  334         if not 'decryptOffset' in mode:
  335             currentKeyFile2.seek(offsetIntArray[1])
  336             byteArrayData2 = currentKeyFile2.read(fileLength)
  337     with open(keyFilepathList[2], 'rb') as currentKeyFile3:
  338         if not 'decryptData' in mode:
  339             currentKeyFile3.seek(40000 + 349*(fileLength % 6666))
  340             byteArrayOff22 = currentKeyFile3.read(4)
  341             currentKeyFile3.seek(50000 + 463*(fileLength % 5555))
  342             byteArrayOff31 = currentKeyFile3.read(4)
  343         if not 'decryptOffset' in mode:
  344             currentKeyFile3.seek(offsetIntArray[2])
  345             byteArrayData3 = currentKeyFile3.read(fileLength)
  346     with open(keyFilepathList[3], 'rb') as currentKeyFile4:
  347         if not 'decryptData' in mode:
  348             currentKeyFile4.seek(60000 + 601*(fileLength % 4444))
  349             byteArrayOff32 = currentKeyFile4.read(4)
  350             currentKeyFile4.seek(70000 + 733*(fileLength % 3333))
  351             byteArrayOff41 = currentKeyFile4.read(4)
  352         if not 'decryptOffset' in mode:
  353             currentKeyFile4.seek(offsetIntArray[3])
  354             byteArrayData4 = currentKeyFile4.read(fileLength)
  355     with open(keyFilepathList[4], 'rb') as currentKeyFile5:
  356         if not 'decryptData' in mode:
  357             currentKeyFile5.seek(80000 + 863*(fileLength % 2222))
  358             byteArrayOff42 = currentKeyFile5.read(4)
  359             currentKeyFile5.seek(90000 + 1013*(fileLength % 1111))
  360             byteArrayOff51 = currentKeyFile5.read(4)
  361         if not 'decryptOffset' in mode:
  362             currentKeyFile5.seek(offsetIntArray[4])
  363             byteArrayData5 = currentKeyFile5.read(fileLength)
  364     
  365     if not 'decryptData' in mode:
  366         cryptoArray.append(byteArrayOff11)
  367         cryptoArray.append(byteArrayOff12)
  368         cryptoArray.append(byteArrayOff21)
  369         cryptoArray.append(byteArrayOff22)
  370         cryptoArray.append(byteArrayOff31)
  371         cryptoArray.append(byteArrayOff32)
  372         cryptoArray.append(byteArrayOff41)
  373         cryptoArray.append(byteArrayOff42)
  374         cryptoArray.append(byteArrayOff51)
  375         cryptoArray.append(byteArrayOff52)
  376     if not 'decryptOffset' in mode:
  377         cryptoArray.append(byteArrayData1)
  378         cryptoArray.append(byteArrayData2)
  379         cryptoArray.append(byteArrayData3)
  380         cryptoArray.append(byteArrayData4)
  381         cryptoArray.append(byteArrayData5)
  382     return cryptoArray
  383 
  384 
  385 
  386 def encrypt(savedName, filesAsByteArray, fileIndex, nbSlices):
  387     ''' Fonction qui permet de procéder au chiffrement du tableau de bytes
  388         'filesAsByteArray' et de le sauver sous le nom savedName '''
  389     setKeyfilesAccess(True)
  390     offsetIntArray = []
  391     offsetBytesArray = []
  392 
  393     # ici, on créé le tableau d'offsets 
  394     # On aura toujours len(filesAsByteArray) < keyFileSize (donc < 100 MBytes)
  395     for index in range(5):
  396         intOffset = secrets.randbelow(100*(index+1)*(2**20)-len(filesAsByteArray))    
  397         byte3 = intOffset >> 24
  398         byte2 = (intOffset - byte3*(256**3)) >> 16
  399         byte1 = (intOffset - byte3*(256**3) - byte2*(256**2)) >> 8
  400         byte0 = (intOffset - byte3*(256**3) - byte2*(256**2) - byte1*256)
  401         bytesList = [byte0, byte2, byte3, byte1]
  402         offsetIntArray.append(intOffset) # offsetIntArray contient les offsets X au format integer normal
  403         offsetBytesArray.append(bytearray(bytesList)) # offsetBytesArray contient les offsets X au format 0231
  404 
  405     # On va créer le byteArray à partir duquel on va chiffrer les offsets et les données
  406     cryptoArray = setCryptoBytes('encrypt', len(filesAsByteArray), offsetIntArray)
  407 
  408     # On procède au chiffrement des offsets
  409     headerXOffset = []
  410     headerXOffset.append(XOR2Arrays(XOR2Arrays(offsetBytesArray[0], cryptoArray[0]), cryptoArray[1]))
  411     headerXOffset.append(XOR2Arrays(XOR2Arrays(offsetBytesArray[1], cryptoArray[2]), cryptoArray[3]))
  412     headerXOffset.append(XOR2Arrays(XOR2Arrays(offsetBytesArray[2], cryptoArray[4]), cryptoArray[5]))
  413     headerXOffset.append(XOR2Arrays(XOR2Arrays(offsetBytesArray[3], cryptoArray[6]), cryptoArray[7]))
  414     headerXOffset.append(XOR2Arrays(XOR2Arrays(offsetBytesArray[4], cryptoArray[8]), cryptoArray[9]))
  415 
  416     # On procède au chiffrement des données du fichier
  417     print("Tranche "+str(fileIndex+1)+"/"+str(nbSlices)+":")
  418     print("--> Chiffrement clé 1/5")
  419     tempData1 = XOR2Arrays(filesAsByteArray, cryptoArray[10])
  420     print("--> Chiffrement clé 2/5")
  421     tempData2 = XOR2Arrays(tempData1, cryptoArray[11])
  422     print("--> Chiffrement clé 3/5")
  423     tempData3 = XOR2Arrays(tempData2, cryptoArray[12])
  424     print("--> Chiffrement clé 4/5")
  425     tempData4 = XOR2Arrays(tempData3, cryptoArray[13])
  426     print("--> Chiffrement clé 5/5")
  427     finalData = XOR2Arrays(tempData4, cryptoArray[14])
  428 
  429     # On sauve le fichier chiffré
  430     with open(savedName, 'wb') as treatedFile:
  431         for oneOffset in headerXOffset:
  432             treatedFile.write(oneOffset)
  433         treatedFile.write(finalData)
  434     print("Chiffrement terminé -> Création du fichier " + savedName )
  435     print()    
  436     setKeyfilesAccess(False)
  437 
  438 
  439 
  440 def addDirToZip(zipHandle, path, basePath=""):
  441     ''' On va ici placer dans l'archive zipHandle tout le contenu du répertoire path '''
  442     basePath = basePath.rstrip("\\/") + ""
  443     basePath = basePath.rstrip("\\/")
  444     for root, dirs, files in os.walk(path):
  445         # add dir itself (needed for empty dirs)
  446         zipHandle.write(os.path.join(root, "."))
  447         # add files
  448         for oneFile in files:
  449             filePath = os.path.join(root, oneFile)
  450             inZipPath = filePath.replace(basePath, "", 1).lstrip("\\/")
  451             #print filePath + " , " + inZipPath
  452             zipHandle.write(filePath, inZipPath)
  453 
  454 
  455 
  456 def sliceAndEncrypt(filePath):
  457     ''' Pour simplifier les choses au niveau de la fonction de chiffrement (encrypt(filePath)), on impose
  458         que pour tout fichier à chiffrer, la taille  doit être inférieure à celle de la clé de chiffement
  459         la plus petite, soit 100MBytes (100 * 2**20). Si le fichier à chiffrer est de taille supérieure, 
  460         on va alors ici le découper en plusieurs tranches de tailles ~ équivalentes et inférieures à cette
  461         limite de 100 MBytes. On chiffrera ensuite l'ensemble des fichiers obtenus
  462         La variable limitSize (voir un peu plus bas après la ligne 'if proceed:') contiendra la limite de
  463         taille réellement choisie '''
  464     
  465     print()
  466     proceed = False
  467     # Si filePath pointe vers un fichier, on va le zipper à partir du fichier avant le chiffrement
  468     # cela permettra de ne pas avoir à se préoccuper du nom du fichier original (qui sera contenu dans le zip)
  469     if os.path.isfile(filePath):  
  470         # On va créer le zip dans le répertoire courant (currentDir)
  471         # Attention à bien avoir les droits d'écriture dans ce répertoire !
  472         simpleFilename = filePath.split('/')[-1] # Dans l'archive, on ne mettra que le nom du fichier, sans son path
  473         print("Chiffrement de " +simpleFilename)
  474         print()
  475         print("Étape 1 : Création de l'archive principale")
  476         zipHandle = zipfile.ZipFile('crypted.zip', 'w', zipfile.ZIP_DEFLATED)
  477         zipHandle.write(simpleFilename) 
  478         zipHandle.close()
  479         proceed = True
  480    
  481     # Si filePath pointe vers un répertoire, on va le zipper afin de pouvoir le traiter comme un fichier
  482     if os.path.isdir(filePath):
  483         # On va créer le zip dans le répertoire courant (currentDir)
  484         # Attention à bien avoir les droits d'écriture dans ce répertoire !
  485         zipHandle = zipfile.ZipFile('crypted.zip', 'w', zipfile.ZIP_DEFLATED)
  486         savedCurrentDir = currentDir
  487         repList = filePath.split('/')
  488         fRepList = []
  489         repToGo = ''
  490         proceed = True
  491 
  492         # Si l'on veut par exemple crypter le répertoire /home/toto/Documents , on va se placer dans /home/toto de
  493         # manière à se trouver à un étage 'supérieur' au répertoire 'Documents'. Ainsi, on pourra plus facilement
  494         # inclure ce nom de répertoire (et uniquement lui) dans l'archive zip, qui contiendra alors le répertoire
  495         #'/Documents' dans lequel on retrouvera tous ses fichiers et sous-répertoires
  496         for nStr in repList:
  497             if len(nStr)>0:
  498                 fRepList.append(nStr)
  499                 zipThisDir = nStr # Selon notre exemple, zipThisDir contiendrait 'Documents'
  500        
  501         if len(fRepList) == 0:
  502             proceed = False
  503             print4("Erreur, vous ne pouvez pas chiffrer l'ensemble de la racine (/) ! \r\n \
  504                     Sélectionnez un répertoire existant !")
  505         
  506         if len(fRepList) == 1:
  507             repToGo = '/'
  508             os.chdir(repToGo) 
  509             print("Chiffrement de " +filePath)
  510             print()
  511             print("Étape 1 : Création de l'archive principale")
  512             addDirToZip(zipHandle, zipThisDir) 
  513             zipHandle.close()
  514             os.chdir(savedCurrentDir) 
  515         
  516         if len(fRepList)>1:
  517             del fRepList[-1]
  518             for oneDir in fRepList:
  519                 repToGo += '/' + oneDir
  520             os.chdir(repToGo) # Selon notre exemple, on remonte ici dans le répertoire '/home/toto'
  521             print("Chiffrement de " +filePath)
  522             print()
  523             print("Étape 1 : Création de l'archive principale")
  524             addDirToZip(zipHandle, zipThisDir) # Ici, on va ajouter à l'archive zip tout le
  525             zipHandle.close()                  # contenu de 'Documents' vu de '/home/toto'
  526             os.chdir(savedCurrentDir) # On retourne ici dans le répertoire d'où l'on a appelé le script
  527 
  528     if proceed :
  529         print()
  530         print("Étape 2 : Découpe et Chiffrement :")
  531         filePath = currentDir+'/crypted.zip'
  532         fileSize = os.path.getsize(filePath)
  533 
  534         # On va charger le fichier à traiter, puis le découper en byteArray(s) de taille < 100MBytes si besoin
  535         # On a le choix ici de la limite de taille des byteArrays (doit être impérativement < 100MBytes)
  536         # Plus on abaisse cette limite, plus le chiffrement sera rapide pour les fichiers de taille supérieure
  537         # En contrepartie, on aura un chiffrement en plusieurs étapes (autant que de tranches, après découpe
  538         # du fichier crypted.zip)
  539         limitSize = (3+int(fileSize/(15*(2**20)))) * (2**20)
  540         if limitSize > (50*(2**20)):
  541             limitSize = 50*(2**20)
  542         print(limitSize)
  543         if fileSize < limitSize:
  544             nbSlices = 1
  545             rawSliceSize = fileSize
  546         else:
  547             nbSlices = int(fileSize/limitSize) + 1
  548             rawSliceSize = int(fileSize/nbSlices) + 1
  549       
  550         filesAsByteArray = []
  551         with open(filePath, 'rb') as treatedFile:
  552             for n in range(nbSlices):
  553                 treatedFile.seek(n*rawSliceSize)
  554                 filesAsByteArray.append(treatedFile.read(rawSliceSize))
  555 
  556         # On va maintenant chiffrer chaque byteArray, puis le sauver en tant que fichier chiffré
  557         namePart = '/' + str(int(time.time()))
  558         print(nbSlices)
  559         for n in range(nbSlices):
  560             fileExt = ".00"
  561             if 9 < n < 100:
  562                 fileExt = ".0"
  563             if 1000 > n > 99:
  564                 fileExt = "."        
  565             saveName = currentDir + namePart + fileExt + str(n)
  566             encrypt(saveName, filesAsByteArray[n], n, nbSlices)
  567             
  568         # On va supprimer le fichier crypted.zip qui n'est plus utile
  569         os.remove(filePath)
  570         time.sleep(2) # Petite pause avant fermeture du terminal si lancé en clic-droit depuis caja
  571 
  572 
  573 
  574 def decrypt(filePath, nbSlices):
  575     ''' Fonction qui permet de procéder au déchiffrement du fichier filePath '''
  576     if os.path.isfile(filePath):  # Si filePath pointe bien vers un fichier
  577         setKeyfilesAccess(True)
  578         usedLength = os.path.getsize(filePath) - 20 # On retire les 20 octets d'entête qui ont été 
  579         headerXOffset = []                          # ajouté lors du chiffrement
  580 
  581         # On va reconstituer le byteArray à partir duquel on a chiffré les offsets
  582         offsetIntArray = 0
  583         cryptoArray = setCryptoBytes('decryptOffset', usedLength, offsetIntArray)
  584 
  585         # Lecture et déchiffrement 1/2 des 5 offsets chiffrés
  586         with open(filePath, 'rb') as cryptedFile:
  587             off1 = cryptedFile.read(4)
  588             headerXOffset.append(XOR2Arrays(XOR2Arrays(off1, cryptoArray[0]), cryptoArray[1]))
  589             cryptedFile.seek(4)
  590             off2 = cryptedFile.read(4)
  591             headerXOffset.append(XOR2Arrays(XOR2Arrays(off2, cryptoArray[2]), cryptoArray[3]))
  592             cryptedFile.seek(8)
  593             off3 = cryptedFile.read(4)
  594             headerXOffset.append(XOR2Arrays(XOR2Arrays(off3, cryptoArray[4]), cryptoArray[5]))
  595             cryptedFile.seek(12)
  596             off4 = cryptedFile.read(4)
  597             headerXOffset.append(XOR2Arrays(XOR2Arrays(off4, cryptoArray[6]), cryptoArray[7]))
  598             cryptedFile.seek(16)
  599             off5 = cryptedFile.read(4)
  600             headerXOffset.append(XOR2Arrays(XOR2Arrays(off5, cryptoArray[8]), cryptoArray[9]))
  601             cryptedFile.seek(20)
  602             cypherData = cryptedFile.read(usedLength)
  603 
  604         # Reconstitution des offsets (Déchiffrement 2/2)
  605         intOffset = []
  606         for oneHeaderOffset in headerXOffset:
  607             byte0 = oneHeaderOffset[0]
  608             byte2 = oneHeaderOffset[1]
  609             byte3 = oneHeaderOffset[2]
  610             byte1 = oneHeaderOffset[3]
  611             intOffset.append(int(byte3*(256**3) + byte2*(256**2)+ byte1*256 + byte0))
  612 
  613         # On va reconstituer le byteArray à partir duquel on a chiffré les données
  614         cryptoArray = setCryptoBytes('decryptData', usedLength, intOffset)
  615 
  616         # On procède au déchiffrement des données
  617         fileExt = filePath.split('.')[-1]
  618         intFileExt = int(fileExt)
  619         print("Tranche "+str(intFileExt+1)+"/"+str(nbSlices)+":")
  620         print("--> Déchiffrement clé 1/5")
  621         tempData1 = XOR2Arrays(cypherData, cryptoArray[4])
  622         print("--> Déchiffrement clé 2/5")
  623         tempData2 = XOR2Arrays(tempData1, cryptoArray[3])
  624         print("--> Déchiffrement clé 3/5")
  625         tempData3 = XOR2Arrays(tempData2, cryptoArray[2])
  626         print("--> Déchiffrement clé 4/5")
  627         tempData4 = XOR2Arrays(tempData3, cryptoArray[1])
  628         print("--> Déchiffrement clé 5/5")
  629         finalData = XOR2Arrays(tempData4, cryptoArray[0])
  630 
  631         # On sauve le fichier déchiffré
  632         with open(currentDir+'/decypher.'+fileExt, 'wb') as treatedFile:
  633             treatedFile.write(finalData)
  634         print("Déchiffrement terminé -> Écriture du fichier " + currentDir+'/decypher.'+fileExt)
  635         print()    
  636         setKeyfilesAccess(False)
  637         return(currentDir+'/decypher.'+fileExt) # On va retourner le nom du fichier déchiffré, 
  638                                                 # afin de pouvoir le ré-assembler si besoin
  639 
  640 
  641 
  642 def getSlicesAndDecrypt(filePath):
  643     ''' On va déterminer ici en combien de tranches le fichier original a été découpé avant chiffrement.
  644         On devra déchiffrer chaque tranche, puis ré-assembler le tout pour reconstituer l'archive originale.
  645         Dans un dernier temps, on pourra enfin décompresser l'archive '''
  646 
  647     print()
  648     if os.path.exists(filePath):
  649         print("Déchiffrement de " +filePath)
  650         print()
  651         repList = filePath.split('.')
  652         if '000' in repList[-1]: # On s'assure que le fichier à déchiffrer possède bien une extension en .000
  653             myCypherList = []
  654             myCypherList.append(filePath)
  655             index = 1
  656             bitContinue = True
  657             while bitContinue:
  658                 fileExt = ".00"
  659                 if 9 < index < 100:
  660                     fileExt = ".0"
  661                 if 1000 > index > 99:
  662                     fileExt = "."        
  663                 tryThisFile = repList[0]+fileExt+str(index)
  664                 index += 1
  665                 if os.path.exists(tryThisFile):
  666                     myCypherList.append(tryThisFile) # myCypherList contiendra la liste des fichiers à déchiffrer
  667                 else:
  668                     bitContinue = False
  669             decypheredList = []
  670             decypheredByteArray = []
  671             for oneCryptedSlice in myCypherList:
  672                 decypheredList.append(decrypt(oneCryptedSlice, len(myCypherList)))
  673             for oneFile in decypheredList:
  674                 with open(oneFile, 'rb') as decypheredSlice:
  675                     tmpArray = decypheredSlice.read()
  676                     decypheredByteArray.append(tmpArray)
  677                 os.remove(oneFile)
  678             with open('finalFile.zip', 'wb') as finalFile:
  679                 for oneByteArray in decypheredByteArray:
  680                     finalFile.write(oneByteArray)
  681             finalZip = zipfile.ZipFile('finalFile.zip', 'r')
  682             try:
  683                rootArcName = finalZip.namelist()[0] # On vient chercher le nom du répertoire racine contenu
  684             except:                                 # dans finalFile.zip
  685                print("L'archive semble vide...")
  686                print()
  687             finalZip.extractall(currentDir)
  688             os.remove('finalFile.zip')
  689             print4("Extraction / création de " +rootArcName+ "  --> Déchiffrement terminé")
  690             time.sleep(2) # Petite pause avant fermeture du terminal si lancé en clic-droit depuis caja
  691         else:
  692             print4(filePath+" n'est pas un fichier valide pour déchiffrement !")
  693             time.sleep(2) # Petite pause avant fermeture du terminal si lancé en clic-droit depuis caja
  694         
  695 
  696 
  697 
  698 ###################### Lancement du programme principal ######################
  699 #
  700 if __name__ == "__main__":
  701     pfcDir = os.path.expanduser('~')+'/.pyFC'
  702     pfcConfFile = pfcDir+'/.pyFC.conf'
  703     currentDir = os.getcwd()
  704     keyFilepathList = []
  705     if len(sys.argv) == 1:
  706         printUsage()
  707     if len(sys.argv) == 2:
  708         foundBit2 = False
  709         if '-help' in (sys.argv[1]):
  710             foundBit2 = True
  711             printUsage()
  712         if '-init' in (sys.argv[1]):
  713             foundBit2 = True
  714             print("Cette opération va générer un nouveau jeu de clés de chiffrement.")
  715             strOK = input("Voulez-vous vraiment continuer ? (Abandon si différent de OK) : ")
  716             if len(strOK)==2 and 'OK' in strOK:
  717                 createKeyFiles()
  718             else:
  719                 print4("Abandon...")
  720         if '-showconf' in (sys.argv[1]):
  721             foundBit2 = True
  722             readConfFile()
  723             setConfFileAccess(True)
  724             setKeyfilesAccess(True)
  725             print4("Configuration et arborescence de clés accessibles.")
  726         if '-hideconf' in (sys.argv[1]):
  727             foundBit2 = True
  728             readConfFile()
  729             setConfFileAccess(False)
  730             setKeyfilesAccess(False)
  731             print4("Configuration et arborescence de clés protégées.")
  732         if not foundBit2: # Cas où l'on oublie par exemple de fournir un chemin pour le chiffrement/déchiffrement
  733             printUsage()
  734     if len(sys.argv) == 3:
  735         ed = False
  736         badFilePath = False
  737         if '-e' in (sys.argv[1]) or '-d' in (sys.argv[1]):
  738             ed = True
  739             if len(sys.argv[2]) > 1:
  740                 if os.path.exists(sys.argv[2]):  # On va ici traiter le chiffrement ou le déchiffrement 
  741                     readConfFile()  # On lit le fichier conf pour accéder aux chemins des fichiers clés
  742                     if '-e' in (sys.argv[1]):
  743                         sliceAndEncrypt(sys.argv[2])
  744                     if '-d' in (sys.argv[1]):
  745                         getSlicesAndDecrypt(sys.argv[2])
  746                 else:
  747                     badFilePath = True
  748         if not ed:
  749             # Erreur sur argument -e ou -d
  750             print4("Erreur : commande incompréhensible !")
  751             printUsage()
  752         if badFilePath:
  753             # Erreur sur chemin vers fichier ou répertoire passé en argument
  754             print4("Erreur : la chaine à traiter n'existe pas, n'est ni un fichier ni un répertoire !")
  755     if len(sys.argv) > 3: # Trop de paramètres passés en argument !
  756         print4("Erreur : trop de paramètres passés en argument !")
  757         printUsage()
  758 
Publicité
Retour à l'accueil
Partager cet article
Repost0
Pour être informé des derniers articles, inscrivez vous :
Commenter cet article