Image Steganography

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.

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)
        new_line.append(p)

    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
        new_line.append(p)

    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():
    try:
        if sys.argv[1] == "encode":
            try:
                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":
            try:
                reveal_image(sys.argv[2])
            except IndexError:
                print "Please supply a PNG with a hidden image."
        else:
            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__":
    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?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s