ODFTOOLKIT-446 - Receiving encrypted file without password should be not NULL

git-svn-id: https://svn.apache.org/repos/asf/incubator/odf/trunk@1786663 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index a244a9e..da20204 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,6 +3,9 @@
 

 ======= Release 0.6.2 =======

 

+The most notable changes in ODF Toolkit 0.6.2 incubating over previous release:

+* Supply signature and manifest features to ODFDOM

+

 Release wiki page: https://cwiki.apache.org/confluence/display/ODFTOOLKIT/0.6.2-incubating

 

 Versions of major components

@@ -19,6 +22,7 @@
 * ODFTOOLKIT-200 Supply signature and manifest features to ODFDOM

 * ODFTOOLKIT-294 Adding the XSL stylesheet for extracting default values to XSLT_RUNNER XSL sample folder

 * ODFTOOLKIT-374 Set the field "Last Modified By" in the metadata file

+* ODFTOOLKIT-410 Set table:error-message for content-validation to activate actual validation

 * ODFTOOLKIT-417 Missing methods for set and get background-color, subscripted and superscripted for a paragraph

 * ODFTOOLKIT-418 missing method to find an embedded section

 * ODFTOOLKIT-420 missing functions in TextProperties set/get background color

@@ -32,14 +36,13 @@
 ---------

 * ODFTOOLKIT-300 Memory Leak in ODF Simple API

 * ODFTOOLKIT-323 Remove old references to odftoolkit.org site

+* ODFTOOLKIT-367 Paragraph.getTextContent throws NullPointerException with exactly 2 spaces between words Improvement ODFTOOLKIT-365 Improve Release Process to easily publish releases with maven 

 * ODFTOOLKIT-368 Column.setWidth wrong size

-* ODFTOOLKIT-379 NullPointerException in Paragraph.getTextContent()

 * ODFTOOLKIT-386 Project doesn't build with JDK 8

 * ODFTOOLKIT-388 Test hangs when iterating over a spreadsheet created with LibreOffice 4.0.0

 * ODFTOOLKIT-391 Publish ODF Toolkit artifacts to Maven Central + tag release version in SVN

 * ODFTOOLKIT-395 [PATCH] validator applies ODF 1.1 rules to ODF 1.2 documents when checking character content in foreign elements

 * ODFTOOLKIT-396 SpreadsheetDocument.appendSheet fails because of buggy alien element cloning

-* ODFTOOLKIT-397 DataSet cannot set values from spreadsheet if there are repeated rows before data rows

 * ODFTOOLKIT-398 crash when calling getCellBackgroundColor from the org.odftoolkit.simple.table.Cell

 * ODFTOOLKIT-401 NullPointerException from typo hides all ZIP exceptions

 * ODFTOOLKIT-404 Obsolete Jena dependency at ODF Toolkit

diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
index b60fdc7..82d8dc9 100644
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
+++ b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
@@ -139,8 +139,8 @@
 	private ErrorHandler mErrorHandler;

 	private String mManifestVersion;

 	private OdfManifestDom mManifestDom;

-	private String oldPwd;

-	private String newPwd;

+	private String mOldPwd;

+	private String mNewPwd;

 

 	/* Commonly used files within the ODF Package */

 	public enum OdfFile {

@@ -247,8 +247,8 @@
 		this();

 		mBaseURI = getBaseURLFromFile(pkgFile);

 		mErrorHandler = errorHandler;

-		oldPwd = password;

-		newPwd = oldPwd;

+		mOldPwd = password;

+		mNewPwd = mOldPwd;

 		mBaseURI = baseURI;

 

 		InputStream packageStream = new FileInputStream(pkgFile);

@@ -280,8 +280,8 @@
 		this(); // calling private constructor

 		mErrorHandler = errorHandler;

 		mBaseURI = baseURI;

-		oldPwd = password;

-		newPwd = oldPwd;

+		mOldPwd = password;

+		mNewPwd = mOldPwd;

 		initializeZip(packageStream);

 	}

 

@@ -382,6 +382,23 @@
 	 *

 	 * @param pkgFile - the ODF Package. A baseURL is being generated based on its location.

 	 * @param password - the ODF Package password.

+	 * @throws SAXException if there's an XML- or validation-related error while loading the package

+	 * @throws IOException if there's an I/O error while loading the package

+	 * @see #getErrorHandler

+	 */

+	public static OdfPackage loadPackage(File pkgFile, String password) throws SAXException, IOException {

+        return OdfPackage.loadPackage(pkgFile, password, null);

+    }

+

+	/**

+	 * Loads an OdfPackage from the given File.

+	 * <p>

+	 * OdfPackage relies on the file being available for read access over the whole lifecycle of

+	 * OdfPackage.

+	 * </p>

+	 *

+	 * @param pkgFile - the ODF Package. A baseURL is being generated based on its location.

+	 * @param password - the ODF Package password.

 	 * @param errorHandler - SAX ErrorHandler used for ODF validation.

 	 * @throws SAXException if there's an XML- or validation-related error while loading the package

 	 * @throws IOException if there's an I/O error while loading the package

@@ -804,9 +821,14 @@
 		return mPkgDocuments.keySet();

 	}

 

-	public OdfPackageDocument getRootDocument() {

-		return mPkgDocuments.get(OdfPackageDocument.ROOT_DOCUMENT_PATH);

-	}

+    public OdfPackageDocument getRootDocument() {

+        OdfPackageDocument odfPackageDocument = null;

+        odfPackageDocument = mPkgDocuments.get(OdfPackageDocument.ROOT_DOCUMENT_PATH);

+        if (odfPackageDocument == null) {

+            odfPackageDocument = this.loadDocument(OdfPackageDocument.ROOT_DOCUMENT_PATH);

+        }

+        return odfPackageDocument;

+    }

 

 	public OdfManifestDom getManifestDom() {

 		return mManifestDom;

@@ -943,7 +965,7 @@
 	 * @since 0.8.9

 	 */

 	public void setPassword(String password) {

-		newPwd = password;

+		mNewPwd = password;

 	}

 

 	/**

@@ -1064,7 +1086,7 @@
 	 * @return true if the file needs encrypted, false, otherwise

 	 */

 	private boolean fileNeedsEncryption(String internalPath) {

-		if (newPwd != null) {

+		if (mNewPwd != null) {

 			// ODF spec does not allow encrytion of "./mimetype" file

 			if (internalPath.endsWith(SLASH) || OdfFile.MANIFEST.getPath().equals(internalPath) || OdfPackage.OdfFile.MEDIA_TYPE.getPath().equals(internalPath)) {

 				return false;

@@ -1688,7 +1710,12 @@
 							OdfFileEntry manifestEntry = getManifestEntries().get(internalPath);

 							EncryptionDataElement encryptionDataElement = manifestEntry.getEncryptionData();

 							if (encryptionDataElement != null) {

-								data = decryptData(data, manifestEntry, encryptionDataElement);

+                                byte[] newData = decryptData(data, manifestEntry, encryptionDataElement);

+                                if(newData != null){

+                                    data = newData;

+                                }else{

+                                    Logger.getLogger(OdfPackage.class.getName()).log(Level.SEVERE, null, "Wrong password being used for decryption!");

+                                }

 							}

 						}

 						// store for further usage; do not care about manifest:

@@ -1730,7 +1757,7 @@
 			// 3. The start key is generated: the byte sequence

 			// representing the password in UTF-8 is used to

 			// generate a 20-byte SHA1 digest.

-			byte[] passBytes = newPwd.getBytes("UTF-8");

+			byte[] passBytes = mNewPwd.getBytes("UTF-8");

 			MessageDigest md = MessageDigest.getInstance("SHA1");

 			passBytes = md.digest(passBytes);

 			// 4. Checksum specifies a digest in BASE64 encoding

@@ -1838,7 +1865,7 @@
 			String checksum = encryptionDataElement.getChecksumAttribute();

 			byte[] salt = Base64Binary.valueOf(saltStr).getBytes();

 			byte[] iv = Base64Binary.valueOf(ivStr).getBytes();

-			byte[] passBytes = oldPwd.getBytes("UTF-8");

+			byte[] passBytes = mOldPwd.getBytes("UTF-8");

 			MessageDigest md = MessageDigest.getInstance("SHA-1");

 			passBytes = md.digest(passBytes);

 			/*

diff --git a/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java b/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java
index 58be527..479d24e 100644
--- a/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java
+++ b/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/PackageTest.java
@@ -1,20 +1,20 @@
 /************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- * 
+ *
  * Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- * 
+ *
  * Use is subject to license terms.
- * 
+ *
  * Licensed 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. You can also
  * obtain a copy of the License at http://odftoolkit.org/docs/license.txt
- * 
+ *
  * 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.
  *
@@ -35,14 +35,12 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
-
 import javax.xml.transform.Templates;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.sax.SAXSource;
 import javax.xml.transform.stream.StreamResult;
-
 import junit.framework.Assert;
-
+import static org.junit.Assert.fail;
 import org.junit.Test;
 import org.odftoolkit.odfdom.doc.OdfDocument;
 import org.odftoolkit.odfdom.doc.OdfPresentationDocument;
@@ -60,7 +58,7 @@
 import org.xml.sax.helpers.DefaultHandler;
 
 public class PackageTest {
-	
+
 	private static final Logger LOG = Logger.getLogger(PackageTest.class.getName());
 	private static final String mImagePath = "src/main/javadoc/doc-files/";
 	private static final String mImageName = "ODFDOM-Layered-Model.png";
@@ -77,10 +75,10 @@
 	private static final String TARGET_STEP_1 = "PackageLoadTestStep1.ods";
 	private static final String TARGET_STEP_2 = "PackageLoadTestStep2.ods";
 	private static final String TARGET_STEP_3 = "PackageLoadTestStep3.ods";
-	
+
 	public PackageTest() {
 	}
-	
+
 	@Test
 	public void testNotCompressImages() throws Exception {
 		// create test presentation
@@ -91,7 +89,7 @@
 		OdfDrawImage image = (OdfDrawImage) frame.newDrawImageElement();
 		image.newImage(ResourceUtilities.getURI(IMAGE_TEST_FILE));
 		odp.save(ResourceUtilities.newTestOutputFile(IMAGE_PRESENTATION));
-		
+
 		// test if the image is not compressed
 		ZipInputStream zinput = new ZipInputStream(ResourceUtilities.getTestResourceAsStream(IMAGE_PRESENTATION));
 		ZipEntry entry = zinput.getNextEntry();
@@ -105,16 +103,16 @@
 			entry = zinput.getNextEntry();
 		}
 	}
-	
+
 	@Test
 	public void loadPackage() {
 		try {
-			
+
 			// LOAD PACKAGE FORMULA
 			LOG.info("Loading an unsupported ODF Formula document as an ODF Package!");
 			OdfPackage formulaPackage = OdfPackage.loadPackage(ResourceUtilities.getAbsolutePath(ODF_FORMULAR_TEST_FILE));
 			Assert.assertNotNull(formulaPackage);
-			
+
 			// LOAD PACKAGE IMAGE
 			LOG.info("Loading an unsupported image file as an ODF Package!");
 			try {
@@ -128,7 +126,7 @@
 					Assert.fail();
 				}
 			}
-			
+
 			// LOAD PACKAGE IMAGE (WITH ERROR HANDLER)
 			LOG.info("Loading an unsupported image file as an ODF Package (with error handler)!");
 			try {
@@ -147,7 +145,7 @@
 			Assert.fail(e.getMessage());
 		}
 	}
-	
+
 	@Test
 	public void testPackage() {
 		File tmpFile1 = ResourceUtilities.newTestOutputFile(TARGET_STEP_1);
@@ -162,18 +160,18 @@
 			LOG.log(Level.SEVERE, mImagePath, ex);
 			Assert.fail();
 		}
-		
+
 		long lengthBefore = tmpFile1.length();
 		try {
 			// not allowed to change the document simply by open and save
 			OdfPackage odfPackage = OdfPackage.loadPackage(tmpFile1);
-			
+
 			URI imageURI = new URI(mImagePath + mImageName);
 			// testing encoded none ASCII in URL path
 			String pkgRef1 = AnyURI.encodePath("Pictures/a&b.jpg");
 			LOG.log(Level.INFO, "Attempt to write graphic to package path: {0}", pkgRef1);
 			odfPackage.insert(uri2ByteArray(imageURI), pkgRef1, mImageMediaType);
-			
+
 			// testing allowed none-ASCII in URL path (see rfc1808.txt)
 			String pkgRef2 = "Pictures/a&%" + "\u00ea" + "\u00f1" + "\u00fc" + "b.jpg";
 			LOG.log(Level.INFO, "Attempt to write graphic to package path: {0}", pkgRef2);
@@ -188,16 +186,16 @@
 			odfPackage.save(tmpFile3);
 			long lengthAfter3 = tmpFile3.length();
 			odfPackage.close();
-			
+
 			// the package without the images should be as long as before
 			Assert.assertTrue("The files \n\t" + tmpFile1.getAbsolutePath() + " and \n\t" + tmpFile3.getAbsolutePath() + " differ!", lengthBefore == lengthAfter3);
-			
+
 		} catch (Exception ex) {
 			LOG.log(Level.SEVERE, mImagePath, ex);
 			Assert.fail();
 		}
 	}
-	
+
 	private static byte[] uri2ByteArray(URI uri) {
 		byte[] fileBytes = null;
 		try {
@@ -222,7 +220,7 @@
 		}
 		return fileBytes;
 	}
-	
+
 	/**
 	 * Testing the XML helper and the OdfPackage to handle two files at the same
 	 * time (have them open)
@@ -247,9 +245,9 @@
 			Logger.getLogger(PackageTest.class.getName()).log(Level.SEVERE, t.getMessage(), t);
 			Assert.fail();
 		}
-		
+
 	}
-	
+
 	@Test
 	public void validationTestDefault() {
 		try {
@@ -260,7 +258,7 @@
 			LOG.log(Level.SEVERE, null, ex);
 			Assert.fail();
 		}
-		
+
 		// default no error handler: fatal errors are reported
 		try {
 			OdfPackage.loadPackage(ResourceUtilities.getAbsolutePath("testA.jpg"));
@@ -272,7 +270,7 @@
 			}
 		}
 	}
-	
+
 	@Test
 	public void loadPackageWithoutManifest() {
 		try {
@@ -284,7 +282,7 @@
 			ZipEntry entry = new ZipEntry("someentry");
 			zipped.putNextEntry(entry);
 			zipped.close();
-			
+
 			byte[] data = out.toByteArray();
 			ByteArrayInputStream in = new ByteArrayInputStream(data);
 			OdfPackage pkg = OdfPackage.loadPackage(in);
@@ -294,14 +292,14 @@
 			Assert.fail();
 		}
 	}
-	
+
 	@Test
 	public void validationTest() {
-		
+
 		// TESTDOC1: Expected ODF Warnings
 		Map expectedWarning1 = new HashMap();
 		expectedWarning1.put(OdfPackageConstraint.MANIFEST_LISTS_DIRECTORY, 10);
-		
+
 		// TESTDOC1: Expected ODF Errors
 		Map expectedErrors1 = new HashMap();
 		expectedErrors1.put(OdfPackageConstraint.MIMETYPE_NOT_FIRST_IN_PACKAGE, 1);
@@ -311,19 +309,19 @@
 		expectedErrors1.put(OdfPackageConstraint.MANIFEST_LISTS_NONEXISTENT_FILE, 1);
 		ErrorHandlerStub handler1 = new ErrorHandlerStub(expectedWarning1, expectedErrors1, null);
 		handler1.setTestFilePath("testInvalidPkg1.odt");
-		
+
 		// TESTDOC2: Expected ODF Warnings
 		Map expectedWarning2 = new HashMap();
 		expectedWarning2.put(OdfPackageConstraint.MIMETYPE_NOT_IN_PACKAGE, 1);
 		expectedWarning2.put(OdfPackageConstraint.MANIFEST_LISTS_DIRECTORY, 10);
-		
+
 		// TESTDOC2: Expected ODF Errors
 		Map expectedErrors2 = new HashMap();
 		expectedErrors2.put(OdfPackageConstraint.MANIFEST_DOES_NOT_LIST_FILE, 1);
 		expectedErrors2.put(OdfPackageConstraint.MANIFEST_LISTS_NONEXISTENT_FILE, 3);
 		ErrorHandlerStub handler2 = new ErrorHandlerStub(expectedWarning2, expectedErrors2, null);
 		handler2.setTestFilePath("testInvalidPkg2.odt");
-		
+
 		// TESTDOC3 DESCRIPTION - only mimetype file in package
 		// TESTDOC3: Expected ODF Errors
 		Map expectedErrors3 = new HashMap();
@@ -331,13 +329,13 @@
 		expectedErrors3.put(OdfPackageConstraint.MIMETYPE_WITHOUT_MANIFEST_MEDIATYPE, 1);
 		ErrorHandlerStub handler3 = new ErrorHandlerStub(null, expectedErrors3, null);
 		handler3.setTestFilePath("testInvalidPkg3.odt");
-		
+
 		// TESTDOC4: Expected ODF FatalErrors
 		Map<ValidationConstraint, Integer> expectedFatalErrors4 = new HashMap<ValidationConstraint, Integer>();
 		// loading a graphic instead an ODF document
 		expectedFatalErrors4.put(OdfPackageConstraint.PACKAGE_IS_NO_ZIP, 1);
 		ErrorHandlerStub handler4 = new ErrorHandlerStub(null, null, expectedFatalErrors4);
-		
+
 		try {
 			OdfPackage pkg1 = OdfPackage.loadPackage(new File(ResourceUtilities.getAbsolutePath(handler1.getTestFilePath())), null, handler1);
 			Assert.assertNotNull(pkg1);
@@ -363,19 +361,37 @@
 		handler3.validate();
 		handler4.validate();
 	}
-	
+
 	@Test
 	public void testPackagePassword() {
 		File tmpFile = ResourceUtilities.newTestOutputFile("PackagePassword.ods");
 		OdfDocument doc = null;
 		try {
 			doc = OdfSpreadsheetDocument.newSpreadsheetDocument();
-			doc.getPackage().setPassword("password");
+            OdfPackage odfPackage = doc.getPackage();
+            LOG.info("Unencrypted content.xml" + odfPackage.getRootDocument().getFileDom("content.xml").toString());
+			odfPackage.setPassword("password");
 			doc.save(tmpFile);
 			doc.close();
-			OdfPackage odfPackage = OdfPackage.loadPackage(tmpFile, "password", null);
+            // using wrong password
+            odfPackage = OdfPackage.loadPackage(tmpFile, "passwordx");
 			byte[] contentBytes = odfPackage.getBytes("content.xml");
+            // some encrypted XML
 			Assert.assertNotNull(contentBytes);
+            try{
+                odfPackage.getRootDocument().getFileDom("content.xml").toString();
+                fail("NullPointerException missing!");
+            }catch(NullPointerException e){
+                // as expected
+            }
+            // using correct password
+            OdfPackage odfPackage2 = OdfPackage.loadPackage(tmpFile, "password");
+			byte[] contentBytes2 = odfPackage2.getBytes("content.xml");
+            // some encrypted XML
+			Assert.assertNotNull(contentBytes2);
+            // due to XML parse errors null
+            LOG.info("Decrypted content.xml" + odfPackage2.getRootDocument().getFileDom("content.xml").toString());
+
 		} catch (Exception ex) {
 			LOG.log(Level.SEVERE, "password test failed.", ex);
 			Assert.fail();