Click here to Skip to main content
15,886,724 members
Articles / Programming Languages / Visual Basic
Tip/Trick

How to hide information in an Image

Rate me:
Please Sign up or sign in to vote.
4.91/5 (10 votes)
22 Sep 2014CPOL6 min read 27.5K   1.3K   20   11
Use an image to store passwords to be used to Encrypt / Decrypt information

Introduction

This piece is a method, certainly not the best, to hide information in an image(s) that can be used to Encrypt / Decrypt information in your application at runtime. When encrypting information a "Key" (password) is required to encrypt and eventually decrypt sensitive information. In my case it was Database connection strings.

Note: Steganography is the process of adding information into the image itself and it can be a timely process since you have to calculate the Horizontal and Vertical locations of the information. Using the EXIF / Meta Tag, it is a direct approach where information is written into the header locations of the image and not the image itself. Using the Tags you are limited to a certain number of them depending on the data you intend storing and the size of the information you wish to store. With Steganography, you are limited by the size and image format type (PNG, TIFF, BMP, etc) of the image. 

Background

Being my first time developing commercially in a .Net environment with Visual Studio, I was ignorant (not aware of) to how easily it was to decompile a .Net assembly. 

I was recently devastated to learn how easily it was to decompile a .Net assembly to the point where nothing was obscured from the decompiler.

To add to my frustration in my quest to try and secure my code through the use of an obfuscater, NONE of them worked. I started with  Dotfuscater as it was part of VS2012 and ended up with .NET Reactor, unfortunately all of them left me with a broken assembly.

I then opted for Strong Name Signing the assembly but because I was using 3rd party DLL's which were not signed (and could not be signed with a ildasm decompile/recompile) I was left to my own devices.

There was no way that I could encrypt sensitive information without somehow having the "Key" stored somewhere in my code and since it can be decompiled I might as well leave everything the way it is and consider it OpenSource thanks to Microsoft and their inability to compile in Native Machine code. (Aparantly, they are bringing it back but only available for Store Apps at the moment)

Being a photographer in my spare time, I worked extensively with images in the past and I was aware that it was possible to Read / Write information to the Meta Data (Exif) of images.

So this is my attempt to reduce the number of school kiddies trying to hack my Databases at least.

I would like to point out again, this is not the most effective way of hiding information but I find it very convenient at this time. Please use this post as a stepping stone to provide other, maybe even better, ways to protect one's intellectual property when tools like Signing and Obfuscating is not an option, 

Using the code

There are a few things we need to achieve this:

1. Read / Write EXIF data methods
This will be used to write a "Key" into one of the EXIF Tags of the image we intend to use in our Project. Since most applications make use of an image at some point it would not be suspicious to have images in our application.

2. Encrypt / Decrypt methods
This will encrypt and decrypt our sensitive strings.

3. An Image
The image will need to be sored as an item in the application Resources because an ImageList only holds a thumbnail version of the original image. This thumbnail does not have the Meta Data of the original image.

4. Our Sensitive strings
These are typical strings that could be a Password, Connection String, etc. The encrypted strings can be stored in the Settings of the application.

Fig 1.0

Image 1

Figure 1.0 shows a simple interface to "inject" our "Key" into one of the image EXIF tags. For this demonstration I have selected to use the Description Tag of the image.

To easily update/insert data into any of the EXIF Tags I used this class from  at the following Code Project post: http://www.codeproject.com/Articles/4956/The-ExifWorks-class.The class is too big to post here. Please download the source code.

Our project is a two part process:
1) Inject "password" into the image,
2) Encrypt / Decrypt plain text with the password retrieved from the EXIF Tag

 

Inject Password:

Add the following private methods:

VB.NET
Private EX As ExifWorks
Private tmpImage As Image
Dim imgInfo As System.IO.FileInfo = Nothing

In the Button.Click event of the "Open" button on the form use the following code:

VB.NET
Private Sub btnLoadImage_Click(sender As Object, e As EventArgs) Handles btnLoadImage.Click
    'Clear the Picbox
    pbSelectedImage.Image = Nothing

    'Select Iamge file
    Dim result As DialogResult = ofdSelectimageFile.ShowDialog()
    If result = DialogResult.OK Then
        'Display Iamge
        pbSelectedImage.Image = Image.FromFile(ofdSelectimageFile.FileName)
    Else
        Return
    End If

    'Display full path of the image file
    imgInfo = New IO.FileInfo(ofdSelectimageFile.FileName)
    txtImagePath.Text = imgInfo.FullName
    
    'Read the Description Exif Tag and display it
    Dim EX As New ExifWorks(imgInfo.FullName)
    txtExifTagValue.Text = EX.Description
End Sub

This should look like this now:
Fig1.1
Image 2

Now that the image has been selected and displayed we can now enter our "Key" in the Password textbox. Once you settled on a password add the following code to the Button.Click event of the "Inject Password" button on the form:

VB.NET
Private Sub btnInject_Click(sender As Object, e As EventArgs) Handles btnInjectImage.Click
   If txtClearTextPassword.Text = "" Then Return
   If IsNothing(pbSelectedImage.Image) Then Return
   pbSelectedImage.Image = Nothing
   pbSelectedImage.Image = Image.FromFile(txtImagePath.Text)
   Dim EX As New ExifWorks(txtImagePath.Text)
   Dim dateStr As String = EX.DateTimeOriginal
   Dim description As String = EX.Description
   'Write the Password the the Description Tag of the EXIF data
   EX.SetPropertyString(ExifWorks.TagNames.ImageDescription, txtClearTextPassword.Text.ToString)
   txtExifTagValue.Text = EX.Description

   'save the image to a new image file to retain the changes in the Meta data (Exif)
   impImage = EX._Image
   tmpImage.Save(imgInfo.DirectoryName + "\Temp.jpg")
   pbSelectedImage.Image = Image.FromFile(imgInfo.DirectoryName + "\Temp.jpg")

   'Clean up
    tmpImage.Dispose()
    EX.Dispose()
End Sub

Now that we have inserted our "Key" into the image and saved it as another image file, we need to open the new image to verify that our "Key" has been added to the Exif Decription Tag of the image.

Fig. 1.3

Image 3
Fig 1.3 shows that we have loaded our new image and that the Exif Description Tag now holds our "Key".

We can now add the image to the Resources of our project to be used when we need to Encrypt/Decrypt information.

Next we are going to use the image in our Encrypt/Decrypt procedures:

Fig 2.0 shows a simple interface to demonstrate using an image to store a Key to be used to Encrypt and Decrypt information. Since an image is already compressed the Exif data is never exposed through any decompiler.

Image 4

We will use this form to load our preselected image into the picturebox control, enter a string, Encrypt the string and then Decrypt it using the same key that we have stored in the Exif Description Tag of the image.

Add the Encrypt/Decrypt class to your project. This class is an adaption from MSDN.

'http://msdn.microsoft.com/en-us/library/ms172831.aspx

Imports System.Security.Cryptography
Public NotInheritable Class _clDes3EncryptDecrypt

    Private Des3CryptoProvider As New TripleDESCryptoServiceProvider

    Sub New(ByVal Key As String)
        'Initialize Des3 Crypto Provider
        Des3CryptoProvider.Key = HashUserKey(Key, Des3CryptoProvider.KeySize \ 8)
        Des3CryptoProvider.IV = HashUserKey("", Des3CryptoProvider.BlockSize \ 8)
    End Sub

    'Hash the Secret Key (Password)
    Private Function HashUserKey(ByVal Key As String, ByVal KeyLength As Integer) As Byte()
        'Create Hash Provider to Hash the Key (Password)
        Dim Sha1CryptoProvider As New SHA1CryptoServiceProvider

        'Hash the password key 
        Dim KeyBytes() As Byte = System.Text.Encoding.Unicode.GetBytes(Key)
        Dim Sha1Hash() As Byte = Sha1CryptoProvider.ComputeHash(KeyBytes)

        'Pad (or Truncate) the Hash 
        ReDim Preserve Sha1Hash(KeyLength - 1)
        Return Sha1Hash
    End Function

    'Encrypt Data with Key
    Public Function EncryptData(ByVal ClearText As String) As String
        'Convert ClearText string to a Byte Array
        Dim ClearTextBytes() As Byte = System.Text.Encoding.Unicode.GetBytes(ClearText)

        'Create a memory stream (ms) 
        Dim ms As New System.IO.MemoryStream

        ' Create Encoder to write to memory stream 
        Dim encodedStream As New CryptoStream(ms, Des3CryptoProvider.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write)

        'Use the crypto stream to write the byte array to the stream.
        encodedStream.Write(ClearTextBytes, 0, ClearTextBytes.Length)
        encodedStream.FlushFinalBlock()

        'Convert the encrypted stream to a printable string. 
        Return Convert.ToBase64String(ms.ToArray)
    End Function

    'Decrypt Data with Key
    Public Function DecryptData(ByVal EncryptedText As String) As String
        'Convert the encrypted text string to a byte array. 
        Dim EncryptedBytes() As Byte = Convert.FromBase64String(EncryptedText)

        'Create the stream. 
        Dim ms As New System.IO.MemoryStream

        'Create the decoder to write to the stream. 
        Dim DecoderStream As New CryptoStream(ms, Des3CryptoProvider.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write)

        'Use the crypto stream to write the byte array to the stream.
        DecoderStream.Write(EncryptedBytes, 0, EncryptedBytes.Length)
        DecoderStream.FlushFinalBlock()

        'Convert the plaintext stream to a string. 
        Return System.Text.Encoding.Unicode.GetString(ms.ToArray)
    End Function
End Class

In the form we add the following private methods:

VB.NET
Private EX As ExifWorks
Private Des3EncryptDecrypt As _clDes3EncryptDecrypt

In the Button.Click event of the "Load Image" button on our form, we add the following code:

VB.NET
Private Sub btnLoadImage_Click(sender As Object, e As EventArgs) Handles btnLoadImage.Click
        'Load image from Resources
        pbImageFromResources.Image = Global.frmInsertPW.My.Resources.Resources.Temp
        'Read the Description Exif Tag and display it
        Dim EX As New ExifWorks(pbImageFromResources.Image)
        txtExifTag.Text = EX.Description
​End Sub

Fig 2.1
Image 5

Fig 2.1 shows our image loaded and our Key retrieved from the Exif Description Tag.
We are now ready to enter our sensitive information and encrypt it. I've used a normal database connection string as it is the reason for the research and this post.

In the Button.Click event of the "Encrypt" button on our form, we add the following code:
(The code has been adapted from MSDN)

VB.NET
'http://msdn.microsoft.com/en-us/library/ms172831.aspx
    Private Sub btnEncrypt_Click(sender As Object, e As EventArgs) Handles btnEncrypt.Click
        Dim EX As New ExifWorks(Global.frmInsertPW.My.Resources.Resources.Temp)
        'retrieve our "password"
        Dim password As String = EX.Description
        Dim ClearText As String = txtClearText.Text
        'Hash the password
        Dim wrapper As New _clDes3EncryptDecrypt(password)
        'Encrypt string
        Dim cipherText As String = wrapper.EncryptData(ClearText)
        'Display Encrypted String
        txtEncodeText.Text = cipherText
    End Sub

Fig 2.2
Image 6

The encryption produces the following encrypted string:

83LtyXE2tYHpN8/ORhZEyeUYbp1d3fZ0YFSue0/zhf4pmd5NtTpURIJAZVWk2BSQqJPUzfmXSBbzTvxkZHEleyIZEYsP1t1FN6HOMI8H6ElHXx45gQKsoKsukZlq3u5QFkoJ/sCXW/IhMS+WiNBPIKN/4ByiTeeb

To decrypt the encrypted string we add the following code to the Button.Click event of the "Decrypt" button on our form.

VB.NET
Private Sub btnDecrypt_Click(sender As Object, e As EventArgs) Handles btnDecrypt.Click
        Dim cipherText As String = txtEncodeText.Text
        Dim EX As New ExifWorks(Global.frmInsertPW.My.Resources.Resources.Temp)
        'retrieve our "password"
        Dim password As String = EX.Description
        'Hash the password
        Dim wrapper As New _clDes3EncryptDecrypt(password)

        ' DecryptData throws if the wrong password is used. 
        Dim ClearText As String = wrapper.DecryptData(cipherText)
        txtDecodedText.Text = ClearText
    End Sub

You will notice that I keep reading the Exif Tag for the Key to Encrypt and Decrypt the strings.

Fig 2.3
Image 7

The decryption produces our exact string:

"database=MyDB;Server=MyServer;User Id=root;Pwd=myPassword"

Remember that this solution will only be truly effective if you are already storing encrypted information in your project and wish to decrypt it at runtime. 

This is all there is to it really.

I would like to hear of any other ways of obscuring information in ways that will foil decompilers when tools like obfusctaing and signing aren't an option.

 

Points of Interest

I've learned that problems are the limitation of our imagination and that each problem we face affords us an opportunity to grow our imagination.

History

None so far.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
South Africa South Africa
Studied Software Development many moons ago, when the sun was still high for Cobol, Fortran, Basic, etc. programmers. However, I found corporate networks and systems more challenging and rewarding than sitting behind a desk all day long doing mostly maintenance on code. Mainframes were the super computers at the time and Tatung made very fancy desktop computers and to soop them up you had to have a TsengLabs VGA card, EGA CRT and a SoundBlaster sound card installed into the system - only then could you call yourself a Boss!

Later in life I reached a turning point where the saying "Jack of all trades, Master of none" became my driving force. I will do everything I know nothing about. Since then, life has become an adventure and not just a journey.

At the moment I write software tools to connect users with disconnected data.

Comments and Discussions

 
QuestionDidn't get the intention of this method Pin
RamNow24-Sep-14 21:45
professionalRamNow24-Sep-14 21:45 
AnswerRe: Didn't get the intention of this method Pin
Tino Fourie24-Sep-14 23:55
Tino Fourie24-Sep-14 23:55 
AnswerRe: Didn't get the intention of this method Pin
RamNow25-Sep-14 1:25
professionalRamNow25-Sep-14 1:25 
GeneralRe: Didn't get the intention of this method Pin
Tino Fourie25-Sep-14 1:52
Tino Fourie25-Sep-14 1:52 
AnswerRe: Didn't get the intention of this method Pin
RamNow25-Sep-14 3:49
professionalRamNow25-Sep-14 3:49 
GeneralRe: Didn't get the intention of this method Pin
Tino Fourie25-Sep-14 4:20
Tino Fourie25-Sep-14 4:20 
QuestionImages not working Pin
fmsalmeida22-Sep-14 23:29
professionalfmsalmeida22-Sep-14 23:29 
AnswerRe: Images not working Pin
Tino Fourie22-Sep-14 23:38
Tino Fourie22-Sep-14 23:38 
AnswerRe: Images not working Pin
Tino Fourie23-Sep-14 0:39
Tino Fourie23-Sep-14 0:39 
GeneralRe: Images not working Pin
cspitzer25-Sep-14 13:15
cspitzer25-Sep-14 13:15 
GeneralRe: Images not working Pin
Tino Fourie25-Sep-14 13:37
Tino Fourie25-Sep-14 13:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.