我正在尝试使用DESede算法在Java中加密和解密图像。 我这样做的方法是从BufferedImage获取像素字节并加密它们,然后从加密字节设置WriteableRaster的数据元素,最后将其保存到文件中。在解密字节时使用相同的方法,我收到错误,因为当我设置栅格的数据元素时,加密的图像仍然与第一个普通图像具有相同的大小/高度。 这些是我的代码:
public byte[] encrypt(byte[] plainByte) {
byte[] encryptedByte = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
encryptedByte = cipher.doFinal(plainByte);
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
System.err.println(e);
JOptionPane.showMessageDialog(null, e.getMessage());
}
return encryptedByte;
}
解密字节的代码:
public byte[] decrypt(byte[] encryptedByte) {
byte[] decryptedByte = null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedByte = cipher.doFinal(encryptedByte);
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
System.err.println(e);
JOptionPane.showMessageDialog(null, e.getMessage());
}
return decryptedByte;
}
这是我在处理图片时的实现:
String password = "12345";//will be hashed with MD5
triDes.setPassword(password);
//proses enkripsi
BufferedImage image = ImageIO.read(new File("tes.jpg"));
byte[] pixels = (byte[]) image.getRaster().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);
byte[] encrypt = triDes.encrypt(pixels);
System.out.println(encrypt.length + " - " + pixels.length);
WritableRaster raster = Raster.createBandedRaster(DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 3, new Point(0, 0));
raster.setDataElements(0, 0, image.getWidth(), image.getHeight(), encrypt);
image.setData(raster);
File outputfile = new File("enkripsi.jpg");
ImageIO.write(image, "jpg", outputfile);
//proses dekripsi
image = ImageIO.read(new File("enkripsi.jpg"));
pixels = (byte[]) image.getRaster().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);
System.out.println(pixels.length);
byte[] decrypt = triDes.decrypt(pixels);
raster = Raster.createBandedRaster(DataBuffer.TYPE_BYTE, image.getWidth(), image.getHeight(), 3, new Point(0, 0));
raster.setDataElements(0, 0, image.getWidth(), image.getHeight(), decrypt);
image.setData(raster);
outputfile = new File("dekripsi.jpg");
ImageIO.write(image, "jpg", outputfile);
我很抱歉我的英语不好。在我的代码中,普通像素字节长度和加密字节长度不是相同的大小。当我读取加密图像时,字节与普通字节的长度相同。 我怀疑保存过程中的错误,也许加密的字节在BufferedImage保存时被修剪。如果我的假设是正确的,如何设置WritableRaster的dataElements而不指定图像的高度和高度?
答案 0 :(得分:3)
你正在做的是
在这种情况下,步骤2之后和步骤5之前的数据实际上不相等,这意味着密文在途中已损坏。
JPEG是一种有损格式。您无法加密像素,将随机像素存储在图像缓冲区中并使用JPEG压缩该图像缓冲区。这将破坏几乎所有的像素,你将无法再解密图像,因为加密和解密是非常精确的算法。如果即使一个位错误,整个块(3DES-ECB或3DES-CBC中的64位)看起来也会完全不同,以下块可能会受到影响。
当最后一个块看起来不符合预期时,会发生填充错误(无法删除填充)。
如果您使用PNG或BMP等无损图像格式,那么erickson的答案将适用。
答案 1 :(得分:2)
如果您只想执行自己的"ECB penguin",版本,请选择图片尺寸,使原始栅格为密码块大小的倍数,然后指定" DESede / ECB / NoPadding&#34 ;作为密码变换。这可能需要裁剪或填充原始图像。
您没有指定正在使用的密码模式,但许多模式(如ECB和CBC)要求纯文本长度可以被密码的块大小整除,并输出倍数块大小。通常,输入将至少填充一个字节,并根据需要填充最终输入块。
这意味着您的加密图像将始终大于原始图像栅格。
当您将加密数据设置(或保存)为栅格时,图像库会修剪它认为是多余数据的全部或部分最终块,并且最终块将丢失。
解密时,密码会找到一个不完整的块,或者无法在最后一个块中找到填充,并抛出异常。
某些模式(如CTR,OFB或CFB)可以使块密码像流密码一样,一次加密一个字节,而无需通过填充形成完整的块。密文的大小与纯文本的大小相同。
任何安全模式的问题是需要初始化向量或随机数。这是一个随机数,可确保每次遇到给定纯文本时将其加密为不同的密文。需要将此随机数存储在某处以启用解密。
您可以将其存储在与图像文件捆绑在一起的另一个文件中,或者可能有某种方法将自定义数据添加到图像元数据中,以便您可以将其保存在同一文件中并在以后恢复。我不熟悉EXIF或Java中可能允许您这样做的API。