You want to send someone an encrypted message but sometimes cryptography isn't enough, for example it might be illegal to use cryptography in some countries and you could get arrested if you are caught using cryptography. So, you need to disguise your message so that it isn't obvious to any eavesdropper that there is even a message at all. Hiding the message in this way is known as Steganography.
One way to do this is to hide your message inside a picture or sound file. This sounds extremely complicated but once you know how it works it is actually quite simple. The technique used in this program is to hide the message inside the least significant bits of each pixel within a bitmap. Let me explain how this works: a bitmap is basically a grid of pixels where each X,Y co-ordinate holds the colour value of that pixel. It is possible to make a tiny change to the value of a pixel that will go unnoticed by the human eye. Here is the screen shot from the program where I encoded the text from the title scene from Star Wars into a picture of Yoda. The image on the left is the original, and the version on the right contains the encoded text.
Here's the program and full Delphi source code
Usage:
Click the load button to load a bitmap onto the left image pane. To encode a message into the text click the hide button (optionally enter an encryption key first). The program will encode the message into the bits of a new bitmap which is displayed on the right. You can then save this image to a new file by clicking the Save button.
To recover the text from a bitmap, click the load button to load the image and click the Recover button. The recovered text will appear on the screen. If the text was encrypted you will need to enter the decryption key to recover the plaintext.
The bottom window shows the output from the program and gives you an idea of how it works.
Geek stuff!
For those that are interested, here is a detailed description of the encoding process:
I want to hide the word 'It'. The first character is 'I', which in Ascii is value 73. In binary 73 is represented as 01001001, so what we need to do is to encode each of these bits within the pixels of the bitmap.
Now let's suppose that the very first pixel in the bitmap that we are using holds the value 10 which in binary is 00001010. What we're going to do is to set the least significant bit in the pixel (which is the rightmost value and is currently 0) to the the value of the first bit of 73 which is 0. As it is already set to 0 this pixel remains unchanged. However, suppose that the next pixel also holds the value 10 (00001010) and we now wish to encode the second bit of 73 which is set to 1. We now set the least significant bit of this pixel to 1, which now gives the binary value 00001011 which is decimal 11. This is now the new value of this pixel. So far we have used two pixels and have only encoded two bits of our first character, and as a character is comprised of eight bits (one byte) we will need to use eight pixels to encode each character of the message. Here is the output of my program when the word 'It' is encoded within a bitmap of Yoda:
Hiding I - Ascii 73 (bin 01001001)
Encoding bit 7=0, pixel at 0,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 6=1, pixel at 1,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Encoding bit 5=0, pixel at 2,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 4=0, pixel at 3,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 3=1, pixel at 4,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Encoding bit 2=0, pixel at 5,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 1=0, pixel at 6,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 0=1, pixel at 7,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Hiding t - Ascii 116 (bin 01110100)
Encoding bit 7=0, pixel at 8,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 6=1, pixel at 9,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Encoding bit 5=1, pixel at 10,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Encoding bit 4=1, pixel at 11,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Encoding bit 3=0, pixel at 12,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 2=1, pixel at 13,0 was dec 10 (bin 00001010) now dec 11 (bin 00001011)
Encoding bit 1=0, pixel at 14,0 was dec 10 (bin 00001010) now dec 10 (bin 00001010)
Encoding bit 0=0, pixel at 15,0 was dec 11 (bin 00001011) now dec 10 (bin 00001010)
When the program has finished it creates a new bitmap with the updated pixels and the embedded text inside. Anybody looking at this bitmap would be unable to tell the difference between the new version and the original bitmap image as we have only made the tiniest change to the colour value of each pixel. So the new bitmap could safely be emailed to somebody or put on a web page and it would be very difficult for anybody to detect that it contains a hidden message. Please note that the bitmap I used in this example is a 24-bit bitmap, if you use an 8-bit bitmap the results may be different and the changes to each pixel are likely to be a lot more obvious.
I will now explain how to recover the message from the bitmap. What we do is basically the process described above but in reverse. For example, to recover the first character of the message we take the least significant bit of the first eight pixels and use these eight bits to reconstruct the binary value of our character (one byte). In the above example the first pixel we wrote out was the value 10. In binary this is expressed as 00001010 so the first bit of the byte we're trying to reconstruct is 0 (taken from the rightmost bit, i.e. 00001010). The next pixel we wrote out was the value 11 which in binary is 00001011 so the second bit of the byte we are reconstructing is 1 (we now have 01). Reading the next six pixels gives us the bits 001001, making the final value 01001001 which in decimal is 73, the Ascii value of 'I'. We then keep repeating the process for the next byte until we have recovered the entire message.
However, when recovering a message how do we know that we have reached the end of the message? For example the bitmap may contain many more pixels after the message and most of these will just give us complete garbage. The technique I used in this program is to write a terminating character at the end of the message, I used Ascii value 0 but you could use any character as long as it is unlikely to occur in a message. The recovery process simply stops as soon as it sees this character. Here is the full output of my program recovering the word 'It' we wrote out earlier:
Pixel at 0,0 is dec 10 (bin 00001010)
Pixel at 1,0 is dec 11 (bin 00001011)
Pixel at 2,0 is dec 10 (bin 00001010)
Pixel at 3,0 is dec 10 (bin 00001010)
Pixel at 4,0 is dec 11 (bin 00001011)
Pixel at 5,0 is dec 10 (bin 00001010)
Pixel at 6,0 is dec 10 (bin 00001010)
Pixel at 7,0 is dec 11 (bin 00001011)
Reconstructed char I = Ascii 73 (bin 01001001)
Pixel at 8,0 is dec 10 (bin 00001010)
Pixel at 9,0 is dec 11 (bin 00001011)
Pixel at 10,0 is dec 11 (bin 00001011)
Pixel at 11,0 is dec 11 (bin 00001011)
Pixel at 12,0 is dec 10 (bin 00001010)
Pixel at 13,0 is dec 11 (bin 00001011)
Pixel at 14,0 is dec 10 (bin 00001010)
Pixel at 15,0 is dec 10 (bin 00001010)
Reconstructed char t = Ascii 116 (bin 01110100)
Please be aware, it would actually be quite easy for somebody to extract the message from this bitmap if they suspected that it contained a message, because the recovery process is actually quite simple as I have explained above. Therefore, I have provided the option to encrypt the text with the AES algorithm before writing it to the bitmap - simply enter your encryption key into the optional text box before clicking Hide. It will then only be possible to recover the text from the bitmap by entering the same key when you need to extract the text by clicking Recover. Also, when an encryption key is used the program will not write to the least significant bit of every pixel - to make Steganalysis more difficult it skips over certain pixels and leaves them unchanged. Rather than just skipping 10 pixels at a time which would be too obvious, it uses a pseudo random number sequence so that a different number of pixels are skipped between each bit. The PRNG is seeded using a hash of the crypto key so as long as the same key is entered when you need to recover the text the exact same sequence of skipped pixels will be used. The maximum number of pixels that will be skipped defaults to 50 but you can change this if you like, although you need to enter exactly the same value when you want to recover the text. Skipping a larger number of pixels is more secure but there is a risk that you may not be able to fit the text before the end of the bitmap is reached.
If you have any questions or want to report a bug please drop me a line at