Steganogrāfija GIF formātā

Ievads

Sveicieni.
Ne tik sen, kad mācījos universitātē, bija kursa darbs disciplīnā “Informācijas drošības programmatūras metodes”. Lai veiktu uzdevumu, mums bija jāizveido programma, kas iegultu ziņojumu GIF failos. Es nolēmu to darīt Java.

Šajā rakstā es aprakstīšu dažus teorētiskos punktus, kā arī to, kā šī mazā programma tika izveidota.

Teorētiskā daļa

GIF formātā

GIF (Graphics Interchange Format — attēlu apmaiņas formāts) ir grafisko attēlu glabāšanas formāts, kas spēj saglabāt saspiestus datus, nezaudējot kvalitāti, formātā līdz 256 krāsām. Šo formātu 1987. gadā (GIF87a) izstrādāja CompuServe rastra attēlu pārsūtīšanai pa tīkliem. 1989. gadā formāts tika modificēts (GIF89a), tika pievienots caurspīdīguma un animācijas atbalsts.

GIF failiem ir bloku struktūra. Šiem blokiem vienmēr ir noteikts garums (vai tas ir atkarīgs no dažiem karogiem), tāpēc ir gandrīz neiespējami kļūdīties, kur katrs bloks atrodas. Vienkāršākā neanimētā GIF attēla struktūra GIF89a formātā:

Steganogrāfija GIF formātā

No visiem struktūras blokiem šajā gadījumā mūs interesēs globālais paletes bloks un parametri, kas ir atbildīgi par paleti:

  • CT — globālās paletes klātbūtne. Ja šis karodziņš ir iestatīts, globālajai paletei jāsākas tūlīt aiz loģiskā ekrāna roktura.
  • Size — paletes izmērs un krāsu skaits attēlā. Šī parametra vērtības:

Izmēri
Krāsu skaits
Paletes izmērs, baiti

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Šifrēšanas metodes

Lai šifrētu ziņojumus attēlu failos, tiks izmantotas šādas metodes:

  • LSB (least Significant Bit) metode
  • Paletes pievienošanas metode

LSB metode - izplatīta steganogrāfijas metode. Tas sastāv no pēdējo nozīmīgo bitu aizstāšanas konteinerā (mūsu gadījumā globālo paletes baitu) ar slēptā ziņojuma bitiem.

Programma izmantos pēdējos divus bitus globālās paletes baitos kā daļu no šīs metodes. Tas nozīmē, ka 24 bitu attēlam, kura krāsu palete ir trīs baiti sarkanai, zilai un zaļai krāsai, pēc ziņojuma iegulšanas tajā katra krāsu sastāvdaļa mainīsies ne vairāk kā par 3/255 gradācijām. Šādas izmaiņas, pirmkārt, būs neredzamas vai grūti pamanāmas cilvēka acij, otrkārt, tās nebūs redzamas nekvalitatīvās informācijas izvades ierīcēs.

Informācijas apjoms būs tieši atkarīgs no attēla paletes izmēra. Tā kā paletes maksimālais izmērs ir 256 krāsas un, ja katras krāsas komponentā ir ierakstīti divi ziņojuma biti, tad maksimālais ziņojuma garums (ar maksimālo paleti attēlā) ir 192 baiti. Kad ziņojums ir iegults attēlā, faila lielums nemainās.

Paletes paplašināšanas metode, kas darbojas tikai GIF struktūrai. Tas būs visefektīvākais attēliem ar nelielu paleti. Tās būtība ir tāda, ka tas palielina paletes izmēru, tādējādi nodrošinot papildu vietu nepieciešamo baitu rakstīšanai krāsu baitu vietā. Ja ņemam vērā, ka minimālais paletes izmērs ir 2 krāsas (6 baiti), tad iegultā ziņojuma maksimālais izmērs var būt 256 × 3–6 = 762 baiti. Trūkums ir zemā kriptogrāfiskā drošība; iegulto ziņojumu var lasīt, izmantojot jebkuru teksta redaktoru, ja ziņojums nav pakļauts papildu šifrēšanai.

Praktiskā daļa

Programmas dizains

Visi nepieciešamie rīki šifrēšanas un atšifrēšanas algoritmu ieviešanai tiks iekļauti komplektā com.tsarik.steganography. Šajā pakotnē ir iekļauts interfeiss Encryptor ar metodēm encrypt и decrypt, Klase Binary, kas nodrošina iespēju strādāt ar bitu masīviem, kā arī izņēmumu klasēm UnableToEncryptException и UnableToDecryptException, kas jāizmanto saskarnes metodēs Encryptor attiecīgi kodēšanas un dekodēšanas kļūdu gadījumā.

Galvenā programmu pakete com.tsarik.programs.gifed ietvers darbināmu programmu klasi ar statisku metodi main, kas ļauj palaist programmu; klase, kas glabā programmas parametrus; un paketes ar citām klasēm.

Pašu algoritmu ieviešana tiks prezentēta komplektā com.tsarik.programs.gifed.gif klases GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Abas šīs klases ieviesīs saskarni Encryptor.

Pamatojoties uz GIF formāta struktūru, varat izveidot vispārīgu algoritmu ziņojuma ievadīšanai attēlu paletē:

Steganogrāfija GIF formātā

Lai noteiktu ziņojuma esamību attēlā, ziņojuma sākumam jāpievieno noteikta bitu secība, kuru dekodētājs vispirms nolasa un pārbauda pareizību. Ja nesakrīt, tad tiek uzskatīts, ka attēlā nav slēpta ziņojuma. Tālāk jums jānorāda ziņojuma garums. Pēc tam pats ziņojuma teksts.

Visa lietojumprogrammas klases diagramma:

Steganogrāfija GIF formātā

Programmas īstenošana

Visas programmas ieviešanu var iedalīt divās daļās: saskarnes šifrēšanas un atšifrēšanas metožu ieviešana Encryptor, nodarbībās GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethodun lietotāja interfeisa ieviešanu.

Apsveriet klasi GIFEncryptorByLSBMethod.

Steganogrāfija GIF formātā

lauki firstLSBit и secondLSBit satur katra attēla baita bitu skaitu, kurā jāievada ziņojums un no kurienes ziņojums jālasa. Lauks checkSequence saglabā pārbaudes bitu secību, lai nodrošinātu iegultā ziņojuma atpazīšanu. Statiskā metode getEncryptingFileParameters atgriež norādītā faila parametrus un potenciālā ziņojuma raksturlielumus.

Metodes algoritms encrypt klase GIFEncryptorByLSBMethod:

Steganogrāfija GIF formātā

Un viņa kods:

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

Metodes algoritms un pirmkods decrypt klase GIFEncryptorByLSBMethod:

Steganogrāfija GIF formātā

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

Klases īstenošana GIFEncryptorByPaletteExtensionMethod būs līdzīgi, atšķiras tikai informācijas saglabāšanas/nolasīšanas metode.

Klasē MainFrame Aprakstītas iesaiņošanas metodes: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), apstrādājot interfeisa metožu rezultātus Encryptor un mijiedarbība ar lietotāju, t.i., failu atlases dialoga atvēršana, kļūdu ziņojumu parādīšana utt.; kā arī citas metodes: openImage(), ļaujot lietotājam izvēlēties attēlu, exit(), kas aizver lietojumprogrammu. Šīs metodes tiek sauktas no Actionatbilstošos izvēlnes vienumus. Šī klase papildus ievieš palīgmetodes: createComponents() - formas sastāvdaļu izveide, loadImageFile(File f) — attēla ielāde īpašā komponentā no faila. Klases īstenošana GIFEncryptorByPaletteExtensionMethod līdzīgi klases ieviešanai GIFEncryptorByLSBMethod, galvenā atšķirība ir veidā, kādā ziņojuma baiti tiek rakstīti un nolasīti no paletes.

Programmas darbība

LBS metode

Pieņemsim, ka ir šāds attēls:

Steganogrāfija GIF formātā

Šajā attēlā palete sastāv no 256 krāsām (kā Paint saglabā). Pirmās četras krāsas ir: balta, melna, sarkana, zaļa. Citas krāsas ir melnas. Globālās paletes bitu secība būs šāda:

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

Steganogrāfija GIF formātā

Kad ziņojums ir iegults, pasvītrotie biti tiks aizstāti ar ziņojuma bitiem. Iegūtais attēls gandrīz neatšķiras no oriģināla.

Oriģināls
Attēls ar iegultu ziņojumu

Steganogrāfija GIF formātā
Steganogrāfija GIF formātā

Paletes paplašināšanas metode

Atverot attēlu, kurā ir ziņojums, izmantojot šo metodi, tiks parādīts šāds attēls:

Steganogrāfija GIF formātā

Ir skaidrs, ka šī metode nedarbosies pilnvērtīgām spiegošanas darbībām, un tai var būt nepieciešama papildu ziņojuma šifrēšana.

Šifrēšana/atšifrēšana animētos attēlos darbojas tāpat kā parastajos statiskajos attēlos, taču animācija nav bojāta.

Izmantotie avoti:

Lejupielādēt:

Avots: www.habr.com

Iegādājieties uzticamu mitināšanu vietnēm ar DDoS aizsardzību, VPS VDS serveriem 🔥 Iegādājieties uzticamu tīmekļa vietņu mitināšanu ar DDoS aizsardzību, VPS VDS serveriem | ProHoster