W zeszłym miesiącu przybliżyłem Państwu zagadnienie steganografii i jej ewolucję wraz z rozwojem techniki. Dzisiaj zapoznam Państwa z trzema podstawowymi algorytmami steganograficznymi stosowanymi w cyfrowych plikach graficznych (w odcieniach szarości, kolorowych z paletą kolorów i bez tzw. TrueColor), szczegółowo opiszę, na czym polega nadmiarowość informacji w nich zawarta i jak można ją wykorzystać do ukrycia informacji w taki sposób, aby ludzkie oko nie zarejestrowało żadnych zmian.
W komputerowym przetwarzaniu obrazów dwuwymiarowy obraz cyfrowy jest prostokątną tablicą (macierzą) o pewnej liczbie elementów nazywanych pikselami, z których każdy reprezentuje natężenie światła w danym punkcie. Przeciętny obraz ma wymiary 640x480 pikseli i przedstawiony jest za pomocą 256 kolorów. W takim obrazie można ukryć średnio około 300 kilobitów danych.
Wyróżnia się trzy podstawowe typy obrazów cyfrowych.
Pierwszy z nich to obrazy bez palety w odcieniach szarości (Greyscale). Są to obrazy, w których każdy piksel jest opisany za pomocą liczby z pewnego zakresu odpowiadającej odcieniowi szarości. Najczęściej spotykane są obrazy o 256 odcieniach szarości. Wartości pikseli takiego obrazu można zapisać w jednym bajcie, czyli na ośmiu bitach.
Drugi typ to kolorowe obrazy bez palety (TrueColor). W tego typu obrazach każdy kolor, który może przybrać piksel, powstaje z trzech składowych: Red (czerwony), Green (zielony), Blue (niebieski). Jednym z popularnych standardów TrueColor jest taki, w którym każda składowa jest reprezentowana przez jeden bajt, czyli każdy piksel jest zdefiniowany za pomocą trzech bajtów. Takie definiowanie piksela znacznie wpływa na rozmiar pliku. Mając np. obraz o standardowej wysokiej rozdzielczości 1024x768, w którym każdy piksel jest reprezentowany za pomocą trzech bajtów, otrzymujemy plik o rozmiarach przekraczających 2 MB. Ich rozmiar może zwracać uwagę, szczególnie podczas transmisji w Internecie. Zaletą ich stosowania jest jednak fakt, że zapewniają największą ilość miejsca do ukrywania informacji.
Trzeci typ to obrazy z paletą kolorów. W tym przypadku każdy piksel jest reprezentowany przez pojedynczy bajt będący indeksem wskazującym na odpowiedni element tablicy (palety) kolorów. Najczęściej paleta taka zawiera 256 kolorów. Każdy kolor w palecie jest reprezentowany przez 3 bajty (podobnie jak w pliku TrueColor), odpowiadające składowym R:G:B. Wyświetlając na ekranie taki obraz programy pobierają z palety odpowiedni kolor (wskazywany przez indeks) i zapalają odpowiednie piksele (rys. 1).
Jak już wspominałem wcześniej, typowe metody zapisu obrazów cyfrowych charakteryzują się nadmiarowością informacji wizualnej. Nadmiarowość tę wykorzystuje się do ukrycia dodatkowych danych.
Najbardziej znaną i najczęściej stosowaną metodą ukrywania informacji w plikach bez palety kolorów jest metoda LSB - Least Significant Bit (najmniej znaczący bit). Polega ona na manipulowaniu najmniej znaczącymi bitami danych obrazowych. Taka manipulacja jest niezauważalna dla ludzkiego oka, a pozwala ukryć na jednym bajcie danych obrazowych jeden lub więcej bitów. Niestety jest ona czuła na jakiekolwiek, nawet drobne zmiany obrazu (skalowanie, obcięcie itp.). Konwersja obrazu z formatu takiego jak BMP czy GIF do JPEG (kompresja stratna) i z powrotem do formatu oryginalnego może również zniszczyć informację ukrytą za pomocą LSB.
Standardem jest, iż obrazy typu w odcieniach szarości (Greyscale) posiadają ich 256, z czego oko przeciętnego człowieka potrafi rozróżnić tylko około 64. Płynie z tego wniosek, iż mając zapisany odcień szarości w postaci np. 01101011 i zmieniając najmniej znaczący bit tego bajtu 01101010 otrzymamy odcień, który dla ludzkiego oka będzie nie do odróżnienia od oryginału.
W ten sposób jesteśmy w stanie na każdym z pikseli zakodować jeden bit, co pozwala nam ukryć informację około ośmiu razy mniejszą niż plik, w którym będziemy kodować. Około ośmiu razy, gdyż informacje kodujemy tylko w danych obrazowych pliku graficznego, a plik taki oprócz bloku danych obrazowych zawiera również blok nagłówka, w którym zapisane są takie dane o pliku obrazu jak: rozmiar, rodzaj obrazu, paleta kolorów (jeśli istnieje) itp.
Dane można również ukryć na dwóch ostatnich lub trzech ostatnich bitach i wciąż (przy dobraniu odpowiednich obrazów) oko ludzkie nie będzie mogło wykryć zmian. Kodując na większej liczbie bitów niż jeden zwiększamy rozmiar danych, które możemy zakodować kosztem zwiększonego prawdopodobieństwa wykrycia operacji.
Na przykład przy kodowaniu na ostatnim bicie litera A może zostać „schowana” w ośmiu pikselach. Oryginalne wartości pikseli mogą wyglądać np. tak:
00100111 11101001 11001000 00100111
11001000 11101001 11001000 00100111
Binarna wartość kodu ASCII odpowiadająca literze A to 01000001.
Umieszczając ją na ostatnich bitach bajtów otrzymamy:
00100110 11101001 11001000 00100110
11001000 11101000 11001000 00100111
Podkreślone trzy bity to jedyne bity, które wymagały zmiany. Średnio LSB potrzebuje zmiany tylko połowy bitów w obrazie. Wynika to z prawdopodobieństwa wystąpienia na najmniej znaczącym bicie 0 lub 1, które wynosi 50%.
W obrazach kolorowych (TrueColor) metoda LSB jest nieznacznie zmodyfikowana w stosunku do obrazów w odcieniach szarości. W tym przypadku opiera się na wykorzystaniu różnej czułości oka ludzkiego na zmianę poszczególnych składowych R:G:B.
Stosunek czułości ludzkiego narządu wzroku dla poszczególnych składowych R:G:B wynosi 3:6:1, co oznacza, że oko najwrażliwsze jest na zmiany składowej zieleni, a najsłabiej reaguje na zmiany składowej niebieskiej. Dlatego też mając do zakodowania jeden bajt najlepiej ukryć go na dwóch najmniej znaczących bitach składowej R, jednym bicie składowej G i aż pięciu bitach składowej B. Może to wyglądać na przykład w następujący sposób:
Binarna wartość odpowiadająca literze A to 01000001.
Mamy piksel o składowych R:G:B:
00011010; 01010101; 00011110
Po zakodowaniu otrzymamy:
00011001; 01010100; 00000001
Widać, iż w tym przypadku metoda LSB jest wydajniejsza niż dla obrazów w odcieniach szarości. W poprzednim przypadku bezpiecznie można było kodować na dwóch najmniej znaczących bitach, przez co na trzech bajtach można było zakodować 6 bitów. W tym przypadku na trzech bajtach zapiszemy aż 8 bitów.
W porównaniu z poprzednimi typami plików graficznych o wiele trudniej jest ukryć informację w plikach z paletą kolorów. Wynika to z większej liczby operacji, które trzeba wykonać, aby zakodować dane oraz ze wstępnego przygotowania pliku nośnika do kodowania. Najważniejszym elementem tego procesu jest redukcja kolorów w palecie w taki sposób, aby po redukcji obraz, który powstanie, jak najmniej różnił się od oryginału, a ingerencja w jego strukturę była niezauważalna.
Cały proces ukrywania danych można przedstawić w następujących krokach:
1. Redukcja kolorów w palecie (rys. 2).
2. Zwielokrotnienie palety (rys. 3).
3. Zmiana indeksów kolorów w palecie Đ przyporządkowanie punktom obrazu indeksów palety zredukowanej.
4. Właściwe zakodowanie danych.
5. Wprowadzenie szumu do indeksów po danych zakodowanych.
6. Wymieszanie kolorów w palecie.
Redukcja kolorów w palecie
Kolory w palecie są redukowane n razy, gdzie n = 2k; k = 1, 2, 3,.... Przykładowo, dla palety 256-kolorowej możliwe są redukcje do 128 (k=1), 64 (k=2), 32 (k=3) itd. Redukcję przeprowadza się w celu uzyskania kilku odwołań do tego samego koloru. Ta nadmiarowość pozwala zakodować dodatkowe dane w pliku będącym nośnikiem informacji.
Istnieje wiele metod redukcji kolorów. Różnią się one od siebie zarówno szybkością działania, jak i jakością obrazu wyjściowego. Do najbardziej znanych można zaliczyć metodę histogramu (popularności), metodę redukcji kolorów podobnych, metody oparte na kwantyzacji wektorowej (Lloyda i LBG).
Zwielokrotnienie palety
Kolejnym krokiem jest utworzenie nowej palety z powtórzonych n razy zredukowanych już kolorów. Dzięki temu każdy kolor w palecie jest w niej powtórzony n-krotnie. Powtórzenie to dokładnie widać na rysunku 4A.
Podczas kopiowania zredukowanych kolorów można je nieco zróżnicować, aby zwiększyć prawdopodobieństwo niewykrycia ukrytego przekazu podczas analizowania palety obrazu będącego nośnikiem takich informacji. Oczywiście zróżnicowanie musi być tak dokonane, by nie można było bez szczegółowej analizy odróżnić koloru oryginalnego i tego nieco zmienionego. Można to zrobić wstawiając losowe wartości bitów do bajtów odpowiadających za daną składową koloru. I tak, jak to wynika z podanej wcześniej czułości ludzkiego oka na zmiany poszczególnych składowych kolorów, dla składowej R możemy zróżnicować 2 ostatnie bity, dla G - 1 bit, a dla B Đ 4 bity.
Zmiana indeksów kolorów w palecie
Następnym krokiem jest zmiana indeksów kolorów w palecie. Musi ona zostać przeprowadzona ze względu na to, iż po redukcji kolorów zmienił się ich układ w palecie. Należy sprawdzić, na który z kolorów z oryginalnej palety wskazuje każdy indeks i zastąpić go indeksem wskazującym na najbardziej zbliżony kolor w nowej palecie.
Podczas procesu porównywania tworzona jest tzw. tablica korekcji. Zawiera ona tyle elementów, ile jest kolorów w oryginalnej palecie (zazwyczaj 256). Każdy jej element jest liczbą wskazującą na ten kolor w nowej, zredukowanej palecie, który jest najbardziej zbliżony do koloru o indeksie danego elementu. Przy wykorzystaniu tablicy korekcji zamiana indeksów danych obrazowych do nowej palety kolorów przebiega bardzo szybko, gdyż pobrany z pliku indeks zamieniany jest na zapisany w tablicy korekcji.
Właściwe zakodowanie danych
Jeżeli każdy kolor występuje w palecie n razy, to istnieje możliwość zakodowania n wartości dzięki zmianie indeksów danych obrazowych tak, by wskazywały na któryś z n powtórzonych, znajdujących się w różnych miejscach palety kolorów. Jak widać na rys. 4A, każdy kolor w palecie jest powtórzony 4 razy. Można założyć, że gdy indeks piksela wskazuje na kolor w pierwszej części palety, to kodowane jest ă00Ó, gdy wskazuje na drugą część, to ă01Ó, gdy na trzecią Đ ă10Ó, a na czwartą – „11”. W ten sposób redukując kolory z 256 do 128 na jednym bajcie danych obrazowych możemy zakodować 1 bit, przy redukcji do 64 - 2 bity, a redukując do 32 kolorów - aż 3 bity. Oczywiście im redukcja jest większa, tym większa jest też różnica między obrazem oryginalnym a tym z ukrytą informacją.
Wprowadzenie szumu do indeksów po danych zakodowanych
Indeksy do palety, które znajdują się za danymi zakodowanymi (nie zawsze przecież ukrywamy w pliku maksymalną dopuszczalną ilość informacji), wskazują na pierwszą ze zredukowanych palet kolorów. Podczas analizy pliku może to wzbudzić podejrzenia; z tego względu można wprowadzić szum do indeksów po danych zakodowanych, który losowo zmieni indeks danego koloru na inny (w innej zredukowanej palecie), pod którym znajduje się ten sam kolor.
Wymieszanie kolorów w palecie
Opisywana metoda wymaga zwielokrotnienia zredukowanej palety kolorów. Jednak umieszczenie jedna po drugiej prawie identycznych zredukowanych palet może być łatwo wykryte. Patrząc na rysunek 4A można łatwo stwierdzić, iż nie jest to oryginalna paleta. Widać bardzo dokładnie, że składa się ona z kilku podobnych palet powtórzonych kilkakrotnie. Taki wygląd palety od razu sugeruje dokładniejszą analizę pliku graficznego, gdyż może on zawierać ukryte informacje. Aby paleta nie wzbudzała podejrzeń, należy zastosować tzw. tablicę mieszającą.
Po uprzednim zakodowaniu informacji w pliku należy wymieszać miejscami kolory w palecie, przechowując informacje o zmianie pozycji w tablicy. Należy również zmienić odpowiednio indeksy, aby wskazywały na odpowiedni kolor w palecie. Wynik mieszania pokazany jest na rysunku 4B. Jak widać, paleta tam przedstawiona budzi znacznie mniejsze podejrzenia niż ta z rysunku 4A.
W procesie ukrywania informacji nie bez znaczenia jest dobór odpowiedniego obrazu. Należy pamiętać, że nie każdy obraz nadaje się do zakodowania danych. Redukcję szczególnie widać na przejściach tonalnych, natomiast w obrazach z przyrodą (trawa, liście) jest to znacznie mniej zauważalne.