You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by co...@apache.org on 2014/06/05 12:32:33 UTC

svn commit: r1600584 - /santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java

Author: coheigea
Date: Thu Jun  5 10:32:33 2014
New Revision: 1600584

URL: http://svn.apache.org/r1600584
Log:
[SANTUARIO-392] - In XMLCipher support use of GCMParameterSpec for AES GCM modes. Thanks to Brent Putman for the patch.

Modified:
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java?rev=1600584&r1=1600583&r2=1600584&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java Thu Jun  5 10:32:33 2014
@@ -28,6 +28,7 @@ import java.security.InvalidKeyException
 import java.security.Key;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.MGF1ParameterSpec;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -59,6 +60,7 @@ import org.apache.xml.security.stax.ext.
 import org.apache.xml.security.transforms.InvalidTransformException;
 import org.apache.xml.security.transforms.TransformationException;
 import org.apache.xml.security.utils.Base64;
+import org.apache.xml.security.utils.ClassLoaderUtils;
 import org.apache.xml.security.utils.Constants;
 import org.apache.xml.security.utils.ElementProxy;
 import org.apache.xml.security.utils.EncryptionConstants;
@@ -82,6 +84,9 @@ public class XMLCipher {
 
     private static org.slf4j.Logger log = 
         org.slf4j.LoggerFactory.getLogger(XMLCipher.class);
+    
+    private static final boolean gcmUseIvParameterSpec =
+            System.getProperty("org.apache.xml.security.cipher.gcm.useIvParameterSpec", "false").equals("true");
 
     /** Triple DES EDE (192 bit key) in CBC mode */
     public static final String TRIPLEDES =                   
@@ -1143,10 +1148,10 @@ public class XMLCipher {
         }
         // Now perform the encryption
 
+        int ivLen = JCEMapper.getIVLengthFromURI(algorithm) / 8;
+        byte[] iv = XMLSecurityConstants.generateBytes(ivLen);
         try {
-            int ivLen = JCEMapper.getIVLengthFromURI(algorithm) / 8;
-            byte[] temp = XMLSecurityConstants.generateBytes(ivLen);
-            IvParameterSpec paramSpec = new IvParameterSpec(temp);
+            AlgorithmParameterSpec paramSpec = constructBlockCipherParameters(algorithm, iv);
             c.init(cipherMode, key, paramSpec);
         } catch (InvalidKeyException ike) {
             throw new XMLEncryptionException("empty", ike);
@@ -1186,7 +1191,6 @@ public class XMLCipher {
 
         // Now build up to a properly XML Encryption encoded octet stream
         // IvParameterSpec iv;
-        byte[] iv = c.getIV();
         byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length];
         System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length);
         System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, encryptedBytes.length);
@@ -1217,6 +1221,51 @@ public class XMLCipher {
     }
 
     /**
+     * Build an <code>AlgorithmParameterSpec</code> instance used to initialize a <code>Cipher</code> instance
+     * for block cipher encryption and decryption.
+     * 
+     * @param algorithm the XML encryption algorithm URI
+     * @param iv the initialization vector
+     * @return the newly constructed AlgorithmParameterSpec instance, appropriate for the
+     *         specified algorithm
+     */
+    private AlgorithmParameterSpec constructBlockCipherParameters(String algorithm, byte[] iv) {
+        if (EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM.equals(algorithm)
+                || EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM.equals(algorithm)
+                || EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM.equals(algorithm)) {
+            
+            if (gcmUseIvParameterSpec) {
+                // This override allows to support Java 1.7+ with (usually older versions of) third-party security 
+                // providers which support or even require GCM via IvParameterSpec rather than GCMParameterSpec,
+                // e.g. BouncyCastle <= 1.49 (really <= 1.50 due to a semi-related bug).
+                log.debug("Saw AES-GCM block cipher, using IvParameterSpec due to system property override: {}", algorithm);
+                return new IvParameterSpec(iv);
+            }
+            
+            log.debug("Saw AES-GCM block cipher, attempting to create GCMParameterSpec: {}", algorithm);
+            
+            try {
+                // This class only added in Java 1.7. So load reflectively until Santuario starts targeting a minimum of Java 1.7. 
+                Class<?> gcmSpecClass = ClassLoaderUtils.loadClass("javax.crypto.spec.GCMParameterSpec", this.getClass());
+                
+                // XML Encryption 1.1 mandates a 128-bit Authentication Tag for AES GCM modes.
+                AlgorithmParameterSpec gcmSpec = (AlgorithmParameterSpec) gcmSpecClass.getConstructor(int.class, byte[].class)
+                        .newInstance(128, iv);
+                log.debug("Successfully created GCMParameterSpec");
+                return gcmSpec;
+            } catch (Exception e) {
+                // This handles the case of Java < 1.7 with a third-party security provider that 
+                // supports GCM mode using only an IvParameterSpec, such as BouncyCastle.
+                log.debug("Failed to create GCMParameterSpec, falling back to returning IvParameterSpec", e);
+                return new IvParameterSpec(iv);
+            }
+        } else {
+            log.debug("Saw non-AES-GCM mode block cipher, returning IvParameterSpec: {}", algorithm);
+            return new IvParameterSpec(iv);
+        }
+    }
+
+    /**
      * Returns an <code>EncryptedData</code> interface. Use this operation if
      * you want to load an <code>EncryptedData</code> structure from a DOM 
      * structure and manipulate the contents. 
@@ -1752,10 +1801,10 @@ public class XMLCipher {
         // necessary bytes into a dedicated array.
 
         System.arraycopy(encryptedBytes, 0, ivBytes, 0, ivLen);
-        IvParameterSpec iv = new IvParameterSpec(ivBytes);		
+        AlgorithmParameterSpec paramSpec = constructBlockCipherParameters(algorithm, ivBytes);
 
         try {
-            c.init(cipherMode, key, iv);
+            c.init(cipherMode, key, paramSpec);
         } catch (InvalidKeyException ike) {
             throw new XMLEncryptionException("empty", ike);
         } catch (InvalidAlgorithmParameterException iape) {