This project will use a technique called "steganography" to encode a text message. Steganography is basically hiding one set of data within another set of data. Some decent discussions of this technique can be found at http://www.garykessler.net/library/steganography.html or http://en.wikipedia.org/wiki/Steganography
For this project we want to take an ascii text message and hide it into the a sound file. We will also want to be able to extract the message. For this we will need to write two program: Proj4a.java and Proj4b.java. Where Proj4a.java will place the message into a sound file and Proj4b.java will extract the message from the sound file.
Recall that a text message is a collection (i.e. encoding) of multiple ascii characters and each each ascii character can be represented as a numeric value and (finally) each numeric value can be represented in a series of decimal digits (values from zero thruogh nine). Thus the text message of "Welcome!" is made up of the ascii characters:
char ch; int asciiValue; asciiValue = (int) ch;
Initially we will want all of the samples in the sound object to be "smoothed" out. This will result in every sample having the one's digit of its amplitude value set to zero. The way to do this is to determine the one's digit of the sample and subtract this value from the sample's amplitude value.
digit = ampValue % 10; modAmpValue = ampValue - digit;
Note that changes of a amplitude value should have no impact to the sound quality on the human ear. Actually it is changes of values around 10 that begin to be detected by the human ear. The average change of this smoothing will be of a value of 5.
Once a sound file has been "smoothed", we will encode one decimal digit from the text message into each sound sample. Since each ASCII character is considered to have 3 decimal digits, we will need 3 sample amplitude values for each ASCII character. Thus to encode a text message of 100 characters, we would need 300 sample amplitude values. At this rate, a one second sound sample can encode 7350 characters.
To encode a decimal digit into a sound sample, we simply add the decimal digit (a value from zero to nine) to the "smoothed" amplitude value of the sound sample when the original amplitude value is positive, and subtract the decimal digit from the "smoothed" amplitude value of the sound sample when the original amplitude value is negative. There are two special cases that we will need to consider. These cases are when the encoded amplitude values fall outside of the normal range of -32768 to +32767.
The following table is to help us with this. It shows the first 24 samples from the file gettysburg10.wav. Note the sample values are relatively small numbers as this is only the first 1000th of the sound and nothing has been stated yet.
Sample
IndexOriginal
Amplitude
Value"Smoothed"
Amplitude
ValueASCII
CharactersDecimal
ValuesDecimal
DigitsDecimal
Digit
PositionModification
OperationFinal
Sample
Values0 59 50 W 87 7 0 + 57 1 39 30 8 1 + 38 2 16 10 0 2 + 10 3 10 10 e 101 1 0 + 11 4 -1 0* 0 1 - 0 5 7 0 1 2 + 1 6 -12 -10 l 108 8 0 - -18 7 -7 0* 0 1 - 0 8 10 10 1 2 + 11 9 25 20 c 99 9 0 + 29 10 61 60 9 1 + 69 11 57 50 0 2 + 50 12 46 40 o 111 1 0 + 41 13 41 40 1 1 + 41 14 43 40 1 2 + 41 15 73 70 m 109 9 0 + 79 16 76 70 0 1 + 70 17 60 60 1 2 + 61 18 46 40 e 101 1 0 + 41 19 39 30 0 1 + 30 20 31 30 1 2 + 31 21 26 20 ! 33 3 0 + 23 22 35 30 3 1 + 33 23 37 30 0 2 + 30
To determine which decimal digit of which character is associated with which sample from the sound object, use the following where sampleIndex is the index of the SoundSample from the sound object:
One we know the Character Number, we can get the character from the string by using the charAt() method of the String class. This method will give use the character at that position. To get that ASCII Character code number for the character simply store the character into a variable of type integer.
To get the Decimal Digit value (zero through nine) for a particular Decimal Digit Position from the ASCII character code number, we should write a method with the following method description:
public static int getDecimalDigit (int asciiCode, int DecimalDigitPosition) { // This method should divide the asciiCode by 10 as many times // as specified by the DecimalDigitPosition, // Then use the modulus operator % to find the remainder // of a division by 10. // This remainder value is the Decimal Digit that we want returned // by the method. }
According to the mathematics, there are only two encoded amplitude values above +32,767 that could exist:
Similarily, thers is only one possible encoded amplitude value:
For example, assume we needed to get the character y. The 3 Decimal Digits and the coorsponding Decimal Digit Positions would be:
ASCII
CharactersDecimal
ValuesDecimal
DigitsDecimal
Digit
Positiony 121 1 0 2 1 1 2 First, we intialize the asciiCode to the Decimal Digit at DecimalDigitPosition 0.
- This would set the asciiCode to 1.We then multiple the Decimal Digit at DecimalDigitPositions 1 by 10 and add it to the asciiCode value.
- This would add the value of 20 (2 * 10) to the asciiCode of 1 which keeps the asciiCode at 21.We then multiple the Decimal Digit at DecimalDigitPositions 2 by 100 and add it to the asciiCode value.
- This would add the value of 100 (1 * 100) to the asciiCode of 21 to give a new value of 121.The final value of asciiCode is 121, which is the proper ASCII code value for the character y.
We will assume that the number of SoundSamples greatly out numbers of number bits that need to be hidden/extracted. Thus there will be a large number of SoundSamples that have only even values in them. While doing the extraction if we encounter a character that was created from 3 sound samples with a zero value for one's digits, we would have extracted ASCII Character 0 or the NULL character. When this occurs, we will stop the extraction process and display the string that has been created and then exit() the program.
For the extracting program, Proj4b.java, you are to prompt the user for a sound file to use. You are to display the extracted string using one of the methods from the SimpleOutput class.
Your header block comment for the program must include the following:
Header block comments for each method must include the following:
For this project, I received help from the following member of CS 101.This statement should list each helping student's name in a comment in the "header comment" of your Java file that includes the main() method.
Department of Computer Science
University of Illinois at Chicago