Steganografie in GIF

Inleiding

Groete.
Nie so lank gelede nie, toe ek aan die universiteit gestudeer het, was daar 'n kursuswerk in die dissipline "Sagtewaremetodes van inligtingsekuriteit." Die opdrag het vereis dat ons 'n program skep wat 'n boodskap in GIF-lêers insluit. Ek het besluit om dit in Java te doen.

In hierdie artikel sal ek 'n paar teoretiese punte beskryf, asook hoe hierdie klein program geskep is.

Teoretiese gedeelte

GIF-formaat

GIF (Graphics Interchange Format - 'n formaat vir die uitruil van beelde) is 'n formaat vir die stoor van grafiese beelde, wat in staat is om saamgeperste data te stoor sonder verlies aan kwaliteit in 'n formaat van tot 256 kleure. Hierdie formaat is in 1987 (GIF87a) deur CompuServe ontwikkel vir die oordrag van rasterbeelde oor netwerke. In 1989 is die formaat gewysig (GIF89a), ondersteuning vir deursigtigheid en animasie is bygevoeg.

GIF-lêers het 'n blokstruktuur. Hierdie blokke het altyd 'n vaste lengte (of dit hang van sommige vlae af), so dit is amper onmoontlik om 'n fout te maak oor waar elke blok geleë is. Die struktuur van die eenvoudigste nie-geanimeerde GIF-beeld in GIF89a-formaat:

Steganografie in GIF

Van al die blokke van die struktuur, in hierdie geval sal ons belangstel in die globale paletblok en die parameters wat verantwoordelik is vir die palet:

  • CT - teenwoordigheid van 'n globale palet. As hierdie vlag gestel is, moet die globale palet onmiddellik na die logiese skermhandvatsel begin.
  • Size - paletgrootte en aantal kleure in die prentjie. Waardes vir hierdie parameter:

grootte
Aantal kleure
Paletgrootte, grepe

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Enkripsie metodes

Die volgende metodes sal gebruik word om boodskappe in beeldlêers te enkripteer:

  • LSB (Least Significant Bit) metode
  • Paletbyvoegingsmetode

LSB metode - 'n algemene metode van steganografie. Dit bestaan ​​uit die vervanging van die laaste beduidende stukkies in die houer (in ons geval, die globale paletgrepe) met die stukkies van die verborge boodskap.

Die program sal die laaste twee bisse in die globale paletgrepe gebruik as deel van hierdie metode. Dit beteken dat vir 'n 24-bis-prent, waar die kleurpalet drie grepe is vir rooi, blou en groen, nadat 'n boodskap daarin ingebed is, sal elke kleurkomponent met 'n maksimum van 3/255 gradasies verander. So 'n verandering sal eerstens onsigbaar of moeilik wees om vir die menslike oog raak te sien, en tweedens sal dit nie sigbaar wees op lae-gehalte inligting-uitsettoestelle nie.

Die hoeveelheid inligting sal direk afhang van die grootte van die prentpalet. Aangesien die maksimum grootte van die palet 256 kleure is, en as twee boodskapbissies in die komponent van elke kleur geskryf word, dan is die maksimum boodskaplengte (met die maksimum palet in die prent) 192 grepe. Sodra die boodskap in die prent ingebed is, verander die lêergrootte nie.

Palet uitbreiding metode, wat net vir die GIF-struktuur werk. Dit sal die doeltreffendste wees op beelde met 'n klein palet. Die essensie daarvan is dat dit die grootte van die palet vergroot, en sodoende bykomende spasie bied om die nodige grepe in die plek van die kleurgrepe te skryf. As ons in ag neem dat die minimum grootte van die palet 2 kleure (6 grepe) is, dan kan die maksimum grootte van die ingebedde boodskap 256 × 3–6 = 762 grepe wees. Die nadeel is lae kriptografiese sekuriteit; die ingebedde boodskap kan met enige teksredigeerder gelees word as die boodskap nie aan bykomende enkripsie onderwerp is nie.

Praktiese deel

Program ontwerp

Alle nodige gereedskap vir die implementering van enkripsie- en dekripsiealgoritmes sal by die pakket ingesluit word com.tsarik.steganography. Hierdie pakket bevat die koppelvlak Encryptor met metodes encrypt и decrypt, Klas Binary, wat die vermoë bied om met bisskikkings te werk, sowel as uitsonderingsklasse UnableToEncryptException и UnableToDecryptException, wat in koppelvlakmetodes gebruik moet word Encryptor in die geval van onderskeidelik enkoderings- en dekoderingsfoute.

Hoofprogrampakket com.tsarik.programs.gifed sal 'n uitvoerbare programklas met 'n statiese metode insluit main, wat jou toelaat om die program te laat loop; 'n klas wat programparameters stoor; en pakkette met ander klasse.

Die implementering van die algoritmes self sal in die pakket aangebied word com.tsarik.programs.gifed.gif klasse GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Albei hierdie klasse sal die koppelvlak implementeer Encryptor.

Op grond van die struktuur van die GIF-formaat, kan u 'n algemene algoritme skep om 'n boodskap in die beeldpalet in te voer:

Steganografie in GIF

Om die teenwoordigheid van 'n boodskap in 'n beeld te bepaal, is dit nodig om 'n sekere volgorde van stukkies aan die begin van die boodskap by te voeg, wat die dekodeerder eerste lees en nagaan vir korrektheid. As dit nie ooreenstem nie, word dit beskou dat daar geen verborge boodskap in die beeld is nie. Volgende moet jy die lengte van die boodskap spesifiseer. Dan die teks van die boodskap self.

Klasdiagram van die hele toepassing:

Steganografie in GIF

Implementering van die program

Die implementering van die hele program kan in twee komponente verdeel word: implementering van koppelvlakenkripsie en dekripsiemetodes Encryptor, in klasse GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, en die implementering van die gebruikerskoppelvlak.

Oorweeg die klas GIFEncryptorByLSBMethod.

Steganografie in GIF

velde firstLSBit и secondLSBit bevat die aantal bisse van elke greep van die beeld waarin die boodskap ingevoer moet word en vanwaar die boodskap gelees moet word. Veld checkSequence stoor 'n kontrolebis-volgorde om herkenning van die ingebedde boodskap te verseker. Statiese metode getEncryptingFileParameters gee die parameters van die gespesifiseerde lêer en die kenmerke van die potensiële boodskap terug.

Metode algoritme encrypt klas GIFEncryptorByLSBMethod:

Steganografie in GIF

En sy kode:

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

Algoritme en bronkode van die metode decrypt klas GIFEncryptorByLSBMethod:

Steganografie in 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);
}

Implementering van die klas GIFEncryptorByPaletteExtensionMethod soortgelyk sal wees, is slegs die metode om inligting te stoor/lees anders.

In die klas MainFrame wikkelmetodes word beskryf: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), verwerking van die resultate van koppelvlakmetodes Encryptor en interaksie met die gebruiker, d.w.s. die opening van 'n lêerseleksie-dialoog, wys foutboodskappe, ens.; sowel as ander metodes: openImage(), wat die gebruiker toelaat om 'n prent te kies, exit(), wat die toepassing verlaat. Hierdie metodes word genoem vanaf Actionse ooreenstemmende spyskaartitems. Hierdie klas implementeer addisioneel hulpmetodes: createComponents() - skepping van vormkomponente, loadImageFile(File f) - laai 'n prent in 'n spesiale komponent vanaf 'n lêer. Implementering van die klas GIFEncryptorByPaletteExtensionMethod soortgelyk aan die klasimplementering GIFEncryptorByLSBMethod, is die belangrikste verskil in die manier waarop boodskapgrepe geskryf en gelees word vanaf die palet.

Program werking

LBS metode

Kom ons sê daar is 'n beeld soos hierdie:

Steganografie in GIF

In hierdie prent bestaan ​​die palet uit 256 kleure (soos Paint stoor). Die eerste vier kleure is: wit, swart, rooi, groen. Ander kleure is swart. Die globale paletbisvolgorde sal soos volg wees:

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

Steganografie in GIF

Sodra die boodskap ingebed is, sal die onderstreepte stukkies vervang word met die stukkies uit die boodskap. Die gevolglike beeld verskil amper nie van die oorspronklike nie.

Original
Beeld met ingebedde boodskap

Steganografie in GIF
Steganografie in GIF

Palet uitbreiding metode

Wanneer jy met hierdie metode 'n prent oopmaak wat 'n boodskap bevat, sal jy die volgende prent sien:

Steganografie in GIF

Dit is duidelik dat hierdie metode nie vir volwaardige spioenasieaktiwiteite sal werk nie, en moontlik addisionele enkripsie van die boodskap sal vereis.

Enkripsie/dekripsie in geanimeerde beelde werk net soos in gewone statiese beelde, maar die animasie is nie gebreek nie.

Bronne gebruik:

Laai:

Bron: will.com

Voeg 'n opmerking