Skip to main content
3 of 5
added 746 characters in body
Daniel T
  • 1.4k
  • 15
  • 22
  1. What is the hidden quote? The quote is "Three may keep a secret, if two of them are dead."
  2. 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 width in pixels
  • Next 16 bits: image height in pixels
  • Raw pixels of the binary image

Hint: Create and fill an image array of the derived width and height with 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.

Task 2 image