2016-09-22 83 views
-2

我试图使用DESede算法在Java中加密和解密图像。 我的做法是通过从BufferedImage中获取像素字节并对它们进行加密,然后从加密字节中设置WriteableRaster的数据元素,最后将其保存到文件中。使用解密字节时的相同方法,我得到错误,因为当我设置栅格的数据元素时,加密的图像仍然与第一个普通图像具有相同的大小/高度。 这是我的代码:在Java中使用TripleDES加密/解密图像

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); 

我为我的英语不好对不起。在我的代码中,普通像素字节长度和加密字节长度不是相同的大小。当我读取加密图像的字节与普通字节的长度相同时。 我怀疑在保存过程中的错误,也许加密的字节在缓存图像保存时被修剪。如果我的假设是正确的,如何setDataElements的WritableRaster没有指定witdth和图像的高度?


+0

你的问题不清楚。你担心,因为图像尺寸没有与栅格一起加密?你已经非常麻烦地加密*只*像素;如果要加密所有内容,只需加密整个文件(不使用图像API)。 – erickson

+0

我很抱歉我的英文不好。在我的代码中,普通像素字节长度和加密字节长度不是相同的大小。当我读取加密图像的字节与普通字节的长度相同时。 我怀疑在保存过程中的错误,也许加密的字节在保存BufferedImage时被修剪。 –

+0

@PutraArdiansyah哪个错误? – Kayaman

回答

2

如果你只是想执行自己的"ECB penguin",版本供您选择图片的尺寸,使得原来的光栅是密码块大小的倍数,然后指定“DESede/ECB/NoPadding”作为密码变换。这可能需要裁剪或填充原始图像。

你没有指定你正在使用的密码模式,但许多模式(如ECB和CBC)要求明文长度被密码块大小均匀分割,并输出块大小的倍数。通常,输入将填充至少一个字节,并根据需要填充最终输入块。

这意味着您的加密图像将始终大于原始图像栅格。

当您将加密数据设置(或保存)为栅格时,图像库会修剪它认为是多余的数据—全部或部分最终块,并且最终块会丢失。

解密时,密码找到一个不完整的块,或无法在最后的块中找到填充并引发异常。

某些模式,如CTR,OFB或CFB,可以使分组密码像流密码一样行为,一次加密一个字节,而不需要通过填充形成完整的块。密文的大小与纯文本—的大小相同。

任何安全模式的问题是需要初始化向量或随机数。这是一个随机数,用于确保每次遇到给定的纯文本都被加密为不同的密文。这个随机数字需要存储在某个地方以启用解密。

您可以将其存储在与图像文件捆绑在一起的另一个文件中,或者可能有一些方法可以将自定义数据添加到图像元数据中,以便您可以将其保存在同一个文件中并稍后恢复。我不熟悉EXIF或Java中的API,可能会允许您这样做。

+0

谢谢你的回答。也许添加填充字节到exif是最有效的方法。 –

+0

@PutraArdiansyah这取决于你想要做什么。如果你想创建一个欧洲央行弱点的视觉描述,裁剪图像和禁用填充是最好的。如果你实际上试图加密图像,EXIF值得探索。之前,我已经使用了[优秀的第三方库*阅读* EXIF](https://www.drewnoakes.com/code/exif/),但我敢打赌它也具有写作功能。 – erickson

3

你在做什么是

  1. 获取图像数据
  2. 加密图像数据
  3. 压缩加密图像(JPEG有损操作)
  4. 解压缩加密图像
  5. 尝试解密加密图像
  6. 显示图片

在这种情况下,步骤2之后和步骤5之前的数据实际上是不相等的,这意味着密文在途中被破坏。

JPEG是有损格式。您不能加密像素,将随机看像素存储在图像缓冲区中,并使用JPEG压缩该图像缓冲区。这将破坏几乎所有的像素,并且您将无法再解密图像,因为加密和解密是非常精确的算法。如果整个块(3DES-ECB或3DES-CBC中的64位)看起来完全不同,并且以下块可能受到影响,则即使出现一位错误也是如此。

当最后一块看起来不如预期时(填充无法删除)发生填充错误。

如果您使用无损图像格式,如PNG或BMP,那么erickson的答案将适用。

+0

杜,我完全忽略了压缩方面!对于那个很抱歉。 – erickson