Reputation: 15158
can anyone give me an example for using GCM and/or CCM modes with AES in BouncyCastle?
My code is this:
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();
but it throws this exception when decrypting in GCM mode (line 70 is 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)
And this Exception when encrypting in CCM mode (line 70 is 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)
Upvotes: 4
Views: 4330
Reputation: 93948
For CCM mode there is a little snag: the size of the IV should be smaller than the block size. Your code crashes on the following:
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);
Try it with an "IV" of 15 bytes instead (the IV is actually a NONCE, but IvParameterSpec
is used for the NONCE).
The other problem is that the cipher.doFinal()
method is both called when CipherInputStream
cannot retrieve any data from the underlying stream, as well as when close()
is called. Note that CipherInputStream
is a very badly written class that also removes BadPaddingException
when it is thrown - this is the exception you get when the tag validation fails (!!!). You are better off creating your own one based on CipherInputStream
. I've changed to the code to throw specific IOException
based exceptions instead of ignoring exceptions, and keeping a boolean
state to see if doFinal()
has been executed on the underlying cipher. It should not call doFinal()
twice.
So you are running in a Java JCE bug here. I might put it in the Oracle bug database, where it not that up till now all my bug reports have been ignored completely.
Tested against latest version of OpenJDK 7 and Bouncy Castle 1.47 (2012-08-30 or something close).
Upvotes: 7