Steganography a cikin GIF

Gabatarwar

Gaisuwa.
Ba da dadewa ba, lokacin da nake karatu a jami'a, akwai aikin kwas a cikin horo "Hanyoyin Tsaro na Software." Aikin ya buƙaci mu ƙirƙiri shirin da ke haɗa saƙo a cikin fayilolin GIF. Na yanke shawarar yin shi a Java.

A cikin wannan labarin zan bayyana wasu batutuwa na ka'idar, da kuma yadda aka ƙirƙiri wannan ƙaramin shirin.

Bangaren ilimi

Tsarin GIF

GIF (Tsarin Musanyar Hotuna - Tsarin musayar hotuna) tsari ne na adana hotuna masu hoto, mai ikon adana bayanan da aka matsa ba tare da asarar inganci ba a cikin sigar har zuwa launuka 256. An ƙirƙira wannan tsari a cikin 1987 (GIF87a) ta CompuServe don watsa hotunan raster akan cibiyoyin sadarwa. A cikin 1989, an gyaggyara tsarin (GIF89a), an ƙara tallafi don nuna gaskiya da raye-raye.

Fayilolin GIF suna da tsarin toshewa. Wadannan tubalan ko da yaushe suna da tsayayyen tsayi (ko ya dogara da wasu tutoci), don haka kusan ba zai yuwu a yi kuskure game da inda kowane shinge yake ba. Tsarin mafi sauƙin hoton GIF mara rai a cikin tsarin GIF89a:

Steganography a cikin GIF

Daga cikin dukkan tubalan tsarin, a cikin wannan yanayin za mu yi sha'awar toshe palette na duniya da sigogi da ke da alhakin palette:

  • CT - kasancewar palette na duniya. Idan an saita wannan tuta, palette ɗin duniya dole ne ya fara nan da nan bayan rikon allo mai ma'ana.
  • Size - Girman palette da adadin launuka a cikin hoton. Ƙimar wannan siga:

size
Yawan launuka
Girman palette, bytes

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Hanyoyin ɓoyewa

Za a yi amfani da hanyoyi masu zuwa don ɓoye saƙonni a cikin fayilolin hoto:

  • Hanyar LSB (Mafi Muhimmanci Bit).
  • Hanyar ƙara palette

Hanyar LSB - hanyar gama gari na steganography. Ya ƙunshi maye gurbin mahimman rago na ƙarshe a cikin akwati (a cikin yanayinmu, baiti na palette na duniya) tare da ɓoyayyun saƙon.

Shirin zai yi amfani da rago biyu na ƙarshe a cikin palette bytes na duniya a matsayin wani ɓangare na wannan hanya. Wannan yana nufin cewa ga hoton 24-bit, inda palette mai launi ya kasance bytes uku don ja, blue, da kore, bayan shigar da saƙo a cikinsa, kowane ɓangaren launi zai canza da iyakar 3/255 gradations. Irin wannan canjin, na farko, zai zama marar ganuwa ko wuyar ganewa ga idon ɗan adam, na biyu kuma, ba za a iya gani a kan ƙananan na'urorin fitar da bayanai ba.

Adadin bayanin zai dogara kai tsaye akan girman palette na hoto. Tun da matsakaicin girman palette shine launuka 256, kuma idan an rubuta ragowar saƙo guda biyu a cikin ɓangaren kowane launi, to matsakaicin tsayin saƙo (tare da matsakaicin palette a cikin hoton) shine 192 bytes. Da zarar an saka saƙon a cikin hoton, girman fayil ɗin ba ya canzawa.

Hanyar fadada palette, wanda kawai ke aiki don tsarin GIF. Zai zama mafi tasiri akan hotuna tare da ƙananan palette. Mahimmancinsa shine yana ƙara girman palette, ta haka yana samar da ƙarin sarari don rubuta abubuwan da suka dace a maimakon launi na launi. Idan muka yi la'akari da cewa mafi ƙarancin girman palette shine launuka 2 (6 bytes), to, matsakaicin girman saƙon da aka saka zai iya zama 256 × 3–6 = 762 bytes. Rashin lahani shine ƙarancin tsaro na sirri; ana iya karanta saƙon da aka haɗa ta amfani da kowane editan rubutu idan ba a shigar da saƙon zuwa ƙarin ɓoyewa ba.

Sashi mai amfani

Tsarin shirin

Duk kayan aikin da ake buƙata don aiwatar da ɓoyayyen ɓoyewa da ɓangarorin ɓarna za a haɗa su a cikin kunshin com.tsarik.steganography. Wannan fakitin ya haɗa da abin dubawa Encryptor tare da hanyoyin encrypt и decrypt, Darasi Binary, wanda ke ba da damar yin aiki tare da raƙuman ruwa, da kuma azuzuwan ban da UnableToEncryptException и UnableToDecryptException, wanda ya kamata a yi amfani da shi a cikin hanyoyin sadarwa Encryptor idan akwai kurakurai na ɓoyewa da yanke hukunci.

Babban kunshin shirin com.tsarik.programs.gifed zai haɗa da ajin shirye-shirye masu gudana tare da tsayayyen hanya main, ba ka damar gudanar da shirin; aji wanda ke adana sigogin shirye-shirye; da fakiti tare da sauran azuzuwan.

Za a gabatar da aiwatar da algorithms kansu a cikin kunshin com.tsarik.programs.gifed.gif azuzuwan GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Duk waɗannan azuzuwan za su aiwatar da hanyar sadarwa Encryptor.

Dangane da tsarin tsarin GIF, zaku iya ƙirƙirar algorithm na gaba ɗaya don gabatar da saƙo a cikin palette ɗin hoto:

Steganography a cikin GIF

Don tantance kasancewar saƙo a cikin hoto, dole ne a ƙara wasu jeri na bits zuwa farkon saƙon, wanda mai yankewa ya fara karantawa kuma ya bincika daidai. Idan bai dace ba, to ana la'akari da cewa babu wani ɓoye a cikin hoton. Na gaba kuna buƙatar tantance tsawon saƙon. Sai rubutun sakon da kansa.

Jadawalin aji na aikace-aikacen duka:

Steganography a cikin GIF

Aiwatar da shirin

Ana iya raba aiwatar da shirin gabaɗaya zuwa sassa biyu: aiwatar da ɓoyayyen ɓoyewa da hanyoyin ɓoye bayanan Encryptor, a cikin azuzuwan GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, da kuma aiwatar da haɗin gwiwar mai amfani.

Yi la'akari da aji GIFEncryptorByLSBMethod.

Steganography a cikin GIF

filayen firstLSBit и secondLSBit yana dauke da lambobi na kowane byte na hoton da ya kamata a shigar da sakon kuma daga inda ya kamata a karanta saƙon. Filin checkSequence tana adana jerin gwano don tabbatar da gane saƙon da aka haɗa. Hanyar a tsaye getEncryptingFileParameters yana dawo da sigogi na ƙayyadaddun fayil da halayen saƙon mai yuwuwa.

Hanyar algorithm encrypt aji GIFEncryptorByLSBMethod:

Steganography a cikin GIF

Kuma code ta:

@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 da lambar tushe na hanyar decrypt aji GIFEncryptorByLSBMethod:

Steganography a cikin 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);
}

Aiwatar da aji GIFEncryptorByPaletteExtensionMethod zai zama kama, kawai hanyar adanawa / karanta bayanai ya bambanta.

A cikin aji MainFrame An bayyana hanyoyin kunsa: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), sarrafa sakamakon hanyoyin sadarwa Encryptor da yin hulɗa tare da mai amfani, watau buɗe maganganun zaɓin fayil, nuna saƙonnin kuskure, da sauransu; da sauran hanyoyin: openImage(), kyale mai amfani ya zaɓi hoto, exit(), wanda ke fita aikace-aikacen. Ana kiran waɗannan hanyoyin daga Actionabubuwan menu masu dacewa. Hakanan wannan ajin yana aiwatar da hanyoyin taimako: createComponents() - ƙirƙirar abubuwan da aka gyara, loadImageFile(File f) - loda hoto zuwa wani yanki na musamman daga fayil. Aiwatar da aji GIFEncryptorByPaletteExtensionMethod kama da aiwatar da aji GIFEncryptorByLSBMethod, Babban bambanci shine yadda ake rubuta bytes na saƙo da karantawa daga palette.

Ayyukan shirin

Hanyar LBS

Bari mu ce akwai hoto kamar haka:

Steganography a cikin GIF

A cikin wannan hoton, palette ɗin ya ƙunshi launuka 256 (kamar yadda Paint ke adanawa). Launuka huɗu na farko sune: fari, baƙi, ja, kore. Sauran launuka baƙar fata ne. Jerin bit palette na duniya zai kasance kamar haka:

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

Steganography a cikin GIF

Da zarar an shigar da saƙon, za a maye gurbin raƙuman raƙuman da aka ja layi tare da ragowa daga saƙon. Hoton da aka samu kusan bai bambanta da na asali ba.

Asali
Hoto mai kunshe da saƙo

Steganography a cikin GIF
Steganography a cikin GIF

Hanyar fadada palette

Lokacin da ka bude hoto mai dauke da sako ta amfani da wannan hanya, za ka ga hoton kamar haka:

Steganography a cikin GIF

A bayyane yake cewa wannan hanyar ba za ta yi aiki don cikakkun ayyukan leƙen asiri ba, kuma tana iya buƙatar ƙarin ɓoyayyen saƙon.

Rufewa/rushewa a cikin hotuna masu rai yana aiki kamar a cikin hotuna na yau da kullun, amma rayarwa ba ta karye ba.

Abubuwan da aka yi amfani da su:

Download:

source: www.habr.com

Add a comment