V pátém století pr. n. l. poslal Rek Demeratus zprávu o chystané perské invazi do mestského státu Sparta na speciálne upravené voskové tabulce. Protoze tabulka musela projít kontrolou na recko-perské hranici, napsal vlastní zprávu o chystaném útoku na drevený podklad tabulky, který byl pokryt vrstvou vosku. Na tabulku byl poté napsán nezávadný text, který kontrolou na hranicích prosel. Díky historikovi Herodotovi, který tuto príhodu zaznamenal, máme z antického Recka první dokumentovaný príklad pouzití steganografie.
Kryptografie je disciplína, která se zasifrováním zprávy snazí schovat její smysl, nikoli utajit existenci tajné informace samotné. Nevadí nám pokud zprávu odposlechne nebo zachytí nekdo jiný nez její príjemce, dulezité je, ze nasi zasifrovanou zprávu není schopen rozlustit.
Steganografie (z rectiny: stegó - kryji, grafó - písi) je disciplína, která se zabývá ukrytím samotné existence tajné informace. Nevadí nám pokud si nekdo prohlízí nosné médium (tabulka v historickém príkladu), dulezité je, ze si nevsiml, ze médium nese jeste dalsí, námi skrytou informaci.
V dnesní digitální dobe se prímo nabízí pouzívat ke skryté komunikaci digitální video a audio. Americké bezpecnostní sluzby tvrdí, ze si teroristé pred útokem na World Trade Center vymenovali informace ukryté ve video a audio souborech a obrázcích, které zverejnovali na porno stránkách, chatovacích místnostech a ruzných sportovních stránkách.
Posledním príkladem se pomalu dostáváme k vlastnímu zadání zápoctového príkladu. Uvedomme si, ze veskeré kompresní techniky dneska (mpeg-4, jpeg, mp3) jsou zalozeny na tom, ze lidské smysly "unesou" i pomerne velkou ztrátu informace, která se projeví napríklad zkreslením videa, ci zvukového záznamu. Podíváme-li se na problém z druhé strany, dojdeme k záveru, ze do obrázku, video ci zvukových záznamu lze pozmenením malého mnozství informace ukrýt informaci jinou (tajnou).
Mejme barevný obrázek o rozmerech 256x256 pixelu ulozený v 24-bitové barevné hloubce. Barva pixelu je ulozena ve formátu (red,green,blue), kde kazdá ze slozek zabírá 8 bitu. Výsledná barva je urcena smícháním techto trí slozek. Jednoduchým výpoctem zjistíme, ze kazdý pixel muze mít jednu z 16 777 216 barev. Uvádí se, ze lidské oko je schopno rozlisit asi 360 000 tisíc barev a nejméne je citlivé na modrou barvu. Malé zmeny odstínu barvy si tedy lidské oko nevsimne. To je prostor pro ukrytí tajné informace. Pokud napr. u naseho obrázku (rozmery 256 x 256) pozmeníme pouze nejméne významný bit modré slozky, muzeme do nej pomerne nepozorovane ulozit az 8KB textu, coz nám pri 1800 znacích na stránku dává ctyri a pul normo-strany textu, bez "viditelné" stopy v obrázku.
Výpocet: Meníme 1 bit (nejméne významný) modré slozky,Pro zakódování textu do obrázku:
./stega -i input_file.bmp -o output_file.bmp -m 'Message text' ./stega -e -i input_file.bmp -o output_file.bmp -m 'Message text'
Pro dekódování textu z obrázku:
./stega -d -i input_file.bmpPoradí prepínacu (-e, -d, -i input_file.bmp, -o output_file, -m 'Message text') se muze lisit. Pri jiném nez výse definovaném tvaru parametru príkazové rádky se program ihned ukoncí s nenulovou hodnotou a na standardní chybový výstup vypíse nápovedu k pouzití programu. Pokud kódování/dekódování probehne v porádku, vrací program nulu.
Parametr -e je mozno vynechat (tj. není-li zadána akce, provede se zakódování).
(pocet_pixelu_na_rádku * 3) modulo 4 != 0.
| Offset (Byte) od zacátku souboru | Velikost (Byte) | Jméno | Úcel |
| 0 | 2 | bfType | Má vzdy ASCII hodnotu 'BM', decimálne 19778 |
| 2 | 4 | bfSize | Velikost celého souboru v Bytech |
| 6 | 2 | bfReserved1 | Rezervováno. Musí se vzdy rovnat 0 |
| 8 | 2 | bfReserved2 | Rezervováno. Musí se vzdy rovnat 0 |
| 10 | 4 | bfOffset | Je v nem ulozeno, po kolika bytech zacínají data |
| Offset (Byte) od zacátku souboru | Velikost (Byte) | Jméno | Úcel |
| 14 | 4 | biSize | Velikost bmp info hlavicky (tato struktura) v bytech. Melo by být rovno 40 |
| 18 | 4 | biWidth | Sírka obrázku v pixelech |
| 22 | 4 | biHeight | Výska obrázku v pixelech |
| 26 | 2 | biPlanes | pocet rezu |
| 28 | 2 | biBitCount | pocet bitu na pixel (v nasem príklade 24) |
| 30 | 4 | biCompression | Komprese. (v nasem prípade 0) |
| 34 | 4 | biSizeImage | Velikost obrázku v bytech |
| 38 | 4 | biXPelsPerMeter | Rozlisení obrázku v ose x. Pocet pixelu na 1 metr. |
| 42 | 4 | biYPelsPerMeter | Rozlisení obrázku v ose y. Pocet pixelu na 1 metr. |
| 46 | 4 | biClrUsed | Pocet barev uzitých v bitmape (Má svuj úcel pri bytových hloubkách < 24) |
| 50 | 4 | biClrImportant | Pocet dulezitých barev v bitmape. (Má svuj úcel pri bytových hloubkách < 24) |
| Hlavicka bmp souboru (14 Bytu) | Info hlavicka o bmp obrázku (40 Bytu) | 1. pixel (B,G,R) (3*1 Byte) | 2. pixel (B,G,R) 3*1 Byte | atd... |
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
int i,j,k,co_robit=2,ende=0,zaciatok_dat,pocet_nul,dlzka_spravy,
pocet_bytov,RGB,a=0,index_pismena;
char ret[35],input[256],output[256],sprava[257],pom[256],bajt,ID_bitu,
pismeno;
FILE *out,*in;
int pixelX,pixelY;
long int velkost;
/*--------------------------------NAPOVEDA-----------------------------------*/
int napoveda(int kod)
{
if (kod==1) printf("\nPROSIM ZADAJTE SPRAVNE PARAMETRE:\n\n");
if (kod==2) printf("\nNIEKTORY PARAMETER NIE JE PLATNY:\n\n");
if (kod==3) printf("\nCHYBAJU POTREBNE PARAMETRE\n\n");
printf(
"Napoveda k programu STEGA:\n\n"
" Program STEGA je urceny pre kodovanie a spetne dekodovanie textovych "
"sprav\n"
"do obrazku typu .bmp s 24-bitovou hlbkov.\n\n"
" Parametre programu STEGA:\n"
" -i [input_file.bmp] -> vstupny obrazok\n"
" -o [output_file] -> vystupny obrazok \n"
" -m [\"text\"] -> sprava na zasifrovanie\n "
" -d -> dekodovanie\n"
" -e -> zakodovanie\n\n"
"funkcne priklady:\n"
" zakodovanie:\n"
" ./stega -e -i input_file.bmp -o output_file.bmp -m 'Message text'"
" odkodovanie:\n"
" ./stega -d -i input_file.bmp\n\n"
);
return 0;
}
/*----------------------------ZAKODUJ----------------------------------------*/
int zakoduj()
{
if((in=fopen(input,"r"))==NULL)
{printf("Vstupny subor sa nepodarilo otvorit.\n");
ende=10;return 2;
}
if((out=fopen(output,"w"))==NULL)
{fclose(in);printf("Vystupny subor sa nepodarilo otvorit.\n");
ende=10;return 2;
}
if (pixelX*pixelY<=(strlen(sprava)*8))
{printf("Obrazokobsahuje malo pixelov pre zakodovanie celej spravy\n");
ende=15;return 15;
}
/* skopirovanie hlavicky obrazku*/
for(i=0;i<zaciatok_dat; i++ , velkost-- )
fputc(fgetc(in),out);
pocet_nul=4-((pixelX*3) % 4);
if (pocet_nul==4) pocet_nul=0;
dlzka_spravy=strlen(sprava);
k=dlzka_spravy;
/* dlzka spravy */
for(i=0;i<8;i++)
{ velkost--;pocet_bytov++;RGB++;
bajt=fgetc(in);
if ((bajt%2)==1) bajt--;
if ((k%2)==1) bajt++;
fputc(bajt,out);
k=k>>1;
}
/*samotne menenie bitov*/
while(index_pismena!=dlzka_spravy)
{
velkost--;
pocet_bytov++;
if(pocet_bytov>(pixelX*3))
{
for(i=0;pocet_nul>i;i++)
{fputc(fgetc(in),out);velkost--;}
pocet_bytov=0;
continue;
}
bajt=fgetc(in);
RGB++;
RGB=RGB%3;
if(RGB==2) /* zmenit bit */
{
if ((bajt%2)==1) bajt--;
pismeno=sprava[index_pismena];
pismeno=pismeno>>a;
if ((pismeno%2)==1) bajt++;
fputc(bajt,out);
a++;a=a%8;
if (a==0) index_pismena++;
}
else
fputc(bajt,out);
}
/* skopirovanie zvysku obrazku*/
for( ;velkost!=0; velkost--) fputc(fgetc(in),out);
fclose(in);
fclose(out);
ende=0;
return 0;
}
/*----------------------------DEKODUJ----------------------------------------*/
int dekoduj()
{
if((in=fopen(input,"r"))==NULL)
{printf("Vstupny subor sa nepodarilo otvorit.\n");
ende=10;return 2;
}
/* skopirovanie hlavicky obrazku*/
for(i=0;i<zaciatok_dat; i++ , velkost-- )
fputc(fgetc(in),out);
fclose(in);
ende=0;
return 0;
}
/*-----------------------------MAIN------------------------------------------*/
int main(int argc,char *argv[])
{
if (argc<4) {napoveda(1);return 1;} /*malo parametrov*/
i=1;
while(i<argc)
{strcpy(ret,argv[i]);
if (ret[0]=='-')
{
if (ret[1]=='d') {co_robit=1;i++;continue;}
if (ret[1]=='e') {co_robit=2;i++;continue;}
if ( (argc==(i+1)) ||(argv[i+1][0]=='-')) {napoveda(1);return(3);}
/* dva parametre po sebe resp posledny potrebuje este jeden*/
if (ret[1]=='i')
{strcpy(input,argv[i+1]);i+=2;continue;}
if (ret[1]=='o')
{strcpy(output,argv[i+1]);i+=2;continue;}
if (ret[1]=='m')
{strcpy(sprava,argv[i+1]);i+=2;continue;}
napoveda(2);return 4;
}
else {napoveda(1);return(2);}
}
if(input==output)
{printf("Vstupny a vystupny subor nesmie byt totozny!!!\n");
return 6;}
if (input[0]==0){napoveda(3);return 5; } /* chybaju parametre*/
if (co_robit==2)
{if (sprava[0]==0 || output[0]==0 ){napoveda(3);return 5;}}
/*--------- Test na .bmp -----------*/
i=0;
while(input[i]!=0) {pom[i]=tolower(input[i]);pom[i+1]=0;i++;}
if(strstr(pom,".bmp")==NULL)
{ printf("Nespravny format vstupneho suboru \n");
return(7);}
/*---------- Test na BM --------------*/
if((in=fopen(input,"r"))==NULL)
{printf("Vstupny subor sa nepodarilo otvorit.\n");
ende=10;return 2;
}
i=fgetc(in);
j=fgetc(in);
if (i!='B' || j!='M')
{printf("Nespravny format vstupneho suboru.\n");
fclose(in);
return 7;}
velkost+=fgetc(in);
velkost+=fgetc(in)*256;
velkost+=fgetc(in)*256*256;
velkost+=fgetc(in)*256*256*256;
if (velkost<60)
{printf("Prilis mala velkost vstupneho suboru.");}
/*--------- Test na zaciatok dat ---------*/
for(i=0;i<4;i++)
{fgetc(in);}
zaciatok_dat=fgetc(in);
/*--------- Test na pocet pixelov ---------*/
for(i=0;i<7;i++)
{
fgetc(in);
}
pixelX+=fgetc(in);
pixelX+=fgetc(in)*256;
pixelX+=fgetc(in)*256*256;
pixelX+=fgetc(in)*256*256*256;
pixelY+=fgetc(in);
pixelY+=fgetc(in)*256;
pixelY+=fgetc(in)*256*256;
pixelY+=fgetc(in)*256*256*256;
if (pixelX<1 || pixelY<1)
{printf("Nespravny format vstupneho suboru.\n");
fclose(in);
return 7;
}
fclose(in);
/*------ Jedna sa o subor v bmp formate -----------*/
if (co_robit==1)
dekoduj();
if (co_robit==2)
zakoduj();
return ende;
}