Archive de l’étiquette stéganographie

Stéganographie et Python

La stéganographie consiste à dissimuler un message dans un autre message. Dans cet article nous verrons une façon de dissimuler un texte dans une image à l’aide de Python.

Stéganographie avec Python
Stéganographie avec Python

Une méthode de stéganographie en Python

Je souhaite incruster les lettres “AB” dans l’image.

Code ASCII des caractères

Il faut d’abord que j’obtienne le code ASCII de chaque caractères. On l’obtient en Python avec la commande :

bin( ord( 'A' ) ) # donne : '0b1000001'
bin( ord( 'B' ) ) # donne : '0b1000010'

Il nous faut un octet donc on supprime le ‘0b’:

bin( ord( 'A' ) )[2:] # donne : '1000001'
bin( ord( 'B' ) )[2:] # donne : '1000010'

Il nous faut encore formater de sorte à bien avoir 8 binaires :

bin( ord( 'A' ) )[2:].rjust(8,'0') # donne : '01000001'
bin( ord( 'B' ) )[2:].rjust(8,'0') # donne : '01000010'

Séparation des niveaux de couleurs

Vous le savez peut-être, une image est composée de 3 ou 4 couches; on va simplifier en disant qu’elle contient 3 niveaux de couleurs : rouge, vert et bleu. On va donc, pour chaque pixel de l’image, récupérer le nombre associé au niveau rouge (par exemple), puis prendre le nombre pair qui lui est inférieur ou égal (si le pixel “0” est associé à 37, on va arrondir à 36 et s’il est associé à 42, on garde 42). Pour chaque pixel, je vais noter R[i] le résultat obtenu pour le pixel i.

Transformation de la valeur

Un tableau est préférable pour expliquer, car là, ça devient chiant à décrire avec des mots ce qui se passe :

Pixel12345678910111213141516
Image3071252010152159618202020208715101
Réduction3070242010152149618202020208614100
Binaire0100000101000010
Couverture3071242010152149718212020208615100
  • première ligne : représente le numéro du pixel de l’image;
  • deuxième ligne : représente le nombre associé au pixel i sur le niveau de rouge;
  • troisième ligne : représente l’arrondi au nombre pair inférieur ou égal;
  • quatrième ligne : représente les deux octets correspondant à ‘A’ et ‘B’ (le message à incruster);
  • dernière ligne : représente la somme des lignes 3 et 4, qui donne le nombre attribué au pixel i sur la couche rouge dans l’image finale, que l’on appelle généralement la couverture.

Ainsi, à l’œil nu, on ne remarque aucune altération de l’image puisque l’on ajoute uniquement 1 (au maximum) sur une seule couche.

Stéganographie en Python à l’aide de PIL

La première chose à savoir est que nous allons manipuler des images en Python et donc utiliser le module PIL. Il faut alors l’installer. Dans un terminal, taper (je suis sous Python 3.8+) :

pip install Pillow

Incruster un message dans une image (stéganographie python)

Voici la définition de la fonction:

from PIL import Image

def stegano(name_img , msg):
    im = Image.open(name_img)
    # on récupère les dimensions de l'image
    w , h = im.size

    # on sépare l'image en trois : rouge, vert et bleu
    r , g , b = im.split()

    # on transforme la partie rouge en liste
    r = list( r.getdata() )

    # on calcule la longueur de la chaîne et on la transforme en binaire
    u = len(msg)
    v = bin( len(msg) )[2:].rjust(8,"0")

    # on transforme la chaîne en une liste de 0 et de 1 
    ascii = [ bin(ord(x))[2:].rjust(8,"0") for x in msg ]

    # transformation de la liste en chaîne
    a = ''.join(ascii)

    # on code la longueur de la liste dans les 8 premiers pixels rouges
    for j in range(8):
        r[j] = 2 * int( r[j] // 2 ) + int( v[j] )

    # on code la chaîne dans les pixels suivants
    for i in range(8*u):
        r[i+8] = 2 * int( r[i+8] // 2 ) + int( a[i] )
        
    # on recrée l'image rouge 
    nr = Image.new("L",(16*w,16*h))
    nr = Image.new("L",(w,h))
    nr.putdata(r)

    # fusion des trois nouvelles images
    imgnew = Image.merge('RGB',(nr,g,b))
    new_name_img = "couv_" + name_img
    imgnew.save(new_name_img)

En tapant:

stegano("grand_pere_a_la_plage.png" , "Il a mangé trop de cassoulet !")

le message est incrusté dans l’image et la couverture est sauvegardée sous le nom “couv_grand_pere_a_la_plage.png”.

Obtention du message

def get_msg(name_couv):
    im = Image.open(name_couv)
    r , g , b = im.split()
    r = list( r.getdata() )
    
    # lecture de la longueur de la chaine
    p = [ str(x%2) for x in r[0:8] ]
    q = "".join(p)
    q = int(q,2)
    
    # lecture du message
    n = [ str(x%2) for x in r[8:8*(q+1)] ]

    b = "".join(n)
    message = ""

    for k in range(0,q):
        l = b[8*k:8*k+8]
        message += chr(int(l,2))
        
    return message

À noter que n’importe qui peut obtenir le message… Ce n’est donc pas très sécurisé. Cette technique est donc à coupler avec une technique de cryptographie pour chiffrer et déchiffrer le message…

Supportscreen tag