ASF Bugzilla – Attachment 34410 Details for
Bug 60320
issue opening password protected xlsx
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
preliminary patch for decrypting
encryption.diff (text/plain), 14.57 KB, created by
Andreas Beeker
on 2016-10-29 21:28:12 UTC
(
hide
)
Description:
preliminary patch for decrypting
Filename:
MIME Type:
Creator:
Andreas Beeker
Created:
2016-10-29 21:28:12 UTC
Size:
14.57 KB
patch
obsolete
>Index: src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java >=================================================================== >--- src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java (revision 1766745) >+++ src/java/org/apache/poi/poifs/crypt/EncryptionHeader.java (working copy) >@@ -16,6 +16,8 @@ > ==================================================================== */ > package org.apache.poi.poifs.crypt; > >+import org.apache.poi.util.Removal; >+ > /** > * Reads and processes OOXML Encryption Headers > * The constants are largely based on ZIP constants. >@@ -83,7 +85,15 @@ > protected void setCipherAlgorithm(CipherAlgorithm cipherAlgorithm) { > this.cipherAlgorithm = cipherAlgorithm; > } >+ >+ public HashAlgorithm getHashAlgorithm() { >+ return hashAlgorithm; >+ } > >+ /** >+ * @deprecated POI 3.16 beta 1. use {@link #getHashAlgorithm()} >+ */ >+ @Removal(version="3.18") > public HashAlgorithm getHashAlgorithmEx() { > return hashAlgorithm; > } >Index: src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileDecryptor.java >=================================================================== >--- 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) >@@ -40,6 +40,7 @@ > 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; >@@ -93,11 +94,11 @@ > 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; >+ HashAlgorithm hashAlgo = ver.getHashAlgorithm(); > >+ int keySize = (ver.getKeySize() == -1 ? header.getKeySize() : ver.getKeySize())/8; >+ int blockSize = (ver.getBlockSize() == -1 ? header.getBlockSize() : ver.getBlockSize()); >+ > byte[] pwHash = hashPassword(password, ver.getHashAlgorithm(), ver.getSalt(), ver.getSpinCount()); > > /** >@@ -113,7 +114,7 @@ > * 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); > byte[] verifierHash = hashMD.digest(verfierInputEnc); >@@ -130,7 +131,7 @@ > * 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); >+ byte verifierHashDec[] = hashInput(ver, pwHash, kHashedVerifierBlock, ver.getEncryptedVerifierHash(), Cipher.DECRYPT_MODE); > verifierHashDec = getBlock0(verifierHashDec, hashAlgo.hashSize); > > /** >@@ -146,7 +147,7 @@ > * blockSize bytes. > * 4. Use base64 to encode the result of step 3. > */ >- byte keyspec[] = hashInput(getEncryptionInfo(), pwHash, kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE); >+ byte keyspec[] = hashInput(header, pwHash, kCryptoKeyBlock, ver.getEncryptedKey(), Cipher.DECRYPT_MODE); > keyspec = getBlock0(keyspec, keySize); > SecretKeySpec secretKey = new SecretKeySpec(keyspec, ver.getCipherAlgorithm().jceId); > >@@ -163,8 +164,9 @@ > * 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(hashAlgo, header.getKeySalt(), kIntegrityKeyBlock, blockSize); >+ CipherAlgorithm cipherAlgo = ver.getCipherAlgorithm(); >+ Cipher cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE); > byte hmacKey[] = cipher.doFinal(header.getEncryptedHmacKey()); > hmacKey = getBlock0(hmacKey, hashAlgo.hashSize); > >@@ -257,18 +259,18 @@ > 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(); >- HashAlgorithm hashAlgo = ver.getHashAlgorithm(); >- byte[] salt = ver.getSalt(); >- >+ /* package */ static byte[] hashInput(AgileEncryptionConfig aec, byte pwHash[], byte blockKey[], byte inputKey[], int cipherMode) { >+ int keySize = aec.getKeySize()/8; >+ int blockSize = aec.getBlockSize(); >+ byte salt[] = aec.getSalt(); >+ HashAlgorithm hashAlgo = aec.getHashAlgorithm(); >+ CipherAlgorithm cipherAlgo = aec.getCipherAlgorithm(); >+ ChainingMode chainMode = aec.getChainingMode(); >+ > byte intermedKey[] = generateKey(pwHash, hashAlgo, blockKey, keySize); >- SecretKey skey = new SecretKeySpec(intermedKey, ver.getCipherAlgorithm().jceId); >+ SecretKey skey = new SecretKeySpec(intermedKey, cipherAlgo.jceId); > byte[] iv = generateIv(hashAlgo, salt, null, blockSize); >- Cipher cipher = getCipher(skey, ver.getCipherAlgorithm(), ver.getChainingMode(), iv, cipherMode); >+ Cipher cipher = getCipher(skey, cipherAlgo, chainMode, iv, cipherMode); > byte[] hashFinal; > > try { >Index: src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionConfig.java >=================================================================== >--- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionConfig.java (nonexistent) >+++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionConfig.java (working copy) >@@ -0,0 +1,19 @@ >+package org.apache.poi.poifs.crypt.agile; >+ >+import org.apache.poi.poifs.crypt.ChainingMode; >+import org.apache.poi.poifs.crypt.CipherAlgorithm; >+import org.apache.poi.poifs.crypt.HashAlgorithm; >+import org.apache.poi.util.Internal; >+ >+/** >+ * A internal interface to provide the common config of header and verifier >+ */ >+@Internal >+/* package */ interface AgileEncryptionConfig { >+ int getKeySize(); >+ int getBlockSize(); >+ byte[] getSalt(); >+ CipherAlgorithm getCipherAlgorithm(); >+ HashAlgorithm getHashAlgorithm(); >+ ChainingMode getChainingMode(); >+} > >Property changes on: src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionConfig.java >___________________________________________________________________ >Added: svn:eol-style >## -0,0 +1 ## >+native >\ No newline at end of property >Index: src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java >=================================================================== >--- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java (revision 1766745) >+++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionHeader.java (working copy) >@@ -27,7 +27,7 @@ > import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument; > import com.microsoft.schemas.office.x2006.encryption.STCipherChaining; > >-public class AgileEncryptionHeader extends EncryptionHeader implements Cloneable { >+public class AgileEncryptionHeader extends EncryptionHeader implements Cloneable, AgileEncryptionConfig { > private byte encryptedHmacKey[], encryptedHmacValue[]; > > public AgileEncryptionHeader(String descriptor) { >@@ -98,6 +98,10 @@ > setChainingMode(chainingMode); > } > >+ public byte[] getSalt() { >+ return getKeySalt(); >+ } >+ > // make method visible for this package > @Override > protected void setKeySalt(byte salt[]) { >Index: src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java >=================================================================== >--- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java (revision 1766745) >+++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptionVerifier.java (working copy) >@@ -39,7 +39,7 @@ > /** > * Used when checking if a key is valid for a document > */ >-public class AgileEncryptionVerifier extends EncryptionVerifier implements Cloneable { >+public class AgileEncryptionVerifier extends EncryptionVerifier implements Cloneable, AgileEncryptionConfig { > > public static class AgileCertificateEntry { > X509Certificate x509; >@@ -48,6 +48,8 @@ > } > > private List<AgileCertificateEntry> certList = new ArrayList<AgileCertificateEntry>(); >+ private int keyBits = -1; >+ private int blockSize = -1; > > public AgileEncryptionVerifier(String descriptor) { > this(AgileEncryptionInfoBuilder.parseDescriptor(descriptor)); >@@ -66,7 +68,11 @@ > } > > int keyBits = (int)keyData.getKeyBits(); >+ setKeySize(keyBits); > >+ int blockSize = keyData.getBlockSize(); >+ setBlockSize(blockSize); >+ > CipherAlgorithm ca = CipherAlgorithm.fromXmlId(keyData.getCipherAlgorithm().toString(), keyBits); > setCipherAlgorithm(ca); > >@@ -125,6 +131,8 @@ > setCipherAlgorithm(cipherAlgorithm); > setHashAlgorithm(hashAlgorithm); > setChainingMode(chainingMode); >+ setKeySize(keyBits); >+ setBlockSize(blockSize); > setSpinCount(100000); // TODO: use parameter > } > >@@ -171,4 +179,47 @@ > 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. if {@code -1}, the keysize hasn't been set, >+ * i.e. the keysize of the header has to be used >+ */ >+ 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, if {@code -1}, the blockSize hasn't been set, >+ * i.e. the blockSize of the header has to be used >+ */ >+ public int getBlockSize() { >+ return blockSize; >+ } >+ >+ /** >+ * Sets the keysize (in bits) of the verifier >+ * >+ * @param keyBits the keysize (in bits), use {@code -1} to unset it >+ */ >+ protected void setKeySize(int keyBits) { >+ this.keyBits = keyBits; >+ } >+ >+ >+ /** >+ * Sets the blockSize (in bytes) of the verifier >+ * >+ * @param blockSize the blockSize (in bytes), use {@code -1} to unset it >+ */ >+ protected void setBlockSize(int blockSize) { >+ this.blockSize = blockSize; >+ } > } >Index: src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java >=================================================================== >--- src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java (revision 1766745) >+++ src/ooxml/java/org/apache/poi/poifs/crypt/agile/AgileEncryptor.java (working copy) >@@ -129,7 +129,7 @@ > * 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); > > >@@ -147,7 +147,7 @@ > */ > MessageDigest hashMD = getMessageDigest(hashAlgo); > 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,7 +163,7 @@ > * 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(header, pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE); > ver.setEncryptedKey(encryptedKey); > > SecretKey secretKey = new SecretKeySpec(keySpec, ver.getCipherAlgorithm().jceId); >Index: src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java >=================================================================== >--- src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java (revision 1766745) >+++ src/ooxml/testcases/org/apache/poi/poifs/crypt/TestDecryptor.java (working copy) >@@ -37,12 +37,22 @@ > import org.apache.poi.xssf.XSSFTestDataSamples; > import org.junit.Test; > >-/** >- * @author Maxim Valyanskiy >- * @author Gary King >- */ > public class TestDecryptor { > @Test >+ public void decrypt2() throws IOException, GeneralSecurityException { >+ POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream("TestThisEncryption.xlsx")); >+ >+ EncryptionInfo info = new EncryptionInfo(fs); >+ >+ Decryptor d = Decryptor.getInstance(info); >+ >+ boolean b = d.verifyPassword("Test001!!"); >+ assertTrue(b); >+ >+ zipOk(fs.getRoot(), d); >+ } >+ >+ @Test > public void passwordVerification() throws IOException, GeneralSecurityException { > POIFSFileSystem fs = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx")); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 60320
:
34408
| 34410