Stéganographie en GIF

introduction

Bienvenue.
Il n'y a pas si longtemps, lorsque j'étudiais à l'université, il y avait un cours dans la discipline « Méthodes logicielles de sécurité de l'information ». La mission nous obligeait à créer un programme qui intègre un message dans des fichiers GIF. J'ai décidé de le faire en Java.

Dans cet article je décrirai quelques points théoriques, ainsi que comment ce petit programme a été créé.

Partie théorique

Format GIF

GIF (Graphics Interchange Format - un format d'échange d'images) est un format de stockage d'images graphiques, capable de stocker des données compressées sans perte de qualité dans un format allant jusqu'à 256 couleurs. Ce format a été développé en 1987 (GIF87a) par CompuServe pour transmettre des images raster sur les réseaux. En 1989, le format a été modifié (GIF89a), le support de la transparence et de l'animation a été ajouté.

Les fichiers GIF ont une structure de blocs. Ces blocs ont toujours une longueur fixe (ou cela dépend de certains drapeaux), il est donc presque impossible de se tromper sur l'emplacement de chaque bloc. La structure de l'image GIF non animée la plus simple au format GIF89a :

Stéganographie en GIF

De tous les blocs de la structure, dans ce cas nous nous intéresserons au bloc palette global et aux paramètres responsables de la palette :

  • CT — présence d'une palette globale. Si cet indicateur est défini, la palette globale doit commencer immédiatement après le handle d'écran logique.
  • Size — taille de la palette et nombre de couleurs dans l'image. Valeurs pour ce paramètre :

Taille
Nombre de couleurs
Taille de la palette, octets

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Méthodes de cryptage

Les méthodes suivantes seront utilisées pour chiffrer les messages dans les fichiers image :

  • Méthode LSB (bit le moins significatif)
  • Méthode d'ajout de palette

Méthode LSB - une méthode courante de stéganographie. Elle consiste à remplacer les derniers bits significatifs du conteneur (dans notre cas, les octets de la palette globale) par les bits du message caché.

Le programme utilisera les deux derniers bits des octets de la palette globale dans le cadre de cette méthode. Cela signifie que pour une image 24 bits, où la palette de couleurs est de trois octets pour le rouge, le bleu et le vert, après y avoir intégré un message, chaque composante de couleur changera d'un maximum de 3/255 gradations. Un tel changement, d'une part, sera invisible ou difficile à remarquer à l'œil humain, et d'autre part, il ne sera pas visible sur les appareils de sortie d'informations de mauvaise qualité.

La quantité d'informations dépendra directement de la taille de la palette d'images. Étant donné que la taille maximale de la palette est de 256 couleurs et que si deux bits de message sont écrits dans le composant de chaque couleur, la longueur maximale du message (avec la palette maximale dans l'image) est de 192 octets. Une fois le message intégré à l'image, la taille du fichier ne change pas.

Méthode d'expansion de la palette, qui ne fonctionne que pour la structure GIF. Ce sera plus efficace sur les images avec une petite palette. Son essence est qu'il augmente la taille de la palette, fournissant ainsi un espace supplémentaire pour écrire les octets nécessaires à la place des octets de couleur. Si l'on considère que la taille minimale de la palette est de 2 couleurs (6 octets), alors la taille maximale du message intégré peut être de 256 × 3–6 = 762 octets. L'inconvénient est une faible sécurité cryptographique ; le message intégré peut être lu à l'aide de n'importe quel éditeur de texte si le message n'a pas été soumis à un cryptage supplémentaire.

Partie pratique

Conception du programme

Tous les outils nécessaires à la mise en œuvre des algorithmes de cryptage et de décryptage seront inclus dans le package com.tsarik.steganography. Ce package comprend l'interface Encryptor avec des méthodes encrypt и decrypt, Classe Binary, qui offre la possibilité de travailler avec des tableaux de bits, ainsi que des classes d'exceptions UnableToEncryptException и UnableToDecryptException, qui doit être utilisé dans les méthodes d'interface Encryptor en cas d'erreurs de codage et de décodage respectivement.

Programme principal com.tsarik.programs.gifed inclura une classe de programme exécutable avec une méthode statique main, vous permettant d'exécuter le programme ; une classe qui stocke les paramètres du programme ; et des forfaits avec d'autres classes.

L'implémentation des algorithmes eux-mêmes sera présentée dans le package com.tsarik.programs.gifed.gif Des classes GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Ces deux classes implémenteront l'interface Encryptor.

Sur la base de la structure du format GIF, vous pouvez créer un algorithme général pour introduire un message dans la palette d'images :

Stéganographie en GIF

Pour déterminer la présence d'un message dans une image, il est nécessaire d'ajouter une certaine séquence de bits au début du message, que le décodeur lit en premier et vérifie son exactitude. Si cela ne correspond pas, alors on considère qu’il n’y a pas de message caché dans l’image. Ensuite, vous devez spécifier la longueur du message. Puis le texte du message lui-même.

Diagramme de classes de l'ensemble de l'application :

Stéganographie en GIF

Mise en œuvre du programme

La mise en œuvre de l'ensemble du programme peut être divisée en deux volets : mise en œuvre des méthodes de cryptage et de décryptage de l'interface. Encryptor, en cours GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, et la mise en œuvre de l'interface utilisateur.

Considérez la classe GIFEncryptorByLSBMethod.

Stéganographie en GIF

champs firstLSBit и secondLSBit contiennent les nombres de bits de chaque octet de l'image dans lequel le message doit être entré et à partir duquel le message doit être lu. Champ checkSequence stocke une séquence de bits de contrôle pour garantir la reconnaissance du message intégré. Méthode statique getEncryptingFileParameters renvoie les paramètres du fichier spécifié et les caractéristiques du message potentiel.

Algorithme de méthode encrypt Classe GIFEncryptorByLSBMethod:

Stéganographie en GIF

Et son code :

@Override
public void encrypt(File in, File out, String text) throws UnableToEncodeException, NullPointerException, IOException {
	if (in == null) {
		throw new NullPointerException("Input file is null");
	}
	if (out == null) {
		throw new NullPointerException("Output file is null");
	}
	if (text == null) {
		throw new NullPointerException("Text is null");
	}
	
	// read bytes from input file
	byte[] bytes = new byte[(int)in.length()];
	InputStream is = new FileInputStream(in);
	is.read(bytes);
	is.close();
	
	// check format
	if (!(new String(bytes, 0, 6)).equals("GIF89a")) {
		throw new UnableToEncodeException("Input file has wrong GIF format");
	}
	
	// read palette size property from first three bits in the 10-th byte from the file
	byte[] b10 = Binary.toBitArray(bytes[10]);
	byte bsize = Binary.toByte(new byte[] {b10[0], b10[1], b10[2]});
	
	// calculate color count and possible message length
	int bOrigColorCount = (int)Math.pow(2, bsize+1);
	int possibleMessageLength = bOrigColorCount*3/4;
	int possibleTextLength = possibleMessageLength-2;// one byte for check and one byte for message length
	
	if (possibleTextLength < text.length()) {
		throw new UnableToEncodeException("Text is too big");
	}
	
	int n = 13;
	
	// write check sequence
	for (int i = 0; i < checkSequence.length/2; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		ba[firstLSBit] = checkSequence[2*i];
		ba[secondLSBit] = checkSequence[2*i+1];
		bytes[n] = Binary.toByte(ba);
		n++;
	}
	
	// write text length
	byte[] cl = Binary.toBitArray((byte)text.length());
	for (int i = 0; i < cl.length/2; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		ba[firstLSBit] = cl[2*i];
		ba[secondLSBit] = cl[2*i+1];
		bytes[n] = Binary.toByte(ba);
		n++;
	}
	
	// write message
	byte[] textBytes = text.getBytes();
	for (int i = 0; i < textBytes.length; i++) {
		byte[] c = Binary.toBitArray(textBytes[i]);
		for (int ci = 0; ci < c.length/2; ci++) {
			byte[] ba = Binary.toBitArray(bytes[n]);
			ba[firstLSBit] = c[2*ci];
			ba[secondLSBit] = c[2*ci+1];
			bytes[n] = Binary.toByte(ba);
			n++;
		}
	}
	
	// write output file
	OutputStream os = new FileOutputStream(out);
	os.write(bytes);
	os.close();
}

Algorithme et code source de la méthode decrypt Classe GIFEncryptorByLSBMethod:

Stéganographie en GIF

@Override
public String decrypt(File in) throws UnableToDecodeException, NullPointerException, IOException {
	if (in == null) {
		throw new NullPointerException("Input file is null");
	}
	
	// read bytes from input file
	byte[] bytes = new byte[(int)in.length()];
	InputStream is = new FileInputStream(in);
	is.read(bytes);
	is.close();
	
	// check format
	if (!(new String(bytes, 0, 6)).equals("GIF89a")) {
		throw new UnableToDecodeException("Input file has wrong GIF format");
	}
	
	// read palette size property from first three bits in the 10-th byte from the file
	byte[] b10 = Binary.toBitArray(bytes[10]);
	byte bsize = Binary.toByte(new byte[] {b10[0], b10[1], b10[2]});
	
	// calculate color count and possible message length
	int bOrigColorCount = (int)Math.pow(2, bsize+1);
	int possibleMessageLength = bOrigColorCount*3/4;
	int possibleTextLength = possibleMessageLength-2;	// one byte for check and one byte for message length
	
	int n = 13;
	
	// read check sequence
	byte[] csBits = new byte[checkSequence.length];
	for (int i = 0; i < 4; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		csBits[2*i] = ba[firstLSBit];
		csBits[2*i+1] = ba[secondLSBit];
		n++;
	}
	byte cs = Binary.toByte(csBits);
	
	if (cs != Binary.toByte(checkSequence)) {
		throw new UnableToDecodeException("There is no encrypted message in the image (Check sequence is incorrect)");
	}
	
	// read text length
	byte[] cl = new byte[8];
	for (int i = 0; i < 4; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		cl[2*i] = ba[firstLSBit];
		cl[2*i+1] = ba[secondLSBit];
		n++;
	}
	byte textLength = Binary.toByte(cl);
	
	if (textLength < 0) {
		throw new UnableToDecodeException("Decoded text length is less than 0");
	}
	if (possibleTextLength < textLength) {
		throw new UnableToDecodeException("There is no messages (Decoded message length (" + textLength + ") is less than Possible message length (" + possibleTextLength + "))");
	}
	
	// read text bits and make text bytes
	byte[] bt = new byte[textLength];
	for (int i = 0; i < bt.length; i++) {
		byte[] bc = new byte[8];
		for (int bci = 0; bci < bc.length/2; bci++) {
			byte[] ba = Binary.toBitArray(bytes[n]);
			bc[2*bci] = ba[firstLSBit];
			bc[2*bci+1] = ba[secondLSBit];
			n++;
		}
		bt[i] = Binary.toByte(bc);
	}
	
	return new String(bt);
}

Mise en œuvre de la classe GIFEncryptorByPaletteExtensionMethod sera similaire, seule la méthode de sauvegarde/lecture des informations est différente.

En classe MainFrame Les méthodes wrapper sont décrites : encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), traitement des résultats des méthodes d'interface Encryptor et interagir avec l'utilisateur, c'est-à-dire ouvrir une boîte de dialogue de sélection de fichier, afficher des messages d'erreur, etc. ; ainsi que d'autres méthodes : openImage(), permettant à l'utilisateur de sélectionner une image, exit(), qui quitte l'application. Ces méthodes sont appelées depuis Actionles éléments de menu correspondants. Cette classe implémente en outre des méthodes auxiliaires : createComponents() - création de composants de formulaire, loadImageFile(File f) — chargement d'une image dans un composant spécial à partir d'un fichier. Mise en œuvre de la classe GIFEncryptorByPaletteExtensionMethod similaire à l'implémentation de classe GIFEncryptorByLSBMethod, la principale différence réside dans la manière dont les octets du message sont écrits et lus à partir de la palette.

Fonctionnement du programme

Méthode LBS

Disons qu'il existe une image comme celle-ci :

Stéganographie en GIF

Dans cette image, la palette se compose de 256 couleurs (comme Paint l'enregistre). Les quatre premières couleurs sont : blanc, noir, rouge, vert. Les autres couleurs sont le noir. La séquence globale de bits de la palette sera la suivante :

11111111 11111111 11111111 00000000 00000000 00000000 11111111 00000000 00000000 00000000 11111111 00000000...

Stéganographie en GIF

Une fois le message intégré, les bits soulignés seront remplacés par les bits du message. L'image résultante n'est presque pas différente de l'originale.

Original
Image avec message intégré

Stéganographie en GIF
Stéganographie en GIF

Méthode d'expansion de la palette

Lorsque vous ouvrez une image contenant un message en utilisant cette méthode, vous verrez l'image suivante :

Stéganographie en GIF

Il est clair que cette méthode ne fonctionnera pas pour des activités d'espionnage à part entière et peut nécessiter un cryptage supplémentaire du message.

Le cryptage/déchiffrement dans les images animées fonctionne comme dans les images statiques classiques, mais l'animation n'est pas interrompue.

Sources utilisées :

Télécharger:

Source: habr.com

Ajouter un commentaire