Steganografi dalam GIF

Pengenalan

ΠŸΡ€ΠΈΠ²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽ.
Tidak lama dahulu, semasa saya belajar di universiti, terdapat kerja kursus dalam disiplin "Kaedah perisian keselamatan maklumat." Tugasan itu memerlukan kami membuat program yang membenamkan mesej dalam fail GIF. Saya memutuskan untuk melakukannya di Jawa.

Dalam artikel ini saya akan menerangkan beberapa perkara teori, serta bagaimana program kecil ini dicipta.

Bahagian teori

format GIF

GIF (Graphics Interchange Format - format untuk bertukar-tukar imej) ialah format untuk menyimpan imej grafik, mampu menyimpan data mampat tanpa kehilangan kualiti dalam format sehingga 256 warna. Format ini telah dibangunkan pada tahun 1987 (GIF87a) oleh CompuServe untuk menghantar imej raster melalui rangkaian. Pada tahun 1989, format telah diubah suai (GIF89a), sokongan untuk ketelusan dan animasi telah ditambah.

Fail GIF mempunyai struktur blok. Blok ini sentiasa mempunyai panjang tetap (atau ia bergantung pada beberapa bendera), jadi hampir mustahil untuk membuat kesilapan tentang di mana setiap blok terletak. Struktur imej GIF bukan animasi paling ringkas dalam format GIF89a:

Steganografi dalam GIF

Daripada semua blok struktur, dalam kes ini kita akan berminat dengan blok palet global dan parameter yang bertanggungjawab untuk palet:

  • CT β€” kehadiran palet global. Jika bendera ini ditetapkan, palet global mesti bermula serta-merta selepas pemegang skrin logik.
  • Size β€” saiz palet dan bilangan warna dalam gambar. Nilai untuk parameter ini:

Saiz
Bilangan warna
Saiz palet, bait

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Kaedah penyulitan

Kaedah berikut akan digunakan untuk menyulitkan mesej dalam fail imej:

  • Kaedah LSB (Least Significant Bit).
  • Kaedah penambahan palet

kaedah LSB - kaedah steganografi yang biasa. Ia terdiri daripada menggantikan bit penting terakhir dalam bekas (dalam kes kami, bait palet global) dengan bit mesej tersembunyi.

Program ini akan menggunakan dua bit terakhir dalam bait palet global sebagai sebahagian daripada kaedah ini. Ini bermakna bahawa untuk imej 24-bit, di mana warna palet ialah tiga bait untuk merah, biru dan hijau, selepas membenamkan mesej ke dalamnya, setiap komponen warna akan berubah sebanyak maksimum 3/255 penggredan. Perubahan sedemikian, pertama, tidak dapat dilihat atau sukar dilihat oleh mata manusia, dan kedua, ia tidak akan kelihatan pada peranti output maklumat berkualiti rendah.

Jumlah maklumat secara langsung akan bergantung pada saiz palet imej. Oleh kerana saiz maksimum palet ialah 256 warna, dan jika dua bit mesej ditulis ke dalam komponen setiap warna, maka panjang mesej maksimum (dengan palet maksimum dalam imej) ialah 192 bait. Setelah mesej dibenamkan dalam imej, saiz fail tidak berubah.

Kaedah pengembangan palet, yang hanya berfungsi untuk struktur GIF. Ia akan menjadi paling berkesan pada imej dengan palet kecil. Intipatinya ialah ia meningkatkan saiz palet, dengan itu menyediakan ruang tambahan untuk menulis bait yang diperlukan sebagai ganti bait warna. Jika kita menganggap bahawa saiz minimum palet ialah 2 warna (6 bait), maka saiz maksimum mesej terbenam boleh menjadi 256 Γ— 3–6 = 762 bait. Kelemahannya ialah keselamatan kriptografi yang rendah; mesej terbenam boleh dibaca menggunakan mana-mana editor teks jika mesej itu tidak tertakluk kepada penyulitan tambahan.

Bahagian praktikal

Reka bentuk program

Semua alat yang diperlukan untuk melaksanakan algoritma penyulitan dan penyahsulitan akan disertakan dalam pakej com.tsarik.steganography. Pakej ini termasuk antara muka Encryptor dengan kaedah encrypt ΠΈ decrypt, Kelas Binary, yang menyediakan keupayaan untuk bekerja dengan tatasusunan bit, serta kelas pengecualian UnableToEncryptException ΠΈ UnableToDecryptException, yang harus digunakan dalam kaedah antara muka Encryptor sekiranya berlaku ralat pengekodan dan penyahkodan masing-masing.

Pakej program utama com.tsarik.programs.gifed akan memasukkan kelas program yang boleh dijalankan dengan kaedah statik main, membolehkan anda menjalankan program; kelas yang menyimpan parameter program; dan pakej dengan kelas lain.

Pelaksanaan algoritma itu sendiri akan dibentangkan dalam pakej com.tsarik.programs.gifed.gif kelas GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod. Kedua-dua kelas ini akan melaksanakan antara muka Encryptor.

Berdasarkan struktur format GIF, anda boleh membuat algoritma umum untuk memperkenalkan mesej ke dalam palet imej:

Steganografi dalam GIF

Untuk menentukan kehadiran mesej dalam imej, adalah perlu untuk menambah jujukan bit tertentu pada permulaan mesej, yang dibaca oleh penyahkod terlebih dahulu dan memeriksa ketepatannya. Jika tidak sepadan, maka dianggap tiada mesej tersembunyi dalam imej. Seterusnya anda perlu menentukan panjang mesej. Kemudian teks mesej itu sendiri.

Gambar rajah kelas keseluruhan aplikasi:

Steganografi dalam GIF

Pelaksanaan program

Pelaksanaan keseluruhan program boleh dibahagikan kepada dua komponen: pelaksanaan penyulitan antara muka dan kaedah penyahsulitan Encryptor, dalam kelas GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod, dan pelaksanaan antara muka pengguna.

Pertimbangkan kelas GIFEncryptorByLSBMethod.

Steganografi dalam GIF

padang firstLSBit ΠΈ secondLSBit mengandungi bilangan bit setiap bait imej yang mana mesej harus dimasukkan dan dari mana mesej itu harus dibaca. Padang checkSequence menyimpan jujukan bit semak untuk memastikan pengecaman mesej terbenam. Kaedah statik getEncryptingFileParameters mengembalikan parameter fail yang ditentukan dan ciri-ciri mesej yang berpotensi.

Algoritma kaedah encrypt kelas GIFEncryptorByLSBMethod:

Steganografi dalam GIF

Dan kodnya:

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

Algoritma dan kod sumber kaedah decrypt kelas GIFEncryptorByLSBMethod:

Steganografi dalam 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);
}

Pelaksanaan kelas GIFEncryptorByPaletteExtensionMethod akan sama, cuma kaedah menyimpan/membaca maklumat sahaja berbeza.

Di dalam kelas MainFrame kaedah pembalut diterangkan: encryptImage(Encryptor encryptor) ΠΈ decryptImage(Encryptor encryptor), memproses hasil kaedah antara muka Encryptor dan berinteraksi dengan pengguna, iaitu membuka dialog pemilihan fail, menunjukkan mesej ralat, dsb.; serta kaedah lain: openImage(), membenarkan pengguna memilih imej, exit(), yang keluar dari aplikasi. Kaedah ini dipanggil daripada Actionitem menu yang sepadan. Kelas ini juga melaksanakan kaedah tambahan: createComponents() - penciptaan komponen bentuk, loadImageFile(File f) β€” memuatkan imej ke dalam komponen khas daripada fail. Pelaksanaan kelas GIFEncryptorByPaletteExtensionMethod serupa dengan pelaksanaan kelas GIFEncryptorByLSBMethod, perbezaan utama adalah dalam cara bait mesej ditulis dan dibaca daripada palet.

Operasi program

kaedah LBS

Katakan ada imej seperti ini:

Steganografi dalam GIF

Dalam imej ini, palet terdiri daripada 256 warna (seperti yang disimpan Cat). Empat warna pertama ialah: putih, hitam, merah, hijau. Warna lain hitam. Urutan bit palet global adalah seperti berikut:

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

Steganografi dalam GIF

Setelah mesej dibenamkan, bit yang digariskan akan digantikan dengan bit daripada mesej. Imej yang terhasil hampir tidak berbeza dengan yang asal.

Asal
Imej dengan mesej terbenam

Steganografi dalam GIF
Steganografi dalam GIF

Kaedah pengembangan palet

Apabila anda membuka imej yang mengandungi mesej menggunakan kaedah ini, anda akan melihat gambar berikut:

Steganografi dalam GIF

Adalah jelas bahawa kaedah ini tidak akan berfungsi untuk aktiviti pengintipan sepenuhnya, dan mungkin memerlukan penyulitan tambahan mesej.

Penyulitan/penyahsulitan dalam imej animasi berfungsi seperti dalam imej statik biasa, tetapi animasi tidak rosak.

Sumber yang digunakan:

Muat turun:

Sumber: www.habr.com

Tambah komen