GIF-də steqanoqrafiya

Giriş

Salamlar.
Bir müddət əvvəl, mən universitetdə oxuyanda “İnformasiya təhlükəsizliyinin proqram təminatı metodları” fənni üzrə kurs işi gedirdi. Tapşırıq bizdən GIF fayllarına mesaj yerləşdirən proqram yaratmağı tələb edirdi. Mən bunu Java-da etmək qərarına gəldim.

Bu yazıda bəzi nəzəri məqamları, eləcə də bu kiçik proqramın necə yaradıldığını təsvir edəcəyəm.

nəzəri hissə

GIF formatı

GIF (Graphics Interchange Format - şəkillərin mübadiləsi üçün format) 256 rəngə qədər formatda keyfiyyətini itirmədən sıxılmış məlumatları saxlamağa qadir olan qrafik təsvirlərin saxlanması üçün formatdır. Bu format 1987-ci ildə (GIF87a) CompuServe tərəfindən şəbəkələr üzərindən rastr təsvirləri ötürmək üçün hazırlanmışdır. 1989-cu ildə format dəyişdirildi (GIF89a), şəffaflıq və animasiya dəstəyi əlavə edildi.

GIF faylları blok quruluşuna malikdir. Bu blokların həmişə sabit uzunluğu var (yaxud bəzi bayraqlardan asılıdır), ona görə də hər blokun harada yerləşdiyi barədə səhv etmək demək olar ki, mümkün deyil. GIF89a formatında ən sadə cizgisiz GIF şəklinin quruluşu:

GIF-də steqanoqrafiya

Strukturun bütün bloklarından, bu halda qlobal palitra bloku və palitraya cavabdeh olan parametrlərlə maraqlanacağıq:

  • CT — qlobal palitranın olması. Əgər bu bayraq qoyulubsa, qlobal palitra məntiqi ekran dəstəyindən dərhal sonra başlamalıdır.
  • Size — palitranın ölçüsü və şəkildəki rənglərin sayı. Bu parametr üçün dəyərlər:

boy
Rənglərin sayı
Palitra ölçüsü, bayt

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

Şifrələmə üsulları

Şəkil fayllarında mesajları şifrələmək üçün aşağıdakı üsullardan istifadə olunacaq:

  • LSB (Least Significant Bit) metodu
  • Palitra əlavə üsulu

LSB üsulu - steqanoqrafiyanın ümumi üsulu. O, konteynerdəki son əhəmiyyətli bitləri (bizim vəziyyətimizdə qlobal palitra baytları) gizli mesajın bitləri ilə əvəz etməkdən ibarətdir.

Proqram bu metodun bir hissəsi kimi qlobal palitra baytlarında son iki bitdən istifadə edəcəkdir. Bu o deməkdir ki, palitra rənginin qırmızı, mavi və yaşıl üçün üç bayt olduğu 24 bitlik bir şəkil üçün mesaj daxil edildikdən sonra hər bir rəng komponenti maksimum 3/255 dərəcə dəyişəcək. Belə bir dəyişiklik, birincisi, insan gözü üçün görünməz və ya çətin hiss olunacaq, ikincisi, aşağı keyfiyyətli məlumat çıxaran cihazlarda görünməyəcəkdir.

Məlumatın miqdarı birbaşa şəkil palitrasının ölçüsündən asılı olacaq. Palitranın maksimum ölçüsü 256 rəng olduğundan və hər rəngin komponentinə iki mesaj biti yazıldıqda, mesajın maksimum uzunluğu (şəkildə maksimum palitra ilə) 192 baytdır. Mesaj şəkilə daxil edildikdən sonra faylın ölçüsü dəyişmir.

Palitranın genişləndirilməsi üsulu, yalnız GIF strukturu üçün işləyir. Kiçik bir palitrası olan şəkillərdə ən təsirli olacaq. Onun mahiyyəti ondan ibarətdir ki, o, palitranın ölçüsünü artırır və bununla da rəngli baytların yerinə lazımi baytların yazılması üçün əlavə yer təmin edir. Palitranın minimum ölçüsünün 2 rəng (6 bayt) olduğunu nəzərə alsaq, onda daxil edilmiş mesajın maksimum ölçüsü 256 × 3–6 = 762 bayt ola bilər. Dezavantaj aşağı kriptoqrafik təhlükəsizlikdir; əgər mesaj əlavə şifrələməyə məruz qalmamışdırsa, daxil edilmiş mesaj istənilən mətn redaktorundan istifadə etməklə oxuna bilər.

Praktiki hissə

Proqram dizayn

Şifrələmə və deşifrə alqoritmlərinin həyata keçirilməsi üçün bütün lazımi alətlər paketə daxil ediləcək com.tsarik.steganography. Bu paketə interfeys daxildir Encryptor üsullarla encrypt и decrypt, Sinif Binary, bu, bit massivləri, həmçinin istisna sinifləri ilə işləmək imkanı verir UnableToEncryptException и UnableToDecryptException, hansı interfeys üsullarında istifadə edilməlidir Encryptor müvafiq olaraq kodlaşdırma və dekodlaşdırma xətaları olduqda.

Əsas proqram paketi com.tsarik.programs.gifed statik metodla işlənə bilən proqram sinfini ehtiva edəcək main, proqramı işə salmağa imkan verir; proqram parametrlərini saxlayan sinif; və digər siniflərlə paketlər.

Alqoritmlərin həyata keçirilməsi paketdə təqdim olunacaq com.tsarik.programs.gifed.gif siniflər GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Bu siniflərin hər ikisi interfeysi həyata keçirəcək Encryptor.

GIF formatının strukturuna əsaslanaraq, şəkil palitrasına mesaj daxil etmək üçün ümumi alqoritm yarada bilərsiniz:

GIF-də steqanoqrafiya

Şəkildə mesajın mövcudluğunu müəyyən etmək üçün mesajın əvvəlinə müəyyən bit ardıcıllığını əlavə etmək lazımdır ki, dekoder ilk olaraq onu oxuyur və düzgünlüyünü yoxlayır. Əgər uyğun gəlmirsə, o zaman təsvirdə heç bir gizli mesaj olmadığı hesab edilir. Sonra mesajın uzunluğunu təyin etməlisiniz. Sonra mesajın mətni özü.

Bütün tətbiqin sinif diaqramı:

GIF-də steqanoqrafiya

Proqramın həyata keçirilməsi

Bütün proqramın həyata keçirilməsini iki komponentə bölmək olar: interfeys şifrələməsinin həyata keçirilməsi və şifrənin açılması üsulları Encryptor, siniflərdə GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod, və istifadəçi interfeysinin həyata keçirilməsi.

Sinfi nəzərdən keçirin GIFEncryptorByLSBMethod.

GIF-də steqanoqrafiya

sahələri firstLSBit и secondLSBit mesajın daxil edilməli olduğu və mesajın haradan oxunmalı olduğu təsvirin hər baytının bitlərinin nömrələrini ehtiva edir. Sahə checkSequence daxil edilmiş mesajın tanınmasını təmin etmək üçün yoxlama bit ardıcıllığını saxlayır. Statik üsul getEncryptingFileParameters göstərilən faylın parametrlərini və potensial mesajın xüsusiyyətlərini qaytarır.

Metod alqoritmi encrypt sinif GIFEncryptorByLSBMethod:

GIF-də steqanoqrafiya

Və onun kodu:

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

Metodun alqoritmi və mənbə kodu decrypt sinif GIFEncryptorByLSBMethod:

GIF-də steqanoqrafiya

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

Sinfin həyata keçirilməsi GIFEncryptorByPaletteExtensionMethod oxşar olacaq, yalnız məlumatın saxlanması/oxuması üsulu fərqlidir.

Sinifdə MainFrame sarğı üsulları təsvir edilmişdir: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), interfeys üsullarının nəticələrinin işlənməsi Encryptor və istifadəçi ilə qarşılıqlı əlaqə, yəni fayl seçimi dialoqunun açılması, səhv mesajlarının göstərilməsi və s.; eləcə də digər üsullar: openImage(), istifadəçiyə şəkil seçməyə imkan verir, exit(), tətbiqdən çıxan. Bu üsullar dən çağırılır Actionmüvafiq menyu elementləri. Bu sinif əlavə olaraq köməkçi metodları həyata keçirir: createComponents() - forma komponentlərinin yaradılması, loadImageFile(File f) — şəkilin fayldan xüsusi komponentə yüklənməsi. Sinfin həyata keçirilməsi GIFEncryptorByPaletteExtensionMethod sinfin həyata keçirilməsinə bənzəyir GIFEncryptorByLSBMethod, əsas fərq mesaj baytlarının palitradan yazılması və oxunmasındadır.

Proqram əməliyyatı

LBS üsulu

Deyək ki, belə bir görüntü var:

GIF-də steqanoqrafiya

Bu şəkildəki palitra 256 rəngdən ibarətdir (Paint saxladığı kimi). İlk dörd rəng: ağ, qara, qırmızı, yaşıl. Digər rənglər qaradır. Qlobal palitranın bit ardıcıllığı aşağıdakı kimi olacaq:

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

GIF-də steqanoqrafiya

Mesaj daxil edildikdən sonra altı çizili bitlər mesajın bitləri ilə əvəz olunacaq. Nəticədə ortaya çıxan görüntü orijinaldan demək olar ki, fərqlənmir.

Orijinal
Daxili mesajı olan şəkil

GIF-də steqanoqrafiya
GIF-də steqanoqrafiya

Palitranın genişləndirilməsi üsulu

Bu üsuldan istifadə edərək mesajı olan şəkli açdığınız zaman aşağıdakı şəkli görəcəksiniz:

GIF-də steqanoqrafiya

Aydındır ki, bu üsul tamhüquqlu casusluq fəaliyyəti üçün işləməyəcək və mesajın əlavə şifrələnməsi tələb oluna bilər.

Animasiya şəkillərində şifrələmə/şifrənin açılması adi statik şəkillərdə olduğu kimi işləyir, lakin animasiya pozulmur.

İstifadə olunan mənbələr:

Download:

Mənbə: www.habr.com

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