Le chiffrement de Vigenère est une méthode de chiffrement par substitution poly-alphabétique, considérée comme l’une des plus simples et des plus connues. Il améliore le chiffrement de César en utilisant une clé pour varier les décalages appliqués aux lettres du message clair.

Principe

Le chiffrement de Vigenère repose sur l’utilisation d’une clé pour déterminer le décalage à appliquer à chaque caractère du message clair. La clé est répétée cycliquement pour couvrir l’intégralité du message.

Notations

  • $ P $ : Texte en clair, $ P = p_0, p_1, p_2, \dots, p_n $.
  • $ K $ : Clé, $ K = k_0, k_1, k_2, \dots, k_m $ (répétée si nécessaire).
  • $ C $ : Texte chiffré, $ C = c_0, c_1, c_2, \dots, c_n $.

Chiffrement

Pour chaque caractère $ i $ du message clair, le caractère chiffré $ c_i $ est calculé comme suit :

\[c_i = (p_i + k_i) \mod 26\]
  • $ p_i $ et $ k_i $ sont les valeurs numériques des lettres (A = 0, B = 1, …, Z = 25).
  • Le résultat est converti en lettre (ex. : 0 = A, 1 = B, etc.).

Déchiffrement

Pour déchiffrer, on utilise la formule suivante :

\[p_i = (c_i - k_i) \mod 26\]

Si le résultat est négatif, on ajoute 26 pour obtenir un nombre entre 0 et 25.


Table de Vigenère

La table de Vigenère (ou carré de Vigenère) permet de visualiser le processus de chiffrement. Chaque ligne correspond à un décalage différent, déterminé par la clé.

  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
B B C D E F G H I J K L M N O P Q R S T U V W X Y Z A
C C D E F G H I J K L M N O P Q R S T U V W X Y Z A B
D D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
E E F G H I J K L M N O P Q R S T U V W X Y Z A B C D
F F G H I J K L M N O P Q R S T U V W X Y Z A B C D E
G G H I J K L M N O P Q R S T U V W X Y Z A B C D E F
H H I J K L M N O P Q R S T U V W X Y Z A B C D E F G
I I J K L M N O P Q R S T U V W X Y Z A B C D E F G H
J J K L M N O P Q R S T U V W X Y Z A B C D E F G H I
K K L M N O P Q R S T U V W X Y Z A B C D E F G H I J
L L M N O P Q R S T U V W X Y Z A B C D E F G H I J K
M M N O P Q R S T U V W X Y Z A B C D E F G H I J K L
N N O P Q R S T U V W X Y Z A B C D E F G H I J K L M
O O P Q R S T U V W X Y Z A B C D E F G H I J K L M N
P P Q R S T U V W X Y Z A B C D E F G H I J K L M N O
Q Q R S T U V W X Y Z A B C D E F G H I J K L M N O P
R R S T U V W X Y Z A B C D E F G H I J K L M N O P Q
S S T U V W X Y Z A B C D E F G H I J K L M N O P Q R
T T U V W X Y Z A B C D E F G H I J K L M N O P Q R S
U U V W X Y Z A B C D E F G H I J K L M N O P Q R S T
V V W X Y Z A B C D E F G H I J K L M N O P Q R S T U
W W X Y Z A B C D E F G H I J K L M N O P Q R S T U V
X X Y Z A B C D E F G H I J K L M N O P Q R S T U V W
Y Y Z A B C D E F G H I J K L M N O P Q R S T U V W X
Z Z A B C D E F G H I J K L M N O P Q R S T U V W X Y

Exemple

Chiffrement

  • Message clair : “HELLO FRIEND”
  • Clé : “ABC”

Conversion en valeurs numériques

Caractère H E L L O   F R I E N D
Valeur 7 4 11 11 14 26 5 17 8 4 13 3
Caractère (Clé) A B C A B C A B C A B C
Valeur 0 1 2 0 1 2 0 1 2 0 1 2

Calcul du texte chiffré

$ p_i $ $ k_i $ $ (p_i + k_i) \mod 26 $ $ c_i $
7 0 7 H
4 1 5 F
11 2 13 N
11 0 11 L
14 1 15 P
26 2 0 A
5 0 5 F
17 1 18 S
8 2 10 K
4 0 4 E
13 1 14 O
3 2 5 F

Texte chiffré : “HFNLP AFSKEOF”

(Note : L’espace a été ignoré dans cet exemple. En pratique, on peut le conserver ou le supprimer selon les besoins.)

Déchiffrement

Pour déchiffrer, on applique la formule $ p_i = (c_i - k_i) \mod 26 $.

$ c_i $ $ k_i $ $ (c_i - k_i) \mod 26 $ $ p_i $
7 0 7 H
5 1 4 E
13 2 11 L
11 0 11 L
15 1 14 O
0 2 24 (car -2 + 26 = 24) Y
5 0 5 F
18 1 17 R
10 2 8 I
4 0 4 E
14 1 13 N
5 2 3 D

(Note : L’espace a été mal géré dans cet exemple. Pour un déchiffrement correct, il faut ignorer les espaces ou les traiter séparément.)


Cas particuliers

  1. Gestion des espaces et caractères spéciaux :
    • On peut ignorer les espaces et les caractères non alphabétiques.
    • Ou les conserver en les chiffrant avec un décalage fixe (ex. : espace = 26).
  2. Clé plus courte que le message :
    • La clé est répétée cycliquement pour couvrir tout le message.
  3. Clé plus longue que le message :
    • Seule la partie de la clé correspondant à la longueur du message est utilisée.
  4. Sensibilité à la casse :
    • Le chiffrement est généralement insensible à la casse (toutes les lettres sont converties en majuscules ou minuscules).

Attaques sur le chiffrement de Vigenère

Malgré sa robustesse apparente, le chiffrement de Vigenère est vulnérable à plusieurs attaques, notamment :

Analyse des fréquences

Si la clé est courte, le texte chiffré présente des motifs répétitifs qui peuvent être exploités pour deviner la longueur de la clé. Une fois la longueur de la clé déterminée, chaque sous-texte peut être attaqué comme un chiffrement de César.

Méthode de Kasiski

Cette méthode consiste à repérer des séquences de lettres répétées dans le texte chiffré. La distance entre ces répétitions est souvent un multiple de la longueur de la clé.

Indice de coïncidence

L’indice de coïncidence permet d’estimer la longueur de la clé en comparant la fréquence des lettres dans le texte chiffré à celle d’un texte aléatoire.

Attaque par force brute

Si la clé est courte, une attaque par force brute (essai de toutes les combinaisons possibles) peut être efficace.


Algorithmes

def EVigenere(plaintext: str, key: str) -> str:
    ciphertext = []
    key_repeated = (key * (len(plaintext) // len(key) + 1))[:len(plaintext)]

    for p, k in zip(plaintext.upper(), key_repeated.upper()):
        if p.isalpha():
            p_val = ord(p) - ord('A')
            k_val = ord(k) - ord('A')
            c_val = (p_val + k_val) % 26
            ciphertext.append(chr(c_val + ord('A')))
        else:
            ciphertext.append(p)  # Garde les caractères non alphabétiques (espaces, ponctuation, etc.)

    return ''.join(ciphertext)

def DVigenere(ciphertext: str, key: str) -> str:
    plaintext = []
    key_repeated = (key * (len(ciphertext) // len(key) + 1))[:len(ciphertext)]

    for c, k in zip(ciphertext.upper(), key_repeated.upper()):
        if c.isalpha():
            c_val = ord(c) - ord('A')
            k_val = ord(k) - ord('A')
            p_val = (c_val - k_val) % 26
            plaintext.append(chr(p_val + ord('A')))
        else:
            plaintext.append(c)  # Garde les caractères non alphabétiques

    return ''.join(plaintext)