2012-09-01 30 views
4

誰能給我一個在BouncyCastle中使用AES加GCM和/或CCM模式的例子嗎?
我的代碼是這樣的:BouncyCastle GCM/CCM ArrayIndexOutOfBoundsException

SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); 
Cipher   cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC"); 
byte[] block = new byte[1048576]; 
int i; 
long st,et; 

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); 

BufferedInputStream bIn=new BufferedInputStream(new ProgressMonitorInputStream(null,"Encrypting ...",new FileInputStream("input"))); 
CipherInputStream  cIn = new CipherInputStream(bIn, cipher); 
BufferedOutputStream bOut=new BufferedOutputStream(new FileOutputStream("output.enc")); 

int ch; 
while ((i = cIn.read(block)) != -1) { 
    bOut.write(block, 0, i); 
} 
cIn.close(); 
bOut.close(); 

Thread.sleep(5000); 

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec); 

BufferedInputStream fis=new BufferedInputStream(new ProgressMonitorInputStream(null,"Decrypting ...",new FileInputStream("output.enc"))); 
//FileInputStream fis=new FileInputStream("output.enc"); 
//FileOutputStream ro=new FileOutputStream("regen.plain"); 
BufferedOutputStream ro=new BufferedOutputStream(new FileOutputStream("regen.plain")); 

CipherInputStream dcIn = new CipherInputStream(fis, cipher); 

while ((i = dcIn.read(block)) != -1) { 
     ro.write(block, 0, i); 
} 

dcIn.close(); 
ro.close(); 

但在GCM模式解密時,它引發此異常(線70是bOut.write(block, 0, i);):

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException 
    at java.lang.System.arraycopy(Native Method) 
    at org.bouncycastle.crypto.modes.CCMBlockCipher.processPacket(Unknown Source) 
    at org.bouncycastle.crypto.modes.CCMBlockCipher.doFinal(Unknown Source) 
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source) 
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source) 
    at javax.crypto.Cipher.doFinal(DashoA13*..) 
    at javax.crypto.CipherInputStream.a(DashoA13*..) 
    at javax.crypto.CipherInputStream.read(DashoA13*..) 
    at javax.crypto.CipherInputStream.read(DashoA13*..) 
    at enctest.Main.main(Main.java:70) 

而這種異常在CCM模式加密時(線70是bOut.write(block, 0, i);):

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException 
    at java.lang.System.arraycopy(Native Method) 
    at org.bouncycastle.crypto.modes.CCMBlockCipher.processPacket(Unknown Source) 
    at org.bouncycastle.crypto.modes.CCMBlockCipher.doFinal(Unknown Source) 
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source) 
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source) 
    at javax.crypto.Cipher.doFinal(DashoA13*..) 
    at javax.crypto.CipherInputStream.a(DashoA13*..) 
    at javax.crypto.CipherInputStream.read(DashoA13*..) 
    at javax.crypto.CipherInputStream.read(DashoA13*..) 
    at enctest.Main.main(Main.java:70) 
+0

我想你錯了70行是什麼。它不是'while((i = cIn.read(block))!= -1)'? –

+0

@DuncanJones:不,它是'.write'行! – RYN

回答

6

對於CCM模式有一個小障礙:所述IV的大小應小於塊大小。你的代碼崩潰在以下方面:

BlockCipher ctrCipher = new SICBlockCipher(cipher); 
byte[] iv = new byte[blockSize]; 
byte[] out; 

iv[0] = (byte)(((15 - nonce.length) - 1) & 0x7); 

System.arraycopy(nonce, 0, iv, 1, nonce.length); 

有15個字節「IV」,而不是嘗試它(IV實際上是一個隨機數,但IvParameterSpec用於NONCE)。

另一個問題是,當CipherInputStream無法從基礎流中檢索任何數據以及調用close()時,都會調用cipher.doFinal()方法。請注意,CipherInputStream是一個寫得很差的類,它在拋出時也會刪除BadPaddingException - 這是您在標記驗證失敗時發生的異常(!!!)。你最好基於CipherInputStream創建自己的一個。我已更改爲代碼以拋出特定的基於IOException的異常,而不是忽略異常,並保留boolean狀態以查看是否已在底層密碼上執行doFinal()。它不應該叫doFinal()兩次。

所以你在這裏運行Java JCE的bug。我可能把它放在Oracle bug數據庫中,直到現在,我的所有bug報告都完全被忽略了。

對最新版本的OpenJDK 7和Bouncy Castle 1.47進行了測試(2012-08-30或者更近的)。

+0

如果你刪除了close調用,那麼代碼應該運行,但是你不會得到任何認證,這很重要。 –