Reading encrypted bytes from an image in java

旧街凉风 提交于 2019-12-12 08:19:02

问题


I have to embed text in an encrypted image(Stegnography). I googled and found codes for embedding text in an image. But I have to encrypt image at first and embed text in this encrypted image. My tries are as follows.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tbn;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.imageio.ImageIO;

/**
 *
 * @author user
 */
public class DbtClass {

    public static void main(String[] args) {
        try {
            BufferedImage orgnlimage = ImageIO.read(new File("parrruuuuu.png"));
            orgnlimage = user_space(orgnlimage);
            byte[] orgnlimagebytes = get_byte_data(orgnlimage);
            byte[] encryptedbytes = encrypt(orgnlimagebytes, "abc");
            BufferedImage encryptedimage = toImage(encryptedbytes, orgnlimage.getWidth(), orgnlimage.getHeight());
            ImageIO.write(encryptedimage, "png", new File("encrypted.png"));

            /////////////////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////////////////

            byte[] encryptedbytes2 = get_byte_data(encryptedimage);
            System.out.println("encryptedbytes before writing: "+encryptedbytes2.length);

            BufferedImage encryptedimage3 = ImageIO.read(new File("encrypted.png"));
            byte[] encryptedbyte3 = get_byte_data(encryptedimage3);
            System.out.println("encryptedbytes after writing: "+encryptedbyte3.length);


        } catch (IOException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static 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;
    }

    public static byte[] get_byte_data(BufferedImage image) {
        WritableRaster raster = image.getRaster();
        DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
        return buffer.getData();
    }

    public static byte[] encrypt(byte[] orgnlbytes, String key) {
        byte[] encbytes = null;
        try {
            Cipher cipher = Cipher.getInstance("AES");
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            // cryptograph. secure random 
            random.setSeed(key.getBytes());

            keyGen.init(128, random);
            // for example
            SecretKey secretKey = keyGen.generateKey();
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            encbytes = cipher.doFinal(orgnlbytes);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        return encbytes;
    }

    public static BufferedImage toImage(byte[] imagebytes, int width, int height) {
        DataBuffer buffer = new DataBufferByte(imagebytes, imagebytes.length);
        WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, 3 * width, 3, new int[]{2, 1, 0}, (Point) null);
        ColorModel cm = new ComponentColorModel(ColorModel.getRGBdefault().getColorSpace(), false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        return new BufferedImage(cm, raster, true, null);
    }
}

Here I was written the encrypted image using raster class and ImageIO.write().Then read this encrypted bytes from file Using ImageIO.read().The encrypted byte[] before writing the image and the byte[] after reading the image are totaly different


回答1:


So here's what happens. Assume an original image of size WxH. Since you have 3 bytes per pixel, your image, orgnlimagebytes, has S = 3*W*H bytes.

Now you encrypt this image with AES, which results in a fixed block size of 16 bytes. If S is not divisible by 16, it will be padded to be so. If it is divisible by 16, another block of 16 bytes will be added. The point here is that the encrypted byte array, encryptedbytes, has a bigger size than orgnlimagebytes. Call this S'.

Now you use the method toImage to create a BufferedImage out of this byte array. You create a buffer of encryptedbytes, turn that to a raster and blah, blah, blah. You do end up with an image of size WxH. What happens, however, is that the BufferedImage object has a reference to the buffer which has S' elements. You only use the first S elements to construct the pixels of the image, but you can still access the rest of the elements from the buffer. So when you turn the BufferedImage to a byte array again, encryptedbytes2, you get all S' number of elements back.

The image only has WxH RGB pixels, so if you try to save that to an image file, that's all you're going to save. You won't save any of the additional bytes from the buffer reference. So when you save and load the image and convert that to a byte array, expectedbytes3, you get the expected number of bytes, which should be S.


This explains the unexpected inconsistency of the encrypted byte array before and after saving to a file. However, aside of the method of encryption, why do you even encrypt the cover image? It would make sense if you encrypted the message before hiding it in the image for extra security in case someone managed to both detect and extract the message. Encrypting the pixel values of the cover image means drastically changing them, which introduces apparent changes.



来源:https://stackoverflow.com/questions/28383811/reading-encrypted-bytes-from-an-image-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!