Tervitused.
Mitte nii kaua aega tagasi, kui ma ülikoolis õppisin, oli kursusetöö erialal "Infoturbe tarkvara meetodid". Ülesanne nõudis meilt programmi loomist, mis manustab sõnumi GIF-failidesse. Otsustasin seda Javas teha.
Selles artiklis kirjeldan mõningaid teoreetilisi punkte ja seda, kuidas see väike programm loodi.
Teoreetiline osa
GIF-vormingus
GIF (Graphics Interchange Format – piltide vahetamise vorming) on graafiliste piltide salvestamise vorming, mis suudab salvestada tihendatud andmeid ilma kvaliteeti kaotamata kuni 256 värvi vormingus. Selle vormingu töötas välja 1987. aastal (GIF87a) CompuServe rasterpiltide edastamiseks võrkude kaudu. 1989. aastal muudeti vormingut (GIF89a), lisati läbipaistvuse ja animatsiooni tugi.
GIF-failidel on plokistruktuur. Need plokid on alati kindla pikkusega (või see oleneb mõnest lipust), mistõttu on peaaegu võimatu eksida, kus iga plokk asub. Lihtsaima mitte-animeeritud GIF-pildi struktuur GIF89a-vormingus:
Kõigist struktuuri plokkidest huvitab meid sel juhul globaalne paletiplokk ja paleti eest vastutavad parameetrid:
CT — globaalse paleti olemasolu. Kui see lipp on määratud, peab globaalne palett algama kohe pärast loogilist ekraanikäepidet.
Size — paleti suurus ja värvide arv pildil. Selle parameetri väärtused:
SUURUS
Värvide arv
Paleti suurus, baidid
7
256
768
6
128
384
5
64
192
4
32
96
3
16
48
2
8
24
1
4
12
0
2
6
Krüpteerimismeetodid
Pildifailides olevate sõnumite krüptimiseks kasutatakse järgmisi meetodeid.
LSB (Least Significant Bit) meetod
Paleti lisamise meetod
LSB meetod - levinud steganograafia meetod. See seisneb konteineri viimaste oluliste bittide (meie puhul globaalsete paletibaitide) asendamises peidetud sõnumi bittidega.
Programm kasutab selle meetodi osana globaalse paleti baitide kahte viimast bitti. See tähendab, et 24-bitise pildi puhul, kus punase, sinise ja rohelise värvipalett on kolm baiti, muutub iga värvikomponent pärast sellesse sõnumi manustamist maksimaalselt 3/255 gradatsiooni võrra. Selline muutus on esiteks inimsilmale nähtamatu või raskesti märgatav ning teiseks ei ole see nähtav madala kvaliteediga infoväljundseadmetel.
Teabe hulk sõltub otseselt pildipaleti suurusest. Kuna paleti maksimaalne suurus on 256 värvi ja kui iga värvi komponendisse on kirjutatud kaks sõnumibitti, siis on sõnumi maksimaalne pikkus (pildil oleva maksimaalse paletiga) 192 baiti. Kui sõnum on pildile manustatud, ei muutu faili suurus.
Paleti laiendamise meetod, mis töötab ainult GIF-struktuuri jaoks. See on kõige tõhusam väikese paletiga piltidel. Selle olemus seisneb selles, et see suurendab paleti suurust, pakkudes seeläbi täiendavat ruumi vajalike baitide kirjutamiseks värvibaitide asemel. Kui arvestada, et paleti minimaalne suurus on 2 värvi (6 baiti), siis võib manustatud sõnumi maksimaalne suurus olla 256 × 3–6 = 762 baiti. Puuduseks on madal krüptograafiline turvalisus; manustatud sõnumit saab lugeda mis tahes tekstiredaktoriga, kui sõnumit pole täiendavalt krüpteeritud.
Praktiline osa
Programmi kujundamine
Kõik krüpteerimis- ja dekrüpteerimisalgoritmide rakendamiseks vajalikud tööriistad on komplektis com.tsarik.steganography. See pakett sisaldab liidest Encryptor meetoditega encrypt и decrypt, klass Binary, mis annab võimaluse töötada nii bitimassiividega kui ka erandiklassidega UnableToEncryptException и UnableToDecryptException, mida tuleks kasutada liidesemeetodites Encryptor vastavalt kodeerimis- ja dekodeerimisvigade korral.
Peamine programmipakett com.tsarik.programs.gifed sisaldab staatilise meetodiga käivitatavat programmiklassi main, mis võimaldab teil programmi käivitada; klass, mis salvestab programmi parameetreid; ja paketid teiste klassidega.
Algoritmide endi rakendamist tutvustatakse paketis com.tsarik.programs.gifed.gif klassid GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethod. Mõlemad klassid rakendavad liidest Encryptor.
GIF-vormingu struktuuri põhjal saate luua üldise algoritmi sõnumi pildipaletti sisestamiseks:
Sõnumi olemasolu kindlakstegemiseks pildil on vaja sõnumi algusesse lisada teatud bittide jada, mille dekooder esimesena loeb ja õigsust kontrollib. Kui see ei ühti, siis loetakse, et pildil pole peidetud sõnumit. Järgmisena peate määrama sõnumi pikkuse. Siis sõnumi tekst ise.
Kogu rakenduse klassiskeem:
Programmi rakendamine
Kogu programmi rakendamise võib jagada kaheks komponendiks: liidese krüpteerimis- ja dekrüpteerimismeetodite rakendamine Encryptor, klassides GIFEncryptorByLSBMethod и GIFEncryptorByPaletteExtensionMethodja kasutajaliidese juurutamine.
Mõelge klassile GIFEncryptorByLSBMethod.
väljad firstLSBit и secondLSBit sisaldavad kujutise iga baidi bittide arvu, kuhu sõnum sisestada ja kust sõnum lugeda. Väli checkSequence salvestab kontrollbittide jada, et tagada manustatud sõnumi äratundmine. Staatiline meetod getEncryptingFileParameters tagastab määratud faili parameetrid ja potentsiaalse sõnumi omadused.
Meetodi algoritm encrypt klass GIFEncryptorByLSBMethod:
Ja tema kood:
@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();
}
Meetodi algoritm ja lähtekood decrypt klass 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);
}
Klassi rakendamine GIFEncryptorByPaletteExtensionMethod on sarnane, erinev on ainult teabe salvestamise/lugemise meetod.
Klassis MainFrame Kirjeldatakse pakkimismeetodeid: encryptImage(Encryptor encryptor) и decryptImage(Encryptor encryptor), töötleb liidesemeetodite tulemusi Encryptor ja kasutajaga suhtlemine, st failivaliku dialoogi avamine, veateadete näitamine jne; samuti muid meetodeid: openImage(), mis võimaldab kasutajal valida pildi, exit(), mis rakendusest väljub. Neid meetodeid kutsutakse Actionvastavad menüüelemendid. See klass rakendab lisaks abimeetodeid: createComponents() - vormikomponentide loomine, loadImageFile(File f) — pildi laadimine failist spetsiaalsesse komponenti. Klassi rakendamine GIFEncryptorByPaletteExtensionMethod sarnane klassi rakendamisega GIFEncryptorByLSBMethod, peamine erinevus on sõnumibaitide kirjutamise ja paleti lugemise viisis.
Programmi toimimine
LBS meetod
Oletame, et on selline pilt:
Sellel pildil koosneb palett 256 värvist (nagu Paint salvestab). Esimesed neli värvi on: valge, must, punane, roheline. Teised värvid on mustad. Globaalne paleti bittide jada on järgmine: