SA-3

Steganography is a technique to hide the presence of information. In this case we will hide a message inside an image. The idea is that people looking at your image will not realize it contains a hidden message; it will appear to them as an ordinary image. The intended recipient knows there is a hidden message and recovers it.

You will encode a text message into an image by converting the message to binary 0 and 1 bits, then for each binary bit, you will subtly alter the red component of one pixel in the image. Starting at pixel (0,0), to encode a 1 bit, you'll make the red color component of the pixel an odd integer. To encode a 0 bit, you'll make the red color component of the pixel an even integer. To encode the next bit, move to the next pixel and adjust its color. By changing the red color component by 1 (at most, if the pixel is already appropriately odd or even to match the bit, leave the red color unchanged), and by leaving the green and blue components unchanged, it will be very difficult for an unintended recipient to notice the tiny color changes. The intended recipient will then recover the message from the image by examining the red pixel color values of each pixel.

Exercises

  1. Start with the scaffold code Steganography.java (note: if you haven't already downloaded them, you will need ImageIOLibrary.java and ImageGUI.java from class)
  2. Complete the public BufferedImage hideMessage(BufferedImage original, String message) method where original is a BufferedImage in which you will hide your message and message is the message to hide in the image. This method converts each character in the message to a binary String of seven ‘0’ or ‘1’ bits (see pseudocode below). For each bit, convert the red component of a pixel to an even value if the bit is 0, convert the red component to an odd value if the bit is 1. If the color already matches the even or odd requirement, make no change. In this way, each character will be spread across seven pixels, and will only alter the red portion of the image. Follow this pseudocode for hideMessage:
    Copy original image into a result image //so the original image is unaltered
    Add a ‘*’ character to the end of the message indicating to the recipient this is the end of the message
    Print an error message if there are not enough pixels in the image to store the entire message and return null
    Set integers x and y to 0
    Loop over each character c in the message 
       Convert c to binary using: String bits = Integer.toBinaryString(c); //should be 7 "0" or "1" bits
       //Java quirkiness: if bits length is 6, prepend with a "0" character (e.g., bits = "0" + bits)
       Loop over each bit character in bits String
          If bit == '0' and red component of the pixel at x,y is odd 
             Increment the red component by 1 to make it even (handle overflowing max color of 255)  
             Keep the existing green and blue components unchanged
          Else if bit == '1' and red component of the pixel at x,y is even
             Increment the red component by 1 to make it odd  
             Keep the existing green and blue components unchanged
          Increment x by 1
          If x goes beyond image width, begin at the start of the next row of pixels
    return result
    

    Some helpful Java methods:

    • % is modulo, useful to determine if a number is even or odd
    • s.length() returns the length of String s
    • Character c = s.charAt(i) fills c with the character in String s at index i.
  3. Complete the public String getMessage(BufferedImage img) method where img is a BufferedImage containing a hidden message. Follow this pseudocode:
    Set message = “”
    Set temp = ""
    Set integers x and y to 0
    Loop until encountering stop character ‘*’
       Read the red color component at image location (x, y)
       If the red color is even, add a '0' character to temp
       If the red color is odd, add a '1' character to temp
       Every seven pixels, convert String temp to a character with:
          Character lastCharacter = (char)Integer.parseInt(temp, 2);
          Add lastCharacter to message
          Reset temp to an empty String
       Move to the next pixel (stay on the image!)
    Return message

Submission Instructions

After completing the methods above: