Concelogram: obraz w obrazie z wykorzystaniem LSB
Jest to rodzaj steganografii, polegająca na ukryciu obrazu, zdjęcia, grafiki. Metoda ta była szeroko wykorzystywana w historii przez szpiegów, którzy ukrywali zdjęcia i mikro filmy w przeróżnych miejscach. Najbardziej znaną metodą jest metoda mikrokropek, polega na ukrycie zminiaturyzowanych danych takich jak tekst, fotografie lub rysunki techniczne w punkcie o średnicy 1 mm. Skala miniaturyzacji wynosiła 1:300. Mikrokropkę wykonuje się przy użyciu urządzenia będącym połączeniem aparatu fotograficznego i mikroskopu. Co ciekawe mikrokropek nadal używa się do zabezpieczenia i znakowania cennych przedmiotów, żetonów, a nawet samochodów. Tak jak mikrokropka concelogram powoduje, że obraz oglądany nieuzbrojonym okiem, nie budzi żadnych podejrzeń. Najłatwiejszą metodą ukrycia obrazu wewnątrz innego obrazu jest wykorzystanie LSB(czym jest LSB, dowiecie się z tego artykułu). Jeśli wiesz już, czym jest LSB, to możemy zaczynać. Jak już zapewne wiesz, piksel przyjmuje trzy wartości, każdą od 0 do 255 co w reprezentacji binarnej reprezentuje 0-11111111. (Można użyć czwartej wartości, którą jest kanał Alfa) W naszym ćwiczeniu użyjemy 4-3 LSB. Każde wykorzystanie LSB na użytek ukrytego obrazka będzie pogarszać jego jakość. Wygląda to następująco:
Jeśli chcecie przeanalizować sobie obrazki zachęcam do ich pobrania: zerowany kotek
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Sub Main() Dim open_dialog As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim bmp As New Bitmap(lokalizacjaPlikuGraficznego) Console.WriteLine("Ile ostatnich bitów chcesz wyzerować") Dim zerowanie As Integer = 0 Do Dim test As String = Console.ReadLine() If IsNumeric(test) Then If test >= 1 And test <= 7 Then zerowanie = test Exit Do Else Console.WriteLine("możesz wybrać tylko cyfrę od 1 do 7.") End If Else Console.WriteLine("możesz wybrać tylko cyfrę od 1 do 7.") End If Loop zerowanie = 2 ^ zerowanie Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim xmax As Integer = bmp.Width - 1 Dim ymax As Integer = bmp.Height - 1 Dim pixelElementIndex As Long = 0 For y = 0 To ymax For x = 0 To xmax With bmp.GetPixel(x, y) R = .R - .R Mod zerowanie G = .G - .G Mod zerowanie B = .B - .B Mod zerowanie End With bmp.SetPixel(x, y, Color.FromArgb(R, G, B)) Next x Next y bmp.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ " (wyzerowano " + Math.Log(zerowanie, 2).ToString + " ostatnich bitów).bmp" _ , System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały wyzerowane!") Console.ReadLine() End If End Sub End Module |
Wykorzystamy sobie cztery ostatnie bity do ukrycia naszego obrazka. Oczywiście nie będzie to takie proste, musimy zachować pewne zasady. Ważną decyzją będzie czy nasz plik graficzny będzie miał obniżoną jakość, czy nie. Jeśli obniżymy mu jakość, będziemy mogli zapisać piksel w pikselu, jeśli postanowimy zachować jakość, ukrytego obrazka wtedy będziemy musieli zapisać jeden piksel ukrytego obrazka w dwóch pikselach obrazka kontenera. Zaczniemy od pierwszego przykładu, zapiszemy obrazek w obrazku, z tym że obrazek ukryty będzie miał obniżoną jakość. Oczywiste będzie, że obrazek ukrywający musi być większej lub równej wielkości niż obrazek ukrywany:
Do pobrania: kotek, lisek
Należy teraz wykorzystać kod powyżej i wpleść algorytm dodania obrazka po zerowaniu bitów. Wyzwaniem zostaje dodanie końca wiersza pikseli. Najprościej będzie wypełnić puste pola zerami, po wydobyciu obrazka ze źródła, będzie on miał taką samą wielkość jak obrazek bazowy. Jak będzie wyglądał taki algorytm:
Jeśli czytaliście poprzednie artykuły, stworzenie takiego algorytmu, nie powinno przysporzyć wam problemów:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Dim lokalizacjaPlikuUkrywanego As String Sub Main() Dim open_dialog As New OpenFileDialog() Dim open_dialog_ukrywany As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryjesz obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) open_dialog_ukrywany.InitialDirectory = "c:\" open_dialog_ukrywany.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog_ukrywany.Title = "Wybierz obrazek który ukryjesz" If open_dialog_ukrywany.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuUkrywanego = open_dialog_ukrywany.FileName Dim ukryty As New Bitmap(lokalizacjaPlikuUkrywanego) If kontener.Width < ukryty.Width Or kontener.Height < ukryty.Height Then Console.WriteLine("Obrazek ukrywany jest większy niż obrazek bazowy, wybierz mniejszy obrazek.") Console.ReadLine() Else Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 For y = 0 To ymax For x = 0 To xmax With kontener.GetPixel(x, y) R = .R - .R Mod (2 ^ 4) G = .G - .G Mod (2 ^ 4) B = .B - .B Mod (2 ^ 4) End With If x < ukryty.Width And y < ukryty.Height Then With ukryty.GetPixel(x, y) R += OdwrocBity(.R - .R Mod (2 ^ 4)) G += OdwrocBity(.G - .G Mod (2 ^ 4)) B += OdwrocBity(.B - .B Mod (2 ^ 4)) End With Else '15 rozjaśni, 0 -przyciemni R += 15 G += 15 B += 15 End If kontener.SetPixel(x, y, Color.FromArgb(R, G, B)) Next x Next y kontener.Save("C:\Users\Piotrek\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ ".bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały ukryte!") Console.ReadLine() End If End If End If End Sub Private Function OdwrocBity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 7 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Efekt działania algorytmu można podziwiać poniżej:
Na pierwszy rzut oka obrazek wygląda jak słabej jakości zdjęcie :P, ale niech to was nie zwiedzie. Po użyciu kodu cofającego nasze zmiany ukaże się nam obrazek ukryty wewnątrz kotka:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Sub Main() Dim open_dialog As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryto obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) Dim ukryty As New Bitmap(kontener.Width, kontener.Height) Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 For y = 0 To ymax For x = 0 To xmax With kontener.GetPixel(x, y) R = .R Mod (2 ^ 4) G = .G Mod (2 ^ 4) B = .B Mod (2 ^ 4) End With R = OdwrocBity(R) G = OdwrocBity(G) B = OdwrocBity(B) ukryty.SetPixel(x, y, Color.FromArgb(R, G, B)) Next x Next y ukryty.Save("C:\Users\Piotrek\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ "(odzyskany).bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały odzyskane!") Console.ReadLine() End If End Sub Private Function OdwrocBity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 7 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Efekt działania algorytmu:
Jeśli zamiast 15 pozostawilibyśmy wyzerowane bity, wtedy przestrzeń większa niż szerokość i wysokość obrazka ukrytego byłaby czarna. Jak działa algorytm:
Oczywiście dużo lepsze efekty otrzymamy po wykorzystaniu tylko dwóch ostatnich bitów. Również natrafimy na ograniczenia, najważniejsze pytanie, jakie musimy sobie zadać to takie czy chcemy obniżać jakość naszego obrazka ukrywanego, sami widzicie, że użycie tylko czterech pierwszych bitów do utworzenia obrazka nie obniża aż tak znacząco jego jakości. Drugim ograniczeniem jest wielkość naszego obrazka, jeśli użyjemy dwóch ostatnich bitów kontenera, wtedy nasz obrazek będzie musiał być co najmniej czterokrotnie większy od obrazka ukrywanego (bez straty jakości). Mamy dwa sposoby, aby ukryć taki piksel. Możemy ukrywać wartości piksela ciągiem, tak jak to miało miejsce w przypadku ukrywaniu tekstu lub ukrywać kolor w kolorze (zielone tylko w zielonych, czerwone w czerwonych itd.)
- Ukrywanie koloru w kolorze:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Dim lokalizacjaPlikuUkrywanego As String Sub Main() Dim open_dialog As New OpenFileDialog() Dim open_dialog_ukrywany As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryjesz obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) open_dialog_ukrywany.InitialDirectory = "c:\" open_dialog_ukrywany.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog_ukrywany.Title = "Wybierz obrazek który ukryjesz" If open_dialog_ukrywany.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuUkrywanego = open_dialog_ukrywany.FileName Dim ukryty As New Bitmap(lokalizacjaPlikuUkrywanego) If kontener.Width < 4 * ukryty.Width Or kontener.Height < ukryty.Height Then Console.WriteLine("Obrazek ukrywany jest większy niż obrazek bazowy, wybierz mniejszy obrazek.") Console.ReadLine() Else Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim R_ukryty As Integer = 0, G_ukryty As Integer = 0, B_ukryty As Integer = 0 Dim x_ukryty As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 Dim indexkoloru As Integer = 0 For y = 0 To ymax For x = 0 To xmax With kontener.GetPixel(x, y) 'zerowanie ostatnich dwóch bitów kontenera R = .R - .R Mod (2 ^ 2) G = .G - .G Mod (2 ^ 2) B = .B - .B Mod (2 ^ 2) End With If x < 4 * ukryty.Width And y < ukryty.Height Then If (x Mod 4) = 0 Then 'pobiera wartości kolorów obrazka ukrywanego With ukryty.GetPixel(x_ukryty, y) R_ukryty = .R G_ukryty = .G B_ukryty = .B End With x_ukryty += 1 End If R += OdwrocBity2(R_ukryty Mod 2 ^ 2) R_ukryty = Math.Floor(R_ukryty / 2 ^ 2) G += OdwrocBity2(G_ukryty Mod 2 ^ 2) G_ukryty = Math.Floor(G_ukryty / 2 ^ 2) B += OdwrocBity2(B_ukryty Mod 2 ^ 2) B_ukryty = Math.Floor(B_ukryty / 2 ^ 2) Else 'wartość 0 przyciemni piksele, wartość 3 rozjaśni je (opcjonalne) R += 3 G += 3 B += 3 End If kontener.SetPixel(x, y, Color.FromArgb(R, G, B)) Next x x_ukryty = 0 Next y kontener.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ " ukryty.bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały ukryte!") Console.ReadLine() End If End If End If End Sub Private Function OdwrocBity2(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 1 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Odzyskanie takich bitów nie stanowi problemu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Sub Main() Dim open_dialog As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryto obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) Dim szerokosc As Integer = Math.Floor(kontener.Width / 4) Dim ukryty As New Bitmap(szerokosc, kontener.Height) Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim x_ukryty As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 For y = 0 To ymax For X = 0 To xmax Dim pix As Color = kontener.GetPixel(X, y) If (X Mod 4) = 0 Then If X > 0 Then ukryty.SetPixel(x_ukryty, y, Color.FromArgb(OdwrocBity(R), OdwrocBity(G), OdwrocBity(B))) R = 0 G = 0 B = 0 x_ukryty += 1 End If R = R * 4 + (pix.R Mod 4) G = G * 4 + (pix.G Mod 4) B = B * 4 + (pix.B Mod 4) Else R = R * 4 + (pix.R Mod 4) G = G * 4 + (pix.G Mod 4) B = B * 4 + (pix.B Mod 4) If X = xmax Then ukryty.SetPixel(x_ukryty, y, Color.FromArgb(OdwrocBity(R), OdwrocBity(G), _ OdwrocBity(B))) End If End If Next X x_ukryty = 0 Next y ukryty.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ "(odzyskany).bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały odzyskane!") Console.ReadLine() End If End Sub Private Function OdwrocBity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 7 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Efekty ukrycia kotka w tapecie znalezionej na dysku:
Tapeta + Kotek = Tapeta-ukryty
Po odzyskaniu bitów z tapeta- ukryty otrzymamy obrazek:
2. Drugim sposobem ukrycia naszego piksela jest ukrycie go ciągiem, bardzo dobrze prezentuje to obrazek poniżej:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Dim lokalizacjaPlikuUkrywanego As String Sub Main() Dim open_dialog As New OpenFileDialog() Dim open_dialog_ukrywany As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryjesz obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) open_dialog_ukrywany.InitialDirectory = "c:\" open_dialog_ukrywany.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog_ukrywany.Title = "Wybierz obrazek który ukryjesz" If open_dialog_ukrywany.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuUkrywanego = open_dialog_ukrywany.FileName Dim ukryty As New Bitmap(lokalizacjaPlikuUkrywanego) If kontener.Width < 4 * ukryty.Width Or kontener.Height < ukryty.Height Then Console.WriteLine("Obrazek ukrywany jest większy niż obrazek bazowy, wybierz mniejszy obrazek.") Console.ReadLine() Else Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim ukrywany As Integer = 0 Dim x_ukryty As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 Dim pixelUkrywanyIndex As Long = 0 For y = 0 To ymax For x = 0 To xmax With kontener.GetPixel(x, y) 'zerowanie ostatnich dwóch bitów kontenera R = .R - .R Mod (2 ^ 2) G = .G - .G Mod (2 ^ 2) B = .B - .B Mod (2 ^ 2) End With If x < 4 * ukryty.Width And y < ukryty.Height Then For i As Integer = 0 To 2 If (pixelElementIndex Mod 4) = 0 Then With ukryty.GetPixel(x_ukryty, y) Select Case pixelUkrywanyIndex Case 0 ukrywany = .R pixelUkrywanyIndex = 1 Case 1 ukrywany = .G pixelUkrywanyIndex = 2 Case 2 ukrywany = .B pixelUkrywanyIndex = 0 x_ukryty += 1 End Select End With End If Select Case i Case 0 R += OdwrocBity2(ukrywany Mod 2 ^ 2) ukrywany = Math.Floor(ukrywany / 2 ^ 2) Case 1 G += OdwrocBity2(ukrywany Mod 2 ^ 2) ukrywany = Math.Floor(ukrywany / 2 ^ 2) Case 2 B += OdwrocBity2(ukrywany Mod 2 ^ 2) ukrywany = Math.Floor(ukrywany / 2 ^ 2) kontener.SetPixel(x, y, Color.FromArgb(R, G, B)) End Select pixelElementIndex += 1 Next Else 'wartość 0 przyciemni piksele, wartość 3 rozjaśni je (opcjonalne) R += 3 G += 3 B += 3 kontener.SetPixel(x, y, Color.FromArgb(R, G, B)) End If Next x x_ukryty = 0 Next y kontener.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ " ukryty.bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały ukryte!") Console.ReadLine() End If End If End If End Sub Private Function OdwrocBity2(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 1 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Algorytm odzyskujący bity z ukrytego obrazka zapisanego bez strat w dwóch ostatnich bitach
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Sub Main() Dim open_dialog As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryto obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) Dim szerokosc As Integer = Math.Floor(kontener.Width / 4) Dim ukryty As New Bitmap(szerokosc, kontener.Height) Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim x_ukryty As Integer = 0 Dim pixelUkrywanyIndex As Long = 0 Dim ukrywany_kolor As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 For y = 0 To ymax For X = 0 To xmax Dim pix As Color = kontener.GetPixel(X, y) For i As Integer = 0 To 2 Select Case i Case 0 ukrywany_kolor = ukrywany_kolor * 4 + (pix.R Mod 4) Case 1 ukrywany_kolor = ukrywany_kolor * 4 + (pix.G Mod 4) Case 2 ukrywany_kolor = ukrywany_kolor * 4 + (pix.B Mod 4) End Select pixelElementIndex += 1 If (pixelElementIndex Mod 4) = 0 Then Select Case pixelUkrywanyIndex Case 0 R = ukrywany_kolor ukrywany_kolor = 0 pixelUkrywanyIndex = 1 Case 1 G = ukrywany_kolor ukrywany_kolor = 0 pixelUkrywanyIndex = 2 Case 2 B = ukrywany_kolor ukrywany_kolor = 0 pixelUkrywanyIndex = 0 ukryty.SetPixel(x_ukryty, y, Color.FromArgb(OdwrocBity(R), OdwrocBity(G), OdwrocBity(B))) x_ukryty += 1 End Select End If Next Next X x_ukryty = 0 Next y ukryty.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ "(odzyskany).bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały odzyskane!") Console.ReadLine() End If End Sub Private Function OdwrocBity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 7 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Jeśli chcecie sprawdzić działanie algorytmu, możecie odzyskać sobie kotka z pliku: tapeta-z-ukrytym-kotkiem-piksele-ukryte-ciagiem.bmp
Można oczywiście zapisać tylko cztery bity obrazka ukrywanego, spowoduje to zmniejszenie jakości obrazka, ale wykorzystamy tylko 2 piksele kontenera do zapisu jednego piksela obrazka ukrywanego. Łącząc metodę z początku artykułu i metodę zapisu pikseli (kolor w kolor lub ciągiem) można stworzyć algorytm ukrywający obrazek ze stratą ostatnich czterech bitów obrazka ukrywanego. Należy po usunięciu ostatnich czterech bitów koloru ukrywanego po prostu je odwrócić:
Przykład programu do ukrywania obrazka ze stratą czterech ostatnich bitów z wykorzystaniem LSB2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Dim lokalizacjaPlikuUkrywanego As String Sub Main() Dim open_dialog As New OpenFileDialog() Dim open_dialog_ukrywany As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryjesz obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) open_dialog_ukrywany.InitialDirectory = "c:\" open_dialog_ukrywany.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog_ukrywany.Title = "Wybierz obrazek który ukryjesz" If open_dialog_ukrywany.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuUkrywanego = open_dialog_ukrywany.FileName Dim ukryty As New Bitmap(lokalizacjaPlikuUkrywanego) If kontener.Width < 2 * ukryty.Width Or kontener.Height < ukryty.Height Then Console.WriteLine("Obrazek ukrywany jest większy niż obrazek bazowy, wybierz mniejszy obrazek.") Console.ReadLine() Else Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim R_ukryty As Integer = 0, G_ukryty As Integer = 0, B_ukryty As Integer = 0 Dim x_ukryty As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 Dim indexkoloru As Integer = 0 For y = 0 To ymax For x = 0 To xmax With kontener.GetPixel(x, y) 'zerowanie ostatnich dwóch bitów kontenera R = .R - .R Mod (2 ^ 2) G = .G - .G Mod (2 ^ 2) B = .B - .B Mod (2 ^ 2) End With If x < 2 * ukryty.Width And y < ukryty.Height Then If (x Mod 2) = 0 Then 'pobiera wartości kolorów obrazka ukrywanego With ukryty.GetPixel(x_ukryty, y) R_ukryty = OdwrocBity(.R - .R Mod (2 ^ 4)) G_ukryty = OdwrocBity(.G - .G Mod (2 ^ 4)) B_ukryty = OdwrocBity(.B - .B Mod (2 ^ 4)) End With x_ukryty += 1 End If R += OdwrocBity2(R_ukryty Mod 2 ^ 2) R_ukryty = Math.Floor(R_ukryty / 2 ^ 2) G += OdwrocBity2(G_ukryty Mod 2 ^ 2) G_ukryty = Math.Floor(G_ukryty / 2 ^ 2) B += OdwrocBity2(B_ukryty Mod 2 ^ 2) B_ukryty = Math.Floor(B_ukryty / 2 ^ 2) Else 'wartość 0 przyciemni piksele, wartość 3 rozjaśni je (opcjonalne) R += 3 G += 3 B += 3 End If kontener.SetPixel(x, y, Color.FromArgb(R, G, B)) Next x x_ukryty = 0 Next y kontener.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ " ukryty.bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały ukryte!") Console.ReadLine() End If End If End If End Sub Private Function OdwrocBity2(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 1 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function Private Function OdwrocBity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 7 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Przykład kodu odzyskującego bity ze stratą:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
Imports System.Windows.Forms Imports System.Drawing Module Module1 Dim lokalizacjaPlikuGraficznego As String Sub Main() Dim open_dialog As New OpenFileDialog() open_dialog.InitialDirectory = "c:\" open_dialog.Filter = "Image Files (*.jpeg; *.png; *.bmp)|*.jpg; *.png; *.bmp" open_dialog.Title = "Wybierz obrazek w którym ukryto obrazek" If open_dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then lokalizacjaPlikuGraficznego = open_dialog.FileName Dim kontener As New Bitmap(lokalizacjaPlikuGraficznego) Dim szerokosc As Integer = Math.Floor(kontener.Width / 2) Dim ukryty As New Bitmap(szerokosc, kontener.Height) Dim R As Integer = 0, G As Integer = 0, B As Integer = 0 Dim x_ukryty As Integer = 0 Dim xmax As Integer = kontener.Width - 1 Dim ymax As Integer = kontener.Height - 1 Dim pixelElementIndex As Long = 0 For y = 0 To ymax For X = 0 To xmax Dim pix As Color = kontener.GetPixel(X, y) If (X Mod 2) = 0 Then If X > 0 Then ukryty.SetPixel(x_ukryty, y, Color.FromArgb(OdwrocBity(R), OdwrocBity(G), OdwrocBity(B))) R = 0 G = 0 B = 0 x_ukryty += 1 End If R = R * 4 + (pix.R Mod 4) G = G * 4 + (pix.G Mod 4) B = B * 4 + (pix.B Mod 4) Else R = Odwroc4Bity(R * 4 + (pix.R Mod 4)) G = Odwroc4Bity(G * 4 + (pix.G Mod 4)) B = Odwroc4Bity(B * 4 + (pix.B Mod 4)) If X = xmax Then ukryty.SetPixel(x_ukryty, y, Color.FromArgb(OdwrocBity(R), OdwrocBity(G), _ OdwrocBity(B))) End If End If Next X x_ukryty = 0 Next y ukryty.Save("C:\Users\piotr\Desktop\" + _ IO.Path.GetFileNameWithoutExtension(lokalizacjaPlikuGraficznego).ToString + _ "(odzyskany).bmp", System.Drawing.Imaging.ImageFormat.Bmp) Console.WriteLine("Bity zostały odzyskane!") Console.ReadLine() End If End Sub Private Function OdwrocBity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 7 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function Private Function Odwroc4Bity(ByVal w As Integer) As Integer Dim rezultat As Integer = 0 For i As Integer = 0 To 3 rezultat = rezultat * 2 + (w Mod 2) w = Math.Floor(w / 2) Next Return rezultat End Function End Module |
Kotek ukryty tą metodą do pobrania i sprawdzenia: Matrix ukryty