Le cryptage des données est très à la mode : il s'agit d'un enjeu aujourd'hui majeur du fait de la connexion quasi permanente des terminaux à internet, de la multiplication des points d'accès à internet, du stockage des données dans le cloud, de l'augmentation incessante des performances des ordinateurs et de l'apparition de nouveaux algorithmes de décryptage. Nous voilà donc lancé dans la fameuse course technologique entre les armes et les armures...
Cryptage simple
Une méthode simple de cryptage peut être de changer tout simplement la palette de couleurs de l'image : si elle à l'avantage d'être assez simple à programmer et à comprendre, elle ne permet toutefois pas de masquer complètement le sujet présenté et n'est donc pas à utiliser pour cacher totalement le sujet de l'image !
La code présentée ici est basé sur un algorithme de type César fonctionnant sur les 3 canaux RVB de l'image.
import pygamefrom pygame.locals import *# Entrée des 3 clés de César pour les 3 canaux RVBr=int(input("Entrer la clé de César pour le canal Rouge :"))v=int(input("Entrer la clé de César pour le canal Vert :"))b=int(input("Entrer la clé de César pour le canal Bleu :"))cesar=[r,v,b]# Initialisation de la fenêtre d'affichagepygame.init()fenetre = pygame.display.set_mode((870,522))pygame.display.set_caption("La Vie Cryptée de Marc Chagall")# Traitement de l'imagefond = pygame.image.load("lavie.jpg").convert()blank_surface = pygame.Surface((870,522))# Affichage de l'image départfenetre.blit(fond,(0,0))pygame.display.flip()pygame.time.wait(1000)# Lecture et remplacement de la couleur de chaque pixelfor i in range(870): for j in range(522): color=list(fond.get_at((i,j))) for k in range(3): color[k]=color[k]+cesar[k] if color[k]>255: color[k]=color[k]-255 color=tuple(color) blank_surface.set_at((i,j),color) #collage du fondfenetre.blit(blank_surface,(0,0))pygame.display.flip()# Sauvegarde de l'image dans un fichierpygame.image.save(blank_surface,"laviecrypteedemarcchagall.jpg")# Boucle principalecontinuer = 1while continuer: for event in pygame.event.get(): # Quitter if event.type == QUIT: continuer = 0 pygame.quit()A noter ici :
pygame.time.wait(1000), ce qui permet de voir un instant l'image de départcesar=[r,v,b], on aurait cependant pu choisir un stockage externe dans un fichiercolor[k]=color[k]+cesar[k]if color[k]>255: color[k]=color[k]-255pygame.image.save(blank_surface,"laviecrypteedemarcchagall.jpg")Exemple d'exercice d'appropriation : créer un deuxième script permettant cette fois-ci de décrypter l'image, en lisant l'image cryptée stockée précédemment et en saisissant les 3 clés de César.
La correction du script est ici.
Voici le résultat du cryptage et du décryptage de César pour les clés de César [100,100,100] (on peut remarquer la surexposition de certains pixels lors du décryptage due à un bug de la version de SDL utilisée) :
Cryptage avancé
il existe et on peut imaginer quantité de méthode de cryptage plus ou moins compliquée. Nous allons ici améliorer notre cryptage tout en conservant le même algorithme : pour cela nous allons crypter chacun des canaux RVB de chacune des lignes avec une clé de César différente déterminée aléatoirement. Ces clés vont être stockées dans un fichier externe qui sera utilisé pour le décryptage de l'image, ainsi il sera impossible de connaître le contenu de l'image sans avoir accès au fichier contenant l'ensemble des clés et au programme de décryptage.
Voici le code complet :
import pygameimport randomfrom pygame.locals import *# Initialisation de la fenêtre d'affichagepygame.init()fenetre = pygame.display.set_mode((870,522))pygame.display.set_caption("La Vie Très Cryptée de Marc Chagall")# Traitement de l'imagefond = pygame.image.load("lavie.jpg").convert()blank_surface = pygame.Surface((870,522))# Affichage de l'image départfenetre.blit(fond,(0,0))pygame.display.flip()pygame.time.wait(1000)# Création de la liste contenant les clés de Césarcesar=[]for j in range(522): cesar=cesar +[[random.randint(0,255),random.randint(0,255),random.randint(0,255)]]# Création du fichier contenant les clés de Césartrousseau = open("topsecret.txt", "w")trousseau.close()trousseau = open("topsecret.txt", "a")for j in range(522): for k in range(3): trousseau.write(str(cesar[j][k])+" ")trousseau.close() # Lecture et remplacement de la couleur de chaque pixelfor i in range(870): for j in range(522): color=list(fond.get_at((i,j))) for k in range(3): color[k]=color[k]+cesar[j][k] if color[k]>255: color[k]=color[k]-255 color=tuple(color) blank_surface.set_at((i,j),color) # Collage du fondfenetre.blit(blank_surface,(0,0))pygame.display.flip()# Sauvegarde de l'image dans un fichierpygame.image.save(blank_surface,"lavietrescrypteedemarcchagall.jpg")# Boucle principalecontinuer = 1while continuer: for event in pygame.event.get(): # Quitter if event.type == QUIT: continuer = 0 pygame.quit()Détaillons maintenant un peu ce code:
import randomrandom.randint(0,255)open("topsecret.txt", "w") sert normalement à accéder au fichier topsecret.txt en écriture, elle est utilisée ici pour simplement effacer le contenu du fichier précédent. Ne pas oublier de fermer le plus tôt possible le fichier ouvert à l'aide de l'instruction close() pour éviter de générer une erreur d'accès. open("topsecret.txt", "a") et les deux boucles for imbriquées servent à parcourir la liste cesar. Son contenu est ensuite écrit dans le fichier texte ouvert précédemment grâce à l'instruction write(str(cesar[j][k])+" ") . A noter la conversion de chaque donnée en chaîne de caractères et l'insertion d'un espace pour préparer le split de la chaîne lors du décodage... color[k]=color[k]+cesar[j][k] Exemple d'exercice d'appropriation : créer un deuxième script permettant cette fois-ci de décrypter l'image, en lisant l'image cryptée stockée précédemment et en utilisant le fichier topsecret.txt.
La correction du script est ici.
Voici le résultat du cryptage avancé et du décryptage avancé de César (même cause et mêmes effet, les altérations sur l'image décryptée sont dues à un bug de la SDL mais on reconnaît bien le sujet de l'image):