从java中的图像读取加密字节 [英] Reading encrypted bytes from an image in java

查看:195
本文介绍了从java中的图像读取加密字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须在加密图像中嵌入文本(Stegnography)。我googled并发现在图像中嵌入文本的代码。但是我必须首先加密图像,并在这个加密的图像中嵌入文本。我的尝试如下。

  / * 
*要更改此模板,请选择工具模板
*并在编辑器中打开模板。
* /
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用户
* /
public class DbtClass {

public static void main (String [] args){
try {
BufferedImage orgnlimage = ImageIO.read(new File(parrruuuuuu.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){
//创建具有图像属性的new_img
BufferedImage new_img = new BufferedImage image.getWidth(),image.getHeight(),BufferedImage.TYPE_3BYTE_BGR);
Graphics2D graphics = new_img.createGraphics();
graphics.drawRenderedImage(image,null);
graphics.dispose(); //释放此图像的所有分配内存
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;
尝试{
密码密码= Cipher.getInstance(AES);
KeyGenerator keyGen = KeyGenerator.getInstance(AES);
SecureRandom random = SecureRandom.getInstance(SHA1PRNG);
//加密。安全随机
random.setSeed(key.getBytes());

keyGen.init(128,random);
//例如
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);
}
返回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);
返回新的BufferedImage(cm,raster,true,null);
}
}

这里我使用栅格类写了加密图像, ImageIO.write()然后从文件中读取加密的字节使用ImageIO.read()。读取图像之前加密的字节[]和读取图像之间的字节[]是完全不同的

解决方案

所以这里会发生什么。假设大小为 WxH 的原始图像。由于您每像素有3个字节,因此您的图像 orgnlimagebytes 具有 S = 3 * W * H 个字节。 / p>

现在,您使用AES加密此映像,这将导致固定块大小为16字节。如果 S 不能被16整除,它将被填充为这样。如果可以被16整除,则会添加16个字节的另一个块。这里的一点是,加密字节数组 encryptedbytes ,具有比 orgnlimagebytes 更大的大小。调用这个 S'



现在您使用方法 toImage 从这个字节数组中创建一个BufferedImage。您创建一个缓冲区为$ code> encryptedbytes ,将其转换为栅格和blah,blah,blah。你最终会得到大小为 WxH 的图像。然而,发生的是BufferedImage对象具有对 S'元素的缓冲区的引用。您只能使用第一个 S 元素来构造图像的像素,但是您仍然可以从缓冲区访问其余元素。所以当你再次将BufferedImage转换成一个字节数组时, encryptedbytes2 ,你可以得到所有元素的数量$ $ / code。



图像只有 WxH RGB像素,所以如果您尝试将其保存到图像文件,那就是你要保存您不会从缓冲区引用中保存任何其他字节。因此,当您保存并加载图像并将其转换为字节数组时, expectedbytes3 ,您将获得预期的字节数,应为 S






这解释了加密字节数组在保存到文件之前和之后的意外不一致。但是,除了加密方法之外,为什么甚至加密封面图像?如果您在将图像隐藏在图像中之前加密了这个额外的安全性,那么这是有意义的,以防有人设法检测和提取消息。加密封面图像的像素值意味着彻底改变它们,这引起了明显的变化。


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

解决方案

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.

这篇关于从java中的图像读取加密字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆