Partage de fichier simple
This repository has been archived on 2022-11-02. You can view files and clone it, but cannot push or open issues or pull requests.
Find a file
2022-11-02 19:53:13 +01:00
src remove time from db 2022-10-28 23:03:33 +02:00
.gitignore * use json to send file to flask 2022-10-27 16:08:04 +02:00
README.md update diagram 2022-11-02 19:53:13 +01:00
requirements.txt use custom font 2022-10-07 00:59:40 +02:00

Sand

Partage de petits fichiers* de façon sécurisée avec RSA.

* ne supportes pas les binaires

Exécution avec Python 3.9.2

Préparation de l'environnement

$ python3 -m venv .
$ source bin/activate
$ pip install -r requirements.txt

Lancement

$ python3 -m flask --app src/app.py run

Ressources utilisés

Fonctionnement

Explication

Le but est que le serveur n'est jamais accès :

  • au fichier déchiffré
  • aux clefs permettant de lire le fichier

Pour cela, tout le chiffrement est fait en local dans le navigateur. Lors de la réception du fichier, une paire de clef RSA (sur 1024 bits) est créer.

À cause des limitations du Javascript, la clef est limitée à 1024 bits, sinon le chiffrement est trop long. Aussi la taille des fichiers est limitée à environ 500 ko.

À cause de RSA, il est recommandé de n'envoyer que des petits fichiers de quelques octets, plus le fichier est lourd, plus le chiffrement sera long. Pendant le chiffrement, l'interface se figera car les calculs sont faits sur le thread principal.

Le fichier reçu est ensuite chiffré avec la clef secrète générée précédemment. Le nom du fichier est également chiffré avec la même clef.

Les deux chiffrés sont envoyés au serveur. Un hash du fichier chiffré est généré par le serveur, cet hash ainsi que le nom du fichier chiffré est stocké dans une base de données SQLite, le fichier est quant à lui enregistrer sur le disque (par défaut dans le dossier uploads/ avec comme nom de fichier l'hash).

L'hash est renvoyé par le serveur au client, une fois reçu le client affiche à l'utilisateur l'URL pour télécharger le fichier, qui se présente ainsi :

HTTP(S)://IP:PORT/file/HASH#CLEF

La clef publique étant composé du module de chiffrement (n) et de l'exposant de chiffrement (e), les deux nombres sont séparés, soit CLEF = e:n.

Quand le second utilisateur clique sur le lien, il peut donc télécharger le fichier car :

  • l'hash permettant de demander au serveur le fichier est contenu dans la première partie de l'URL (avant le #)
  • la clef permettant de déchiffrer le chiffré est contenue dans la seconde partie de l'URL (après le #)

Le nom du fichier est stocké pour permettre de garder le même nom de fichier quand on reçoit le fichier.

Le serveur ne connaît donc jamais la clef permettant de déchiffrer les fichiers qu'il reçoit et stocke.

Implémentation et limite

Pour le chiffrement, je transforme le fichier en base64, puis je regarde le code ASCII, par exemple "<3" devient "060051" pour 60 et 51. Je vais devoir convertir mes string en bigint pour le chiffrement RSA, alors pour rester dans la limite de bigint, je garde la taille de mes strings fixe à max 100 caractères. Au maximum un code ASCII est composé de 3 chiffres alors je sais que pour retrouver mes chiffres je vais devoir découper mon string tous les 3 caractères. Pour garder mon code "060051" qui sera 60051 en int, j'ajoute un 1 au début, que je retirerais lors de la transformation en bigint. Ces opérations sont faites dans le fichier rsa.js (cf. l'arborescence expliquée en dessous) dans str_to_int et int_to_str. Cette implémentation n'est pas optimisée et c'est ce qu'il faudrait changer pour pouvoir supporter les fichiers binaires.

Le chiffrement se fait donc par bloc, tous les 100 chiffres, dans RSA_enc_data.

Le fait que JS ne gère pas aussi bien les très gros nombre que Python est un problème qui fragilise encore plus le RSA, car je dois envoyer le chiffré découpé par des virgules tous les x caractères pour qu'il soit correctement déchiffré. Ce qui rend reconnaissable le chiffré produit car il contient une suite de nombres séparés régulièrement par des virgules.

Organisation du projet

src
├── app.py ------------> Point d'entrée pour lancer l'application
├── config.py ---------> Configuration globale + télécharge les dépendances
├── public ------------> Accessible depuis le client
│  ├── js
│  │  ├── download.js -> Gère la partie téléchargement
│  │  ├── index.js ----> Gère la partie téléversement
│  │  └── rsa.js ------> Implémentation de RSA
│  └── styles
│     └── style.css
├── routes
│  ├── api ------------> /api
│  │  ├── download.py -> /api/download -> Envoie les données au client
│  │  └── upload.py ---> /api/upload ---> Reçoit les données du client
│  ├── file.py --------> /file ---------> Interface de téléchargement
│  └── index.py -------> / -------------> Interface de téléversement
├── templates ---------> Fichier HTML
│  ├── download.html
│  └── index.html
└── utils
   ├── font.py -------> Permets de télécharger la police
   ├── libjs.py ------> Permets de télécharger la librairie Javascript
   ├── misc.py -------> Entre autres, implémente la fonction de hashage
   └── sqlite.py -----> Gère ce qui est en rapport avec SQLite

Schéma récapitulatif