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:
- Pobieramy plik graficzny do wewnętrznego bufora.
- Obliczamy ile mamy dostępnych LSB.
- Ograniczamy długość ukrytej wiadomości do Floor(((ilości Pixeli)*3)/8).
- Skanuj wszystkie pixele obrazka.
- Dla każdego R , G i B ustawiamy ostatni bit (LSB) na 0.
- 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) = 1 = 10111111 = 191
181= 10110101 \\ = 181- (181%2) = 180 10110100 Floor(3/2)= 1 (1%2) = 1 =10111111 = 181
230= 11100110 \\ = 230- (230%2) = 230 11100110 Floor(1/2)= 0 (0%2) = 0 = 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)=0 = 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.
- 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.
- 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