diff --git a/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java b/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java index 9adec4d6e..2f10e98ed 100644 --- a/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java +++ b/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java @@ -16,15 +16,16 @@ ==================================================================== */ package org.apache.poi.poifs.crypt; -import org.apache.commons.codec.binary.Base64; -import org.apache.poi.poifs.filesystem.DocumentInputStream; - -import java.io.IOException; import java.io.ByteArrayInputStream; +import java.io.IOException; -import org.w3c.dom.NamedNodeMap; import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.commons.codec.binary.Base64; import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.poifs.filesystem.DocumentInputStream; +import org.apache.poi.util.LittleEndianConsts; +import org.w3c.dom.NamedNodeMap; /** * Reads and processes OOXML Encryption Headers @@ -69,18 +70,24 @@ public class EncryptionHeader { is.readLong(); // skip reserved - StringBuilder builder = new StringBuilder(); - - while (true) { - char c = (char) is.readShort(); - - if (c == 0) { - break; + // CSPName may not always be specified + // In some cases, the sale value of the EncryptionVerifier has the details + is.mark(LittleEndianConsts.INT_SIZE+1); + int checkForSalt = is.readInt(); + is.reset(); + + if (checkForSalt == 16) { + cspName = ""; + } else { + StringBuilder builder = new StringBuilder(); + while (true) { + char c = (char) is.readShort(); + if (c == 0) break; + builder.append(c); } - - builder.append(c); + cspName = builder.toString(); } - cspName = builder.toString(); + cipherMode = MODE_ECB; keySalt = null; } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/AllXWPFTests.java b/src/ooxml/testcases/org/apache/poi/xwpf/AllXWPFTests.java index b1a9983f7..12b768bba 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/AllXWPFTests.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/AllXWPFTests.java @@ -41,6 +41,7 @@ public final class AllXWPFTests { public static Test suite() { TestSuite result = new TestSuite(AllXWPFTests.class.getName()); + result.addTestSuite(TestXWPFBugs.class); result.addTestSuite(TestXWPFDocument.class); result.addTestSuite(TestXWPFWordExtractor.class); result.addTestSuite(TestXWPFHeaderFooterPolicy.class); diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java b/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java new file mode 100644 index 000000000..d0286f671 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFBugs.java @@ -0,0 +1,52 @@ +package org.apache.poi.xwpf; + +import java.io.File; +import java.io.InputStream; + +import junit.framework.TestCase; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.poifs.crypt.Decryptor; +import org.apache.poi.poifs.crypt.EncryptionHeader; +import org.apache.poi.poifs.crypt.EncryptionInfo; +import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; +import org.apache.poi.xwpf.extractor.XWPFWordExtractor; +import org.apache.poi.xwpf.usermodel.XWPFDocument; + +public class TestXWPFBugs extends TestCase { + /** + * A word document that's encrypted with non-standard + * Encryption options, and no cspname section. See bug 53475 + */ + public void test53475() throws Exception { + try { + Biff8EncryptionKey.setCurrentUserPassword("solrcell"); + File file = POIDataSamples.getDocumentInstance().getFile("bug53475-password-is-solrcell.docx"); + NPOIFSFileSystem filesystem = new NPOIFSFileSystem(file, true); + + // Check the encryption details + EncryptionInfo info = new EncryptionInfo(filesystem); + assertEquals(128, info.getHeader().getKeySize()); + assertEquals(EncryptionHeader.ALGORITHM_AES_128, info.getHeader().getAlgorithm()); + assertEquals(EncryptionHeader.HASH_SHA1, info.getHeader().getHashAlgorithm()); + + // Check it can be decoded + Decryptor d = Decryptor.getInstance(info); + assertTrue("Unable to process: document is encrypted", d.verifyPassword("solrcell")); + + // Check we can read the word document in that + InputStream dataStream = d.getDataStream(filesystem); + OPCPackage opc = OPCPackage.open(dataStream); + XWPFDocument doc = new XWPFDocument(opc); + XWPFWordExtractor ex = new XWPFWordExtractor(doc); + String text = ex.getText(); + assertNotNull(text); + assertEquals("This is password protected Word document.", text.trim()); + ex.close(); + } finally { + Biff8EncryptionKey.setCurrentUserPassword(null); + } + } +} diff --git a/test-data/document/bug53475-password-is-solrcell.docx b/test-data/document/bug53475-password-is-solrcell.docx new file mode 100644 index 000000000..2723d5654 Binary files /dev/null and b/test-data/document/bug53475-password-is-solrcell.docx differ