Steganografia GIF-muodossa

Esittely

Tervehdys.
Ei niin kauan sitten, kun opiskelin yliopistossa, siellä oli kurssityö aiheesta "Tietoturvallisuuden ohjelmistomenetelmät". Tehtävä vaati meitä luomaan ohjelman, joka upottaa viestin GIF-tiedostoihin. Päätin tehdä sen Javalla.

Tässä artikkelissa kuvaan joitain teoreettisia kohtia sekä kuinka tämä pieni ohjelma luotiin.

Teoreettinen osa

GIF-muoto

GIF (Graphics Interchange Format - kuvien vaihtomuoto) on graafisten kuvien tallennusmuoto, joka pystyy tallentamaan pakattuja tietoja laadun heikkenemättä jopa 256 värin muodossa. CompuServe kehitti tämän muodon vuonna 1987 (GIF87a) rasterikuvien lähettämiseen verkkojen kautta. Vuonna 1989 muotoa muutettiin (GIF89a), läpinäkyvyyden ja animaation tuki lisättiin.

GIF-tiedostoilla on lohkorakenne. Näillä lohkoilla on aina kiinteä pituus (tai se riippuu joistakin lipuista), joten on lähes mahdotonta tehdä virhettä kunkin lohkon sijainnin suhteen. Yksinkertaisimman ei-animoidun GIF-kuvan rakenne GIF89a-muodossa:

Steganografia GIF-muodossa

Kaikista rakenteen lohkoista olemme tässä tapauksessa kiinnostuneita globaalista palettilohkosta ja paletista vastaavista parametreista:

  • CT — maailmanlaajuisen paletin läsnäolo. Jos tämä lippu on asetettu, globaalin paletin on aloitettava välittömästi loogisen näytön kahvan jälkeen.
  • Size - paletin koko ja värien lukumäärä kuvassa. Tämän parametrin arvot:

Koko
Värien lukumäärä
Paletin koko, tavua

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Salausmenetelmät

Seuraavia menetelmiä käytetään kuvatiedostojen viestien salaamiseen:

  • LSB (Least Significant Bit) -menetelmä
  • Paletin lisäysmenetelmä

LSB menetelmä - yleinen steganografiamenetelmä. Se koostuu säiliön viimeisten merkitsevien bittien (tässä tapauksessa globaalien palettitavujen) korvaamisesta piilotetun viestin biteillä.

Ohjelma käyttää globaalien palettitavujen kahta viimeistä bittiä osana tätä menetelmää. Tämä tarkoittaa, että 24-bittisessä kuvassa, jossa paletin väri on kolme tavua punaiselle, siniselle ja vihreälle, jokainen värikomponentti muuttuu sen jälkeen, kun siihen on upotettu viesti, enintään 3/255 sävyjä. Sellainen muutos on ensinnäkin näkymätön tai vaikeasti havaittavissa ihmissilmälle, ja toiseksi se ei näy huonolaatuisilla tiedonantolaitteilla.

Tietojen määrä riippuu suoraan kuvapaletin koosta. Koska paletin maksimikoko on 256 väriä ja jos kunkin värin komponenttiin kirjoitetaan kaksi viestibittiä, niin viestin maksimipituus (kuvan enimmäispaletilla) on 192 tavua. Kun viesti on upotettu kuvaan, tiedoston koko ei muutu.

Paletin laajennusmenetelmä, joka toimii vain GIF-rakenteessa. Se on tehokkain kuvissa, joissa on pieni paletti. Sen olemus on, että se kasvattaa paletin kokoa ja tarjoaa siten lisätilaa tarvittavien tavujen kirjoittamiseen väritavujen tilalle. Jos otetaan huomioon, että paletin vähimmäiskoko on 2 väriä (6 tavua), upotetun viestin enimmäiskoko voi olla 256 × 3–6 = 762 tavua. Haittapuolena on alhainen salausturva; upotettu viesti voidaan lukea millä tahansa tekstieditorilla, jos viestiä ei ole salattu lisäsalauksella.

Käytännön osa

Ohjelman suunnittelu

Kaikki tarvittavat työkalut salaus- ja salauksenpurkualgoritmien toteuttamiseen sisältyvät pakettiin com.tsarik.steganography. Tämä paketti sisältää käyttöliittymän Encryptor menetelmien kanssa encrypt и decrypt, Luokka Binary, joka tarjoaa mahdollisuuden työskennellä bittitaulukoiden sekä poikkeusluokkien kanssa UnableToEncryptException и UnableToDecryptException, jota tulisi käyttää rajapintamenetelmissä Encryptor koodaus- ja dekoodausvirheiden tapauksessa.

Pääohjelmapaketti com.tsarik.programs.gifed sisältää ajettavan ohjelmaluokan staattisella menetelmällä main, jonka avulla voit suorittaa ohjelman; luokka, joka tallentaa ohjelman parametrit; ja paketit muiden luokkien kanssa.

Itse algoritmien toteutus esitellään paketissa com.tsarik.programs.gifed.gif luokat GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Molemmat luokat toteuttavat käyttöliittymän Encryptor.

GIF-muodon rakenteen perusteella voit luoda yleisen algoritmin viestin tuomiseksi kuvapalettiin:

Steganografia GIF-muodossa

Viestin läsnäolon määrittämiseksi kuvassa on tarpeen lisätä viestin alkuun tietty bittisarja, jonka dekooderi lukee ensin ja tarkistaa sen oikeellisuuden. Jos se ei täsmää, katsotaan, että kuvassa ei ole piilotettua viestiä. Seuraavaksi sinun on määritettävä viestin pituus. Sitten itse viestin teksti.

Koko sovelluksen luokkakaavio:

Steganografia GIF-muodossa

Ohjelman toteuttaminen

Koko ohjelman toteutus voidaan jakaa kahteen osaan: rajapinnan salauksen toteutukseen ja salauksen purkumenetelmiin Encryptor, luokissa GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethodja käyttöliittymän toteutus.

Harkitse luokkaa GIFEncryptorByLSBMethod.

Steganografia GIF-muodossa

kentät firstLSBit и secondLSBit sisältävät kuvan kunkin tavun bittien lukumäärät, joihin viesti tulee syöttää ja mistä viesti tulee lukea. Ala checkSequence tallentaa tarkistusbittisekvenssin varmistaakseen upotetun viestin tunnistamisen. Staattinen menetelmä getEncryptingFileParameters palauttaa määritetyn tiedoston parametrit ja mahdollisen viestin ominaisuudet.

Menetelmän algoritmi encrypt luokka GIFEncryptorByLSBMethod:

Steganografia GIF-muodossa

Ja hänen koodinsa:

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

Menetelmän algoritmi ja lähdekoodi decrypt luokka GIFEncryptorByLSBMethod:

Steganografia GIF-muodossa

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

Luokan toteutus GIFEncryptorByPaletteExtensionMethod on samanlainen, vain tietojen tallennus-/lukutapa on erilainen.

Luokassa MainFrame käärintämenetelmät on kuvattu: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), käsittelee rajapintamenetelmien tuloksia Encryptor ja vuorovaikutuksessa käyttäjän kanssa, ts. tiedostonvalintaikkunan avaaminen, virheilmoitusten näyttäminen jne.; sekä muut menetelmät: openImage(), jolloin käyttäjä voi valita kuvan, exit(), joka sulkee sovelluksen. Näitä menetelmiä kutsutaan kohteesta Actionvastaavat valikon kohdat. Tämä luokka toteuttaa lisäksi apumenetelmiä: createComponents() - lomakekomponenttien luominen, loadImageFile(File f) — kuvan lataaminen tiedostosta erityiskomponenttiin. Luokan toteutus GIFEncryptorByPaletteExtensionMethod samanlainen kuin luokan toteutus GIFEncryptorByLSBMethod, suurin ero on tavassa, jolla viestitavut kirjoitetaan ja luetaan paletista.

Ohjelman toiminta

LBS-menetelmä

Oletetaan, että siellä on tällainen kuva:

Steganografia GIF-muodossa

Tässä kuvassa paletti koostuu 256 väristä (kuten Paint tallentaa). Ensimmäiset neljä väriä ovat: valkoinen, musta, punainen, vihreä. Muut värit ovat musta. Globaali palettibittijärjestys on seuraava:

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

Steganografia GIF-muodossa

Kun viesti on upotettu, alleviivatut bitit korvataan viestin biteillä. Tuloksena oleva kuva ei juuri eroa alkuperäisestä.

Alkuperäinen
Kuva, jossa on upotettu viesti

Steganografia GIF-muodossa
Steganografia GIF-muodossa

Paletin laajennusmenetelmä

Kun avaat viestin sisältävän kuvan tällä menetelmällä, näet seuraavan kuvan:

Steganografia GIF-muodossa

On selvää, että tämä menetelmä ei toimi täysimittaisessa vakoilutoiminnassa ja saattaa vaatia viestin lisäsalausta.

Animoitujen kuvien salaus/salauksen purku toimii kuten tavallisissa staattisissa kuvissa, mutta animaatio ei ole rikki.

Käytetyt lähteet:

Lataa:

Lähde: will.com

Lisää kommentti