Steganografija v GIF

Predstavitev

Pozdravljeni.
Ne tako dolgo nazaj, ko sem študiral na univerzi, je potekalo predavanje v disciplini "Programske metode informacijske varnosti." Naloga je zahtevala, da ustvarimo program, ki vdela sporočilo v datoteke GIF. Odločil sem se, da bom to naredil v Javi.

V tem članku bom opisal nekaj teoretičnih točk in kako je nastal ta majhen program.

Teoretični del

format GIF

GIF (Graphics Interchange Format - format za izmenjavo slik) je format za shranjevanje grafičnih slik, zmožen shranjevanja stisnjenih podatkov brez izgube kakovosti v formatu do 256 barv. Ta format je leta 1987 (GIF87a) razvil CompuServe za prenos rastrskih slik po omrežjih. Leta 1989 je bil format spremenjen (GIF89a), dodana je bila podpora za preglednost in animacijo.

Datoteke GIF imajo strukturo blokov. Ti bloki imajo vedno fiksno dolžino (oz. je ta odvisna od nekaterih zastavic), tako da je skoraj nemogoče narediti napako, kje se kateri blok nahaja. Struktura najpreprostejše neanimirane slike GIF v formatu GIF89a:

Steganografija v GIF

Od vseh blokov strukture nas bo v tem primeru zanimal globalni blok palete in parametri, odgovorni za paleto:

  • CT — prisotnost globalne palete. Če je ta zastavica nastavljena, se mora globalna paleta začeti takoj za logično ročico zaslona.
  • Size — velikost palete in število barv na sliki. Vrednosti za ta parameter:

Velikosti
Število barv
Velikost palete, bajti

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Metode šifriranja

Za šifriranje sporočil v slikovnih datotekah bodo uporabljene naslednje metode:

  • Metoda LSB (najmanj pomembni bit).
  • Metoda dodajanja palete

LSB metoda - običajna metoda steganografije. Sestoji iz zamenjave zadnjih pomembnih bitov v vsebniku (v našem primeru bajtov globalne palete) z bitmi skritega sporočila.

Program bo kot del te metode uporabil zadnja dva bita v bajtih globalne palete. To pomeni, da se bo za 24-bitno sliko, kjer barvna paleta obsega tri bajte za rdečo, modro in zeleno, po vdelavi sporočila vanjo vsaka barvna komponenta spremenila za največ 3/255 gradacije. Takšna sprememba bo, prvič, nevidna ali težko opazna za človeško oko, in drugič, ne bo vidna na napravah za izhod informacij nizke kakovosti.

Količina informacij bo neposredno odvisna od velikosti palete slik. Ker je največja velikost palete 256 barv in če sta v komponento vsake barve zapisana dva bita sporočila, je največja dolžina sporočila (z največjo paleto na sliki) 192 bajtov. Ko je sporočilo vdelano v sliko, se velikost datoteke ne spremeni.

Metoda razširitve palete, ki deluje samo za strukturo GIF. Najbolj učinkovito bo na slikah z majhno paleto. Njegovo bistvo je, da poveča velikost palete in s tem zagotovi dodaten prostor za zapisovanje potrebnih bajtov namesto barvnih bajtov. Če upoštevamo, da je najmanjša velikost palete 2 barvi (6 bajtov), ​​potem je lahko največja velikost vdelanega sporočila 256 × 3–6 = 762 bajtov. Pomanjkljivost je nizka kriptografska varnost, vdelano sporočilo je mogoče prebrati s katerim koli urejevalnikom besedil, če sporočilo ni dodatno šifrirano.

Praktični del

Oblikovanje programa

V paketu bodo vključena vsa potrebna orodja za implementacijo algoritmov šifriranja in dešifriranja com.tsarik.steganography. Ta paket vključuje vmesnik Encryptor z metodami encrypt и decrypt, Razred Binary, ki omogoča delo z bitnimi nizi, pa tudi z izjemnimi razredi UnableToEncryptException и UnableToDecryptException, ki naj bi se uporabljal v metodah vmesnika Encryptor v primeru napak pri kodiranju oziroma dekodiranju.

Glavni programski paket com.tsarik.programs.gifed bo vključeval zagonski programski razred s statično metodo main, ki vam omogoča zagon programa; razred, ki shranjuje parametre programa; in paketi z drugimi razredi.

V paketu bo predstavljena implementacija samih algoritmov com.tsarik.programs.gifed.gif razredi GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Oba razreda bosta izvajala vmesnik Encryptor.

Na podlagi strukture formata GIF lahko ustvarite splošni algoritem za vnos sporočila v slikovno paleto:

Steganografija v GIF

Za ugotavljanje prisotnosti sporočila v sliki je treba na začetek sporočila dodati določeno zaporedje bitov, ki jih dekoder najprej prebere in preveri pravilnost. Če se ne ujema, se šteje, da na sliki ni skritega sporočila. Nato morate določiti dolžino sporočila. Nato samo besedilo sporočila.

Diagram razredov celotne aplikacije:

Steganografija v GIF

Izvedba programa

Izvedbo celotnega programa lahko razdelimo na dve komponenti: implementacijo metode šifriranja vmesnika in metode dešifriranja Encryptor, v razredih GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, in implementacijo uporabniškega vmesnika.

Upoštevajte razred GIFEncryptorByLSBMethod.

Steganografija v GIF

polja firstLSBit и secondLSBit vsebujejo število bitov vsakega bajta slike, v katero je treba vnesti sporočilo in od koder je treba sporočilo prebrati. Polje checkSequence shrani zaporedje kontrolnih bitov, da zagotovi prepoznavanje vdelanega sporočila. Statična metoda getEncryptingFileParameters vrne parametre podane datoteke in značilnosti morebitnega sporočila.

Algoritem metode encrypt Razred GIFEncryptorByLSBMethod:

Steganografija v GIF

In njegova koda:

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

Algoritem in izvorna koda metode decrypt Razred GIFEncryptorByLSBMethod:

Steganografija v 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);
}

Izvedba razreda GIFEncryptorByPaletteExtensionMethod bo podobna, le način shranjevanja/branja informacij je drugačen.

V razredu MainFrame opisane so metode zavijanja: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), obdelava rezultatov vmesniških metod Encryptor in interakcijo z uporabnikom, tj. odpiranje pogovornega okna za izbiro datoteke, prikazovanje sporočil o napakah itd.; kot tudi druge metode: openImage(), ki uporabniku omogoča izbiro slike, exit(), ki zapusti aplikacijo. Te metode se kličejo iz Actionustrezni elementi menija. Ta razred dodatno implementira pomožne metode: createComponents() - izdelava komponent obrazca, loadImageFile(File f) — nalaganje slike v posebno komponento iz datoteke. Izvedba razreda GIFEncryptorByPaletteExtensionMethod podobno kot pri izvedbi razreda GIFEncryptorByLSBMethod, glavna razlika je v načinu zapisa in branja bajtov sporočil iz palete.

Delovanje programa

LBS metoda

Recimo, da obstaja taka slika:

Steganografija v GIF

Na tej sliki je paleta sestavljena iz 256 barv (kot jih shrani Paint). Prve štiri barve so: bela, črna, rdeča, zelena. Ostale barve so črne. Zaporedje bitov globalne palete bo naslednje:

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

Steganografija v GIF

Ko je sporočilo vdelano, bodo podčrtani biti nadomeščeni z deli iz sporočila. Nastala slika se skoraj ne razlikuje od izvirnika.

Original
Slika z vdelanim sporočilom

Steganografija v GIF
Steganografija v GIF

Metoda razširitve palete

Ko s to metodo odprete sliko, ki vsebuje sporočilo, boste videli naslednjo sliko:

Steganografija v GIF

Jasno je, da ta metoda ne bo delovala za popolne vohunske dejavnosti in bo morda zahtevala dodatno šifriranje sporočila.

Šifriranje/dešifriranje v animiranih slikah deluje tako kot v običajnih statičnih slikah, vendar animacija ni poškodovana.

Uporabljeni viri:

Prenos:

Vir: www.habr.com

Dodaj komentar