Exercices
Exercice 1
Utilisation des bibliothèques cryptographiques du module sympy.
Documentation : https://docs.sympy.org/latest/modules/crypto.html
Décoder la phrase RYTVJKGCLJWRTZCVRMVTLEDFULCVHLZWRZKKFLKRMFKIVGCRTV, sachant qu'elle a été chiffrée par décalage (shift en anglais...)
Correction
1 2 3 4 5 6 7 | |
Exercice 2
Chiffrage affine
Principe du chiffrage affine :
- Chaque lettre est codée par son rang, en commençant à 0 (A->0, B->1, ..., Z->25)
- On applique à chaque rang la transformation affine \(f(x) = (ax+b)\, \%26\)
où \(a\) et \(b\) sont deux nombres entiers. Attention, \(a\) doit être premier avec 26.
Rappel sur les nombres premiers entre eux
Deux nombres sont dits premiers entre eux si leur PGCD vaut 1.
Exemples :
- 8 et 15 sont premiers entre eux (ils n'ont aucun diviseur commun autre que 1)
- 8 et 12 ne sont pas premiers entre eux (leur PGCD vaut 4).
Q1. Codez votre fonction affine(msg, a, b).
Pour tester votre fonction :
>>> affine("BONJOUR", 3, 5)
'IVSGVNE'
Correction
1 2 3 4 5 6 7 8 9 10 11 | |
Q2. Comparez vos résultats avec ceux obtenus par la fonction encipher_affine() de sympy.
Q3. Décodez la phrase UCGXLODCMOXPMFMSRJCFQOGTCRSUSXC, sachant qu'elle contient le mot TRAVAIL et que \(a\) et \(b\) sont inférieurs à 20.
Aide
L'instruction gcd du module math permet de calculer le PGCD de deux nombres.
Correction
1 2 3 4 5 6 7 8 9 | |
Exercice 3
Exercice 3 (Parties A et B) du sujet Métropole J2 2025
Partie A
alphabet = ['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']
Correction Q1
On obtient le mot PGRDX.
Correction Q2
def indice(L, element):
for i in range(len(L)):
if L[i] == element:
return i
Correction Q3
def lettres_vers_indices(txt):
lst = []
for c in txt:
lst.append(indice(alphabet,c))
return lst
def indices_vers_lettres(lst):
s = ''
for c in lst:
s += alphabet[c]
return s
def chiffrement(msg, cle):
assert len(cle) >= len(msg), 'impossible'
indices_msg = lettres_vers_indices(msg)
indices_cle = lettres_vers_indices(cle)
n = len(msg)
indices_msg_chiffre = []
for k in range(n):
ind = ...
if ind >= 26:
ind = ...
indices_msg_chiffre.append(ind)
msg_chiffre = indices_vers_lettres(...)
return msg_chiffre
Correction Q4
def chiffrement(msg, cle):
assert len(cle) >= len(msg), 'impossible'
indices_msg = lettres_vers_indices(msg)
indices_cle = lettres_vers_indices(cle)
n = len(msg)
indices_msg_chiffre = []
for k in range(n):
ind = indices_msg[k] + indices_cle[k]
if ind >= 26:
ind = ind - 26
indices_msg_chiffre.append(ind)
msg_chiffre = indices_vers_lettres(indices_msg_chiffre)
return msg_chiffre
Correction Q5
On obtient AssertionError 'impossible' car la longueur de la clé est inférieure à la longueur du message.
Correction Q6
On obtient le mot BRAVO.
Correction Q7
Pour chaque caractère du message chiffré, on effectue la soustraction entre sa position dans l’alphabet et la position du caractère associé dans le masque. Si la valeur obtenue est strictement négative, on ajoute 26. On obtient finalement la position du caractère en clair dans l’alphabet.
Correction Q8
def dechiffrement(msg, cle):
assert len(cle) >= len(msg), 'impossible'
indices_msg = lettres_vers_indices(msg)
indices_cle = lettres_vers_indices(cle)
n = len(msg)
indices_msg_dechiffre = []
for k in range(n):
ind = indices_msg[k] - indices_cle[k]
if ind < 0:
ind = ind + 26
indices_msg_dechiffre.append(ind)
msg_dechiffre = indices_vers_lettres(indices_msg_dechiffre)
return msg_dechiffre
Partie B
Correction Q9
Avec un chiffrement symétrique, la connaissance d'une seule et unique clé est requise pour chiffrer et déchiffrer le message. Dans un chiffrement asymétrique, la clé de déchiffrement est connue seulement du destinataire, alors que la clé de chiffrement est publique et distribuée à tous.
Correction Q10
Il suffit à Bob de déchiffer le message avec sa clé privée.
Correction Q11
Tout le monde a la clé publique de Bob, donc tout le monde peut écrire en se faisant passer pour Alice.
Correction Q12
Dans le protocole https, une clé AES est générée par chiffrement asymétrique au tout début de la communication (TLS). Ensuite, le reste du flux est chiffré avec le chiffrement symétrique AES.
Correction Q13
Utiliser un chiffrement asymétrique tout au long de la navigation ralentirait considérablement le trafic car un chiffrement asymétrique consomme beaucoup de ressources de calcul, contrairement au chiffrement symétrique.
Exercice 4
Cryptographie RSA presque à la main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
- Pour générer un grand nombre premier de taille
bits, on utilise la fonctionCrypto.Util.number.getPrime(bits, randfunc=get_random_bytes). - Pour inverser un nombre \(x\) modulo \(n\), on utilise la fonction
pow(x, -1, n). - Pour calculer
aà la puissancebmodulon, on utilisepow(a, b, n).
Correction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Exercice 5
En vous servant du code précédent, déchiffrez le message 58152918114477529438769495136495430966050302170947748011925859233600631318929939319619808279389222131229963717435870597641010567365311762267359794338657867540621133550787677728203831932548041236152866441194127191404729294628415184239755221703677388875259927092794165578604353985011899152968982365630138088486380827379488939561996226754182 sachant que :
- \(e\) vaut 65537.
- \(p\) et \(q\) sont respectivement les 13èmes et 14èmes nombres de Mersenne.
Correction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Exercice 6
module RSA dans les règles de l'art
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import binascii
keyPair = RSA.generate(1024)
pubKey = keyPair.publickey()
pubKeyPEM = pubKey.exportKey()
privKeyPEM = keyPair.exportKey()
msg = b'vive la crypto en NSI !'
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(msg)
print("Encrypted:", binascii.hexlify(encrypted))
decryptor = PKCS1_OAEP.new(keyPair)
decrypted = decryptor.decrypt(encrypted)
print('Decrypted:', decrypted)
Exercice 7
Exercice 3 du sujet Polynésie J1 2025
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Correction Q1
gen_mdp(8, True, True, False)
Correction Q2
8 9 10 | |
Correction Q3
12 13 14 15 16 17 | |
Correction Q4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Correction Q5
Comme on utilise une fonction aléatoire, rien ne garantit qu'on aura un caractère spécial ou une lettre minuscule.
Correction Q6
Le principe d'une clé primaire est de référence de manière unique chaque enregistrement. Si l'attribut mot_de_passe est déclaré clé primaire de la table compte, il est alors impossible d'avoir le même mot de passe pour deux sites différents.
Correction Q7
SELECT url
FROM site
Correction Q8
UPDATE compte
SET mot_de_passe = '@rDfohpj!&'
WHERE mot_de_passe = 'yhTS?d@UTJe'
Correction Q9
SELECT id_site
FROM compte
WHERE renouvellement < '2024-03-20'
Correction Q10
Ce format de date permet de faire des comparaisons entre les dates, puisqu'on commence par l'année, puis le mois, puis le jour.
Avec le format JJ-MM-AAAA, le fait de commencer par le jour rend la date '01-02-2023' inférieure à la date '13-06-2022', ce qui est illogique.
Correction Q11
SELECT compte.mot_de_passe, compte.utilisateur
FROM compte
JOIN site ON site.id = compte.id_site
WHERE site.nom_site = 'Votremailp'
ORDER BY compte.renouvellement
Correction Q12
Utiliser deux tables permet à Alice de ne pas mélanger les informations : une table pour la gestion de ses mots de passe, une table pour les sites.
Correction Q13
chiffrement('gestionnaire.db', '../Perso/secret.db', '../Perso/cle')
Correction Q14
A3correspond au nombre décimal 163, donc au nombre binaire10100011.59correspond au nombre décimal 89, donc au nombre binaire1011001.- L'opération XOR entre les nombres binaires
10100011et1011001donne 250, qui s'écritFAen hexadécimal.
Correction Q15
a |
b |
a XOR b |
(a XOR b) XOR b |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 |
| 1 | 1 | 0 | 1 |
La colonne (a XOR b) XOR b est identique la colonne a.
Correction Q16
L'opération XOR permet de chiffrer et de déchiffrer avec la même clé, ce qui est caractéristique d'un chiffrement symétrique.
Correction Q17
Le fichier secret.db étant directement accessible en lecture pour tout le monde, il est donc à la merci d'un attaquant. Alice devrait restreindre les droits en lecture de son fichier pour ne le rendre lisible que par elle-même.
Correction Q18
- Alice a des mots de passe différents pour chaque site, elle respecte donc la recommandation P1.
- Ses mots de passe sont bien de longueur minimale 8 et contiennent des minuscules, des majuscules, des chiffres et des caractères spéciaux. Elle respecte donc la recommandation P2.
- On ne sait pas si Alice communique ou non ses mots de passe à des tiers. On ne peut donc rien dire sur la recommandation P3.
- Alice n'utilise pas de gestionnaire de mots de passe : elle ne respecte donc pas la recommandation P4.
Exercice 8
Exercice 3 du sujet Métropole J2 2025
Correction Q1
Prenons comme exemple la deuxième lettre, I. Son rang est 8. La lettre du masque qui lui correspond est Y, qui est de rang 24.
\(8+24=32=6\%26\)
On prend donc la lettre de rang 6, qui est G.
Si on fait de même pour les autres lettres, on trouve PGRDX.
Correction Q2
def indice(L, element):
for i in range(len(L)):
if L[i] == element:
return i
def indice(L, element):
return L.index(element)
Correction Q3
def lettres_vers_indices(chaine):
lst = []
for car in chaine:
lst.append(indice(alphabet, car))
return lst
alphabet = ['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']
def indices_vers_lettres(lst):
s = ''
for k in lst:
s += alphabet[k]
return s
def chiffrement(msg, cle):
assert len(cle) >= len(msg), 'impossible'
indices_msg = lettres_vers_indices(msg)
indices_cle = lettres_vers_indices(cle)
n = len(msg)
indices_msg_chiffre = []
for k in range(n):
ind = ...
if ind >= 26:
ind = ...
indices_msg_chiffre.append(ind)
msg_chiffre = indices_vers_lettres(...)
return msg_chiffre
Correction Q4
def chiffrement(msg, cle):
assert len(cle) >= len(msg), 'impossible'
indices_msg = lettres_vers_indices(msg)
indices_cle = lettres_vers_indices(cle)
n = len(msg)
indices_msg_chiffre = []
for k in range(n):
ind = indices_msg[k] + indices_cle[k]
if ind >= 26:
ind = ind % 26
indices_msg_chiffre.append(ind)
msg_chiffre = indices_vers_lettres(indices_msg_chiffre)
return msg_chiffre
Correction Q5
La longueur de la clé est plus petite que le message à chiffrer, donc la fonction va s'arrêter au premier assert et renvoyer impossible.
Correction Q6
On obtient le message BRAVO.
Correction Q7
Prenons par exemple l'avant-dernière lettre du message chiffré, D. Elle a été chiffrée avec la lettre I.
D a pour rang 3, I a pour rang 8. On fait 3 - 8, qui donne -5. On ajoute 26 pour finalement trouver 21. La lettre de rang 21 est la lettre V.
Correction Q8
def dechiffrement(msg, cle):
assert len(cle) >= len(msg), 'impossible'
indices_msg = lettres_vers_indices(msg)
indices_cle = lettres_vers_indices(cle)
n = len(msg)
indices_msg_chiffre = []
for k in range(n):
ind = indices_msg[k] - indices_cle[k]
if ind < 0:
ind = ind + 26
indices_msg_dechiffre.append(ind)
msg_dechiffre = indices_vers_lettres(indices_msg_dechiffre)
return msg_dechiffre
Correction Q9
Dans un chiffrement symétrique, c'est la même clé qui sert à chiffrer et à déchiffrer.
Dans un chiffrement asymétrique, il y a 2 clés, une clé publique et une clé privée. Si Bob veut communiquer avec Alice, il va chiffrer son message avec la clé publique d'Alice. Seule Alice pourra le déchiffrer à l'aide de sa clé privée.
Correction Q10
Il suffit à Bob d'appliquer sa clé privée sur le message envoyé par Alice.
Correction Q11
Comme tout le monde connaît la clé publique de Bob, rien ne garantit qu'Alice est l'expéditrice du message.
Correction Q12
Le protocole HTTPS fonctionne en 2 temps.
Dans un premier temps, le client et le serveur vont échanger une clé en utilisant un chiffrement asymétrique (souvent RSA).
Dans un second temps, ils vont communiquer en chiffrement symétrique (souvent AES) avec la clé échangée au préalable.
Correction Q13
Le chiffrement asymétrique demande beaucoup de ressources, il n'est donc pas adapté aux échanges rapides.
Correction Q14
Marc s'est trompé dans le troisième octet de l'adresse IP. Il aurait dû écrire ping 192.168.110.115.
Correction Q15
Le masque en binaire 11111111.11111111.11111111.11100000 a pour représentation décimale 255.255.255.224. (on convertit chaque octet en décimal)
Correction Q16
Il y a 5 bits à zéro dans le masque, ce qui donne 32 adresses disponibles. Si on enlève la première (adresse du réseau) et la dernière (adresse de broadcast), il reste 30 adresses disponibles.
Correction Q17
134 s'écrit 10000110 en binaire.
Correction Q18
L'adresse IP 192.168.110.134 donne une adresse de réseau de 192.168.110.128.
L'adresse IP 192.168.110.115 (commande n°1) donne une adresse de réseau de 192.168.110.96.
L'adresse IP 192.168.110.153 (commande n°2) donne une adresse de réseau de 192.168.110.128.
Seule le ping de la commande n°2 peut donc aboutir.