Steganograafia GIF-is

Sissejuhatus

Tervitused.
Mitte nii kaua aega tagasi, kui ma ĂŒlikoolis Ă”ppisin, oli kursusetöö erialal "Infoturbe tarkvara meetodid". Ülesanne nĂ”udis meilt programmi loomist, mis manustab sĂ”numi GIF-failidesse. Otsustasin seda Javas teha.

Selles artiklis kirjeldan mÔningaid teoreetilisi punkte ja seda, kuidas see vÀike programm loodi.

Teoreetiline osa

GIF-vormingus

GIF (Graphics Interchange Format – piltide vahetamise vorming) on ​​graafiliste piltide salvestamise vorming, mis suudab salvestada tihendatud andmeid ilma kvaliteeti kaotamata kuni 256 vĂ€rvi vormingus. Selle vormingu töötas vĂ€lja 1987. aastal (GIF87a) CompuServe rasterpiltide edastamiseks vĂ”rkude kaudu. 1989. aastal muudeti vormingut (GIF89a), lisati lĂ€bipaistvuse ja animatsiooni tugi.

GIF-failidel on plokistruktuur. Need plokid on alati kindla pikkusega (vÔi see oleneb mÔnest lipust), mistÔttu on peaaegu vÔimatu eksida, kus iga plokk asub. Lihtsaima mitte-animeeritud GIF-pildi struktuur GIF89a-vormingus:

Steganograafia GIF-is

KÔigist struktuuri plokkidest huvitab meid sel juhul globaalne paletiplokk ja paleti eest vastutavad parameetrid:

  • CT — globaalse paleti olemasolu. Kui see lipp on mÀÀratud, peab globaalne palett algama kohe pĂ€rast loogilist ekraanikĂ€epidet.
  • Size — paleti suurus ja vĂ€rvide arv pildil. Selle parameetri vÀÀrtused:

MÔÔt
VĂ€rvide arv
Paleti suurus, baidid

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

KrĂŒpteerimismeetodid

Pildifailides olevate sĂ”numite krĂŒptimiseks kasutatakse jĂ€rgmisi meetodeid.

  • LSB (Least Significant Bit) meetod
  • Paleti lisamise meetod

LSB meetod - levinud steganograafia meetod. See seisneb konteineri viimaste oluliste bittide (meie puhul globaalsete paletibaitide) asendamises peidetud sÔnumi bittidega.

Programm kasutab selle meetodi osana globaalse paleti baitide kahte viimast bitti. See tÀhendab, et 24-bitise pildi puhul, kus punase, sinise ja rohelise vÀrvipalett on kolm baiti, muutub iga vÀrvikomponent pÀrast sellesse sÔnumi manustamist maksimaalselt 3/255 gradatsiooni vÔrra. Selline muutus on esiteks inimsilmale nÀhtamatu vÔi raskesti mÀrgatav ning teiseks ei ole see nÀhtav madala kvaliteediga infovÀljundseadmetel.

Teabe hulk sÔltub otseselt pildipaleti suurusest. Kuna paleti maksimaalne suurus on 256 vÀrvi ja kui iga vÀrvi komponendisse on kirjutatud kaks sÔnumibitti, siis on sÔnumi maksimaalne pikkus (pildil oleva maksimaalse paletiga) 192 baiti. Kui sÔnum on pildile manustatud, ei muutu faili suurus.

Paleti laiendamise meetod, mis töötab ainult GIF-struktuuri jaoks. See on kĂ”ige tĂ”husam vĂ€ikese paletiga piltidel. Selle olemus seisneb selles, et see suurendab paleti suurust, pakkudes seelĂ€bi tĂ€iendavat ruumi vajalike baitide kirjutamiseks vĂ€rvibaitide asemel. Kui arvestada, et paleti minimaalne suurus on 2 vĂ€rvi (6 baiti), siis vĂ”ib manustatud sĂ”numi maksimaalne suurus olla 256 × 3–6 = 762 baiti. Puuduseks on madal krĂŒptograafiline turvalisus; manustatud sĂ”numit saab lugeda mis tahes tekstiredaktoriga, kui sĂ”numit pole tĂ€iendavalt krĂŒpteeritud.

Praktiline osa

Programmi kujundamine

KĂ”ik krĂŒpteerimis- ja dekrĂŒpteerimisalgoritmide rakendamiseks vajalikud tööriistad on komplektis com.tsarik.steganography. See pakett sisaldab liidest Encryptor meetoditega encrypt Đž decrypt, klass Binary, mis annab vĂ”imaluse töötada nii bitimassiividega kui ka erandiklassidega UnableToEncryptException Đž UnableToDecryptException, mida tuleks kasutada liidesemeetodites Encryptor vastavalt kodeerimis- ja dekodeerimisvigade korral.

Peamine programmipakett com.tsarik.programs.gifed sisaldab staatilise meetodiga kÀivitatavat programmiklassi main, mis vÔimaldab teil programmi kÀivitada; klass, mis salvestab programmi parameetreid; ja paketid teiste klassidega.

Algoritmide endi rakendamist tutvustatakse paketis com.tsarik.programs.gifed.gif klassid GIFEncryptorByLSBMethod О GIFEncryptorByPaletteExtensionMethod. MÔlemad klassid rakendavad liidest Encryptor.

GIF-vormingu struktuuri pĂ”hjal saate luua ĂŒldise algoritmi sĂ”numi pildipaletti sisestamiseks:

Steganograafia GIF-is

SĂ”numi olemasolu kindlakstegemiseks pildil on vaja sĂ”numi algusesse lisada teatud bittide jada, mille dekooder esimesena loeb ja Ă”igsust kontrollib. Kui see ei ĂŒhti, siis loetakse, et pildil pole peidetud sĂ”numit. JĂ€rgmisena peate mÀÀrama sĂ”numi pikkuse. Siis sĂ”numi tekst ise.

Kogu rakenduse klassiskeem:

Steganograafia GIF-is

Programmi rakendamine

Kogu programmi rakendamise vĂ”ib jagada kaheks komponendiks: liidese krĂŒpteerimis- ja dekrĂŒpteerimismeetodite rakendamine Encryptor, klassides GIFEncryptorByLSBMethod Đž GIFEncryptorByPaletteExtensionMethodja kasutajaliidese juurutamine.

MÔelge klassile GIFEncryptorByLSBMethod.

Steganograafia GIF-is

vÀljad firstLSBit О secondLSBit sisaldavad kujutise iga baidi bittide arvu, kuhu sÔnum sisestada ja kust sÔnum lugeda. VÀli checkSequence salvestab kontrollbittide jada, et tagada manustatud sÔnumi Àratundmine. Staatiline meetod getEncryptingFileParameters tagastab mÀÀratud faili parameetrid ja potentsiaalse sÔnumi omadused.

Meetodi algoritm encrypt klass GIFEncryptorByLSBMethod:

Steganograafia GIF-is

Ja tema kood:

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

Meetodi algoritm ja lÀhtekood decrypt klass GIFEncryptorByLSBMethod:

Steganograafia GIF-is

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

Klassi rakendamine GIFEncryptorByPaletteExtensionMethod on sarnane, erinev on ainult teabe salvestamise/lugemise meetod.

Klassis MainFrame Kirjeldatakse pakkimismeetodeid: encryptImage(Encryptor encryptor) Đž decryptImage(Encryptor encryptor), töötleb liidesemeetodite tulemusi Encryptor ja kasutajaga suhtlemine, st failivaliku dialoogi avamine, veateadete nĂ€itamine jne; samuti muid meetodeid: openImage(), mis vĂ”imaldab kasutajal valida pildi, exit(), mis rakendusest vĂ€ljub. Neid meetodeid kutsutakse Actionvastavad menĂŒĂŒelemendid. See klass rakendab lisaks abimeetodeid: createComponents() - vormikomponentide loomine, loadImageFile(File f) — pildi laadimine failist spetsiaalsesse komponenti. Klassi rakendamine GIFEncryptorByPaletteExtensionMethod sarnane klassi rakendamisega GIFEncryptorByLSBMethod, peamine erinevus on sĂ”numibaitide kirjutamise ja paleti lugemise viisis.

Programmi toimimine

LBS meetod

Oletame, et on selline pilt:

Steganograafia GIF-is

Sellel pildil koosneb palett 256 vÀrvist (nagu Paint salvestab). Esimesed neli vÀrvi on: valge, must, punane, roheline. Teised vÀrvid on mustad. Globaalne paleti bittide jada on jÀrgmine:

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

Steganograafia GIF-is

Kui sÔnum on manustatud, asendatakse allajoonitud bitid sÔnumi bittidega. Saadud pilt peaaegu ei erine originaalist.

Originaal
Manustatud sÔnumiga pilt

Steganograafia GIF-is
Steganograafia GIF-is

Paleti laiendamise meetod

Kui avate seda meetodit kasutades sÔnumit sisaldava pildi, nÀete jÀrgmist pilti:

Steganograafia GIF-is

On selge, et see meetod ei tööta tĂ€ieĂ”igusliku spionaaĆŸitegevuse jaoks ja vĂ”ib nĂ”uda sĂ”numi tĂ€iendavat krĂŒpteerimist.

Animeeritud piltide krĂŒptimine/dekrĂŒpteerimine toimib nagu tavaliste staatiliste piltide puhul, kuid animatsioon ei katke.

Kasutatud allikad:

Lae alla:

Allikas: www.habr.com

Ostke DDoS-kaitsega saitide jaoks usaldusvÀÀrne hostimine, VPS VDS-serverid đŸ”„ Osta usaldusvÀÀrne veebimajutus DDoS-kaitsega, VPS VDS serverid | ProHoster