Sveicieni.
Ne tik sen, kad mÄcÄ«jos universitÄtÄ, bija kursa darbs disciplÄ«nÄ āInformÄcijas droŔības programmatÅ«ras metodesā. Lai veiktu uzdevumu, mums bija jÄizveido programma, kas iegultu ziÅojumu GIF failos. Es nolÄmu to darÄ«t Java.
Å ajÄ rakstÄ es aprakstÄ«Å”u dažus teorÄtiskos punktus, kÄ arÄ« to, kÄ Å”Ä« mazÄ programma tika izveidota.
TeorÄtiskÄ daļa
GIF formÄtÄ
GIF (Graphics Interchange Format ā attÄlu apmaiÅas formÄts) ir grafisko attÄlu glabÄÅ”anas formÄts, kas spÄj saglabÄt saspiestus datus, nezaudÄjot kvalitÄti, formÄtÄ lÄ«dz 256 krÄsÄm. Å o formÄtu 1987. gadÄ (GIF87a) izstrÄdÄja CompuServe rastra attÄlu pÄrsÅ«tÄ«Å”anai pa tÄ«kliem. 1989. gadÄ formÄts tika modificÄts (GIF89a), tika pievienots caurspÄ«dÄ«guma un animÄcijas atbalsts.
GIF failiem ir bloku struktÅ«ra. Å iem blokiem vienmÄr ir noteikts garums (vai tas ir atkarÄ«gs no dažiem karogiem), tÄpÄc ir gandrÄ«z neiespÄjami kļūdÄ«ties, kur katrs bloks atrodas. VienkÄrÅ”ÄkÄ neanimÄtÄ GIF attÄla struktÅ«ra GIF89a formÄtÄ:
No visiem struktÅ«ras blokiem Å”ajÄ gadÄ«jumÄ mÅ«s interesÄs globÄlais paletes bloks un parametri, kas ir atbildÄ«gi par paleti:
CT ā globÄlÄs paletes klÄtbÅ«tne. Ja Å”is karodziÅÅ” ir iestatÄ«ts, globÄlajai paletei jÄsÄkas tÅ«lÄ«t aiz loÄ£iskÄ ekrÄna roktura.
Size ā paletes izmÄrs un krÄsu skaits attÄlÄ. Å Ä« parametra vÄrtÄ«bas:
IzmÄri
KrÄsu skaits
Paletes izmÄrs, baiti
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ÄÅ”anas metodes
Lai Å”ifrÄtu ziÅojumus attÄlu failos, tiks izmantotas Å”Ädas metodes:
LSB (least Significant Bit) metode
Paletes pievienoŔanas metode
LSB metode - izplatÄ«ta steganogrÄfijas metode. Tas sastÄv no pÄdÄjo nozÄ«mÄ«go bitu aizstÄÅ”anas konteinerÄ (mÅ«su gadÄ«jumÄ globÄlo paletes baitu) ar slÄptÄ ziÅojuma bitiem.
Programma izmantos pÄdÄjos divus bitus globÄlÄs paletes baitos kÄ daļu no Ŕīs metodes. Tas nozÄ«mÄ, ka 24 bitu attÄlam, kura krÄsu palete ir trÄ«s baiti sarkanai, zilai un zaļai krÄsai, pÄc ziÅojuma iegulÅ”anas tajÄ katra krÄsu sastÄvdaļa mainÄ«sies ne vairÄk kÄ par 3/255 gradÄcijÄm. Å Ädas izmaiÅas, pirmkÄrt, bÅ«s neredzamas vai grÅ«ti pamanÄmas cilvÄka acij, otrkÄrt, tÄs nebÅ«s redzamas nekvalitatÄ«vÄs informÄcijas izvades ierÄ«cÄs.
InformÄcijas apjoms bÅ«s tieÅ”i atkarÄ«gs no attÄla paletes izmÄra. TÄ kÄ paletes maksimÄlais izmÄrs ir 256 krÄsas un, ja katras krÄsas komponentÄ ir ierakstÄ«ti divi ziÅojuma biti, tad maksimÄlais ziÅojuma garums (ar maksimÄlo paleti attÄlÄ) ir 192 baiti. Kad ziÅojums ir iegults attÄlÄ, faila lielums nemainÄs.
Paletes paplaÅ”inÄÅ”anas metode, kas darbojas tikai GIF struktÅ«rai. Tas bÅ«s visefektÄ«vÄkais attÄliem ar nelielu paleti. TÄs bÅ«tÄ«ba ir tÄda, ka tas palielina paletes izmÄru, tÄdÄjÄdi nodroÅ”inot papildu vietu nepiecieÅ”amo baitu rakstÄ«Å”anai krÄsu baitu vietÄ. Ja Åemam vÄrÄ, ka minimÄlais paletes izmÄrs ir 2 krÄsas (6 baiti), tad iegultÄ ziÅojuma maksimÄlais izmÄrs var bÅ«t 256 Ć 3ā6 = 762 baiti. TrÅ«kums ir zemÄ kriptogrÄfiskÄ droŔība; iegulto ziÅojumu var lasÄ«t, izmantojot jebkuru teksta redaktoru, ja ziÅojums nav pakļauts papildu Å”ifrÄÅ”anai.
PraktiskÄ daļa
Programmas dizains
Visi nepiecieÅ”amie rÄ«ki Å”ifrÄÅ”anas un atÅ”ifrÄÅ”anas algoritmu ievieÅ”anai tiks iekļauti komplektÄ com.tsarik.steganography. Å ajÄ pakotnÄ ir iekļauts interfeiss Encryptor ar metodÄm encrypt Šø decrypt, Klase Binary, kas nodroÅ”ina iespÄju strÄdÄt ar bitu masÄ«viem, kÄ arÄ« izÅÄmumu klasÄm UnableToEncryptException Šø UnableToDecryptException, kas jÄizmanto saskarnes metodÄs Encryptor attiecÄ«gi kodÄÅ”anas un dekodÄÅ”anas kļūdu gadÄ«jumÄ.
GalvenÄ programmu pakete com.tsarik.programs.gifed ietvers darbinÄmu programmu klasi ar statisku metodi main, kas ļauj palaist programmu; klase, kas glabÄ programmas parametrus; un paketes ar citÄm klasÄm.
PaÅ”u algoritmu ievieÅ”ana tiks prezentÄta komplektÄ com.tsarik.programs.gifed.gif klases GIFEncryptorByLSBMethod Šø GIFEncryptorByPaletteExtensionMethod. Abas Ŕīs klases ieviesÄ«s saskarni Encryptor.
Pamatojoties uz GIF formÄta struktÅ«ru, varat izveidot vispÄrÄ«gu algoritmu ziÅojuma ievadÄ«Å”anai attÄlu paletÄ:
Lai noteiktu ziÅojuma esamÄ«bu attÄlÄ, ziÅojuma sÄkumam jÄpievieno noteikta bitu secÄ«ba, kuru dekodÄtÄjs vispirms nolasa un pÄrbauda pareizÄ«bu. Ja nesakrÄ«t, tad tiek uzskatÄ«ts, ka attÄlÄ nav slÄpta ziÅojuma. TÄlÄk jums jÄnorÄda ziÅojuma garums. PÄc tam pats ziÅojuma teksts.
Visa lietojumprogrammas klases diagramma:
Programmas īstenoŔana
Visas programmas ievieÅ”anu var iedalÄ«t divÄs daļÄs: saskarnes Å”ifrÄÅ”anas un atÅ”ifrÄÅ”anas metožu ievieÅ”ana Encryptor, nodarbÄ«bÄs GIFEncryptorByLSBMethod Šø GIFEncryptorByPaletteExtensionMethodun lietotÄja interfeisa ievieÅ”anu.
Apsveriet klasi GIFEncryptorByLSBMethod.
lauki firstLSBit Šø secondLSBit satur katra attÄla baita bitu skaitu, kurÄ jÄievada ziÅojums un no kurienes ziÅojums jÄlasa. Lauks checkSequence saglabÄ pÄrbaudes bitu secÄ«bu, lai nodroÅ”inÄtu iegultÄ ziÅojuma atpazÄ«Å”anu. StatiskÄ metode getEncryptingFileParameters atgriež norÄdÄ«tÄ faila parametrus un potenciÄlÄ ziÅojuma raksturlielumus.
Metodes algoritms encrypt klase GIFEncryptorByLSBMethod:
Un viÅa kods:
@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();
}
Metodes algoritms un pirmkods decrypt klase 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);
}
Klases Ä«stenoÅ”ana GIFEncryptorByPaletteExtensionMethod bÅ«s lÄ«dzÄ«gi, atŔķiras tikai informÄcijas saglabÄÅ”anas/nolasÄ«Å”anas metode.
KlasÄ MainFrame AprakstÄ«tas iesaiÅoÅ”anas metodes: encryptImage(Encryptor encryptor) Šø decryptImage(Encryptor encryptor), apstrÄdÄjot interfeisa metožu rezultÄtus Encryptor un mijiedarbÄ«ba ar lietotÄju, t.i., failu atlases dialoga atvÄrÅ”ana, kļūdu ziÅojumu parÄdÄ«Å”ana utt.; kÄ arÄ« citas metodes: openImage(), ļaujot lietotÄjam izvÄlÄties attÄlu, exit(), kas aizver lietojumprogrammu. Å Ä«s metodes tiek sauktas no ActionatbilstoÅ”os izvÄlnes vienumus. Å Ä« klase papildus ievieÅ” palÄ«gmetodes: createComponents() - formas sastÄvdaļu izveide, loadImageFile(File f) ā attÄla ielÄde Ä«paÅ”Ä komponentÄ no faila. Klases Ä«stenoÅ”ana GIFEncryptorByPaletteExtensionMethod lÄ«dzÄ«gi klases ievieÅ”anai GIFEncryptorByLSBMethod, galvenÄ atŔķirÄ«ba ir veidÄ, kÄdÄ ziÅojuma baiti tiek rakstÄ«ti un nolasÄ«ti no paletes.
Programmas darbība
LBS metode
PieÅemsim, ka ir Å”Äds attÄls:
Å ajÄ attÄlÄ palete sastÄv no 256 krÄsÄm (kÄ Paint saglabÄ). PirmÄs Äetras krÄsas ir: balta, melna, sarkana, zaļa. Citas krÄsas ir melnas. GlobÄlÄs paletes bitu secÄ«ba bÅ«s Å”Äda: