2014-10-05 39 views
0

我自己實現CBC模式。我使用AES作爲每個CBC塊的E函數。AES。 javax.crypto.Cipher返回解密模式下的空數組

這裏是我的加密代碼:

public static List<Byte> encrypt(List<Byte> bytes, byte[] key) throws Exception { 
    byte[] bytesArray = BytesConverter.toByteArray(bytes); 

    SecretKey secretKey = new SecretKeySpec(key, AES); 

    Cipher cipher = Cipher.getInstance(AES); 
    cipher.init(Cipher.ENCRYPT_MODE, secretKey); 

    return BytesConverter.toByteList(cipher.update(bytesArray)); 
} 

我使用update因爲我不希望添加AES墊。我自己在CBC algorythm開始時的最後一塊。

當我想解密cyphertext塊時,我使用與Cipher.DECRYPTION_MODE相同的函數。

public static List<Byte> decrypt(List<Byte> bytes, byte[] key) throws Exception { 
    byte[] bytesArray = BytesConverter.toByteArray(bytes); 

    SecretKey secretKey = new SecretKeySpec(key, AES); 

    Cipher cipher = Cipher.getInstance(AES); 
    cipher.init(Cipher.DECRYPT_MODE, secretKey); 

    return BytesConverter.toByteList(cipher.update(bytesArray)); 
} 

的問題之一是,Cipher.update解密模式返回其通過所述encrypt方法加密輸入空字節數組。

我很困惑。怎麼了?

+1

請注意,由於裝箱,「列表」將消耗比字節數組多16倍的內存。 – SLaks 2014-10-05 19:45:16

+1

@SLaks依賴於'BytesConverter.toByteList'的實現,但我認爲LinkedList或ArrayList被使用,並且在這些情況下你肯定是正確的。而且幾乎沒有理由使用'List'。如果需要包裝器,請查看'java.nio.ByteBuffer'。 – 2014-10-05 20:24:54

+0

@owlstead我只需要子列表。這就是我使用List的原因。 – 2014-10-05 20:43:27

回答

2

您錯過了致電doFinal。由於用於ECB和CBC模式加密的填充,因此Cipher實例需要緩衝到塊大小(字節1),該塊只能在調用doFinal()時進行填充和加密(或解密和未填充),這會釋放最後一部分密文(或用於解密的明文)。

你應該做的是使用"AES/ECB/NoPadding"只有doFinal而不是update實施CBC每個塊(雖然只是update也可以工作,但它不是100%的規定,它應該)。這與底層AES密碼的塊加密相同。您還可以使用Bouncy Castle的較低級別輕量級(即:直接,非JCE)API,該API提供AES 引擎,它們只是實現分組密碼本身。

+0

但是,如果我嘗試加密完整的16字節塊,它會爲下一個unpadd添加一個虛擬塊,對吧?所以輸出將是32個字節(16個加密字節+16個空字節)。這不是我想要的。 – 2014-10-05 21:16:25

+1

您可以使用CTR,但請注意,如果您重複使用IV,您可能會失去所有機密性。如果你想要在沒有定義IV的情況下擁有相同大小的密文,你可以進入稱爲「格式保存加密」的加密部分。還要注意,你通常需要一個認證標籤,例如通過使用GCM模式加密,這也需要一些字節。 – 2014-10-06 07:24:18

+1

以上是一般性建議,我已更新答案以指示如何處理CBC模式。 – 2014-10-06 08:17:51