diff options
author | Andreas Beeker <kiwiwings@apache.org> | 2016-11-01 01:30:48 +0000 |
---|---|---|
committer | Andreas Beeker <kiwiwings@apache.org> | 2016-11-01 01:30:48 +0000 |
commit | ff6f6bb7c4745add4983629598891d0f68afa3f6 (patch) | |
tree | c154f56c71f682f14b7596785d7b0600227d501c | |
parent | 61c1b722e779d74332ba83ce12df4e10d1b69e91 (diff) | |
download | poi-ff6f6bb7c4745add4983629598891d0f68afa3f6.tar.gz poi-ff6f6bb7c4745add4983629598891d0f68afa3f6.zip |
Bug 60320 - issue opening password protected xlsx
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1767399 13f79535-47bb-0310-9956-ffa450edef68
13 files changed, 345 insertions, 84 deletions
diff --git a/src/integrationtest/org/apache/poi/TestAllFiles.java b/src/integrationtest/org/apache/poi/TestAllFiles.java index e0e2c0bde2..dcce6269f1 100644 --- a/src/integrationtest/org/apache/poi/TestAllFiles.java +++ b/src/integrationtest/org/apache/poi/TestAllFiles.java @@ -210,6 +210,7 @@ public class TestAllFiles { //EXPECTED_FAILURES.add("poifs/extenxls_pwd123.xlsx"); //EXPECTED_FAILURES.add("poifs/protected_agile.docx"); EXPECTED_FAILURES.add("spreadsheet/58616.xlsx"); + EXPECTED_FAILURES.add("poifs/60320-protected.xlsx"); // TODO: fails XMLExportTest, is this ok? EXPECTED_FAILURES.add("spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx"); diff --git a/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java b/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java index c52e87c62b..f13c116e0b 100644 --- a/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java +++ b/src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java @@ -16,6 +16,9 @@ ==================================================================== */ package org.apache.poi.poifs.crypt; +import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.util.Removal; + /** * Reads and processes OOXML Encryption Headers * The constants are largely based on ZIP constants. @@ -82,8 +85,19 @@ public abstract class EncryptionHeader implements Cloneable { protected void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) { this.cipherAlgorithm = cipherAlgorithm; + if (cipherAlgorithm.allowedKeySize.length == 1) { + setKeySize(cipherAlgorithm.defaultKeySize); + } + } + + public HashAlgorithm getHashAlgorithm() { + return hashAlgorithm; } + /** + * @deprecated POI 3.16 beta 1. use {@link #getHashAlgorithm()} + */ + @Removal(version="3.18") public HashAlgorithm getHashAlgorithmEx() { return hashAlgorithm; } @@ -96,8 +110,21 @@ public abstract class EncryptionHeader implements Cloneable { return keyBits; } + /** + * Sets the keySize (in bits). Before calling this method, make sure + * to set the cipherAlgorithm, as the amount of keyBits gets validated against + * the list of allowed keyBits of the corresponding cipherAlgorithm + * + * @param keyBits + */ protected void setKeySize(int keyBits) { this.keyBits = keyBits; + for (int allowedBits : getCipherAlgorithm().allowedKeySize) { + if (allowedBits == keyBits) { + return; + } + } + throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for cipher "+getCipherAlgorithm()); } public int getBlockSize() { diff --git a/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java b/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java index 6e8059261a..df216c0714 100644 --- a/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java +++ b/src/java/org/apache/poi/poifs/crypt/EncryptionVerifier.java @@ -16,6 +16,8 @@ ==================================================================== */ package org.apache.poi.poifs.crypt; +import org.apache.poi.util.Removal; + /** * Used when checking if a key is valid for a document */ @@ -48,10 +50,17 @@ public abstract class EncryptionVerifier implements Cloneable { return spinCount; } + /** + * @deprecated POI 3.16 beta 1. use {@link #getChainingMode()} + */ + @Removal(version="3.18") public int getCipherMode() { return chainingMode.ecmaId; } + /** + * @deprecated POI 3.16 beta 1. use {@link #getCipherAlgorithm()} + */ public int getAlgorithm() { return cipherAlgorithm.ecmaId; } diff --git a/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java b/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java index 30f35581f7..a04f74d400 100644 --- a/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java +++ b/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionHeader.java @@ -108,7 +108,7 @@ public class StandardEncryptionHeader extends EncryptionHeader implements Encryp bos.writeInt(getFlags());
bos.writeInt(0); // size extra
bos.writeInt(getCipherAlgorithm().ecmaId);
- bos.writeInt(getHashAlgorithmEx().ecmaId);
+ bos.writeInt(getHashAlgorithm().ecmaId);
bos.writeInt(getKeySize());
bos.writeInt(getCipherProvider().ecmaId);
bos.writeInt(0); // reserved1
diff --git a/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java b/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java index f00efecfb6..4fd284a86c 100644 --- a/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java +++ b/src/java/org/apache/poi/poifs/crypt/standard/StandardEncryptionVerifier.java @@ -56,7 +56,7 @@ public class StandardEncryptionVerifier extends EncryptionVerifier implements En setCipherAlgorithm(header.getCipherAlgorithm()); setChainingMode(header.getChainingMode()); setEncryptedKey(null); - setHashAlgorithm(header.getHashAlgorithmEx()); + setHashAlgorithm(header.getHashAlgorithm()); } protected StandardEncryptionVerifier(CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) { diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java index 480137ef8a..ffe0cdf3f7 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java @@ -40,13 +40,13 @@ import javax.crypto.spec.RC2ParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.poifs.crypt.ChainingMode; import org.apache.poi.poifs.crypt.ChunkedCipherInputStream; import org.apache.poi.poifs.crypt.CipherAlgorithm; import org.apache.poi.poifs.crypt.CryptoFunctions; 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.crypt.EncryptionVerifier; import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry; import org.apache.poi.poifs.filesystem.DirectoryNode; @@ -93,10 +93,8 @@ public class AgileDecryptor extends Decryptor implements Cloneable { public boolean verifyPassword(String password) throws GeneralSecurityException { AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier(); AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader(); - HashAlgorithm hashAlgo = header.getHashAlgorithmEx(); - CipherAlgorithm cipherAlgo = header.getCipherAlgorithm(); + int blockSize = header.getBlockSize(); - int keySize = header.getKeySize()/8; byte[] pwHash = hashPassword(password, ver.getHashAlgorithm(), ver.getSalt(), ver.getSpinCount()); @@ -113,9 +111,9 @@ public class AgileDecryptor extends Decryptor implements Cloneable { * blockSize bytes. * 4. Use base64 to encode the result of step 3. */ - byte verfierInputEnc[] = hashInput(getEncryptionInfo(), pwHash, kVerifierInputBlock, ver.getEncryptedVerifier(), Cipher.DECRYPT_MODE); + byte verfierInputEnc[] = hashInput(ver, pwHash, kVerifierInputBlock, ver.getEncryptedVerifier(), Cipher.DECRYPT_MODE); setVerifier(verfierInputEnc); - MessageDigest hashMD = getMessageDigest(hashAlgo); + MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm()); byte[] verifierHash = hashMD.digest(verfierInputEnc); /** @@ -130,8 +128,8 @@ public class AgileDecryptor extends Decryptor implements Cloneable { * blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes. * 4. Use base64 to encode the result of step 3. */ - byte verifierHashDec[] = hashInput(getEncryptionInfo(), pwHash, kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE); - verifierHashDec = getBlock0(verifierHashDec, hashAlgo.hashSize); + byte verifierHashDec[] = hashInput(ver, pwHash, kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE); + verifierHashDec = getBlock0(verifierHashDec, ver.getHashAlgorithm().hashSize); /** * encryptedKeyValue: This attribute MUST be generated by using the following steps: @@ -146,9 +144,9 @@ public class AgileDecryptor extends Decryptor implements Cloneable { * blockSize bytes. * 4. Use base64 to encode the result of step 3. */ - byte keyspec[] = hashInput(getEncryptionInfo(), pwHash, kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE); - keyspec = getBlock0(keyspec, keySize); - SecretKeySpec secretKey = new SecretKeySpec(keyspec, ver.getCipherAlgorithm().jceId); + byte keyspec[] = hashInput(ver, pwHash, kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE); + keyspec = getBlock0(keyspec, header.getKeySize()/8); + SecretKeySpec secretKey = new SecretKeySpec(keyspec, header.getCipherAlgorithm().jceId); /** * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor @@ -163,10 +161,11 @@ public class AgileDecryptor extends Decryptor implements Cloneable { * array with 0x00 to the next integral multiple of blockSize bytes. * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3. */ - byte vec[] = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityKeyBlock, blockSize); - Cipher cipher = getCipher(secretKey, cipherAlgo, ver.getChainingMode(), vec, Cipher.DECRYPT_MODE); + byte vec[] = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, blockSize); + CipherAlgorithm cipherAlgo = header.getCipherAlgorithm(); + Cipher cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE); byte hmacKey[] = cipher.doFinal(header.getEncryptedHmacKey()); - hmacKey = getBlock0(hmacKey, hashAlgo.hashSize); + hmacKey = getBlock0(hmacKey, header.getHashAlgorithm().hashSize); /** * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message), @@ -177,10 +176,10 @@ public class AgileDecryptor extends Decryptor implements Cloneable { * 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33. * 7. Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6. */ - vec = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityValueBlock, blockSize); + vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityValueBlock, blockSize); cipher = getCipher(secretKey, cipherAlgo, ver.getChainingMode(), vec, Cipher.DECRYPT_MODE); byte hmacValue[] = cipher.doFinal(header.getEncryptedHmacValue()); - hmacValue = getBlock0(hmacValue, hashAlgo.hashSize); + hmacValue = getBlock0(hmacValue, header.getHashAlgorithm().hashSize); if (Arrays.equals(verifierHashDec, verifierHash)) { setSecretKey(secretKey); @@ -206,7 +205,7 @@ public class AgileDecryptor extends Decryptor implements Cloneable { public boolean verifyPassword(KeyPair keyPair, X509Certificate x509) throws GeneralSecurityException { AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier(); AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader(); - HashAlgorithm hashAlgo = header.getHashAlgorithmEx(); + HashAlgorithm hashAlgo = header.getHashAlgorithm(); CipherAlgorithm cipherAlgo = header.getCipherAlgorithm(); int blockSize = header.getBlockSize(); @@ -231,12 +230,12 @@ public class AgileDecryptor extends Decryptor implements Cloneable { byte certVerifier[] = x509Hmac.doFinal(ace.x509.getEncoded()); byte vec[] = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityKeyBlock, blockSize); - cipher = getCipher(secretKey, cipherAlgo, ver.getChainingMode(), vec, Cipher.DECRYPT_MODE); + cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE); byte hmacKey[] = cipher.doFinal(header.getEncryptedHmacKey()); hmacKey = getBlock0(hmacKey, hashAlgo.hashSize); vec = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityValueBlock, blockSize); - cipher = getCipher(secretKey, cipherAlgo, ver.getChainingMode(), vec, Cipher.DECRYPT_MODE); + cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE); byte hmacValue[] = cipher.doFinal(header.getEncryptedHmacValue()); hmacValue = getBlock0(hmacValue, hashAlgo.hashSize); @@ -257,18 +256,17 @@ public class AgileDecryptor extends Decryptor implements Cloneable { return fillSize; } - protected static byte[] hashInput(EncryptionInfo encryptionInfo, byte pwHash[], byte blockKey[], byte inputKey[], int cipherMode) { - EncryptionVerifier ver = encryptionInfo.getVerifier(); - AgileDecryptor dec = (AgileDecryptor)encryptionInfo.getDecryptor(); - int keySize = dec.getKeySizeInBytes(); - int blockSize = dec.getBlockSizeInBytes(); + /* package */ static byte[] hashInput(AgileEncryptionVerifier ver, byte pwHash[], byte blockKey[], byte inputKey[], int cipherMode) { + CipherAlgorithm cipherAlgo = ver.getCipherAlgorithm(); + ChainingMode chainMode = ver.getChainingMode(); + int keySize = ver.getKeySize()/8; + int blockSize = ver.getBlockSize(); HashAlgorithm hashAlgo = ver.getHashAlgorithm(); - byte[] salt = ver.getSalt(); - + byte intermedKey[] = generateKey(pwHash, hashAlgo, blockKey, keySize); - SecretKey skey = new SecretKeySpec(intermedKey, ver.getCipherAlgorithm().jceId); - byte[] iv = generateIv(hashAlgo, salt, null, blockSize); - Cipher cipher = getCipher(skey, ver.getCipherAlgorithm(), ver.getChainingMode(), iv, cipherMode); + SecretKey skey = new SecretKeySpec(intermedKey, cipherAlgo.jceId); + byte[] iv = generateIv(hashAlgo, ver.getSalt(), null, blockSize); + Cipher cipher = getCipher(skey, cipherAlgo, chainMode, iv, cipherMode); byte[] hashFinal; try { @@ -281,7 +279,6 @@ public class AgileDecryptor extends Decryptor implements Cloneable { } @Override - @SuppressWarnings("resource") public InputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { DocumentInputStream dis = dir.createDocumentInputStream(DEFAULT_POIFS_ENTRY); _length = dis.readLong(); @@ -307,7 +304,7 @@ public class AgileDecryptor extends Decryptor implements Cloneable { byte[] blockKey = new byte[4]; LittleEndian.putInt(blockKey, 0, block); - byte[] iv = generateIv(header.getHashAlgorithmEx(), header.getKeySalt(), blockKey, header.getBlockSize()); + byte[] iv = generateIv(header.getHashAlgorithm(), header.getKeySalt(), blockKey, header.getBlockSize()); AlgorithmParameterSpec aps; if (header.getCipherAlgorithm() == CipherAlgorithm.rc2) { diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java index 88bccabf6c..ebb64cb5be 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java @@ -45,18 +45,18 @@ public class AgileEncryptionHeader extends EncryptionHeader implements Cloneable throw new EncryptedDocumentException("Unable to parse keyData");
}
- setKeySize((int)keyData.getKeyBits());
- setFlags(0);
- setSizeExtra(0);
- setCspName(null);
- setBlockSize(keyData.getBlockSize());
-
int keyBits = (int)keyData.getKeyBits();
CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), keyBits);
setCipherAlgorithm(ca);
setCipherProvider(ca.provider);
+ setKeySize(keyBits);
+ setFlags(0);
+ setSizeExtra(0);
+ setCspName(null);
+ setBlockSize(keyData.getBlockSize());
+
switch (keyData.getCipherChaining().intValue()) {
case STCipherChaining.INT_CHAINING_MODE_CBC:
setChainingMode(ChainingMode.cbc);
@@ -73,7 +73,7 @@ public class AgileEncryptionHeader extends EncryptionHeader implements Cloneable HashAlgorithm ha = HashAlgorithm.fromEcmaId(keyData.getHashAlgorithm().toString());
setHashAlgorithm(ha);
- if (getHashAlgorithmEx().hashSize != hashSize) {
+ if (getHashAlgorithm().hashSize != hashSize) {
throw new EncryptedDocumentException("Unsupported hash algorithm: " +
keyData.getHashAlgorithm() + " @ " + hashSize + " bytes");
}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java index 53d4cd6ed2..6d9ec6d66f 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java @@ -21,6 +21,7 @@ import java.security.GeneralSecurityException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -48,6 +49,8 @@ public class AgileEncryptionVerifier extends EncryptionVerifier implements Clone } private List<AgileCertificateEntry> certList = new ArrayList<AgileCertificateEntry>(); + private int keyBits = -1; + private int blockSize = -1; public AgileEncryptionVerifier(String descriptor) { this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor)); @@ -66,10 +69,14 @@ public class AgileEncryptionVerifier extends EncryptionVerifier implements Clone } int keyBits = (int)keyData.getKeyBits(); - CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), keyBits); setCipherAlgorithm(ca); + setKeySize(keyBits); + + int blockSize = keyData.getBlockSize(); + setBlockSize(blockSize); + int hashSize = keyData.getHashSize(); HashAlgorithm ha = HashAlgorithm.fromEcmaId(keyData.getHashAlgorithm().toString()); @@ -125,6 +132,8 @@ public class AgileEncryptionVerifier extends EncryptionVerifier implements Clone setCipherAlgorithm(cipherAlgorithm); setHashAlgorithm(hashAlgorithm); setChainingMode(chainingMode); + setKeySize(keyBits); + setBlockSize(blockSize); setSpinCount(100000); // TODO: use parameter } @@ -171,4 +180,60 @@ public class AgileEncryptionVerifier extends EncryptionVerifier implements Clone other.certList = new ArrayList<AgileCertificateEntry>(certList); return other; } + + + /** + * The keysize (in bits) of the verifier data. This usually equals the keysize of the header, + * but only on a few exceptions, like files generated by Office for Mac, can be + * different. + * + * @return the keysize (in bits) of the verifier. + */ + public int getKeySize() { + return keyBits; + } + + + /** + * The blockSize (in bytes) of the verifier data. + * This usually equals the blocksize of the header. + * + * @return the blockSize (in bytes) of the verifier, + */ + public int getBlockSize() { + return blockSize; + } + + /** + * Sets the keysize (in bits) of the verifier + * + * @param keyBits the keysize (in bits) + */ + protected void setKeySize(int keyBits) { + this.keyBits = keyBits; + for (int allowedBits : getCipherAlgorithm().allowedKeySize) { + if (allowedBits == keyBits) { + return; + } + } + throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for cipher "+getCipherAlgorithm()); + } + + + /** + * Sets the blockSize (in bytes) of the verifier + * + * @param blockSize the blockSize (in bytes) + */ + protected void setBlockSize(int blockSize) { + this.blockSize = blockSize; + } + + @Override + protected void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) { + super.setCipherAlgorithm(cipherAlgorithm); + if (cipherAlgorithm.allowedKeySize.length == 1) { + setKeySize(cipherAlgorithm.defaultKeySize); + } + } } diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java index 5ff45ad814..96aa9b5f9f 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java @@ -86,9 +86,10 @@ public class AgileEncryptor extends Encryptor implements Cloneable { public void confirmPassword(String password) {
// see [MS-OFFCRYPTO] - 2.3.3 EncryptionVerifier
Random r = new SecureRandom();
- int blockSize = getEncryptionInfo().getHeader().getBlockSize();
- int keySize = getEncryptionInfo().getHeader().getKeySize()/8;
- int hashSize = getEncryptionInfo().getHeader().getHashAlgorithmEx().hashSize;
+ AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+ int blockSize = header.getBlockSize();
+ int keySize = header.getKeySize()/8;
+ int hashSize = header.getHashAlgorithm().hashSize;
byte[] newVerifierSalt = new byte[blockSize]
, newVerifier = new byte[blockSize]
@@ -107,14 +108,14 @@ public class AgileEncryptor extends Encryptor implements Cloneable { @Override
public void confirmPassword(String password, byte keySpec[], byte keySalt[], byte verifier[], byte verifierSalt[], byte integritySalt[]) {
AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
- ver.setSalt(verifierSalt);
AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+
+ ver.setSalt(verifierSalt);
header.setKeySalt(keySalt);
- HashAlgorithm hashAlgo = ver.getHashAlgorithm();
int blockSize = header.getBlockSize();
- pwHash = hashPassword(password, hashAlgo, verifierSalt, ver.getSpinCount());
+ pwHash = hashPassword(password, ver.getHashAlgorithm(), verifierSalt, ver.getSpinCount());
/**
* encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
@@ -129,7 +130,7 @@ public class AgileEncryptor extends Encryptor implements Cloneable { * blockSize bytes.
* 4. Use base64 to encode the result of step 3.
*/
- byte encryptedVerifier[] = hashInput(getEncryptionInfo(), pwHash, kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
+ byte encryptedVerifier[] = hashInput(ver, pwHash, kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
ver.setEncryptedVerifier(encryptedVerifier);
@@ -145,9 +146,9 @@ public class AgileEncryptor extends Encryptor implements Cloneable { * blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes.
* 4. Use base64 to encode the result of step 3.
*/
- MessageDigest hashMD = getMessageDigest(hashAlgo);
+ MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm());
byte[] hashedVerifier = hashMD.digest(verifier);
- byte encryptedVerifierHash[] = hashInput(getEncryptionInfo(), pwHash, kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
+ byte encryptedVerifierHash[] = hashInput(ver, pwHash, kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
ver.setEncryptedVerifierHash(encryptedVerifierHash);
/**
@@ -163,10 +164,10 @@ public class AgileEncryptor extends Encryptor implements Cloneable { * blockSize bytes.
* 4. Use base64 to encode the result of step 3.
*/
- byte encryptedKey[] = hashInput(getEncryptionInfo(), pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
+ byte encryptedKey[] = hashInput(ver, pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
ver.setEncryptedKey(encryptedKey);
- SecretKey secretKey = new SecretKeySpec(keySpec, ver.getCipherAlgorithm().jceId);
+ SecretKey secretKey = new SecretKeySpec(keySpec, header.getCipherAlgorithm().jceId);
setSecretKey(secretKey);
/*
@@ -196,17 +197,17 @@ public class AgileEncryptor extends Encryptor implements Cloneable { this.integritySalt = integritySalt.clone();
try {
- byte vec[] = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityKeyBlock, header.getBlockSize());
- Cipher cipher = getCipher(secretKey, ver.getCipherAlgorithm(), ver.getChainingMode(), vec, Cipher.ENCRYPT_MODE);
- byte filledSalt[] = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
- byte encryptedHmacKey[] = cipher.doFinal(filledSalt);
+ byte vec[] = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, header.getBlockSize());
+ Cipher cipher = getCipher(secretKey, header.getCipherAlgorithm(), header.getChainingMode(), vec, Cipher.ENCRYPT_MODE);
+ byte hmacKey[] = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
+ byte encryptedHmacKey[] = cipher.doFinal(hmacKey);
header.setEncryptedHmacKey(encryptedHmacKey);
cipher = Cipher.getInstance("RSA");
for (AgileCertificateEntry ace : ver.getCertificates()) {
cipher.init(Cipher.ENCRYPT_MODE, ace.x509.getPublicKey());
ace.encryptedKey = cipher.doFinal(getSecretKey().getEncoded());
- Mac x509Hmac = CryptoFunctions.getMac(hashAlgo);
+ Mac x509Hmac = CryptoFunctions.getMac(header.getHashAlgorithm());
x509Hmac.init(getSecretKey());
ace.certVerifier = x509Hmac.doFinal(ace.x509.getEncoded());
}
@@ -236,10 +237,12 @@ public class AgileEncryptor extends Encryptor implements Cloneable { // as the integrity hmac needs to contain the StreamSize,
// it's not possible to calculate it on-the-fly while buffering
// TODO: add stream size parameter to getDataStream()
- AgileEncryptionVerifier ver = (AgileEncryptionVerifier)getEncryptionInfo().getVerifier();
- HashAlgorithm hashAlgo = ver.getHashAlgorithm();
+ AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
+ int blockSize = header.getBlockSize();
+ HashAlgorithm hashAlgo = header.getHashAlgorithm();
Mac integrityMD = CryptoFunctions.getMac(hashAlgo);
- integrityMD.init(new SecretKeySpec(integritySalt, hashAlgo.jceHmacId));
+ byte hmacKey[] = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
+ integrityMD.init(new SecretKeySpec(hmacKey, hashAlgo.jceHmacId));
byte buf[] = new byte[1024];
LittleEndian.putLong(buf, 0, oleStreamSize);
@@ -256,12 +259,10 @@ public class AgileEncryptor extends Encryptor implements Cloneable { }
byte hmacValue[] = integrityMD.doFinal();
+ byte hmacValueFilled[] = getBlock0(hmacValue, getNextBlockSize(hmacValue.length, blockSize));
- AgileEncryptionHeader header = (AgileEncryptionHeader)getEncryptionInfo().getHeader();
- int blockSize = header.getBlockSize();
- byte iv[] = CryptoFunctions.generateIv(header.getHashAlgorithmEx(), header.getKeySalt(), kIntegrityValueBlock, blockSize);
+ byte iv[] = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityValueBlock, blockSize);
Cipher cipher = CryptoFunctions.getCipher(getSecretKey(), header.getCipherAlgorithm(), header.getChainingMode(), iv, Cipher.ENCRYPT_MODE);
- byte hmacValueFilled[] = getBlock0(hmacValue, getNextBlockSize(hmacValue.length, blockSize));
byte encryptedHmacValue[] = cipher.doFinal(hmacValueFilled);
header.setEncryptedHmacValue(encryptedHmacValue);
@@ -288,18 +289,21 @@ public class AgileEncryptor extends Encryptor implements Cloneable { keyPass.setSpinCount(ver.getSpinCount());
keyData.setSaltSize(header.getBlockSize());
- keyPass.setSaltSize(header.getBlockSize());
+ keyPass.setSaltSize(ver.getBlockSize());
keyData.setBlockSize(header.getBlockSize());
- keyPass.setBlockSize(header.getBlockSize());
+ keyPass.setBlockSize(ver.getBlockSize());
keyData.setKeyBits(header.getKeySize());
- keyPass.setKeyBits(header.getKeySize());
+ keyPass.setKeyBits(ver.getKeySize());
- HashAlgorithm hashAlgo = header.getHashAlgorithmEx();
- keyData.setHashSize(hashAlgo.hashSize);
- keyPass.setHashSize(hashAlgo.hashSize);
+ keyData.setHashSize(header.getHashAlgorithm().hashSize);
+ keyPass.setHashSize(ver.getHashAlgorithm().hashSize);
+ // header and verifier have to have the same cipher algorithm
+ if (!header.getCipherAlgorithm().xmlId.equals(ver.getCipherAlgorithm().xmlId)) {
+ throw new EncryptedDocumentException("Cipher algorithm of header and verifier have to match");
+ }
STCipherAlgorithm.Enum xmlCipherAlgo = STCipherAlgorithm.Enum.forString(header.getCipherAlgorithm().xmlId);
if (xmlCipherAlgo == null) {
throw new EncryptedDocumentException("CipherAlgorithm "+header.getCipherAlgorithm()+" not supported.");
@@ -320,12 +324,8 @@ public class AgileEncryptor extends Encryptor implements Cloneable { throw new EncryptedDocumentException("ChainingMode "+header.getChainingMode()+" not supported.");
}
- STHashAlgorithm.Enum xmlHashAlgo = STHashAlgorithm.Enum.forString(hashAlgo.ecmaString);
- if (xmlHashAlgo == null) {
- throw new EncryptedDocumentException("HashAlgorithm "+hashAlgo+" not supported.");
- }
- keyData.setHashAlgorithm(xmlHashAlgo);
- keyPass.setHashAlgorithm(xmlHashAlgo);
+ keyData.setHashAlgorithm(mapHashAlgorithm(header.getHashAlgorithm()));
+ keyPass.setHashAlgorithm(mapHashAlgorithm(ver.getHashAlgorithm()));
keyData.setSaltValue(header.getKeySalt());
keyPass.setSaltValue(ver.getSalt());
@@ -352,6 +352,14 @@ public class AgileEncryptor extends Encryptor implements Cloneable { return ed;
}
+
+ private static STHashAlgorithm.Enum mapHashAlgorithm(HashAlgorithm hashAlgo) {
+ STHashAlgorithm.Enum xmlHashAlgo = STHashAlgorithm.Enum.forString(hashAlgo.ecmaString);
+ if (xmlHashAlgo == null) {
+ throw new EncryptedDocumentException("HashAlgorithm "+hashAlgo+" not supported.");
+ }
+ return xmlHashAlgo;
+ }
protected void marshallEncryptionDocument(EncryptionDocument ed, LittleEndianByteArrayOutputStream os) {
XmlOptions xo = new XmlOptions();
@@ -371,7 +379,7 @@ public class AgileEncryptor extends Encryptor implements Cloneable { try {
bos.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n".getBytes("UTF-8"));
ed.save(bos, xo);
- os.write(bos.toByteArray());
+ bos.writeTo(os);
} catch (IOException e) {
throw new EncryptedDocumentException("error marshalling encryption info document", e);
}
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java index d2260dc998..19dc34b84e 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java @@ -37,10 +37,6 @@ import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.XSSFTestDataSamples;
import org.junit.Test;
-/**
- * @author Maxim Valyanskiy
- * @author Gary King
- */
public class TestDecryptor {
@Test
public void passwordVerification() throws IOException, GeneralSecurityException {
@@ -162,4 +158,22 @@ public class TestDecryptor { //dec.verifyPassword(null);
dec.getDataStream(pfs);
}
+
+ @Test
+ public void bug60320() throws IOException, GeneralSecurityException {
+ InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
+ POIFSFileSystem fs = new POIFSFileSystem(is);
+ is.close();
+
+ EncryptionInfo info = new EncryptionInfo(fs);
+
+ Decryptor d = Decryptor.getInstance(info);
+
+ boolean b = d.verifyPassword("Test001!!");
+ assertTrue(b);
+
+ zipOk(fs.getRoot(), d);
+
+ fs.close();
+ }
}
\ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java index 3227334429..204c2ed621 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptionInfo.java @@ -35,7 +35,7 @@ public class TestEncryptionInfo { assertEquals(2, info.getVersionMinor());
assertEquals(CipherAlgorithm.aes128, info.getHeader().getCipherAlgorithm());
- assertEquals(HashAlgorithm.sha1, info.getHeader().getHashAlgorithmEx());
+ assertEquals(HashAlgorithm.sha1, info.getHeader().getHashAlgorithm());
assertEquals(128, info.getHeader().getKeySize());
assertEquals(32, info.getVerifier().getEncryptedVerifierHash().length);
assertEquals(CipherProvider.aes, info.getHeader().getCipherProvider());
@@ -54,7 +54,7 @@ public class TestEncryptionInfo { assertEquals(4, info.getVersionMinor());
assertEquals(CipherAlgorithm.aes256, info.getHeader().getCipherAlgorithm());
- assertEquals(HashAlgorithm.sha512, info.getHeader().getHashAlgorithmEx());
+ assertEquals(HashAlgorithm.sha512, info.getHeader().getHashAlgorithm());
assertEquals(256, info.getHeader().getKeySize());
assertEquals(64, info.getVerifier().getEncryptedVerifierHash().length);
assertEquals(CipherProvider.aes, info.getHeader().getCipherProvider());
diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java index 02e021d7d8..f3e6c97e4c 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestEncryptor.java @@ -36,7 +36,9 @@ import javax.crypto.Cipher; import org.apache.poi.POIDataSamples;
import org.apache.poi.openxml4j.opc.ContentTypes;
import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.poifs.crypt.agile.AgileDecryptor;
import org.apache.poi.poifs.crypt.agile.AgileEncryptionHeader;
+import org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentNode;
import org.apache.poi.poifs.filesystem.Entry;
@@ -87,7 +89,7 @@ public class TestEncryptor { assertArrayEquals(payloadExpected.toByteArray(), payloadActual.toByteArray());
}
-
+
@Test
public void agileEncryption() throws Exception {
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
@@ -379,4 +381,142 @@ public class TestEncryptor { }
}
}
+
+ /*
+ * this test simulates the generation of bugs 60320 sample file
+ * as the padding bytes of the EncryptedPackage stream are random or in POIs case PKCS5-padded
+ * one would need to mock those bytes to get the same hmacValues - see diff below
+ *
+ * this use-case is experimental - for the time being the setters of the encryption classes
+ * are spreaded between two packages and are protected - so you would need to violate
+ * the packages rules and provide a helper class in the *poifs.crypt package-namespace.
+ * the default way of defining the encryption settings is via the EncryptionInfo class
+ */
+ @Test
+ public void bug60320CustomEncrypt() throws Exception {
+ // --- src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java (revision 1766745)
+ // +++ src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java (working copy)
+ // @@ -208,6 +208,13 @@
+ // protected int invokeCipher(int posInChunk, boolean doFinal) throws GeneralSecurityException {
+ // byte plain[] = (_plainByteFlags.isEmpty()) ? null : _chunk.clone();
+ //
+ // + if (posInChunk < 4096) {
+ // + _cipher.update(_chunk, 0, posInChunk, _chunk);
+ // + byte bla[] = { (byte)0x7A,(byte)0x0F,(byte)0x27,(byte)0xF0,(byte)0x17,(byte)0x6E,(byte)0x77,(byte)0x05,(byte)0xB9,(byte)0xDA,(byte)0x49,(byte)0xF9,(byte)0xD7,(byte)0x8E,(byte)0x03,(byte)0x1D };
+ // + System.arraycopy(bla, 0, _chunk, posInChunk-2, bla.length);
+ // + return posInChunk-2+bla.length;
+ // + }
+ // +
+ // int ciLen = (doFinal)
+ // ? _cipher.doFinal(_chunk, 0, posInChunk, _chunk)
+ // : _cipher.update(_chunk, 0, posInChunk, _chunk);
+ //
+ // --- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (revision 1766745)
+ // +++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java (working copy)
+ //
+ // @@ -300,7 +297,7 @@
+ // protected static Cipher initCipherForBlock(Cipher existing, int block, boolean lastChunk, EncryptionInfo encryptionInfo, SecretKey skey, int encryptionMode)
+ // throws GeneralSecurityException {
+ // EncryptionHeader header = encryptionInfo.getHeader();
+ // - String padding = (lastChunk ? "PKCS5Padding" : "NoPadding");
+ // + String padding = "NoPadding"; // (lastChunk ? "PKCS5Padding" : "NoPadding");
+ // if (existing == null || !existing.getAlgorithm().endsWith(padding)) {
+ // existing = getCipher(skey, header.getCipherAlgorithm(), header.getChainingMode(), header.getKeySalt(), encryptionMode, padding);
+ // }
+
+ InputStream is = POIDataSamples.getPOIFSInstance().openResourceAsStream("60320-protected.xlsx");
+ POIFSFileSystem fsOrig = new POIFSFileSystem(is);
+ is.close();
+ EncryptionInfo infoOrig = new EncryptionInfo(fsOrig);
+ Decryptor decOrig = infoOrig.getDecryptor();
+ boolean b = decOrig.verifyPassword("Test001!!");
+ assertTrue(b);
+ InputStream decIn = decOrig.getDataStream(fsOrig);
+ byte[] zipInput = IOUtils.toByteArray(decIn);
+ decIn.close();
+
+ InputStream epOrig = fsOrig.getRoot().createDocumentInputStream("EncryptedPackage");
+ // ignore the 16 padding bytes
+ byte[] epOrigBytes = IOUtils.toByteArray(epOrig, 9400);
+ epOrig.close();
+
+ EncryptionInfo eiNew = new EncryptionInfo(EncryptionMode.agile);
+ AgileEncryptionHeader aehHeader = (AgileEncryptionHeader)eiNew.getHeader();
+ aehHeader.setCipherAlgorithm(CipherAlgorithm.aes128);
+ aehHeader.setHashAlgorithm(HashAlgorithm.sha1);
+ AgileEncryptionVerifier aehVerifier = (AgileEncryptionVerifier)eiNew.getVerifier();
+
+ // this cast might look strange - if the setters would be public, it will become obsolete
+ // see http://stackoverflow.com/questions/5637650/overriding-protected-methods-in-java
+ ((EncryptionVerifier)aehVerifier).setCipherAlgorithm(CipherAlgorithm.aes256);
+ aehVerifier.setHashAlgorithm(HashAlgorithm.sha512);
+
+ Encryptor enc = eiNew.getEncryptor();
+ enc.confirmPassword("Test001!!",
+ infoOrig.getDecryptor().getSecretKey().getEncoded(),
+ infoOrig.getHeader().getKeySalt(),
+ infoOrig.getDecryptor().getVerifier(),
+ infoOrig.getVerifier().getSalt(),
+ infoOrig.getDecryptor().getIntegrityHmacKey()
+ );
+ NPOIFSFileSystem fsNew = new NPOIFSFileSystem();
+ OutputStream os = enc.getDataStream(fsNew);
+ os.write(zipInput);
+ os.close();
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ fsNew.writeFilesystem(bos);
+ fsNew.close();
+
+ NPOIFSFileSystem fsReload = new NPOIFSFileSystem(new ByteArrayInputStream(bos.toByteArray()));
+ InputStream epReload = fsReload.getRoot().createDocumentInputStream("EncryptedPackage");
+ byte[] epNewBytes = IOUtils.toByteArray(epReload, 9400);
+ epReload.close();
+
+ assertArrayEquals(epOrigBytes, epNewBytes);
+
+ EncryptionInfo infoReload = new EncryptionInfo(fsOrig);
+ Decryptor decReload = infoReload.getDecryptor();
+ b = decReload.verifyPassword("Test001!!");
+ assertTrue(b);
+
+ AgileEncryptionHeader aehOrig = (AgileEncryptionHeader)infoOrig.getHeader();
+ AgileEncryptionHeader aehReload = (AgileEncryptionHeader)infoReload.getHeader();
+ assertEquals(aehOrig.getBlockSize(), aehReload.getBlockSize());
+ assertEquals(aehOrig.getChainingMode(), aehReload.getChainingMode());
+ assertEquals(aehOrig.getCipherAlgorithm(), aehReload.getCipherAlgorithm());
+ assertEquals(aehOrig.getCipherProvider(), aehReload.getCipherProvider());
+ assertEquals(aehOrig.getCspName(), aehReload.getCspName());
+ assertArrayEquals(aehOrig.getEncryptedHmacKey(), aehReload.getEncryptedHmacKey());
+ // this only works, when the paddings are mocked to be the same ...
+ // assertArrayEquals(aehOrig.getEncryptedHmacValue(), aehReload.getEncryptedHmacValue());
+ assertEquals(aehOrig.getFlags(), aehReload.getFlags());
+ assertEquals(aehOrig.getHashAlgorithm(), aehReload.getHashAlgorithm());
+ assertArrayEquals(aehOrig.getKeySalt(), aehReload.getKeySalt());
+ assertEquals(aehOrig.getKeySize(), aehReload.getKeySize());
+
+ AgileEncryptionVerifier aevOrig = (AgileEncryptionVerifier)infoOrig.getVerifier();
+ AgileEncryptionVerifier aevReload = (AgileEncryptionVerifier)infoReload.getVerifier();
+ assertEquals(aevOrig.getBlockSize(), aevReload.getBlockSize());
+ assertEquals(aevOrig.getChainingMode(), aevReload.getChainingMode());
+ assertEquals(aevOrig.getCipherAlgorithm(), aevReload.getCipherAlgorithm());
+ assertArrayEquals(aevOrig.getEncryptedKey(), aevReload.getEncryptedKey());
+ assertArrayEquals(aevOrig.getEncryptedVerifier(), aevReload.getEncryptedVerifier());
+ assertArrayEquals(aevOrig.getEncryptedVerifierHash(), aevReload.getEncryptedVerifierHash());
+ assertEquals(aevOrig.getHashAlgorithm(), aevReload.getHashAlgorithm());
+ assertEquals(aevOrig.getKeySize(), aevReload.getKeySize());
+ assertArrayEquals(aevOrig.getSalt(), aevReload.getSalt());
+ assertEquals(aevOrig.getSpinCount(), aevReload.getSpinCount());
+
+ AgileDecryptor adOrig = (AgileDecryptor)infoOrig.getDecryptor();
+ AgileDecryptor adReload = (AgileDecryptor)infoReload.getDecryptor();
+
+ assertArrayEquals(adOrig.getIntegrityHmacKey(), adReload.getIntegrityHmacKey());
+ // doesn't work without mocking ... see above
+ // assertArrayEquals(adOrig.getIntegrityHmacValue(), adReload.getIntegrityHmacValue());
+ assertArrayEquals(adOrig.getSecretKey().getEncoded(), adReload.getSecretKey().getEncoded());
+ assertArrayEquals(adOrig.getVerifier(), adReload.getVerifier());
+
+ fsReload.close();
+ }
}
diff --git a/test-data/poifs/60320-protected.xlsx b/test-data/poifs/60320-protected.xlsx Binary files differnew file mode 100644 index 0000000000..71c6b4cbe8 --- /dev/null +++ b/test-data/poifs/60320-protected.xlsx |