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:

SUURUS
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

Lisa kommentaar