简体   繁体   English

从Java中的图像读取加密的字节

[英]Reading encrypted bytes from an image in java

I have to embed text in an encrypted image(Stegnography). 我必须将文本嵌入加密的图像中(Stegnography)。 I googled and found codes for embedding text in an image. 我在Google上搜索并找到了在图像中嵌入文本的代码。 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 在这里,我使用光栅类和ImageIO.write()编写了加密的图像。然后使用ImageIO.read()从文件读取了此加密字节。写入图像之前的加密byte []和读取图像之后的byte []是完全不同

So here's what happens. 所以这就是发生的事情。 Assume an original image of size WxH . 假定尺寸为WxH的原始图像。 Since you have 3 bytes per pixel, your image, orgnlimagebytes , has S = 3*W*H bytes. 由于每个像素3个字节,因此图像orgnlimagebytes具有S = 3*W*H字节。

Now you encrypt this image with AES, which results in a fixed block size of 16 bytes . 现在,您使用AES加密此图像,这将导致16字节固定块大小 If S is not divisible by 16, it will be padded to be so. 如果S不能被16整除,它将被填充成16。 If it is divisible by 16, another block of 16 bytes will be added. 如果可被16整除,则将添加另一个16字节的块。 The point here is that the encrypted byte array, encryptedbytes , has a bigger size than orgnlimagebytes . 这里的要点是,将加密的字节数组, encryptedbytes ,具有比更大尺寸orgnlimagebytes Call this S' . 称为S'

Now you use the method toImage to create a BufferedImage out of this byte array. 现在,您使用toImage方法toImage字节数组中创建一个BufferedImage。 You create a buffer of encryptedbytes , turn that to a raster and blah, blah, blah. 您创建了一个encryptedbytes的缓冲区,将其转换为栅格,等等,等等。 You do end up with an image of size WxH . 您最终得到的图像大小为WxH What happens, however, is that the BufferedImage object has a reference to the buffer which has S' elements. 但是,发生的情况是BufferedImage对象引用了具有S'元素的缓冲区。 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. 您仅使用前S元素来构造图像的像素,但是仍然可以从缓冲区访问其余元素。 So when you turn the BufferedImage to a byte array again, encryptedbytes2 , you get all S' number of elements back. 因此,当您再次将BufferedImage转换为字节数组encryptedbytes2 ,您会得到所有S'个元素。

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. 该图像只有WxH RGB像素,因此,如果您尝试将其保存到图像文件中,则仅此而已。 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 . 因此,当您保存并加载图像并将其转换为字节数组expectedbytes3 ,您将获得预期的字节数,应为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. 加密封面图像的像素值意味着彻底改变它们,这会带来明显的变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM