Steganografia në GIF

Hyrje

Përshëndetje.
Së fundmi, ndërsa studionja në universitet, pata një punim për disiplinën "Metodat softuerike të mbrojtjes së informacionit". Sipas detyrës, duhej të bëja një program që integronte një mesazh në skedarët e formatit GIF. Vendosa ta realizoja atë në Java.

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

Pjesa teorike

Formati GIF

GIF (angl. Graphics Interchange Format - formati për shkëmbimin e imazheve) është një format për ruajtjen e imazheve grafike, në gjëndje të ruajë të dhëna të kompresuara pa humbje cilësie në format deri në 256 ngjyra. Ky format u zhvillua në vitin 1987 (GIF87a) nga kompania CompuServe për transmetimin e imazheve raster nëpër rrjete. Në vitin 1989, formati u modifikua (GIF89a), u shtua mbështetje për transparencën dhe animacionin.

Skedarët e formatit GIF kanë një strukturë bllokesh. Të dhënat e blloqeve kanë gjithmonë një gjatësi fikse (ose ajo varet nga disa flags), kështu që është pothuajse e pamundur të gabosh se ku ndodhet cila bllok. Struktura e një GIF-i të thjeshtë jo-animuar në formatin GIF89a:

Steganografia në GIF

Nga të gjithë blloqet e strukturës, në këtë rast do të na interesojnë blloku i paletës globale dhe parametrit që përgjigjen për paletën:

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

Size
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 (Bit i PaktĂ« mĂ« tĂ« RendĂ«sishĂ«m)
  • Metoda e plotĂ«simit tĂ« paletĂ«s

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

Në program do të përdoren dy bita të fundit në bajtat e paletës globale. Kjo do të thotë se për një imazh 24-bit, ku ngjyra e paletës përfaqëson tre bajta për ngjyrat e kuqe, blu dhe të gjelbër, pas përfshirjes së mesazhit, çdo komponent ngjyre do të ndryshojë maksimumi në 3/255 gradacione. Ky ndryshim, së pari, do të jetë i padukshëm ose i vështirë për t'u vërejtur nga syri njerëzor, dhe së dyti, nuk do të jetë i dallueshëm në pajisjet e ulëta të cilësisë.

Sasia 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 regjistrohen dy bita të mesazhit në çdo komponent ngjyre, maksimumi i gjatësi së mesazhit (në paletën maksimale në imazh) është 192 bajta. Pas përfshirjes së mesazhit në imazh, madhësia e skedarit nuk ndryshon.

Metoda e zgjerimit tĂ« paletĂ«s, e cila punon vetĂ«m pĂ«r strukturĂ«n GIF. Ajo do tĂ« jetĂ« mĂ« efektive nĂ« imazhet me paleta tĂ« vogla. Thelbi i saj qĂ«ndron nĂ« rritjen e madhĂ«sisĂ« sĂ« paletĂ«s, duke i dhĂ«nĂ« kĂ«shtu hapĂ«sirĂ« tĂ« shtuar pĂ«r regjistrimin e bajtave tĂ« nevojshĂ«m nĂ« vendin e bajtave tĂ« ngjyrave. NĂ«se merret parasysh se madhĂ«sia minimale e paletĂ«s Ă«shtĂ« 2 ngjyra (6 bajta), atĂ«herĂ« madhĂ«sia maksimale e mesazhit tĂ« pĂ«rfshirĂ« mund tĂ« jetĂ« 256×3–6=762 bajta. Disavantazhi — siguria e ulĂ«t, mesazhi i pĂ«rfshirĂ« mund tĂ« lexohet nga çdo redaktor teksti, nĂ«se mesazhi nuk Ă«shtĂ« nĂ«ndeshur me ndonjĂ« enkriptim shtesĂ«.

Pjesa praktike

Projektimi i programit

Të gjitha mjetet e nevojshme për realizimin e algoritmeve të enkriptimit dhe dekriptimit do të gjenden në paketën com.tsarik.steganography. Kjo paketë përfshin ndërfaqen Encryptor me metodat encrypt dhe decrypt, klasa Binary, që ofron mundësinë për të punuar me arrays bitesh, si dhe klasat e përjashtimit UnableToEncryptException dhe UnableToDecryptException, që duhet të përdoren në metodat e ndërfaqes Encryptor në rast të gabimeve të kodimit dhe dekodimit përkatësisht.

Pakoja kryesore e programit com.tsarik.programs.gifed do të përfshijë klasën e ekzekutueshme të programit me metodën statike main, e cila lejon fillimin e programit; klasa që ruan parametrat e programit; dhe paketat me klasa të tjera.

Zbatimi i algoritmeve të vetë do të paraqitet në paketë com.tsarik.programs.gifed.gif klasat GIFEncryptorByLSBMethod dhe GIFEncryptorByPaletteExtensionMethod. Të dy këto klasa do të implementojnë ndërfaqen Encryptor.

Në bazë të strukturës së formatit GIF mund të përpilojmë një algoritëm të përgjithshëm për integrimin e një mesazhi në paletën e imazhit:

Steganografia 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, të cilën dekuruesi e lexon në radhë të parë dhe kontrollon për saktësi. Nëse ajo nuk përputhet, atëherë konsiderohet se nuk ka mesazh të fshehur në imazh. Më pas duhet të tregoni gjatësinë e mesazhit. Pas kësaj, vetë teksti i mesazhit.

Diagrami i klasave të tërë aplikacionit:

Steganografia në GIF

Zbatimi i programit

Zbatimi i tërë programit mund të ndahet në dy komponentë: implementimi i metodave të enkriptimit dhe dekriptimit të ndërfaqes Encryptor, në klasat GIFEncryptorByLSBMethod dhe GIFEncryptorByPaletteExtensionMethod, dhe zbatimi i ndërfaqes së përdoruesit.

Le të shqyrtojmë klasën GIFEncryptorByLSBMethod.

Steganografia në GIF

Fushat firstLSBit dhe secondLSBit përmbajnë numrat e bitëve të çdo byte të imazhit, në të cilat duhen vendosur dhe prej nga duhen lexuar mesazhi. Fusha checkSequence ruan sekuencën kontroluese të bitëve për sigurimin e njohjes së mesazhit të integruar. Metoda statike getEncryptingFileParameters kthen parametrat e skedarit të dhënë dhe karakteristikat e mundshme të mesazhit.

Algoritmi i metodës encrypt klasës GIFEncryptorByLSBMethod:

Steganografia 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 bajtat 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("Input file has wrong GIF format");
	}
	
	// lexoni pronën e madhësisë së paletave 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ë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ësi të mesazhit
	
	if (possibleTextLength < text.length()) {
		throw new UnableToEncodeException("Text is too big");
	}
	
	int n = 13;
	
	// shkruaj 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++;
	}
	
	// shkruaj gjatësi të 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++;
	}
	
	// shkruaj 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++;
		}
	}
	
	// shkruaj skedarin e daljes
	OutputStream os = new FileOutputStream(out);
	os.write(bytes);
	os.close();
}

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

Steganografia në GIF

@Override
public String decrypt(File in) throws UnableToDecodeException, NullPointerException, IOException {
	if (in == null) {
		throw new NullPointerException("Input file is null");
	}
	
	// lexho 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);
}

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

NĂ« klasĂ«n MainFrame janĂ« pĂ«rshkruar metodat-«mbĂ«shtjellĂ«se»: encryptImage(Encryptor encryptor) dhe decryptImage(Encryptor encryptor), duke pĂ«rpunuar rezultatet e metodave tĂ« interfesĂ«s Encryptor dhe duke realizuar ndĂ«rveprimin me pĂ«rdoruesin, pra hapen dialogĂ« pĂ«rzgjedhjeje skedelli, tregojnĂ« mesazhe gabimish etj.; si dhe metoda tĂ« tjera: openImage(), e cila i jep mundĂ«sinĂ« pĂ«rdoruesit tĂ« zgjedhĂ« njĂ« imazh, exit(), qĂ« realizon daljen nga aplikacioni. KĂ«to metoda thirren nga Veprimi‘t e pikave pĂ«rkatĂ«se tĂ« menusĂ«. NĂ« kĂ«tĂ« klasĂ« janĂ« implementuar gjithashtu metoda ndihmĂ«se: createComponents() — krijimi i komponenteve tĂ« formĂ«s, loadImageFile(File f) — ngarkimi i imazhit nĂ« njĂ« komponent tĂ« veçantĂ« nga skedari. Implementimi i klasĂ«s GIFEncryptorByPaletteExtensionMethod Ă«shtĂ« i ngjashĂ«m me implementimin e klasĂ«s GIFEncryptorByLSBMethod, dallimi kryesor qĂ«ndron nĂ« mĂ«nyrĂ«n e shkruarjes dhe leximit tĂ« bajtĂ«ve tĂ« mesazhit nga paleta.

Funksioni i programit

Metoda LBS

Njëherë le të supozojmë se ka një imazh të tillë:

Steganografia në GIF

Në këtë imazh, paleta përbëhet nga 256 ngjyra (në këtë mënyrë ruan Paint). Katër ngjyrat e para: e bardhë, e zezë, e kuqe, e gjelbër. Ngjyrat e tjera janë të zeza. Sekuenca 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


Steganografia në GIF

Pas implementimit, bitët e theksuar do të zëvendësohen me bitët nga mesazhi. Imazhi i marrë ndryshon pak nga origjinali.

Originali
Imazhi me mesazhin e implementuar

Steganografia në GIF
Steganografia 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ë:

Steganografia në GIF

Natyrisht, që kjo metodë nuk është e përshtatshme për aktivitete të plota spiunazhi, dhe kërkon, ndoshta, një enkriptim të mëtejshëm të mesazhit.

Enkriptimi/dekriptimi në imazhet e animuar funksionon si në imazhet statike normale, pa prishur animacionin.

Burimet e përdorura:

Shkarko:

Burimi: habr.com

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