Powrót do Kryptografia

steganografia w plikach graficznych

Steganografia jest metodą ukrywania informacji tajnej przez osadzenie jej w innym nietajnym elemencie (filmie, grafice, dźwięku). Poprzez zastąpienie bitów danych niepotrzebnych lub nieużywanych bitami wiadomości tajnej. Taka wiadomość może być tekstem, szyfrogramem, zdjęciem, filmem, wszystkim, co chcemy (o ile niepotrzebnych lub nieużywanych bitami jest wystarczająco dużo). W naszym przypadku nasze dane będą zwykłym tekstem, które musimy ukryć, a niewykorzystane dane są najmniej znaczącymi bitami (LSB) w pikselach obrazu.

Czym jest LSB

W celu znalezienia wartości dziesiętnej reprezentacji binarnej sumujemy wszystkie wartości 1, przemnożone przez 2n gdzie n jest pozycją (indeksem), zaczynając od zera z prawej strony. Przykładowo konwersja 01001010 na system dziesiętny zaczniemy od prawej strony:

0*20+1*21+0*22+1*23+0*24+0*25+1*26+0*27=2+8+64= 74

Najmniej znaczącym bitem (LSB) jest pierwszy bit od prawej strony. Jego zmiana na 1 nie zmieni nam znacząco liczby dziesiętnej, jej wartość zostanie zakłócona jedynie o 1:

0*20+1*21+0*22+1*23+0*24+0*25+1*26+0*27=2+8+64= 74 | 1*20+1*21+0*22+1*23+0*24+0*25+1*26+0*27=1+2+8+64= 75

Oznacza to, że w pewnych okolicznościach nasze źródło nie zostanie znacząco zmienione, gdy zarezerwujemy ten bit dla naszych celów. Kiedy staramy się ukryć wiadomość w pliku graficznym, musimy wiedzieć jaką pulą LSB dysponujemy. Bity te zlokalizowane są w pikselach obrazu. Przy założeniu nieprzezroczystości koloru, piksel składać się bezie z kombinacji kolorów czerwonego, zielonego i niebieskiego (RGB), przy czym każdy z tych elementów może mieć wartość od 0 do 255. Jeśli założymy, że obraz ma 200 pikseli szerokości i 300 wysokości, daje nam to 200*300*3 = 180000 LSB. W takiej puli możemy ukryć 180000/8 = 22500 znaków reprezentowanych przy użyciu 8 bitów (np. znaki z rodziny ASCII).

Jeśli chcielibyśmy ukryć wiadomość tekstową w pliku graficznym, musimy wiedzieć, jak taki plik jest zbudowany, zmiana bita nawet w plikach graficznych może prowadzić do ich uszkodzenia, lub utraty bitów informacji ukrytej podczas kompresji, pliki mogą zawierać Metadane lub dodatkowe informacje, które podczas zmiany wypadałoby ominąć, aby skutecznie ukryć wiadomość bez wykrycia. Napiszemy sobie teraz program, który będzie ukrywał nam taką wiadomość w pliku graficznym. Formaty, w którym będziemy mogli bezpiecznie ukryć taką wiadomość to format *.bmp, ponieważ obsługuje tryb RGB i RGBA i podlega prostej kompresji bezstratnej. Więcej o budowie plików z grafiką bitmapową można poczytać na Wikipedi -> link

Proces ukrycia wiadomości:

  1. Pobieramy plik graficzny do wewnętrznego bufora.
  2. Obliczamy ile mamy dostępnych LSB.
  3. Ograniczamy długość ukrytej wiadomości do Floor(((ilości Pixeli)*3)/8).
  4. Skanuj wszystkie pixele obrazka.
  5. Dla każdego R , G i B ustawiamy ostatni bit (LSB) na 0.  
  6. Teraz pobierz numer ASCII aktualnej litery (na podstawie rosnącego indeksu). Następnie schowaj jego 8 bitów w kolejnych kolorach R1,B1,G1,R2,B2,G2,R3,B3 obrazka używając pętli. W każdym LSB każdego R1 R2….B3 ukryj jeden bit znaku. Kiedy 8 bitów znaku zostaną wyczerpane, przejdź do następnego znaku. Powtórz proces dla każdego znaku w teście, który chcemy ukryć. Na koniec dodaj 8 zer, które oddzielą ukrytą wiadomość od reszty pikseli i ułatwi zadanie przy wydobyciu tekstu.

Przykładowo, mamy plik graficzny, złożony z trzech kolorów , pierwszy (ciemny żółty) to RBG(255;201;14), drugi RBG(112;146;190) i trzeci RBG(181;230;29), zmieści nam się tylko jedna litera, więc umieścimy tam sobie literę „t” której numer ASCII to 116 a reprezentacja bitowa to 0111 0100

przed wyzerowaniem:

255 = 11111111    \\ = 255- (255%2) = 254        11111110                                                         (116%2)   = 0   = 11111110       = 254

201= 11001001    \\ = 201- (201%2) = 200      11001000                 Floor(116/2)= 58           ( 58%2)   = 0   = 11001000     = 200

14=             1110    \\ = 14- (14%2) = 14                      1110                  Floor(58/2)= 29              (29%2)   = 1   =1111                  =15

112=    1110000    \\ = 112- (112%2) = 112         1110000                  Floor(29/2)= 14             (14%2)   = 0  =1110000          = 112

146= 10010010    \\ = 146- (146%2) = 146     10010010                  Floor(14/2)= 7                  (7%2)   = 1  =1110001         = 147

190= 10111110    \\ = 190- (190%2) = 190       10111110                  Floor(7/2)= 3                     (3%2)   = = 10111111      = 191

181= 10110101    \\ = 181- (181%2) = 180      10110100                  Floor(3/2)= 1                   (1%2)   = =10111111         = 181

230= 11100110    \\ = 230- (230%2) = 230       11100110                  Floor(1/2)= 0                   (0%2)   = = 11100110       = 230

29=           11101    \\ = 29- (29%2) = 28                    11100                   następna litera lub zero kontrolne         = 11100         = 28

Oczywiście nic nie szkodzi na przeszkodzie, aby użyć dwóch ostatnich bitów, trzech lub czterech:

dla dwóch ostatnich bitów

przed wyzerowaniem:

255 = 11111111    \\ = 255- (255%4) = 252        11111100               (116%(2^2)) =0 (odwróć bity)== 00           = 11111100      = 252

201= 11001001    \\ = 201- (201%4) = 200      11001000                 (29%(2^2)) = 1 (01) (odwróć bity)=2 = 10   = 11001010     = 202

14=             1110    \\ = 14- (14%4) = 12                      1100                 (7%(2^2)) =3 (odwróć bity)=3 = 11                         = 1111     =15

112=    1110000    \\ = 112- (112%4) = 112         1110000                 (1%(2^2))= 1 (01) (odwróć bity)=2 = 10          = 1110010     = 114

146= 10010010    \\ = 146- (146%4) = 144     10010000                 następna litera lub zero kontrolne       = 10010000     = 144

190= 10111110    \\ = 190- (190%4) = 188       10111100                  następna litera lub zero kontrolne       = 10111100     = 188

181= 10110101    \\ = 181- (181%4) = 180      10110100                następna litera lub zero kontrolne       = 10110100      = 180

230= 11100110    \\ = 230- (230%4) = 228       11100100                 następna litera lub zero kontrolne      = 11100100      = 228

29=           11101    \\ = 29- (29%4) = 28                    11100                  koniec pętli                                                                         = 29

Oczywiście im więcej bitów użyjemy, tym nasz obrazek będzie bardziej zniekształcony, na pierwszym etapie dzieliliśmy modulo przez 2, w kolejnym przez 2*2 = 4 w kolejnym byłoby to 2*2*2 = 8 itd. Kiedy wiemy, już jak działa ukrywanie tekstu w pikselach, przejdźmy teraz do interpretatora naszego tekstu. Skorzystajmy z przykładu powyżej:

x= nasz znak =0

254 = 11111110   \\  0* 2 + (254%2) = 0

200 = 11001000   \\ 0*2 + (200%2)   =0

15  =1111              \\ 0*2 + (15%2)       =1

112 =1110000     \\ 1*2 + (112%2)      =2

147 =1110001     \\  2*2+ (147%2)      =5

191 =10111111   \\  5*2+ (191%2)      =11

181 =10111111   \\  11*2+ (181%2)    =23

230 =11100110   \\  23*2+ (230%2)   =46 = 00101110   ->  po odwróceniu  ->  0111 0100 = 116 = Chr(116) = t

28 =11100          koniec pętli

przykład dla dwóch bitów:

x= nasz znak =0

252 = 11111100  \\  0* 4 + (252%4) = 0

202 = 11001001  \\ 0*4 + (202%4)   =2 

15  =1111              \\ 2*4 + (15%4)     =11

114 =1110001     \\ 11*4 + (114%4)  =46 = 00101110   ->  po odwróceniu  ->  0111 0100 = 116 = Chr(116) = t

144 =10010000       =00

188 =10111100        =00

180 =10110100       =00

228 =11100100       =00

29 –          koniec pętli

Algorytm który odszyfruje nam wiadomość jest dużo prostszy, wygląda następująco:

Przykładowy program który ukrywa wiadomość w pliku graficznym, zapisuje go i odczytuje dane:  

Przykładowy program który ukrywa wiadomość w pliku graficznym z wykorzystaniem dwóch ostatnich bitów, zapisuje go i odczytuje dane:  

Oczywiście im jesteśmy sprytniejsi tym nasza wiadomość będzie lepiej ukryta, można taką wiadomość w prosty sposób zaszyfrować używając szyfru przestawnego lub szyfru z kluczem który dodatkowo utrudni odczytanie wiadomości. Do naszego programu można dodać dodatkowy element piksela którym jest kanał Alfa. Odpowiada on za przezroczystość naszego piksela i oznaczony jest jako A, jego skala jest taka jak dla kolorów od 0-255 z tą różnicą, że 255 odpowiada za pełną widoczność piksela więc automatycznie jego wartość ustawiona jest na 255. Zwiększa to ilość bitów które możemy ukryć, plik taki możemy zapisać w formacie png lub gif na przykład:

Przykład powyższy ukazuje jak w praktyce ukrywać dane w pikselach, lecz pliki graficzne zawierają różne miejsca w których możemy te dane ukryć, nie są to tylko piksele. Takich miejsc jest więcej, lecz aby je znaleźć musimy poznać strukturę danego formatu. zazwyczaj taki plik składa się z nagłówka i danych, aby podejrzeć i edytować budowę pliku należy wiedzieć czym jest bajt i bit.

  1. Bit – to najmniejsza ilość informacji potrzebna do określenia, który z dwóch równie prawdopodobnych stanów przyjął układ. Jednostka logiczna. Binarny sposób zapisu informacji związany jest z tym, że komputer jako urządzenie cyfrowe rozpoznać może dwa stany napięciowe 0 lub 1.
  2. Bajt – najmniejsza adresowalna jednostka informacji pamięci komputerowej, składająca się z bitów. Zwykle przyjmuje się, że jeden bajt to 8 bitów,  w praktyce jeden bajt może zawierać dowolną liczbę bitów.

Aby wniknąć w strukturę pliku należy dysponować programem do edycji hex’ów, ja używam programu HxD za pomocą którego prezentował będę wnętrza plików. wyświetla on dane w systemie szesnastkowym. Jeśli jeden bajt to 8 bitów w takim bądź razie przyjmuje on wartości:

00000000-11111111 w systemie dziesiętnym jest to 0-255 w szesnastkowym będzie to 0- FF

Teraz gdy już  wiecie czym są LSB i jak zastosować steganografie w praktyce, stwórzcie własne programy bardziej skomplikowane i rozbudowane, powodzenia

Permalink do tego artykułu: https://visualmonsters.cba.pl/kryptografia/steganografia/

steganografia w plikach graficznych (pliki bmp)

Historie tego formatu można znaleźć w internecie i nie będziemy się na niej za bardzo skupiać. Jest to chyba najlepszy format do ukrywania danych w pikselach, ponieważ zawiera prostą kompresje bezstratną i w momencie zapisu pliku nasze piksele nie ulegają zmianie, oczywiście mowa tutaj o plikach bez palety barw, w przeciwieństwie do formatów takich jak …