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 2012/04/16 11:41:24 UTC

svn commit: r1326538 - in /santuario/xml-security-java/trunk: ./ src/main/java/org/apache/xml/security/c14n/ src/main/java/org/apache/xml/security/c14n/implementations/ src/main/java/org/apache/xml/security/encryption/ src/test/java/org/apache/xml/secu...

Author: coheigea
Date: Mon Apr 16 09:41:23 2012
New Revision: 1326538

URL: http://svn.apache.org/viewvc?rev=1326538&view=rev
Log:
[SANTUARIO-309][SANTUARIO-308] - Move to using a "Physical" C14N algorithm by default for encryption/decryption

Added:
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerPhysical.java
Modified:
    santuario/xml-security-java/trunk/CHANGELOG.txt
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BaltimoreEncTest.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BobKeyResolver.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLCipherTest.java

Modified: santuario/xml-security-java/trunk/CHANGELOG.txt
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/CHANGELOG.txt?rev=1326538&r1=1326537&r2=1326538&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/CHANGELOG.txt (original)
+++ santuario/xml-security-java/trunk/CHANGELOG.txt Mon Apr 16 09:41:23 2012
@@ -1,6 +1,8 @@
 Changelog for "Apache xml-security" <http://santuario.apache.org/>
 
 New in v1.5.2-SNAPSHOT:
+    Fixed SANTUARIO-309 - Default XMLCipher canonicalizer may decrypt element to the wrong namespace.
+    Fixed SANTUARIO-308 - Canonicalizer error when encrypting multiple elements.
     Fixed SANTUARIO-310 - Implement KeyResolvers for PrivateKeys and SecretKeys.
     Fixed SANTUARIO-305 - No way to register internal key resolvers in DECRYPT_MODE.
     Fixed SANTUARIO-306 - KeySelectors loop

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java?rev=1326538&r1=1326537&r2=1326538&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/Canonicalizer.java Mon Apr 16 09:41:23 2012
@@ -35,6 +35,7 @@ import org.apache.xml.security.c14n.impl
 import org.apache.xml.security.c14n.implementations.Canonicalizer20010315ExclWithComments;
 import org.apache.xml.security.c14n.implementations.Canonicalizer20010315OmitComments;
 import org.apache.xml.security.c14n.implementations.Canonicalizer20010315WithComments;
+import org.apache.xml.security.c14n.implementations.CanonicalizerPhysical;
 import org.apache.xml.security.exceptions.AlgorithmAlreadyRegisteredException;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -87,6 +88,11 @@ public class Canonicalizer {
      */
     public static final String ALGO_ID_C14N11_WITH_COMMENTS = 
         ALGO_ID_C14N11_OMIT_COMMENTS + "#WithComments";
+    /**
+     * Non-standard algorithm to serialize the physical representation for XML Encryption
+     */
+    public static final String ALGO_ID_C14N_PHYSICAL = 
+        "http://santuario.apache.org/c14n/physical";
 
     private static Map<String, Class<? extends CanonicalizerSpi>> canonicalizerHash = 
         new ConcurrentHashMap<String, Class<? extends CanonicalizerSpi>>();
@@ -198,6 +204,10 @@ public class Canonicalizer {
             Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS, 
             Canonicalizer11_WithComments.class
         );
+        canonicalizerHash.put(
+            Canonicalizer.ALGO_ID_C14N_PHYSICAL, 
+            CanonicalizerPhysical.class
+        );
     }
 
     /**

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java?rev=1326538&r1=1326537&r2=1326538&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerBase.java Mon Apr 16 09:41:23 2012
@@ -75,12 +75,13 @@ public abstract class CanonicalizerBase 
     private static final byte[] END_TAG = {'<','/'};
     private static final byte[] AMP = {'&','a','m','p',';'};
     private static final byte[] equalsStr = {'=','\"'};
-    private static final int NODE_BEFORE_DOCUMENT_ELEMENT = -1;
-    private static final int NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT = 0;
-    private static final int NODE_AFTER_DOCUMENT_ELEMENT = 1;
+    
+    protected static final int NODE_BEFORE_DOCUMENT_ELEMENT = -1;
+    protected static final int NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT = 0;
+    protected static final int NODE_AFTER_DOCUMENT_ELEMENT = 1;
     
     static {
-        // The null xmlns definiton.
+        // The null xmlns definition.
         try {
             DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
             nullNode = documentBuilder.newDocument().createAttributeNS(Constants.NamespaceSpecNS, XMLNS);
@@ -737,7 +738,7 @@ public abstract class CanonicalizerBase 
      * @param writer where to write the things
      * @throws IOException
      */
-    protected static final void outputPItoWriter(
+    protected void outputPItoWriter(
         ProcessingInstruction currentPI, OutputStream writer, int position
     ) throws IOException {   	  
         if (position == NODE_AFTER_DOCUMENT_ELEMENT) {
@@ -791,7 +792,7 @@ public abstract class CanonicalizerBase 
      * @param writer writer where to write the things
      * @throws IOException
      */
-    protected static final void outputCommentToWriter(
+    protected void outputCommentToWriter(
         Comment currentComment, OutputStream writer, int position
     ) throws IOException {   	  
         if (position == NODE_AFTER_DOCUMENT_ELEMENT) {

Added: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerPhysical.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerPhysical.java?rev=1326538&view=auto
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerPhysical.java (added)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/c14n/implementations/CanonicalizerPhysical.java Mon Apr 16 09:41:23 2012
@@ -0,0 +1,182 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.xml.security.c14n.implementations;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xml.security.c14n.CanonicalizationException;
+import org.apache.xml.security.c14n.Canonicalizer;
+import org.apache.xml.security.signature.XMLSignatureInput;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.xml.sax.SAXException;
+
+/**
+ * Serializes the physical representation of the subtree. All the attributes
+ * present in the subtree are emitted. The attributes are sorted within an element,
+ * with the namespace declarations appearing before the regular attributes.
+ * This algorithm is not a true canonicalization since equivalent subtrees
+ * may produce different output. It is therefore unsuitable for digital signatures.
+ * This same property makes it ideal for XML Encryption Syntax and Processing,
+ * because the decrypted XML content will share the same physical representation
+ * as the original XML content that was encrypted.
+ */
+public class CanonicalizerPhysical extends CanonicalizerBase {
+    
+    private final SortedSet<Attr> result = new TreeSet<Attr>(COMPARE);
+
+    /**
+     * Constructor Canonicalizer20010315
+     *
+     * @param includeComments
+     */
+    public CanonicalizerPhysical() {
+        super(true);
+    }
+    
+    /**
+     * Always throws a CanonicalizationException.
+     *
+     * @param xpathNodeSet
+     * @param inclusiveNamespaces
+     * @return none it always fails
+     * @throws CanonicalizationException always
+     */
+    public byte[] engineCanonicalizeXPathNodeSet(Set<Node> xpathNodeSet, String inclusiveNamespaces)
+        throws CanonicalizationException {
+
+        /** $todo$ well, should we throw UnsupportedOperationException ? */
+        throw new CanonicalizationException("c14n.Canonicalizer.UnsupportedOperation");
+    }
+
+    /**
+     * Always throws a CanonicalizationException.
+     *
+     * @param rootNode
+     * @param inclusiveNamespaces
+     * @return none it always fails
+     * @throws CanonicalizationException
+     */
+    public byte[] engineCanonicalizeSubTree(Node rootNode, String inclusiveNamespaces)
+        throws CanonicalizationException {
+
+        /** $todo$ well, should we throw UnsupportedOperationException ? */
+        throw new CanonicalizationException("c14n.Canonicalizer.UnsupportedOperation");
+    }
+
+    /**
+     * Returns the Attr[]s to be output for the given element.
+     * <br>
+     * The code of this method is a copy of {@link #handleAttributes(Element,
+     * NameSpaceSymbTable)},
+     * whereas it takes into account that subtree-c14n is -- well -- subtree-based.
+     * So if the element in question isRoot of c14n, it's parent is not in the
+     * node set, as well as all other ancestors.
+     *
+     * @param element
+     * @param ns
+     * @return the Attr[]s to be output
+     * @throws CanonicalizationException
+     */
+    @Override
+    protected Iterator<Attr> handleAttributesSubtree(Element element, NameSpaceSymbTable ns)
+        throws CanonicalizationException {
+        if (!element.hasAttributes()) {
+            return null; 
+        }
+        
+        // result will contain all the attrs declared directly on that element
+        final SortedSet<Attr> result = this.result;       
+        result.clear();
+
+        if (element.hasAttributes()) {
+            NamedNodeMap attrs = element.getAttributes();
+            int attrsLength = attrs.getLength();      
+    
+            for (int i = 0; i < attrsLength; i++) {
+                Attr attribute = (Attr) attrs.item(i);
+                result.add(attribute);
+            }
+        }
+
+        return result.iterator();
+    }
+
+    /**
+     * Returns the Attr[]s to be output for the given element.
+     * 
+     * @param element
+     * @param ns
+     * @return the Attr[]s to be output
+     * @throws CanonicalizationException
+     */
+    @Override
+    protected Iterator<Attr> handleAttributes(Element element, NameSpaceSymbTable ns) 
+        throws CanonicalizationException {    
+
+        /** $todo$ well, should we throw UnsupportedOperationException ? */
+        throw new CanonicalizationException("c14n.Canonicalizer.UnsupportedOperation");
+    }
+    
+    protected void circumventBugIfNeeded(XMLSignatureInput input) 
+        throws CanonicalizationException, ParserConfigurationException, IOException, SAXException {
+    	// nothing to do
+    }
+
+    @Override
+    protected void handleParent(Element e, NameSpaceSymbTable ns) {
+    	// nothing to do
+    }
+
+    /** @inheritDoc */
+    public final String engineGetURI() {
+        return Canonicalizer.ALGO_ID_C14N_PHYSICAL;
+    }
+
+    /** @inheritDoc */
+    public final boolean engineGetIncludeComments() {
+        return true;
+    }
+
+	@Override
+	protected void outputPItoWriter(ProcessingInstruction currentPI,
+			OutputStream writer, int position) throws IOException {
+		// Processing Instructions before or after the document element are not treated specially
+		super.outputPItoWriter(currentPI, writer, NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT);
+	}
+
+	@Override
+	protected void outputCommentToWriter(Comment currentComment,
+			OutputStream writer, int position) throws IOException {
+		// Comments before or after the document element are not treated specially
+		super.outputCommentToWriter(currentComment, writer, NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT);
+	}
+    
+}

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=1326538&r1=1326537&r2=1326538&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 Mon Apr 16 09:41:23 2012
@@ -179,6 +179,10 @@ public class XMLCipher {
     public static final String EXCL_XML_N14C_WITH_COMMENTS = 
         Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS;
     
+    /** N14C_PHYSICAL preserve the physical representation*/
+    public static final String PHYSICAL_XML_N14C = 
+        Canonicalizer.ALGO_ID_C14N_PHYSICAL;
+    
     /** Base64 encoding */
     public static final String BASE64_ENCODING =             
         org.apache.xml.security.transforms.Transforms.TRANSFORM_BASE64_DECODE;
@@ -297,7 +301,8 @@ public class XMLCipher {
         // prior to encryption (and for the reverse)
 
         if (canon == null) {
-            canon = Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS;
+        	// The default is to preserve the physical representation.
+            canon = Canonicalizer.ALGO_ID_C14N_PHYSICAL;
         }
 
         try {

Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BaltimoreEncTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BaltimoreEncTest.java?rev=1326538&r1=1326537&r2=1326538&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BaltimoreEncTest.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BaltimoreEncTest.java Mon Apr 16 09:41:23 2012
@@ -633,6 +633,6 @@ public class BaltimoreEncTest extends or
      */
     private void checkDecryptedData(byte[] data) throws Exception {
         String input = new String(data, "ASCII");
-        assert testDecryptString.equals(input);
+        assertEquals(testDecryptString, input);
     }
 }

Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BobKeyResolver.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BobKeyResolver.java?rev=1326538&r1=1326537&r2=1326538&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BobKeyResolver.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/BobKeyResolver.java Mon Apr 16 09:41:23 2012
@@ -40,10 +40,10 @@ import org.w3c.dom.Element;
 public class BobKeyResolver extends KeyResolverSpi {
 
     /** {@link org.apache.commons.logging} logging facility */
-    static org.apache.commons.logging.Log log = 
+    private static org.apache.commons.logging.Log log = 
         org.apache.commons.logging.LogFactory.getLog(BobKeyResolver.class.getName());
 
-    KeyName _kn = null;
+    private KeyName _kn = null;
 
     /**
      * Method engineCanResolve

Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLCipherTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLCipherTest.java?rev=1326538&r1=1326537&r2=1326538&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLCipherTest.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLCipherTest.java Mon Apr 16 09:41:23 2012
@@ -48,6 +48,7 @@ import org.apache.xml.security.encryptio
 import org.apache.xml.security.transforms.params.XPathContainer;
 import org.apache.xml.security.utils.EncryptionConstants;
 import org.apache.xml.security.keys.KeyInfo;
+import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -61,7 +62,7 @@ import org.w3c.dom.NodeList;
 public class XMLCipherTest extends org.junit.Assert {
 
     /** {@link org.apache.commons.logging} logging facility */
-    static org.apache.commons.logging.Log log = 
+    private static org.apache.commons.logging.Log log = 
         org.apache.commons.logging.LogFactory.getLog(XMLCipherTest.class.getName());
     
     static {
@@ -166,8 +167,7 @@ public class XMLCipherTest extends org.j
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn(
                 "Test testAES128ElementAES192KWCipherUsingKEK skipped as "
@@ -238,10 +238,7 @@ public class XMLCipherTest extends org.j
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-            log.debug("Output document");
-            log.debug(target);
-
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn(
                 "Test testAES128ElementRSAKWCipherUsingKEK skipped as "
@@ -328,8 +325,7 @@ public class XMLCipherTest extends org.j
             dd = cipher3.doFinal(ed, ee);
 
             target = toString(dd);
-
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn(
                 "Test testAES192ElementAES256KWCipher skipped as "
@@ -369,11 +365,11 @@ public class XMLCipherTest extends org.j
             ee = (Element) ed.getElementsByTagName("xenc:EncryptedData").item(0);
             EncryptedData encryptedData = cipher.loadEncryptedData(ed, ee);
             String algorithm = encryptedData.getEncryptionMethod().getAlgorithm();
-            assert(XMLCipher.TRIPLEDES.equals(algorithm));
+            assertEquals(XMLCipher.TRIPLEDES, algorithm);
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn(
                 "Test testTripleDesElementCipher skipped as necessary algorithms not available"
@@ -413,11 +409,11 @@ public class XMLCipherTest extends org.j
             ee = (Element) ed.getElementsByTagName("xenc:EncryptedData").item(0);
             EncryptedData encryptedData = cipher.loadEncryptedData(ed, ee);
             String algorithm = encryptedData.getEncryptionMethod().getAlgorithm();
-            assert(XMLCipher.AES_128.equals(algorithm));
+            assertEquals(XMLCipher.AES_128, algorithm);
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn(
                 "Test testAes128ElementCipher skipped as necessary algorithms not available"
@@ -459,11 +455,11 @@ public class XMLCipherTest extends org.j
             ee = (Element) ed.getElementsByTagName("xenc:EncryptedData").item(0);
             EncryptedData encryptedData = cipher.loadEncryptedData(ed, ee);
             String algorithm = encryptedData.getEncryptionMethod().getAlgorithm();
-            assert(XMLCipher.AES_192.equals(algorithm));
+            assertEquals(XMLCipher.AES_192, algorithm);
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn("Test testAes192ElementCipher skipped as necessary algorithms not available");
         }
@@ -505,11 +501,11 @@ public class XMLCipherTest extends org.j
             ee = (Element) ed.getElementsByTagName("xenc:EncryptedData").item(0);
             EncryptedData encryptedData = cipher.loadEncryptedData(ed, ee);
             String algorithm = encryptedData.getEncryptionMethod().getAlgorithm();
-            assert(XMLCipher.AES_256.equals(algorithm));
+            assertEquals(XMLCipher.AES_256, algorithm);
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn("Test testAes265ElementCipher skipped as necessary algorithms not available");
         }
@@ -551,8 +547,7 @@ public class XMLCipherTest extends org.j
             dd = cipher.doFinal(ed, ee);
 
             target = toString(dd);
-
-            assert source.equals(target);
+            assertEquals(source, target);
         } else {
             log.warn(
                 "Test testTripleDesDocumentCipher skipped as "
@@ -625,8 +620,8 @@ public class XMLCipherTest extends org.j
             cipherDecrypt.init(XMLCipher.DECRYPT_MODE, key);
             byte[] decryptBytes = cipherDecrypt.decryptToByteArray(ee);
 
-            assert (new String(decryptBytes, "ASCII")).equals(
-                new String("A test encrypted secret"));
+            assertEquals("A test encrypted secret",
+            		new String(decryptBytes, "ASCII")); 
         } else {
             log.warn(
                 "Test testSameDocumentCipherReference skipped as "
@@ -635,6 +630,109 @@ public class XMLCipherTest extends org.j
         }
     }
 
+    /*
+     * Test physical representation of decrypted element, see SANTUARIO-309
+     */
+    @org.junit.Test
+    public void testPhysicalRepresentation() throws Exception {
+
+        if (haveISOPadding) {
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+            DocumentBuilder db = dbf.newDocumentBuilder();
+
+            byte[] bits192 = "abcdefghijklmnopqrstuvwx".getBytes();
+            DESedeKeySpec keySpec = new DESedeKeySpec(bits192);
+            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
+            SecretKey secretKey = keyFactory.generateSecret(keySpec);
+
+            // Test inherited namespaces don't add extra attributes
+            // Test unused namespaces are preserved
+            final String DATA1 = "<ns:root xmlns:ns=\"ns.com\"><ns:elem xmlns:ns2=\"ns2.com\">11</ns:elem></ns:root>";
+            Document doc = db.parse(new ByteArrayInputStream(DATA1.getBytes("UTF8")));
+            Element elem = (Element)doc.getDocumentElement().getFirstChild();
+
+            XMLCipher dataCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
+            dataCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
+            dataCipher.doFinal(doc, elem);
+            
+            Element encrElem = (Element)doc.getDocumentElement().getFirstChild();
+            assertEquals("EncryptedData", encrElem.getLocalName());
+
+            XMLCipher deCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
+            deCipher.init(XMLCipher.DECRYPT_MODE, secretKey);
+            deCipher.doFinal(doc, encrElem);
+
+            Element decrElem = (Element)doc.getDocumentElement().getFirstChild();
+            assertEquals("ns:elem", decrElem.getNodeName());
+            assertEquals("ns.com", decrElem.getNamespaceURI());
+            assertEquals(1, decrElem.getAttributes().getLength());
+            Attr attr = (Attr)decrElem.getAttributes().item(0);
+            assertEquals("xmlns:ns2", attr.getName());
+            assertEquals("ns2.com", attr.getValue());
+
+            // Test default namespace undeclaration is preserved
+            final String DATA2 = "<ns:root xmlns=\"defns.com\" xmlns:ns=\"ns.com\"><elem xmlns=\"\">11</elem></ns:root>";
+            doc = db.parse(new ByteArrayInputStream(DATA2.getBytes("UTF8")));
+            elem = (Element)doc.getDocumentElement().getFirstChild();
+
+            dataCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
+            dataCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
+            dataCipher.doFinal(doc, elem);
+            
+            encrElem = (Element)doc.getDocumentElement().getFirstChild();
+            assertEquals("EncryptedData", encrElem.getLocalName());
+
+            deCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
+            deCipher.init(XMLCipher.DECRYPT_MODE, secretKey);
+            deCipher.doFinal(doc, encrElem);
+
+            decrElem = (Element)doc.getDocumentElement().getFirstChild();
+            assertEquals("elem", decrElem.getNodeName());
+            assertNull(decrElem.getNamespaceURI());
+            assertEquals(1, decrElem.getAttributes().getLength());
+            attr = (Attr)decrElem.getAttributes().item(0);
+            assertEquals("xmlns", attr.getName());
+            assertEquals("", attr.getValue());
+            
+            // Test comments and PIs are not treated specially when serializing element content.
+            // Other c14n algorithms add a newline after comments and PIs, when they are before or after the document element.
+            final String DATA3 = "<root><!--comment1--><?pi1 target1?><elem/><!--comment2--><?pi2 target2?></root>";
+            doc = db.parse(new ByteArrayInputStream(DATA3.getBytes("UTF8")));
+            elem = (Element)doc.getDocumentElement();
+
+            dataCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
+            dataCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
+            dataCipher.doFinal(doc, elem, true);
+            
+            encrElem = (Element)elem.getFirstChild();
+            assertEquals("EncryptedData", encrElem.getLocalName());
+            assertNull(encrElem.getNextSibling());
+
+            deCipher = XMLCipher.getInstance(XMLCipher.TRIPLEDES);
+            deCipher.init(XMLCipher.DECRYPT_MODE, secretKey);
+            deCipher.doFinal(doc, encrElem);
+
+            Node n = elem.getFirstChild();
+            assertEquals(Node.COMMENT_NODE, n.getNodeType());
+            n = n.getNextSibling();
+            assertEquals(Node.PROCESSING_INSTRUCTION_NODE, n.getNodeType());
+            n = n.getNextSibling();
+            assertEquals(Node.ELEMENT_NODE, n.getNodeType());
+            n = n.getNextSibling();
+            assertEquals(Node.COMMENT_NODE, n.getNodeType());
+            n = n.getNextSibling();
+            assertEquals(Node.PROCESSING_INSTRUCTION_NODE, n.getNodeType());
+            n = n.getNextSibling();
+            assertNull(n);
+        } else {
+            log.warn(
+                "Test testPhysicalRepresentation skipped as "
+                + "necessary algorithms not available"
+            );
+        }
+    }
+
     @org.junit.Test
     public void testSerializedData() throws Exception {
         if (!haveISOPadding) {
@@ -676,10 +774,10 @@ public class XMLCipherTest extends org.j
         XMLCipher dcipher = XMLCipher.getInstance(XMLCipher.AES_128);
         dcipher.init(XMLCipher.DECRYPT_MODE, key);
         String algorithm = encryptedData.getEncryptionMethod().getAlgorithm();
-        assert(XMLCipher.AES_128.equals(algorithm));
+        assertEquals(XMLCipher.AES_128, algorithm);
         byte[] bytes = dcipher.decryptToByteArray(dcipher.martial(encryptedData));
         String after = new String(bytes, "UTF-8");
-        assert before.equals(after);
+        assertEquals(before, after);
 
         // test with null type
         encryptedData = cipher.encryptData(d, null, new ByteArrayInputStream(serialized));