Académique Documents
Professionnel Documents
Culture Documents
TD2
Exercice 1
Pour chirer un message, le chirement de Vernam (ou méthode du masque jetable), consiste à
combiner le message avec une chaîne de caractères de longueur comparable.
Une implémentation possible utilise l'opérateur XOR (ou exclusif) dont voici la table de vérité :
a b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0
Dans la suite, les nombres écrits en binaire seront précédés du préxe 0b.
1. Pour chirer un message, on convertit chacun de ses caractères en binaire (à l'aide du format
Unicode), et on réalise l'opération XOR bit à bit avec la clé.
Après conversion en binaire, et avant que l'opération XOR bit à bit avec la clé n'ait été
eectuée, Alice obtient le message suivant :
m = 0b 0110 0011 0100 0110
(a) Le message m correspond à deux caractères codés chacun sur 8 bits : déterminer quels
sont ces caractères. On fournit pour cela la table ci-dessous qui associe à l'écriture hexadé-
cimale d'un octet le caractère correspondant (gure 2). Exemple de lecture : le caractère
correspondant à l'octet codé 4A en hexadécimal est la lettre J.
gure 2
Solution:
(b) Pour chirer le message d'Alice, on réalise l'opération XOR bit à bit avec la clé suivante :
k = 0b 1110 1110 1111 0000
Donner l'écriture binaire du message obtenu.
Solution:
m 0 1 1 0 0 0 1 1 0 1 0 0 0 1 1 0
k 1 1 1 0 1 1 1 0 1 1 1 1 0 0 0 0
m XOR k 1 0 0 0 1 1 0 1 1 0 1 1 0 1 1 0
Solution:
(b) Bob connaît la chaîne de caractères utilisée par Alice pour chirer le message. Quelle
opération doit-il réaliser pour déchirer son message ?
Solution:
D'après la question précédente : (m XOR k) XOR k = m
Bob doit donc réaliser un XOR entre le message reçu (m XOR k) et la clé k pour obtenir
le message initial m.
Exercice 2
Écrire en Python une fonction une fonction chiffre_xor(msg, cle) qui prend en arguments deux
chaînes d'octets (de type bytes) et qui renvoie le chirement XOR du message avec la clé, sous
forme d'une chaîne d'octets.
Indications :
Page 2
L'opérateur XOR est noté en Python.
Il est possible de créer une chaîne d'octets en utilisant le constructeur bytes et en lui donnant
en argument une liste d'entiers, chacun compris entre 0 et 255. Informations sur le type bytes
Pour tester, appliquez la méthode encode() sur les string pour les coder en UTF-8.
Solution:
# test
m = "L'INFORMATIQUE C'EST SUPER".encode()
c = "NSI".encode()
s = chiffre_xor(m,c)
print(s)
print(chiffre_xor(s,c))
Exercice 3
Lorsque la longueur de la clé est inférieure à celle du message à chirer, on recopie plusieurs fois
la clé de façon à obtenir une chaîne de même longueur que le message.
Nous allons voir qu'une clé trop courte peut compromettre la sécurité de la communication.
Dans cet exercice, on va montrer qu'en connaissant quelques informations on peut facilement re-
trouver la clé si cette dernière est trop courte.
Solution:
Page 3
import time
secret = b'\x0e6/+y;.< x-(7,,\x9b\xf0z48z:646<z*\x9a\xf3(64+<{'
def force():
cA = ord('A')
cZ1 = ord('Z')+1
for c1 in range(cA, cZ1):
for c2 in range(cA, cZ1):
for c3 in range(cA, cZ1):
cle = bytes([c1,c2,c3])
test = chiffre_xor(secret,cle)
if test.endswith(b"nse!"):
return (cle, test)
# test
t1 = time.time()
res = force()
t2 = time.time()
if res is None:
print("Je n'ai pas trouvé la clé")
else:
print("Clé:", res[0])
print("Message décrypté:", res[1])
print("Temps de calcul:", t2-t1, "secondes")
Sur une machine relativement récente, énumérer de cette façon toutes les clés entre AAA, AAB,
. . ., XYZ (qui est la clé) prend moins d'une seconde.
Le message en clair est la chaîne d'octets :
b'Vous avez trouv\xc3\xa9 la bonne r\xc3\xa9ponse!'
La séquence d'octets \xc3\xa9 correspond au caractère é en UTF-8.
Exemple :
Page 4
P1
# Un exemple bitmap de la lettre "J"
7 10
0 0 0 0 0 0 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 1 0 0 0 1 0
0 0 1 1 1 0 0
0 0 0 0 0 0 0
Un chier est enregistré avec l'extension .pbm. Pour visualiser l'image, il sut de l'ouvrir avec un
logiciel comme XnView ou GIMP.
Une image est représentée par une matrice, i.e. une liste de listes en Python. Pour l'exemple
ci-dessus, on obtient : [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0], ..., 0, 0, 1, 1,
1, 0, 0], 0, 0, 0, 0, 0, 0, 0]]
m1 = matrice(240, 180)
1. Écrire une fonction fichier qui prend en paramètres une matrice comme celle dénie ci-
dessus, et une chaîne de caractères représentant le nom d'un chier, sans l'extension.
La fonction fichier crée le chier image, avec l'extension pbm, et y écrit les lignes dénissant
l'image avec les valeurs données par la matrice.
Vérier que l'instruction fichier(m1, "image1") crée un chier image1.pbm et visualiser
l'image avec par exemple le logiciel XnView ou GIMP.
Vous devez obtenir l'image suivante :
Page 5
Solution: La fonction fichier.
def fichier(mat, nom):
hauteur = len(mat)
largeur = len(mat[0])
nom = nom + '.pbm'
f = open(nom, 'w')
f.write('P1\n' + str(largeur) + ' ' + str(hauteur) + '\n')
for i in range(hauteur):
for j in range(largeur):
bit = str(mat[i][j])
f.write(bit + ' ')
f.close()
fichier(m1, "image1")
2. Écrire une fonction hasard qui prend en paramètres les dimensions d'une image n (la hauteur)
et p (la largeur), et renvoie une matrice représentant une image aléatoire. Chaque pixel vaut
0 ou 1 de manière équiprobable.
Créer une image aléatoire avec les dimensions que l'image image1.pbm. Nommer cette image
alea.pbm et visualiser la.
a = hasard(240, 180)
fichier(a, "alea")
Page 6
On obtient une image aléatoire comme celle-ci :
3. Écrire une fonction chiffre pour chirer l'image image1.pbm. La fonction prend en para-
mètres une image à chirer et une image clé sous la forme de matrices de mêmes dimensions.
Elle crée une nouvelle image de même dimension. Pour déterminer chaque bit de l'image, on
utilise l'opérateur ou exclusif entre les bits de l'image à chirée et ceux de l'image clé.
L'image clé s'appelle un masque.
Tester la fonction chiffre avec l'image image1.pbm et l'image clé alea.pbm. Visualiser le
résultat.
c = chiffre(m1,a)
fichier(c, "image_chiffree")
Page 7
Il s'agit d'un chirement symétrique. Pour déchirer le résultat, on utilise la clé de chif-
frement avec le même programme et on écrit simplement :
d = chiffre(c, a)
fichier(d,"image_dechiffree")
On obtient une image identique à l'image initiale. On peut vérier que le contenu des
deux chiers image1.pbm et image_dechiffree.pbm est exactement le même.
Solution:
On reprend la fonction chiffre qui sert aussi à déchirer et on remplace l'opérateur ou
exclusif par l'opérateur ou.
dv = devoile(c, a)
fichier(dv, "image_devoilee")
On obtient une image dite dévoilée . Elle laisse apparaître l'image déchirée.
Page 8
Pour travailler avec des images plus motivantes, on peut utiliser une image de son choix au
format jpeg ou png et la convertir au format pbm. Après le chirement on reconvertit l'image
chirée en jpeg ou png.
Pour les images en niveau de gris ou en couleur, les formats avec les mêmes principes que le
pbm sont les formats pgm et ppm. Ces trois formats (P1, P2, P3) utilise le codage ASCII.
Avec un codage brut sous forme d'octets on obtient les formats similaires (P4, P5 et P6),
moins gourmands en taille de stockage.
Page 9