使用TripleDES在Java中加密/解密图像

时间:2016-09-22 19:55:50

标签: java encryption cryptography bufferedimage tripledes

我正在尝试使用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而不指定图像的高度和高度?

2 个答案:

答案 0 :(得分:3)

你正在做的是

  1. 获取图像数据
  2. 加密图像数据
  3. 压缩加密图像(有损JPEG操作)
  4. 解压缩加密图片
  5. 尝试解密加密图片
  6. 显示图片
  7. 在这种情况下,步骤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。