In: Computer Science
Steganography is the technique of hiding secret messages/information within other non-secret data/information. One popular way of steganography is hiding text (plaintext) within images (cover text). Each image is a collection of pixels, where each pixel is typically represented by 3 values (RGB). Each of R, G, and B is a value between 0 and 255 and thus can be represented by 8 bits. The color of the pixel depends on these values. However, if the least significant bit (last bit from the right) is changed for each of R, G, B then the resulting change in pixel color may not be noticeable. Using this fact, we can convert a text message to bits and embed them one by one in R, G, B values of the pixel. That is, each R, G, B value’s last bit actually carries one bit of the secret message. This is one way to create a covert (secret) channel to pass information. Upon receipt of the image, the receiver can extract the last bit from each R, G, B and combine them to reveal the secret message. In this assignment, we will follow this simple version of LSB algorithm. The students are required to write a Java program that can embed and extract a simple text message into a chosen PNG image. The program should also allow extraction of the message from the stegotext image. In particular, the program should do the following: 1. Prompts user to enter a choice of PNG image to hide a text message. 2. Prompts user to enter the text message that is to be hidden. 3. Create a modified image after hiding the text message (as explained above) and save the image as a new PNG picture. 4. Display the hidden message when a PNG image is supplied. [For testing purpose, the user may choose to use a different image file that already has a message hidden into it following the above scheme.] [Hint: a sample Java code (PixelData.java) is provided on BlazeVIEW to give an idea how to get R, G, B values of a pixel in a PNG image. You can build on that, but you need to explore BufferedImage class, Color class, ImageIO package in JavaFX, getRGB(), setRGB() methods etc.from Java API.] [This program is simple in terms of coding complexity (use of simple loops and arrays), but the logic (design of the steps) should be carefully thought of. Also, it is important to use the Java API methods appropriately. ]
import java.util.*;
import java.io.*;
import java.math.BigInteger;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.image.BufferedImage;
public class HidingText {
private static int[] PixelData(BufferedImage img, int x, int y)
{
int argb = img.getRGB(x, y);
int[] rgb = new int[3];
rgb[0] = (argb >> 16) & 0xff; //Red
rgb[1] = (argb >> 8) & 0xff; // Green
rgb[2] = (argb) & 0xff; // Blue
// 0xff is hex for 255 and used as a mask to get last 8 bits of a
bit string
//System.out.println("Red: " + rgb[0] + ", Green: " + rgb[1] + ",
Blue: " + rgb[2]);
return rgb;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter the input image file name (with .jpg
extension): ");
String file = input.nextLine();
String textToHide="";
System.out.println("Enter text to be hidden in the image:");
textToHide=input.nextLine();
String textToBinary=new
BigInteger(textToHide.getBytes()).toString(2);
BufferedImage img;
String savedImg;
try {
img = ImageIO.read(new File(file));
int h = img.getHeight();
int w = img.getWidth();
System.out.println("Image height = " + h + " and Image width = " +
w);
System.out.println("Total number of pixels = " + (h*w));
// store each pixel's RGB values
int[][] pixelData = new int[h*w][3];
int[] rgb;
int numberOfPixels = 0;
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
rgb = PixelData(img, j, i);
for(int k = 0; k < rgb.length; k++){
pixelData[numberOfPixels][k] = rgb[k];
}
numberOfPixels++;
}
}
//embed text in image & get new image
savedImg=saveTextInImage(textToBinary,pixelData,h,w);
//extract embedded msg from stored image
String message=getMessageFromImage(savedImg);
System.out.println("Decode msg is:"+message);
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getMessageFromImage(String savedImg) {
// TODO Auto-generated method stub
String msg="";
String temp;
BufferedImage img;
try {
img = ImageIO.read(new File(savedImg));
// There is a method ImageIO.write() to create a
// picture file from a BufferedImage object
int h = img.getHeight();
int w = img.getWidth();
System.out.println("Image height = " + h + " and Image width = " +
w);
System.out.println("Total number of pixels = " + (h*w));
// store each pixel's RGB values
int[] rgb;
for(int i = 0; i < h; i++){
for(int j = 0; j < w; j++){
rgb = PixelData(img, j, i);
for(int k = 0; k < rgb.length; k++){
temp=Integer.toBinaryString(rgb[k]);
msg=msg+temp.charAt(temp.length()-1);
System.out.println(msg);
}
}
}
int charCode = Integer.parseInt(msg, 2);
msg=new Character((char)charCode).toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return msg;
}
private static String saveTextInImage(String textToBinary, int[][]
pixelData, int height, int width) {
// TODO Auto-generated method stub
int i,j,newBit,rgb;
String temp,imPath;
imPath="D:\\test.jpg";
int pixelsRequired=textToBinary.length()/3;
for(i=0;i<pixelsRequired;i++){
for(j=0;j<3;j++){
temp=Integer.toBinaryString(pixelData[i][j]);
newBit=Integer.valueOf(temp.charAt(temp.length()-1));
temp=temp.replace(temp.charAt(temp.length()-1),
(char)newBit);
pixelData[i][j]=Integer.parseInt(temp, 2);
}
}
BufferedImage newImage = new BufferedImage(width,
height,BufferedImage.TYPE_INT_RGB);
//do something to populate the image
//such as
int pixelNo = 0;
for(i=0;i<height;i++){
for(j=0;j<width;j++){
rgb = new Color(pixelData[pixelNo][0], pixelData[pixelNo][1],
pixelData[pixelNo][2]).getRGB();
newImage.setRGB( j, i, rgb);
pixelNo++;
}
}
//set your own pixels color
try {
ImageIO.write(newImage, "jpg", new File(imPath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return imPath;
}
}