-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 TP3 : cryptographie et chiffrement avec GPG info-223 : « science informatique » Printemps 2014 - ------------------------------------------------------------------------ Consignes 1. Stockage des mots de passes 1.1. Fonction de hashage 1.2. Attaque par dictionnaire 1.3. Attaque "brute force" 2. GPG et le chiffrement symétrique 2.1. Vérifications 2.2. Chiffrement 2.3. Déchiffrement 2.4. Attaque par dictionnaire / brute force 3. Gestion des clés publique / privée 3.1. Création des clés 3.2. Partage des clés 3.3. Donner et récupérer une clé 3.3.1. Vérifier et contre-signer une clé 4. Chiffrement 4.1. Chiffrement 4.2. Déchiffrement 5. Signature électronique 5.1. Signature 5.2. Vérification 6. FIN - ------------------------------------------------------------------------ Consignes ========= Vous devrez utiliser l'interface TPLab (http://lama.univ-savoie.fr/TPLab/liste_TP/info223) pour envoyer vos TP aux encadrants de TP. Pour ce TP, vous devrez envoyer un message (signé et crypté) contenant un petit rapport. Le rapport sera devra être un fichier texte. Les rapports envoyés dans un autre format (pdf, openoffice, openrtf, word) ne seront pas lus. Faites attention lors de la rédaction du rapport : je ne veux pas lire la suite des commandes que vous avez utilisées. Soyez concis... <<>> ==Liens utiles== - la page de GPG (http://www.gnupg.org/), - la page de PGP (http://www.pgp.com/), - un gros fichier texte (« Les misérables » de Victor Hugo) (./TP3/miserables.txt) ============================================================================= 1. Stockage des mots de passes ============================== 1.1. Fonction de hashage ======================== Vos mots de passe pour vous connecter à votre compte Facebook, univ-savoie ou tout autre service necessitant une authentification ne sont normalement pas stockés directement dans un fichier. Le risque de fuite serait trop important... Normalement, seul un hash de votre mot de passe est enregistré sur un ordinateur : un hash est une suite de caractères de taille fixe associée à une chaîne quelconque. Par exemple, le hash (pour l'algorithme sha1) de la chaîne {{{code:txt J'aime les pizzas. }}} est "ac4f7e9c94319a21136f8e5f9189bdaf7899c25e". Pour la chaîne {{{code:txt j'aime les pizzas. }}} (sans majuscule), le hash est maintenant "2edba57751b915a8dd8d562e1179265f5d16088c" Le hash de {{{code:txt Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. }}} est "63990c1f17df756f8d7cb96cdf18e933b66ec0f0" et contient exactement le même nombre de caractères que les hash précédents... Les fonctions de hash utilisées en cryptographie sont toujours faciles (rapide) à calculer, mais elles doivent vérifient )les propriétés suivantes : - il est très difficile de trouver une chaîne ayant un hash donné, - il est très difficile de modifier une chaîne sans modifier son hash, - il est très difficile de trouver deux chaînes avec le même hash. Les algorithmes de hashage les plus connus sont : - md5 (mais cet algorithme n'est plus sûr) - sha1, - sha256 / sha512 Pour vous authentifier sur un site, vous tapez votre mot de passe, et le programme vérifie que son hash est bien identique au hash stocké sur le serveur... <<>> 1.2. Attaque par dictionnaire ============================= Si on possède le hash d'un mot de passe, on peut essayer de retrouver le mot de passe en essayant toutes les possibilités. En général, il est intéressant de commencer par les mots du dictionnaire. Le fichier dico.txt (./TP5/dico.txt) contient les mots du dictionnaire "le Littré" qui ne contiennent pas d'accent. Il contient 47666 mots... Le code Python suivant permet de tester tous les mots de ce fichier et de comparer leur hash avec un hash passé en argument : {{{code:python import hashlib def attaque_dico_hash(h, dic): dico = open(dic, mode="r") n = 0 # pour compter le nombre de mots for mot in dico: mot = mot.strip() n = n + 1 if hashlib.sha256(mot.encode()).hexdigest() == h: print("TROUVÉ ! Le mot '{}' a le hash {}".format(mot,h)) dico.close() return if n % 1000 == 0: print("{} mots testés...".format(n)) print("Aucun des {} mots testés n'avait le hash {}...".format(n, h)) }}} <<>> 1.3. Attaque "brute force" ========================== Nous allons maintenant tester tous les mots de passe d'une taille donnée. Pour les mots de passe sur 3 lettres, cela pourrait donner : {{{code:python import hashlib def attaque_brute_force_hash(h): n = 0 # pour compter le nombre de mots alphabet = "abcdefghijklmnopqrstuvwxyz" for a in alphabet: for b in alphabet: for c in alphabet: mot = a+b+c n = n + 1 if hashlib.sha256(mot.encode()).hexdigest() == h: print("TROUVÉ ! '{}' a le hash {}".format(mot,h)) return if n % 1000 == 0: print("{} mots testés...".format(n)) print("Aucun des {} mots testés n'avait le hash {}...".format(n, h)) }}} <<>> 2. GPG et le chiffrement symétrique =================================== 2.1. Vérifications ================== Le but de la suite de ce TP est de vous familiariser avec la notion de signature électronique et de chiffrement clé publique / clé privée en utilisant le logiciel GPG (Gnu Privacy Guard : http://www.gnupg.org/). GPG est une version libre du logiciel PGP (Pretty Good Privacy : http://www.pgp.com/) crée par Philip Zimmermann. Bien qu'il existe des clients graphique (GPA par exemple), nous allons utilisez l'outil le plus basique (mais aussi le plus puissant) : le programme gpg en mode texte. Dans un terminal (Menu Applications --> Accessoire --> Terminal, vérifiez que le logiciel est bien installé avec la commande [[[shell $ gpg --version ]]] Créez ensuite un répertoire dans le bureau et positionnez-vous dans ce répertoire : [[[shell $ mkdir Bureau/info223-TP3 $ cd Bureau/info223-TP3 ]]] <<>> 2.2. Chiffrement ================ Si vous partagez une clé secrète avec votre destinataire, vous pouvez utiliser GPG pour faire de la cryptographie symétrique. Pour crypter le fichier "nom_fichier", il faut utiliser la commande : [[[shell $ gpg --symmetric --armour nom_fichier ]]] Ceci créera un fichier "nom_fichier.asc" contenant le fichier chiffré. Cette méthode est préférée quand vous voulez par exemple envoyer le fichier par email. Vous pouvez également créer un fichier crypté binaire. La commande correspondante est [[[shell $ gpg --symmetric nom_fichier ]]] Ceci créera un fichier binaire "nom_fichier.gpg" contenant le fichier binaire chiffré. <<>> 2.3. Déchiffrement ================== Pour décrypter, il suffit d'utiliser : [[[shell $ gpg --decrypt nom_fichier.asc ]]] (Bien entendu, "nom_fichier.asc" sera remplacé par "nom_fichier.gpg" si le fichier a été crypté en binaire..) <<>> 2.4. Attaque par dictionnaire / brute force =========================================== On peut essayer une attaque "brute force" comme pour les mots de passe. Le code suivant permet de lancer la commande gpg --decrypt sur un fichier existant. Elle teste toutes les lignes d'un autre fichier comme clé... {{{code:Python import os import subprocess def attaque_dico_gpg(fichier, dic): dico = open(dic, mode="r") n = 0 # pour compter les mots # tableau contenant les différents morceau de la commande à executer... # il faudra remplacer "CLE SECRETE" par la clé que l'on veut tester commande = "gpg", "--decrypt", "--quiet", "--passphrase", "CLE SECRETE", (fichier) NULL = open(os.devnull, mode="a") for mot in dico: mot = mot.strip() n = n + 1 commande[-2] = mot res = subprocess.call(commande, stdout=NULL, stderr=NULL) if res == 0: print("TROUVÉ ! Le mot '{}' est la clé secrète pour décrypter le fichier {}".format(mot, fichier)) return if n % 1000 == 0: print("{} mots testés...".format(n)) print("Aucun des {} mots testés ne permet de décrypter le fichier {}...".format(n, fichier)) }}} <<>> 3. Gestion des clés publique / privée ===================================== 3.1. Création des clés ====================== Les clés sont stockées dans un répertoire caché de votre répertoire personnel : .gnupg. Vous êtes la seule personne à avoir accès à ce fichier. De plus, vos clés sont protégées par un mot de passe pour renforcer la sécurité. Pour créer votre propre clé publique/clé privée, il faut utiliser la commande [[[shell $ gpg --gen-key ]]] - Créez vos clés en acceptant les choix par défaut, sauf pour la durée de validité de vos clés : comme il s'agit d'un premier essai, je vous conseille de ne créer qu'une clé temporaire (30 jours). Vous pourrez toujours recréer des clés quand vous vous serez familiarisés avec le fonctionnement de GPG... - Mettez votre vrai nom (ou au moins vos initiales) et choisissez ``info-223 2014'' comme commentaire. Choisissez une adresse email valide... - Choisissez une « passphrase » sûre et dont vous vous rappellerez... Elle vous servira à chaque fois que vous aurez à utiliser votre clé privée. <<>> Pour vérifiez que les clés ont bien été créées, utilisez la commande [[[shell $ gpg --list-keys ]]] Vous devriez obtenir quelque chose du genre [[[shell $HOME/.gnupg/pubring.gpg pub 2048R/9623ABA3 2014-04-24 expire : (2014-05-24) uid Pierre Hyvernat (clé temporaire, TP3 info223) sub 2048R/32DB7919 2014-04-24 expire : (2014-05-24) ]]] qui vous indique que vous avez une clé principale (ligne "pub") qui expire le 19 mai ; et une sous-clé (ligne "sub") qui expire aussi le 19 mai. La ligne "uid" vous donne l'identité de l'utilisateur correspondant. La clé principale est utilisé pour les signatures, et la sous-clé pour le chiffrement. <<>> <<>> 3.2. Partage des clés ===================== 3.3. Donner et récupérer une clé ================================ Pour envoyer votre clé publique à quelqu'un, vous pouvez commencer par l'exporter avec la commande [[[shell $ gpg --output cle.asc --export --armour uid ]]] où "uid" est l'identité (l'adresse email par exemple) de la clé concernée et "cle.asc" le nom du fichier qui contiendra la clé en ASCII. Si vous voulez exporter la clé en binaire, il faut utiliser : [[[shell $ gpg --output cle.gpg --export uid ]]] À l'inverse, pour importer une clé (en binaire ou en ASCII) contenue dans le fichier "cle.asc", il suffit d'utiliser la commande [[[shell $ gpg --import cle.asc ]]] <<>> <<>> 3.3.1. Vérifier et contre-signer une clé ======================================== Chaque clé possède une « empreinte digitale ». Quand vous récupérez une clé, il est important de vérifier cette empreinte... Cette empreinte est suffisamment petite pour être facilement transmissible (carte de visite etc.) Par exemple, nos clés possèdent l'empreinte - Pierre Hyvernat 0AA3 4777 06C9 61A0 02D2 7AEB DF14 C879 9623 ABA3 (lien vers la clé (./TP3/cle-hyvernat.asc)) - Louis Cuel 663B 4C4A FD91 EA77 6232  ECE0 8227 E420 6E85 0391 (lien vers la clé (./TP3/cle-cuel.asc)) Comme on ne peut pas faire confiance à une page web, je vous l'écrirais au tableau... Pour trouver l'empreinte d'une clé, vous pouvez utiliser [[[shell $ gpg --fingerprint ]]] qui listera toutes les clés connues avec leur empreinte. Si vous mettez une chaîne de caractères à la fin de la commande, cela ne listera que les clés qui contiennent la chaîne en question. (Pratique quand vous avez beaucoup de clés.) Une fois que vous avez vérifié une clé, vous pouvez l'authentifier pour dire « je fais confiance à cette clé... » On parle de contre-signature. La commande est simplement : [[[shell $ gpg --sign-key uid ]]] où "uid" est l'identité de la clé à authentifier. <<>> <<>> 4. Chiffrement ============== Maintenant que vous avez des clés, vous pouvez crypter des messages sans partager de clés secrètes... 4.1. Chiffrement ================ On utilise [[[shell $ gpg --encrypt --armour fichier ]]] pour obtenir un fichier ASCII "fichier.asc" contenant le fichier original crypté. GPG nous demandera les destinataires, à choisir parmi les gens dont on possède les clés publiques. Si on veut obtenir un fichier binaire, la commande devient : [[[shell $ gpg --encrypt fichier ]]] pour obtenir un fichier "fichier.gpg" contenant le fichier original crypté. 4.2. Déchiffrement ================== Toujours pareil : pour décrypter, on utilise [[[shell $ gpg --decrypt fichier ]]] <<>> 5. Signature électronique ========================= 5.1. Signature ============== Maintenant que vous avez des clés, vous pouvez signer des messages. Pour cela, il faut utiliser : [[[shell $ gpg --clearsign fichier ]]] pour signer le fichier "fichier". Ceci créera un nouveau fichier "fichier.asc" qui contiendra le fichier original avec une signature vous authentifiant. La commande [[[shell $ gpg --detach-sign fichier ]]] permet elle de créer uniquement une signature (binaire) pour le fichier en question. Cette signature (fichier "fichier.sig") devra être envoyé avec le fichier original. Pour un fichier texte, la première méthode est préférable. (Sauf si c'est un email et que votre logiciel gère les signatures en pièce jointe...) Pour un fichier binaire, il faut mieux utiliser la seconde méthode. 5.2. Vérification ================= Pour vérifier un fichier signé, on utilise [[[shell $ gpg --verify fichier.asc ]]] Il faut bien entendu pour cela disposer de la clé publique de la personne qui a signé le document. <<>> <<>> <<>> 6. FIN ====== <<>> <<>> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQEcBAEBAgAGBQJTWR7BAAoJEN8UwHmWI6ujwKUH/1oXButuQOb1NRifR3y9pWUa 0HQ63Fjadyg6XL7mLtDteC/SKQQ5ahQQr5DPAYXsgQ5dVi2ldID5/pLXfGCfunw1 XLDmmSZdQR6K3is9Mx+zLTYDYJC8gxjkPj2x+2poQOuGD40M+F2GL/KFcJ/tHZXs bnWKPz8MYdD3qWVoz4mzHWvzIsGwdZ46KW1zTDf4QIQvJ1EKljuTX8i/eVbgKvEq ZVE+2B/t3tx3ZI7nbUz/ZQ1MZ5l5kZfVBuBBNhkYeIgQksq5yXaOnt+f0NqyuZlP Dau93GemP5FxTws4YZnLFPpXY4d0mZg6YqMjp9Pm0k73DFpHbax5G8hG3cjTJCU= =Poxk -----END PGP SIGNATURE-----