Stéganographie et cryptologie visuelle

Professeurs référents :

M FAURY (ISN)

Objectif

Cryptographie et stéganographie visuelles consistent à dissimuler et/ou crypter un message dans une image.

La stéganographie est l’art de la dissimulation : son objet est de faire passer inaperçu un message dans un autre message.Cette méthode est connue depuis l’antiquité et elle a de multiples variantes, fonctions du support, de la méthode ou de la technologie existante. Dans ce projet, nous nous intéressons uniquement à la dissimulation d’une image dans une autre en en créant une troisième. En utilisant la stéganographie, on veut que, lorsqu’un autre que le destinataire découvre l’image obtenue, il ne puisse pas soupçonner l’existence d’une autre image dissimulée dans celle qu’il voit, ni même qu’il soupçonne un contenu caché. Ainsi, l’observateur ne peut pas empêcher la transmission de l’image cachée et ne peut pas non plus utiliser la même méthode pour faire passer d’autres informations fausses. Dans notre projet, pour dissimuler une image dans une autre, nous modifions les bits de poids faibles des pixels de l’image contenante.
Cependant, la stéganographie est une méthode connue et si l’on soupçonne une image de contenir une information secrète avec cette méthode, il est aisé de réussir à la récupérer. Aujourd’hui, il existe d’autres méthodes qui permettent de rendre incompréhensible une information à une personne autre que son destinataire.
La cryptologie permet de rendre un message inintelligible à autre que qui-de-droit et englobe la cryptographie, le codage et la cryptanalyse, le décodage. Elle est également connue depuis l’antiquité mais acquiert le statut de sciences seulement dans les années 1970 en devenant thème de recherche avec l’essor de l’informatique puis d’internet et des communications. Le but de la cryptologie visuelle, c’est que seul l’oeil humain doit être capable de décoder et d’authentifier le message. Dans ce projet, pour cacher une image, nous utilisons une méthode de cryptographie à clé secrète qui permet de chiffrer et déchiffrer à partir de la même clé. L’image doit être binarisée (seulement en noir et blanc, sans niveau de gris) et la clé est une image de taille proportionnelle à celle de l’image, composée aléatoirement de pixels noirs et blancs.

Présentation du projet

  • Peut-on modifier une image de façon à ce que seul le destinataire puisse la voir ?
  • Le projet se rapporte aux domaines de compétence suivants :
    • Dimension algorithmique : Création d’algorithmes qui permettent de coder une image selon deux méthodes : stéganographie et cryptologie à clé secrète.
    • Éléments de programmation : Pour la réalisation, nous utilisons le langage de programmation Python avec la distribution Pyzo qui inclut des modules complémentaires, un éditeur de programme et une console qui affiche les résultats du programme exécuté dans l’éditeur. Nous avons utilisé ces modules ou bibliothèques : imageio (pour travailler avec les images), matpotlib (pour afficher les images), pillow (pour travailler avec les images et en créer à partir de tableaux de valeurs numpy), numpy (pour créer des matrices), et tkinter (pour l’interface utilisateur).

Cahier des charges

Production finale attendue : Un algorithme qui permet de coder n’importe quelle image selon une clé donnée (ou générée aléatoirement) (cryptographie) ou bien de la cacher dans une autre (stéganographie) et de la décoder dans les deux cas.

Caractéristiques de la production finale : Fonctionne correctement, petite interface qui permet de rentrer une image ou de choisir la méthode.

Contraintes à respecter : Date butoir, travail en équipe, dossier écrit (5-10 pages)

Matériel et logiciel à mettre en œuvre :  Python et éditeur d’image

Tâches à réaliser

Clémence Vessaire Naouel Kouiss
Codage Stéganographie Décodage Stéganographie
Codage Cryptographie Décodage Cryptographie
Algorithme de binarisation d’image Interface utilisateur

 

Dossiers personnels

Naouel Kouiss

Clémence Vessaire

 

Stéganographie

CODAGE

Image conteneur Image secrète (à cacher)
[reveal heading= »%image% Cliquer ici pour voir le code »]
##Codage
import imageio
import matplotlib.pyplot as plt
plt.axis("off") #pour désactiver l'affichage des axes sur Matplotlib

print("Pour saisir les adresses url des images à coder, il faut les mettre entre guillemets ou apostrophes")
image_1 = input("Copier l'adresse url de votre image conteneur :")
image_2 = input("Copier l'adresse url de votre image secrete :")
image_conteneur = imageio.imread(image_1)
image_secrete = imageio.imread(image_2)

def codage_image(image_conteneur, image_secrete):
    print("Plus le nombre de bits de poids faibles utilisés pour cacher l'image secrète est faible, mieux l'image est cachée mais plus elle en perd en qualité")
    choix_nombre = int(input("Choississez ce nombre entre 1 et 7 :"))
    dico = { 1 : 0b11111110, 2 : 0b11111100, 3 : 0b11111000, 4 : 0b11110000, 5: 0b11100000, 6 : 0b11000000, 7 : 0b10000000 }
    nombre = 8 - choix_nombre
    decalage = dico[choix_nombre]
    largeur = list(range(list(image_conteneur.shape)[0])) #pour obtenir une liste contenant le même nombre que la valeur de la largeur
    hauteur = list(range(list(image_conteneur.shape)[1])) #idem pour la hauteur
  
    for pixel_l in largeur: #sur chaque ligne
        for pixel_h in hauteur: #sur chaque pixel de cette ligne
            #fonction codage_pixel :
            pixel_c = list(image_conteneur[pixel_l][pixel_h])  #pour transformer les tuples des valeurs des pixels en listes modifiables
            pixel_s = list(image_secrete[pixel_l][pixel_h])
            pixel_conteneur= [] #pixel conteneur une fois codé avec les bits de poids faible à 0
            pixel_secret=[]  #pixel secret une fois codé avec les bits de poids forts décalés à gauche
            for octet in pixel_c:  #pour coder chaque octet du pixel conteneur 
                pixel_conteneur.append(decalage & octet) #mettre a zero le bit de poids faible
            for octet in pixel_s:   #pour coder chaque octet du pixel secret  
                pixel_secret.append(octet>>choix_nombre)  #décalage du premier octet de quatre colonnes vers la droite
            #etape 1 du codage finie
            pixel_code = list(range(len(pixel_conteneur)))
            for octet in pixel_code:  #etape 2 du codage :
                pixel_code[octet] = pixel_conteneur[octet] | pixel_secret[octet] #OU logique des deux octets
            image_conteneur[pixel_l][pixel_h] = tuple(pixel_code)   
    plt.imshow(image_conteneur)
         
    
if image_conteneur.shape != image_secrete.shape: # on verifie que les deux images font la même taille 
    print("Les deux images doivent avoir les mêmes dimensions")
else:
    codage_image(image_conteneur, image_secrete)
[/reveal]

 

Résulat :

Autres exemples :

  

 

DÉCODAGE

[reveal heading= »%image% Cliquer ici pour voir le code »]
def decode_octet(octet_code):
    return (0b00001111 & octet_code) << 4
print(bin(decode_octet(0b01101101)))

def decode_pixel(pixel_code):
    pixel_code = list(pixel_code) # pour mettre en liste les octets du pixel
    pixel_decode = [] # ça va faire un tableau dans lequel va se mettre les valeurs des pixels décodés
    for octet in pixel_code: #pour chaque octet du pixel
        pixel_decode.append((0b00001111 & octet) << 4) # mettre les bits de poids fort à 0 et puis décaler de 4 rangs vers la gauche
    return pixel_decode
print(decode_pixel((140,213,109)))

image_codee = imageio.imread("https://upload.wikimedia.org/wikipedia/commons/a/a8/Steganography_original.png")

import matplotlib.pyplot as plt

def decode_image(image_codee):
    largeur = image_codee.shape[0] #pour obtenir la valeur de la largeur
    hauteur = image_codee.shape[1] #pour obtenir la valeur de la hauteur
    for pixel_l in range(largeur): # pour chacun des pixels de la ligne
        for pixel_h in range(hauteur): # pour chacun des pixels de la colonne
            pixel_code = list(image_codee[pixel_l][pixel_h]) # donne les trois composantes RGB
            pixel_decode = [] # ça va faire un tableau dans lequel va se mettre les valeurs des pixels décodés
            for octet in pixel_code: # pour chaque octet du pixel
                pixel_decode.append((0b000001111 & octet) << 4) # mettre les bits de poids fort à 0 et puis décaler de 4 rangs vers la gauche
            image_codee[pixel_l][pixel_h] = tuple(pixel_decode)
    plt.imshow(image_codee) # mettre l'image codée sous plt
    plt.show()
    
decode_image(image_codee) # afficher l'image décodée
[/reveal]

Cryptographie

Décodage

[reveal heading= »%image% Cliquer ici pour voir le code »]
import random        #importation du module random

i = 0                #on initialise une valeur i à 0
image_codee = [0, 1, 0, 1, 1, 0, 1, 0]        #image codee
cle = []                        #initialisation de la cle
                                #generation aleatoire de la cle avec le bipixel cle
while i< len(image_codee)/2:            #tant qu’on est pas a la fin de la liste divisee par 2
alea = random.randint(0,1)        #on choisit un chiffre aleatoirement entre 0 et 1
cle.append(alea)            #on l’ajoute dans cle
if alea == 0:                # si alea = 0, on ajoute son inverse 1
cle.append(1)
elif alea == 1:                #si alea = 1, on ajoute son inverse 0
cle.append(0)
i +=1                    #on incremente la valeur de i de +1
print(cle)

image_decodee = []                #initialisation image_decodee

i = 0                        #on remet i à 0

while i < len(image_codee):            #tant qu’on est pas a la fin de la liste
if image_codee[i] ^ cle[i] == 0:        #si OU exclusif entre l’image et la cle est egal a 0 alors 1
image_decodee.append(1)
elif image_codee[i] ^ cle[i] == 1:        #si OU exclusif entre l’image et la cle est egal a 1 alors 0
image_decodee.append(0)
i += 2                     #on incremente la variable de debut de +2
print(image_decodee)                #on affiche l’image decode
[/reveal]

Interface graphique

[reveal heading= »%image% Cliquer ici pour voir le code »]
from tkinter import * #Importation du module Tkinter

#from tkinter.messagebox import * #Inutile
#from tkinter.filedialog import * #Inutile

import imageio #Importation du module imageio
import matplotlib.pyplot as plt #Importation du module matplotlib
plt.axis("off") #pour désactiver les axes sur Maplotlib

fenetre = Tk() # création de la première fenêtre
titre = Label(fenetre, text = "Choisis ton codage ", fg  = 'blue') #titre
titre.pack() #Affichage du titre

value = StringVar() 

def codage_stega(entree1, entree2): #Codage de la steganographie
    image_conteneur = imageio.imread(entree1.get()) #Transformation de l'adresse URL de l'image conteneur donnée par l'utilisateur en imageio
    image_secrete = imageio.imread(entree2.get()) #Transformation de l'adresse URL de l'image secrete donnée par l'utilisateur en imageio

    largeur = list(range(list(image_conteneur.shape)[0])) #pour obtenir la valeur de la largeur
    hauteur = list(range(list(image_conteneur.shape)[1])) #pour obtenir la valeur de la hauteur
    for pixel_l in largeur: #sur chaque ligne
        for pixel_h in hauteur: #sur chaque pixel de cette colonne
            pixel_1 = image_conteneur[pixel_l][pixel_h] #pour obtenir les valeurs
            pixel_2 = image_secrete[pixel_l][pixel_h]
            #fonction codage_pixel :
            pixel_c = list(pixel_1)  #pour transformer les tuples en listes modifiables
            pixel_s = list(pixel_2)
            pixel_conteneur= [] #pixel conteneur une fois codé avec les bits de poids faible à 0
            pixel_secret=[]  #pixel secret une fois codé avec les bits de poids forts décalés à gauche
            for octet in pixel_c:  #pour coder chaque octet du pixel conteneur 
                pixel_conteneur.append(int('11110000', 2)& octet) #mettre a zero le bit de poids faible
            for octet in pixel_s:   #pour coder chaque octet du pixel secret  
                pixel_secret.append(octet>>4)  #décalage du premier octet de quatre colonnes vers la droite
            #etape 1 du codage finie
            pixel_code = list(range(len(pixel_conteneur)))
            for octet in pixel_code:  #etape 2 du codage :
                pixel_code[octet] = pixel_conteneur[octet] | pixel_secret[octet] #OU logique des deux octets
            image_conteneur[pixel_l][pixel_h] = tuple(pixel_code)   
    plt.imshow(image_conteneur)
    plt.show()
    return imageio.imsave("image_conteneur.png", image_conteneur)
         

def decodage_stega(result): #Décodage de la stéganographie

    image_codee = imageio.imread(result.get()) #Transformation de l'adresse URL de l'image codée donnée par l'utilisateur en imageio
    largeur = image_codee.shape[0] #pour obtenir la valeur de la largeur
    hauteur = image_codee.shape[1] #pour obtenir la valeur de la hauteur
    
    for pixel_l in range(largeur): # pour chacun des pixels de la ligne
        for pixel_h in range(hauteur): # pour chacun des pixels de la colonne
            pixel_code = list(image_codee[pixel_l][pixel_h]) # donne les trois composantes RGB
            pixel_decode = [] #ça va faire un tableau dans lequel vont se mettre les valeurs des pixels décodé
            for octet in pixel_code: #décodage pour chaque octet de chaque pixel
                pixel_decode.append((0b00001111 & octet) << 4) # mettre les bit de poids fort à 0 et puis décaler de 4 rangs vers la gauche
            image_codee[pixel_l][pixel_h] = tuple(pixel_decode)
    plt.imshow(image_codee) # mettre image_codee sous plt
    plt.show()
    
    

def choix1(): #Pour le choix du codage ou du décodage pour la stéganographie
    fenetre1 = Tk() #Création de la fenêtre
    titre = Label(fenetre1, text = "Choix codage/décodage ") #titre
    titre.pack() #Affichage du titre
    cadre = Frame(fenetre1) #Cadre pour la fenêtre
    cadre.pack() #Affichage du cadre
    bouton1 = Radiobutton(fenetre1, text="Codage", variable = value, value = 0, command = recupere11) #bouton pour le choix Codage
    bouton2 = Radiobutton(fenetre1, text="Decodage", variable = value, value = 1, command = recupere12) #bouton pour le choix Decodage
    bouton1.pack() #Affichage du bouton1
    bouton2.pack() #Affichage du bouton2
    bouton1.select()
    fenetre1.mainloop() #Démarrage de la boucle Tkinter
    
def choix2(): #Pour le choix du codage ou du décodage pour la cryptologie
    fenetre1 = Tk() #Définition de la fenêtre
    titre = Label(fenetre1, text = "Choix codage/décodage ") #titre
    titre.pack() #Affichage du titre
    cadre = Frame(fenetre1) #Cadre pour la fenêtre
    cadre.pack() #Affichage du cadre
    bouton1 = Radiobutton(fenetre1, text="Codage", variable = value, value = 0, command = recupere21) #bouton pour le choix Codage
    bouton2 = Radiobutton(fenetre1, text="Decodage", variable = value, value = 1, command = recupere22) #bouton pour le choix Decodage
    bouton1.pack() #Affichage du bouton1
    bouton2.pack() #Affichage du bouton2
    bouton1.select()
    fenetre1.mainloop() #Démarrage de la boucle Tkinter

def recupere11(): #Codage Steganographie         pour recuperer les images telecharger
    fenetre2 = Tk() #Création de la fenêtre
    fenetre2.title("Codage Steganographie")#Titre de la fenêtre
    titre1 = Label(fenetre2, text = "Insérer l'url de l'image conteneur")#Titre1
    titre1.pack() #Affichage du titre1
    cadre = Frame(fenetre2) #Cadre pour la fenêtre
    cadre.pack() #Affichage du cadre
    entree1 = Entry(cadre, width=30)
    entree1.pack() #Affichage de l'entree1
    titre2 = Label(fenetre2, text = "Insérer l'url de l'image à cacher")#Titre2
    titre2.pack() #Affichage du titre2
    entree2 = Entry(cadre, width=30)
    entree2.pack()#Affichage de l'entree2
    valider = Button(cadre, text="Valider", command= lambda: codage_stega(entree1, entree2))#Bouton valider
    valider.pack() #Affichage du bouton valider
    fenetre2.mainloop() #Démarrage de la boucle Tkinter
    
def recupere12(): #Decodage Steganographie         pour recuperer les images telecharger
    fenetre2 = Tk()#Definition de la fenêtre
    fenetre2.title("Decodage Steganographie ")#Titre de la fenêtre
    titre1 = Label(fenetre2, text = "Inserer l'url de l'image à décoder")#Titre1
    titre1.pack() #Affichage du titre1
    cadre = Frame(fenetre2) #Cadre pour la fenêtre
    cadre.pack() #Affichage du cadre
    entree1 = Entry(cadre, width=30)
    entree1.pack()#Affichage de l'entree1
    valider = Button(cadre, text="Valider", command= lambda: decodage_stega(entree1)) #Bouton valider
    valider.pack() #Affichage du bouton valider
    fenetre2.mainloop() #Démarrage de la boucle Tkinter

def recupere21(): #Codage crypto
    fenetre2 = Tk() #Définition de la fenêtre
    fenetre2.title("Codage Cryptologie") #Titre de la fenêtre
    titre = Label(fenetre2, text = "Inserer l'url de l'image à cacher") #titre
    titre.pack() #Affichage du titre
    cadre = Frame(fenetre2) #Cadre pour la fenêtre
    cadre.pack() #Affichage du cadre
    entree1 = Entry(cadre, width=30)
    entree1.pack()#Affichage de l'entree1
    fenetre2.mainloop() #Démarrage de la boucle Tkinter
    
def recupere22(): #Decodage crypto
    fenetre2 = Tk() #Définition de la fenêtre
    fenetre2.title("Decodage Cryptologie") #Titre de la fenêtre
    titre = Label(fenetre2, text = "Inserer l'url de l'image à décoder") #titre
    titre.pack() #Affichage du titre
    cadre = Frame(fenetre2) #Cadre pour la fenêtre
    cadre.pack() #Affichage du cadre
    entree1 = Entry(cadre, width=30)
    entree1.pack()#Affichage de l'entree1
    fenetre2.mainloop() #Démarrage de la boucle Tkinter


cadre = Frame(fenetre) #Cadre pour la fenêtre
cadre.pack() #Affichage du cadre

bouton1 = Radiobutton(fenetre, text="Steganographie", variable = value, value = 0, command = choix1) #bouton pour le choix Steganographie
bouton2 = Radiobutton(fenetre, text="Cryptologie", variable = value, value = 1, command = choix2) #bouton pour le choix Cryptologie


bouton1.pack()#Affichage du bouton1
bouton2.pack()#Affichage du bouton2
bouton1.select()

fenetre.mainloop() #Démarrage de la boucle Tkinter
[/reveal]

 

Ressources

Fichiers du projet

  • Ajouter un(des) fichier(s) puis cliquer sur Téléverser.
  • Rafraichir la page pour vérifier que le dépôt a bien eu lieu.

 

 

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *