Aller au contenu

Evaluation

Évaluation

Sujet

Le ROT47 est un cas particulier du chiffre de César, où la clé vaut 47. Les caractères d'un texte sont associés à leur valeur ASCII. On n'applique le décalage qu'aux caractères ayant une valeur comprise entre [33, 126], les autres caractères restent inchangés.

Par exemple, le caractère ! devient P :

>>> chr(33)
'!'
>>> chr(33 +47)
'p'

Lorsque l'on dépasse 126, on retourne à 33. La lettre S, par exemple, qui a pour code ASCII 83. Avec la rotation 47, cela donne 83 + 47 = 130 = 127 + 3. Donc S est codé en chr(33 + 3) = $

  1. Écrire une fonction python qui permet de chiffrer en ROT47. Déterminer alors le chiffrement de "Bonjour le monde ! "

  2. Comment déchiffrer un message dont on sait qu'il a été chiffré avec ROT47 ? Quelle est sa particularité ?

  3. On intercepte le fichier rotXcrypte.txt, codé en ROTx, avec x un nombre inconnu. On sait juste que cette fois, on utilise les points de code de 0x21 à 0x1F0DF compris. Il ne s'agit donc plus d'ASCII mais le principe reste le même. Seule la limite maximum passe de 126 (Ox7e) à 0x1f0df

  4. Comment procéder à une attaque de force brute ? Combien d'essais devrait-on effectuer au pire ?

  5. Comment effectuer une attaque statistique sachant que le texte original est en français ?

  6. Comparons donc avec un texte en français, les Trois Mousquetaires d'Alexandre Dumas:

    from urllib.request import urlretrieve
    url_mousq = "https://www.gutenberg.org/cache/epub/13951/pg13951.txt"
    urlretrieve(url_mousq, 'mousq.txt')
    fic: str = open('mousq.txt', 'r').read()
    

    Créer une fonction de signature:

    def stat(mes: str) -> list
    

    Qui prend une chaîne de caractères en paramètre et renvoie la liste des caractères rangés par ordre décroissant de fréquence

  7. On suppose disposer d'un tableau de fréquence pour le message à déchiffrer. Créer la fonction

def remplace (origine: str, etalon: str) -> str

qui va remplacer chaque lettre dans le message chiffré par la lettre du message "etalon" (ici les Trois Mousquetaires) en suivant l'ordre d'apparition des lettres.

Obtient-on une bonne traduction ? Pourquoi ?

  1. On découvre qu'il s'agit d'un chiffrement par décalage. Quelle autre stratégie peut-on employer pour découvrir ce décalage si l'on connaît le caractère le plus fréquent dans le message à déchiffrer et dans le texte étalon ?

  2. Créer une fonction de même signature que la précédente mais qui utilise les nouveaux renseignements pour déchiffrer plus efficacement. Expliquer votre fonction.

  3. Quelle pourrait être l'utilisation moderne de ROT47 dans le contexte d'Internet ?


Corrigé

  1. ```python def rot47(clair: str) -> str: chif ="" dec = 33 amp = 127 - dec for car in clair: new_code = dec + ((ord( car) - dec + 47) % amp) chif += chr(new_code) if 33 <= ord(car) <= 126 else car return chif
On obtient donc :

```python
>>> rot47("Bonjour le monde !")
'q@?;@FC =6 >@?56 P'
  1. Le nombre de caractères décalables vaut 127 - 33 = 94. Il faut donc appliquer un décalage de -47 pour déchiffrer, sauf que... On remarque que si on applique un décalage de 47 après un premier décalage de 47, on effectue donc un décalage de 94 qui revient au point de départ. On peut imaginer le ROT47 comme un déplacement sur une roue ayant 94 graduations.

​ On n'a donc pas besoin de nouvelle fonction : la fonction de chiffrement est aussi la fonction de déchiffrement.

    • 0x1f0df - 0x21 = 127166. Il y a donc autant de clés possible à essayer.
  1. Dans un chiffrement par décalage, chaque lettre est toujours chiffrée de la même manière donc la fréquence d'un caractère, par exemple le e, dans le texte clair, sera la même que la fréquence de son caractère associé dans le texte chiffré.

    Il suffit donc de classer les caractères du texte chiffré selon leurs fréquences d'apparition et de comparer aux fréquences d'apparition usuelles des caractères de la langue française.

  2. On parcourt le texte. On regarde chaque caractère. S'il est dans le dictionnaire, on ajoute 1 à la valeur associée, sinon on crée une entrée avec pour valeur 1. On renvoie le dictionnaire trié par fréquence décroissante.

def stat(mes: str) -> list:
  dico = {}
  for lettre in mes:
    if lettre in dico:
      dico[lettre] += 1
    else:
      dico[lettre] = 1
  return sorted(dico, key = lambda x: dico[x], reverse=True)  

On veut que le i-ième caractère du texte chiffré soit remplacé par le i-ième caractère du texte français de référence. Ces listes de fréquences n'étant pas a priori de même taille, on prend la précaution de récupérer la taille minimum.

def remplace (origine: str, etalon: str) -> str:
  s_origine = stat(origine) #frequence du message 
  s_etalon = stat(etalon) # frequence du texte de référence
  mini = min(len(s_origine), len(s_etalon)) # taille minimum
  dic = {} # dictionnaire de correspondance chiffré -> référence
  for i in range(mini):
    dic[ s_origine[i] ] = s_etalon[i]
    # on parcourt chaque caractère et on le remplace par sa traduction
  trad = ""
  for lettre in origine:
    trad += dic[lettre]
  return trad

Mais cela ne donne pas la meilleure traduction.

  1. On repère le caractère le plus fréquent dans les deux textes ce qui nous donne le décalage probable en effectuant la différence des points de code de chacun.

    def guess(origine: str, etalon: str) -> str:
      s_origine = stat(origine)
      s_etalon = stat(etalon)
      dec = ord(s_origine[0]) - ord(s_etalon[0])
      return rotx(origine, -dec)
    
    1. Sans oublier de créer la fonction rotx qui généralise rot47:

    def rotx(clair: str, cle : int) -> str: chif ="" dec = 0x20 amp = 0x1f0e0 - dec for car in clair: new_code = dec + ((ord(car) - dec + cle) % amp) chif += chr(new_code) if 0x20 <= ord(car) <= 0x1f0df else car return chif

Cette fois ci, c'est bon.

  1. ROT47 et ROT13 sont souvent disponibles sur les navigateurs web car ils permettent de brouiller des textes pour les divers robots interceptant les données entrées par un utilisateur afin de faire de l'analyse de texte...

Auteur : Florian Mathieu

Licence CC BY NC

Licence Creative Commons
Ce cours est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International.