Aller au contenu

Chiffre de Vigenère : identifier et déchiffrer

Le chiffre de Vigenère applique une série de décalages alphabétiques (chiffre de César) dont la valeur change à chaque lettre selon une clé qui se répète cycliquement. Le texte chiffré produit résiste à une simple analyse de fréquence, contrairement au César.

Le chiffrement consiste à décaler chaque lettre du message clair d’une valeur définie par la lettre correspondante de la clé, en cyclant sur la clé si le message est plus long.

Chiffrement :

position chiffrée = (position claire + position clé) mod 26

Déchiffrement :

position claire = (position chiffrée - position clé + 26) mod 26

Exemple avec la clé KEY :

Message clair : H E L L O
Clé (cyclique) : K E Y K E
Décalages : +10 +4 +24 +10 +4
Message chiffré: R I J V S

La lettre H (position 7) décalée de K (10) donne R (17). La clé se répète : après Y, elle repart à K.

Un texte chiffré par Vigenère :

  • Ne contient que des lettres (majuscules ou minuscules selon l’implémentation)
  • Ne présente pas de mots reconnaissables
  • Affiche une distribution de fréquences plus aplatie qu’un texte en clair, mais pas uniformément plate (contrairement à un One-Time Pad)

L’indice de coïncidence (IC) mesure la probabilité que deux lettres tirées au hasard dans le texte soient identiques. Un texte en langue naturelle a un IC caractéristique :

  • Français : IC ≈ 0.074
  • Anglais : IC ≈ 0.065
  • Texte chiffré par César ou substitution monoalphabétique : IC ≈ 0.065 (la distribution est conservée)
  • Texte chiffré par Vigenère (clé longue) : IC ≈ 0.038 (distribution aplatie)
  • Texte aléatoire : IC ≈ 0.038

Un IC compris entre 0.04 et 0.06 sur un texte alphabétique évoque un chiffrement polyalphabétique comme Vigenère.

from collections import Counter
def indice_coincidence(texte):
texte = texte.upper().replace(' ', '')
n = len(texte)
freq = Counter(texte)
ic = sum(f * (f - 1) for f in freq.values()) / (n * (n - 1))
return ic
print(indice_coincidence("RIJVS..."))
https://www.dcode.fr/vigenere-cipher
  1. Coller le texte chiffré dans « Texte chiffré »
  2. Entrer la clé dans « Clé »
  3. Cliquer sur « Déchiffrer »
def vigenere_decode(ciphertext, key):
key = key.upper()
result = []
key_index = 0
for char in ciphertext.upper():
if char.isalpha():
shift = ord(key[key_index % len(key)]) - ord('A')
decoded = chr((ord(char) - ord('A') - shift) % 26 + ord('A'))
result.append(decoded)
key_index += 1
else:
result.append(char)
return ''.join(result)
print(vigenere_decode("RIJVS", "KEY"))
# HELLO

Si la clé est inconnue, deux informations sont nécessaires : la longueur de la clé, puis les lettres qui la composent.

Le test de Kasiski cherche des séquences de lettres qui se répètent dans le texte chiffré. La distance entre deux occurrences d’une même séquence est un multiple de la longueur de la clé.

def kasiski(ciphertext, seq_len=3):
text = ciphertext.upper().replace(' ', '')
positions = {}
for i in range(len(text) - seq_len):
seq = text[i:i+seq_len]
if seq in positions:
positions[seq].append(i)
else:
positions[seq] = [i]
distances = []
for seq, pos in positions.items():
if len(pos) > 1:
for i in range(1, len(pos)):
distances.append(pos[i] - pos[i-1])
from math import gcd
from functools import reduce
if distances:
pgcd = reduce(gcd, distances)
print(f"PGCD des distances : {pgcd}")
print(f"Longueur de clé probable : {pgcd} (ou un diviseur)")
return distances

Trouver la longueur de la clé, méthode de l’IC

Section intitulée « Trouver la longueur de la clé, méthode de l’IC »

Pour chaque longueur candidate L, diviser le texte en L sous-textes (les lettres en positions 0, L, 2L… ; puis 1, L+1, 2L+1… ; etc.). Calculer l’IC de chaque sous-texte. Si L est la bonne longueur, chaque sous-texte est un chiffre de César et son IC se rapproche de celui de la langue source (≈ 0.065 pour l’anglais, ≈ 0.074 pour le français).

def ic_moyen(ciphertext, key_len):
text = ciphertext.upper().replace(' ', '')
ics = []
for i in range(key_len):
sous_texte = text[i::key_len]
ics.append(indice_coincidence(sous_texte))
return sum(ics) / len(ics)
for L in range(1, 20):
print(f"L={L:2d} IC moyen={ic_moyen(texte_chiffre, L):.4f}")

La longueur pour laquelle l’IC moyen est le plus élevé est la longueur de clé probable.

Une fois la longueur L déterminée, chaque sous-texte (lettres en positions 0, L, 2L… etc.) est un César. Analyser la fréquence de chaque sous-texte : la lettre la plus fréquente correspond à la lettre la plus fréquente de la langue source (E en anglais, E ou A en français), ce qui donne le décalage de chaque position de la clé.

def trouver_cle(ciphertext, key_len, lettre_frequente='E'):
text = ciphertext.upper().replace(' ', '')
key = []
for i in range(key_len):
sous_texte = text[i::key_len]
freq = Counter(sous_texte)
lettre_max = max(freq, key=freq.get)
decalage = (ord(lettre_max) - ord(lettre_frequente)) % 26
key.append(chr(decalage + ord('A')))
return ''.join(key)

dcode.fr propose une analyse sans clé qui combine Kasiski et analyse fréquentielle :

https://www.dcode.fr/vigenere-cipher

Coller le texte chiffré, laisser le champ « Clé » vide, et lancer l’analyse automatique. L’outil propose plusieurs longueurs de clé candidates et les clés correspondantes.

1. Vérifier que le texte est uniquement alphabétique
→ chiffres ou caractères spéciaux → probablement un autre chiffrement
2. Calculer l'indice de coïncidence
→ IC proche de la langue source (≈ 0.065–0.074) → substitution monoalphabétique (César)
→ IC ≈ 0.038–0.055 → polyalphabétique, probable Vigenère
3. Si la clé est connue
→ dcode.fr ou script Python
4. Si la clé est inconnue
→ test de Kasiski ou méthode IC pour trouver la longueur
→ analyse fréquentielle par sous-texte pour trouver les lettres
→ ou analyse automatique dcode.fr

Le chiffre de Vigenère se distingue d’un César par son IC : plus bas que celui d’un texte naturel, plus élevé que celui d’un texte aléatoire. La longueur de la clé se déduit sans la connaître via le test de Kasiski ou l’analyse de l’IC par longueur. Avec la longueur trouvée, chaque sous-texte devient un César standard, déchiffrable par analyse de fréquence.