Click here to Skip to main content
15,867,488 members
Articles / Programming Languages / C#
Article

Steganography - Hiding messages in the Noise of a Picture

Rate me:
Please Sign up or sign in to vote.
4.74/5 (64 votes)
12 Jul 2004CPOL3 min read 390.6K   11.3K   185   131
Hiding all kinds of data in the pixels of bitmaps.

Sample Image - steganodotnet.jpg

Introduction

This article describes how any data can be hidden in the noise pixels of an image.

Background

There is only one safe place for private data and messages: the place where nobody looks for it. A file encrypted with algorithms like PGP are not readable, but everybody knows that there is something hidden. Wouldn't it be nice, if everyone could open your encrypted files, and see noisy photos of some old friends instead of your private data? They surely wouldn't look for pieces of encrypted messages in the pixel values.

Using the code

To hide a message, open a bitmap file, then enter a password or select a key file. The key file can be any file, another bitmap for example. This password or key will be treated as a stream of bytes specifying the space between two changed pixels. I don't recommend text files, because they may result in a quite regular noise pattern. The longer your key file or password is, the less regular the noise will appear.

Next step, enter the secret message or choose a file, and click the Hide button. The application writes the length of the message in bytes into the first pixel. After that it reads a byte from the message, reads another byte from the key, and calculates the coordinates of the pixel to use for the message-byte. It increments or resets the color component index, to switch between the R, G and B component. Then it replaces the R, G or B component of the pixel (according to the color component index) with the message-byte, and repeats the procedure with the next byte of the message. At last, the new bitmap is displayed. Save the bitmap by clicking the Save button. If the grayscale flag is set, all components of the color are changed. Grayscale noise is less visible in most images.

To extract a hidden message from a bitmap, open the bitmap file and specify the password or key you used when hiding the message. Then choose a file to store the extracted message in (or leave the field blank, if you only want to view hidden Unicode text), and click the Extract button. The application steps through the pattern specified by the key and extracts the bytes from the pixels. At last, it stores the extracted stream in the file and tries to display the message. Don't bother about the character chaos, if your message is not a Unicode text. The data in the file will be all right. This works with every kind of data, you can even hide a small bitmap inside a larger bitmap. If you are really paranoid, you can encrypt your files with PGP or GnuPG before hiding them in bitmaps.

How it works

To see how the application works, you should view the source. I've commented every block, because otherwise I'd have to post nearly all the code here to explain it.

Here is a summary about hiding:

Image 2

And about extracting:

Image 3

The process starts with writing the length of the entire message into the first pixel. We'll need this value before extracting the message later on.

C#
messageLength = (Int32)messageStream.Length;


//do some length conflict checking here
//...
String colorValue = messageLength.ToString("x");
colorValue = UnTrimColorString(colorValue, 6);
int red = Int16.Parse(colorValue.Substring(0,2), NumberStyles.HexNumber);
int green = Int16.Parse(colorValue.Substring(2,2), NumberStyles.HexNumber);
int blue = Int16.Parse(colorValue.Substring(4,2), NumberStyles.HexNumber);
pixelColor = Color.FromArgb(red, green, blue);
bitmap.SetPixel(0,0, pixelColor);

Then it reads a byte from the key stream to calculate the next position:

C#
//start with second pixel
Point pixelPosition = new Point(1,0);
//Loop over the message
for(int messageIndex=0; messageIndex<messageLength; messageIndex++){
 //repeat the key, if it is shorter than the message
 if(keyStream.Position == keyStream.Length){
  keyStream.Seek(0, SeekOrigin.Begin);
 }

 //Get the next pixel-count from the key, use "1" if it's 0
 currentKeyByte = (byte)keyStream.ReadByte();
 currentStepWidth = (currentKeyByte==0) ? (byte)1 : currentKeyByte;

 //jump to reverse-read position and read from the end of the stream
 keyPosition = keyStream.Position;
 keyStream.Seek(keyPosition, SeekOrigin.End);
 currentReverseKeyByte = (byte)keyStream.ReadByte();
 //jump back to normal read position
 keyStream.Seek(keyPosition, SeekOrigin.Begin);

 //Perform line breaks, if current step is wider than the image
 while(currentStepWidth > bitmapWidth){
  currentStepWidth -= bitmapWidth;
  pixelPosition.Y++;
 }

 //Move X-position
 if((bitmapWidth - pixelPosition.X) < currentStepWidth){
  pixelPosition.X = currentStepWidth - (bitmapWidth - pixelPosition.X); 
  pixelPosition.Y++;
 }else{

  pixelPosition.X += currentStepWidth;
 }

Now, get the pixel and put the message-byte into one color component (or all components, if the grayscale flag is set):

C#
 //Get color of the "clean" pixel
 pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y);

 //To add a bit of confusion, xor the byte with 
 //a byte read from the keyStream
 int currentByte = messageStream.ReadByte() ^ currentReverseKeyByte;

 if(useGrayscale){
  pixelColor = Color.FromArgb(currentByte, currentByte, currentByte);
 }else{
  //Change one component of the color to the message-byte
  SetColorComponent(ref pixelColor, currentColorComponent, currentByte);
  //Rotate color components
  currentColorComponent = 
   (currentColorComponent==2) ? 0 : (currentColorComponent+1);
 }
} //end of for - proceed to next byte

If the method runs in extraction mode, it reads the message's length and the color components instead of setting it. Here is how to get the length from the first pixel:

C#
pixelColor = bitmap.GetPixel(0,0);
//UnTrimColorString fill the String with '0'-chars 
//to match the specified length
String colorString = UnTrimColorString(pixelColor.R.ToString("x"), 2)
 + UnTrimColorString(pixelColor.G.ToString("x"), 2)
 + UnTrimColorString(pixelColor.B.ToString("x"), 2);

 messageLength = Int32.Parse(colorString, NumberStyles.HexNumber);
 messageStream = new MemoryStream(messageLength);

The pixel coordinates are calculated the same way as described above. Then the hidden byte is extracted from the color value:

C#
 //Get color of the modified pixel
 pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y);
 //Extract the hidden message-byte from the color
 byte foundByte = (byte)(currentReverseKeyByte ^ 
   GetColorComponent(pixelColor, currentColorComponent));
 messageStream.WriteByte(foundByte);
 //Rotate color components
 currentColorComponent = 
   (currentColorComponent==2) ? 0 : (currentColorComponent+1);
} //end of for - proceed to next byte

License

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


Written By
Software Developer
Germany Germany
Corinna lives in Hanover/Germany and works as a C# developer.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 135541592-Dec-17 23:01
Member 135541592-Dec-17 23:01 
GeneralMy vote of 1 Pin
Member 135541592-Dec-17 22:57
Member 135541592-Dec-17 22:57 
QuestionShifting bytes filelenght Pin
Member 1241206221-May-16 5:29
Member 1241206221-May-16 5:29 
Questionthanks Pin
nurman denai26-Apr-15 5:42
nurman denai26-Apr-15 5:42 
QuestionNeed steganography code using 4-bit lsb Pin
Member 1066199711-Apr-14 6:10
Member 1066199711-Apr-14 6:10 
QuestionAlgorithm used Pin
Eslam1312-Jan-13 21:34
Eslam1312-Jan-13 21:34 
Questionsteganography _hiding message in audio .wave Pin
hadeel altamimi9-Dec-12 3:10
hadeel altamimi9-Dec-12 3:10 
QuestionSteganography - Hiding messages in the Noise of a Picture Pin
shaker19-Oct-12 11:12
shaker19-Oct-12 11:12 
Questionimage steganography Pin
Member 915518927-Jun-12 20:31
Member 915518927-Jun-12 20:31 
AnswerRe: image steganography Pin
Matiwade sunita vasant15-Aug-12 19:37
Matiwade sunita vasant15-Aug-12 19:37 
QuestionSpread Spectrum Algorithm Pin
Igi Shellshock26-Jun-12 18:07
Igi Shellshock26-Jun-12 18:07 
QuestionNeed which algorithm using for this artical- Steganography -Hiding messages in the Noise of a Picture Pin
senthilvenkat8423-Jan-12 22:42
senthilvenkat8423-Jan-12 22:42 
AnswerNice work Pin
Dan Randolph5-Sep-11 17:28
Dan Randolph5-Sep-11 17:28 
GeneralMy vote of 5 Pin
Dan Randolph5-Sep-11 17:08
Dan Randolph5-Sep-11 17:08 
Code was easy to adapt to practical use.
Questionalgorithms used in steganography II with multiple keys and carrier files Pin
sudheer755018-Jul-11 3:29
sudheer755018-Jul-11 3:29 
AnswerRe: algorithms used in steganography II with multiple keys and carrier files Pin
Corinna John18-Jul-11 5:30
Corinna John18-Jul-11 5:30 
GeneralRe: algorithms used in steganography II with multiple keys and carrier files Pin
sudheer755018-Jul-11 7:14
sudheer755018-Jul-11 7:14 
QuestionOut image Pin
174t26-Jun-11 2:11
174t26-Jun-11 2:11 
Generalalgorithm Pin
ichaiye16-Apr-11 23:53
ichaiye16-Apr-11 23:53 
GeneralRe: algorithm Pin
Corinna John17-Apr-11 22:34
Corinna John17-Apr-11 22:34 
GeneralRe: algorithm Pin
ichaiye28-Apr-11 5:08
ichaiye28-Apr-11 5:08 
GeneralRe: algorithm Pin
174t26-Jun-11 2:20
174t26-Jun-11 2:20 
Generalavi steganographic algo Pin
Nidheeshkumar13-Feb-11 0:41
Nidheeshkumar13-Feb-11 0:41 
Generalquery Pin
Member 766806212-Feb-11 7:49
Member 766806212-Feb-11 7:49 
Generalstegnography code Pin
vaibhavsalunke5-Feb-11 22:44
vaibhavsalunke5-Feb-11 22:44 

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.