Introduction
In this tip/trick, I'll try to explain an easy method to hide data (images in this case) in an image file. This file may be opened with any image viewer, and all you'll see is the image that covers the hidden data. Later, you may recover the hidden data using this method.
Motivation
Well, this tip is in fact an answer to a quick answers section question. But I thought this could be of any help to anyone else. :)
Hiding the Images
This process is very simple. What we are going to do is create a byte array and read all the images in it. But we must also store the number of images we are joining and the size of each image so we will be able to recover the information later:
foreach (string path in paths)
{
byte[] b = File.ReadAllBytes(path);
imageList.Add(b);
byte[] imgsize = BitConverter.GetBytes(b.Length);
byteArraySize += imgsize.Length;
byteArraySize += b.Length;
}
byteArraySize++;
byte[] concatenatedImage = new byte[byteArraySize];
int pos = 0;
foreach (byte[] b in imageList)
{
foreach (byte bi in b)
{
concatenatedImage[pos] = bi;
pos++;
}
}
foreach (byte[] b in imageList)
{
byte[] imgsize = BitConverter.GetBytes(b.Length);
foreach (byte bi in imgsize)
{
concatenatedImage[pos] = bi;
pos++;
}
}
concatenatedImage[pos] = Convert.ToByte(paths.Length);
So the output file will have:
- All the images, one after the other
- 4 bytes for each image, with the size of the file
- 1 byte with the number of images
When we open this output file with an image viewer, it will show us the first image we stored, leaving the others hidden.
Recovering the Hidden Data
This is very simple as well. We must read the previously created image and cut it into as many images as the last byte tells us, having each "piece" the size we also stored at the end of our file:
byte[] images = File.ReadAllBytes(path);
int numberOfImages = Convert.ToInt32(images[images.Length-1]);
Image[] decodedImages = new Image[numberOfImages];
int[] sizes = new int[numberOfImages];
int pos=images.Length-1;
pos = pos - (numberOfImages * 4);
for (int i = 0; i < numberOfImages; i++)
{
byte[] imgsize = new byte[4];
Array.Copy(images,pos,imgsize,0,4);
sizes[i] = BitConverter.ToInt32(imgsize, 0);
pos += 4;
}
pos = 0;
for (int i = 0; i < numberOfImages; i++)
{
byte[] image = new byte[sizes[i]];
Array.Copy(images, pos, image, 0, sizes[i]);
Image img;
using (var ms = new MemoryStream(image))
{
img = Image.FromStream(ms);
}
decodedImages[i] = img;
pos += sizes[i];
}
Points of Interest
When I first read the question, I thought of stenography, but this technique did not exactly meet the requirements. I really thought that creating a file with data attached which could be opened with a regular viewer was not possible, but lastly the thing was easier than expected.
Attached there is a sample project. If you have any suggestions, please comment.
BTW, this is my first submission, so please be kind :)
History
- 11/06/2014: First submission