In the context of images, steganography is the hiding of an image (or other information) within another image. The “carrier image” can then be sent over an untrusted channel (e.g., published on the Internet), and only people that know that the hidden message is there will be able to extract it. Needless to say that the trivial example that follows can easily be detected by someone familiar with steganography. In “real” steganography, more complicated methods are used. But I wanted to keep things simple. Steganography can also be applied to other things such as audio and video, and the term is also used for non-digital techniques such as using invisible ink on paper. But I’ll only talk about digital images in this article.
The Final Image
Figure 1 shows an image from my collection of photos that is still available on this site, even though I’ve shifted my focus to blogging about technical and scientific topics years ago. The original picture was taken at the waterfalls in the Krka National Park in Croatia, and can be found here.
In Figure 1, a complete (black-and-white) image is hidden in the so-called least significant bit of the blue channel. As you know, a digital color image actually contains three monochrome images, namely a red, a green, and a blue one. Typically, each pixel in each of these three monochrome images consists of a single byte, which is a number in the range of 0–255. A value of zero represents black, a value of 255 represents maximum brightness. The following table lists some examples.
In the binary numbers, the least significant bit is the one on the right, representing \(2^0\). The bits further to the right represent \(2^1\), \(2^2\), etc. This is completely equivalent to the decimal numbers that you might be more familiar with. Because changing the least significant bit only changes the value of a byte by one, the effect is typically not at all visible in an image.
The Hidden Image
What I did in the image of Figure 1 is replace the least significant bit in each pixel with the corrsponding pixel of a black-and-white image (using zero for a black pixel and one for a white one). This black-and-white image is shown in Figure 2, and it turns out to be a QR code. Note that you could add two additional images by simply doing the same for the red and green channels. In practice, you can even replace the two least significant bits without much visual difference.
If you feel like it, why don’t you download the image from Figure 1 and try to extract the hidden image yourself? If you do that, you’ll notice that the hidden image in Figure 1 is not exactly the QR code that is shown in Figure 2, but a slight variation of if that you can easily describe in words to convince me that you’ve managed to extract it…