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

我必须在加密图像(Stegnography)中嵌入文本。 我用Google搜索并找到了在图片中嵌入文字的代码。 但我必须首先加密图像并在此加密图像中嵌入文本。 我的尝试如下。

/* * 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); } } 

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

所以这就是发生的事情。 假设大小为WxH的原始图像。 由于每个像素有3个字节,因此您的图像orgnlimagebytes具有S = 3*W*H字节。

现在,您使用AES加密此映像,从而产生16字节的固定块大小 。 如果S不能被16整除,它将被填充为。 如果它可被16整除,则将添加另一个16字节的块。 这里的要点是加密字节数组( encryptedbytes )的大小比orgnlimagebytes 。 叫这个S'

现在使用方法toImage从该字节数组中创建一个BufferedImage。 你创建一个encryptedbytes的缓冲区,将其转换为栅格,等等,等等,等等。 你最终会得到一张尺寸为WxH的图像。 然而,发生的事情是BufferedImage对象具有对具有S'元素的缓冲区的引用。 您只使用前S元素来构造图像的像素,但您仍然可以从缓冲区访问其余元素。 因此,当您再次将BufferedImage转换为字节数组( encryptedbytes2 ,您将获得所有S'个元素。

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


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