Sissejuhatus
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:
MÔÔt
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:
11111111 11111111 11111111 00000000 00000000 00000000 11111111 00000000 00000000 00000000 11111111 00000000...

Kui sÔnum on manustatud, asendatakse allajoonitud bitid sÔnumi bittidega. Saadud pilt peaaegu ei erine originaalist.
Originaal
Manustatud sÔnumiga pilt

![]()
Paleti laiendamise meetod
Kui avate seda meetodit kasutades sÔnumit sisaldava pildi, nÀete jÀrgmist pilti:

On selge, et see meetod ei tööta tĂ€ieĂ”igusliku spionaaĆŸitegevuse jaoks ja vĂ”ib nĂ”uda sĂ”numi tĂ€iendavat krĂŒpteerimist.
Animeeritud piltide krĂŒptimine/dekrĂŒpteerimine toimib nagu tavaliste staatiliste piltide puhul, kuid animatsioon ei katke.
Kasutatud allikad:
Lae alla:
Allikas: www.habr.com
