Steganografia katika GIF

Utangulizi

Salamu.
Sio zamani sana, nilipokuwa nikisoma chuo kikuu, kulikuwa na kozi katika taaluma "Njia za programu za usalama wa habari." Jukumu lilituhitaji kuunda programu inayopachika ujumbe katika faili za GIF. Niliamua kuifanya katika Java.

Katika makala hii nitaelezea baadhi ya pointi za kinadharia, pamoja na jinsi programu hii ndogo iliundwa.

Sehemu ya kinadharia

Muundo wa GIF

GIF (Muundo wa Maingiliano ya Picha - umbizo la kubadilishana picha) ni umbizo la kuhifadhi picha za picha, zenye uwezo wa kuhifadhi data iliyobanwa bila kupoteza ubora katika umbizo la hadi rangi 256. Umbizo hili lilianzishwa mwaka wa 1987 (GIF87a) na CompuServe kwa ajili ya kusambaza picha mbaya zaidi kwenye mitandao. Mnamo 1989, muundo ulibadilishwa (GIF89a), usaidizi wa uwazi na uhuishaji uliongezwa.

Faili za GIF zina muundo wa kuzuia. Vitalu hivi kila wakati huwa na urefu uliowekwa (au inategemea bendera kadhaa), kwa hivyo karibu haiwezekani kufanya makosa kuhusu mahali ambapo kila kizuizi kinapatikana. Muundo wa picha rahisi zaidi ya GIF isiyohuishwa katika umbizo la GIF89a:

Steganografia katika GIF

Kati ya vizuizi vyote vya muundo, katika kesi hii tutavutiwa na kizuizi cha palette ya ulimwengu na vigezo vinavyohusika na palette:

  • CT - uwepo wa palette ya kimataifa. Ikiwa bendera hii imewekwa, paleti ya kimataifa lazima ianze mara tu baada ya mpini wa skrini wenye mantiki.
  • Size β€” saizi ya palette na idadi ya rangi kwenye picha. Thamani za parameter hii:

ukubwa
Idadi ya rangi
Ukubwa wa palette, ka

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Mbinu za usimbaji fiche

Mbinu zifuatazo zitatumika kusimba ujumbe katika faili za picha:

  • Mbinu ya LSB (Isiyo Muhimu Zaidi).
  • Njia ya kuongeza palette

Mbinu ya LSB - njia ya kawaida ya steganografia. Inajumuisha kubadilisha biti muhimu za mwisho kwenye kontena (kwa upande wetu, baiti za palette za ulimwengu) na biti za ujumbe uliofichwa.

Programu itatumia biti mbili za mwisho katika baiti za palette za kimataifa kama sehemu ya njia hii. Hii ina maana kwamba kwa picha ya 24-bit, ambapo palette ya rangi ni ka tatu kwa nyekundu, bluu, na kijani, baada ya kupachika ujumbe ndani yake, kila sehemu ya rangi itabadilika kwa kiwango cha juu cha 3/255 gradations. Mabadiliko kama hayo, kwanza, hayataonekana au ni ngumu kuyaona kwa macho ya mwanadamu, na pili, hayataonekana kwenye vifaa vya ubora wa chini vya pato la habari.

Kiasi cha habari kitategemea moja kwa moja ukubwa wa palette ya picha. Kwa kuwa ukubwa wa juu wa palette ni rangi 256, na ikiwa bits mbili za ujumbe zimeandikwa kwenye sehemu ya kila rangi, basi urefu wa juu wa ujumbe (pamoja na palette ya juu kwenye picha) ni 192 byte. Mara tu ujumbe unapoingia kwenye picha, saizi ya faili haibadilika.

Njia ya upanuzi wa palette, ambayo inafanya kazi kwa muundo wa GIF pekee. Itakuwa na ufanisi zaidi kwenye picha na palette ndogo. Kiini chake ni kwamba huongeza ukubwa wa palette, na hivyo kutoa nafasi ya ziada ya kuandika byte muhimu mahali pa byte za rangi. Ikiwa tunazingatia kwamba ukubwa wa chini wa palette ni rangi 2 (6 byte), basi ukubwa wa juu wa ujumbe ulioingia unaweza kuwa 256 Γ— 3-6 = 762 bytes. Ubaya ni usalama mdogo wa kriptografia; ujumbe uliopachikwa unaweza kusomwa kwa kutumia kihariri chochote cha maandishi ikiwa ujumbe haujawekewa usimbaji fiche wa ziada.

Sehemu ya manufaa

Ubunifu wa programu

Zana zote muhimu za kutekeleza usimbaji fiche na usimbaji fiche zitajumuishwa kwenye kifurushi com.tsarik.steganography. Kifurushi hiki kinajumuisha kiolesura Encryptor na mbinu encrypt ΠΈ decrypt, Darasa Binary, ambayo hutoa uwezo wa kufanya kazi na safu kidogo, pamoja na madarasa ya ubaguzi UnableToEncryptException ΠΈ UnableToDecryptException, ambayo inapaswa kutumika katika njia za interface Encryptor katika kesi ya makosa ya usimbaji na usimbaji mtawalia.

Kifurushi kikuu cha programu com.tsarik.programs.gifed itajumuisha darasa la programu inayoweza kukimbia na njia tuli main, hukuruhusu kuendesha programu; darasa ambalo huhifadhi vigezo vya programu; na vifurushi na madarasa mengine.

Utekelezaji wa algorithms wenyewe utawasilishwa kwenye kifurushi com.tsarik.programs.gifed.gif madarasa GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod. Madarasa haya yote mawili yatatumia kiolesura Encryptor.

Kulingana na muundo wa umbizo la GIF, unaweza kuunda algorithm ya jumla ya kutambulisha ujumbe kwenye paji la picha:

Steganografia katika GIF

Kuamua uwepo wa ujumbe kwenye picha, ni muhimu kuongeza mlolongo fulani wa bits mwanzoni mwa ujumbe, ambayo decoder inasoma kwanza na kuangalia kwa usahihi. Ikiwa hailingani, basi inachukuliwa kuwa hakuna ujumbe uliofichwa kwenye picha. Ifuatayo, unahitaji kutaja urefu wa ujumbe. Kisha maandishi ya ujumbe yenyewe.

Mchoro wa darasa la programu nzima:

Steganografia katika GIF

Utekelezaji wa programu

Utekelezaji wa mpango mzima unaweza kugawanywa katika vipengele viwili: utekelezaji wa usimbaji wa kiolesura na mbinu za usimbuaji Encryptor, katika madarasa GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod, na utekelezaji wa kiolesura cha mtumiaji.

Fikiria darasa GIFEncryptorByLSBMethod.

Steganografia katika GIF

mashamba firstLSBit ΠΈ secondLSBit vyenye nambari za biti za kila baiti ya picha ambayo ujumbe unapaswa kuingizwa na kutoka ambapo ujumbe unapaswa kusomwa. Shamba checkSequence huhifadhi mfuatano wa biti ya udhibiti ili kuhakikisha utambuzi wa ujumbe uliopachikwa. Mbinu tuli getEncryptingFileParameters inarudisha vigezo vya faili maalum na sifa za ujumbe unaowezekana.

Njia ya algorithm encrypt tabaka la GIFEncryptorByLSBMethod:

Steganografia katika GIF

Na kanuni yake:

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

Algorithm na msimbo wa chanzo wa njia decrypt tabaka la GIFEncryptorByLSBMethod:

Steganografia katika 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);
}

Utekelezaji wa darasa GIFEncryptorByPaletteExtensionMethod itakuwa sawa, njia pekee ya kuhifadhi/kusoma habari ndiyo tofauti.

Darasani MainFrame Njia za kuoka zimeelezewa: encryptImage(Encryptor encryptor) ΠΈ decryptImage(Encryptor encryptor), usindikaji matokeo ya mbinu za interface Encryptor na kuingiliana na mtumiaji, yaani, kufungua kidadisi cha uteuzi wa faili, kuonyesha ujumbe wa makosa, n.k.; pamoja na njia zingine: openImage(), kuruhusu mtumiaji kuchagua picha, exit(), ambayo huacha programu. Njia hizi zinaitwa kutoka Actionvipengee vya menyu vinavyolingana. Darasa hili pia hutumia njia za msaidizi: createComponents() - kuunda vipengele vya fomu; loadImageFile(File f) β€” kupakia picha katika sehemu maalum kutoka kwa faili. Utekelezaji wa darasa GIFEncryptorByPaletteExtensionMethod sawa na utekelezaji wa darasa GIFEncryptorByLSBMethod, tofauti kuu ni katika njia ya kaiti za ujumbe zimeandikwa na kusomwa kutoka kwa palette.

Uendeshaji wa programu

Mbinu ya LBS

Wacha tuseme kuna picha kama hii:

Steganografia katika GIF

Katika picha hii, palette ina rangi 256 (kama Rangi huokoa). Rangi nne za kwanza ni: nyeupe, nyeusi, nyekundu, kijani. Rangi nyingine ni nyeusi. Mlolongo wa biti ya palette ya ulimwengu utakuwa kama ifuatavyo:

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

Steganografia katika GIF

Mara baada ya ujumbe kupachikwa, biti zilizopigiwa mstari zitabadilishwa na biti kutoka kwa ujumbe. Picha inayotokana ni karibu hakuna tofauti na ya awali.

Original
Picha iliyo na ujumbe uliopachikwa

Steganografia katika GIF
Steganografia katika GIF

Njia ya upanuzi wa palette

Unapofungua picha iliyo na ujumbe kwa kutumia njia hii, utaona picha ifuatayo:

Steganografia katika GIF

Ni wazi kuwa njia hii haitafanya kazi kwa shughuli kamili za ujasusi, na inaweza kuhitaji usimbaji fiche wa ziada wa ujumbe.

Usimbaji fiche/usimbuaji katika picha zilizohuishwa hufanya kazi kama katika picha tuli za kawaida, lakini uhuishaji haujavunjwa.

Vyanzo vilivyotumika:

Kushusha:

Chanzo: mapenzi.com

Kuongeza maoni