Problème — cryptage d'un fichier texte (10 points), dans l'esprit des sessions 2017–2021
Pour échanger des messages confidentiels, une association crypte le contenu d'un fichier texte nommé "Clair.txt", enregistré dans le dossier D:\Secret. Chaque ligne de ce fichier contient un message formé de mots écrits en lettres majuscules et séparés par un seul espace ; une ligne compte au plus 60 caractères.
Le cryptage utilise une clé formée de deux entiers a et b. Chaque lettre est cryptée en trois étapes :
Étape 1 : remplacer la lettre par son rang X dans l'alphabet : "A" a le rang 0, "B" le rang 1, …, "Z" le rang 25.
Étape 2 : calculer l'entier Y défini par :
Étape 3 : remplacer Y par la lettre de rang Y.
Les espaces ne sont pas cryptés : chacun reste à sa place.
Exemple : pour la clé a = 7 et b = 3, la lettre "C" a le rang X = 2 ; Y = (7 × 2 + 3) Mod 26 = 17, qui est le rang de la lettre "R". En procédant de même pour chaque lettre, le mot "BAC" devient "KDR".
Pour que le décryptage soit possible, deux lettres différentes ne doivent jamais donner la même lettre cryptée. On admet que c'est le cas si et seulement si a est un entier impair de [1..25], différent de 13. L'entier b est choisi dans [0..25].
Une lettre cryptée de rang Y se décrypte en la lettre de rang X donné par :
où a' est l'inverse de a modulo 26, c'est-à-dire l'unique entier de [1..25] tel que (a × a') Mod 26 = 1. Par exemple, pour a = 7, on a a' = 15.
On se propose d'écrire un programme qui :
- saisit une clé (a, b) valide ;
- crée, dans le dossier D:\Secret, le fichier texte "Crypte.txt" dont chaque ligne est le cryptage de la ligne de même rang du fichier "Clair.txt" ;
- affiche ensuite le décryptage de chaque ligne de "Crypte.txt", afin de vérifier qu'on retrouve le contenu du fichier "Clair.txt".
Travail demandé :
- Dans cette question, la clé est a = 7 et b = 3.
- Crypter à la main le mot "CODE" en donnant, pour chaque lettre, les valeurs de X et de Y.
- Crypter à la main le mot "ZERO".
- Vérifier, à l'aide de la formule de décryptage, que la lettre cryptée "R" redonne la lettre "C".
- On choisit la clé a = 13 et b = 3. Crypter les lettres "A" et "C", puis expliquer pourquoi cette clé est refusée.
- Écrire l'algorithme du programme principal, solution à ce problème, en le décomposant en modules, et dresser le tableau de déclaration des objets globaux.
- Écrire l'algorithme d'une procédure Saisir(a, b) qui saisit une clé valide.
- Écrire l'algorithme d'une fonction CrypterLigne(ligne, a, b) qui retourne le cryptage d'une ligne du fichier "Clair.txt".
- Écrire l'algorithme d'une procédure Codage(ch1, ch2, a, b) qui lit le fichier dont le chemin est ch1 ligne par ligne et écrit chaque ligne cryptée dans le fichier dont le chemin est ch2.
- Écrire l'algorithme d'une fonction DecrypterLigne(ligne, a, b) qui retourne le décryptage d'une ligne du fichier "Crypte.txt".
- Écrire l'algorithme d'une procédure Verifier(ch2, a, b) qui affiche le décryptage de chaque ligne du fichier dont le chemin est ch2.
- Le fichier "Clair.txt" contient les deux lignes
BAC INFOetLE CODE SECRET. Donner le contenu du fichier "Crypte.txt" obtenu avec la clé a = 7 et b = 3.
NB : le candidat n'est pas appelé à remplir le fichier "Clair.txt". On dispose de la fonction Inverse(a), qui retourne l'inverse a' de a modulo 26 ; le candidat peut l'utiliser sans la développer. Les tableaux de déclaration des objets locaux accompagnent chaque module.
Voir la correction commentéeAprès avoir posé votre démarche
1.a Idée : on applique les trois étapes lettre par lettre ; seul le reste de la division par 26 demande de l'attention.
| Lettre | X | 7X + 3 | Y | Lettre cryptée |
|---|---|---|---|---|
| "C" | 2 | 17 | 17 | "R" |
| "O" | 14 | 101 | 23 | "X" |
| "D" | 3 | 24 | 24 | "Y" |
| "E" | 4 | 31 | 5 | "F" |
Le mot "CODE" devient .
1.b Même calcul. Pour "Z", 7 × 25 + 3 = 178 et 178 = 6 × 26 + 22 : le reste 22 ramène au début de l'alphabet, c'est la lettre "W".
| Lettre | X | 7X + 3 | Y | Lettre cryptée |
|---|---|---|---|---|
| "Z" | 25 | 178 | 22 | "W" |
| "E" | 4 | 31 | 5 | "F" |
| "R" | 17 | 122 | 18 | "S" |
| "O" | 14 | 101 | 23 | "X" |
Le mot "ZERO" devient .
1.c "R" a le rang Y = 17 et a' = 15 (en effet 7 × 15 = 105 = 4 × 26 + 1). On calcule 15 × (17 − 3 + 26) = 15 × 40 = 600, et 600 = 23 × 26 + 2 : X = 2, c'est bien la lettre "C".
2. Avec a = 13 et b = 3 : "A" donne 13 × 0 + 3 = 3, soit "D" ; "C" donne 13 × 2 + 3 = 29, et 29 Mod 26 = 3, soit encore "D". Deux lettres différentes ont la même lettre cryptée : en lisant "D", on ne peut pas savoir s'il faut revenir à "A" ou à "C". Le décryptage est impossible, d'où le refus de cette clé (13 × X Mod 26 ne prend que les valeurs 0 et 13).
3. Idée : un module par tâche de l'énoncé — saisir la clé, crypter le fichier, vérifier. Les deux fonctions sur une ligne sont appelées à l'intérieur de Codage et de Verifier.
Algorithme Cryptage_affine
DEBUT
Saisir (a, b)
Codage ("D:\Secret\Clair.txt", "D:\Secret\Crypte.txt", a, b)
Verifier ("D:\Secret\Crypte.txt", a, b)
FIN| Objet | Type / Nature | Rôle |
|---|---|---|
| a, b | Entier | Clé de cryptage |
| Saisir | Procédure | Saisir une clé valide |
| Codage | Procédure | Créer "Crypte.txt" à partir de "Clair.txt" |
| Verifier | Procédure | Afficher le décryptage de "Crypte.txt" |
4. Idée : la condition de l'énoncé se recopie telle quelle dans le Jusqu'à : a impair, entre 1 et 25, différent de 13 ; b entre 0 et 25.
Procédure Saisir (@ a, @ b : Entier)
DEBUT
Répéter
Ecrire ("a = ")
Lire (a)
Jusqu'à (a ≥ 1) Et (a ≤ 25) Et (a Mod 2 = 1) Et (a ≠ 13)
Répéter
Ecrire ("b = ")
Lire (b)
Jusqu'à (b ≥ 0) Et (b ≤ 25)
FINa et b sont tous deux passés par adresse : chacun porte son propre @ (écrire « @ a, b » passerait b par valeur, et la valeur saisie serait perdue au retour).
5. Idée : un seul parcours de la ligne. Un espace est recopié ; une lettre passe par les trois étapes : Ord pour le rang, le calcul de Y, Chr pour revenir à une lettre.
Fonction CrypterLigne (ligne : Chaîne, a, b : Entier) : Chaîne
DEBUT
res ← ""
Pour i de 0 à Long (ligne) - 1 Faire
Si ligne[i] = " " Alors
res ← res + " "
Sinon
x ← Ord (ligne[i]) - Ord ("A")
y ← (a * x + b) Mod 26
res ← res + Chr (y + Ord ("A"))
Fin Si
Fin Pour
Retourner res
FIN| Objet | Type / Nature | Rôle |
|---|---|---|
| res | Chaîne | Ligne cryptée en construction |
| i | Entier | Indice du caractère traité |
| x, y | Entier | Rang de la lettre, rang de la lettre cryptée |
6. Idée : c'est le parcours standard d'un fichier texte ; la transformation est déléguée à CrypterLigne. Le fichier source s'ouvre en lecture ("r"), le fichier résultat en création ("w").
Procédure Codage (ch1, ch2 : Chaîne, a, b : Entier)
DEBUT
Ouvrir (ch1, Fc, "r")
Ouvrir (ch2, Fk, "w")
Tant que Non (Fin_fichier (Fc)) Faire
Lire_ligne (Fc, ligne)
Ecrire_nl (Fk, CrypterLigne (ligne, a, b))
Fin Tant que
Fermer (Fc)
Fermer (Fk)
FIN| Objet | Type / Nature | Rôle |
|---|---|---|
| Fc, Fk | Fichier texte | Fichiers "Clair.txt" et "Crypte.txt" |
| ligne | Chaîne | Ligne lue dans "Clair.txt" |
| CrypterLigne | Fonction | Crypter une ligne |
Ecrire_nl termine chaque ligne écrite : "Crypte.txt" a autant de lignes que "Clair.txt", dans le même ordre.
7. Idée : même parcours que CrypterLigne, avec la formule inverse. On ajoute 26 avant de réduire : y − b est compris entre −25 et 25, donc y − b + 26 est positif et le reste Mod 26 est bien celui attendu.
Fonction DecrypterLigne (ligne : Chaîne, a, b : Entier) : Chaîne
DEBUT
inv ← Inverse (a)
res ← ""
Pour i de 0 à Long (ligne) - 1 Faire
Si ligne[i] = " " Alors
res ← res + " "
Sinon
y ← Ord (ligne[i]) - Ord ("A")
x ← (inv * (y - b + 26)) Mod 26
res ← res + Chr (x + Ord ("A"))
Fin Si
Fin Pour
Retourner res
FIN| Objet | Type / Nature | Rôle |
|---|---|---|
| inv | Entier | Inverse de a modulo 26 |
| res | Chaîne | Ligne décryptée en construction |
| i | Entier | Indice du caractère traité |
| x, y | Entier | Rang de la lettre claire, rang de la lettre cryptée |
| Inverse | Fonction | Fonction disponible (inverse modulo 26) |
Inverse(a) est appelée une seule fois, avant la boucle, et non pour chaque lettre.
8. Idée : "Crypte.txt" a été fermé à la fin de Codage ; on le rouvre en lecture et on affiche, ligne par ligne, le résultat de DecrypterLigne.
Procédure Verifier (ch2 : Chaîne, a, b : Entier)
DEBUT
Ouvrir (ch2, Fk, "r")
Tant que Non (Fin_fichier (Fk)) Faire
Lire_ligne (Fk, ligne)
Ecrire (DecrypterLigne (ligne, a, b))
Fin Tant que
Fermer (Fk)
FIN| Objet | Type / Nature | Rôle |
|---|---|---|
| Fk | Fichier texte | Fichier "Crypte.txt" |
| ligne | Chaîne | Ligne lue dans "Crypte.txt" |
| DecrypterLigne | Fonction | Décrypter une ligne |
9. Les espaces restent en place et les mots "BAC" et "CODE" donnent "KDR" et "RXYF", comme à l'exemple et à la question 1.a :
KDR HQMX
CF RXYF ZFRSFGVerifier affiche alors BAC INFO puis LE CODE SECRET : on retrouve bien le contenu de "Clair.txt".