Steganography is a form of cryptography where a hidden message is concealed inside another message. For images, this process works by encrypting the most significant bits of a hidden image into the least significant bits of a main image, and then displaying the hidden image bits to reveal the image. The beauty of the steganography is that the hidden bits fly under the human vision radar, yet the information is readily available for the computer to decrypt it.
- Encrypt a hidden image into another image
- Decrypt and reveal hidden image
- Beautiful terminal interface with colors!
- Automatically scale images to fit correctly
- Bit manipulations on image buffer 😋
I wrote this program in Rust and gained experience with using the image
crate from this amazing tutorial by freeCodeCamp (link).
I want to feature 2 pieces of code, because they were the most rewarding and challenging things to get right.
1. Bit Manipulation
This was super fun for me to figure out and I learned how to use the bitwise operators AND &
, OR |
, and << BITSHIFT >>
.
// src/main.rs, line 134
encrypted.push(
(main_pixel[i] & 0b_1111_1000) + // Replace last 3 bits of main pixel
((hidden_pixel[i] & 0b_1110_0000) >> 5) // with first 3 bits of hidden pixel
);
2. Traversing Through Image Buffer
Images are stored in buffers (1d arrays), so I had to figure out how to traverse the buffer while keeping track of the 2d location of the pixels. After a lot of mindless debugging, I realized that image_height * image_width * 4 == buffer_length
and having reached enlightenment, I blissfully wrote the code below in a state of nirvana.
// src/main.rs, lines 97-107
for h in 0..main_height {
for w in 0..main_width {
// Convert 2d pixel location (w, h) to 1d index in image buffer
i = (h * main_width + w) * 4;
if h < hidden_height && w < hidden_width {
encrypted.splice(i..=i + 3, encrypt_bits(&main_vec, i, &hidden_vec, (h * hidden_width + w) * 4));
} else {
encrypted.splice(i..=i + 3, encode_transparent_pixel(&main_vec, i));
}
}
}
My steganographer passes my tests with flying colors on .png
files and fails on .jpg
(I suspect that jpeg does some compression which conflicts with my bit manipulations).
Credit to pngimg.com for Mario and Stack Overflow post for Linux Penguin.
Main - Mario | Hidden - Penguin |
---|---|
Encrypted (Penguin Hidden in Mario) | Decrypted (Penguin Revealed 🥳) |
---|---|
Credit to Wikipedia for Paysage by Camille Pissarro and Mona Lisa
Main - Paysage | Hidden - Mona Lisa |
---|---|
Encrypted (Mona Lisa Hidden in Paysage) | Decrypted (Mona Lisa Revealed 🎉) |
---|---|