Steganografia in GIF

Introduzione

Saluti.
Ùn tantu tempu, quandu studiava à l'università, ci era un cursu in a disciplina "Metudi di software di sicurità di l'infurmazioni". L'assignazione ci vole à creà un prugramma chì incrusta un missaghju in i fugliali GIF. Aghju decisu di fà in Java.

In questu articulu, vi descriverà qualchi punti teorichi, è ancu cumu hè statu creatu stu picculu prugramma.

Parte teorica

formatu GIF

GIF (Graphics Interchange Format - un formatu per u scambiu d'imaghjini) hè un furmatu per almacenà l'imaghjini grafichi, capaci di almacenà dati cumpressi senza perdita di qualità in un formatu di 256 culori. Stu formatu hè statu sviluppatu in u 1987 (GIF87a) da CompuServe per trasmette l'imaghjini raster nantu à e rete. In u 1989, u furmatu hè statu mudificatu (GIF89a), u supportu per a trasparenza è l'animazione hè aghjuntu.

I schedari GIF anu una struttura di bloccu. Questi blocchi anu sempre una durata fissa (o dipende di qualchi bandiere), per quessa, hè quasi impussibile di fà un sbagliu induve si trova ogni bloccu. A struttura di l'imagine GIF micca animata più simplice in u formatu GIF89a:

Steganografia in GIF

Di tutti i blocchi di a struttura, in questu casu, seremu interessate in u bloccu di paleta globale è i paràmetri rispunsevuli di a paleta:

  • CT - prisenza di una paleta globale. Se sta bandiera hè stabilita, a paleta glubale deve principià subitu dopu à u manicu di u screnu logicu.
  • Size - dimensione di paleta è numeru di culori in a stampa. Valori per stu paràmetru:

Size
Numero di culori
Dimensione di paleta, byte

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

I metudi di criptografia

I seguenti metudi seranu usati per criptà i missaghji in i fugliali d'imaghjini:

  • Metudu LSB (Least Significant Bit).
  • Metudu di aghjunghje paleta

Metudu LSB - un metudu cumuni di steganografia. Hè custituitu di rimpiazzà l'ultimi bits significati in u cuntinuu (in u nostru casu, i bytes di paleta glubale) cù i pezzi di u messagiu oculatu.

U prugramma hà da utilizà l'ultimi dui bits in i bytes di paleta glubale cum'è parte di stu metudu. Questu significa chì per una maghjina di 24-bit, induve a paleta di culore hè di trè byte per u rossu, u blu è u verde, dopu à incrustà un missaghju in questu, ogni cumpunente di culore cambierà da un massimu di gradazioni 3/255. Un tali cambiamentu, prima, serà invisibili o difficiuli di nutà à l'ochju umanu, è in segundu, ùn serà micca visibile nantu à i dispusitivi di output d'informazioni di bassa qualità.

A quantità di infurmazione dipenderà direttamente da a dimensione di a paleta di l'imaghjini. Siccomu a dimensione massima di a paleta hè di 256 culori, è se dui bits di missaghju sò scritti in u cumpunente di ogni culore, a durata massima di u messagiu (cù a paleta massima in l'imaghjina) hè 192 bytes. Una volta u messagiu hè incrustatu in l'imaghjini, a dimensione di u schedariu ùn cambia micca.

Metudu di espansione di paleta, chì travaglia solu per a struttura GIF. Serà più efficace nantu à l'imaghjini cù una piccula paleta. A so essenza hè chì aumenta a dimensione di a paleta, fornendu cusì spaziu supplementu per scrive i bytes necessarii in u locu di i bytes di culore. Se cunsideremu chì a dimensione minima di a paleta hè 2 culori (6 bytes), allura a dimensione massima di u messagiu incrustatu pò esse 256 × 3-6 = 762 bytes. U svantaghju hè a bassa sicurezza criptografica; u missaghju incrustatu pò esse lettu cù qualsiasi editore di testu se u messagiu ùn hè micca statu sottumessu à una criptografia supplementaria.

Parte pratica

Cuncepimentu di prugramma

Tutti i strumenti necessarii per l'implementazione di l'algoritmi di criptografia è decifrazione seranu inclusi in u pacchettu com.tsarik.steganography. Stu pacchettu include l'interfaccia Encryptor cù metudi encrypt и decrypt, Classe Binary, chì furnisce a capacità di travaglià cù arrays di bit, è ancu classi d'eccezzioni UnableToEncryptException и UnableToDecryptException, chì deve esse usatu in metudi di interfaccia Encryptor in casu di errore di codificazione è di decodificazione rispettivamente.

U pacchettu di prugramma principale com.tsarik.programs.gifed includerà una classa di prugramma runnable cun un metudu staticu main, chì vi permette di eseguisce u prugramma; una classa chì guarda i paràmetri di u prugramma; è pacchetti cù altre classi.

L'implementazione di l'algoritmi stessi serà presentata in u pacchettu com.tsarik.programs.gifed.gif classi GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. E duie classi implementanu l'interfaccia Encryptor.

Basatu nantu à a struttura di u formatu GIF, pudete creà un algoritmu generale per intruduce un missaghju in a paleta di l'imaghjini:

Steganografia in GIF

Per determinà a presenza di un missaghju in una maghjina, hè necessariu aghjunghje una certa sequenza di bits à l'iniziu di u messagiu, chì u decoder leghje prima è verifica a correzione. Se ùn currisponde micca, allora hè cunsideratu chì ùn ci hè micca un missaghju oculatu in l'imaghjini. Dopu avete bisognu di specificà a durata di u missaghju. Allora u testu di u missaghju stessu.

Diagramma di classi di tutta l'applicazione:

Steganografia in GIF

Implementazione di u prugramma

L'implementazione di u prugramma sanu pò esse divisu in dui cumpunenti: implementazione di criptografia di l'interfaccia è metudi di decryption Encryptor, in classi GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, è l'implementazione di l'interfaccia d'utilizatore.

Cunsiderate a classa GIFEncryptorByLSBMethod.

Steganografia in GIF

campi firstLSBit и secondLSBit cuntene i numeri di bit di ogni byte di l'imaghjini in quale u messagiu deve esse inseritu è ​​da induve u missaghju deve esse lettu. Campu checkSequence almacena una sequenza di bit di verificazione per assicurà a ricunniscenza di u missaghju incrustatu. Metudu staticu getEncryptingFileParameters torna i paràmetri di u schedariu specificatu è e caratteristiche di u missaghju potenziale.

Algoritmu di u metudu encrypt класса GIFEncryptorByLSBMethod:

Steganografia in GIF

È u so codice:

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

Algoritmu è codice fonte di u metudu decrypt класса GIFEncryptorByLSBMethod:

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

Implementazione di a classe GIFEncryptorByPaletteExtensionMethod serà simile, solu u metudu di salvà / leghje infurmazione hè diversu.

In classe MainFrame I metudi di wrapper sò descritti: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), trasfurmendu i risultati di i metudi di l'interfaccia Encryptor è interagisce cù l'utilizatore, vale à dì apre un dialogu di selezzione di u schedariu, mostra missaghji d'errore, etc.; è ancu altri metudi: openImage(), chì permette à l'utilizatori di selezziunà una maghjina, exit(), chì esce da l'applicazione. Sti metudi sò chjamati da Actionle voci di menu corrispondenti a. Questa classa implementa in più metudi ausiliari: createComponents() - creazione di cumpunenti di forma, loadImageFile(File f) - carica una maghjina in un cumpunente speciale da un schedariu. Implementazione di a classe GIFEncryptorByPaletteExtensionMethod simile à l'implementazione di classi GIFEncryptorByLSBMethod, A diferenza principale hè in a manera chì i bytes di missaghju sò scritti è leghje da a paleta.

U funziunamentu di u prugramma

Metudu LBS

Diciamu chì ci hè una maghjina cum'è questu:

Steganografia in GIF

In questa imagine, a paleta hè custituita da 256 culori (cum'è Paint a salva). I primi quattru culori sò: biancu, neru, rossu, verde. L'altri culori sò neri. A sequenza di bit di palette globale serà a seguente:

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

Steganografia in GIF

Una volta chì u missaghju hè incrustatu, i bits sottolineati seranu rimpiazzati cù i bits da u messagiu. L'imaghjini resultanti ùn hè quasi micca sfarente di l'uriginale.

Originale
Image cù missaghju incrustatu

Steganografia in GIF
Steganografia in GIF

Metudu di espansione di paleta

Quandu avete apertu una maghjina chì cuntene un missaghju cù stu metudu, vi vede a seguente stampa:

Steganografia in GIF

Hè chjaru chì stu metudu ùn funziona micca per attività di spionamentu cumpletu, è pò esse bisognu di criptografia supplementu di u messagiu.

A criptografia / decryption in l'imaghjini animati funziona cum'è in l'imaghjini statici regulari, ma l'animazione ùn hè micca rotta.

Fonti aduprate:

Download:

Source: www.habr.com

Cumprate un hosting affidabile per i siti cù prutezzione DDoS, servitori VPS VDS 🔥 Cumprate un hosting di siti web affidabile cù prutezzione DDoS, servitori VPS VDS | ProHoster