图像加密:PNG像素数据转字节值的代码问题排查
问题分析与修正方案
你的像素与字节数组转换逻辑完全错误,这是ECB加密后无法呈现预期企鹅轮廓的核心原因,以下是具体问题和修正方案:
原代码的关键错误
- 未使用实际像素数据:你创建了
Color[] colors存储像素,但后续完全没用到这个数组,反而往IntBuffer中写入了total_pixels这个单一整数,等于你加密的根本不是图像像素,而是一个无关数值,自然无法得到正确结果。 - 字节序不匹配:还原时指定了
LITTLE_ENDIAN,但Java中BufferedImage.getRGB()返回的int是大端序(ARGB格式,高位到低位依次是Alpha、Red、Green、Blue),字节序不一致会导致颜色还原错乱。 - 低效且易出错的像素遍历:手动循环逐个获取像素不仅效率低,还容易因遍历顺序错误导致图像错位。
修正后的代码实现
加密前的像素转字节数组
// 1. 直接提取所有像素的int数组(高效且准确) int w = image.getWidth(); int h = image.getHeight(); int total_pixels = w * h; int[] pixelArray = new int[total_pixels]; // 一次性获取所有像素,避免循环遍历 image.getRGB(0, 0, w, h, pixelArray, 0, w); // 2. 将像素int数组转换为字节数组(保持大端序,和getRGB的格式一致) ByteBuffer byteBuffer = ByteBuffer.allocate(total_pixels * 4).order(ByteOrder.BIG_ENDIAN); IntBuffer intBuffer = byteBuffer.asIntBuffer(); intBuffer.put(pixelArray); // 写入实际的像素int数组 byte[] toBeEnc = byteBuffer.array();
加密后的字节数组还原为图像
byte[] encBytes = cipher.doFinal(toBeEnc); // 3. 将加密后的字节数组转回int数组(使用和加密时一致的大端序) IntBuffer intBuf = ByteBuffer.wrap(encBytes).order(ByteOrder.BIG_ENDIAN).asIntBuffer(); int[] encArray = new int[intBuf.remaining()]; intBuf.get(encArray); // 4. 转换为BufferedImage(注意格式匹配ARGB) DataBufferInt rgbData = new DataBufferInt(encArray, encArray.length); // 使用4字节的ARGB掩码,对应getRGB返回的int格式 WritableRaster raster = Raster.createPackedRaster(rgbData, w, h, w, new int[]{0xff0000, 0xff00, 0xff, 0xff000000}, null); ColorModel colorModel = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); BufferedImage img = new BufferedImage(colorModel, raster, false, null); // 保存图像 String fileName = "C:\\Users\\Mark Case\\Pictures\\Saved Pictures\\tux-enc.png"; ImageIO.write(img, "png", new File(fileName));
修正后效果说明
修正后,ECB模式会因为相同像素值被加密为相同密文,保留原图中相同色块的分布,从而呈现出预期的企鹅轮廓;而CBC模式因为每个分组依赖前一个分组的密文,会彻底打乱像素相关性,符合你之前观察到的特性。
内容的提问来源于stack exchange,提问作者Schoggi_23
相关产品推荐
相关产品推荐

