2016-09-22 94 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