Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout Inria - UCA

Exercice, niveau intermédiaire

Le code ou chiffre de Vigénère est une méthode de chiffrement très rustique, qui est une version un peu améliorée du chiffre de César.

Les deux méthodes fonctionnent par simple décalage dans l’alphabet modulo 26.

Je précise tout de suite que les conventions que nous avons adoptées dans cet exercice sont légèrement différentes de celles décrites dans les deux pages wikipédia citées ci-dessus.

Dans le chiffre de César, on se donne une clé constituée d’un seul caractère, disons par exemple C (la 3-ième lettre de l’alphabet), et avec cette clé on chiffre l’alphabet par un décalage de 3, ce qui donne :

clé     : C    
clair   : ABCDEFGHIJKLMNOPQRSTUVWXYZ
chiffré : DEFGHIJKLMNOPQRSTUVWXYZABC

ou avec d’autres clés

clé     : L
clair   : ABCDEFGHIJKLMNOPQRSTUVWXYZ
chiffré : MNOPQRSTUVWXYZABCDEFGHIJKL
clé     : E    
clair   : ABCDEFGHIJKLMNOPQRSTUVWXYZ
chiffré : FGHIJKLMNOPQRSTUVWXYZABCDE

La méthode de Vigenère consiste à choisir cette fois pour clé un mot, qui est utilisé de manière répétitive.

Ainsi par exemple si je choisis la clé CLE, on va chiffrer un message en appliquant la méthode de César

Le but de cet exercice est d’écrire une fonction qui implémente la méthode de Vigenère pour, à partir d’une clé connue, coder ou décoder des messages.

Première partie : le code de César

Dans un premier temps on se propose d’implémenter le code de César ; pour rester simple, nous allons nous limiter à ne chiffrer que les caractères alphabétiques dans la plage des caractères ASCII, c’est-à-dire sans accent, cédille ou autre.

Je rappelle par ailleurs l’existence en Python de deux fonctions qui peuvent être très utiles dans ce contexte :

# la fonction ord() retourne le codepoint
# d'un caractère
ord('a')
97
# et réciproquement avec chr()
chr(97)
The history saving thread hit an unexpected error (OperationalError('disk I/O error')).History will not be written to the database.
'a'

Une fois qu’on a dit ça, il est intéressant de constater que les caractères minuscules et majuscules auxquels nous nous intéressons sont, fort heureusement, contigus dans l’espace des codepoints.

import string
string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
COLUMNS = 7
for index, char in enumerate(string.ascii_uppercase, 1):
    print(f"{char}→{ord(char):3d} ", end="")
    if index % COLUMNS == 0:
        print()
A→ 65 B→ 66 C→ 67 D→ 68 E→ 69 F→ 70 G→ 71 
H→ 72 I→ 73 J→ 74 K→ 75 L→ 76 M→ 77 N→ 78 
O→ 79 P→ 80 Q→ 81 R→ 82 S→ 83 T→ 84 U→ 85 
V→ 86 W→ 87 X→ 88 Y→ 89 Z→ 90 
for index, char in enumerate(string.ascii_lowercase, 1):
    print(f"{char}→{ord(char):3d} ", end="")
    if index % COLUMNS == 0:
        print()
a→ 97 b→ 98 c→ 99 d→100 e→101 f→102 g→103 
h→104 i→105 j→106 k→107 l→108 m→109 n→110 
o→111 p→112 q→113 r→114 s→115 t→116 u→117 
v→118 w→119 x→120 y→121 z→122 

Forts de ces observations, vous devez pouvoir à présent écrire une première fonction qui implémente le décalage de César.

Comme par ailleurs les opérations d’encodage et de décodage sont symétriques l’une de l’autre, on choisit pour éviter d’avoir à dupliquer du code, d’écrire une fonction dont la signature est :

def cesar(clear, key, encode=True):
    # retourne un caractère

La fonction en question doit :

Voici ce que cela donnerait sur quelques exemples :

from corrections.exo_vigenere import exo_cesar
exo_cesar.example()
Loading...
# à vous de jouer pour implémenter la fonction cesar
def cesar(clear, key, encode=True):
    pass
# et pour vous corriger
exo_cesar.correction(cesar)
Loading...

Deuxième partie : le code de Vigenère

Cette première partie étant acquise, nous pouvons passer à l’amélioration de Vigenère, qui comme on l’a vu dans l’introduction consiste à prendre un mot dont on utilise les lettres successivement, et en boucle, comme clé pour la méthode de César.

Donc pour calculer le chiffrement de ce message avec la clé cle, on va se souvenir que

clé     : C    
clair   : ABCDEFGHIJKLMNOPQRSTUVWXYZ
chiffré : DEFGHIJKLMNOPQRSTUVWXYZABC
clé     : L
clair   : ABCDEFGHIJKLMNOPQRSTUVWXYZ
chiffré : MNOPQRSTUVWXYZABCDEFGHIJKL
clé     : E    
clair   : ABCDEFGHIJKLMNOPQRSTUVWXYZ
chiffré : FGHIJKLMNOPQRSTUVWXYZABCDE

et du coup faire

cesar('c', 'c') → 'f'
cesar('e', 'l') → 'q'
cesar(' ', 'e') → ' '
cesar('m', 'c') → 'p'
cesar('e', 'l') → 'q'
cesar('s', 'e') → 'x'
cesar('s', 'c') → 'v'
cesar('a', 'l') → 'm'
cesar('g', 'e') → 'l'
cesar('e', 'c') → 'h'

Voyons cet exemple sous forme de code :

from corrections.exo_vigenere import exo_vigenere
exo_vigenere.example()
Loading...

indices

# à vous de jouer
def vigenere(clear, key, encode=True):
    pass
# et pour corriger
exo_vigenere.correction(vigenere)
Loading...