Ստեգանոգրաֆիա GIF-ում

Ներածություն

Ողջույններ:
Ոչ վաղ անցյալում, երբ ես սովորում էի համալսարանում, կար դասընթաց «Տեղեկատվական անվտանգության ծրագրային մեթոդներ» թեմայով: Հանձնարարությունը մեզանից պահանջում էր ստեղծել ծրագիր, որը հաղորդագրություն կտեղադրի GIF ֆայլերում: Ես որոշեցի դա անել Java-ում:

Այս հոդվածում ես նկարագրելու եմ որոշ տեսական կետեր, ինչպես նաև, թե ինչպես է ստեղծվել այս փոքրիկ ծրագիրը:

Տեսական մաս

GIF ձևաչափ

GIF-ը (Graphics Interchange Format - պատկերների փոխանակման ձևաչափ) գրաֆիկական պատկերներ պահելու ձևաչափ է, որն ընդունակ է պահել սեղմված տվյալներն առանց որակի կորստի մինչև 256 գույների ձևաչափով։ Այս ձևաչափը մշակվել է 1987 թվականին (GIF87a) CompuServe-ի կողմից՝ ցանցերի միջոցով ռաստերային պատկերներ փոխանցելու համար: 1989 թվականին ձևաչափը փոփոխվել է (GIF89a), ավելացվել է թափանցիկության և անիմացիայի աջակցություն։

GIF ֆայլերը բլոկային կառուցվածք ունեն: Այս բլոկները միշտ ունեն ֆիքսված երկարություն (կամ դա կախված է որոշ դրոշներից), ուստի գրեթե անհնար է սխալվել, թե որտեղ է գտնվում յուրաքանչյուր բլոկը: Ամենապարզ ոչ անիմացիոն GIF պատկերի կառուցվածքը GIF89a ձևաչափով.

Ստեգանոգրաֆիա GIF-ում

Կառուցվածքի բոլոր բլոկներից այս դեպքում մեզ կհետաքրքրի գլոբալ պալիտրա բլոկը և ներկապնակի համար պատասխանատու պարամետրերը.

  • CT - գլոբալ ներկապնակի առկայություն: Եթե ​​այս դրոշը դրված է, ապա գլոբալ գունապնակը պետք է սկսվի էկրանի տրամաբանական բռնակից անմիջապես հետո:
  • Size — ներկապնակի չափը և նկարի գույների քանակը: Այս պարամետրի արժեքները.

չափ
Գույների քանակը
Պալիտրա չափը, բայթ

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Գաղտնագրման մեթոդներ

Պատկերային ֆայլերում հաղորդագրությունները գաղտնագրելու համար կօգտագործվեն հետևյալ մեթոդները.

  • LSB (Նվազագույն նշանակալի բիթ) մեթոդ
  • Պալիտրա ավելացման մեթոդ

LSB մեթոդ - ստեգանոգրաֆիայի ընդհանուր մեթոդ. Այն բաղկացած է կոնտեյների վերջին նշանակալի բիթերը (մեր դեպքում՝ գլոբալ գունապնակի բայթերը) թաքնված հաղորդագրության բիթերով փոխարինելուց:

Ծրագիրը որպես այս մեթոդի մաս կօգտագործի գլոբալ պալիտրա բայթերի վերջին երկու բիթերը: Սա նշանակում է, որ 24-բիթանոց պատկերի համար, որտեղ գունային գունապնակը երեք բայթ է կարմիր, կապույտ և կանաչի համար, հաղորդագրություն ներդնելուց հետո յուրաքանչյուր գունային բաղադրիչ կփոխվի առավելագույնը 3/255 աստիճանով: Նման փոփոխությունը, նախ, անտեսանելի կամ դժվար նկատելի կլինի մարդու աչքին, երկրորդ՝ տեսանելի չի լինի անորակ տեղեկատվության ելքային սարքերի վրա։

Տեղեկատվության քանակն ուղղակիորեն կախված կլինի պատկերի ներկապնակի չափից: Քանի որ ներկապնակի առավելագույն չափը 256 գույն է, և եթե հաղորդագրության երկու բիթ գրված է յուրաքանչյուր գույնի բաղադրիչի մեջ, ապա հաղորդագրության առավելագույն երկարությունը (պատկերի առավելագույն գունապնակով) 192 բայթ է: Հաղորդագրությունը պատկերի մեջ տեղադրվելուց հետո ֆայլի չափը չի փոխվում:

Պալիտրա ընդլայնման մեթոդ, որն աշխատում է միայն GIF կառուցվածքի համար։ Այն առավել արդյունավետ կլինի փոքր գունապնակ ունեցող պատկերների վրա: Դրա էությունը կայանում է նրանում, որ այն մեծացնում է ներկապնակի չափը, դրանով իսկ լրացուցիչ տարածք տրամադրելով գունային բայթերի փոխարեն անհրաժեշտ բայթերը գրելու համար: Եթե ​​հաշվի առնենք, որ ներկապնակի նվազագույն չափը 2 գույն է (6 բայթ), ապա ներկառուցված հաղորդագրության առավելագույն չափը կարող է լինել 256 × 3–6 = 762 բայթ։ Թերությունը ցածր ծածկագրային անվտանգությունն է. ներկառուցված հաղորդագրությունը կարելի է կարդալ ցանկացած տեքստային խմբագրիչի միջոցով, եթե հաղորդագրությունը չի ենթարկվել լրացուցիչ կոդավորման:

Գործնական մասը

Ծրագրի ձևավորում

Փաթեթում կներառվեն գաղտնագրման և վերծանման ալգորիթմների ներդրման համար անհրաժեշտ բոլոր գործիքները com.tsarik.steganography. Այս փաթեթը ներառում է ինտերֆեյսը Encryptor մեթոդներով encrypt и decrypt, Դաս Binary, որն ապահովում է բիթային զանգվածների, ինչպես նաև բացառությունների դասերի հետ աշխատելու հնարավորություն UnableToEncryptException и UnableToDecryptException, որը պետք է օգտագործվի ինտերֆեյսի մեթոդներում Encryptor համապատասխանաբար կոդավորման և վերծանման սխալների դեպքում։

Հիմնական ծրագրի փաթեթ com.tsarik.programs.gifed կներառի runnable ծրագրի դաս՝ ստատիկ մեթոդով main, որը թույլ է տալիս գործարկել ծրագիրը; դաս, որը պահպանում է ծրագրի պարամետրերը. և փաթեթներ այլ դասերի հետ:

Փաթեթում կներկայացվի բուն ալգորիթմների իրականացումը com.tsarik.programs.gifed.gif դասեր GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Այս երկու դասերն էլ կիրականացնեն ինտերֆեյսը Encryptor.

Հիմնվելով GIF ձևաչափի կառուցվածքի վրա՝ կարող եք ստեղծել ընդհանուր ալգորիթմ՝ պատկերի ներկապնակում հաղորդագրություն ներմուծելու համար.

Ստեգանոգրաֆիա GIF-ում

Պատկերում հաղորդագրության առկայությունը որոշելու համար անհրաժեշտ է հաղորդագրության սկզբում ավելացնել բիթերի որոշակի հաջորդականություն, որը նախ կարդում է ապակոդավորիչը և ստուգում դրանց ճշգրտությունը։ Եթե ​​այն չի համընկնում, ապա համարվում է, որ պատկերում թաքնված հաղորդագրություն չկա։ Հաջորդը դուք պետք է նշեք հաղորդագրության երկարությունը: Այնուհետև հենց հաղորդագրության տեքստը:

Ամբողջ դիմումի դասի դիագրամ.

Ստեգանոգրաֆիա GIF-ում

Ծրագրի իրականացում

Ամբողջ ծրագրի իրականացումը կարելի է բաժանել երկու բաղադրիչի՝ ինտերֆեյսի գաղտնագրման և գաղտնազերծման մեթոդների իրականացում Encryptor, դասարաններում GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, և օգտագործողի միջերեսի իրականացումը:

Հաշվի առեք դասը GIFEncryptorByLSBMethod.

Ստեգանոգրաֆիա GIF-ում

դաշտերը firstLSBit и secondLSBit պարունակում է պատկերի յուրաքանչյուր բայթի բիթերի համարները, որոնց մեջ պետք է մուտքագրվի հաղորդագրությունը և որտեղից պետք է կարդալ հաղորդագրությունը: Դաշտ checkSequence պահպանում է ստուգման բիթերի հաջորդականությունը՝ ներկառուցված հաղորդագրության ճանաչումը ապահովելու համար: Ստատիկ մեթոդ getEncryptingFileParameters վերադարձնում է նշված ֆայլի պարամետրերը և հնարավոր հաղորդագրության բնութագրերը:

Մեթոդի ալգորիթմ encrypt դաս GIFEncryptorByLSBMethod:

Ստեգանոգրաֆիա GIF-ում

Եվ նրա կոդը.

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

Մեթոդի ալգորիթմը և աղբյուրի կոդը decrypt դաս GIFEncryptorByLSBMethod:

Ստեգանոգրաֆիա 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);
}

Դասի իրականացում GIFEncryptorByPaletteExtensionMethod նման կլինի, միայն տեղեկատվության պահպանման/ընթերցման եղանակն է տարբեր։

Դասարանում MainFrame փաթաթման մեթոդները նկարագրված են. encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), ինտերֆեյսի մեթոդների արդյունքների մշակում Encryptor և շփվել օգտագործողի հետ, այսինքն՝ բացել ֆայլի ընտրության երկխոսություն, ցույց տալ սխալ հաղորդագրություններ և այլն; ինչպես նաև այլ մեթոդներ. openImage(), թույլ տալով օգտվողին ընտրել պատկեր, exit(), որը դուրս է գալիս հավելվածից: Այս մեթոդները կոչվում են Action-ի համապատասխան մենյուի տարրերը: Այս դասը լրացուցիչ իրականացնում է օժանդակ մեթոդներ. createComponents() - ձևի բաղադրիչների ստեղծում, loadImageFile(File f) — պատկերի բեռնում ֆայլից հատուկ բաղադրիչի մեջ: Դասի իրականացում GIFEncryptorByPaletteExtensionMethod նման է դասի իրականացմանը GIFEncryptorByLSBMethod, հիմնական տարբերությունն այն է, թե ինչպես են հաղորդագրության բայթերը գրվում և ընթերցվում ներկապնակից։

Ծրագրի շահագործում

LBS մեթոդ

Ենթադրենք, կա այսպիսի պատկեր.

Ստեգանոգրաֆիա GIF-ում

Այս պատկերում ներկապնակը բաղկացած է 256 գույնից (ինչպես պահպանում է Paint-ը): Առաջին չորս գույներն են՝ սպիտակ, սև, կարմիր, կանաչ։ Մնացած գույները սև են։ Համաշխարհային պալիտրա բիթերի հաջորդականությունը կլինի հետևյալը.

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

Ստեգանոգրաֆիա GIF-ում

Հաղորդագրությունը ներկառուցվելուց հետո ընդգծված բիթերը կփոխարինվեն հաղորդագրության բիթերով: Ստացված պատկերը գրեթե չի տարբերվում բնօրինակից:

Original
Պատկեր՝ ներկառուցված հաղորդագրությամբ

Ստեգանոգրաֆիա GIF-ում
Ստեգանոգրաֆիա GIF-ում

Պալիտրա ընդլայնման մեթոդ

Այս մեթոդով հաղորդագրություն պարունակող պատկեր բացելիս կտեսնեք հետևյալ նկարը.

Ստեգանոգրաֆիա GIF-ում

Հասկանալի է, որ այս մեթոդը չի աշխատի լիարժեք լրտեսական գործունեության համար և կարող է պահանջել հաղորդագրության լրացուցիչ ծածկագրում:

Կոդավորումը/գաղտնագրումը անիմացիոն պատկերներում աշխատում է այնպես, ինչպես սովորական ստատիկ պատկերներում, բայց անիմացիան չի կոտրվել:

Օգտագործված աղբյուրները.

Բեռնել:

Source: www.habr.com

Добавить комментарий