Stéganographie fréquentielle



La stéganographie fréquentielle



Les images Jpeg sont des supports très célèbres de stéganographie, puisque beaucoup d'images sont échangées dans ce format sur le Web.
Il existe de nombreuses méthodes qui cachent les données secrètes dans ces fichiers.

Méthode LSB des coefficients DCT

Cette méthode incorpore le message en remplaçant les bits de poids faibles des coefficients DCT non nuls avec les bits du message secret.
Dans [Danti et Preethi, 2010], on propose une nouvelle méthode stéganographique, appelée "LSB-DCT avec seuillage",
basée sur l'insertion du message dans les coefficients DCT.
Elle consiste à calculer d'abord la transformée DCT de l'image porteuse, ensuite l'image stégo est construite en cachant l'image secrète bit par bit,
dans le bit de poids faible LSB des coefficients DCT qui sont inférieurs à un certain seuil. Cette méthode appelée "LSB-DCT avec seuillage" est l'une des techniques la plus utilisée en stéganographie.
Elle consiste à cacher une image secrète dans une image porteuse en se basant sur les valeurs des coefficients DCT.
Pour ne pas avoir une distorsion visuelle, l'intégration des informations secrètes est évitée pour les coefficients DCT de valeur égale à 0 [Danti et Preethi, 2010].
La dissimulation des bits secrets se fait selon les étapes suivantes :

Voici en détails la méthode LSB-DCT avec seuillage.
On va cacher chaque bit des codes Ascii de chaque caractère du message secret en remplaçant le bit de poids faible (LSB) de chaque coefficient DCT compris entre -100 et 0 exclus (le seuillage)
Pour cela l’algorithme reprend le début de l’algorithme de compression Jpeg jusqu’au calcul des coefficients DCT puis cache le message dans les LSB des bons coefficients
puis remonte l’algorithme de compression Jpeg et recalcule le code RGB de chaque pixel avant de recrée l’image stéganographiée.
Pour faire cela sous python 3, on a besoin de bibliothèques :

  1. La première étape consiste à transformer les triplets (R,G,B) en (L,Cb,Cr) en utilisant la formule donnée en partie compression JPEG
  2. Ensuite comme la compression Jpeg conserve la luminance, le message secret ne pourra être caché que dans la luminance, la chrominance étant échantillonnée donc modifiée par compression.
  3. Le tableau des coefficients de luminance est découpé en bloc de 8x8 , afin d’y subir la transformation en cosinus discrète
  4. C’est à ce moment là que l’on modifie les coefficients DCT en remplaçant le bit de poids faible du coefficient DCT compris entre -100 et 0 par le bit du code ascii du caractère du message secret.
  5. Ensuite il faut appliquer à tous ces coefficients la DCT inverse pour retrouver les coefficients de luminance,
  6. Enfin il faut recalculer les triplets (RVB), à partir de la nouvelle luminance et des coefficients de chrominance Cb et Cr conservés au début de l’étape 1.

Conclusion L’idée paraît séduisante mais en réalité, beaucoup de problèmes ont été soulevés :
L’essentiel des soucis vient au moment de la dernière étape de recalcul de la nouvelle image, et notamment du calcul des triplets (R,G,B) qui nécessitent d’être arrondis pour pouvoir utiliser la méthode .putpixel((x,y)(R,G,B)) de PIL Image
et donc les arrondis modifie les LSB des coefficients donc il y a perte de l’information.
J’ai tenté de diminuer le problème en modifiant, non plus le chiffre des unités, trop sensible aux arrondis,
mais en modifiant la parité du chiffre des dizaines, par exemple :
Si je souhaite cacher un 0 dans le coefficient DCT -73 je transforme le 7 en 8 pour respecter la parité du zéro et je centre le coefficient
pour qu’au moment de l’arrondi cela se passe le mieux possible, c’est-à-dire qu’il devient -85.
Malgré cela, certains coefficient continuent à mal réagir aux arrondis,
donc j’ai crée une liste qui exclue certains coefficients. Le problème de l’arrondi peut être réglé comme cela,
mais il est long d’exclure un par un les coefficients qui ne conviennent pas.

Le deuxième problème rencontré, est au moment de la procédure d’enregistrement de l’image : image.save()
cela modifie encore les coefficients, donc le message secret se perd.

Je n’ai pas réussi à régler ce second problème, je n’ai pas su maitriser ce qui se cache derrière la méthode .save().