La cryptographie est l’ensemble des manières qui permettent de sécuriser des informations.
On peut le faire simplement en python ou utiliser des modules pour chiffrer de manière plus complexe des messages.
Tu vas maintenant pouvoir commencer à expérimenter en commençant par des concepts simples jusqu’à l’utilisation de modules !
On peut utiliser du chiffrage professionnel avec des bibliothèques :
On peut aussi chiffrer des fichiers entiers !
Premier truc un peu enfantin mais qui permet de nous échauffer sur la manipulation de chaines de caractères : inverser l'order des lettres !
On prend chaque lettre du message une à une et on les ajoute à l'envers:
message ="patate" inverse = "" for lettre in message : inverse = lettre + inverse print(inverse)
Pour déchiffrer le message, il suffit de refaire passer le message chiffrer dans le même programme !!
Tu peux maintenant essayer d'inverser un message et le déchiffrer !
Le principe : remplacer chaque lettre par une autre selon un certain décalage. Pour l'exemple suivant, on décale chaque lettre de 3 : A devient D, B devient E, etc, etc...
Pour le faire, on va utiliser le code ASCII.
Le code ASCII (American Standard Code for Information Interchange) est la norme d'encodage informatique des caractères qui associe un nombre à un caractère, par exemple "d" est le caractère numéro 100 :
En python, on peut récupérer le code ascii d'un caractère avec la commande ord()
ord('0') >> 48
Et inversement trouver quel est le caractère numéro 48 avec la commande chr()
chr(48) >> '0'
Pour décaler les lettres de 3 crans, on va:
message_secret = "MESSAGE SUPER SECRET" message_code ="" message_decode ="" ######################### # on chiffre le message # ######################### for lettre in message_secret : # Pour chaque lettre du message nb_lettre = ord(lettre) # On récupère le numéro Ascii de la lettre nb_lettre_code = nb_lettre + 3 # On y ajoute 3 lettre_code = chr(nb_lettre_code) # On reconverti en lettre message_code += lettre_code # On ajoute la nouvelle lettre au message codé print(message_code) ###################################################################### # Pour déchiffrer le message on fait la même chose mais en enlevant 3# ###################################################################### for lettre_code in message_code : # Pour chaque lettre du message codé nb_lettre_code = ord(lettre_code) # On récupère le numéro Ascii de la lettre codée nb_lettre = nb_lettre_code - 3 # On y enlève 3 lettre = chr(nb_lettre) # On reconverti en lettre message_decode += lettre # On ajoute la nouvelle lettre au message decodé print(message_decode)
message_secret = "MESSAGE SUPER SECRET" message_code ="" message_decode ="" ######################### # on chiffre le message # ######################### for lettre in message_secret : # Pour chaque lettre du message nb_lettre = ord(lettre) # On récupère le numéro Ascii de la lettre nb_lettre_code = nb_lettre + 3 # On y ajoute 3 lettre_code = chr(nb_lettre_code) # On reconverti en lettre message_code += lettre_code # On ajoute la nouvelle lettre au message codé print(message_code) ###################################################################### # Pour déchiffrer le message on fait la même chose mais en enlevant 3# ###################################################################### for lettre_code in message_code : # Pour chaque lettre du message codé nb_lettre_code = ord(lettre_code) # On récupère le numéro Ascii de la lettre codée nb_lettre = nb_lettre_code - 3 # On y enlève 3 lettre = chr(nb_lettre) # On reconverti en lettre message_decode += lettre # On ajoute la nouvelle lettre au message decodé print(message_decode)
">Ce code est assez facile à casser maintenant car il suffit de tester les différentes possibilités, mais à l'époque où il était utilisé le temps qu'il fallait pour le casser était trop grand pour être utile (si le message codé a un impact le soir même ou le lendemain il n'y a pas assez de temps pour le casser à la main...)
Si on a un message codé assez grand, on peut essayer de trouver la clé en étudiant la fréquence des lettres (en français, le "e" est la lettre la plus utilisée - fréquence d'apparition : 17.26 % - donc il suffit de trouver la lettre la plus utilisée et faire la différence avec le "e" - code ascii 101 - pour trouver la clé - ou essayer la 2 ème plus présente)
Tu peux maintenant essayer de créer ton propre code de César !
Pour aller plus loin, tu peux utiliser le modulo ( % en python) pour boucler parmi les lettres uniquement !!
On peut aussi convertir notre message en binaire !
Le binaire n'est qu'une manière de compter.
Nous comptons d'habitude en base 10 (car on a 10 doigts) c'est à dire avec 10 chiffres (0 à 9).
En binaire on compte avec 2 chiffres (0 et 1). Compter en binaire donne : 0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, ...
Donc passer notre message en binaire c'est :
les lettres sont stockés sur un octet (8 bits) donc on veut récupérer le code de chaque lettre dans une séquence de 8 "0" et "1".
On utilise la fonction format() pour convertir le nombre en sa représentation binaire (une chaîne de caractères) et on utilise le format "08b" pour l'avoir sur 8 bits.
message = "secretsecret" message_code = "" message_decode = "" ######################### # On chiffre le message # ######################### for lettre in message : # Pour chaque lettre du message a chiffrer nb_lettre = ord(lettre) # On recupere le numero Ascii de la lettre binaire_lettre = format(nb_lettre, '08b') # On recupere la representation binaire de ce nombre message_code += binaire_lettre # On ajoute cette serie de "0" et de "1" au message code message_code +=' ' # On ajoute un espace pour distinguer les lettres # Avec la boucle precedente, on se retrouve avec un espace message_code = message_code[:-1] # apres le message, on va donc le retirer ici # [:-1] permet de tout garder sauf le dernier element print(message_code) ########################### # On dechiffre le message # ########################### message_code = message_code.split(" ") # On transforme le message code en un tableau dont # chaque case est une lettre en binaire for binaire_lettre in message_code : # Pour chaque lettre en binaire nb_lettre = int(binaire_lettre, 2) # On converti la representation binaire en nombre entier (int) lettre = chr(nb_lettre) # On recupere la lettre correspondant au nombre dans la table Ascii message_decode += lettre # On ajoute la lettre au message decode print(message_decode)
Pour résumer, il y a beaucoup de possibilités !
Tu peux maintenant essayer de coder un message en binaire !
Le chiffrement symétrique consiste à utiliser une clé pour chiffrer un message et la même clé pour le déchiffrer.
Un exemple de chiffrement symétrique : le code de César.
Pour utiliser ce chiffrement, on va utiliser le module PyCrypto.
On commence par choisir un algorithme de chiffrement. Il en existe plusieurs. Nous allons utiliser l'algorithme standard AES (Advanced Encryption Standard), qui est rapide et robuste.
AES est un algorithme de chiffrement par blocs. Il traite des blocs de données de 128 bits, c’est à dire de 16 caractères. Le nombre de caractères dans notre message devra donc être un multiple de 16 !
On va combiner cet algorithme avec un mode pour traiter les données. Il en existe aussi plusieurs. Nous allons utiliser le plus courant, le mode CBC (Cipher Block Chaining).
Ce mode va crypter chaque bloc de données en fonction du bloc précédent. Nous allons donc devoir décider d'un IV (vecteur d'initialisation) pour crypter le premier bloc ! En changeant ce vecteur à chaque chiffrement, un même message ne sera pas chiffré de la même manière, ce qui permet de renforcer notre code !
On va choisir une clé de 128 bits, soit 16 caractères.
16 caractères = 16 octets et 1 octet = 8 bits, on a donc 16*8 = 128 bits
Une fois que l'on a tous ces éléments, on peut programmer le chiffrement de notre message :
Si le module n'est pas déjà installé : avant de l'utiliser, il faut l'installer ! Pour cela, tu peux suivre la procédure suivante :
from Crypto.Cipher import AES
On commence par importer le module !
On peut ensuite déclarer les paramètres que l'on a vu plus haut : la clé, le mode et le vecteur d'initialisation.
mes_parametres = AES.new(b'Ceci est une cle', AES.MODE_CBC, b'Ceci est un IV16')
On peut maintenant crypter un message !
texte_chiffre = mes_parametres.encrypt(b"Mon message super suuper secret.")
Si on affiche notre texte chiffré, on obtient :
Attention, si notre message n'est pas un multiple de 16, on obtient cette erreur :
Et pour déchiffrer, il nous suffit de réutiliser les paramètres que l'on a défini :
mes_parametres = AES.new(b'Ceci est une cle', AES.MODE_CBC, b'Ceci est un IV16') texte_normal = mes_parametres.decrypt(texte_chiffre)
Ce chiffrement implique donc que les personnes qui communiquent aient toutes les deux la même clé et le même vecteur d'initialisation.
Si un espion intercepte un message, il pourra difficilement le déchiffrer. Mais cette méthode implique qu'on échange la clé et le vecteur d'initialisation avec la personne avec qui on communique. Si un espion récupère la clé et le vecteur d'initialisation à ce moment, il n'aura aucun problème pour déchiffrer le message.
Le chiffrement asymétrique est un chiffrement plus robuste car il repose sur deux clés : une clé publique et une clé privée.
Le fonctionnement est différent du chiffrement symétrique. Cette fois-ci, n'importe quelle personne avec la clé publique peut crypter un message mais seule la personne avec la clé privée peut le décrypter.
Alice et Bob ont chacun deux clés, une privée et une publique.
Pour pouvoir communiquer, ils n'ont qu'à échanger leur clé publique qui sert à crypter un message. Si un espion intercepte l'échange de clés, il pourra seulement crypter des messages !
Pour envoyer un message à Bob, Alice crypte son message avec la clé publique de Bob. Bob pourra le décrypter avec sa clé privée ! Et inversement.
Pour utiliser ce chiffrement, on va commencer par choisir un algorithme de chiffrement asymétrique. Il en existe plusieurs. Nous allons utiliser un des plus utilisés : le chiffrement RSA.
On commence par importer le module RSA :
import rsa
Si le module n'est pas installé, on peut l'installer simplement avec : pip install RSA
Il nous faut maintenant deux clés : une publique et une privée.
On va les générer avec notre module !
On va pouvoir choisir la taille de nos clés (le nombre de bits) qui détermine la taille maximum de notre message mais aussi la force de notre chiffrement.
Attention : Générer des clés prend du temps. Plus la taille de la clé sera grande, plus la génération de clés prendra du temps.
On peut générer des clés de 128, 256, 384, 512, 1024, 2048, 3072 ou 4096 bits. (Générer des clés de plus de 512 bits peut prendre plus d'une minute !)
Rappel : 1 caractère = 1 octet = 8 bits -> 512 bits = 64 caractères max
Une fois que l'on a choisi le nombre de bits de nos clés, on va les générer avec le module :
(cle_pub, cle_priv) = rsa.newkeys(512)
On peut maintenant s'échanger les clés publiques.
Le module nous permet de sauvegarder et importer une clé facilement. On va sauvegarder la clé au format PEM qui est utilisé pour stocker des données en cryptographie.
On sauvegarde notre clé publique pour l'envoyer avec rsa.PublicKey.save_pkcs1 :
cle_pub_a_envoyer = rsa.PublicKey.save_pkcs1(cle_pub)
Notre partenaire récupère la clé avec rsa.PublicKey.load_pkcs1 :
cle_pub = rsa.PublicKey.load_pkcs1(b'-----BEGIN RSA PUBLIC KEY-----\nMEgCQQCDZkm635nztdvgCIg0zKUsu9Hb/pSTI0DV7eK6OOTtX1heSDJPLQQAqa+f\nLQ4HXUt1cRy9oT1X3d7Mm2QEgdxZAgMBAAE=\n-----END RSA PUBLIC KEY-----\n')
On va maintenant pouvoir crypter et décrypter des messages !
On commence par programmer notre message en UTF-8. Le module RSA n'agit que sur des bytes et non des strings, cette étape est donc importante !
message = 'Mon message secret'.encode('utf8')
Ce qui nous donne :
Le format byte commence toujours pas un 'b'. On ne peut pas le manipuler comme une string. Ici, si on essaye d'afficher le premier élément du message, on obtient un nombre entier (qui correspond à la table ASCII).
message_crypte = rsa.encrypt(message, cle_pub)
Pour décrypter les messages de notre partenaire, on va utiliser notre clé privée :
message = rsa.decrypt(message_crypte, cle_priv)
Pour finir, on transforme notre message en string :
message = message.decode('utf8')
Ce chiffrement est plus sécurisé mais il est assez long. En pratique on l'utilisera pour transmettre la clé d'un chiffrement symétrique !