From ad8b09095e4a3cd5c1bfa8c3defaa89693092b53 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 11 Sep 2013 22:22:30 +0000 Subject: [PATCH] Support more hashing formats for OOXML protected documents, for bug #55544 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1522074 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/poifs/crypt/EncryptionHeader.java | 32 +++++++++++++----- .../poi/poifs/crypt/TestEncryptionInfo.java | 17 +++++++++- .../protected_sha512.xlsx} | Bin 3 files changed, 40 insertions(+), 9 deletions(-) rename test-data/{openxml4j/EncryptedSHA512.xlsx => poifs/protected_sha512.xlsx} (100%) diff --git a/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java b/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java index 21dd25e99..9adec4d6e 100644 --- a/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java +++ b/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java @@ -27,8 +27,8 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.apache.poi.EncryptedDocumentException; /** - * @author Maxim Valyanskiy - * @author Gary King + * Reads and processes OOXML Encryption Headers + * The constants are largely based on ZIP constants. */ public class EncryptionHeader { public static final int ALGORITHM_RC4 = 0x6801; @@ -36,7 +36,11 @@ public class EncryptionHeader { public static final int ALGORITHM_AES_192 = 0x660F; public static final int ALGORITHM_AES_256 = 0x6610; + public static final int HASH_NONE = 0x0000; public static final int HASH_SHA1 = 0x8004; + public static final int HASH_SHA256 = 0x800C; + public static final int HASH_SHA384 = 0x800D; + public static final int HASH_SHA512 = 0x800E; public static final int PROVIDER_RC4 = 1; public static final int PROVIDER_AES = 0x18; @@ -112,9 +116,9 @@ public class EncryptionHeader { else if (blockSize == 32) algorithm = ALGORITHM_AES_256; else - throw new EncryptedDocumentException("Unsupported key length"); + throw new EncryptedDocumentException("Unsupported key length " + blockSize); } else { - throw new EncryptedDocumentException("Unsupported cipher"); + throw new EncryptedDocumentException("Unsupported cipher " + cipher); } String chaining = keyData.getNamedItem("cipherChaining").getNodeValue(); @@ -124,16 +128,28 @@ public class EncryptionHeader { else if ("ChainingModeCFB".equals(chaining)) cipherMode = MODE_CFB; else - throw new EncryptedDocumentException("Unsupported chaining mode"); + throw new EncryptedDocumentException("Unsupported chaining mode " + chaining); String hashAlg = keyData.getNamedItem("hashAlgorithm").getNodeValue(); int hashSize = Integer.parseInt(keyData.getNamedItem("hashSize") .getNodeValue()); - if ("SHA1".equals(hashAlg) && hashSize == 20) + if ("SHA1".equals(hashAlg) && hashSize == 20) { hashAlgorithm = HASH_SHA1; - else - throw new EncryptedDocumentException("Unsupported hash algorithm"); + } + else if ("SHA256".equals(hashAlg) && hashSize == 32) { + hashAlgorithm = HASH_SHA256; + } + else if ("SHA384".equals(hashAlg) && hashSize == 64) { + hashAlgorithm = HASH_SHA384; + } + else if ("SHA512".equals(hashAlg) && hashSize == 64) { + hashAlgorithm = HASH_SHA512; + } + else { + throw new EncryptedDocumentException("Unsupported hash algorithm: " + + hashAlg + " @ " + hashSize + " bytes"); + } String salt = keyData.getNamedItem("saltValue").getNodeValue(); int saltLength = Integer.parseInt(keyData.getNamedItem("saltSize") diff --git a/src/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java b/src/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java index 62607e7e8..098d503dc 100644 --- a/src/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java +++ b/src/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java @@ -37,9 +37,24 @@ public class TestEncryptionInfo extends TestCase { assertEquals(EncryptionHeader.ALGORITHM_AES_128, info.getHeader().getAlgorithm()); assertEquals(EncryptionHeader.HASH_SHA1, info.getHeader().getHashAlgorithm()); assertEquals(128, info.getHeader().getKeySize()); + assertEquals(32, info.getVerifier().getVerifierHash().length); assertEquals(EncryptionHeader.PROVIDER_AES, info.getHeader().getProviderType()); assertEquals("Microsoft Enhanced RSA and AES Cryptographic Provider", info.getHeader().getCspName()); + } + + public void testEncryptionInfoSHA512() throws Exception { + POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protected_sha512.xlsx")); - assertEquals(32, info.getVerifier().getVerifierHash().length); + EncryptionInfo info = new EncryptionInfo(fs); + + assertEquals(4, info.getVersionMajor()); + assertEquals(4, info.getVersionMinor()); + + assertEquals(EncryptionHeader.ALGORITHM_AES_128, info.getHeader().getAlgorithm()); + assertEquals(EncryptionHeader.HASH_SHA512, info.getHeader().getHashAlgorithm()); + assertEquals(256, info.getHeader().getKeySize()); + assertEquals(64, info.getVerifier().getVerifierHash().length); + assertEquals(EncryptionHeader.PROVIDER_AES, info.getHeader().getProviderType()); +// assertEquals("Microsoft Enhanced RSA and AES Cryptographic Provider", info.getHeader().getCspName()); } } diff --git a/test-data/openxml4j/EncryptedSHA512.xlsx b/test-data/poifs/protected_sha512.xlsx similarity index 100% rename from test-data/openxml4j/EncryptedSHA512.xlsx rename to test-data/poifs/protected_sha512.xlsx