Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

COMP 3621 (Winter 20204)

Advanced Data Structures

Lab 3  Bitmap Steganography

You are going to produce a modified version of BitmapHacker named BitmapHacker2.  Sub- mit both Pixel. java and BitmapHacker2. java to Moodle (you can also update Pixel. java if there were things you needed to fix in your earlier version).  Note that you do not need to include a main method in the code you submit (but, of course, you should perform your own extensive testing).

Overview

Your challenge is to enhance BitmapHacker. java to perform steganography, which is the art and science of hiding information, often inside other information. This differs from cryptog- raphy, which involves transforming information in order to protect it from adversaries, but not necessarily concealing the presence of the information.

In particular, your goal is to hide information inside Bitmap files (uncompressed, 24-bit-color Bitmap files), and also to extract such hidden information.  For most BMP images, it is pos- sible to hide 6 bits inside each pixel without altering the image in a way that is noticeable to the human eye.  This is done by replacing the least significant 2 bits of each color component of some of the pixels with 2 bits of hidden information.  Because these are the low-end bits, modifying them rarely alters the appearance of the image perceptibly.  (Note that we’re only playing around with pixel data; we don’t touch the header portion of a BMP file, in order to avoid corrupting the file.)

To be precise, suppose you want to hide a file of length B bytes inside a BMP file. Form an int array of length B + 4, each position of which will store a single byte as a value in the range 0 ... 255.  Use the first 4 positions to encode the value B as a 4-byte (32-bit) integer in the little-endian format.  Then fill the remaining positions in the array with the bytes of the file in order (so the first byte of the file goes in the 5-th position in the array, i.e., in the position with index 4).  This array of data can be hidden inside a BMP file as long as the number of bits it contains is less than or equal to the  hiding room” of the BMP file, which is 6 bits per pixel.

(As you may have guessed, the reason for including the length of the to-be-hidden file in the hidden data is that this makes it possible for an extraction procedure to determine how many bytes to extract.)

To be even more precise, suppose the bytes in the array are x0 , x1 , x2 , . . ..

. The 2 most significant bits of x0 will replace the 2 least significant bits of the red component of the pixel in row 0, column 0.  (To  be  even  more precise, the most significant bit of x0 will replace the second least significant bit of the red component of this top-left pixel.)

. The 3-rd and 4-th most significant bits of x0  will replace the 2 least significant bits of the green component of the pixel in row 0, column 0.

. The 5-th and 6-th most significant bits of x0  will replace the 2 least significant bits of the blue component of the pixel in row 0, column 0.

. The two least significant bits of x0  will replace the 2 least significant bits of the red component of the pixel in row 0, column 1.

.  ... and so on . . .

Additions to the BitmapHacker Class

(The two methods described below potentially throw IOExceptions.  As before, you are not required to use try/catch to handle these; instead, each method signature can just specify that it throws IOException.)

. hide  This method has a single parameter of type File, and returns a boolean.  If the argument is null, construct and throw an IllegalArgumentException containing an appropriate message.   If the  argument is not null, but does not specify a disk file, construct and throw an IllegalArgumentException containing an appropriate message.  Otherwise, attempt to hide the specified file in the current 2-D pixel array. If the data to be hidden (the 4  “size bytes” plus the specified file) is too large for the pixel array, return false. Otherwise, hide the data and return true.

. unhide This method has asingle parameter of type File, and returns a boolean. If the argument is null, construct and throw an IllegalArgumentException containing an appropriate message. Otherwise, attempt to extract a hidden file from the current 2-D pixel array.  If the number of pixels is too small even to allow the hiding of the 4-byte “size bytes”, return false.  If there is enough room for the size bytes, but, when extracted, the indicated file size is larger than the amount of remaining “hiding room” in the pixel array, return false.  Otherwise, extract the file and write it to disk at the location specified by the File argument.

Sample Files

You have been given three BMP files, each containing a hidden file:

. baby-owl-mod. bmp  contains a hidden PDF file

.  cat-mod. bmp  contains a hidden PDF file

.  dragon-mod. bmp  contains a hidden JPEG file

Fine Points

. Note that hiding in / unhiding from a BMP file does not involve the possible zero padding bytes that you needed to consider in Phase  1.   When  hide  is  called,  the BitmapHacker constructor has already extracted the pixel data from a BMP file and placed it in the 2-D pixels array, so simply hide the file to be hidden in the color com- ponents of the pixels in pixels, as specified. There is no change to writeImageToFile; it creates an output BMP file based on the pixel data in pixels, whether or not any- thing has been hidden.

Similarly, when unhide is called, the BitmapHacker constructor has already placed pixel data from a BMP file into the pixels array, so just attempt to extract a hidden file from this pixel data.

.  Claim:   The size of any file that is correctly hidden inside a BMP file can never be

too large to fit in an int.  The reason is that a BMP file has maximum size 232  − 1 bytes (see the end of the Phase 1 handout), which means that the maximum number of pixels is approximately 1.4 billion ((232  − 1)/3).  Since only 3/4 of a byte can be hidden in each pixel, clearly the total number of bytes that can be hidden is less than 1.4 billion, so this number will fit safely in an int.

However, what if unhide is applied to a BMP file in which nothing has been hidden? In this case, the  size” information that is extracted could be any 32-bit value.  If your unhide method extracts the size value into an int, how will your code behave if this value overflows an int (leaving you with a negative number)?