You are on page 1of 8

http://www.dreamincode.

net/forums/topic/27950-steganography/
/* 002 *@author William_Wilson 003 *@version 1.6 004 *Created: May 8, 2007 005 */ 006 007 /* 008 *import list 009 */ import java.io.File;

import java.awt.Point; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.awt.image.DataBufferByte;

import javax.imageio.ImageIO; import javax.swing.JOptionPane; /* 022 *Class Steganography 023 */ public class Steganography { /* *Steganography Empty Constructor */ public Steganography() { } /* *Encrypt an image with text, the output file will be of type .png *@param path *@param original *@param ext1 The path (folder) containing the image to modify The name of the image to modify The extension type of the image to modify (jpg,

http://www.dreamincode.net/forums/topic/27950-steganography/
png) *@param stegan The output name of the file The text to hide in the image

*@param message *@param type */

integer representing either basic or advanced encoding

public boolean encode(String path, String original, String ext1, String stegan, String message) { String BufferedImage file_name = image_path(path,original,ext1); = getImage(file_name); image_orig

//user space is not necessary for Encrypting BufferedImage image = user_space(image_orig); image = add_text(image,message);

return(setImage(image,new File(image_path(path,stegan,"png")),"png"); } /* *Decrypt assumes the image being used is of type .png, extracts the hidden text from an image *@param path message from The path (folder) containing the image to extract the

*@param name The name of the image to extract the message from *@param type integer representing either basic or advanced encoding */ public String decode(String path, String name) { byte[] decode; try { //user space is necessary for decrypting BufferedImage image = user_space(getImage(image_path(path,name,"png"))); decode = decode_text(get_byte_data(image)); return(new String(decode)); } catch(Exception e) {

http://www.dreamincode.net/forums/topic/27950-steganography/
JOptionPane.showMessageDialog(null, "There is no hidden message in this image!","Error", JOptionPane.ERROR_MESSAGE); return ""; } } /* *Returns the complete path of a file, in the form: path\name.ext *@param path *@param ext */ private String image_path(String path, String name, String ext) { return path + "/" + name + "." + ext; } /* *Get method to return an image file *@param f The complete path name of the image. *@return A BufferedImage of the supplied file path *@see */ private BufferedImage getImage(String f) { BufferedImage File try { image = ImageIO.read(file); } catch(Exception ex) { JOptionPane.showMessageDialog(null, "Image could not be read!","Error",JOptionPane.ERROR_MESSAGE); file image = null; = new File(f); Steganography.image_path The path (folder) of the file The extension of the file *@param name The name of the file *@return A String representing the complete path of a file

http://www.dreamincode.net/forums/topic/27950-steganography/
} return image; } /* *Set method to save an image file *@param image The image file to save *@param file *@param ext */ private boolean setImage(BufferedImage image, File file, String ext) { try { file.delete(); //delete resources used by the File ImageIO.write(image,ext,file); return true; } catch(Exception e) { JOptionPane.showMessageDialog(null, "File could not be saved!","Error",JOptionPane.ERROR_MESSAGE); return false; } } /* *Handles the addition of text into an image *@param image The image to add hidden text to *@param text */ private BufferedImage add_text(BufferedImage image, String text) { //convert all items to byte arrays: image, message, message length byte img[] = get_byte_data(image); The text to hide in the image *@return Returns the image with the text embedded in it File to save the image to The extension and thus format of the file to be saved

*@return Returns true if the save is succesful

byte msg[] = text.getBytes();

http://www.dreamincode.net/forums/topic/27950-steganography/

byte len[] try {

= bit_conversion(msg.length);

encode_text(img, len,

0); //0 first positiong

encode_text(img, msg, 32); //4 bytes of space for length: 4bytes*8bit = 32 bits } catch(Exception e) { JOptionPane.showMessageDialog(null, "Target File cannot hold message!", "Error",JOptionPane.ERROR_MESSAGE); } return image; } /* *Creates a user space version of a Buffered Image, for editing and saving bytes *@param image The image to put into user space, removes compression interferences *@return The user space version of the supplied image */ private BufferedImage user_space(BufferedImage image) { //create new_img with the attributes of image BufferedImage new_img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR); Graphics2D graphics = new_img.createGraphics(); graphics.drawRenderedImage(image, null); graphics.dispose(); //release all allocated memory for this image return new_img; } /* *Gets the byte array of an image *@param image The image to get byte data from *@return Returns the byte array of the image supplied *@see Raster *@see WritableRaster *@see DataBufferByte

http://www.dreamincode.net/forums/topic/27950-steganography/
*/ 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 array *@param offset data *@return Returns data Array of merged image and addition data The offset into the image array to add the addition /* *Encode an array of bytes into another array of bytes at a supplied offset *@param image Array of data representing an image *@param addition Array of data to add to the supplied image data } //only using 4 bytes byte byte3 = (byte)((i & 0xFF000000) >>> 24); //0 byte byte2 = (byte)((i & 0x00FF0000) >>> 16); //0 byte byte1 = (byte)((i & 0x0000FF00) >>> 8 ); //0 byte byte0 = (byte)((i & 0x000000FF) ); //{0,0,0,byte0} is equivalent, since all shifts >=8 will be 0 return(new byte[]{byte3,byte2,byte1,byte0}); { //originally integers (ints) cast into bytes //byte byte7 = (byte)((i & 0xFF00000000000000L) >>> 56); //byte byte6 = (byte)((i & 0x00FF000000000000L) >>> 48); //byte byte5 = (byte)((i & 0x0000FF0000000000L) >>> 40); //byte byte4 = (byte)((i & 0x000000FF00000000L) >>> 32); bytes */ private byte[] bit_conversion(int i) /* *Gernerates proper byte format of an integer *@param i The integer to convert *@return Returns a byte[4] array converting the supplied integer into } private byte[] get_byte_data(BufferedImage image) { WritableRaster raster return buffer.getData(); = image.getRaster(); DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();

http://www.dreamincode.net/forums/topic/27950-steganography/
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 { int length = 0; int offset = 32; //loop through 32 bytes of data to determine text length /* *Retrieves hidden text from an image *@param image Array of data, representing an image *@return Array of data which contains the hidden text */ private byte[] decode_text(byte[] image) } } return image; } } //loop through each addition byte for(int i=0; i<addition.length; ++i) { //loop through the 8 bits of each byte int add = addition[i]; for(int bit=7; bit>=0; --bit, ++offset) //ensure the new offset value carries on through both loops { //assign an integer to b, shifted by bit spaces AND 1 //a single bit of the current byte int b = (add >>> bit) & 1; //assign the bit by taking: [(previous byte value) AND 0xfe] OR bit to add //changes the last bit of the byte in the image to be the bit of addition image[offset] = (byte)((image[offset] & 0xFE) | b ); { //check that the data + offset will fit in the image if(addition.length + offset > image.length) { throw new IllegalArgumentException("File not long enough!"); */ private byte[] encode_text(byte[] image, byte[] addition, int offset)

http://www.dreamincode.net/forums/topic/27950-steganography/

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

for(int i=0; i<32; ++i) //i=24 will also work, as only the 4th byte contains real data { length = (length << 1) | (image[i] & 1); }

byte[] result = new byte[length]; //loop through each byte of text for(int b=0; b<result.length; ++b ) { //loop through each bit within a byte of text for(int i=0; i<8; ++i, ++offset) { //assign bit: [(new byte value) << 1] OR [(text byte) AND 1] result[b] = (byte)((result[b] << 1) | (image[offset] & 1)); } } return result; }

276 }