package org.bouncycastle.tls.crypto.impl.jcajce;

import java.security.GeneralSecurityException;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jcajce.spec.AEADParameterSpec;
import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl;

/**
 * A basic wrapper for a JCE Cipher class to provide the needed AEAD cipher functionality for TLS.
 */
public class JceAEADCipherImpl
    implements TlsAEADCipherImpl
{
    private final int cipherMode;
    private final Cipher cipher;
    private final String algorithm;

    private SecretKey key;

    public JceAEADCipherImpl(Cipher cipher, String algorithm, boolean isEncrypting)
        throws GeneralSecurityException
    {
        this.cipher = cipher;
        this.algorithm = algorithm;
        this.cipherMode = (isEncrypting) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
    }

    public void setKey(byte[] key)
    {
        this.key = new SecretKeySpec(key, algorithm);
    }

    public void init(byte[] nonce, int macSize, byte[] additionalData)
    {
        try
        {
            cipher.init(cipherMode, key, new AEADParameterSpec(nonce, macSize * 8, additionalData));
        }
        catch (GeneralSecurityException e)
        {
            throw new IllegalStateException(e);
        }
    }

    public int getOutputSize(int inputLength)
    {
        return cipher.getOutputSize(inputLength);
    }

    public int doFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
    {
        try
        {
            return cipher.doFinal(input, inputOffset, inputLength, output, outputOffset);
        }
        catch (GeneralSecurityException e)
        {
            throw new IllegalStateException(e);
        }
    }
}

@@ -59,41 +59,129 @@
 ava.
-security.GeneralSecurityException
+lang.reflect.Constructor;%0Aimport java.security.GeneralSecurityException;%0Aimport java.security.spec.AlgorithmParameterSpec
 ;%0A%0Ai
@@ -238,16 +238,58 @@
 retKey;%0A
+import javax.crypto.spec.IvParameterSpec;%0A
 import j
@@ -609,16 +609,670 @@
 rImpl%0A%7B%0A
+    private static Constructor%3CAlgorithmParameterSpec%3E initSpecConstructor()%0A    %7B%0A        try%0A        %7B%0A            Class%3CAlgorithmParameterSpec%3E clazz = (Class%3CAlgorithmParameterSpec%3E)%0A                Class.forName(%22javax.crypto.spec.GCMParameterSpec%22, true, IvParameterSpec.class.getClassLoader());%0A            return clazz.getConstructor(int.class, byte%5B%5D.class);%0A        %7D%0A        catch (Exception ignore)%0A        %7B%0A            // TODO%5Blogging%5D Log the fact that we are falling back to BC-specific class%0A            return null;%0A        %7D%0A    %7D%0A%0A    private static final Constructor%3CAlgorithmParameterSpec%3E specConstructor = initSpecConstructor();%0A%0A
     priv
@@ -1855,32 +1855,33 @@
 onalData)%0A    %7B%0A
+%0A
         try%0A    
@@ -1868,32 +1868,32 @@
  %7B%0A%0A        try%0A
-
         %7B%0A      
@@ -1878,32 +1878,729 @@
   try%0A        %7B%0A
+            // Try to use GCMParameterSpec (introduced in JDK 7)%0A            if (specConstructor != null)%0A            %7B%0A                try%0A                %7B%0A                    AlgorithmParameterSpec spec = specConstructor.newInstance(macSize * 8, nonce);%0A                    cipher.init(cipherMode, key, spec);%0A                    if (additionalData != null && additionalData.length %3E 0)%0A                    %7B%0A                        cipher.updateAAD(additionalData);%0A                    %7D%0A                    return;%0A                %7D%0A                catch (Exception e)%0A                %7B%0A                %7D%0A            %7D%0A%0A            // Otherwise fall back to the BC-specific AEADParameterSpec%0A
             ciph

Use GCMParameterSpec if available, else BC's AEADParameterSpec