Esteganografia GIF-n

Sarrera

Agurra.
Duela ez hainbeste, unibertsitatean ikasten ari nintzela, "Informazioaren segurtasunerako software metodoak" diziplinako ikastaro bat zegoen. Eginkizunak GIF fitxategietan mezu bat txertatzen duen programa bat sortzea eskatzen zigun. Javan egitea erabaki nuen.

Artikulu honetan puntu teoriko batzuk deskribatuko ditut, baita programa txiki hau nola sortu zen ere.

Parte teorikoa

GIF formatua

GIF (Graphics Interchange Format - irudiak trukatzeko formatua) irudi grafikoak gordetzeko formatua da, konprimitutako datuak kalitatea galdu gabe gordetzeko gai dena 256 koloreko formatuan. Formatu hau 1987an (GIF87a) garatu zuen CompuServe-k sareen bidez raster irudiak transmititzeko. 1989an, formatua aldatu zen (GIF89a), gardentasunerako eta animaziorako euskarria gehitu zen.

GIF fitxategiek bloke-egitura dute. Bloke hauek beti dute luzera finkoa (edo bandera batzuen araberakoa da), beraz ia ezinezkoa da bloke bakoitza non dagoen akatsa egitea. GIF89a formatuan animatu gabeko GIF irudi sinpleenaren egitura:

Esteganografia GIF-n

Egituraren bloke guztien artean, kasu honetan paleta bloke globala eta paletaren ardura duten parametroak interesatuko zaizkigu:

  • CT β€” paleta global baten presentzia. Bandera hau ezartzen bada, paleta globala pantaila logikoaren heldulekuaren ondoren berehala hasi behar da.
  • Size β€” paletaren tamaina eta irudiko kolore kopurua. Parametro honen balioak:

Tamaina
Kolore kopurua
Paletaren tamaina, byteak

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Enkriptatzeko metodoak

Irudi fitxategietan mezuak enkriptatzeko metodo hauek erabiliko dira:

  • LSB (Least Significant Bit) metodoa
  • Paleta gehitzeko metodoa

LSB metodoa - Esteganografia metodo arrunta. Edukiontziko azken bit esanguratsuak (gure kasuan, paleta globalaren byteak) ezkutuko mezuaren bitekin ordezkatzean datza.

Programak paleta globalaren byteetako azken bi bitak erabiliko ditu metodo honen zati gisa. Horrek esan nahi du 24 biteko irudi baterako, non kolore-paleta gorria, urdina eta berdea hiru byte den, mezu bat bertan txertatu ondoren, kolore-osagai bakoitza gehienez 3/255 graduazioz aldatuko dela. Aldaketa hori, lehenik, ikusezina edo zaila izango da giza begiarentzat, eta, bigarrenik, ez da ikusgai izango kalitate baxuko informazioa ateratzeko gailuetan.

Informazio kantitatea irudi-paletaren tamainaren araberakoa izango da zuzenean. Paletaren gehienezko tamaina 256 kolorekoa denez, eta kolore bakoitzaren osagaian bi mezu-bit idazten badira, mezuaren gehienezko luzera (irudian paleta maximoarekin) 192 byte-koa da. Mezua irudian txertatu ondoren, fitxategiaren tamaina ez da aldatzen.

Paleta zabaltzeko metodoa, GIF egiturarako bakarrik funtzionatzen duena. Paleta txikia duten irudietan eraginkorrena izango da. Bere funtsa da paletaren tamaina handitzen duela, eta horrela kolore-byteen ordez beharrezko byteak idazteko espazio gehigarria eskaintzen du. Paletaren gutxieneko tamaina 2 kolorekoa (6 byte) dela kontuan hartzen badugu, kapsulatutako mezuaren gehienezko tamaina 256 Γ— 3–6 = 762 byte izan daiteke. Desabantaila segurtasun kriptografiko baxua da; kapsulatutako mezua edozein testu-editore erabiliz irakur daiteke mezua enkriptazio gehigarririk jasan ez badu.

Zati praktikoa

Programaren diseinua

Enkriptatzeko eta deszifratzeko algoritmoak ezartzeko beharrezko tresna guztiak sartuko dira paketean com.tsarik.steganography. Pakete honek interfazea dakar Encryptor metodoekin encrypt ΠΈ decrypt, Klasea Binary, bit-matrizeekin lan egiteko gaitasuna ematen duena, baita salbuespen klaseekin ere UnableToEncryptException ΠΈ UnableToDecryptException, interfaze-metodoetan erabili behar dena Encryptor hurrenez hurren kodetze eta deskodetze akatsen kasuan.

Programaren pakete nagusia com.tsarik.programs.gifed exekutatu daitekeen programa klase bat sartuko du metodo estatiko batekin main, programa exekutatzeko aukera emanez; programaren parametroak gordetzen dituen klasea; eta beste klase batzuekin paketeak.

Algoritmoen ezarpena beraiek paketean aurkeztuko da com.tsarik.programs.gifed.gif klaseak GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod. Bi klase hauek interfazea ezarriko dute Encryptor.

GIF formatuaren egituran oinarrituta, irudi-paletan mezu bat sartzeko algoritmo orokor bat sor dezakezu:

Esteganografia GIF-n

Irudi batean mezu baten presentzia zehazteko, mezuaren hasieran bit-sekuentzia jakin bat gehitzea beharrezkoa da, deskodetzaileak lehenik irakurtzen duena eta zuzentasuna egiaztatzen duena. Bat ez badator, irudian ezkutuko mezurik ez dagoela uste da. Ondoren, mezuaren luzera zehaztu behar duzu. Ondoren, mezuaren testua bera.

Aplikazio osoaren klase-diagrama:

Esteganografia GIF-n

Programaren ezarpena

Programa osoaren ezarpena bi osagaitan bana daiteke: interfazearen enkriptatzea eta deszifratzeko metodoak ezartzea Encryptor, klaseetan GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod, eta erabiltzailearen interfazearen ezarpena.

Demagun klasea GIFEncryptorByLSBMethod.

Esteganografia GIF-n

eremuak firstLSBit ΠΈ secondLSBit mezua sartu behar den eta mezua nondik irakurri behar den irudiaren byte bakoitzeko bit-kopuruak ditu. Eremua checkSequence kontrol-bit-sekuentzia bat gordetzen du kapsulatutako mezua ezagutzeko. Metodo estatikoa getEncryptingFileParameters zehaztutako fitxategiaren parametroak eta balizko mezuaren ezaugarriak itzultzen ditu.

Metodoaren algoritmoa encrypt class GIFEncryptorByLSBMethod:

Esteganografia GIF-n

Eta bere kodea:

@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();
}

Metodoaren algoritmoa eta iturburu-kodea decrypt class GIFEncryptorByLSBMethod:

Esteganografia GIF-n

@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);
}

Klasearen ezarpena GIFEncryptorByPaletteExtensionMethod antzekoa izango da, informazioa gorde/irakurtzeko metodoa bakarrik desberdina da.

Klasean MainFrame bilgarri metodoak deskribatzen dira: encryptImage(Encryptor encryptor) ΠΈ decryptImage(Encryptor encryptor), interfaze-metodoen emaitzak prozesatzen Encryptor eta erabiltzailearekin interakzioan aritzea, hau da, fitxategiak hautatzeko elkarrizketa-koadroa irekitzea, errore-mezuak erakutsiz, etab.; baita beste metodo batzuk ere: openImage(), erabiltzaileari irudi bat hautatzeko aukera emanez, exit(), aplikaziotik irteten dena. Metodo hauei deitzen zaie Action-ren menuko elementuak. Klase honek, gainera, metodo laguntzaileak inplementatzen ditu: createComponents() - forma osagaiak sortzea, loadImageFile(File f) β€” irudi bat fitxategi batetik osagai berezi batean kargatzea. Klasearen ezarpena GIFEncryptorByPaletteExtensionMethod klasearen ezarpenaren antzekoa GIFEncryptorByLSBMethod, desberdintasun nagusia mezuen byteak paletatik idazteko eta irakurtzeko moduan dago.

Programaren funtzionamendua

LBS metodoa

Demagun honelako irudi bat dagoela:

Esteganografia GIF-n

Irudi honetan, paleta 256 kolorez osatuta dago (Paint-ek gordetzen duen moduan). Lehenengo lau koloreak hauek dira: zuria, beltza, gorria, berdea. Beste kolore batzuk beltzak dira. Paleta bit-sekuentzia globala honako hau izango da:

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

Esteganografia GIF-n

Mezua txertatu ondoren, azpimarratutako bitak mezuko bitekin ordezkatuko dira. Lortutako irudia ez da ia jatorrizkoaren desberdina.

Original
Irudia kapsulatutako mezuarekin

Esteganografia GIF-n
Esteganografia GIF-n

Paleta zabaltzeko metodoa

Metodo hau erabiliz mezu bat duen irudi bat irekitzen duzunean, argazki hau ikusiko duzu:

Esteganografia GIF-n

Argi dago metodo honek ez duela funtzionatuko espioitza-jardueretarako, eta baliteke mezuaren enkriptazio gehigarria behar izatea.

Irudi animatuetan zifratzeak/deszifratzeak ohiko irudi estatikoetan bezala funtzionatzen du, baina animazioa ez da hautsita.

Erabilitako iturriak:

deskargatzeko:

Iturria: www.habr.com

Gehitu iruzkin berria