Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Images' Steganography

4.45/5 (53 votes)
25 Jun 20074 min read 1   36.6K  
Using images for encrypted text transmission

Introduction

Our goal is to build a simple application that is able to send and receive encrypted messages embedded inside images. The user is able to choose the image he wants and the program must tell if this image will suit the text or not. No pixel deformation or size distortion is allowed. TIF images may suffer slight size increments or decrements, but we will get to that later. The user can set a different password for every message he sends, which will enable the manager to transmit the same image to two groups, but with two different passwords and two different messages.

Using the code

Below, I've put the main procedure that will embed the text in the image. The code is commented for every step:

VB
If MsgBox("You are about to encrypt and embed this message :[[ 
    " + TextBox1.Text + " ]] , Shall We Proceed?", MsgBoxStyle.OkCancel, 
    "Stealth") = MsgBoxResult.Cancel Then Exit Sub 
        Label2.Text = ""
If RadioButton1.Checked = False And RadioButton2.Checked = False Then
    MsgBox("Please select an extention") 
    Exit Sub
End If 

Dim text As String 
text = TextBox1.Text.ToString + " "
Dim passw As String = "" input("Enter Password To Protect Your Text", passw) 

If passw = "" Then 'err handler for ugly passwords 
    MsgBox("Error ! You Didn,t Choose Any Password To Protect The Message.")
    Exit Sub
ElseIf passw.Length < 4 Then 
    MsgBox("Error ! Password Is Too Short.") 
    Exit Sub 
End If 

Dim amount As Double = text.Length 
process_pass_with_tx(passw, text) ' this will encrypt the test by the 
' password this is done by generating a string from the password and this 
' string is tall enough to perform bit stream xor operation on all chares 
' included in the message text that we want to send. we secured the text,
' now we will try hide the encrypted text in the image.

TextBox1.Text = text 
If RadioButton1.Checked = True Then GoTo mode2 ''started deferences 
between tow modes here 

If Me.OpenFileDialog1.ShowDialog = DialogResult.Cancel Then
    Exit Sub
Else 'err handler to prevent wrong extensions 
    Dim infoReader As System.IO.FileInfo 
    infoReader = My.Computer.FileSystem.GetFileInfo(
        Me.OpenFileDialog1.FileName)
If infoReader.Extension.Substring(1, 3).ToLower <> (
    RadioButton2.Text.ToLower) Then
    MsgBox("Error : Encryption mode requires different extension ")
    Exit Sub 
End If

LoadNewPict(Me.OpenFileDialog1.FileName) 'display the selected image preview 

If PictureBox1.Image.Size.Width < 64 Or PictureBox1.Image.Size.Height < 
    64 Then 
' prevent user from using unproperiate images 
    MsgBox("Error! Tiny Images Cann,t Be Used In Steganography.") 
    Exit Sub
End If

Dim w1 As Integer = PictureBox1.Image.Size.Width - 1
Dim w2 As Integer = PictureBox1.Image.Size.Height - 1 
Dim possible_size As Double = ((w1 - 7) * (w2 - 7)) / 8 ' 8 bits make one 
' char, and avoid edges 
If possible_size < amount Then ' determine if the image is not big enough 
' for text
    MsgBox("This image is not big enough to carry your message", 
        MsgBoxStyle.Critical)
    Exit Sub
End If
End If ' file dialog if 
' load accurding to extention 
Dim dib, val, reslt As Integer
dib = FreeImage.FreeImage_Load(FreeImage.FREE_IMAGE_FORMAT.FIF_TIFF, 
    OpenFileDialog1.FileName, 0) 
On Error GoTo rongex1
Dim ba As bits_array 
ba.Initialize() 
Dim sz As Long
Dim sz1, sz2, sz3, sz4 As Byte
Dim t As Double sz = text.Length ' number of chars to encrypt 
    
sz1 = Decimal.Remainder(sz, 100) ' take the lowest 2 digits of it
t = sz / 100 'take the left numbers (all except lowest 2 digits) 
sz = Decimal.Truncate(t) ' set size_variable to hold left numbers (all except
' lowest 2 digits)
sz2 = Decimal.Remainder(sz, 100) ' repeat 
t = sz / 100 
sz = Decimal.Truncate(t) 
sz3 = Decimal.Remainder(sz, 100) ' ' repeat

t = sz / 100 
sz = Decimal.Truncate(t) 
sz4 = Decimal.Remainder(sz, 100) ' will take final 2 digits, now you can 
' see: the maximum size of text is ( 99 99 99 99 ) 
 
' now we will convert sz1 to bits array and stor it in the first line of the 
' picture after it we will do the sz2 and then sz3 and then sz4.. 
' the coming 4 for loops are used for that 
Dim i, j, m 
i = 0 
j = 1 
ba.Initialize()
byte_to_bits(sz1, ba)
For m = 0 To 7 '''''''''''''''''' 1 
    i = i + 1 
    FreeImage.FreeImage_GetPixelColor(dib, i, j, val) 
    ' set the lowest bit according to my bit
    If odd(val) = True Then
        If ba.bits(m) = False Then 'bit is zero 
            FreeImage.FreeImage_SetPixelColor(dib, i, j, (val + 1))
        End If 
    End If 
    If odd(val) = False Then 
        If ba.bits(m) = True Then 'bit is one 
            FreeImage.FreeImage_SetPixelColor(dib, i, j, (val + 1))
        End If 
    End If 
Next m
ba.Initialize() 
byte_to_bits(sz2, ba) 
For m = 0 To 7 '''''''''''''''''''''' 2 
    i = i + 1 
    FreeImage.FreeImage_GetPixelColor(dib, i, j, val) 
    If odd(val) = True Then
        If ba.bits(m) = False Then 'bit is zero 
            FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1)
        End If
    End If 
    If odd(val) = False Then 
        If ba.bits(m) = True Then 'bit is one
            FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1) 
        End If 
    End If 
Next m
ba.Initialize()
byte_to_bits(sz3, ba)
For m = 0 To 7 '''''''''''''''''''''''''''' 3 
    i = i + 1
    FreeImage.FreeImage_GetPixelColor(dib, i, j, val)
    If odd(val) = True Then
        If ba.bits(m) = False Then 'bit is zero 
            FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1) 
        End If 
    End If 
    If odd(val) = False Then
        If ba.bits(m) = True Then 'bit is one
            FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1)
        End If 
    End If 
Next m 
ba.Initialize() 
byte_to_bits(sz4, ba)
For m = 0 To 7 ''''''''''''''''''''''''''''' 4 
    i = i + 1 
    FreeImage.FreeImage_GetPixelColor(dib, i, j, val)
    If odd(val) = True Then 
        If ba.bits(m) = False Then 'bit is zero 
            FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1) 
        End If
    End If 
    If odd(val) = False Then
        If ba.bits(m) = True Then 'bit is one 
            FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1) 
        End If
    End If 
Next m '''' we have just stored the size of the text 

Dim n As Byte
Dim count As Long 
count = 0 'i already set size ===>>> first line for size 
' Now i will scan the picture from the second line 

For j = 2 To PictureBox1.Image.Size.Height Step 1
    i = 1 
    Do While (i + 7) < PictureBox1.Image.Size.Width ' Step 8 ' may use 
    ' freeimage_getdotspermeterx 
        n = Asc(CChar(text.Substring(count, 1))) ' this give ascii code for 
        ' the every text letter, to reverse it use chr() function
        count = count + 1 
        If count = text.Length Then GoTo out 
            ba.Initialize()
            byte_to_bits(n, ba) ''''''''''' 
        For m = 0 To 7 
            FreeImage.FreeImage_GetPixelColor(dib, i, j, val) 
            ' change it according to my bit
            If odd(val) = True Then 
                If ba.bits(m) = False Then 'bit is zero 
                    FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1) 
                End If
            End If 
            If odd(val) = False Then 
                If ba.bits(m) = True Then 'bit is one 
                    FreeImage.FreeImage_SetPixelColor(dib, i, j, val + 1)
                End If 
            End If 
            i = i + 1
         Next m 
         i = i + 8 
    Loop 
Next j 
out:
Dim fn As String 
Dim con As Integer = 0 
fn = OpenFileDialog1.FileName + "_stealth.tif" 
up1: 
If File.Exists(fn) = False Then
    FreeImage.FreeImage_Save(FreeImage.FREE_IMAGE_FORMAT.FIF_TIFF, 
        dib, fn, &H800S) 
Else 
    con = con + 1 
    MsgBox("FILE: " + fn + " ALREADY EXISTS ,WE WILL CHANGE THE NAME TO " + 
        OpenFileDialog1.FileName + con.ToString + "_stealth.tif") 
    fn = OpenFileDialog1.FileName + con.ToString + "_stealth.tif" 
    GoTo up1
End If 
Label2.Text = fn
Exit Sub 
mode2: '
' in mode2 we will treat the file with the deferent extension in the same 
way, just change the lib calls according to the extension 
' to decrypt the message we will reverse what we have done 

Points of interest

You must put freeimage.dll in the same path as the EXE to make it work. This has already been done for you. The output image will be named the same as the input image plus "_stealth" if the output file already exists; the program will handle that. The textbox control has a maximum amount of characters to hold; if your text is bigger than that, try to separate it and use one image for each part. Lossy compression algorithms will damage encrypted data inside the image, so it is not recommended to compress the output images before transmission.

You may notice some size change for some images. This change can probably be ignored when compared to total file size. This probably happened because the compression algorithm that generated the native image that you supplied to the program is different from the compression algorithm in my DLL lib, which generated the output image, and not because the embedded data increased the size. The proof is this: before you start the program, write a mini program and use the same function that I used in my code to resave your image under a different name with the same extension. Let's say this new image is called beta. Now start the program and use it to embed some text. See the output image? It is exactly the same size as the image beta.

You can use any encryption algorithm you trust, i.e. Public-Private key, ElGamal... Our way of Stega is independent from the bit sampling (bits per pixel) of images, but it is strongly recommended that it be used with 24 bpp images or higher. This will guarantee the prevention of pixel deformation. Most of the web images are sampled 24 bpp.

Note that my key generation was weak, as I just repeated the key. If any character in the key were discovered, then all message characters encrypted by it would also be discovered. You should use good functions to generate a big string to make the xor or maybe use a better cipher. You can also use this program for authentication by using a background image somewhere inside your application to set a copyright text.

Low order bits (this program) don't work with JPEG because they use the Lossy compression algorithm. So, working with JPEG requires extra work. You can take the red/green/blue channel of the image and do the same. You can use this to take the channel whose histogram is approximated to a horizontal line and then divide the new image to squares like this:

1 1 1
1 x 1
1 1 1

In the central pixel, x, put a value that is bigger than all neighbors if we got bit 1. Put a value that is smaller than all neighbors if we got bit 0. Now the possible size to hold data here is divided by 9. This way may sometimes cause slight distortion because it works on high-order bits. We can only use the squares whose values are bigger than the proper threshold. Alternatively, divide the image into squares like this:

X Y
Y X

If X's pixels hold the same value, then the square represents 1 and Y's pixels must be changed to something different. If Y's pixels hold the same value, then the square represents 0 and X's pixels must be changed to something different. Now when we receive, if X's pixels and Y's pixels are different or both are the same, then someone was playing with this image and the bit is invalid. We can apply this on more than one channel, so if one is corrupted we will use the backup. Last 2 algorithms: Alaa Jebran © 2007.

Don't be surprised to know that some big agencies like the CIA, NSA, etc. use celebrities' web sites or pornographic web sites to send and receive encrypted messages using similar technologies.

History

  • 14 May, 2007 -- Original version posted
  • 25 June, 2007 -- Article edited and moved to the main CodeProject.com article base

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here