Introduction
This article describes how any data can be hidden in the noise pixels of an image.
Background
There is only one save 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.
How it works
To see how the application works, you should view the source.
Here is a summary about hiding:
And about extracting:
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.
messageLength = (Int32)messageStream.Length; //do some length conflict checking here //... //Write length of the message into the first pixel int colorValue = messageLength; int red = colorValue >> 2; colorValue -= red << 2; int green = colorValue >> 1; int blue = colorValue - (green << 1); pixelColor = Color.FromArgb(red, green, blue); bitmap.SetPixel(0,0, pixelColor);
Then it reads a byte from the key stream to calculate the position of the next pixel to use:
//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 currentStepWidth = keyStream.ReadByte() + 1; //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):
//Get color of the "clean" pixel pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y); //To add a bit of confusion, xor the byte with the current pixel distance int currentByte = messageStream.ReadByte() ^ currentKeyByte; 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:
pixelColor = bitmap.GetPixel(0,0); messageLength = (pixelColor.R << 2) + (pixelColor.G << 1) + pixelColor.B; 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:
//Get color of the modified pixel pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y); //Extract the hidden message-byte from the color byte foundByte = (byte)(currentKeyByte ^ GetColorComponent(pixelColor, currentColorComponent)); messageStream.WriteByte(foundByte); //Rotate color components currentColorComponent = (currentColorComponent==2) ? 0 : (currentColorComponent+1); } //end of for - proceed to next byte