Aller au contenu

TP - Chiffrement symétrique XOR

Ce TP a pour but de vous faire programmer l'algorithmes de chiffrement symétrique XOR pour les caractères dont le code ASCII décimal est compris entre 32 et 255.

Dans le dossier [NSI], commencez par créer le dossier [C03-Securisation].

Téléchargez le fichier « à trous » TPC03.10.py (clic droit -> [Enregistrer la cible du lien sous]) et enregistrez-le dans le dossier [C03-Securisation].

Des exemples de tests sont proposés pour chaque fonction. Il faudra ajouter vos propres tests dans le main de votre programme.

Partie A - Conversion en chaîne de bits, et vice-versa

Pour appliquer l'algorithme de chiffrage symétrique XOR, il faut déterminer l'écriture binaire d'une chaîne de caractère. Chaque caractère de cette chaîne sera représenté par un octet (de type str).

  1. Complétez la définition de la fonction texte_to_binaire() qui prend en paramètre une chaîne de caractères et qui renvoie la représentation binaire de ce texte sous forme de chaîne, chaque caractère sur un octet.

    1
    2
    3
    4
    5
    6
    7
    def texte_to_binaire(texte):
        """
        texte - str, une chaîne de caractères de code ASCII compris entre 32 et 255
        Sortie: str - Représentation binaire de ce texte, chaque caractère sur un octet
        >>> texte_to_binaire('NSI')
        '010011100101001101001001'
        """
    
    Une piste

    Programmez des fonctions intermédiaires.

    • La première qui prend en paramètre un unique caractère et renvoie son code ASCII binaire (sous forme de chaîne)
    • La seconde qui complète ce code sur un octet si besoin.
      Par exemple '10101' est complété en '00010101'.
    Une autre piste

    Consultez ce cours de Première.

  2. Complétez la définition de la fonction binaire_to_texte() qui prend en paramètre la représentation binaire d'un texte (sous forme de chaîne, chaque caractère sur un octet) et qui renvoie la traduction du texte sous forme de chaîne de caractères.

    1
    2
    3
    4
    5
    6
    7
    def binaire_to_texte(binaire):
        """
        binaire - str, représentation binaire d'un texte, chaque caractère sur un octet
        Sortie: str - traduction du texte sous forme de chaîne de caractères
        >>> binaire_to_texte('010011100101001101001001')
        'NSI'
        """
    
    Une piste

    A nouveau, il est conseillé de programmer au moins une fonction intermédiaire.

    Une autre piste

    Cette fonction pourrait prendre en paramètre un octet (sous forme de chaîne) et renvoyer le caractère ASCII correspondant.

Partie B - Chiffrement et déchiffrement

  1. Complétez la définition de la fonction xor() en respectant ses spécifications.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    def xor(a, b):
        """
        a - str, caractère valant soit "0", soit "1"
        b - str, caractère valant soit "0", soit "1"
        Sortie: str - caractère de valeur a xor b, c'est-à-dire soit "0", soit "1"
        >>> xor("0", "0")
        '0'
        >>> xor("0", "1")
        '1'
        >>> xor("1", "0")
        '1'
        >>> xor("1", "1")
        '0'
        """
    
  2. Complétez la définition de la fonction crypte_xor() qui prend en paramètres deux représentations binaires de textes (sous forme de chaîne, chaque caractère sur un octet). Cette fonction renvoie une représentation binaire correspondant au message (la première représentation) ()cryptée par la clef (la seconde représentation).

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    def crypte_xor(message_bin, clef_bin):
        """
        message_bin - str, chaîne de caractères "0" et "1"
        clef_bin - str, chaîne de caractères "0" et "1" - clef de (dé)chiffrement
        Sortie: str - chaîne de caractères "0" et "1" correspondant à message_bin
                (dé)crypté par clef_bin selon l'algorithme de chiffrement symétrique XOR
        >>> message_bin = '01000011011100100111100101110000011101000110010101110010'
        >>> clef_bin = '010011100101001101001001'
        >>> crypte_xor(message_bin, clef_bin)
        '00001101001000010011000000111110001001110010110000111100'
        """
    
    Une piste

    La clef a souvent moins de caractères que le message, il faut donc « dupliquer » la clef d'autant de caractères que nécessaires pour réaliser la totalité du cryptage.

    Une autre piste

    Il y a plusieurs façons de gérer la duplication de la clef :

    • ou bien créer une fonction auxiliaire permettant cette duplication (ni plus, ni moins) ;
    • ou bien utiliser la division euclidienne sur les indices des caractères.
  3. Complétez la définition des fonctions chiffre_xor() et dechiffre_xor() en respectant leur spécification et en faisant appel à la fonction crypte_xor().

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def chiffre_xor(message, clef):
        """
        message - str, chaîne de caractères à crypter
        clef - str, clef de chiffrement, qui sera répétée si len(clef) < len(message)
        Sortie: str - chaîne de caractères "0" et "1" correpondant au message crypté
                par clef selon l'algorithme de chiffrement symétrique XOR
        >>> chiffre_xor("Crypter", "NSI")
        '00001101001000010011000000111110001001110010110000111100'
        """
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def dechiffre_xor(message_crypte, clef):
        """
        message_crypte - str, chaîne de caractères "0" et "1" correspondant au message
                    crypté par clef selon l'algorithme de chiffrement symétrique XOR
        clef - str, clef de chiffrement (sous forme de caractères "usuels")
        Sortie: str - le message décrypté.
        >>> dechiffre_xor("00001101001000010011000000111110001001110010110000111100", "NSI")
        'Crypter'
        """
    

Partie C - Déchiffrer par force brute

Vous interceptez la représentation binaire d'un message chiffré par l'algorithme XOR :

000011000010000100100000001110000011110001100001011011110111001100010111001000010010011000110010011011100011011100100100001110000011011000101111001010110010100101100001001110110011110101100001001110000010000100100000001001110111001100001001001011110011000000101010001010110010000101101111011011100001000100101000001010110011110101100001001011010011110000110011001010100011101000100000001000100011011000101100001010110011110100110101011000100111001100001111000011000001000101101111

Vous savez que ce message a été envoyé par votre enseignant et vous connaissez toutes ses mauvaises habitudes :

  • il utilise toujours une clef composée de trois lettres majuscules ;
  • il signe toujours ses messages en terminant par les caractères 'NBB.'.

Le but de cette partie est de déchiffrer, par force brute, ce message.

  1. Complétez la définition de la fonction forcer_xor() qui prend en paramètres la représentation binaire d'un message (sous forme de chaîne, chaque caractère sur un octet) et les derniers caractères non chiffrés de ce message. Cette fonction renvoie un couple constitué du message décrypté et de la clef de chiffrement, cette clef étant constituée de trois lettres majuscules.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    def forcer_xor(message_crypte, fin):
        """
        message_crypte - str, chaîne de caractères "0" et "1" correspondant au message
                    crypté par une clef de trois caractères majuscules
        fin - str, les derniers caractères du message, en clair (non cryptés)
        Sortie: tuple - le message décrypté et la clef.
        >>> message_crypte = "00001101001000010011000000111110001001110010110000111100"
        >>> forcer_xor(message_crypte, "pter")
        ('Crypter', 'NSI')
        """
    
  2. Utilisez cette fonction pour déchiffrer le message intercepté.
    A l'aide du module time, vérifiez qu'il faut entre 1 et 4 secondes pour forcer la clef et déchiffrer ce message...