summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <quikee@gmail.com>2013-08-15 17:11:04 +0200
committerTomaž Vajngerl <quikee@gmail.com>2013-08-15 17:18:20 +0200
commit0566ddb1841ac1e8c87db6d766739e6df7e1856d (patch)
treef3922668f24cfaef7d069f6a96b747bb92105253
parentef947839c9e6e5e86e11f7a7cbf13470010ca48f (diff)
Move OOXML decryption to DocumentCrypt.
OOXML decryption was implemented in filterdetect. With this the decryption was moved to a common place where it shares functions and constants with encryption. Change-Id: Id334daf7c2eb1e18735d6a500132f6bb61bb3ba0
-rw-r--r--include/oox/core/DocumentCrypt.hxx95
-rw-r--r--oox/source/core/DocumentCrypt.cxx564
-rw-r--r--oox/source/core/filterdetect.cxx515
3 files changed, 528 insertions, 646 deletions
diff --git a/include/oox/core/DocumentCrypt.hxx b/include/oox/core/DocumentCrypt.hxx
index 30102365f59d..9831c190fdcf 100644
--- a/include/oox/core/DocumentCrypt.hxx
+++ b/include/oox/core/DocumentCrypt.hxx
@@ -23,11 +23,77 @@
#include "oox/dllapi.h"
#include "oox/ole/olestorage.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/binaryoutputstream.hxx"
+
#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <vector>
+
namespace oox {
namespace core {
+const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
+const sal_uInt32 ENCRYPTINFO_DOCPROPS = 0x00000008;
+const sal_uInt32 ENCRYPTINFO_EXTERNAL = 0x00000010;
+const sal_uInt32 ENCRYPTINFO_AES = 0x00000020;
+
+const sal_uInt32 ENCRYPT_ALGO_AES128 = 0x0000660E;
+const sal_uInt32 ENCRYPT_ALGO_AES192 = 0x0000660F;
+const sal_uInt32 ENCRYPT_ALGO_AES256 = 0x00006610;
+const sal_uInt32 ENCRYPT_ALGO_RC4 = 0x00006801;
+
+const sal_uInt32 ENCRYPT_HASH_SHA1 = 0x00008004;
+
+const sal_uInt32 ENCRYPT_KEY_SIZE_AES_128 = 0x00000080;
+const sal_uInt32 ENCRYPT_KEY_SIZE_AES_192 = 0x000000C0;
+const sal_uInt32 ENCRYPT_KEY_SIZE_AES_256 = 0x00000100;
+
+const sal_uInt32 ENCRYPT_PROVIDER_TYPE_AES = 0x00000018;
+const sal_uInt32 ENCRYPT_PROVIDER_TYPE_RC4 = 0x00000001;
+
+// version of encryption info used in MS Office 2007 (major = 3, minor = 2)
+const sal_uInt32 VERSION_INFO_2007_FORMAT = 0x00030002;
+
+const sal_Int32 SALT_LENGTH = 16;
+const sal_Int32 ENCRYPTED_VERIFIER_LENGTH = 16;
+const sal_Int32 ENCRYPTED_VERIFIER_HASH_LENGTH = 32;
+
+struct EncryptionStandardHeader
+{
+ sal_uInt32 flags;
+ sal_uInt32 sizeExtra; // 0
+ sal_uInt32 algId; // if flag AES && CRYPTOAPI this defaults to 128-bit AES
+ sal_uInt32 algIdHash; // 0: determine by flags - defaults to SHA-1 if not external
+ sal_uInt32 keySize; // key size in bits: 0 (determine by flags), 128, 192, 256
+ sal_uInt32 providedType; // AES or RC4
+ sal_uInt32 reserved1; // 0
+ sal_uInt32 reserved2; // 0
+
+ EncryptionStandardHeader();
+};
+
+
+struct EncryptionVerifierAES
+{
+ sal_uInt32 saltSize; // must be 0x00000010
+ sal_uInt8 salt[SALT_LENGTH]; // random generated salt value
+ sal_uInt8 encryptedVerifier[ENCRYPTED_VERIFIER_LENGTH]; // randomly generated verifier value
+ sal_uInt32 encryptedVerifierHashSize; // actually written hash size - depends on algorithm
+ sal_uInt8 encryptedVerifierHash[ENCRYPTED_VERIFIER_HASH_LENGTH]; // verifier value hash - itself also encrypted
+
+ EncryptionVerifierAES();
+};
+
+struct PackageEncryptionInfo
+{
+ EncryptionStandardHeader header;
+ EncryptionVerifierAES verifier;
+};
+
class OOX_DLLPUBLIC AesEncoder
{
private:
@@ -35,6 +101,11 @@ private:
oox::ole::OleStorage& mrOleStorage;
OUString maPassword;
+ PackageEncryptionInfo mEncryptionInfo;
+
+ bool checkEncryptionInfo(std::vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength);
+ bool writeEncryptionInfo( BinaryOutputStream& rStream );
+
public:
AesEncoder(
com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream,
@@ -42,8 +113,32 @@ public:
OUString aPassword);
bool encode();
+
};
+class OOX_DLLPUBLIC AesDecoder
+{
+private:
+ oox::ole::OleStorage& mrOleStorage;
+ PackageEncryptionInfo mEncryptionInfo;
+ std::vector<sal_uInt8> mKey;
+ sal_uInt32 mKeyLength;
+
+ bool readEncryptionInfoFromStream( BinaryInputStream& rStream );
+
+public:
+ AesDecoder(oox::ole::OleStorage& rOleStorage);
+
+ bool decode(com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream);
+ bool readEncryptionInfo();
+ bool generateEncryptionKey(const OUString& rPassword);
+
+ com::sun::star::uno::Sequence< com::sun::star::beans::NamedValue > createEncryptionData();
+
+ bool checkCurrentEncryptionData();
+
+ static bool checkEncryptionData( const com::sun::star::uno::Sequence< com::sun::star::beans::NamedValue >& rEncryptionData );
+};
} // namespace core
} // namespace oox
diff --git a/oox/source/core/DocumentCrypt.cxx b/oox/source/core/DocumentCrypt.cxx
index 9ec9f8d54ee7..ac0b255b1703 100644
--- a/oox/source/core/DocumentCrypt.cxx
+++ b/oox/source/core/DocumentCrypt.cxx
@@ -11,8 +11,6 @@
#include "oox/core/DocumentCrypt.hxx"
#include <config_oox.h>
-#include <comphelper/docpasswordhelper.hxx>
-#include <comphelper/mediadescriptor.hxx>
#if USE_TLS_OPENSSL
#include <openssl/evp.h>
#endif // USE_TLS_OPENSSL
@@ -21,8 +19,9 @@
#include <pk11pub.h>
#endif // USE_TLS_NSS
#include <rtl/digest.h>
-#include "oox/helper/binaryinputstream.hxx"
-#include "oox/helper/binaryoutputstream.hxx"
+
+#include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/mediadescriptor.hxx>
#include <osl/time.h>
#include <rtl/random.h>
@@ -40,44 +39,14 @@ using namespace ::com::sun::star::uno;
using ::comphelper::MediaDescriptor;
using ::comphelper::SequenceAsHashMap;
+using namespace std;
+
/* =========================================================================== */
/* Kudos to Caolan McNamara who provided the core decryption implementations. */
/* =========================================================================== */
namespace {
-const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
-const sal_uInt32 ENCRYPTINFO_DOCPROPS = 0x00000008;
-const sal_uInt32 ENCRYPTINFO_EXTERNAL = 0x00000010;
-const sal_uInt32 ENCRYPTINFO_AES = 0x00000020;
-
-const sal_uInt32 ENCRYPT_ALGO_AES128 = 0x0000660E;
-const sal_uInt32 ENCRYPT_ALGO_AES192 = 0x0000660F;
-const sal_uInt32 ENCRYPT_ALGO_AES256 = 0x00006610;
-const sal_uInt32 ENCRYPT_ALGO_RC4 = 0x00006801;
-
-const sal_uInt32 ENCRYPT_HASH_SHA1 = 0x00008004;
-
-const sal_uInt32 ENCRYPT_KEY_SIZE_AES_128 = 0x00000080;
-const sal_uInt32 ENCRYPT_KEY_SIZE_AES_192 = 0x000000C0;
-const sal_uInt32 ENCRYPT_KEY_SIZE_AES_256 = 0x00000100;
-
-const sal_uInt32 ENCRYPT_PROVIDER_TYPE_AES = 0x00000018;
-const sal_uInt32 ENCRYPT_PROVIDER_TYPE_RC4 = 0x00000001;
-
-struct PackageEncryptionInfo
-{
- sal_uInt8 mpnSalt[ 16 ];
- sal_uInt8 mpnEncrVerifier[ 16 ];
- sal_uInt8 mpnEncrVerifierHash[ 32 ];
- sal_uInt32 mnFlags;
- sal_uInt32 mnAlgorithmId;
- sal_uInt32 mnAlgorithmIdHash;
- sal_uInt32 mnKeySize;
- sal_uInt32 mnSaltSize;
- sal_uInt32 mnVerifierHashSize;
-};
-
void lclRandomGenerateValues( sal_Int32 nLength, sal_uInt8* aArray )
{
TimeValue aTime;
@@ -88,81 +57,10 @@ void lclRandomGenerateValues( sal_Int32 nLength, sal_uInt8* aArray )
rtl_random_destroyPool ( aRandomPool );
}
-struct EncryptionStandardHeader {
- sal_uInt32 flags;
- sal_uInt32 sizeExtra;
- sal_uInt32 algId; // if flag AES && CRYPTOAPI this defaults to 128-bit AES
- sal_uInt32 algIdHash; // 0 - determined by flags - defaults to SHA-1 if not external
- sal_uInt32 keySize; // 0 - determined by flags, 128, 192, 256 for AES
- sal_uInt32 providedType;
- sal_uInt32 reserved1;
- sal_uInt32 reserved2;
-};
-
-struct EncryptionVerifierAES {
- sal_uInt32 saltSize; // must be 0x00000010
- sal_uInt8 salt[16]; //
- sal_uInt8 encryptedVerifier[16]; // randomly generated verifier value
- sal_uInt32 verifierHashSize;
- sal_uInt8 encryptedVerifierHash[32];
-};
-
-bool lclWriteEncryptionInfo( PackageEncryptionInfo& rEncrInfo, BinaryOutputStream& rStream )
-{
- const sal_uInt16 versionInfoMajor = 0x003;
- const sal_uInt16 versionInfoMinor = 0x002;
-
- rStream.writeValue(versionInfoMajor);
- rStream.writeValue(versionInfoMinor);
-
- const OUString cspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
- sal_Int32 cspNameSize = (cspName.getLength() * 2) + 2;
-
- EncryptionStandardHeader encryptionHeader;
- sal_Int32 encryptionHeaderSize = static_cast<sal_Int32>(sizeof(EncryptionStandardHeader));
- memset(&encryptionHeader, 0, encryptionHeaderSize);
-
- EncryptionVerifierAES encryptionVerifier;
- sal_Int32 encryptionVerifierSize = static_cast<sal_Int32>(sizeof(EncryptionVerifierAES));
- memset(&encryptionVerifier, 0, encryptionVerifierSize);
-
- rStream << rEncrInfo.mnFlags;
-
- sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
- rStream << headerSize;
-
- encryptionHeader.flags = rEncrInfo.mnFlags;
- encryptionHeader.algId = rEncrInfo.mnAlgorithmId;
- encryptionHeader.algIdHash = rEncrInfo.mnAlgorithmIdHash;
- encryptionHeader.keySize = rEncrInfo.mnKeySize;
- encryptionHeader.providedType = ENCRYPT_PROVIDER_TYPE_AES;
-
- rStream.writeMemory(&encryptionHeader, encryptionHeaderSize);
- rStream.writeUnicodeArray(cspName);
- rStream.writeValue<sal_uInt16>(0);
-
- if (rEncrInfo.mnSaltSize != 16)
- return false;
-
- encryptionVerifier.saltSize = rEncrInfo.mnSaltSize;
-
- memcpy(&encryptionVerifier.salt, rEncrInfo.mpnSalt, 16);
-
- memcpy(&encryptionVerifier.encryptedVerifier, rEncrInfo.mpnEncrVerifier, 16);
-
- encryptionVerifier.verifierHashSize = rEncrInfo.mnVerifierHashSize;
-
- memcpy(encryptionVerifier.encryptedVerifierHash, rEncrInfo.mpnEncrVerifierHash, 32);
-
- rStream.writeMemory(&encryptionVerifier, encryptionVerifierSize);
-
- return true;
-}
-
-void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen )
+void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, vector<sal_uInt8>& rKey, sal_uInt32 aKeyLength )
{
// De facto we are always called with nRequiredKeyLen == 16, at least currently
- assert(nRequiredKeyLen == 16);
+ assert(aKeyLength == 16);
sal_uInt8 pnBuffer[ 64 ];
memset( pnBuffer, 0x36, sizeof( pnBuffer ) );
@@ -187,46 +85,47 @@ void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKe
#if 0 // for now nRequiredKeyLen will always be 16 and thus less than
// RTL_DIGEST_LENGTH_SHA1==20, see assert above...
- if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 )
+ if( aKeyLength > RTL_DIGEST_LENGTH_SHA1 )
{
// This memcpy call generates a (bogus?) warning when
// compiling with gcc 4.7 and 4.8 and optimising: array
// subscript is above array bounds.
- memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 );
- nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1;
+ std::copy(pnX1, pnX1 + aKeyLength - RTL_DIGEST_LENGTH_SHA1, rKey.begin() + RTL_DIGEST_LENGTH_SHA1);
+ aKeyLength = RTL_DIGEST_LENGTH_SHA1;
}
#endif
- memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
+ std::copy(pnX1, pnX1 + aKeyLength, rKey.begin());
+ //memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
}
-bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const sal_uInt8* pKey, sal_uInt32 nKeySize)
+bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const vector<sal_uInt8>& rKey, sal_uInt32 nKeySize)
{
- bool bResult = false;
-
+ // only support key of size 128 bit (16 byte)
if (nKeySize != 16)
- return bResult;
+ return false;
- sal_uInt8 aVerifier[16];
+ sal_uInt8 aVerifier[ENCRYPTED_VERIFIER_LENGTH];
sal_Int32 aVerifierSize = sizeof(aVerifier);
- memset( aVerifier, 0, aVerifierSize );
lclRandomGenerateValues(aVerifierSize, aVerifier);
#if USE_TLS_OPENSSL
{
EVP_CIPHER_CTX aContext;
EVP_CIPHER_CTX_init( &aContext );
- EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, pKey, 0 );
+ EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, &rKey[0], 0 );
EVP_CIPHER_CTX_set_padding( &aContext, 0 );
- int aEncryptedVerifierSize = 0;
- EVP_EncryptUpdate( &aContext, rEncryptionInfo.mpnEncrVerifier, &aEncryptedVerifierSize, aVerifier, aVerifierSize );
+ int aWrittenLength = 0;
+ EVP_EncryptUpdate( &aContext, rEncryptionInfo.verifier.encryptedVerifier, &aWrittenLength, aVerifier, aVerifierSize );
+ if (aWrittenLength != ENCRYPTED_VERIFIER_LENGTH)
+ return false;
EVP_CIPHER_CTX_cleanup( &aContext );
}
#endif // USE_TLS_OPENSSL
- sal_uInt8 pSha1Hash[ 32 ];
- memset(pSha1Hash, 0, 32);
- rEncryptionInfo.mnVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
+ sal_uInt8 pSha1Hash[ENCRYPTED_VERIFIER_HASH_LENGTH];
+ memset(pSha1Hash, 0, sizeof(pSha1Hash));
+ rEncryptionInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
rtl_digest_update( aDigest, aVerifier, aVerifierSize );
@@ -235,106 +134,95 @@ bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const sal_uInt8
#if USE_TLS_OPENSSL
{
- memset(rEncryptionInfo.mpnEncrVerifierHash, 0, rEncryptionInfo.mnVerifierHashSize);
- int written = 0;
+ int aWrittenLength = 0;
EVP_CIPHER_CTX aContext;
EVP_CIPHER_CTX_init( &aContext );
- EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, pKey, 0 );
+ EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, &rKey[0], 0 );
EVP_CIPHER_CTX_set_padding( &aContext, 0 );
- EVP_EncryptUpdate( &aContext, rEncryptionInfo.mpnEncrVerifierHash, &written, pSha1Hash, 32 );
+ EVP_EncryptUpdate( &aContext, rEncryptionInfo.verifier.encryptedVerifierHash, &aWrittenLength, pSha1Hash, sizeof(pSha1Hash) );
EVP_CIPHER_CTX_cleanup( &aContext );
}
-
#endif // USE_TLS_OPENSSL
- bResult = true;
-
- return bResult;
+ return true;
}
-
bool lclCheckEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize )
{
- bool bResult = false;
-
// the only currently supported algorithm needs key size 128
- if ( nKeySize == 16 && nVerifierSize == 16 )
- {
- // check password
+ if ( nKeySize != 16 || nVerifierSize != 16 )
+ return false;
+
+ // check password
#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX aes_ctx;
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
- int nOutLen = 0;
- sal_uInt8 pnTmpVerifier[ 16 ];
- (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
-
- /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize );
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
- sal_uInt8* pnTmpVerifierHash = new sal_uInt8[nVerifierHashSize];
- (void) memset( pnTmpVerifierHash, 0, nVerifierHashSize );
-
- /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize );
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
+ EVP_CIPHER_CTX aes_ctx;
+ EVP_CIPHER_CTX_init( &aes_ctx );
+ EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
+ EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
+ int nOutLen = 0;
+ sal_uInt8 pnTmpVerifier[ 16 ];
+ (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
+
+ /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize );
+ EVP_CIPHER_CTX_cleanup( &aes_ctx );
+
+ EVP_CIPHER_CTX_init( &aes_ctx );
+ EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
+ EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
+ sal_uInt8* pnTmpVerifierHash = new sal_uInt8[nVerifierHashSize];
+ (void) memset( pnTmpVerifierHash, 0, nVerifierHashSize );
+
+ /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize );
+ EVP_CIPHER_CTX_cleanup( &aes_ctx );
#endif // USE_TLS_OPENSSL
#if USE_TLS_NSS
- PK11SlotInfo *aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
- sal_uInt8 *key( new sal_uInt8[ nKeySize ] );
- (void) memcpy( key, pnKey, nKeySize * sizeof(sal_uInt8) );
+ PK11SlotInfo *aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
+ sal_uInt8 *key( new sal_uInt8[ nKeySize ] );
+ (void) memcpy( key, pnKey, nKeySize * sizeof(sal_uInt8) );
- SECItem keyItem;
- keyItem.type = siBuffer;
- keyItem.data = key;
- keyItem.len = nKeySize;
+ SECItem keyItem;
+ keyItem.type = siBuffer;
+ keyItem.data = key;
+ keyItem.len = nKeySize;
- PK11SymKey *symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
- SECItem *secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
- PK11Context *encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
+ PK11SymKey *symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
+ SECItem *secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
+ PK11Context *encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
- int nOutLen(0);
- sal_uInt8 pnTmpVerifier[ 16 ];
- (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
+ int nOutLen(0);
+ sal_uInt8 pnTmpVerifier[ 16 ];
+ (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
- PK11_CipherOp( encContext, pnTmpVerifier, &nOutLen, sizeof(pnTmpVerifier), const_cast<sal_uInt8*>(pnVerifier), nVerifierSize );
+ PK11_CipherOp( encContext, pnTmpVerifier, &nOutLen, sizeof(pnTmpVerifier), const_cast<sal_uInt8*>(pnVerifier), nVerifierSize );
- sal_uInt8* pnTmpVerifierHash = new sal_uInt8[nVerifierHashSize];
- (void) memset( pnTmpVerifierHash, 0, nVerifierHashSize );
- PK11_CipherOp( encContext, pnTmpVerifierHash, &nOutLen, nVerifierHashSize, const_cast<sal_uInt8*>(pnVerifierHash), nVerifierHashSize );
+ sal_uInt8* pnTmpVerifierHash = new sal_uInt8[nVerifierHashSize];
+ (void) memset( pnTmpVerifierHash, 0, nVerifierHashSize );
+ PK11_CipherOp( encContext, pnTmpVerifierHash, &nOutLen, nVerifierHashSize, const_cast<sal_uInt8*>(pnVerifierHash), nVerifierHashSize );
- PK11_DestroyContext( encContext, PR_TRUE );
- PK11_FreeSymKey( symKey );
- SECITEM_FreeItem( secParam, PR_TRUE );
- delete[] key;
+ PK11_DestroyContext( encContext, PR_TRUE );
+ PK11_FreeSymKey( symKey );
+ SECITEM_FreeItem( secParam, PR_TRUE );
+ delete[] key;
#endif // USE_TLS_NSS
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) );
- sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 );
- }
+ rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
+ rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) );
+ sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ];
+ rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
+ rtl_digest_destroy( aDigest );
- return bResult;
+ return memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0;
}
-// ----------------------------------------------------------------------------
-
-Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen )
+bool lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncryptionInfo, const OUString& rPassword, vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength )
{
- size_t nBufferSize = rEncrInfo.mnSaltSize + 2 * rPassword.getLength();
+ size_t nBufferSize = rEncryptionInfo.verifier.saltSize + 2 * rPassword.getLength();
sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
- memcpy( pnBuffer, rEncrInfo.mpnSalt, rEncrInfo.mnSaltSize );
+ memcpy( pnBuffer, rEncryptionInfo.verifier.salt, rEncryptionInfo.verifier.saltSize );
- sal_uInt8* pnPasswordLoc = pnBuffer + rEncrInfo.mnSaltSize;
+ sal_uInt8* pnPasswordLoc = pnBuffer + rEncryptionInfo.verifier.saltSize;
const sal_Unicode* pStr = rPassword.getStr();
for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 )
ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) );
@@ -364,24 +252,32 @@ Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rE
rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 );
rtl_digest_destroy( aDigest );
- lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, pnKey, nRequiredKeyLen );
+ lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, aKey, aKeyLength );
delete[] pnHash;
+ return true;
+}
- Sequence< NamedValue > aResult;
- if( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) )
- {
- SequenceAsHashMap aEncryptionData;
- aEncryptionData[ "AES128EncryptionKey" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen );
- aEncryptionData[ "AES128EncryptionSalt" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize );
- aEncryptionData[ "AES128EncryptionVerifier" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) );
- aEncryptionData[ "AES128EncryptionVerifierHash" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) );
- aResult = aEncryptionData.getAsConstNamedValueList();
- }
+} // namespace
- return aResult;
+EncryptionStandardHeader::EncryptionStandardHeader()
+{
+ flags = 0;
+ sizeExtra = 0;
+ algId = 0;
+ algIdHash = 0;
+ keySize = 0;
+ providedType = 0;
+ reserved1 = 0;
+ reserved2 = 0;
}
-} // namespace
+EncryptionVerifierAES::EncryptionVerifierAES()
+{
+ saltSize = SALT_LENGTH;
+ memset(salt, 0, sizeof(salt));
+ memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
+ memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
+}
AesEncoder::AesEncoder(Reference< XStream > xDocumentStream, oox::ole::OleStorage& rOleStorage, OUString aPassword) :
mxDocumentStream(xDocumentStream),
@@ -390,6 +286,37 @@ AesEncoder::AesEncoder(Reference< XStream > xDocumentStream, oox::ole::OleStorag
{
}
+bool AesEncoder::checkEncryptionInfo(vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength)
+{
+ return lclCheckEncryptionData(
+ &aKey[0], aKeyLength,
+ mEncryptionInfo.verifier.encryptedVerifier, sizeof(mEncryptionInfo.verifier.encryptedVerifier),
+ mEncryptionInfo.verifier.encryptedVerifierHash, ENCRYPTED_VERIFIER_HASH_LENGTH);
+}
+
+bool AesEncoder::writeEncryptionInfo( BinaryOutputStream& rStream )
+{
+ rStream.writeValue(VERSION_INFO_2007_FORMAT);
+
+ const OUString cspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
+ sal_Int32 cspNameSize = (cspName.getLength() * 2) + 2;
+
+ sal_Int32 encryptionHeaderSize = static_cast<sal_Int32>(sizeof(EncryptionStandardHeader));
+
+ rStream << mEncryptionInfo.header.flags;
+ sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
+ rStream << headerSize;
+
+ rStream.writeMemory(&mEncryptionInfo.header, encryptionHeaderSize);
+ rStream.writeUnicodeArray(cspName);
+ rStream.writeValue<sal_uInt16>(0);
+
+ sal_Int32 encryptionVerifierSize = static_cast<sal_Int32>(sizeof(EncryptionVerifierAES));
+ rStream.writeMemory(&mEncryptionInfo.verifier, encryptionVerifierSize);
+
+ return true;
+}
+
bool AesEncoder::encode()
{
Reference< XInputStream > xInputStream ( mxDocumentStream->getInputStream(), UNO_SET_THROW );
@@ -405,31 +332,32 @@ bool AesEncoder::encode()
Reference< XOutputStream > xEncryptionInfo( mrOleStorage.openOutputStream( "EncryptionInfo" ), UNO_SET_THROW );
- PackageEncryptionInfo rEncrInfo;
- rEncrInfo.mnFlags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
- rEncrInfo.mnAlgorithmId = ENCRYPT_ALGO_AES128;
- rEncrInfo.mnAlgorithmIdHash = ENCRYPT_HASH_SHA1;
- rEncrInfo.mnKeySize = ENCRYPT_KEY_SIZE_AES_128;
+ mEncryptionInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
+ mEncryptionInfo.header.algId = ENCRYPT_ALGO_AES128;
+ mEncryptionInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
+ mEncryptionInfo.header.keySize = ENCRYPT_KEY_SIZE_AES_128;
+ mEncryptionInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
- rEncrInfo.mnSaltSize = 16;
+ lclRandomGenerateValues( mEncryptionInfo.verifier.saltSize, mEncryptionInfo.verifier.salt );
- lclRandomGenerateValues( rEncrInfo.mnSaltSize, rEncrInfo.mpnSalt );
+ const sal_Int32 keyLength = mEncryptionInfo.header.keySize / 8;
+ vector<sal_uInt8> aKey;
+ aKey.resize(keyLength, 0);
- const sal_Int32 keyLength = rEncrInfo.mnKeySize / 8;
- sal_uInt8 key[16];
assert(keyLength == 16);
- memset(key, 0, keyLength);
- lclGenerateEncryptionKey(rEncrInfo, maPassword, key, keyLength);
+ lclGenerateEncryptionKey(mEncryptionInfo, maPassword, aKey, keyLength);
+
+ sal_uInt8 key[16];
+ std::copy(aKey.begin(), aKey.end(), key);
- lclGenerateVerifier(rEncrInfo, key, keyLength);
+ lclGenerateVerifier(mEncryptionInfo, aKey, keyLength);
- bool aResult = lclCheckEncryptionData(key, keyLength, rEncrInfo.mpnEncrVerifier, 16, rEncrInfo.mpnEncrVerifierHash, 32);
- if (!aResult)
+ if (!checkEncryptionInfo(aKey, keyLength))
return false;
BinaryXOutputStream aEncryptionInfoBinaryOutputStream( xEncryptionInfo, false );
- lclWriteEncryptionInfo( rEncrInfo, aEncryptionInfoBinaryOutputStream );
+ writeEncryptionInfo( aEncryptionInfoBinaryOutputStream );
aEncryptionInfoBinaryOutputStream.close();
xEncryptionInfo->flush();
@@ -484,6 +412,198 @@ bool AesEncoder::encode()
return true;
}
+bool AesDecoder::checkCurrentEncryptionData()
+{
+ return lclCheckEncryptionData(
+ &mKey[0], mKeyLength,
+ mEncryptionInfo.verifier.encryptedVerifier, ENCRYPTED_VERIFIER_LENGTH,
+ mEncryptionInfo.verifier.encryptedVerifierHash, ENCRYPTED_VERIFIER_HASH_LENGTH );
+}
+
+bool AesDecoder::checkEncryptionData(const Sequence<NamedValue>& rEncryptionData)
+{
+ SequenceAsHashMap aHashData( rEncryptionData );
+ Sequence<sal_Int8> aKey = aHashData.getUnpackedValueOrDefault( "AES128EncryptionKey", Sequence<sal_Int8>() );
+ Sequence<sal_Int8> aVerifier = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifier", Sequence<sal_Int8>() );
+ Sequence<sal_Int8> aVerifierHash = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifierHash", Sequence<sal_Int8>() );
+
+ return lclCheckEncryptionData(
+ reinterpret_cast<const sal_uInt8*>( aKey.getConstArray() ), aKey.getLength(),
+ reinterpret_cast<const sal_uInt8*>( aVerifier.getConstArray() ), aVerifier.getLength(),
+ reinterpret_cast<const sal_uInt8*>( aVerifierHash.getConstArray() ), aVerifierHash.getLength() );
+}
+
+bool AesDecoder::generateEncryptionKey(const OUString& rPassword)
+{
+ return lclGenerateEncryptionKey(mEncryptionInfo, rPassword, mKey, mKeyLength);
+}
+
+AesDecoder::AesDecoder(oox::ole::OleStorage& rOleStorage) :
+ mrOleStorage(rOleStorage),
+ mKeyLength(0)
+{
+#if USE_TLS_NSS
+ // Initialize NSS, database functions are not needed
+ NSS_NoDB_Init( NULL );
+#endif // USE_TLS_NSS
+}
+
+bool AesDecoder::readEncryptionInfoFromStream( BinaryInputStream& rStream )
+{
+ sal_uInt32 aVersion;
+ rStream >> aVersion;
+
+ if (aVersion != VERSION_INFO_2007_FORMAT)
+ return false;
+
+ rStream >> mEncryptionInfo.header.flags;
+ if( getFlag( mEncryptionInfo.header.flags, ENCRYPTINFO_EXTERNAL ) )
+ return false;
+
+ sal_uInt32 nHeaderSize;
+ rStream >> nHeaderSize;
+
+ sal_uInt32 actualHeaderSize = sizeof(mEncryptionInfo.header);
+
+ if( (nHeaderSize < actualHeaderSize) )
+ return false;
+
+ rStream >> mEncryptionInfo.header;
+ rStream.skip( nHeaderSize - actualHeaderSize );
+ rStream >> mEncryptionInfo.verifier;
+
+ if( mEncryptionInfo.verifier.saltSize != 16 )
+ return false;
+ return !rStream.isEof();
+}
+
+bool AesDecoder::readEncryptionInfo()
+{
+ if( !mrOleStorage.isStorage() )
+ return false;
+
+ Reference< XInputStream > xEncryptionInfo( mrOleStorage.openInputStream( "EncryptionInfo" ), UNO_SET_THROW );
+
+ // read the encryption info stream
+ BinaryXInputStream aInputStream( xEncryptionInfo, true );
+ bool bValidInfo = readEncryptionInfoFromStream( aInputStream );
+
+ if (!bValidInfo)
+ return false;
+
+ // check flags and algorithm IDs, required are AES128 and SHA-1
+ bool bImplemented =
+ getFlag( mEncryptionInfo.header.flags , ENCRYPTINFO_CRYPTOAPI ) &&
+ getFlag( mEncryptionInfo.header.flags, ENCRYPTINFO_AES ) &&
+ // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
+ ((mEncryptionInfo.header.algId == 0) || (mEncryptionInfo.header.algId == ENCRYPT_ALGO_AES128)) &&
+ // hash algorithm ID 0 defaults to SHA-1 too
+ ((mEncryptionInfo.header.algIdHash == 0) || (mEncryptionInfo.header.algIdHash == ENCRYPT_HASH_SHA1)) &&
+ (mEncryptionInfo.verifier.encryptedVerifierHashSize == 20);
+
+ mKeyLength = (mEncryptionInfo.header.keySize / 8);
+ mKey.clear();
+ mKey.resize(mKeyLength, 0);
+
+ return bImplemented;
+}
+
+Sequence<NamedValue> AesDecoder::createEncryptionData()
+{
+ Sequence<NamedValue> aResult;
+
+ if (mKeyLength > 0)
+ {
+ SequenceAsHashMap aEncryptionData;
+ EncryptionVerifierAES& verifier = mEncryptionInfo.verifier;
+ aEncryptionData["AES128EncryptionKey"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( &mKey[0] ), mKeyLength );
+ aEncryptionData["AES128EncryptionSalt"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( verifier.salt ), verifier.saltSize );
+ aEncryptionData["AES128EncryptionVerifier"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( verifier.encryptedVerifier ), sizeof( verifier.encryptedVerifier ) );
+ aEncryptionData["AES128EncryptionVerifierHash"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( verifier.encryptedVerifierHash ), sizeof( verifier.encryptedVerifierHash ) );
+ aResult = aEncryptionData.getAsConstNamedValueList();
+ }
+
+ return aResult;
+}
+
+bool AesDecoder::decode( com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream )
+{
+ if( !mrOleStorage.isStorage() )
+ return false;
+
+ // open the required input streams in the encrypted package
+ Reference< XInputStream > xEncryptedPackage( mrOleStorage.openInputStream( "EncryptedPackage" ), UNO_SET_THROW );
+
+ // create temporary file for unencrypted package
+ Reference< XOutputStream > xDecryptedPackage( xDocumentStream->getOutputStream(), UNO_SET_THROW );
+ BinaryXOutputStream aDecryptedPackage( xDecryptedPackage, true );
+ BinaryXInputStream aEncryptedPackage( xEncryptedPackage, true );
+
+#if USE_TLS_OPENSSL
+ EVP_CIPHER_CTX aes_ctx;
+ EVP_CIPHER_CTX_init( &aes_ctx );
+ EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, &mKey.front(), 0 );
+ EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
+#endif // USE_TLS_OPENSSL
+
+#if USE_TLS_NSS
+ PK11SlotInfo* aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
+ sal_uInt8* key = new sal_uInt8[ mKeyLength ];
+ std::copy(mKey.begin(), mKey.end(), key);
+
+ SECItem keyItem;
+ keyItem.type = siBuffer;
+ keyItem.data = key;
+ keyItem.len = mKeyLength;
+
+ PK11SymKey* symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
+ SECItem* secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
+ PK11Context* encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
+#endif // USE_TLS_NSS
+
+ sal_uInt8 pnInBuffer[ 1024 ];
+ sal_uInt8 pnOutBuffer[ 1024 ];
+ sal_Int32 nInLen;
+ int nOutLen;
+ aEncryptedPackage.skip( 8 ); // decrypted size
+ while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 )
+ {
+#if USE_TLS_OPENSSL
+ EVP_DecryptUpdate( &aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen );
+#endif // USE_TLS_OPENSSL
+
+#if USE_TLS_NSS
+ PK11_CipherOp( encContext, pnOutBuffer, &nOutLen, sizeof(pnOutBuffer), pnInBuffer, nInLen );
+#endif // USE_TLS_NSS
+ aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
+ }
+#if USE_TLS_OPENSSL
+ EVP_DecryptFinal_ex( &aes_ctx, pnOutBuffer, &nOutLen );
+#endif // USE_TLS_OPENSSL
+
+#if USE_TLS_NSS
+ uint finalLength;
+ PK11_DigestFinal( encContext, pnOutBuffer, &finalLength, nInLen - nOutLen );
+ nOutLen = finalLength;
+#endif // USE_TLS_NSS
+ aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
+
+#if USE_TLS_OPENSSL
+ EVP_CIPHER_CTX_cleanup( &aes_ctx );
+#endif // USE_TLS_OPENSSL
+
+#if USE_TLS_NSS
+ PK11_DestroyContext( encContext, PR_TRUE );
+ PK11_FreeSymKey( symKey );
+ SECITEM_FreeItem( secParam, PR_TRUE );
+ delete[] key;
+#endif // USE_TLS_NSS
+ xDecryptedPackage->flush();
+ aDecryptedPackage.seekToStart();
+
+ return true;
+}
+
} // namespace core
} // namespace oox
diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx
index 12f53e460fc5..232864211bbe 100644
--- a/oox/source/core/filterdetect.cxx
+++ b/oox/source/core/filterdetect.cxx
@@ -19,45 +19,37 @@
#include "oox/core/filterdetect.hxx"
-#include <config_oox.h>
#include <com/sun/star/io/TempFile.hpp>
#include <com/sun/star/io/XStream.hpp>
#include <comphelper/docpasswordhelper.hxx>
#include <comphelper/mediadescriptor.hxx>
-#if USE_TLS_OPENSSL
-#include <openssl/evp.h>
-#endif // USE_TLS_OPENSSL
-#if USE_TLS_NSS
-#include <nss.h>
-#include <pk11pub.h>
-#endif // USE_TLS_NSS
-#include <rtl/digest.h>
+
+#include "oox/core/DocumentCrypt.hxx"
#include "oox/core/fastparser.hxx"
#include "oox/helper/attributelist.hxx"
-#include "oox/helper/binaryinputstream.hxx"
-#include "oox/helper/binaryoutputstream.hxx"
#include "oox/helper/zipstorage.hxx"
#include "oox/ole/olestorage.hxx"
+
#include <com/sun/star/uri/UriReferenceFactory.hpp>
namespace oox {
namespace core {
-// ============================================================================
-
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::uri;
-using ::comphelper::MediaDescriptor;
-using ::comphelper::SequenceAsHashMap;
-
-// ============================================================================
+using comphelper::MediaDescriptor;
+using comphelper::SequenceAsHashMap;
+using comphelper::IDocPasswordVerifier;
+using comphelper::DocPasswordVerifierResult;
FilterDetectDocHandler::FilterDetectDocHandler( const Reference< XComponentContext >& rxContext, OUString& rFilterName ) :
- mrFilterName( rFilterName ), mxContext( rxContext )
+ mrFilterName( rFilterName ),
+ mxContext( rxContext )
{
maContextStack.reserve( 2 );
}
@@ -163,15 +155,15 @@ void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs )
OUString aType = rAttribs.getString( XML_Type, OUString() );
if ( aType == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" )
{
- Reference< com::sun::star::uri::XUriReferenceFactory > xFac = com::sun::star::uri::UriReferenceFactory::create( mxContext );
+ Reference<XUriReferenceFactory> xFactory = UriReferenceFactory::create( mxContext );
try
{
// use '/' to representent the root of the zip package ( and provide a 'file' scheme to
// keep the XUriReference implementation happy )
- Reference< com::sun::star::uri::XUriReference > xBase = xFac->parse( OUString("file:///") );
+ Reference< XUriReference > xBase = xFactory->parse( OUString("file:///") );
- Reference< com::sun::star::uri::XUriReference > xPart = xFac->parse( rAttribs.getString( XML_Target, OUString() ) );
- Reference< com::sun::star::uri::XUriReference > xAbs = xFac->makeAbsolute( xBase, xPart, sal_True, com::sun::star::uri::RelativeUriExcessParentSegments_RETAIN );
+ Reference< XUriReference > xPart = xFactory->parse( rAttribs.getString( XML_Target, OUString() ) );
+ Reference< XUriReference > xAbs = xFactory->makeAbsolute( xBase, xPart, sal_True, RelativeUriExcessParentSegments_RETAIN );
if ( xAbs.is() )
maTargetPath = xAbs->getPath();
@@ -237,8 +229,6 @@ void FilterDetectDocHandler::parseContentTypesOverride( const AttributeList& rAt
mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) );
}
-// ============================================================================
-
/* Helper for XServiceInfo */
Sequence< OUString > FilterDetect_getSupportedServiceNames()
{
@@ -259,8 +249,6 @@ Reference< XInterface > SAL_CALL FilterDetect_createInstance( const Reference< X
return static_cast< ::cppu::OWeakObject* >( new FilterDetect( rxContext ) );
}
-// ----------------------------------------------------------------------------
-
FilterDetect::FilterDetect( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
mxContext( rxContext, UNO_SET_THROW )
{
@@ -270,25 +258,8 @@ FilterDetect::~FilterDetect()
{
}
-/* =========================================================================== */
-/* Kudos to Caolan McNamara who provided the core decryption implementations. */
-/* =========================================================================== */
-
-namespace {
-
-const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
-const sal_uInt32 ENCRYPTINFO_DOCPROPS = 0x00000008;
-const sal_uInt32 ENCRYPTINFO_EXTERNAL = 0x00000010;
-const sal_uInt32 ENCRYPTINFO_AES = 0x00000020;
-
-const sal_uInt32 ENCRYPT_ALGO_AES128 = 0x0000660E;
-const sal_uInt32 ENCRYPT_ALGO_AES192 = 0x0000660F;
-const sal_uInt32 ENCRYPT_ALGO_AES256 = 0x00006610;
-const sal_uInt32 ENCRYPT_ALGO_RC4 = 0x00006801;
-
-const sal_uInt32 ENCRYPT_HASH_SHA1 = 0x00008004;
-
-// ----------------------------------------------------------------------------
+namespace
+{
bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm )
{
@@ -296,413 +267,109 @@ bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Ref
return aZipStorage.isStorage();
}
-// ----------------------------------------------------------------------------
-
-struct PackageEncryptionInfo
-{
- sal_uInt8 mpnSalt[ 16 ];
- sal_uInt8 mpnEncrVerifier[ 16 ];
- sal_uInt8 mpnEncrVerifierHash[ 32 ];
- sal_uInt32 mnFlags;
- sal_uInt32 mnAlgorithmId;
- sal_uInt32 mnAlgorithmIdHash;
- sal_uInt32 mnKeySize;
- sal_uInt32 mnSaltSize;
- sal_uInt32 mnVerifierHashSize;
-};
-
-bool lclReadEncryptionInfo( PackageEncryptionInfo& rEncrInfo, BinaryInputStream& rStrm )
-{
- rStrm.skip( 4 );
- rStrm >> rEncrInfo.mnFlags;
- if( getFlag( rEncrInfo.mnFlags, ENCRYPTINFO_EXTERNAL ) )
- return false;
-
- sal_uInt32 nHeaderSize, nRepeatedFlags;
- rStrm >> nHeaderSize >> nRepeatedFlags;
- if( (nHeaderSize < 20) || (nRepeatedFlags != rEncrInfo.mnFlags) )
- return false;
-
- rStrm.skip( 4 );
- rStrm >> rEncrInfo.mnAlgorithmId >> rEncrInfo.mnAlgorithmIdHash >> rEncrInfo.mnKeySize;
- rStrm.skip( nHeaderSize - 20 );
- rStrm >> rEncrInfo.mnSaltSize;
- if( rEncrInfo.mnSaltSize != 16 )
- return false;
-
- rStrm.readMemory( rEncrInfo.mpnSalt, 16 );
- rStrm.readMemory( rEncrInfo.mpnEncrVerifier, 16 );
- rStrm >> rEncrInfo.mnVerifierHashSize;
- rStrm.readMemory( rEncrInfo.mpnEncrVerifierHash, 32 );
- return !rStrm.isEof();
-}
-
-// ----------------------------------------------------------------------------
-
-void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen )
-{
- sal_uInt8 pnBuffer[ 64 ];
- memset( pnBuffer, 0x36, sizeof( pnBuffer ) );
- for( sal_uInt32 i = 0; i < nHashLen; ++i )
- pnBuffer[ i ] ^= pnHash[ i ];
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
- sal_uInt8 pnX1[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnX1, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- memset( pnBuffer, 0x5C, sizeof( pnBuffer ) );
- for( sal_uInt32 i = 0; i < nHashLen; ++i )
- pnBuffer[ i ] ^= pnHash[ i ];
-
- aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
- sal_uInt8 pnX2[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnX2, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 )
- {
- memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 );
- nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1;
- }
- memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
-}
-
-// ----------------------------------------------------------------------------
-
-bool lclCheckEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize )
-{
- bool bResult = false;
-
- // the only currently supported algorithm needs key size 128
- if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 )
- {
- // check password
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX aes_ctx;
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
- int nOutLen = 0;
- sal_uInt8 pnTmpVerifier[ 16 ];
- (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
-
- /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize );
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
- sal_uInt8 pnTmpVerifierHash[ 32 ];
- (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) );
-
- /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize );
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11SlotInfo *aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
- sal_uInt8 *key( new sal_uInt8[ nKeySize ] );
- (void) memcpy( key, pnKey, nKeySize * sizeof(sal_uInt8) );
-
- SECItem keyItem;
- keyItem.type = siBuffer;
- keyItem.data = key;
- keyItem.len = nKeySize;
-
- PK11SymKey *symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
- SECItem *secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
- PK11Context *encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
-
- int nOutLen(0);
- sal_uInt8 pnTmpVerifier[ 16 ];
- (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
-
- PK11_CipherOp( encContext, pnTmpVerifier, &nOutLen, sizeof(pnTmpVerifier), const_cast<sal_uInt8*>(pnVerifier), nVerifierSize );
-
- sal_uInt8 pnTmpVerifierHash[ 32 ];
- (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) );
- PK11_CipherOp( encContext, pnTmpVerifierHash, &nOutLen, sizeof(pnTmpVerifierHash), const_cast<sal_uInt8*>(pnVerifierHash), nVerifierHashSize );
-
- PK11_DestroyContext( encContext, PR_TRUE );
- PK11_FreeSymKey( symKey );
- SECITEM_FreeItem( secParam, PR_TRUE );
- delete[] key;
-#endif // USE_TLS_NSS
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) );
- sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 );
- }
-
- return bResult;
-}
-
-// ----------------------------------------------------------------------------
-
-Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen )
-{
- size_t nBufferSize = rEncrInfo.mnSaltSize + 2 * rPassword.getLength();
- sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
- memcpy( pnBuffer, rEncrInfo.mpnSalt, rEncrInfo.mnSaltSize );
-
- sal_uInt8* pnPasswordLoc = pnBuffer + rEncrInfo.mnSaltSize;
- const sal_Unicode* pStr = rPassword.getStr();
- for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 )
- ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) );
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnBuffer, nBufferSize );
- delete[] pnBuffer;
-
- size_t nHashSize = RTL_DIGEST_LENGTH_SHA1 + 4;
- sal_uInt8* pnHash = new sal_uInt8[ nHashSize ];
- rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- for( sal_uInt32 i = 0; i < 50000; ++i )
- {
- ByteOrderConverter::writeLittleEndian( pnHash, i );
- aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnHash, nHashSize );
- rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
- }
-
- memmove( pnHash, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
- memset( pnHash + RTL_DIGEST_LENGTH_SHA1, 0, 4 );
- aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnHash, nHashSize );
- rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, pnKey, nRequiredKeyLen );
- delete[] pnHash;
-
- Sequence< NamedValue > aResult;
- if( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) )
- {
- SequenceAsHashMap aEncryptionData;
- aEncryptionData[ "AES128EncryptionKey" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen );
- aEncryptionData[ "AES128EncryptionSalt" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize );
- aEncryptionData[ "AES128EncryptionVerifier" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) );
- aEncryptionData[ "AES128EncryptionVerifierHash" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) );
- aResult = aEncryptionData.getAsConstNamedValueList();
- }
-
- return aResult;
-}
-
-// the password verifier ------------------------------------------------------
-
-class PasswordVerifier : public ::comphelper::IDocPasswordVerifier
+class PasswordVerifier : public IDocPasswordVerifier
{
public:
- explicit PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo );
-
- virtual ::comphelper::DocPasswordVerifierResult
- verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData );
- virtual ::comphelper::DocPasswordVerifierResult
- verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData );
+ explicit PasswordVerifier( AesDecoder& decoder );
- inline const sal_uInt8* getKey() const { return &maKey.front(); }
+ virtual DocPasswordVerifierResult verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData );
+ virtual DocPasswordVerifierResult verifyEncryptionData( const Sequence<NamedValue>& rEncryptionData );
private:
- const PackageEncryptionInfo& mrEncryptInfo;
- ::std::vector< sal_uInt8 > maKey;
+ AesDecoder& mDecoder;
};
-PasswordVerifier::PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ) :
- mrEncryptInfo( rEncryptInfo ),
- maKey( static_cast< size_t >( rEncryptInfo.mnKeySize / 8 ), 0 )
-{
-}
+PasswordVerifier::PasswordVerifier( AesDecoder& decoder ) :
+ mDecoder(decoder)
+{}
-::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData )
+comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData )
{
- // verifies the password and writes the related decryption key into maKey
- o_rEncryptionData = lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() );
- return o_rEncryptionData.hasElements() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+ if( mDecoder.generateEncryptionKey(rPassword) && mDecoder.checkCurrentEncryptionData() )
+ rEncryptionData = mDecoder.createEncryptionData();
+
+ return rEncryptionData.hasElements() ? comphelper::DocPasswordVerifierResult_OK : comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
}
-::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const Sequence<NamedValue>& rEncryptionData )
{
- SequenceAsHashMap aHashData( rEncryptionData );
- Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( "AES128EncryptionKey", Sequence< sal_Int8 >() );
- Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifier", Sequence< sal_Int8 >() );
- Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifierHash", Sequence< sal_Int8 >() );
-
- bool bResult = lclCheckEncryptionData(
- reinterpret_cast< const sal_uInt8* >( aKey.getConstArray() ), aKey.getLength(),
- reinterpret_cast< const sal_uInt8* >( aVerifier.getConstArray() ), aVerifier.getLength(),
- reinterpret_cast< const sal_uInt8* >( aVerifierHash.getConstArray() ), aVerifierHash.getLength() );
-
- return bResult ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+ comphelper::DocPasswordVerifierResult aResult = comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+ if (AesDecoder::checkEncryptionData(rEncryptionData))
+ aResult = comphelper::DocPasswordVerifierResult_OK;
+ return aResult;
}
} // namespace
-// ----------------------------------------------------------------------------
-Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescriptor& rMediaDesc ) const
+Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescriptor& rMediaDescriptor ) const
{
// try the plain input stream
- Reference< XInputStream > xInStrm( rMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY );
- if( !xInStrm.is() || lclIsZipPackage( mxContext, xInStrm ) )
- return xInStrm;
+ Reference<XInputStream> xInputStream( rMediaDescriptor[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY );
+ if( !xInputStream.is() || lclIsZipPackage( mxContext, xInputStream ) )
+ return xInputStream;
// check if a temporary file is passed in the 'ComponentData' property
- Reference< XStream > xDecrypted( rMediaDesc.getComponentDataEntry( "DecryptedPackage" ), UNO_QUERY );
+ Reference<XStream> xDecrypted( rMediaDescriptor.getComponentDataEntry( "DecryptedPackage" ), UNO_QUERY );
if( xDecrypted.is() )
{
- Reference< XInputStream > xDecrInStrm = xDecrypted->getInputStream();
- if( lclIsZipPackage( mxContext, xDecrInStrm ) )
- return xDecrInStrm;
+ Reference<XInputStream> xDecryptedInputStream = xDecrypted->getInputStream();
+ if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
+ return xDecryptedInputStream;
}
// try to decrypt an encrypted OLE package
- ::oox::ole::OleStorage aOleStorage( mxContext, xInStrm, false );
- if( aOleStorage.isStorage() ) try
+ oox::ole::OleStorage aOleStorage( mxContext, xInputStream, false );
+ if( aOleStorage.isStorage() )
{
- // open the required input streams in the encrypted package
- Reference< XInputStream > xEncryptionInfo( aOleStorage.openInputStream( "EncryptionInfo" ), UNO_SET_THROW );
- Reference< XInputStream > xEncryptedPackage( aOleStorage.openInputStream( "EncryptedPackage" ), UNO_SET_THROW );
-
- // read the encryption info stream
- PackageEncryptionInfo aEncryptInfo;
- BinaryXInputStream aInfoStrm( xEncryptionInfo, true );
- bool bValidInfo = lclReadEncryptionInfo( aEncryptInfo, aInfoStrm );
-
- // check flags and algorithm IDs, required are AES128 and SHA-1
- bool bImplemented = bValidInfo &&
- getFlag( aEncryptInfo.mnFlags, ENCRYPTINFO_CRYPTOAPI ) &&
- getFlag( aEncryptInfo.mnFlags, ENCRYPTINFO_AES ) &&
- // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
- ((aEncryptInfo.mnAlgorithmId == 0) || (aEncryptInfo.mnAlgorithmId == ENCRYPT_ALGO_AES128)) &&
- // hash algorithm ID 0 defaults to SHA-1 too
- ((aEncryptInfo.mnAlgorithmIdHash == 0) || (aEncryptInfo.mnAlgorithmIdHash == ENCRYPT_HASH_SHA1)) &&
- (aEncryptInfo.mnVerifierHashSize == 20);
-
- if( bImplemented )
+ try
{
-#if USE_TLS_NSS
- // Initialize NSS, database functions are not needed
- NSS_NoDB_Init( NULL );
-#endif // USE_TLS_NSS
-
- /* "VelvetSweatshop" is the built-in default encryption
- password used by MS Excel for the "workbook protection"
- feature with password. Try this first before prompting the
- user for a password. */
- ::std::vector< OUString > aDefaultPasswords;
- aDefaultPasswords.push_back( "VelvetSweatshop" );
-
- /* Use the comphelper password helper to request a password.
- This helper returns either with the correct password
- (according to the verifier), or with an empty string if
- user has cancelled the password input dialog. */
- PasswordVerifier aVerifier( aEncryptInfo );
- Sequence< NamedValue > aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
- aVerifier, rMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
-
- if( aEncryptionData.getLength() == 0 )
- {
- rMediaDesc[ MediaDescriptor::PROP_ABORTED() ] <<= true;
- }
- else
+ AesDecoder aDecoder(aOleStorage);
+
+ if( aDecoder.readEncryptionInfo() )
{
- // create temporary file for unencrypted package
- Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
- Reference< XOutputStream > xDecryptedPackage( xTempFile->getOutputStream(), UNO_SET_THROW );
- BinaryXOutputStream aDecryptedPackage( xDecryptedPackage, true );
- BinaryXInputStream aEncryptedPackage( xEncryptedPackage, true );
-
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX aes_ctx;
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, aVerifier.getKey(), 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- // Retrieve the valid key so we can get its size later
- SequenceAsHashMap aHashData( aEncryptionData );
- Sequence<sal_Int8> validKey( aHashData.getUnpackedValueOrDefault("AES128EncryptionKey", Sequence<sal_Int8>() ) );
-
- PK11SlotInfo *aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
- sal_uInt8 *key = new sal_uInt8[ validKey.getLength() ];
- (void) memcpy( key, aVerifier.getKey(), validKey.getLength() );
-
- SECItem keyItem;
- keyItem.type = siBuffer;
- keyItem.data = key;
- keyItem.len = validKey.getLength();
-
- PK11SymKey *symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
- SECItem *secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
- PK11Context *encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
-#endif // USE_TLS_NSS
-
- sal_uInt8 pnInBuffer[ 1024 ];
- sal_uInt8 pnOutBuffer[ 1024 ];
- sal_Int32 nInLen;
- int nOutLen;
- aEncryptedPackage.skip( 8 ); // decrypted size
- while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 )
+ /* "VelvetSweatshop" is the built-in default encryption
+ password used by MS Excel for the "workbook protection"
+ feature with password. Try this first before prompting the
+ user for a password. */
+ std::vector<OUString> aDefaultPasswords;
+ aDefaultPasswords.push_back("VelvetSweatshop");
+
+ /* Use the comphelper password helper to request a password.
+ This helper returns either with the correct password
+ (according to the verifier), or with an empty string if
+ user has cancelled the password input dialog. */
+ PasswordVerifier aVerifier( aDecoder );
+ Sequence<NamedValue> aEncryptionData;
+ aEncryptionData = comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
+ aVerifier, rMediaDescriptor,
+ comphelper::DocPasswordRequestType_MS,
+ &aDefaultPasswords );
+
+ if( aEncryptionData.getLength() == 0 )
{
-#if USE_TLS_OPENSSL
- EVP_DecryptUpdate( &aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11_CipherOp( encContext, pnOutBuffer, &nOutLen, sizeof(pnOutBuffer), pnInBuffer, nInLen );
-#endif // USE_TLS_NSS
- aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
+ rMediaDescriptor[ MediaDescriptor::PROP_ABORTED() ] <<= true;
+ }
+ else
+ {
+ // create temporary file for unencrypted package
+ Reference<XStream> xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
+ aDecoder.decode( xTempFile );
+
+ // store temp file in media descriptor to keep it alive
+ rMediaDescriptor.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
+
+ Reference<XInputStream> xDecryptedInputStream = xTempFile->getInputStream();
+ if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
+ return xDecryptedInputStream;
}
-#if USE_TLS_OPENSSL
- EVP_DecryptFinal_ex( &aes_ctx, pnOutBuffer, &nOutLen );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- uint final;
- PK11_DigestFinal( encContext, pnOutBuffer, &final, nInLen - nOutLen );
- nOutLen = final;
-#endif // USE_TLS_NSS
- aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
-
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11_DestroyContext( encContext, PR_TRUE );
- PK11_FreeSymKey( symKey );
- SECITEM_FreeItem( secParam, PR_TRUE );
- delete[] key;
-#endif // USE_TLS_NSS
- xDecryptedPackage->flush();
- aDecryptedPackage.seekToStart();
-
- // store temp file in media descriptor to keep it alive
- rMediaDesc.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
-
- Reference< XInputStream > xDecrInStrm = xTempFile->getInputStream();
- if( lclIsZipPackage( mxContext, xDecrInStrm ) )
- return xDecrInStrm;
}
}
+ catch( const Exception& )
+ {
+ }
}
- catch( const Exception& )
- {
- }
-
- return Reference< XInputStream >();
+ return Reference<XInputStream>();
}
// com.sun.star.lang.XServiceInfo interface -----------------------------------
@@ -730,24 +397,24 @@ Sequence< OUString > SAL_CALL FilterDetect::getSupportedServiceNames() throw( Ru
OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq ) throw( RuntimeException )
{
OUString aFilterName;
- MediaDescriptor aMediaDesc( rMediaDescSeq );
+ MediaDescriptor aMediaDescriptor( rMediaDescSeq );
/* Check that the user has not choosen to abort detection, e.g. by hitting
'Cancel' in the password input dialog. This may happen because this
filter detection is used by different filters. */
- bool bAborted = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_ABORTED(), false );
+ bool bAborted = aMediaDescriptor.getUnpackedValueOrDefault( MediaDescriptor::PROP_ABORTED(), false );
if( !bAborted ) try
{
- aMediaDesc.addInputStream();
+ aMediaDescriptor.addInputStream();
/* Get the unencrypted input stream. This may include creation of a
temporary file that contains the decrypted package. This temporary
file will be stored in the 'ComponentData' property of the media
descriptor. */
- Reference< XInputStream > xInStrm( extractUnencryptedPackage( aMediaDesc ), UNO_SET_THROW );
+ Reference< XInputStream > xInputStream( extractUnencryptedPackage( aMediaDescriptor ), UNO_SET_THROW );
// stream must be a ZIP package
- ZipStorage aZipStorage( mxContext, xInStrm );
+ ZipStorage aZipStorage( mxContext, xInputStream );
if( aZipStorage.isStorage() )
{
// create the fast parser, register the XML namespaces, set document handler
@@ -768,7 +435,7 @@ OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq
}
// write back changed media descriptor members
- aMediaDesc >> rMediaDescSeq;
+ aMediaDescriptor >> rMediaDescSeq;
return aFilterName;
}