lowmanio.co.uk title image

Image Steganography

Sun, 01 Nov 2009 01:33PM

Category: Digital Forensics & Malware

Written by Sarah | With 1 comment

Steganography is the art of hiding something in something else in plain sight. Usually images or text are hidden within other images or sound files. For example, in the image below of trees there is an image of a cat hidden inside it. Wikipedia explains that for each component of each RGB value, if you take just the last 2 bits of it and then turn the brightness up 85%, you get a picture of the cat. The whole point is so the image of the trees looks identical to an image of the trees without an image hidden inside to the human eye.

original image hidden image

I decided to try and see if I could get the image of the cat out of the trees using Python. I used the library pyPNG and help from Steven. Download the full script here.

import sys
import png

def decode(line):
    """ Takes in a line of RGB values. Each value is replaced by the last
    two bits of the value multiplied by 85 """

    new_line = []
    for p in line:
        p = p & 3       # 3 is 00000011 in binary
        p = 85 * p      # scale p to be between 0 and 255 (255/3 = 85)

    return new_line

def encode(line, hideLine):
    """ Takes in the same line of RGB values from the file to hide in (A) and
    the file to be hidden (B). Each value of B is turned into a number between
    0 and 3 and then ORed with the first 6 bits of A. """
    new_line = []
    for p, q in zip(line, hideLine):
        x = int(round(q / 85))
        p = (p & 252) | x

    return new_line

def hide_image(file, hiddenfile):
    """ Hides 'hiddenfile' within 'file' """
    im = png.Reader(filename=file)
    width, height, pixels, meta = im.read()

    imHide = png.Reader(filename=hiddenfile)
    widthHide, heightHide, pixelsHide, metaHide = imHide.read()
    out_file = open('hidden.png', 'wb')
    # transform
    new_pixels = [encode(line, hideLine) \
    for line, hideLine in zip(pixels, pixelsHide)]
    # output image
    writer = png.Writer(width=width, height=height, **meta)
    writer.write(out_file, new_pixels)    

def reveal_image(file):
    """ Reveals an image hidden within 'file' """
    # input image
    im = png.Reader(filename=file)
    width, height, pixels, meta = im.read()
    out_file = open('recovered.png', 'wb')
    # transform
    new_pixels = [decode(line) for line in pixels]
    # output image
    writer = png.Writer(width=width, height=height, **meta)
    writer.write(out_file, new_pixels)

def main():
        if sys.argv[1] == "encode":
                hide_image(sys.argv[2], sys.argv[3])
            except IndexError:
                print "Please supply two PNG files. The first is \
                the file the image will be hidden in, the second \
                is the image to hide."
        elif sys.argv[1] == "decode":
            except IndexError:
                print "Please supply a PNG with a hidden image."
            print "invalid argument. Please use 'encode' or 'decode'"
    except IndexError:
        print "Please type 'encode' or 'decode' after the python \
        file followed by two PNG files for encode, and one for decode."
if __name__ == "__main__":

To reveal an image, just type:

python steg.py decode file-with-hidden-image.png

To hide an image, type:

python steg.py encode file-to-hide-data-in.png file-to-be-hidden.png

Decoding will output an image called recovered.png and encoding will output an image called hidden.png. To encode, you'll need to use two PNGs of exactly the same height and width, and it only works really well if the image to be hidden has a low resolution with high contrasting colours. Black text on white/transparent works perfectly.

Can you decode the message I've hidden in the image below?

image of a fractal

Tagged with: Python, steganography, PNG


Steganography! Have you seen the whitespace steganography program in the International Obfuscated C Contest? The source for the encoder is steganographed into the source of the decoder, so you have to compile the decoder and run it on its own source to get the encoder! Cool or what?
Andrew Bell
Tue, 10 Nov 2009 06:57PM

Add a comment