TP - Chiffrement et Déchiffrement
TP – Chiffrement et Déchiffrement
BTS SIO 1ère année · Bloc B3 : Cybersécurité
Introduction
Contraintes du TP
- Des lettres majuscules (A à Z)
- Sans accents ni caractères spéciaux
- Une chaîne de caractères
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - L'opérateur
%26pour revenir au début de l'alphabet
Rappels utiles
- Longueur d'une chaîne :
len("BONJOUR")→ 7 - Accès à un caractère :
"BONJOUR"[0]→ 'B' - Position d'un caractère :
"BONJOUR".index('N')→ 2 - L'opérateur
%permet de faire des calculs circulaires
L'opérateur modulo % retourne le reste de la division. Il est très utile pour revenir au début d'une séquence :
# Exemples avec %26 pour l'alphabet
25 % 26 = 25 # Z reste Z
26 % 26 = 0 # Retour à A
27 % 26 = 1 # Retour à B
30 % 26 = 4 # Retour à E
# Avec des nombres négatifs (pour le déchiffrement)
-1 % 26 = 25 # Avant A, c'est Z
-2 % 26 = 24 # Avant A de 2, c'est Y
Partie 1 : Chiffrement de César
Principe
Le chiffre de César consiste à décaler chaque lettre de l'alphabet d'un nombre fixe de positions (la clé).
- A → D
- B → E
- Z → C (retour au début grâce à %26)
Exemple
Message : BONJOUR
Clé : 3
Chiffré : ERQMRXU
Exercice 1.1 · Fonction indice_dans_alphabet
Écrire une fonction qui prend une lettre majuscule, retourne son indice dans ALPHABET, et -1 si ce n'est pas une lettre.
ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
print(indice_dans_alphabet('A')) # Attendu : 0
print(indice_dans_alphabet('Z')) # Attendu : 25
print(indice_dans_alphabet('M')) # Attendu : 12
print(indice_dans_alphabet(' ')) # Attendu : -1
Exercice 1.2 · Chiffrement d'un caractère
Écrire chiffrer_caractere_cesar(caractere, cle). Formule : (indice_actuel + cle) % 26.
print(chiffrer_caractere_cesar('A', 3)) # D
print(chiffrer_caractere_cesar('Z', 3)) # C
print(chiffrer_caractere_cesar('X', 5)) # C
print(chiffrer_caractere_cesar(' ', 3)) # ' '
Exercice 1.3 · Message complet
Écrire chiffrer_cesar(message, cle) en utilisant la fonction précédente.
print(chiffrer_cesar("BONJOUR", 3)) # ERQMRXU
print(chiffrer_cesar("HELLO WORLD", 5)) # MJQQT BTWQI
print(chiffrer_cesar("ABC XYZ", 1)) # BCD YZA
Exercice 1.4 · Déchiffrement
Pour déchiffrer, soustraire la clé : (indice_actuel - cle) % 26.
message = "BONJOUR"
chiffre = chiffrer_cesar(message, 3)
print(chiffre) # ERQMRXU
dechiffre = dechiffrer_cesar(chiffre, 3)
print(dechiffre) # BONJOUR
Exercice 1.5 · Cassage par force brute
Tester toutes les clés (0 à 25) et afficher chaque résultat avec la clé.
Cle 0 : ERQMRXU
Cle 1 : DQPLQWT
Cle 2 : CPOKPVS
Cle 3 : BONJOUR
Cle 4 : ANMINNT
...
casser_cesar("ERQMRXU")
# Identifier visuellement que la clé 3 donne BONJOUR
Partie 2 : Chiffrement de Vigenère
Principe
Le chiffre de Vigenère utilise une clé composée de lettres. Chaque lettre de la clé détermine le décalage de la lettre correspondante du message. La clé se répète si nécessaire.
Message : BONJOUR (indices: 1,14,13,9,14,20,17)
Clé : CLE (indices: 2,11,4 répétés)
Calcul : (1+2)%26=3→D, (14+11)%26=25→Z, (13+4)%26=17→R,
(9+2)%26=11→L, (14+11)%26=25→Z, (20+4)%26=24→Y,
(17+2)%26=19→T
Résultat : DZRLZYT
Exercice 2.1 · Conversion lettre → décalage
Écrire lettre_vers_decalage(lettre) en utilisant indice_dans_alphabet().
print(lettre_vers_decalage('A')) # 0
print(lettre_vers_decalage('C')) # 2
print(lettre_vers_decalage('Z')) # 25
Exercice 2.2 · Chiffrement de Vigenère
Écrire chiffrer_vigenere(message, cle). Ignorer les caractères non alphabétiques, répéter la clé, et calculer (indice_lettre + decalage) % 26.
print(chiffrer_vigenere("BONJOUR", "CLE")) # DZRLZYT
print(chiffrer_vigenere("HELLO WORLD", "KEY")) # RIJVS UYVJN
print(chiffrer_vigenere("AAA", "BCD")) # BDF
function chiffrer_vigenere(message, clef)
"" -> res
0 -> indice_clef
pour chaque lettre dans message
indice de la lettre dans l'alphabet -> indice_lettre
si indice == -1
res += lettre
sinon
indice_dans_clef = indice_dans_alphabet(clef[indice_clef], ALPHABET)
indice_dans_mot = indice_dans_alphabet(lettre, ALPHABET)
res += ALPHABET[(indice_dans_mot + indice_dans_clef) % 26]
indice_clef = (indice_clef + 1) % len(clef)
renvoyer res
Partie 3 : Chiffrement RSA
Principe
Le chiffrement RSA est un algorithme de chiffrement asymétrique. Il utilise deux clés différentes.
- Clé publique pour chiffrer (peut être partagée)
- Clé privée pour déchiffrer (doit rester secrète)
RSA repose sur des opérations mathématiques avec de grands nombres premiers.
Concepts mathématiques de base
Les nombres premiers : Un nombre premier n'est divisible que par 1 et par lui-même.
Algorithme RSA simplifié
- Choisir deux nombres premiers p et q
- Calculer n = p × q
- Calculer φ(n) = (p - 1) × (q - 1)
- Choisir e tel que 1 < e < φ(n) et e est premier avec φ(n)
- Calculer d tel que (d × e) % φ(n) = 1
Clé publique : (e, n)
Clé privée : (d, n)
Chiffrement d'un nombre m : c = (m^e) % n
Déchiffrement d'un nombre c : m = (c^d) % n
Exercice 3.1 · Vérifier si un nombre est premier
Écrire une fonction est_premier(n) qui retourne True si le nombre est premier, False sinon.
Algorithme :
- Si n ≤ 1, retourner False
- Si n = 2, retourner True
- Si n est pair, retourner False
- Tester la divisibilité par tous les nombres impairs de 3 à nn
print(est_premier(2)) # Attendu : True
print(est_premier(17)) # Attendu : True
print(est_premier(20)) # Attendu : False
print(est_premier(97)) # Attendu : True
Exercice 3.2 · Calculer le PGCD
Écrire une fonction pgcd(a, b) qui calcule le Plus Grand Commun Diviseur de deux nombres (algorithme d'Euclide).
Algorithme d'Euclide
Tant que b ≠ 0 :
r = a % b
a = b
b = r
Retourner a
print(pgcd(48, 18)) # Attendu : 6
print(pgcd(17, 13)) # Attendu : 1
print(pgcd(100, 50)) # Attendu : 50
Exercice 3.3 · Calculer l'inverse modulaire
Écrire une fonction inverse_modulaire(e, phi) qui retourne d tel que (d × e) % phi = 1, et None si aucun inverse n'existe.
Algorithme (méthode simple)
Pour d allant de 2 à phi :
Si (d * e) % phi == 1 :
Retourner d
Retourner None
print(inverse_modulaire(7, 3120)) # Attendu : 1783
print(inverse_modulaire(17, 3120)) # Attendu : 2753
Exercice 3.4 · Générer les clés RSA
Écrire une fonction generer_cles_rsa(p, q) qui retourne ((e, n), (d, n)).
- Calculer n = p × q
- Calculer phi = (p - 1) × (q - 1)
- Trouver e tel que pgcd(e, phi) = 1
- Calculer d avec
inverse_modulaire(e, phi) - Retourner ((e, n), (d, n))
n <- p * q
phi <- (p-1) * (q-1)
e = 0
pour i allant de 2 à phi
si le pgcg de i et phi vaut 1
e <- i
sortir de la boucle (break)
d <- inverse_modulaire(e,phi)
renvoyer (e,n),(d,n)
cle_pub, cle_priv = generer_cles_rsa(61, 53)
print("Clé publique:", cle_pub) # Exemple : (7, 3233)
print("Clé privée:", cle_priv) # Exemple : (1783, 3233)
Note : Utiliser de petits nombres premiers pour l'exercice. En pratique, RSA utilise des nombres de plusieurs centaines de chiffres.
Exercice 3.5 · Chiffrer un nombre avec RSA
Écrire une fonction chiffrer_nombre_rsa(m, cle_publique) qui calcule (m^e) % n. Utiliser pow(m, e, n).
cle_pub, cle_priv = generer_cles_rsa(61, 53)
message_num = 123
chiffre = chiffrer_nombre_rsa(message_num, cle_pub)
print(f"Message {message_num} chiffré : {chiffre}")
Exercice 3.6 · Déchiffrer un nombre avec RSA
Écrire une fonction dechiffrer_nombre_rsa(c, cle_privee) qui calcule (c^d) % n.
cle_pub, cle_priv = generer_cles_rsa(61, 53)
message_num = 123
chiffre = chiffrer_nombre_rsa(message_num, cle_pub)
dechiffre = dechiffrer_nombre_rsa(chiffre, cle_priv)
print(f"Message déchiffré : {dechiffre}") # Attendu : 123
Exercice 3.7 · Chiffrer un message texte avec RSA
Convertir chaque lettre en indice dans ALPHABET, chiffrer ces indices, puis reconstituer le message.
Fonctions attendues
chiffrer_message_rsa(message, cle_publique)dechiffrer_message_rsa(liste_chiffree, cle_privee)
cle_pub, cle_priv = generer_cles_rsa(61, 53)
message = "HELLO"
liste_chiffree = chiffrer_message_rsa(message, cle_pub)
print("Message chiffré:", liste_chiffree)
message_dechiffre = dechiffrer_message_rsa(liste_chiffree, cle_priv)
print("Message déchiffré:", message_dechiffre) # Attendu : HELLO