Steganografi di GIF

pengenalan

Selamat Datang.
Belum lama ini, ketika saya masih kuliah, ada mata kuliah pada disiplin ilmu “Metode perangkat lunak keamanan informasi”. Tugas tersebut mengharuskan kami membuat program yang menyematkan pesan dalam file GIF. Saya memutuskan untuk melakukannya di Jawa.

Pada artikel ini saya akan menjelaskan beberapa poin teoritis, serta bagaimana program kecil ini dibuat.

Bagian teoretis

format GIF

GIF (Graphics Interchange Format - format untuk bertukar gambar) adalah format untuk menyimpan gambar grafik, mampu menyimpan data terkompresi tanpa kehilangan kualitas dalam format hingga 256 warna. Format ini dikembangkan pada tahun 1987 (GIF87a) oleh CompuServe untuk mentransmisikan gambar raster melalui jaringan. Pada tahun 1989, formatnya diubah (GIF89a), dukungan untuk transparansi dan animasi ditambahkan.

File GIF memiliki struktur blok. Balok-balok ini selalu memiliki panjang yang tetap (atau bergantung pada beberapa bendera), sehingga hampir tidak mungkin membuat kesalahan tentang lokasi setiap balok. Struktur gambar GIF non-animasi paling sederhana dalam format GIF89a:

Steganografi di GIF

Dari semua blok struktur, dalam hal ini kita akan tertarik pada blok palet global dan parameter yang bertanggung jawab atas palet:

  • CT — kehadiran palet global. Jika tanda ini disetel, palet global harus dimulai segera setelah pengendali layar logis.
  • Size — ukuran palet dan jumlah warna dalam gambar. Nilai untuk parameter ini:

Ukuran
Jumlah warna
Ukuran palet, 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

Metode enkripsi

Metode berikut akan digunakan untuk mengenkripsi pesan dalam file gambar:

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

metode LSB - metode steganografi yang umum. Ini terdiri dari penggantian bit penting terakhir dalam wadah (dalam kasus kami, byte palet global) dengan bit pesan tersembunyi.

Program ini akan menggunakan dua bit terakhir dalam byte palet global sebagai bagian dari metode ini. Artinya untuk gambar 24 bit yang palet warnanya tiga byte untuk merah, biru, dan hijau, setelah disisipkan pesan ke dalamnya, setiap komponen warna akan berubah maksimal 3/255 gradasi. Perubahan seperti itu, pertama, tidak akan terlihat atau sulit dilihat oleh mata manusia, dan kedua, tidak akan terlihat pada perangkat keluaran informasi berkualitas rendah.

Jumlah informasi akan bergantung langsung pada ukuran palet gambar. Karena ukuran maksimum palet adalah 256 warna, dan jika dua bit pesan ditulis ke dalam komponen setiap warna, maka panjang pesan maksimum (dengan palet maksimum pada gambar) adalah 192 byte. Setelah pesan disematkan pada gambar, ukuran file tidak berubah.

Metode perluasan palet, yang hanya berfungsi untuk struktur GIF. Ini akan paling efektif pada gambar dengan palet kecil. Esensinya adalah meningkatkan ukuran palet, sehingga memberikan ruang tambahan untuk menulis byte yang diperlukan sebagai pengganti byte warna. Jika kita menganggap bahwa ukuran minimum palet adalah 2 warna (6 byte), maka ukuran maksimum pesan yang disematkan bisa menjadi 256 × 3–6 = 762 byte. Kerugiannya adalah keamanan kriptografi yang rendah, pesan yang disematkan dapat dibaca menggunakan editor teks apa pun jika pesan tersebut belum dienkripsi tambahan.

Bagian praktis

Desain program

Semua alat yang diperlukan untuk mengimplementasikan algoritma enkripsi dan dekripsi akan disertakan dalam paket com.tsarik.steganography. Paket ini mencakup antarmuka Encryptor dengan metode encrypt и decrypt, Kelas Binary, yang menyediakan kemampuan untuk bekerja dengan array bit, serta kelas pengecualian UnableToEncryptException и UnableToDecryptException, yang harus digunakan dalam metode antarmuka Encryptor dalam kasus kesalahan pengkodean dan decoding masing-masing.

Paket program utama com.tsarik.programs.gifed akan menyertakan kelas program yang dapat dijalankan dengan metode statis main, memungkinkan Anda menjalankan program; kelas yang menyimpan parameter program; dan paket dengan kelas lain.

Implementasi dari algoritmanya sendiri akan disajikan dalam paket com.tsarik.programs.gifed.gif kelas GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Kedua kelas ini akan mengimplementasikan antarmuka Encryptor.

Berdasarkan struktur format GIF, Anda dapat membuat algoritme umum untuk memasukkan pesan ke dalam palet gambar:

Steganografi di GIF

Untuk menentukan keberadaan pesan dalam suatu gambar, perlu untuk menambahkan urutan bit tertentu ke awal pesan, yang dibaca oleh decoder terlebih dahulu dan diperiksa kebenarannya. Jika tidak cocok, maka dianggap tidak ada pesan tersembunyi pada gambar tersebut. Selanjutnya Anda perlu menentukan panjang pesan. Kemudian teks pesan itu sendiri.

Diagram kelas seluruh aplikasi:

Steganografi di GIF

Implementasi program

Implementasi keseluruhan program dapat dibagi menjadi dua komponen: implementasi metode enkripsi antarmuka dan dekripsi Encryptor, di kelas GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, dan implementasi antarmuka pengguna.

Pertimbangkan kelasnya GIFEncryptorByLSBMethod.

Steganografi di GIF

Lapangan firstLSBit и secondLSBit berisi jumlah bit setiap byte gambar ke mana pesan harus dimasukkan dan dari mana pesan harus dibaca. Bidang checkSequence menyimpan urutan bit pemeriksaan untuk memastikan pengenalan pesan yang tertanam. Metode statis getEncryptingFileParameters mengembalikan parameter file tertentu dan karakteristik pesan potensial.

Algoritma metode encrypt kelas GIFEncryptorByLSBMethod:

Steganografi di GIF

Dan kodenya:

@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 kode sumber metode decrypt kelas GIFEncryptorByLSBMethod:

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

Implementasi kelas GIFEncryptorByPaletteExtensionMethod akan serupa, hanya cara menyimpan/membaca informasinya saja yang berbeda.

Di kelas MainFrame metode pembungkus dijelaskan: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), memproses hasil metode antarmuka Encryptor dan berinteraksi dengan pengguna, misalnya membuka dialog pemilihan file, menampilkan pesan kesalahan, dll.; serta metode lainnya: openImage(), memungkinkan pengguna untuk memilih gambar, exit(), yang keluar dari aplikasi. Metode-metode ini dipanggil dari Actionitem menu yang sesuai. Kelas ini juga mengimplementasikan metode tambahan: createComponents() - pembuatan komponen formulir, loadImageFile(File f) — memuat gambar ke dalam komponen khusus dari sebuah file. Implementasi kelas GIFEncryptorByPaletteExtensionMethod mirip dengan implementasi kelas GIFEncryptorByLSBMethod, perbedaan utamanya terletak pada cara byte pesan ditulis dan dibaca dari palet.

Operasi program

metode LBS

Katakanlah ada gambar seperti ini:

Steganografi di GIF

Dalam gambar ini, palet terdiri dari 256 warna (seperti yang disimpan Paint). Empat warna pertama adalah: putih, hitam, merah, hijau. Warna lainnya adalah hitam. Urutan bit palet global adalah sebagai berikut:

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

Steganografi di GIF

Setelah pesan tertanam, bit yang digarisbawahi akan diganti dengan bit dari pesan tersebut. Gambar yang dihasilkan hampir tidak berbeda dengan aslinya.

Asli
Gambar dengan pesan tertanam

Steganografi di GIF
Steganografi di GIF

Metode perluasan palet

Saat Anda membuka gambar yang berisi pesan menggunakan metode ini, Anda akan melihat gambar berikut:

Steganografi di GIF

Jelas bahwa metode ini tidak akan berfungsi untuk aktivitas spionase penuh, dan mungkin memerlukan enkripsi pesan tambahan.

Enkripsi/dekripsi pada gambar animasi berfungsi seperti gambar statis biasa, tetapi animasinya tidak rusak.

Sumber yang digunakan:

Unduh:

Sumber: www.habr.com

Tambah komentar