Introduction:
Steganography is the practice of hiding information within other media, such as images, audio, or video files. In this blog post, we will explore a simple implementation of text steganography using C# and explain the algorithm behind it.
Overview:
The SteganographyHelper class provides methods to encode and decode text in images. It utilizes the System.Drawing namespace to work with images in C#. The algorithm used in this implementation hides the text by modifying the pixel colors in the image.
Algorithm:
- Given an integer value representing a character, such as 72 for the character ‘H’.
- Convert the integer value to binary representation. For example, 72 is represented as ‘01001000’ in binary.
- Extract the individual bytes from the binary value: byte3, byte2, byte1, and byte0.
- Convert the extracted bytes to decimal representation.
- Create a new Color object using the extracted bytes, resulting in a modified pixel color.
- Set the modified pixel color in the image at the corresponding location.
- Repeat steps 3-6 for each character in the text.
- Set the last pixel in the image to store the text length as the blue component of the color.
- Save the modified image to the output file.
Code Explanation:
Let’s take a look at the HideTextInImage
method and understand its logic:
private static void HideTextInImage(Bitmap image, string text)
{
int textLength = text.Length;
int charIndex = 0;
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
Color pixel = image.GetPixel(i, j);
if (charIndex < textLength)
{
char letter = text[charIndex];
int value = Convert.ToInt32(letter);
Color modifiedColor = ModifyPixelColor(value);
image.SetPixel(i, j, modifiedColor);
}
if (i == image.Width - 1 && j == image.Height - 1)
{
image.SetPixel(i, j, Color.FromArgb(pixel.R, pixel.G, textLength));
}
charIndex++;
}
}
}
Explanation:
- The
HideTextInImage
method takes an image and the text to be hidden as input and modifies the image to encode the text. - It starts by determining the length of the text.
- Two nested loops iterate over each pixel in the image, row by row.
- Inside the loops, it checks if there are more characters to be hidden (
charIndex < textLength
). - If there are characters remaining, it retrieves the next character from the text (
char letter = text[charIndex]
). - The character is converted to an integer value (
int value = Convert.ToInt32(letter)
). - The
ModifyPixelColor
method is called to obtain a modified pixel color based on the integer value. - The modified pixel color is then set in the image at the corresponding location (
image.SetPixel(i, j, modifiedColor)
). - Finally, when reaching the last pixel in the image, the blue component of the color is set to the text length to mark the end of the hidden text.
Now, let’s explore the ExtractTextFromImage
method:
private static string ExtractTextFromImage(Bitmap image)
{
string extractedText = "";
Color lastPixel = image.GetPixel(image.Width - 1, image.Height - 1);
int textLength = lastPixel.B;
int charIndex = 0;
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
if (charIndex < textLength)
{
Color pixel = image.GetPixel(i, j);
int value = pixel.B;
char c = Convert.ToChar(value);
extractedText += c;
}
charIndex++;
}
}
return extractedText;
}
Explanation:
- The
ExtractTextFromImage
method takes an image as input and returns the extracted hidden text. - It starts by initializing an empty string to store the extracted text.
- The last pixel of the image is retrieved to obtain the text length (
Color lastPixel = image.GetPixel(image.Width - 1, image.Height - 1)
). - The blue component of the last pixel represents the text length (
int textLength = lastPixel.B
). - Two nested loops iterate over each pixel in the image, row by row.
- Inside the loops, it checks if there are more characters to be extracted (
charIndex < textLength
). - If there are characters remaining, it retrieves the blue component of the current pixel (
int value = pixel.B
). - The integer value is converted to a character (
char c = Convert.ToChar(value)
). - The character is appended to the
extractedText
string. - Finally, the extracted text is returned.
Please note that these are just parts of the overall steganography implementation. The complete code includes methods for encoding text into images, decoding text from images, and other supporting functionalities. You can find the complete code below.
public static class SteganographyHelper
{
public static void EncodeText(string imagePath, string outputImagePath, string text)
{
if (string.IsNullOrEmpty(imagePath))
{
throw new ArgumentException("Image path cannot be null or empty.");
}
if (string.IsNullOrEmpty(text))
{
throw new ArgumentException("Text to be hidden cannot be null or empty.");
}
Bitmap image = new Bitmap(imagePath);
var textSize = text.Length * 8; // Assuming each character is represented by 16 bits
var textSizeInKB = textSize / 1024;
if (textSizeInKB > GetImageSizeInKB(image))
{
throw new Exception("Image cannot save text more than " + GetImageSizeInKB(image) + " KB");
}
HideTextInImage(image, text);
image.Save(outputImagePath, ImageFormat.Png);
}
public static string DecodeText(string imagePath)
{
if (string.IsNullOrEmpty(imagePath))
{
throw new ArgumentException("Image path cannot be null or empty.");
}
Bitmap image = new Bitmap(imagePath);
return ExtractTextFromImage(image);
}
private static void HideTextInImage(Bitmap image, string text)
{
int textLength = text.Length;
int charIndex = 0;
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
Color pixel = image.GetPixel(i, j);
if (charIndex < textLength)
{
char letter = text[charIndex];
int value = Convert.ToInt32(letter);
Color modifiedColor = ModifyPixelColor(value);
image.SetPixel(i, j, modifiedColor);
}
if (i == image.Width - 1 && j == image.Height - 1)
{
image.SetPixel(i, j, Color.FromArgb(pixel.R, pixel.G, textLength));
}
charIndex++;
}
}
}
private static Color ModifyPixelColor(int value)
{
// Extract the individual bytes from the integer value
byte byte3 = (byte)((value & 0xFF000000) >> 24);
byte byte2 = (byte)((value & 0x00FF0000) >> 16);
byte byte1 = (byte)((value & 0x0000FF00) >> 8);
byte byte0 = (byte)(value & 0x000000FF);
// Create a new Color object using the extracted bytes
return Color.FromArgb(byte3, byte2, byte1, byte0);
}
private static string ExtractTextFromImage(Bitmap image)
{
string extractedText = "";
Color lastPixel = image.GetPixel(image.Width - 1, image.Height - 1);
int textLength = lastPixel.B;
int charIndex = 0;
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
if (charIndex < textLength)
{
Color pixel = image.GetPixel(i, j);
int value = pixel.B;
char c = Convert.ToChar(value);
extractedText += c;
}
charIndex++;
}
}
return extractedText;
}
private static double GetImageSizeInKB(Bitmap image)
{
return (image.Width * image.Height * 16) / 1024.0; // Assuming each pixel stores 16 bits
}
}
class Program
{
static void Main()
{
string imagePath = @"C:\temp\input.jpg";
string outputImagePath = @"C:\temp\output.jpg";
string textToHide = "Hello World!";
SteganographyHelper.EncodeText(imagePath, outputImagePath, textToHide);
Console.WriteLine("Text encoded successfully.");
string extractedText = SteganographyHelper.DecodeText(outputImagePath);
Console.WriteLine("Extracted Text: " + extractedText);
}
}
In this blog post, we explored a simple implementation of text steganography using C#. We discussed the algorithms behind the encoding and decoding process and provided explanations for the ModifyPixelColor
, HideTextInImage
, and ExtractTextFromImage
methods. This implementation allows you to hide text within images, offering a way to store secret messages or communicate covertly.
Please note that this is a basic implementation for educational purposes. Real-world steganography techniques can be much more complex and employ advanced algorithms and encryption methods to ensure the hidden information’s security.