- What is the hidden quote? The quote is "Three may keep a secret, if two of them are dead."
- Which object is on the line? (Note, there are two possible correct answers here.) A kite is on the line. Alternatively, a key is on the line.
I implemented the LSB-first image–bits decoder first. I wasted 15 minutes debugging why I got gibberish only to find I had to swap width/height.
# mylib.py
from PIL import Image
def SteganographyBitstream(path: str):
with open(path, "rb") as f:
image = Image.open(f)
data = image.load()
for y in range(image.height):
for x in range(image.width):
r, g, b = data[x,y]
yield r & 1
yield g & 1
yield b & 1
def read_byte(bitstream):
result: int = 0
for _ in range(8):
result = (result << 1) | next(bitstream)
return result
Then task 1 was a simple bits–MSB-ASCII converter:
#!/usr/bin/env python3
# task1.py
from mylib import SteganographyBitstream, read_byte
def challenge_bytestream(bitstream):
assert next(bitstream) == 0
assert next(bitstream) == 0
length: int = (read_byte(bitstream) << 8) | read_byte(bitstream)
for _ in range(length // 8):
yield read_byte(bitstream)
print(bytes(challenge_bytestream(SteganographyBitstream("MBlXyTSp.png"))).decode("ascii"))
Task 2 was a similar conversion as described. Knowing the Netpbm format exists allowed me to skip a "map 0 -> 0 and 1 -> 255" step and print the image directly. I tried using Unicode without Netpbm, but my terminal wouldn't let me zoom out far enough, so I used Netpbm and GIMP.
#!/usr/bin/env python3
# task2.py
from mylib import SteganographyBitstream, read_byte
def print_pbm(bitstream):
assert next(bitstream) == 1
assert next(bitstream) == 0
width: int = (read_byte(bitstream) << 8) | read_byte(bitstream)
height: int = (read_byte(bitstream) << 8) | read_byte(bitstream)
print("P1")
print(width, height)
for _ in range(height):
for _ in range(width):
print(next(bitstream), end="")
print()
print_pbm(SteganographyBitstream("mCeETXDs.png"))
To run those files after saving them:
python3 -m venv venv
. venv/bin/activate
pip install pillow
wget https://i.sstatic.net/MBlXyTSp.png
python3 ./task1.py
wget https://i.sstatic.net/mCeETXDs.png
python3 ./task2.py > ./part2.pbm
gimp ./task2.pbm
Task 1 output:
The first part of the sentence is "Three may keep a secret, ...".
Task 2: Decode a binary image
A binary image is hidden in the least significant bits of the butterfly image, the encoding scheme is:
- Simple LSB Encoding**
- Header:
[1, 0]- Next 16 bits: image
widthin pixels- Next 16 bits: image
heightin pixels- Raw pixels of the binary image
Hint: Create and fill an image array of the derived
widthandheightwith the encoded hidden pixels. In order to view your image in classic viewers, it might be helpful to map 0 -> 0 and 1 -> 255. Derive the second part of the sentence and answer the question about the image.