Salomlar.
Yaqinda men universitetda o'qiyotganimda "Axborot xavfsizligini dasturiy ta'minot usullari" fanidan kurs ishi bor edi. Topshiriq bizdan xabarni GIF fayllariga joylashtiradigan dastur yaratishni talab qildi. Men buni Java-da qilishga qaror qildim.
Ushbu maqolada men ba'zi nazariy fikrlarni tasvirlab beraman, shuningdek, bu kichik dastur qanday yaratilgan.
Nazariy qism
GIF formati
GIF (Graphics Interchange Format - tasvirlarni almashish formati) - bu grafik tasvirlarni saqlash uchun format bo'lib, siqilgan ma'lumotlarni sifatini yo'qotmasdan 256 ranggacha formatda saqlashga qodir. Ushbu format 1987 yilda (GIF87a) CompuServe tomonidan rastrli tasvirlarni tarmoqlar orqali uzatish uchun ishlab chiqilgan. 1989 yilda format o'zgartirildi (GIF89a), shaffoflik va animatsiyani qo'llab-quvvatlash qo'shildi.
GIF fayllari blokli tuzilishga ega. Ushbu bloklar har doim qattiq uzunlikka ega (yoki bu ba'zi bayroqlarga bog'liq), shuning uchun har bir blokning qaerda joylashganligi haqida xato qilish deyarli mumkin emas. GIF89a formatidagi eng oddiy animatsiyasiz GIF tasvirining tuzilishi:
Strukturaning barcha bloklaridan, bu holda biz global palitra bloki va palitra uchun mas'ul bo'lgan parametrlarga qiziqamiz:
CT β global palitraning mavjudligi. Agar bu bayroq o'rnatilgan bo'lsa, global palitra mantiqiy ekran tutqichidan keyin darhol boshlanishi kerak.
Size β palitraning o'lchami va rasmdagi ranglar soni. Ushbu parametr uchun qiymatlar:
O'lcham
Ranglar soni
Palitra hajmi, baytlar
7
256
768
6
128
384
5
64
192
4
32
96
3
16
48
2
8
24
1
4
12
0
2
6
Shifrlash usullari
Rasm fayllaridagi xabarlarni shifrlash uchun quyidagi usullar qo'llaniladi:
LSB (Least Significant Bit) usuli
Palitrani qo'shish usuli
LSB usuli - steganografiyaning keng tarqalgan usuli. U konteynerdagi oxirgi muhim bitlarni (bizning holimizda global palitra baytlari) yashirin xabarning bitlari bilan almashtirishdan iborat.
Dastur ushbu usulning bir qismi sifatida global palitradagi baytlardagi oxirgi ikki bitdan foydalanadi. Bu shuni anglatadiki, ranglar palitrasi qizil, ko'k va yashil ranglar uchun uch baytdan iborat bo'lgan 24 bitli tasvir uchun unga xabar kiritilgandan so'ng, har bir rang komponenti maksimal 3/255 gradatsiyaga o'zgaradi. Bunday o'zgarish, birinchidan, inson ko'ziga ko'rinmas yoki sezilishi qiyin bo'ladi, ikkinchidan, u past sifatli axborot chiqarish qurilmalarida ko'rinmaydi.
Ma'lumot miqdori to'g'ridan-to'g'ri tasvirlar palitrasining o'lchamiga bog'liq bo'ladi. Palitraning maksimal hajmi 256 rang bo'lganligi sababli va har bir rangning komponentiga ikkita xabar biti yozilsa, u holda maksimal xabar uzunligi (tasvirdagi maksimal palitra bilan) 192 baytni tashkil qiladi. Xabar rasmga kiritilgandan so'ng, fayl hajmi o'zgarmaydi.
Palitrani kengaytirish usuli, bu faqat GIF tuzilishi uchun ishlaydi. Kichkina palitrali tasvirlarda eng samarali bo'ladi. Uning mohiyati shundaki, u palitraning hajmini oshiradi va shu bilan rangli baytlar o'rniga kerakli baytlarni yozish uchun qo'shimcha joy beradi. Agar palitraning minimal hajmi 2 rang (6 bayt) ekanligini hisobga olsak, u holda o'rnatilgan xabarning maksimal hajmi 256 Γ 3-6 = 762 bayt bo'lishi mumkin. Kamchilik - kriptografik xavfsizlikning pastligi; agar xabar qo'shimcha shifrlashdan o'tkazilmagan bo'lsa, o'rnatilgan xabarni istalgan matn muharriri yordamida o'qish mumkin.
Amaliy qism
Dastur dizayni
Paketga shifrlash va shifrni ochish algoritmlarini amalga oshirish uchun barcha zarur vositalar kiritiladi com.tsarik.steganography. Ushbu paket interfeysni o'z ichiga oladi Encryptor usullari bilan encrypt ΠΈ decrypt, Sinf Binary, bu bit massivlari, shuningdek istisno sinflari bilan ishlash qobiliyatini ta'minlaydi UnableToEncryptException ΠΈ UnableToDecryptException, bu interfeys usullarida qo'llanilishi kerak Encryptor mos ravishda kodlash va dekodlash xatolari bo'lsa.
Asosiy dastur to'plami com.tsarik.programs.gifed statik usul bilan ishlaydigan dastur sinfini o'z ichiga oladi main, dasturni ishga tushirish imkonini beruvchi; dastur parametrlarini saqlaydigan sinf; va boshqa sinflar bilan paketlar.
Algoritmlarning o'zlari amalga oshirilishi paketda taqdim etiladi com.tsarik.programs.gifed.gif sinflar GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod. Ushbu sinflarning ikkalasi ham interfeysni amalga oshiradi Encryptor.
GIF formatining tuzilishiga asoslanib, siz tasvirlar palitrasiga xabar kiritishning umumiy algoritmini yaratishingiz mumkin:
Tasvirda xabar mavjudligini aniqlash uchun xabarning boshiga ma'lum bir ketma-ketlikni qo'shish kerak, bu dekoder birinchi bo'lib o'qiydi va to'g'riligini tekshiradi. Agar u mos kelmasa, rasmda yashirin xabar yo'q deb hisoblanadi. Keyin xabarning uzunligini belgilashingiz kerak. Keyin xabarning o'zi.
Butun ilovaning sinf diagrammasi:
Dasturni amalga oshirish
Butun dasturni amalga oshirishni ikkita komponentga bo'lish mumkin: interfeysni shifrlash va shifrni ochish usullarini amalga oshirish Encryptor, sinflarda GIFEncryptorByLSBMethod ΠΈ GIFEncryptorByPaletteExtensionMethod, va foydalanuvchi interfeysini amalga oshirish.
Sinfni ko'rib chiqing GIFEncryptorByLSBMethod.
sohalar firstLSBit ΠΈ secondLSBit xabar kiritilishi kerak bo'lgan va xabarni o'qilishi kerak bo'lgan tasvirning har bir baytining bit raqamlarini o'z ichiga oladi. Maydon checkSequence o'rnatilgan xabarning tan olinishini ta'minlash uchun chek bit ketma-ketligini saqlaydi. Statik usul getEncryptingFileParameters belgilangan fayl parametrlarini va potentsial xabarning xususiyatlarini qaytaradi.
Usul algoritmi encrypt daraja GIFEncryptorByLSBMethod:
Va uning kodi:
@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();
}
Usulning algoritmi va manba kodi decrypt daraja GIFEncryptorByLSBMethod:
@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);
}
Sinfni amalga oshirish GIFEncryptorByPaletteExtensionMethod o'xshash bo'ladi, faqat ma'lumotni saqlash/o'qish usuli boshqacha.
Sinfda MainFrame o'rash usullari tavsiflanadi: encryptImage(Encryptor encryptor) ΠΈ decryptImage(Encryptor encryptor), interfeys usullari natijalarini qayta ishlash Encryptor va foydalanuvchi bilan muloqot qilish, ya'ni fayl tanlash dialogini ochish, xato xabarlarini ko'rsatish va h.k.; shuningdek, boshqa usullar: openImage(), foydalanuvchiga rasm tanlashga ruxsat berish, exit(), bu ilovadan chiqadi. Ushbu usullar dan chaqiriladi Actionning tegishli menyu elementlari. Ushbu sinf qo'shimcha ravishda yordamchi usullarni amalga oshiradi: createComponents() - shakl komponentlarini yaratish; loadImageFile(File f) β rasmni fayldan maxsus komponentga yuklash. Sinfni amalga oshirish GIFEncryptorByPaletteExtensionMethod sinfni amalga oshirishga o'xshaydi GIFEncryptorByLSBMethod, asosiy farq xabar baytlarini yozish va palitradan o'qish usulida.
Dasturning ishlashi
LBS usuli
Aytaylik, shunday tasvir bor:
Ushbu rasmda palitra 256 rangdan iborat (Bo'yoq saqlaganidek). Birinchi to'rtta rang: oq, qora, qizil, yashil. Boshqa ranglar qora. Global palitraning bit ketma-ketligi quyidagicha bo'ladi: