Steganoografia në GIF

Hyrje

Përshëndetje.
Jo shumĂ« kohĂ« mĂ« parĂ«, kur isha duke studiuar nĂ« universitet, kisha njĂ« projekt pĂ«r disiplinĂ«n “Metodat software tĂ« mbrojtjes sĂ« informacionit”. Detyra duhej tĂ« pĂ«rfshinte njĂ« program qĂ« futte mesazhin nĂ« skedarĂ«t me format GIF. Vendosa ta realizoj nĂ« Java.

Në këtë artikull do të përshkruaj disa aspekte teorike, si dhe si e krijova këtë program të vogël.

Pjesa Teorike

Formati GIF

GIF (angl. Graphics Interchange Format — format pĂ«r shkĂ«mbimin e imazheve) Ă«shtĂ« njĂ« format ruajtjeje pĂ«r imazhe grafike, qĂ« mund tĂ« ruajĂ« tĂ« dhĂ«na tĂ« kompresuara pa humbur cilĂ«si nĂ« njĂ« format deri nĂ« 256 ngjyra. Ky format u zhvillua nĂ« vitin 1987 (GIF87a) nga firma CompuServe pĂ«r transmetimin e imazheve raster nĂ«pĂ«r rrjeta. NĂ« vitin 1989, formati u modifikua (GIF89a), duke shtuar mbĂ«shtetje pĂ«r transparencĂ« dhe animacion.

Skedarët me format GIF kanë një strukturë bllokesh. Këto blloket gjithmonë kanë një gjatësi fikse (ose ajo varet nga disa flamuj), ndonëse është praktikisht e pamundur të gabosh ku është i vendosur secili bllok. Struktura e një imazhi GIF të thjeshtë të paanimuar në formatin GIF89a:

Steganoografia në GIF

Nga të gjithë blloqet e strukturës, në këtë rast do të na interesojnë blloku i paletës globale dhe parametrat që lidhen me paletën:

  • CT — prania e paletĂ«s globale. NĂ«se ky flag Ă«shtĂ« vendosur, atĂ«herĂ« menjĂ«herĂ« pas pĂ«rshkruesit tĂ« ekranit logjik duhet tĂ« fillojĂ« paleta globale.
  • MadhĂ«sia — madhĂ«sia e paletĂ«s dhe numri i ngjyrave tĂ« imazhit. Vlerat e kĂ«tij parametri:

Madhësia
Numri i ngjyrave
Madhësia e paletës, byte

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Metodat e enkriptimit

Si metoda për enkriptimin e mesazheve në skedarët e imazheve do të përdoren:

  • Metoda LSB (Bitit mĂ« tĂ« rĂ«ndĂ«sishĂ«m tĂ« vogĂ«l)
  • Metoda e plotĂ«simit tĂ« paletĂ«s

Metoda LSB — njĂ« metodĂ« e zakonshme e steganografisĂ«. Ajo pĂ«rfshin zĂ«vendĂ«simin e biteve tĂ« fundit tĂ« rĂ«ndĂ«sishĂ«m nĂ« kontejner (nĂ« rastin tonĂ« byte tĂ« paletĂ«s globale) me bitĂ«t e mesazhit tĂ« fshehur.

Në program do të përdoren dy bitet e fundit në bajtat e paletës globale në kuadër të këtij metode. Kjo do të thotë se për një imazh 24-bitësh, ku ngjyra e paletës përfaqëson tre bajta për ngjyrat e kuqe, blu dhe jeshile, pas futurjes së mesazhit në të, çdo komponent ngjyre do të ndryshojë maksimumi në 3/255 gradacione. Ky ndryshim, nga njëra anë, do të jetë i padukshëm ose i vështirë për tu vënë re nga syri njerëzor, dhe nga ana tjetër, nuk do të jetë i dallueshëm në pajisjet e ulta cilësore të output-it.

Shuma e informacionit do të varet drejtpërdrejt nga madhësia e paletës së imazhit. Duke qenë se madhësia maksimale e paletës është 256 ngjyra dhe, nëse shkruhen dy bitë mesazhi në komponentin e çdo ngjyre, atëherë gjatësia maksimale e mesazhit (në paletën maksimale në imazh) arrin deri në 192 bajtë. Pas futjes së mesazhit në imazh, madhësia e skedarit nuk ndryshon.

Metoda e zgjerimit tĂ« paletĂ«s, qĂ« funksionon vetĂ«m pĂ«r strukturĂ«n GIF. Ai do tĂ« jetĂ« mĂ« efikas nĂ« imazhet me njĂ« paletĂ« tĂ« vogĂ«l. QĂ«llimi i tij Ă«shtĂ« qĂ« tĂ« rrisĂ« madhĂ«sinĂ« e paletĂ«s, duke ofruar kĂ«shtu hapĂ«sirĂ« shtesĂ« pĂ«r regjistrimin e bajtave tĂ« nevojshĂ«m nĂ« vendin e bajtave tĂ« ngjyrave. Duke marrĂ« parasysh se madhĂ«sia minimale e paletĂ«s Ă«shtĂ« 2 ngjyra (6 bajta), atĂ«herĂ« madhĂ«sia maksimale e mesazhit tĂ« inkorporuar mund tĂ« jetĂ« 256×3–6=762 bajta. Disavantazhi — sigurimi i ulĂ«t, mesazhi i inkorporuar mund tĂ« lexohen me çdo redaktues teksti, nĂ«se mesazhi nuk Ă«shtĂ« nĂ«nshtruar kodimit tĂ« mĂ«tejshĂ«m.

Pjesa praktike

Projektimi i programit

Të gjitha mjetet e nevojshme për realizimin e algoritmeve të kodimit dhe dekodimit do të jenë në paketën com.tsarik.steganography. Kjo paketë përfshin ndërfaqen Encryptor me metodat encrypt dhe decrypt, klasi Binary, duke ofruar mundësinë për të punuar me grupe bitësh, si dhe klasat e përjashtimeve UnableToEncryptException dhe UnableToDecryptException, të cilat duhet të përdoren në metodat e ndërfaqes Encryptor në rast gabimesh në kodim dhe dekodim përkatësisht.

Paketë kryesore e programit com.tsarik.programs.gifed do të përfshijë një klasë të programit të nisur me një metodë statike main, e cila lejon nisjen e programit; një klasë që mban parametrat e programit; dhe paketa me klasa të tjera.

Implementimi i algoritmeve do të paraqitet në paketën com.tsarik.programs.gifed.gif klasat GIFEncryptorByLSBMethod dhe GIFEncryptorByPaletteExtensionMethod. Të dyja këto klasa do të realizojnë interfacinë Encryptor.

Në bazë të strukturës së formatit GIF, mund të krijohet një algoritëm i përgjithshëm për futjen e mesazhit në paletën e imazhit:

Steganoografia në GIF

Për të përcaktuar praninë e mesazhit në imazh, është e nevojshme që në fillim të mesazhit të shtohet një sekuencë e caktuar bitësh, që dekoduesi e lexon së pari dhe kontrollon për saktësinë. Nëse ajo nuk përputhet, atëherë mendohet se nuk ka mesazh të fshehur në imazh. Më pas duhet të specifikohet gjatësi e mesazhit. Pastaj vetë teksti i mesazhit.

Diagrami i klasave të aplikacionit të gjithë:

Steganoografia në GIF

Implementimi i programit

Implementimi i të gjithë programit mund të ndahet në dy përbërës: implementimi i metodave të enkriptimeve dhe dekrypton të interfacinë Encryptor, në klasat GIFEncryptorByLSBMethod dhe GIFEncryptorByPaletteExtensionMethod, dhe implementimi i interfesës së përdoruesit.

Le të shqyrtojmë klasën GIFEncryptorByLSBMethod.

Steganoografia në GIF

Fushat firstLSBit dhe secondLSBit përmbajnë numrat e bitëve të çdo byte të imazhit, në të cilat duhet të regjistrohet dhe nga ku duhet të lexohen mesazhet. Fusha checkSequence ruan një sekuencë kontrolli bitësh për të siguruar njohjen e mesazhit të integruar. Metoda statike getEncryptingFileParameters kthen parametrat e skedarit të specifikuar dhe karakteristikat e mesazhit potencial.

Algoritmi i metodës encrypt klasës GIFEncryptorByLSBMethod:

Steganoografia në GIF

Dhe kodi i tij:

@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");
	}
	
	// lexoni bajt nga skedari hyrës
	byte[] bytes = new byte[(int)in.length()];
	InputStream is = new FileInputStream(in);
	is.read(bytes);
	is.close();
	
	// kontrolloni formatin
	if (!(new String(bytes, 0, 6)).equals("GIF89a")) {
		throw new UnableToEncodeException("Skedari hyrës ka format të gabuar GIF");
	}
	
	// lexoni pronën e madhësisë së paletës nga tri bitët e para në bajtin e 10-të nga skedari
	byte[] b10 = Binary.toBitArray(bytes[10]);
	byte bsize = Binary.toByte(new byte[] {b10[0], b10[1], b10[2]});
	
	// llogaritni numrin e ngjyrave dhe gjatësi të mundshme të mesazhit
	int bOrigColorCount = (int)Math.pow(2, bsize+1);
	int possibleMessageLength = bOrigColorCount*3/4;
	int possibleTextLength = possibleMessageLength-2; // një bajt për verifikim dhe një bajt për gjatësi të mesazhit
	
	if (possibleTextLength < text.length()) {
		throw new UnableToEncodeException("Teksti është shumë i madh");
	}
	
	int n = 13;
	
	// shkruani sekuencën e kontrollit
	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++;
	}
	
	// shkruani gjatësi e tekstit
	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++;
	}
	
	// shkruani mesazhin
	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++;
		}
	}
	
	// shkruani skedarin e daljes
	OutputStream os = new FileOutputStream(out);
	os.write(bytes);
	os.close();
}

Algoritmi dhe kodi burimor i metodës decrypt klasës GIFEncryptorByLSBMethod:

Steganoografia në GIF

@Override
public String decrypt(File in) throws UnableToDecodeException, NullPointerException, IOException {
	if (in == null) {
		throw new NullPointerException("Input file is null");
	}
	
	// lexoni bajtat nga skedari i inputit
	byte[] bytes = new byte[(int)in.length()];
	InputStream is = new FileInputStream(in);
	is.read(bytes);
	is.close();
	
	// kontrolloni formatin
	if (!(new String(bytes, 0, 6)).equals("GIF89a")) {
		throw new UnableToDecodeException("Input file has wrong GIF format");
	}
	
	// lexoni pronën e madhësisë së paletës nga tre bitët e parë në bajtin e 10-të nga skedari
	byte[] b10 = Binary.toBitArray(bytes[10]);
	byte bsize = Binary.toByte(new byte[] {b10[0], b10[1], b10[2]});
	
	// llogaritni numrin e ngjyrave dhe gjatësinë e mundshme të mesazhit
	int bOrigColorCount = (int)Math.pow(2, bsize+1);
	int possibleMessageLength = bOrigColorCount*3/4;
	int possibleTextLength = possibleMessageLength-2;	// një bajt për kontroll dhe një bajt për gjatësinë e mesazhit
	
	int n = 13;
	
	// lexoni sekuencën e kontrollit
	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)");
	}
	
	// lexoni gjatësinë e tekstit
	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 + "))");
	}
	
	// lexoni bajtat e teksti dhe bëni bajtat e tekstit
	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);
}

Implementimi i klasës GIFEncryptorByPaletteExtensionMethod do të jetë i ngjashëm, vetëm se ndryshon metoda e ruajtjes/leximit të informacionit.

NĂ« klasĂ«n MainFrame janĂ« pĂ«rshkruar metodat-«mbĂ«shtjellĂ«se»: encryptImage(Encryptor encryptor) dhe decryptImage(Encryptor encryptor), qĂ« pĂ«rpunojnĂ« rezultatet e metodave tĂ« ndĂ«rfaqes Encryptor dhe realizojnĂ« ndĂ«rveprimin me pĂ«rdoruesin, domethĂ«nĂ« hapin dialogun pĂ«r zgjedhjen e skedarĂ«ve, tregojnĂ« mesazhe gabimi etj.; si edhe metodat e tjera: openImage(), qĂ« i jep pĂ«rdoruesit mundĂ«sinĂ« pĂ«r tĂ« zgjedhur njĂ« imazh, exit(), qĂ« realizon daljen nga aplikacioni. KĂ«to metoda thirren nga Veprimi‘at e pikave pĂ«rkatĂ«se tĂ« menusĂ«. NĂ« kĂ«tĂ« klasĂ« janĂ« realizuar gjithashtu metoda ndihmĂ«se: createComponents() — krijimi i komponentĂ«ve tĂ« formĂ«s, loadImageFile(File f) — ngarkimi i imazhit nĂ« njĂ« komponent tĂ« veçantĂ« nga njĂ« skedar. Implementimi i klasĂ«s GIFEncryptorByPaletteExtensionMethod Ă«shtĂ« i ngjashĂ«m me implementimin e klasĂ«s GIFEncryptorByLSBMethod, dallimi kryesor qĂ«ndron nĂ« mĂ«nyrĂ«n e shkrimit dhe leximit tĂ« bajtĂ«ve tĂ« mesazhit nga paleta.

Puna e programit

Metoda LBS

Supozoni se ka një imazh të tillë:

Steganoografia në GIF

Në këtë imazh, paleta përbëhet nga 256 ngjyra (si ruan Paint). Ngjyrat e para katër: të bardhë, të zezë, të kuqe, të gjelbër. Ngjyrat e tjera janë të zeza. Renditja e bitëve të paletës globale do të jetë si më poshtë:

11111111 11111111 11111111 00000000 00000000 00000000 11111111 00000000 00000000 00000000 11111111 00000000


Steganoografia në GIF

Pas inkorporimit të mesazhit, bitët e theksuar do të zëvendësohen me bitët nga mesazhi. Imazhi i marrë është pothuajse identik me origjinalin.

Origjinali
Imazhi me mesazhin e inkorporuar

Steganoografia në GIF
Steganoografia në GIF

Metoda e zgjerimit të paletës

Duke hapur imazhin në të cilin është vendosur mesazhi me këtë metodë, mund të hasni një pamje të tillë:

Steganoografia në GIF

ËshtĂ« e qartĂ« se pĂ«r aktivitetet e plota spiunazhi, njĂ« metodĂ« e tillĂ« nuk do tĂ« funksionojĂ« dhe kĂ«rkon, ndoshta, njĂ« enkriptim tĂ« mĂ«tejshĂ«m tĂ« mesazhit.

Enkriptimi/zhbllokimi në imazhet e animuara funksionon ashtu si në imazhet statike normale, duke mos e prishur animacionin.

Burimet e përdorura:

Shkarko:

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster