从 java 中的图像读取加密字节
Reading encrypted bytes from an image in java
我必须在加密图像中嵌入文本(隐写术)。我用谷歌搜索并找到了在图像中嵌入文本的代码。但是我必须首先加密图像并将文本嵌入到这个加密图像中。我的尝试如下。
/*
* 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);
}
}
这里我使用光栅 class 和 ImageIO.write() 写入了加密图像。然后使用 ImageIO.read() 从文件中读取这个加密字节。之前的加密字节 []写入图像和读取图像后的byte[]完全不同
事情是这样的。假设原始图像大小为 WxH
。由于每个像素有 3 个字节,因此您的图像 orgnlimagebytes
有 S = 3*W*H
个字节。
现在您使用 AES 加密此图像,结果是 fixed block size of 16 bytes。如果 S
不能被 16 整除,它将被填充为整除。如果它可以被 16 整除,则将添加另一个 16 字节的块。这里的要点是加密字节数组 encryptedbytes
的大小比 orgnlimagebytes
大。调用此 S'
.
现在您使用方法 toImage
从这个字节数组创建一个 BufferedImage。您创建了一个 encryptedbytes
的缓冲区,将其转换为光栅,等等等等。您最终会得到一张大小为 WxH
的图像。但是,发生的情况是 BufferedImage 对象引用了具有 S'
元素的缓冲区。您仅使用前 S
个元素来构造图像的像素,但您仍然可以访问缓冲区中的其余元素。因此,当您再次将 BufferedImage 转换为字节数组时,encryptedbytes2
,您将返回所有 S'
个元素。
该图像只有 WxH
RGB 像素,因此如果您尝试将其保存到图像文件中,那么您将只能保存该图像。您不会保存缓冲区引用中的任何额外字节。因此,当您保存和加载图像并将其转换为字节数组 expectedbytes3
时,您会得到预期的字节数,应该是 S
.
这解释了加密字节数组在保存到文件之前和之后意外的不一致。但是,抛开加密方法不谈,为什么还要加密封面图片呢?如果您在将消息隐藏在图像中之前对其进行加密以提高安全性,以防有人设法检测和提取消息,这将是有意义的。加密封面图像的像素值意味着彻底改变它们,这会引入明显的变化。
我必须在加密图像中嵌入文本(隐写术)。我用谷歌搜索并找到了在图像中嵌入文本的代码。但是我必须首先加密图像并将文本嵌入到这个加密图像中。我的尝试如下。
/*
* 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);
}
}
这里我使用光栅 class 和 ImageIO.write() 写入了加密图像。然后使用 ImageIO.read() 从文件中读取这个加密字节。之前的加密字节 []写入图像和读取图像后的byte[]完全不同
事情是这样的。假设原始图像大小为 WxH
。由于每个像素有 3 个字节,因此您的图像 orgnlimagebytes
有 S = 3*W*H
个字节。
现在您使用 AES 加密此图像,结果是 fixed block size of 16 bytes。如果 S
不能被 16 整除,它将被填充为整除。如果它可以被 16 整除,则将添加另一个 16 字节的块。这里的要点是加密字节数组 encryptedbytes
的大小比 orgnlimagebytes
大。调用此 S'
.
现在您使用方法 toImage
从这个字节数组创建一个 BufferedImage。您创建了一个 encryptedbytes
的缓冲区,将其转换为光栅,等等等等。您最终会得到一张大小为 WxH
的图像。但是,发生的情况是 BufferedImage 对象引用了具有 S'
元素的缓冲区。您仅使用前 S
个元素来构造图像的像素,但您仍然可以访问缓冲区中的其余元素。因此,当您再次将 BufferedImage 转换为字节数组时,encryptedbytes2
,您将返回所有 S'
个元素。
该图像只有 WxH
RGB 像素,因此如果您尝试将其保存到图像文件中,那么您将只能保存该图像。您不会保存缓冲区引用中的任何额外字节。因此,当您保存和加载图像并将其转换为字节数组 expectedbytes3
时,您会得到预期的字节数,应该是 S
.
这解释了加密字节数组在保存到文件之前和之后意外的不一致。但是,抛开加密方法不谈,为什么还要加密封面图片呢?如果您在将消息隐藏在图像中之前对其进行加密以提高安全性,以防有人设法检测和提取消息,这将是有意义的。加密封面图像的像素值意味着彻底改变它们,这会引入明显的变化。