This is an old revision of the document!
Steganography is the practice of hiding information within another medium (which is, usually, communicated in plain sight). If in encryption the difficulty lies in finding the secret (i.e.: the key) used to obfuscate the data, here the problem consists of detecting whether the data exists at all (the plausible deniability concept).
One stegano technique that is easy to understand consists of encoding messages into pixel data. As we all know, images are made out of pixels, and pixels are made out of three color channels: Red, Green, Blue. Usually, each channel is represented via an 8-bit value (0 - 255, or 0xFF
). The higher the value, the more intense the color. Thus, it follows that altering the more significant bits of any channel will produce visible alterations: in the image below, we masked (i.e.: set to 0) the most significant bit of every channel, of every pixel.
But what happens if we play around with some of the less significant bits? Answer: no human will be able to tell the difference! As a result, one way to exfiltrate data is by splitting the message into bits and encoding them into the least significant bits of the image. If only the least significant bit is used, you will need 3px in order to encode 1 byte of data (with 1 bit to spare, or it could also be considered the next byte of our secret). For example:
# Note: using PIL representation, where each pixel is a (R, G, B) tuple pixels = [(0xff, 0x00, 0x04), (0xff, 0x19, 0x1d), (0xff, 0x34, 0x37)] bin_message = [0, 1, 0, 0, 1, 0, 0, 0, 1] # ASCII for 'H' (+ the '1' extra bit for the next byte) # after the (color & 0xFE | msg_bit) bitwise operation for each pixel / channel: enc_pixels = [(0xfe, 0x01, 0x04), (0xfe, 0x19, 0x1c), (0xfe, 0x34, 0x37)]
The goal of this assignment is to write a simple Flask-based web application that helps you encode / decode a secret message into an existing image (uploaded by the user) using the steganography method described above. Furthermore, we also want the server containerized using Docker (together with its dependencies) such that, regardless of the machine, it can be easily started with minimal effort (especially for evaluation purposes!).
bmp
, png
)!
In contrast, lossy image formats (e.g., jpeg
) may randomly alter the color data of the pixels, so the information concealed there will get corrupted. We will only consider the former case (no lossess)!
You must implement either a Python CLI – command-line interface (for a max. score of 40%) – or a web-based page, or both (for an easy bonus!). Whatever you choose, you must respect the specifications written at each of the sub-sections below:
This will decouple the tasks (encoding / decoding vs web frontend), allowing you to partly validate the solution before continuing.
Bonus for using unit testing ;) , although this is out of scope.
The CLI script (if present) must be named cli.py
and use the following syntax:
./cli.py [encode|decode] [-m MESSAGE] INPUT_IMAGE [OUTPUT_IMAGE] Encodes or decodes the .
The web server must repond to the following URLs implementing the requested functionality:
/image/encode
: receives a multipart/form-data
with the following arguments:asdasd
pip3
(see our previous lab for info regarding pip
and virtual environments).The base assignment constitutes 4p out of your final grade (100p homework = 5p final grade). The 100p are split between the following tasks:
argparse
) + Web frontend using a modular approach (shared encoding / decoding code!);
NOTE: Assistants are free do deduct points for bad / illegible code.
This archive contains a PNG image with 5 secrets hidden at certain bit levels and at different channels.
Q: Can I write the tool in something other than Python?
A: No.
Q: What platform will this assignment be tested on?
A: Linux (though, you don't need to use any platform-specific APIs).