Steganograffeg mewn GIF

Cyflwyniad

Cyfarchion.
Ddim mor bell yn ôl, pan oeddwn yn astudio yn y brifysgol, roedd yna waith cwrs yn y ddisgyblaeth “Meddalwedd dulliau diogelwch gwybodaeth.” Roedd yr aseiniad yn gofyn i ni greu rhaglen sy'n mewnosod neges mewn ffeiliau GIF. Penderfynais ei wneud yn Java.

Yn yr erthygl hon byddaf yn disgrifio rhai pwyntiau damcaniaethol, yn ogystal â sut y cafodd y rhaglen fach hon ei chreu.

Rhan ddamcaniaethol

Fformat GIF

Mae GIF (Fformat Cyfnewid Graffeg - fformat ar gyfer cyfnewid delweddau) yn fformat ar gyfer storio delweddau graffig, sy'n gallu storio data cywasgedig heb golli ansawdd mewn fformat hyd at 256 o liwiau. Datblygwyd y fformat hwn ym 1987 (GIF87a) gan CompuServe ar gyfer trosglwyddo delweddau raster dros rwydweithiau. Ym 1989, addaswyd y fformat (GIF89a), ychwanegwyd cefnogaeth ar gyfer tryloywder ac animeiddio.

Mae gan ffeiliau GIF strwythur bloc. Mae gan y blociau hyn hyd sefydlog bob amser (neu mae'n dibynnu ar rai baneri), felly mae bron yn amhosibl gwneud camgymeriad ynghylch lleoliad pob bloc. Strwythur y ddelwedd GIF symlaf heb ei hanimeiddio mewn fformat GIF89a:

Steganograffeg mewn GIF

O'r holl flociau o'r strwythur, yn yr achos hwn bydd gennym ddiddordeb yn y bloc palet byd-eang a'r paramedrau sy'n gyfrifol am y palet:

  • CT — presenoldeb palet byd-eang. Os gosodir y faner hon, rhaid i'r palet byd-eang ddechrau yn syth ar ôl handlen y sgrin resymegol.
  • Size — maint palet a nifer y lliwiau yn y llun. Gwerthoedd ar gyfer y paramedr hwn:

Maint
Nifer o liwiau
Maint palet, beit

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Dulliau amgryptio

Defnyddir y dulliau canlynol i amgryptio negeseuon mewn ffeiliau delwedd:

  • Dull LSB (Y Rhan Lleiaf Arwyddocaol).
  • Dull ychwanegu palet

dull LSB - dull cyffredin o steganograffeg. Mae'n cynnwys disodli'r darnau arwyddocaol olaf yn y cynhwysydd (yn ein hachos ni, y bytes palet byd-eang) gyda darnau'r neges gudd.

Bydd y rhaglen yn defnyddio'r ddau ddarn olaf yn y palet beit byd-eang fel rhan o'r dull hwn. Mae hyn yn golygu, ar gyfer delwedd 24-did, lle mae'r palet lliw yn dri beit ar gyfer coch, glas a gwyrdd, ar ôl ymgorffori neges ynddo, bydd pob cydran lliw yn newid o uchafswm o 3/255 graddiad. Bydd newid o'r fath, yn gyntaf, yn anweledig neu'n anodd sylwi arno i'r llygad dynol, ac yn ail, ni fydd yn weladwy ar ddyfeisiau allbwn gwybodaeth o ansawdd isel.

Bydd faint o wybodaeth yn dibynnu'n uniongyrchol ar faint y palet delwedd. Gan mai maint mwyaf y palet yw 256 o liwiau, ac os yw dau ddarn neges wedi'u hysgrifennu i gydran pob lliw, yna uchafswm hyd y neges (gyda'r palet mwyaf yn y ddelwedd) yw 192 beit. Unwaith y bydd y neges wedi'i hymgorffori yn y ddelwedd, nid yw maint y ffeil yn newid.

Dull ehangu palet, sydd ond yn gweithio ar gyfer y strwythur GIF. Bydd yn fwyaf effeithiol ar ddelweddau gyda phalet bach. Ei hanfod yw ei fod yn cynyddu maint y palet, a thrwy hynny ddarparu gofod ychwanegol ar gyfer ysgrifennu'r bytes angenrheidiol yn lle'r beit lliw. Os ydym yn ystyried mai lleiafswm maint y palet yw 2 liw (6 beit), yna gall maint mwyaf y neges fewnosod fod yn 256 × 3–6 = 762 beit. Yr anfantais yw diogelwch cryptograffig isel; gellir darllen y neges wreiddiedig gan ddefnyddio unrhyw olygydd testun os nad yw'r neges wedi'i hamgryptio ychwanegol.

Rhan ymarferol

Dyluniad rhaglen

Bydd yr holl offer angenrheidiol ar gyfer gweithredu algorithmau amgryptio a dadgryptio yn cael eu cynnwys yn y pecyn com.tsarik.steganography. Mae'r pecyn hwn yn cynnwys y rhyngwyneb Encryptor gyda dulliau encrypt и decrypt, Dosbarth Binary, sy'n darparu'r gallu i weithio gydag araeau didau, yn ogystal â dosbarthiadau eithriad UnableToEncryptException и UnableToDecryptException, y dylid ei ddefnyddio mewn dulliau rhyngwyneb Encryptor rhag ofn y bydd gwallau amgodio a dadgodio yn y drefn honno.

Prif becyn rhaglen com.tsarik.programs.gifed yn cynnwys dosbarth rhaglen rhedadwy gyda dull statig main, sy'n eich galluogi i redeg y rhaglen; dosbarth sy'n storio paramedrau rhaglen; a phecynnau gyda dosbarthiadau eraill.

Bydd gweithrediad yr algorithmau eu hunain yn cael eu cyflwyno yn y pecyn com.tsarik.programs.gifed.gif dosbarthiadau GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Bydd y ddau ddosbarth hyn yn gweithredu'r rhyngwyneb Encryptor.

Yn seiliedig ar strwythur y fformat GIF, gallwch greu algorithm cyffredinol ar gyfer cyflwyno neges i'r palet delwedd:

Steganograffeg mewn GIF

Er mwyn pennu presenoldeb neges mewn delwedd, mae angen ychwanegu dilyniant penodol o ddarnau i ddechrau'r neges, y mae'r datgodiwr yn ei ddarllen yn gyntaf ac yn gwirio cywirdeb. Os nad yw'n cyfateb, yna ystyrir nad oes neges gudd yn y ddelwedd. Nesaf mae angen i chi nodi hyd y neges. Yna testun y neges ei hun.

Diagram dosbarth o'r cais cyfan:

Steganograffeg mewn GIF

Gweithredu'r rhaglen

Gellir rhannu gweithrediad y rhaglen gyfan yn ddwy gydran: gweithredu dulliau amgryptio rhyngwyneb a dadgryptio Encryptor, mewn dosbarthiadau GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, a gweithredu'r rhyngwyneb defnyddiwr.

Ystyriwch y dosbarth GIFEncryptorByLSBMethod.

Steganograffeg mewn GIF

Maes firstLSBit и secondLSBit cynnwys nifer y darnau o bob beit o'r ddelwedd y dylid mewnbynnu'r neges iddo ac o ble y dylid darllen y neges. Maes checkSequence yn storio dilyniant did siec i sicrhau adnabyddiaeth o'r neges wedi'i fewnosod. Dull statig getEncryptingFileParameters yn dychwelyd paramedrau'r ffeil penodedig a nodweddion y neges bosibl.

Algorithm dull encrypt dosbarth GIFEncryptorByLSBMethod:

Steganograffeg mewn GIF

A'i god:

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

Algorithm a chod ffynhonnell y dull decrypt dosbarth GIFEncryptorByLSBMethod:

Steganograffeg mewn 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);
}

Gweithrediad y dosbarth GIFEncryptorByPaletteExtensionMethod yn debyg, dim ond y dull o gadw/darllen gwybodaeth sy'n wahanol.

Yn y dosbarth MainFrame Disgrifir dulliau lapio: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), prosesu canlyniadau dulliau rhyngwyneb Encryptor a rhyngweithio â'r defnyddiwr, h.y. agor deialog dewis ffeil, dangos negeseuon gwall, ac ati; yn ogystal â dulliau eraill: openImage(), gan ganiatáu i'r defnyddiwr ddewis delwedd, exit(), sy'n gadael y cais. Gelwir y dulliau hyn o Actioneitemau dewislen cyfatebol. Mae'r dosbarth hwn hefyd yn gweithredu dulliau ategol: createComponents() - creu cydrannau ffurf, loadImageFile(File f) — llwytho delwedd i gydran arbennig o ffeil. Gweithrediad y dosbarth GIFEncryptorByPaletteExtensionMethod debyg i weithrediad y dosbarth GIFEncryptorByLSBMethod, Y prif wahaniaeth yw'r ffordd y mae neges beit yn cael ei ysgrifennu a'i ddarllen o'r palet.

Gweithrediad rhaglen

dull LBS

Gadewch i ni ddweud bod delwedd fel hyn:

Steganograffeg mewn GIF

Yn y ddelwedd hon, mae'r palet yn cynnwys 256 o liwiau (fel y mae Paint yn ei arbed). Y pedwar lliw cyntaf yw: gwyn, du, coch, gwyrdd. Mae lliwiau eraill yn ddu. Bydd y dilyniant didau palet byd-eang fel a ganlyn:

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

Steganograffeg mewn GIF

Unwaith y bydd y neges wedi'i mewnosod, bydd y darnau sydd wedi'u tanlinellu yn cael eu disodli gan y darnau o'r neges. Nid yw'r ddelwedd sy'n deillio o hyn bron yn wahanol i'r gwreiddiol.

Gwreiddiol
Delwedd gyda neges wedi'i hymgorffori

Steganograffeg mewn GIF
Steganograffeg mewn GIF

Dull ehangu palet

Pan fyddwch chi'n agor delwedd sy'n cynnwys neges gan ddefnyddio'r dull hwn, fe welwch y llun canlynol:

Steganograffeg mewn GIF

Mae'n amlwg na fydd y dull hwn yn gweithio ar gyfer gweithgareddau ysbïo llawn, ac efallai y bydd angen amgryptio ychwanegol o'r neges.

Mae amgryptio/dadgryptio mewn delweddau animeiddiedig yn gweithio yn union fel mewn delweddau sefydlog rheolaidd, ond nid yw'r animeiddiad wedi'i dorri.

Ffynonellau a ddefnyddiwyd:

Lawrlwytho:

Ffynhonnell: hab.com

Ychwanegu sylw