summaryrefslogtreecommitdiffstats
path: root/include/filter/msfilter/mscodec.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'include/filter/msfilter/mscodec.hxx')
-rw-r--r--include/filter/msfilter/mscodec.hxx499
1 files changed, 499 insertions, 0 deletions
diff --git a/include/filter/msfilter/mscodec.hxx b/include/filter/msfilter/mscodec.hxx
new file mode 100644
index 000000000..90c39a8cc
--- /dev/null
+++ b/include/filter/msfilter/mscodec.hxx
@@ -0,0 +1,499 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_FILTER_MSFILTER_MSCODEC_HXX
+#define INCLUDED_FILTER_MSFILTER_MSCODEC_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <filter/msfilter/msfilterdllapi.h>
+#include <rtl/cipher.h>
+#include <rtl/digest.h>
+#include <sal/types.h>
+#include <comphelper/hash.hxx>
+#include <vector>
+
+namespace com::sun::star {
+ namespace beans { struct NamedValue; }
+}
+
+namespace msfilter {
+
+
+/** Encodes and decodes data from protected MSO 95- documents.
+ */
+class MSFILTER_DLLPUBLIC MSCodec_Xor95
+{
+public:
+ explicit MSCodec_Xor95(int nRotateDistance);
+ virtual ~MSCodec_Xor95();
+
+ /** Initializes the algorithm with the specified password.
+
+ @param pPassData
+ Character array containing the password. Must be zero terminated,
+ which results in a maximum length of 15 characters.
+ */
+ void InitKey( const sal_uInt8 pnPassData[ 16 ] );
+
+ /** Initializes the algorithm with the encryption data.
+
+ @param aData
+ The sequence contains the necessary data to initialize
+ the codec.
+ */
+ bool InitCodec( const css::uno::Sequence< css::beans::NamedValue >& aData );
+
+ /** Retrieves the encryption data
+
+ @return
+ The sequence contains the necessary data to initialize
+ the codec.
+ */
+ css::uno::Sequence< css::beans::NamedValue > GetEncryptionData();
+
+
+ /** Verifies the validity of the password using the passed key and hash.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param nKey
+ Password key value read from the file.
+ @param nHash
+ Password hash value read from the file.
+
+ @return
+ true = Test was successful.
+ */
+ bool VerifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const;
+
+ /** Reinitializes the codec to start a new memory block.
+
+ Resets the internal key offset to 0.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+ */
+ void InitCipher();
+
+ /** Decodes a block of memory inplace.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param pnData
+ Encrypted data block. Will contain the decrypted data afterwards.
+ @param nBytes
+ Size of the passed data block.
+ */
+ virtual void Decode( sal_uInt8* pnData, std::size_t nBytes )=0;
+
+ /** Lets the cipher skip a specific amount of bytes.
+
+ This function sets the cipher to the same state as if the specified
+ amount of data has been decoded with one or more calls of Decode().
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param nBytes
+ Number of bytes to be skipped (cipher "seeks" forward).
+ */
+ void Skip( std::size_t nBytes );
+
+protected:
+ sal_uInt8 mpnKey[ 16 ] = {}; /// Encryption key.
+ std::size_t mnOffset; /// Key offset.
+
+private:
+ MSCodec_Xor95( const MSCodec_Xor95& ) = delete;
+ MSCodec_Xor95& operator=( const MSCodec_Xor95& ) = delete;
+
+ sal_uInt16 mnKey; /// Base key from password.
+ sal_uInt16 mnHash; /// Hash value from password.
+ int mnRotateDistance;
+};
+
+/** Encodes and decodes data from protected MSO XLS 95- documents.
+ */
+class MSFILTER_DLLPUBLIC MSCodec_XorXLS95 final : public MSCodec_Xor95
+{
+public:
+ explicit MSCodec_XorXLS95() : MSCodec_Xor95(2) {}
+
+ /** Decodes a block of memory inplace.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param pnData
+ Encrypted data block. Will contain the decrypted data afterwards.
+ @param nBytes
+ Size of the passed data block.
+ */
+ virtual void Decode( sal_uInt8* pnData, std::size_t nBytes ) override;
+};
+
+/** Encodes and decodes data from protected MSO Word 95- documents.
+ */
+class MSFILTER_DLLPUBLIC MSCodec_XorWord95 final : public MSCodec_Xor95
+{
+public:
+ explicit MSCodec_XorWord95() : MSCodec_Xor95(7) {}
+
+ /** Decodes a block of memory inplace.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param pnData
+ Encrypted data block. Will contain the decrypted data afterwards.
+ @param nBytes
+ Size of the passed data block.
+ */
+ virtual void Decode( sal_uInt8* pnData, std::size_t nBytes ) override;
+};
+
+class MSFILTER_DLLPUBLIC MSCodec97
+{
+public:
+ MSCodec97(size_t nHashLen, OUString aEncKeyName);
+ virtual ~MSCodec97();
+
+ /** Initializes the algorithm with the encryption data.
+
+ @param aData
+ The sequence contains the necessary data to initialize
+ the codec.
+ */
+ bool InitCodec(const css::uno::Sequence< css::beans::NamedValue >& aData);
+
+ /** Retrieves the encryption data
+
+ @return
+ The sequence contains the necessary data to initialize
+ the codec.
+ */
+ virtual css::uno::Sequence<css::beans::NamedValue> GetEncryptionData();
+
+ /** Initializes the algorithm with the specified password and document ID.
+
+ @param pPassData
+ Wide character array containing the password. Must be zero
+ terminated, which results in a maximum length of 15 characters.
+ @param pDocId
+ Unique document identifier read from or written to the file.
+ */
+ virtual void InitKey(const sal_uInt16 pPassData[16],
+ const sal_uInt8 pDocId[16]) = 0;
+
+
+ /** Verifies the validity of the password using the passed salt data.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param pSaltData
+ Salt data block read from the file.
+ @param pSaltDigest
+ Salt digest read from the file.
+
+ @return
+ true = Test was successful.
+ */
+ bool VerifyKey(const sal_uInt8* pSaltData, const sal_uInt8* pSaltDigest);
+
+ virtual void GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) = 0;
+
+ /** Rekeys the codec using the specified counter.
+
+ After reading a specific amount of data the cipher algorithm needs to
+ be rekeyed using a counter that counts the data blocks.
+
+ The block size is for example 512 Bytes for Word files and 1024 Bytes
+ for Excel files.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param nCounter
+ Block counter used to rekey the cipher.
+ */
+ virtual bool InitCipher(sal_uInt32 nCounter) = 0;
+
+ /** Encodes a block of memory.
+
+ @see rtl_cipher_encode()
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used. The destination buffer must be able to take all
+ unencoded data from the source buffer (usually this means it must be
+ as long as or longer than the source buffer).
+
+ @param pData
+ Unencrypted source data block.
+ @param nDatLen
+ Size of the passed source data block.
+ @param pBuffer
+ Destination buffer for the encrypted data.
+ @param nBufLen
+ Size of the destination buffer.
+
+ @return
+ true = Encoding was successful (no error occurred).
+ */
+ bool Encode(const void* pData, std::size_t nDatLen,
+ sal_uInt8* pBuffer, std::size_t nBufLen);
+
+ /** Decodes a block of memory.
+
+ @see rtl_cipher_decode()
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used. The destination buffer must be able to take all
+ encoded data from the source buffer (usually this means it must be
+ as long as or longer than the source buffer).
+
+ @param pData
+ Encrypted source data block.
+ @param nDatLen
+ Size of the passed source data block.
+ @param pBuffer
+ Destination buffer for the decrypted data.
+ @param nBufLen
+ Size of the destination buffer.
+
+ @return
+ true = Decoding was successful (no error occurred).
+ */
+ bool Decode(const void* pData, std::size_t nDatLen,
+ sal_uInt8* pBuffer, std::size_t nBufLen);
+
+ /** Lets the cipher skip a specific amount of bytes.
+
+ This function sets the cipher to the same state as if the specified
+ amount of data has been decoded with one or more calls of Decode().
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param nDatLen
+ Number of bytes to be skipped (cipher "seeks" forward).
+ */
+ bool Skip(std::size_t nDatLen);
+
+ /* allows to get the unique document id from the codec
+ */
+ void GetDocId( sal_uInt8 pDocId[16] );
+
+private:
+ MSCodec97(const MSCodec97&) = delete;
+ MSCodec97& operator=(const MSCodec97&) = delete;
+
+protected:
+ OUString m_sEncKeyName;
+ size_t m_nHashLen;
+ rtlCipher m_hCipher;
+ std::vector<sal_uInt8> m_aDocId;
+ std::vector<sal_uInt8> m_aDigestValue;
+};
+
+/** Encodes and decodes data from protected MSO 97+ documents.
+
+ This is a wrapper class around low level cryptographic functions from RTL.
+ Implementation is based on the wvDecrypt package by Caolan McNamara:
+ http://www.csn.ul.ie/~caolan/docs/wvDecrypt.html
+ */
+class MSFILTER_DLLPUBLIC MSCodec_Std97 final : public MSCodec97
+{
+public:
+ MSCodec_Std97();
+ virtual ~MSCodec_Std97() override;
+
+ /** Initializes the algorithm with the specified password and document ID.
+
+ @param pPassData
+ Wide character array containing the password. Must be zero
+ terminated, which results in a maximum length of 15 characters.
+ @param pDocId
+ Unique document identifier read from or written to the file.
+ */
+ virtual void InitKey(const sal_uInt16 pPassData[16],
+ const sal_uInt8 pDocId[16]) override;
+
+ /** Rekeys the codec using the specified counter.
+
+ After reading a specific amount of data the cipher algorithm needs to
+ be rekeyed using a counter that counts the data blocks.
+
+ The block size is for example 512 Bytes for Word files and 1024 Bytes
+ for Excel files.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param nCounter
+ Block counter used to rekey the cipher.
+ */
+ virtual bool InitCipher(sal_uInt32 nCounter) override;
+
+ /** Creates an MD5 digest of salt digest. */
+ void CreateSaltDigest(
+ const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] );
+
+ /** Gets salt data and salt digest.
+
+ @precond
+ The codec must be initialized with InitKey() before this function
+ can be used.
+
+ @param pSalt
+ Salt, a random number.
+ @param pSaltData
+ Salt data block generated from the salt.
+ @param pSaltDigest
+ Salt digest generated from the salt.
+ */
+ void GetEncryptKey (
+ const sal_uInt8 pSalt[16],
+ sal_uInt8 pSaltData[16],
+ sal_uInt8 pSaltDigest[16]);
+
+ virtual void GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) override;
+
+private:
+ MSCodec_Std97( const MSCodec_Std97& ) = delete;
+ MSCodec_Std97& operator=( const MSCodec_Std97& ) = delete;
+
+ rtlDigest m_hDigest;
+};
+
+class MSFILTER_DLLPUBLIC MSCodec_CryptoAPI final : public MSCodec97
+{
+private:
+ css::uno::Sequence<sal_Int8> m_aStd97Key;
+public:
+ MSCodec_CryptoAPI();
+
+ virtual void InitKey(const sal_uInt16 pPassData[16],
+ const sal_uInt8 pDocId[16]) override;
+ virtual bool InitCipher(sal_uInt32 nCounter) override;
+ virtual void GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) override;
+ virtual css::uno::Sequence<css::beans::NamedValue> GetEncryptionData() override;
+};
+
+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 1997 (major = 1, minor = 1)
+const sal_uInt32 VERSION_INFO_1997_FORMAT = 0x00010001;
+// version of encryption info used in MS Office 2007 (major = 3, minor = 2)
+const sal_uInt32 VERSION_INFO_2007_FORMAT = 0x00020003;
+// version of encryption info used in MS Office 2007 SP2 and older (major = 4, minor = 2)
+const sal_uInt32 VERSION_INFO_2007_FORMAT_SP2 = 0x00020004;
+
+// version of encryption info - agile (major = 4, minor = 4)
+const sal_uInt32 VERSION_INFO_AGILE = 0x00040004;
+
+const sal_uInt32 AGILE_ENCRYPTION_RESERVED = 0x00000040;
+
+const sal_uInt32 SALT_LENGTH = 16;
+const sal_uInt32 ENCRYPTED_VERIFIER_LENGTH = 16;
+
+struct MSFILTER_DLLPUBLIC 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 keyBits; // 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 MSFILTER_DLLPUBLIC 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[comphelper::SHA256_HASH_LENGTH] = {}; // verifier value hash - itself also encrypted
+
+ EncryptionVerifierAES();
+};
+
+struct MSFILTER_DLLPUBLIC EncryptionVerifierRC4
+{
+ 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[comphelper::SHA1_HASH_LENGTH] = {}; // verifier value hash - itself also encrypted
+
+ EncryptionVerifierRC4();
+};
+
+struct MSFILTER_DLLPUBLIC StandardEncryptionInfo
+{
+ EncryptionStandardHeader header;
+ EncryptionVerifierAES verifier;
+};
+
+struct MSFILTER_DLLPUBLIC RC4EncryptionInfo
+{
+ EncryptionStandardHeader header;
+ EncryptionVerifierRC4 verifier;
+};
+
+} // namespace msfilter
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */