Aller au contenu

TP Sécurisation des Communications : Cryptographie

Certificats HTTPS

Observer le certificat de ce site en cliquant sur le cadenas. Trouvez

  • sa date d'expiration
  • le nom de l'émetteur
  • l'émetteur du certificat est-il directement une autorité de certification ? On parle de chaîne de certificats quand une autorité certifie quelqu'un qui a son tour certifie quelqu'un d'autre.

Vous devez pouvoir trouver la clé publique du site.

  • Quel algorithme est utilisé ?
  • Quelle est la taille de la clé ?
  • Quel est l'exposant e de chiffrement ? (cela signifie qu'un message M sera chiffré par le reste de M^e dans la division euclidienne par le module)
  • Dans quel encodage (base) est affiché le module dans Firefox ?

Clés SSH

On a vu au précédent TP que ssh est un protocole (et un logiciel, la commande associée) qui permet de se connecter de manière chiffrée sur une autre machine et d'y avoir un terminal.

Sur linux, si un utilisateur les a générées, il dispose d'une clé ssh publique .ssh/id_rsa.pub et d'une clé ssh privée .ssh/id_rsa. Affichez les deux dans le terminal avec la commande cat. Avec quel encodage sont-elles affichées ? (combien de caractères possibles à votre avis ? c'est une puissance de 2)

La clé privée sert à décoder les messages chiffrés reçus, mais peut aussi servir à se connecter sur un serveur en s'authentifiant, remplaçant ainsi le mot de passe :

  • Si on veut s'authentifier sur un serveur avec notre clé publique, on ajoute le contenu de .ssh/id_rsa.pub au fichier .ssh/authorized_keys du serveur et on autorise l'identification par clé dans les paramètres du serveur ssh (/etc/ssh/sshd_config sur le serveur).
  • Le serveur autorise la connection à la personne qui peut prouver qu'elle dispose de la clé privée associée à cette clé publique (en signant un message dans le protocole).

On désactive en général alors l'identification par mot de passe, ce qui permet d'éviter toutes les attaques qui essaient de deviner un mot de passe faible.

Masque jetable (xor bit à bit) en python

Pour faire le XOR bit-à-bit d'un message, il faut se mettre d'accord sur la représentation binaire du texte. Cela dépend de l'encodage choisi.

Pour vous en rendre compte, essayez successivement dans une console python:

  • "départ".encode("ascii")
  • "départ".encode("iso-8859-1")
  • "départ".encode("utf-8")

Info

  • L'affichage \xe9 signifie e9 en hexadécimal. Un octet peut en effet toujours être représenté par 2 chiffres hexadécimaux (ou bien 8 chiffres binaires, ou bien un nombre décimal entre 0 et 255)
  • Le résultat, affiché sous la forme b'blabla' en python, est du type bytes qui permet de représenter des valeurs d'octets brutes (sans se soucier de si ça représente un texte valide ou non). La valeur d'un octet est affiché en caractère si c'est un code ASCII valide, et sous la forme \x?? sinon.

Écrire une fonction xor_octet(a,b) qui effectue le xor sur deux octets a et b de type int, et renvoie le résultat sous forme d'une valeur de type bytes de longueur 1.

  • pour faire le XOR bit-à-bit sur des nombres en python, on utilise l'opérateur ^
  • pour convertir un int en bytes, on utilise la méthode suivante : (56).to_bytes(length=1,byteorder="big")

Écrire une fonction chiffrage_xor(m,key) qui :

  • prend un paramètre m de type bytes (le message), et un paramètre key de type bytes (la clé)
  • si la longueur de la clé est plus petite que celle du message, renvoie None
  • sinon, parcourt tous les octets m[i] de m, et les chiffre en utilisant xor_octet avec la clé key[i]. On pourra créer une variable resultat initialisée à b'' (de type bytes et vide), et ajouter les octets à la fin avec resultat += ....
  • renvoie le résultat chiffré de type bytes

Créez des variables avec une clé et un message (de type bytes), et tester votre fonction. Comment faire le déchiffrage ?

Essayez l'exercice suivant :

# on suppose que clé et message1 ont été définis
# et qu'on a obtenu message1_chiffre à partir de clé
message2 = b'jecontrolecemessage'
message2_chiffre = chiffrage_xor(message2, clé)

# on a réutilisé deux fois la même clé, ce qui rend le chiffrement attaquable
# Retrouvez message1 seulement à partir de message1_chiffre, message2, message2_chiffre
# (sans utiliser la clé)

Attaque temporelle

On a vu que ce code :

def verifie(mot_de_passe, mot):
    """Renvoie True si et seulement si mot == mot_de_passe"""
    n = len(mot_de_passe)
    if len(mot) != n:
        return False
    for i in range(n):
        if mot[i] != mot_de_passe[i]:
            return False
    return True

est correct mais permet de deviner une petite information en fonction du temps mis à répondre : plus on a de caractères corrects au début du mot (s'il a la bonne taille), plus on va faire de tours dans la boucle for avant de s'arrêter.

Cela permet une attaque par canal auxiliaire, qu'on va essayer de faire marcher concrètement.

Téléchargez et décompressez timing_attack.zip puis complétez le fichier timing_attack_eleve.py pour essayer de deviner le mot de passe contenu dans crypto_trouee.py juste en appelant la fonction verifie, en bien moins d'un milliard d'années...

Utilisation de bibliothèques pour RSA, AES, ...

S'il est très conseillé de recoder de la cryptographie soi-même, pour le fun et pour apprendre comment ça marche (voir section suivante), il ne faut pas le faire pour des vrais projets qui seront utilisés par d'autres gens !

Installez la bibliothèque cryptography, et utilisez la documentation pour :

À faire

déchiffrer le message b'gAAAAABiMifXdoh1jmgSvLyg6DtoXtZGL-R-AT0w00a407KrfUIw1uVTPU7iBuR6U8zugq873etsFjixkbF8TXH8iNRFP4T8WjaKFq39oBjpSC3SmL-zkB3AL7j8UUmLZFsolSfZ_PIlZfnjzbYWj9CTkUrEyHP0M0VPcN6GvyS1IVhOrGIrPuEv9LbkjBKy6sqG4XIgUJ-2-PHRnRxIb-Wz54g6OLvJ34Uq896jgQdtuV8EZen6rUnYchVAwJKMRMzAHoSSx-DT' chiffré avec le module de chiffrement symétrique Fernet et la clé b'L28Yw473ZH8mjAnP0B3LH-XGX_kcjPHg7Kqz8yAaB8k='

Quelles sont les deux limitations de sécurité mentionnées sur la documentation de la biibliothèque ? Essayez de les comprendre, et appelez-moi pour me les réexpliquer.

Pour aller plus loin

Le site https://cryptopals.com/ contient une série de 48 exercices qui peuvent se résoudre en python et qui font coder des attaques concrètes sur des procédés de cryptographie. Il faut un peu d'aisance en programmation mais il n'y a pas besoin de beaucoup de maths : la plupart des attaques n'utilisent que des maths élémentaires. Ça prend du temps mais c'est très recommandé si vous avez envie de savoir dans les détails comment fonctionne et comment se casse la cryptographie moderne.