Question: In this assignment, we will write code that hides secret messages (strings) in binary files. This is a technique known as steganography, which means hiding
In this assignment, we will write code that hides secret messages (strings) in binary files. This is a technique known as "steganography," which means hiding messages in "plain sight." Anyone eavesdropping thinks you are just sharing an audio file, but there is actually a secret message hidden inside.
A .wav file begins with a header (usually 44 or 46 bytes). The header contains information about the data and includes things like the number of audio channels and how to interpret the data in the file. We will put information about our message into the file after the header. By hiding our message after the header, we will still be able to play the file; the only hint that our message is hidden there is that there will be some clicking noises added. Our message will be small compared to the size of the data so our secret will go (mostly) unnoticed. To make sure we do not corrupt the header, we will skip the first 50 bytes.
After skipping 50 bytes, we will write an int that contains the length of the message. Next, we will write one character of the message, then a long that indicates where to find the next character. At that location of the file, we will write the next character and a long that indicates where to find the next character. We will repeat this until the end of the message. The long after the last number should be 0.
You will be writing 4 classes: two new exceptions classes, a class named Steganography with static methods for encoding and decoding secret messages, and a driver containing a main method. Here is a description of these classes:
SecretMessageException
This exception will be thrown when there is an error encoding or decoding the message. You should throw this exception when either the input file does not exist or an IOException occurs. In the case of the decode method, you should also throw this exception if there is no secret message in the file. (The most likely indicator of this will be trying to invoke the seek method with a negative number. In this case, the seek method will throw an IOException.)
NotEnoughSpaceException
This exception will be thrown when there are more characters in the message than available bytes in the file. The message should indicate how much space was needed and how much is available. You will need enough bytes so you can have a minimum of one byte between each character/position combination of the secret message.
Steganography
This class will contain 3 static methods:
public static String decodeMessage(File inputFile) throws SecretMessageException
This method will read an input file and return the secret message hidden inside. If this method fails for any reason, you should throw a SecretMessageException. You will need to use a try/catch block in this method to catch any exceptions and then in your catch block(s) rethrow any exception as a SecretMessageException with an appropriate message.
You will need to use the RandomAccessFile class and its seek(), readChar(), readInt(), and readLong() methods. Hint: the String class has a constructor that takes an array of chars.
To test this method, see if you can read the secret message in the file SecretMessage.wav. You should also be able to play the file with an audio player. It should not be obvious that a secret message is hidden in the file.
public static void encodeMessage(File inputFile, File outputFile, String message) throws NotEnoughSpaceException, SecretMessageException
This method should do the following:
Make a copy of inputFile, and save it in outputFile. You can use the static
copy() method in the Files class. File objects have a toPath() method that you will need to use. Use the copy option StandardCopyOption.REPLACE_EXISTING. This option will overwrite the output file if it exists.
Compute where to put the data in the file using the getDataLocations method described below. Remember, the first 50 bytes should not be altered. Immediately after that, we will write the size of the message as an integer.
Write the secret message in the file in character/next position combinations. Again, this will involve the RandomAccessFile class and its seek(), writeLong(), and writeChar() methods.
Note that the encode method potentially throws two exceptions. The SecretMessageException is described above. The NotEnoughSpaceException is described below.
private static long[] getDataLocations(long start, long stop, int numLocations) throws NotEnoughSpaceException
This method returns an array that indicates where each character in the message should be stored. For each character, you will need enough space to store the character itself, and a long indicating where the next character is. The parameters start and stop indicate the first and last bytes that can be used. If there's not enough room to store all the bytes, this method should throw a NotEnoughSpaceException.
You can use whatever approach you would like for this method as long as each character/position pair of the secret message is separated by data from the original .wav file.
A simple solution is to place all the locations as far apart as possible (find the maximum distance you can fit between each one and place them equidistantly far apart). Choosing locations randomly is another approach, but requires some care so that the locations do not overlap. Do not bunch all the data together. When we play the file, it will be obvious that we are hiding a secret message.
SteganographyDriver
The driver should ask the user to enter a message and then write the secret message to a file. It should then read the secret message back from the file and verify that it matches the original message. Make sure that you create a NEW file to hide the message in. Do not overwrite the original .wav file. The original version of the .wav
file from above is named NoSecretMessage.wav and is included with this assignment.
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
