Jump to content




Recent Status Updates

  • Photo
      30 Sep
    rhossis

    laptop hard disk seated beneath motherboard but with no access panel. 7 hours to replace :(

    Show comments (3)
  • Photo
      19 Sep
    Chall

    I love it when you go to write a help thread, then while writing, you reach an enlightenment, and figure it out yourself.

    Show comments (3)
View All Updates

Developed by TechBiz Xccelerator
Photo
- - - - -

Java: encrypt text into an image

encryption

  • Please log in to reply
3 replies to this topic

#1 Sinipull

Sinipull

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 383 posts

Posted 16 June 2009 - 12:59 PM

i've made a simple class, that encrypts data into an image, using RGB and UTF char codes.

Main idea: Two pictures, key-image and encrypted-text-image, that are slightly different from each other, can be used to calculate differences between their pixels, which can be converted into UTF char code, which means - text.

Data hiding: Actual, useful data, is scattered through out the picture and caps are filled with random "trash". RGB, which consists of 3 separate numbers can be used to hide data well from any algorithm, that searches for similarities between 2 or more pictures, which were generated by the same key - The UTF char code will be distributed randomly between the R, G and B which will be added or subtracted from the original RGB. So, even if the same picture is used to encrypt the same text, it will look different from previously made picture and actual data pixels are unrecognizable from "trash" data, which will also change randomly every time.

How does decrypter know, which is data and which is trash?
First pixel is a flag pixel. It also uses the same technique for hiding as other data( random distribution between R G and B mixed with original color) and data from there can be obtained using the difference between the two pictures. Then, decrypter calculates the distance between each data-pixel, using received data, and starts to read the picture.

Can data be read if someone guesses the flag pixel?
No, even if someone knows the exact position of each data pixel, it is not readable, as it is mix of distributed UTF char code and original pixel from key-image and can only be calculated using the key-image.

Any known bugs?
Yes, Sometimes the ratio between pixels and text doesn't fit very well for such distribution algorithm. Text might be too big to set distance between data-pixels N, and too small to set it N-1, and it will be set N-1 anyway, so data loss will not occur and when decrypter reads it, it doesn't know where the actual text ends and some weird characters may appear at the end of the decrypted String. Nothing fatal. I could've fixed it with some terminator pixel, but wanted to keep picture side as simple as possible.

Is this program useless, because there are much better encryption technologies available?
Maybe, but it sure was fun to program :)


Ok, Here's a sample:
Key:
Posted Image

Encryption:
Posted Image


Download whole Eclipse project:
Posted Image

Classes separately:

Crypter.java
import java.awt.Color;

/**
 * This class encrypts text into image using key-picture. The same key-picture can be used to obtain the text from the image. 
 *  
 * 
 * To start: Create new Crypter object and use methods encrypt() and decrypt().
 * 
 *  
 * 
 * NB: Picture class by Robert Sedgewick and Kevin Wayne is used for IO and image modification.
 */


public class Crypter {    
    private Picture copy;
    private Picture key;
    private int bytes;
    private int countc; //count chars at text, when crypting
    /**
     * Construct Crypter object. 
     * @param key insert Key-picture for encryption or decryption. Must be .png! 
     */
    public Crypter(String key){
        this.key = new Picture(key);
        copy = new Picture(key);
        bytes = this.key.width() * this.key.height()-2;
        
    }
    
    /**
     * Decrypt the String from the picture
     * @param file insert the image file. Note: Make sure you defined the correct key while constructing Crypter object
     * @return Returns the String extracted from the picture
     */
    public String deCrypt(String file){
        if(file.length() < 1)
            return null;
        copy = new Picture(file);
        int allowed = deCalcAllowed(1, 1);
        int count=0;
        String text = "";
        
        for(int i = 0; i<key.width(); i++)
            for(int j = 0; j<key.height(); j++){
                if(!(i == 1 && j == 1)){
                    count++;
                    if(count==allowed){
                        text += deCryptChar(i, j);
                        count=0;
                    }                
                }
            }
        
        return text;
    }
    
    /**
     * encrypt String into the picture using key-picture defined in constructor. 
     * @param text insert the String for encryption
     * @param file file name for result. Must be .png
     * @return Returns true, if everything went fine. False, if something went wrong. 
     */
    public boolean encrypt(String text, String file){
        copy = new Picture(key.toString());        
        countc = 0;        
        int count=0;
        
        if(text.length() == 0) return false; // Nothing to encrypt
        if(text.length() > bytes) return false; // The string is too long
        
        int allowed = (int) Math.floor(bytes/text.length()); // bytes between characters. includes char.                
        allowed(allowed, 1, 1);        
        
        //int badData = (int)Math.floor(bytes/allowed)-text.length(); 
        
        try{
            for(int i = 0; i<key.width(); i++)
                for(int j = 0; j<key.height(); j++){
                    if(!(i == 1 && j == 1)){
                        count++;
                        if(count==allowed){
                            cryptChar(i, j, next(text));
                            count=0;
                        }
                        else{
                            cryptChar(i, j, 0);
                        }                
                    }
                }
            
            copy.save(file);
        }
        catch(Exception e){
            System.out.println("I'm sorry, something went wrong, probably invalid character, try using characters present in 8-bit ASCII");
            return false;
        }
        
        return true;        
    }
    
    private char deCryptChar(int x, int y){
        Color d = difference(x, y);
        int a = d.getRed() + d.getGreen() + d.getBlue();
        return (char) a;
    }
    
    private void cryptChar(int x, int y, int a){
        Color pix = key.get(x,y);
        int blue = pix.getBlue();
        int red = pix.getRed();
        int green = pix.getGreen();
        
        if(a == 0){
            int intensity=30; // close to 40 is most secure
            int r = (int)(Math.random()*intensity);
            if(blue >= 128) blue -= r;
            else  blue += r;
            r = (int)(Math.random()*intensity);
            if(green >= 128) green -= r;
            else  green += r;
            r = (int)(Math.random()*intensity);
            if(red >= 128) red -= r;
            else  red += r;
        }
        else{
            Coord c = split3(a);
            int r = c.x;
            if(blue >= 128) blue -= r;
            else  blue += r;
            r = c.y;
            if(green >= 128) green -= r;
            else  green += r;
            r = c.z;
            if(red >= 128) red -= r;
            else  red += r;
        }        
        pix = new Color(red, green, blue);
        copy.set(x, y, pix);
    
    }
    
    private int next(String text){
        char a = 0;
        if(text.length() > countc){
        a=text.charAt(countc);        
        countc++;
        }        
        return a;        
    }
    
    private void allowed(int allowed, int x, int y){
        Color pix = key.get(x,y);
        int blue = pix.getBlue();
        int red = pix.getRed();
        int green = pix.getGreen();
        
        int count = 0;
        while(allowed > 127){
            count++;
            allowed-=127;
        }
        if(count > 0){
            Coord e = split2(count);
            if(red < 128){
                red += e.x;
            }
            else{
                red -= e.x;
            }
            if(green < 128){
                green += e.y;
            }
            else{
                green -= e.y;
            }
        }
        if(allowed <= 127){            
            if(blue < 128){                
                blue += allowed;
            }
            else if(blue >= 128){                
                blue -= allowed;
            }            
            
        }
        
        pix = new Color(red, green, blue);
        copy.set(x, y, pix);
        
        
    }
    
    private int deCalcAllowed(int x, int y){
        Color d = difference(x, y);
        return (d.getRed() * 127 + d.getGreen() * 127) + d.getBlue();
    }
    
    private Color difference(int x, int y){
        Color pix = key.get(x,y);
        int blue = pix.getBlue();
        int red = pix.getRed();
        int green = pix.getGreen();
        Color c = copy.get(x,y);
        int Cblue = c.getBlue();
        int Cred = c.getRed();
        int Cgreen = c.getGreen();
        return new Color(Math.abs(red-Cred), Math.abs(green-Cgreen), Math.abs(blue-Cblue)); 
    }
    
    private Coord split2(int a){
        int r = (int)(Math.random() * a);
        a-=r;
        Coord c = new Coord(a, r);
        return c;
    }
    
    private Coord split3(int a){
        int z = 0;
        int r = (int)(Math.random() * a);
        a-=r;
        if(a > r){
            z = (int)(Math.random() * a);
            a-=z;            
        }
        else{
            z = (int)(Math.random() * r);
            r-=z;            
        }
        
        Coord c = new Coord(a, r, z);
        return c;
    }
    
    
}

class Coord {
    public int x;
    public int y;
    public int z;
    
    public Coord(int x, int y){
        this.x = x;
        this.y = y;
    }
    
    public Coord(int x, int y, int z){
        this.x = x;
        this.y = y;
        this.z = z;
    }

}


Picture.java (Not written by me)
/*************************************************************************
 *  Compilation:  javac Picture.java
 *  Execution:    java Picture filename
 *
 *  Data type for manipulating individual pixels of an image. The original
 *  image can be read from a file in JPEG, GIF, or PNG format, or the
 *  user can create a blank image of a given size. Includes methods for
 *  displaying the image in a window on the screen or saving to a file.
 *
 *  % java Picture image.jpg
 *
 *  Remarks
 *  -------
 *   - pixel (0, 0) is upper left hand corner
 *
 *   - see also GrayPicture.java for a grayscale version
 *
 *************************************************************************/
 
 /************************************************************************
  *Used by Color Reader - Team 1                                         *
  *We found this picture class on the internet and utilized it in its raw*
  *form. Used as an member variable in our ColorFinder class to hold the *
  *current picture we are trying to identify colors in.                  *
  ************************************************************************/

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;
import java.awt.FileDialog;
import java.awt.Toolkit;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;


/**
 *  This class provides methods for manipulating individual pixels of
 *  an image. The original image can be read from a file in JPEG, GIF,
 *  or PNG format, or the user can create a blank image of a given size.
 *  This class includes methods for displaying the image in a window on
 *  the screen or saving to a file.
 *  <p>
 *  For additional documentation, see
 *  <a href="http://www.cs.princeton.edu/introcs/31datatype">Section 3.1</a> of
 *  <i>Introduction to Programming in Java: An Interdisciplinary Approach</i>
 *  by Robert Sedgewick and Kevin Wayne.
 */
public final class Picture implements ActionListener 
{
    private BufferedImage image;    // the rasterized image
    private JFrame frame;           // on-screen view
    private String filename;        // name of file

   /**
     * Create an empty w-by-h picture.
     */
    public Picture(int w, int h) 
    {
        image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        // set to TYPE_INT_ARGB to support transparency
        filename = w + "-by-" + h;
    }

    public String toString(){
        return filename;
    }
   /**
     * Create a picture by reading in a .png, .gif, or .jpg from
     * the given filename or URL name.
     */
    public Picture(String filename) 
    {
        this.filename = filename;
        try {
            // try to read from file in working directory
            File file = new File(filename);
            if (file.isFile()) {
                image = ImageIO.read(file);
            }

            // now try to read from file in same directory as this .class file
            else {
                URL url = getClass().getResource(filename);
                if (url == null) { url = new URL(filename); }
                image = ImageIO.read(url);
            }
        }
        catch (IOException e) {
            // e.printStackTrace();
            throw new RuntimeException("Could not open file: " + filename);
        }

        // check that image was read in
        if (image == null) {
            throw new RuntimeException("Invalid image file: " + filename);
        }
    }

   /**
     * Create a picture by reading in a .png, .gif, or .jpg from a File.
     */
    public Picture(File file) 
    {
        try { image = ImageIO.read(file); }
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("Could not open file: " + file);
        }
        if (image == null) {
            throw new RuntimeException("Invalid image file: " + file);
        }
    }

   /**
     * Return a JLabel containing this Picture, for embedding in a JPanel,
     * JFrame or other GUI widget.
     */
    public JLabel getJLabel() {
        if (image == null) { return null; }         // no image available
        ImageIcon icon = new ImageIcon(image);
        return new JLabel(icon);
    }

   /**
     * Display the picture in a window on the screen.
     */
    public void show()     
    {

        // create the GUI for viewing the image if needed
        if (frame == null) {
            frame = new JFrame();

            JMenuBar menuBar = new JMenuBar();
            JMenu menu = new JMenu("File");
            menuBar.add(menu);
            JMenuItem menuItem1 = new JMenuItem(" Save...   ");
            menuItem1.addActionListener(this);
            menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
                                     Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
            menu.add(menuItem1);
            frame.setJMenuBar(menuBar);



            frame.setContentPane(getJLabel());
            // f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.setTitle(filename);
            frame.setResizable(false);
            frame.pack();
            frame.setVisible(true);
        }

        // draw
        frame.repaint();
    }

   /**
     * Return the height of the picture (in pixels).
     */
    public int height() 
    {
        return image.getHeight(null);
    }

   /**
     * Return the width of the picture (in pixels).
     */
    public int width() 
    {
        return image.getWidth(null);
    }

   /**
     * Return the Color of pixel (i, j).
     */
    public Color get(int i, int j) 
    {
        return new Color(image.getRGB(i, j));
    }

   /**
     * Set the Color of pixel (i, j) to c.
     */
    public void set(int i, int j, Color c) {
        if (c == null) { throw new RuntimeException("can't set Color to null"); }
        image.setRGB(i, j, c.getRGB());
    }

   /**
     * Save the picture to a file in a standard image format.
     * The filetype must be .png or .jpg.
     */
    public void save(String name) 
    {
        save(new File(name));
    }

   /**
     * Save the picture to a file in a standard image format.
     */
    public void save(File file) 
    {
        this.filename = file.getName();
        if (frame != null) { frame.setTitle(filename); }
        String suffix = filename.substring(filename.lastIndexOf('.') + 1);
        suffix = suffix.toLowerCase();
        if (suffix.equals("jpg") || suffix.equals("png")) 
        {
            try { ImageIO.write(image, suffix, file); }
            catch (IOException e) { e.printStackTrace(); }
        }
        else 
        {
            System.out.println("Error: filename must end in .jpg or .png");
        }
    }

   /**
     * Opens a save dialog box when the user selects "Save As" from the menu.
     */
    public void actionPerformed(ActionEvent e) 
    {
        FileDialog chooser = new FileDialog(frame,
                             "Use a .png or .jpg extension", FileDialog.SAVE);
        chooser.setVisible(true);
        if (chooser.getFile() != null) 
        {
            save(chooser.getDirectory() + File.separator + chooser.getFile());
        }
    }
}

Example program
Test.java
public class Test {
    public static void main(String[] args) {
        Crypter c = new Crypter("key.png"); // Key picture.
        
        //Crypt
        //c.encrypt("Hello i've just encrypted text into image!", "secret.png");
        
        //Decrypt
        System.out.println(c.deCrypt("secret.png"));
        
                
    }
}



Edited by Sinipull, 08 November 2011 - 10:07 AM.

  • 0

#2 Jrb

Jrb

    CC Regular

  • Member
  • PipPipPip
  • 48 posts

Posted 30 January 2011 - 07:30 PM

Tried and tested it, works :) Thanks.
  • 0

#3 Sinipull

Sinipull

    CC Addict

  • Senior Member
  • PipPipPipPipPip
  • 383 posts

Posted 04 February 2011 - 10:12 AM

You are welcome! Please do not use it in any serious projects. i wrote it a while ago and lacked programming experience. It's not tested and may contain critical bugs.
  • 0

#4 null

null

    CC Addict

  • Advanced Member
  • PipPipPipPipPip
  • 128 posts

Posted 04 April 2011 - 12:26 AM

This is a great program! Thumbs Up
  • 0





Also tagged with one or more of these keywords: encryption

Powered by binpress