xref: /AOO42X/main/oox/source/core/encryption.cxx (revision b1c5455db1639c48e26c568e4fa7ee78ca5d60ee)
14e7b0f82SDamjan Jovanovic /**************************************************************
24e7b0f82SDamjan Jovanovic  *
34e7b0f82SDamjan Jovanovic  * Licensed to the Apache Software Foundation (ASF) under one
44e7b0f82SDamjan Jovanovic  * or more contributor license agreements.  See the NOTICE file
54e7b0f82SDamjan Jovanovic  * distributed with this work for additional information
64e7b0f82SDamjan Jovanovic  * regarding copyright ownership.  The ASF licenses this file
74e7b0f82SDamjan Jovanovic  * to you under the Apache License, Version 2.0 (the
84e7b0f82SDamjan Jovanovic  * "License"); you may not use this file except in compliance
94e7b0f82SDamjan Jovanovic  * with the License.  You may obtain a copy of the License at
104e7b0f82SDamjan Jovanovic  *
114e7b0f82SDamjan Jovanovic  *   http://www.apache.org/licenses/LICENSE-2.0
124e7b0f82SDamjan Jovanovic  *
134e7b0f82SDamjan Jovanovic  * Unless required by applicable law or agreed to in writing,
144e7b0f82SDamjan Jovanovic  * software distributed under the License is distributed on an
154e7b0f82SDamjan Jovanovic  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
164e7b0f82SDamjan Jovanovic  * KIND, either express or implied.  See the License for the
174e7b0f82SDamjan Jovanovic  * specific language governing permissions and limitations
184e7b0f82SDamjan Jovanovic  * under the License.
194e7b0f82SDamjan Jovanovic  *
204e7b0f82SDamjan Jovanovic  *************************************************************/
214e7b0f82SDamjan Jovanovic 
224e7b0f82SDamjan Jovanovic 
234e7b0f82SDamjan Jovanovic 
244e7b0f82SDamjan Jovanovic #include "oox/core/encryption.hxx"
254e7b0f82SDamjan Jovanovic #include "oox/core/fastparser.hxx"
264e7b0f82SDamjan Jovanovic #include "oox/helper/attributelist.hxx"
274e7b0f82SDamjan Jovanovic #include "oox/helper/helper.hxx"
284e7b0f82SDamjan Jovanovic #include "oox/helper/openssl_wrapper.hxx"
294e7b0f82SDamjan Jovanovic 
304e7b0f82SDamjan Jovanovic #include <rtl/digest.h>
314e7b0f82SDamjan Jovanovic #include <cppuhelper/implbase1.hxx>
324e7b0f82SDamjan Jovanovic #include <openssl/evp.h>
334e7b0f82SDamjan Jovanovic 
344e7b0f82SDamjan Jovanovic #include <com/sun/star/io/XStream.hpp>
354e7b0f82SDamjan Jovanovic 
364e7b0f82SDamjan Jovanovic 
374e7b0f82SDamjan Jovanovic 
384e7b0f82SDamjan Jovanovic namespace oox {
394e7b0f82SDamjan Jovanovic namespace core {
404e7b0f82SDamjan Jovanovic 
414e7b0f82SDamjan Jovanovic // ============================================================================
424e7b0f82SDamjan Jovanovic 
434e7b0f82SDamjan Jovanovic using namespace ::com::sun::star::beans;
444e7b0f82SDamjan Jovanovic using namespace ::com::sun::star::uno;
454e7b0f82SDamjan Jovanovic using namespace ::com::sun::star::xml::sax;
464e7b0f82SDamjan Jovanovic 
474e7b0f82SDamjan Jovanovic using ::com::sun::star::io::XInputStream;
484e7b0f82SDamjan Jovanovic using ::comphelper::SequenceAsHashMap;
494e7b0f82SDamjan Jovanovic using ::rtl::OUString;
504e7b0f82SDamjan Jovanovic using ::std::vector;
514e7b0f82SDamjan Jovanovic 
524e7b0f82SDamjan Jovanovic // ============================================================================
534e7b0f82SDamjan Jovanovic 
544e7b0f82SDamjan Jovanovic 
554e7b0f82SDamjan Jovanovic /* =========================================================================== */
564e7b0f82SDamjan Jovanovic /*  Kudos to Caolan McNamara who provided the core decryption implementation   */
574e7b0f82SDamjan Jovanovic /*  of Standard Encryption (MS-OFFCRYPTO section 2.3.4.5).                     */
584e7b0f82SDamjan Jovanovic /* =========================================================================== */
594e7b0f82SDamjan Jovanovic 
604e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_CRYPTOAPI        0x00000004U
614e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_DOCPROPS         0x00000008U
624e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_EXTERNAL         0x00000010U
634e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_AES              0x00000020U
644e7b0f82SDamjan Jovanovic 
654e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_AES128          0x0000660EU
664e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_AES192          0x0000660FU
674e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_AES256          0x00006610U
684e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_RC4             0x00006801U
694e7b0f82SDamjan Jovanovic 
704e7b0f82SDamjan Jovanovic #define ENCRYPT_HASH_SHA1            0x00008004U
714e7b0f82SDamjan Jovanovic 
724e7b0f82SDamjan Jovanovic class StandardEncryptionInfo : public EncryptionInfo
734e7b0f82SDamjan Jovanovic {
744e7b0f82SDamjan Jovanovic public:
754e7b0f82SDamjan Jovanovic     StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception );
~StandardEncryptionInfo()764e7b0f82SDamjan Jovanovic     ~StandardEncryptionInfo() {}
774e7b0f82SDamjan Jovanovic     bool isImplemented();
784e7b0f82SDamjan Jovanovic     Sequence< NamedValue > verifyPassword( const OUString& rPassword ) throw ( Exception );
794e7b0f82SDamjan Jovanovic     bool verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception );
804e7b0f82SDamjan Jovanovic     bool checkEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize ) throw ( Exception );
814e7b0f82SDamjan Jovanovic     void decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception );
824e7b0f82SDamjan Jovanovic 
834e7b0f82SDamjan Jovanovic private:
844e7b0f82SDamjan Jovanovic     sal_uInt8           mpnSalt[ 16 ];
854e7b0f82SDamjan Jovanovic     sal_uInt8           mpnEncrVerifier[ 16 ];
864e7b0f82SDamjan Jovanovic     sal_uInt8           mpnEncrVerifierHash[ 32 ];
874e7b0f82SDamjan Jovanovic     sal_uInt32          mnFlags;
884e7b0f82SDamjan Jovanovic     sal_uInt32          mnAlgorithmId;
894e7b0f82SDamjan Jovanovic     sal_uInt32          mnAlgorithmIdHash;
904e7b0f82SDamjan Jovanovic     sal_uInt32          mnKeySize;
914e7b0f82SDamjan Jovanovic     sal_uInt32          mnSaltSize;
924e7b0f82SDamjan Jovanovic     sal_uInt32          mnVerifierHashSize;
934e7b0f82SDamjan Jovanovic     vector< sal_uInt8>  encryptionKey;
944e7b0f82SDamjan Jovanovic };
954e7b0f82SDamjan Jovanovic 
StandardEncryptionInfo(BinaryInputStream & rStrm)964e7b0f82SDamjan Jovanovic StandardEncryptionInfo::StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception )
974e7b0f82SDamjan Jovanovic {
984e7b0f82SDamjan Jovanovic     char msg[ 1024 ];
994e7b0f82SDamjan Jovanovic     rStrm >> mnFlags;
100ae7dce1fSDamjan Jovanovic     if( getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_EXTERNAL ) )
1014e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: \"Extensible encryption\" is not currently supported, please report" ), Reference< XInterface >() );
1024e7b0f82SDamjan Jovanovic 
1034e7b0f82SDamjan Jovanovic     sal_uInt32 nHeaderSize, nRepeatedFlags;
1044e7b0f82SDamjan Jovanovic     rStrm >> nHeaderSize >> nRepeatedFlags;
1054e7b0f82SDamjan Jovanovic     if( nHeaderSize < 20 )
1064e7b0f82SDamjan Jovanovic     {
1074e7b0f82SDamjan Jovanovic         snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: header size %u is too short", nHeaderSize );
1084e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() );
1094e7b0f82SDamjan Jovanovic     }
1104e7b0f82SDamjan Jovanovic     if( nRepeatedFlags != mnFlags )
1114e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: flags don't match" ), Reference< XInterface>() );
1124e7b0f82SDamjan Jovanovic 
1134e7b0f82SDamjan Jovanovic     rStrm.skip( 4 );
1144e7b0f82SDamjan Jovanovic     rStrm >> mnAlgorithmId >> mnAlgorithmIdHash >> mnKeySize;
1154e7b0f82SDamjan Jovanovic     rStrm.skip( nHeaderSize - 20 );
1164e7b0f82SDamjan Jovanovic     rStrm >> mnSaltSize;
1174e7b0f82SDamjan Jovanovic     if( mnSaltSize != 16 )
1184e7b0f82SDamjan Jovanovic     {
1194e7b0f82SDamjan Jovanovic         snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: salt size is %u instead of 16", mnSaltSize );
1204e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() );
1214e7b0f82SDamjan Jovanovic     }
1224e7b0f82SDamjan Jovanovic 
1234e7b0f82SDamjan Jovanovic     rStrm.readMemory( mpnSalt, 16 );
1244e7b0f82SDamjan Jovanovic     rStrm.readMemory( mpnEncrVerifier, 16 );
1254e7b0f82SDamjan Jovanovic     rStrm >> mnVerifierHashSize;
1264e7b0f82SDamjan Jovanovic     rStrm.readMemory( mpnEncrVerifierHash, 32 );
1274e7b0f82SDamjan Jovanovic     if( rStrm.isEof() )
1284e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: standard encryption header too short" ), Reference< XInterface >() );
1294e7b0f82SDamjan Jovanovic }
1304e7b0f82SDamjan Jovanovic 
isImplemented()1314e7b0f82SDamjan Jovanovic bool StandardEncryptionInfo::isImplemented()
1324e7b0f82SDamjan Jovanovic {
133ae7dce1fSDamjan Jovanovic     return getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_CRYPTOAPI ) &&
134ae7dce1fSDamjan Jovanovic         getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_AES ) &&
1354e7b0f82SDamjan Jovanovic         // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
1364e7b0f82SDamjan Jovanovic        ( ( mnAlgorithmId == 0 ) || ( mnAlgorithmId == ENCRYPT_ALGO_AES128 ) ) &&
1374e7b0f82SDamjan Jovanovic        // hash algorithm ID 0 defaults to SHA-1 too
1384e7b0f82SDamjan Jovanovic        ( ( mnAlgorithmIdHash == 0 ) || ( mnAlgorithmIdHash == ENCRYPT_HASH_SHA1 ) ) &&
1394e7b0f82SDamjan Jovanovic        ( mnVerifierHashSize == 20 );
1404e7b0f82SDamjan Jovanovic }
1414e7b0f82SDamjan Jovanovic 
deriveKey(const sal_uInt8 * pnHash,sal_uInt32 nHashLen,sal_uInt8 * pnKeyDerived,sal_uInt32 nRequiredKeyLen)1424e7b0f82SDamjan Jovanovic static void deriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen )
1434e7b0f82SDamjan Jovanovic {
1444e7b0f82SDamjan Jovanovic     sal_uInt8 pnBuffer[ 64 ];
1454e7b0f82SDamjan Jovanovic     memset( pnBuffer, 0x36, sizeof( pnBuffer ) );
1464e7b0f82SDamjan Jovanovic     for( sal_uInt32 i = 0; i < nHashLen; ++i )
1474e7b0f82SDamjan Jovanovic         pnBuffer[ i ] ^= pnHash[ i ];
1484e7b0f82SDamjan Jovanovic 
1494e7b0f82SDamjan Jovanovic     rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
1504e7b0f82SDamjan Jovanovic     rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
1514e7b0f82SDamjan Jovanovic     sal_uInt8 pnX1[ RTL_DIGEST_LENGTH_SHA1 ];
1524e7b0f82SDamjan Jovanovic     aError = rtl_digest_get( aDigest, pnX1, RTL_DIGEST_LENGTH_SHA1 );
1534e7b0f82SDamjan Jovanovic     rtl_digest_destroy( aDigest );
1544e7b0f82SDamjan Jovanovic 
1554e7b0f82SDamjan Jovanovic     memset( pnBuffer, 0x5C, sizeof( pnBuffer ) );
1564e7b0f82SDamjan Jovanovic     for( sal_uInt32 i = 0; i < nHashLen; ++i )
1574e7b0f82SDamjan Jovanovic         pnBuffer[ i ] ^= pnHash[ i ];
1584e7b0f82SDamjan Jovanovic 
1594e7b0f82SDamjan Jovanovic     aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
1604e7b0f82SDamjan Jovanovic     aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
1614e7b0f82SDamjan Jovanovic     sal_uInt8 pnX2[ RTL_DIGEST_LENGTH_SHA1 ];
1624e7b0f82SDamjan Jovanovic     aError = rtl_digest_get( aDigest, pnX2, RTL_DIGEST_LENGTH_SHA1 );
1634e7b0f82SDamjan Jovanovic     rtl_digest_destroy( aDigest );
1644e7b0f82SDamjan Jovanovic 
1654e7b0f82SDamjan Jovanovic     if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 )
1664e7b0f82SDamjan Jovanovic     {
1674e7b0f82SDamjan Jovanovic         memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 );
1684e7b0f82SDamjan Jovanovic         nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1;
1694e7b0f82SDamjan Jovanovic     }
1704e7b0f82SDamjan Jovanovic     memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
1714e7b0f82SDamjan Jovanovic }
1724e7b0f82SDamjan Jovanovic 
verifyPassword(const OUString & rPassword)1734e7b0f82SDamjan Jovanovic Sequence< NamedValue > StandardEncryptionInfo::verifyPassword( const OUString& rPassword ) throw ( Exception )
1744e7b0f82SDamjan Jovanovic {
1754e7b0f82SDamjan Jovanovic     size_t nBufferSize = mnSaltSize + 2 * rPassword.getLength();
1764e7b0f82SDamjan Jovanovic     sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
1774e7b0f82SDamjan Jovanovic     memcpy( pnBuffer, mpnSalt, mnSaltSize );
1784e7b0f82SDamjan Jovanovic 
1794e7b0f82SDamjan Jovanovic     sal_uInt8* pnPasswordLoc = pnBuffer + mnSaltSize;
1804e7b0f82SDamjan Jovanovic     const sal_Unicode* pStr = rPassword.getStr();
1814e7b0f82SDamjan Jovanovic     for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 )
1824e7b0f82SDamjan Jovanovic         ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) );
1834e7b0f82SDamjan Jovanovic 
1844e7b0f82SDamjan Jovanovic     rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
1854e7b0f82SDamjan Jovanovic     rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, nBufferSize );
1864e7b0f82SDamjan Jovanovic     delete[] pnBuffer;
1874e7b0f82SDamjan Jovanovic 
1884e7b0f82SDamjan Jovanovic     size_t nHashSize = RTL_DIGEST_LENGTH_SHA1 + 4;
1894e7b0f82SDamjan Jovanovic     sal_uInt8* pnHash = new sal_uInt8[ nHashSize ];
1904e7b0f82SDamjan Jovanovic     aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
1914e7b0f82SDamjan Jovanovic     rtl_digest_destroy( aDigest );
1924e7b0f82SDamjan Jovanovic 
1934e7b0f82SDamjan Jovanovic     for( sal_uInt32 i = 0; i < 50000; ++i )
1944e7b0f82SDamjan Jovanovic     {
1954e7b0f82SDamjan Jovanovic         ByteOrderConverter::writeLittleEndian( pnHash, i );
1964e7b0f82SDamjan Jovanovic         aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
1974e7b0f82SDamjan Jovanovic         aError = rtl_digest_update( aDigest, pnHash, nHashSize );
1984e7b0f82SDamjan Jovanovic         aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
1994e7b0f82SDamjan Jovanovic         rtl_digest_destroy( aDigest );
2004e7b0f82SDamjan Jovanovic     }
2014e7b0f82SDamjan Jovanovic 
2024e7b0f82SDamjan Jovanovic     memmove( pnHash, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
2034e7b0f82SDamjan Jovanovic     memset( pnHash + RTL_DIGEST_LENGTH_SHA1, 0, 4 );
2044e7b0f82SDamjan Jovanovic     aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
2054e7b0f82SDamjan Jovanovic     aError = rtl_digest_update( aDigest, pnHash, nHashSize );
2064e7b0f82SDamjan Jovanovic     aError = rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 );
2074e7b0f82SDamjan Jovanovic     rtl_digest_destroy( aDigest );
2084e7b0f82SDamjan Jovanovic 
2094e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > key( mnKeySize / 8 );
210d5436bf6SDamjan Jovanovic     deriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, &key[ 0 ], key.size() );
2114e7b0f82SDamjan Jovanovic     delete[] pnHash;
2124e7b0f82SDamjan Jovanovic 
2134e7b0f82SDamjan Jovanovic     Sequence< NamedValue > aResult;
214d5436bf6SDamjan Jovanovic     if( checkEncryptionData( &key[ 0 ], key.size(), mpnEncrVerifier, sizeof( mpnEncrVerifier ), mpnEncrVerifierHash, sizeof( mpnEncrVerifierHash ) ) )
2154e7b0f82SDamjan Jovanovic     {
2164e7b0f82SDamjan Jovanovic         SequenceAsHashMap aEncryptionData;
217d5436bf6SDamjan Jovanovic         aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionKey" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( &key[ 0 ] ), key.size() );
2184e7b0f82SDamjan Jovanovic         aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionSalt" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnSalt ), mnSaltSize );
2194e7b0f82SDamjan Jovanovic         aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifier" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnEncrVerifier ), sizeof( mpnEncrVerifier ) );
2204e7b0f82SDamjan Jovanovic         aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifierHash" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnEncrVerifierHash ), sizeof( mpnEncrVerifierHash ) );
2214e7b0f82SDamjan Jovanovic         encryptionKey = key;
2224e7b0f82SDamjan Jovanovic         aResult = aEncryptionData.getAsConstNamedValueList();
2234e7b0f82SDamjan Jovanovic     }
2244e7b0f82SDamjan Jovanovic 
2254e7b0f82SDamjan Jovanovic     return aResult;
2264e7b0f82SDamjan Jovanovic }
2274e7b0f82SDamjan Jovanovic 
verifyEncryptionData(const Sequence<NamedValue> & rEncryptionData)2284e7b0f82SDamjan Jovanovic bool StandardEncryptionInfo::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception )
2294e7b0f82SDamjan Jovanovic {
2304e7b0f82SDamjan Jovanovic     SequenceAsHashMap aHashData( rEncryptionData );
2314e7b0f82SDamjan Jovanovic     Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionKey" ), Sequence< sal_Int8 >() );
2324e7b0f82SDamjan Jovanovic     Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifier" ), Sequence< sal_Int8 >() );
2334e7b0f82SDamjan Jovanovic     Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifierHash" ), Sequence< sal_Int8 >() );
2344e7b0f82SDamjan Jovanovic     const sal_uInt8 *pnKey = reinterpret_cast< const sal_uInt8* >( aKey.getConstArray() );
2354e7b0f82SDamjan Jovanovic     sal_uInt32 nKeySize = aKey.getLength();
2364e7b0f82SDamjan Jovanovic     const sal_uInt8 *pnVerifier = reinterpret_cast< const sal_uInt8* >( aVerifier.getConstArray() );
2374e7b0f82SDamjan Jovanovic     sal_uInt32 nVerifierSize = aVerifier.getLength();
2384e7b0f82SDamjan Jovanovic     const sal_uInt8 *pnVerifierHash = reinterpret_cast< const sal_uInt8* >( aVerifierHash.getConstArray() );
2394e7b0f82SDamjan Jovanovic     sal_uInt32 nVerifierHashSize = aVerifierHash.getLength();
2404e7b0f82SDamjan Jovanovic     if( checkEncryptionData( pnKey, nKeySize, pnVerifier, nVerifierSize, pnVerifierHash, nVerifierHashSize ) )
2414e7b0f82SDamjan Jovanovic     {
2424e7b0f82SDamjan Jovanovic         encryptionKey = vector< sal_uInt8 >( &pnKey[ 0 ], &pnKey[ nKeySize ] );
2434e7b0f82SDamjan Jovanovic         return true;
2444e7b0f82SDamjan Jovanovic     }
2454e7b0f82SDamjan Jovanovic     else
2464e7b0f82SDamjan Jovanovic         return false;
2474e7b0f82SDamjan Jovanovic }
2484e7b0f82SDamjan Jovanovic 
checkEncryptionData(const sal_uInt8 * pnKey,sal_uInt32 nKeySize,const sal_uInt8 * pnVerifier,sal_uInt32 nVerifierSize,const sal_uInt8 * pnVerifierHash,sal_uInt32 nVerifierHashSize)2494e7b0f82SDamjan Jovanovic bool StandardEncryptionInfo::checkEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize ) throw ( Exception )
2504e7b0f82SDamjan Jovanovic {
2514e7b0f82SDamjan Jovanovic     bool bResult = false;
2524e7b0f82SDamjan Jovanovic 
2534e7b0f82SDamjan Jovanovic     // the only currently supported algorithm needs key size 128
2544e7b0f82SDamjan Jovanovic     if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 )
2554e7b0f82SDamjan Jovanovic     {
2564e7b0f82SDamjan Jovanovic         // check password
2574e7b0f82SDamjan Jovanovic         EVP_CIPHER_CTX *aes_ctx;
2584e7b0f82SDamjan Jovanovic         aes_ctx = EVP_CIPHER_CTX_new();
2594e7b0f82SDamjan Jovanovic         if ( aes_ctx == NULL )
2604e7b0f82SDamjan Jovanovic             return false;
2614e7b0f82SDamjan Jovanovic         EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
2624e7b0f82SDamjan Jovanovic         EVP_CIPHER_CTX_set_padding( aes_ctx, 0 );
2634e7b0f82SDamjan Jovanovic         int nOutLen = 0;
2644e7b0f82SDamjan Jovanovic         sal_uInt8 pnTmpVerifier[ 16 ];
2654e7b0f82SDamjan Jovanovic         (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
2664e7b0f82SDamjan Jovanovic 
2674e7b0f82SDamjan Jovanovic         /*int*/ EVP_DecryptUpdate( aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize );
2684e7b0f82SDamjan Jovanovic         EVP_CIPHER_CTX_free( aes_ctx );
2694e7b0f82SDamjan Jovanovic 
2704e7b0f82SDamjan Jovanovic         aes_ctx = EVP_CIPHER_CTX_new();
2714e7b0f82SDamjan Jovanovic         if ( aes_ctx == NULL )
2724e7b0f82SDamjan Jovanovic             return false;
2734e7b0f82SDamjan Jovanovic         EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
2744e7b0f82SDamjan Jovanovic         EVP_CIPHER_CTX_set_padding( aes_ctx, 0 );
2754e7b0f82SDamjan Jovanovic         sal_uInt8 pnTmpVerifierHash[ 32 ];
2764e7b0f82SDamjan Jovanovic         (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) );
2774e7b0f82SDamjan Jovanovic 
2784e7b0f82SDamjan Jovanovic         /*int*/ EVP_DecryptUpdate( aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize );
2794e7b0f82SDamjan Jovanovic         EVP_CIPHER_CTX_free( aes_ctx );
2804e7b0f82SDamjan Jovanovic 
2814e7b0f82SDamjan Jovanovic         rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
2824e7b0f82SDamjan Jovanovic         rtlDigestError aError = rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) );
2834e7b0f82SDamjan Jovanovic         sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ];
2844e7b0f82SDamjan Jovanovic         aError = rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
2854e7b0f82SDamjan Jovanovic         rtl_digest_destroy( aDigest );
2864e7b0f82SDamjan Jovanovic 
2874e7b0f82SDamjan Jovanovic         bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 );
2884e7b0f82SDamjan Jovanovic     }
2894e7b0f82SDamjan Jovanovic 
2904e7b0f82SDamjan Jovanovic     return bResult;
2914e7b0f82SDamjan Jovanovic }
2924e7b0f82SDamjan Jovanovic 
decryptStream(BinaryXInputStream & aEncryptedPackage,BinaryXOutputStream & aDecryptedPackage)2934e7b0f82SDamjan Jovanovic void StandardEncryptionInfo::decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception )
2944e7b0f82SDamjan Jovanovic {
2954e7b0f82SDamjan Jovanovic     EVP_CIPHER_CTX *aes_ctx;
2964e7b0f82SDamjan Jovanovic     aes_ctx = EVP_CIPHER_CTX_new();
2974e7b0f82SDamjan Jovanovic     if ( aes_ctx == NULL )
2984e7b0f82SDamjan Jovanovic         throw Exception();
299d5436bf6SDamjan Jovanovic     EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, &encryptionKey[ 0 ], 0 );
3004e7b0f82SDamjan Jovanovic     EVP_CIPHER_CTX_set_padding( aes_ctx, 0 );
3014e7b0f82SDamjan Jovanovic 
3024e7b0f82SDamjan Jovanovic     sal_uInt8 pnInBuffer[ 1024 ];
3034e7b0f82SDamjan Jovanovic     sal_uInt8 pnOutBuffer[ 1024 ];
3044e7b0f82SDamjan Jovanovic     sal_Int32 nInLen;
3054e7b0f82SDamjan Jovanovic     int nOutLen;
3064e7b0f82SDamjan Jovanovic     aEncryptedPackage.skip( 8 ); // decrypted size
3074e7b0f82SDamjan Jovanovic     while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 )
3084e7b0f82SDamjan Jovanovic     {
3094e7b0f82SDamjan Jovanovic         EVP_DecryptUpdate( aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen );
3104e7b0f82SDamjan Jovanovic         aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
3114e7b0f82SDamjan Jovanovic     }
3124e7b0f82SDamjan Jovanovic     EVP_DecryptFinal_ex( aes_ctx, pnOutBuffer, &nOutLen );
3134e7b0f82SDamjan Jovanovic     aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
3144e7b0f82SDamjan Jovanovic 
3154e7b0f82SDamjan Jovanovic     EVP_CIPHER_CTX_free( aes_ctx );
3164e7b0f82SDamjan Jovanovic     aDecryptedPackage.flush();
3174e7b0f82SDamjan Jovanovic }
3184e7b0f82SDamjan Jovanovic 
3194e7b0f82SDamjan Jovanovic // ============================================================================
3204e7b0f82SDamjan Jovanovic // "Agile" encryption, 2.3.4.10 of MS-OFFCRYPTO
3214e7b0f82SDamjan Jovanovic // ============================================================================
3224e7b0f82SDamjan Jovanovic 
3234e7b0f82SDamjan Jovanovic struct AgileKeyData
3244e7b0f82SDamjan Jovanovic {
3254e7b0f82SDamjan Jovanovic     sal_Int32 saltSize;
3264e7b0f82SDamjan Jovanovic     sal_Int32 blockSize;
3274e7b0f82SDamjan Jovanovic     sal_Int32 keyBits;
3284e7b0f82SDamjan Jovanovic     sal_Int32 hashSize;
3294e7b0f82SDamjan Jovanovic     OUString cipherAlgorithm;
3304e7b0f82SDamjan Jovanovic     OUString cipherChaining;
3314e7b0f82SDamjan Jovanovic     OUString hashAlgorithm;
3324e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > saltValue;
3334e7b0f82SDamjan Jovanovic };
3344e7b0f82SDamjan Jovanovic 
3354e7b0f82SDamjan Jovanovic struct AgileDataIntegrity
3364e7b0f82SDamjan Jovanovic {
3374e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > encryptedHmacKey;
3384e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > encryptedHmacValue;
3394e7b0f82SDamjan Jovanovic };
3404e7b0f82SDamjan Jovanovic 
3414e7b0f82SDamjan Jovanovic struct AgilePasswordKeyEncryptor
3424e7b0f82SDamjan Jovanovic {
3434e7b0f82SDamjan Jovanovic     sal_Int32 saltSize;
3444e7b0f82SDamjan Jovanovic     sal_Int32 blockSize;
3454e7b0f82SDamjan Jovanovic     sal_Int32 keyBits;
3464e7b0f82SDamjan Jovanovic     sal_Int32 hashSize;
3474e7b0f82SDamjan Jovanovic     OUString cipherAlgorithm;
3484e7b0f82SDamjan Jovanovic     OUString cipherChaining;
3494e7b0f82SDamjan Jovanovic     OUString hashAlgorithm;
3504e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > saltValue;
3514e7b0f82SDamjan Jovanovic     sal_Int32 spinCount;
3524e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > encryptedVerifierHashInput;
3534e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > encryptedVerifierHashValue;
3544e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > encryptedKeyValue;
3554e7b0f82SDamjan Jovanovic };
3564e7b0f82SDamjan Jovanovic 
decodeBase64(OUString & base64,vector<sal_uInt8> & bytes)3574e7b0f82SDamjan Jovanovic static bool decodeBase64( OUString& base64, vector< sal_uInt8 >& bytes )
3584e7b0f82SDamjan Jovanovic {
3594e7b0f82SDamjan Jovanovic     ::rtl::OString base64Ascii = ::rtl::OUStringToOString( base64, RTL_TEXTENCODING_UTF8 );
3604e7b0f82SDamjan Jovanovic     const sal_uInt32 len = base64Ascii.getLength();
3614e7b0f82SDamjan Jovanovic     bytes.resize( (len + 3) / 4 * 3 );
362d5436bf6SDamjan Jovanovic     int decodedSize = EVP_DecodeBlock( &bytes[ 0 ], reinterpret_cast< sal_uInt8 const * >( base64Ascii.getStr() ), len );
3634e7b0f82SDamjan Jovanovic     if ( decodedSize < 0 )
3644e7b0f82SDamjan Jovanovic         return false;
3654e7b0f82SDamjan Jovanovic     if ( len >= 2 && base64Ascii[ len-1 ] == '=' && base64Ascii[ len-2 ] == '=' )
3664e7b0f82SDamjan Jovanovic         decodedSize -= 2;
3674e7b0f82SDamjan Jovanovic     else if ( len >= 1 && base64Ascii[ len-1] == '=' )
3684e7b0f82SDamjan Jovanovic         decodedSize--;
3694e7b0f82SDamjan Jovanovic     bytes.resize( decodedSize );
3704e7b0f82SDamjan Jovanovic     return true;
3714e7b0f82SDamjan Jovanovic }
3724e7b0f82SDamjan Jovanovic 
3734e7b0f82SDamjan Jovanovic class AgileEncryptionInfo : public EncryptionInfo
3744e7b0f82SDamjan Jovanovic {
3754e7b0f82SDamjan Jovanovic public:
3764e7b0f82SDamjan Jovanovic     AgileEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) throw ( Exception );
~AgileEncryptionInfo()3774e7b0f82SDamjan Jovanovic     ~AgileEncryptionInfo() {}
isImplemented()3784e7b0f82SDamjan Jovanovic     bool isImplemented() { return true; } // FIXME
3794e7b0f82SDamjan Jovanovic     Sequence< NamedValue > verifyPassword( const OUString& rPassword ) throw ( Exception );
3804e7b0f82SDamjan Jovanovic     bool verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception );
3814e7b0f82SDamjan Jovanovic     void decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception );
3824e7b0f82SDamjan Jovanovic 
3834e7b0f82SDamjan Jovanovic private:
3844e7b0f82SDamjan Jovanovic     AgileKeyData keyData;
3854e7b0f82SDamjan Jovanovic     AgileDataIntegrity dataIntegrity;
3864e7b0f82SDamjan Jovanovic     AgilePasswordKeyEncryptor passwordKeyEncryptor;
3874e7b0f82SDamjan Jovanovic     vector< sal_uInt8> encryptionKey;
3884e7b0f82SDamjan Jovanovic     vector< sal_uInt8> hmacKey;
3894e7b0f82SDamjan Jovanovic     vector< sal_uInt8> hmacValue;
3904e7b0f82SDamjan Jovanovic };
3914e7b0f82SDamjan Jovanovic 
3924e7b0f82SDamjan Jovanovic // A SAX handler that parses the XML from the "XmlEncryptionDescriptor" in the EncryptionInfo stream.
3934e7b0f82SDamjan Jovanovic class AgileEncryptionHandler : public ::cppu::WeakImplHelper1< XFastDocumentHandler >
3944e7b0f82SDamjan Jovanovic {
3954e7b0f82SDamjan Jovanovic public:
AgileEncryptionHandler(AgileKeyData & aKeyData,AgileDataIntegrity & aDataIntegrity,AgilePasswordKeyEncryptor & aPasswordKeyEncryptor)3964e7b0f82SDamjan Jovanovic     AgileEncryptionHandler( AgileKeyData &aKeyData, AgileDataIntegrity &aDataIntegrity, AgilePasswordKeyEncryptor &aPasswordKeyEncryptor )
3974e7b0f82SDamjan Jovanovic     : keyData( aKeyData ),
3984e7b0f82SDamjan Jovanovic       dataIntegrity( aDataIntegrity ),
3994e7b0f82SDamjan Jovanovic       passwordKeyEncryptor( aPasswordKeyEncryptor )
4004e7b0f82SDamjan Jovanovic     {
4014e7b0f82SDamjan Jovanovic     }
4024e7b0f82SDamjan Jovanovic 
4034e7b0f82SDamjan Jovanovic     // XFastDocumentHandler
4044e7b0f82SDamjan Jovanovic     virtual void SAL_CALL startDocument() throw (SAXException, RuntimeException);
4054e7b0f82SDamjan Jovanovic     virtual void SAL_CALL endDocument() throw (SAXException, RuntimeException);
4064e7b0f82SDamjan Jovanovic     virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) throw (SAXException, RuntimeException);
4074e7b0f82SDamjan Jovanovic 
4084e7b0f82SDamjan Jovanovic     // XFastContextHandler
4094e7b0f82SDamjan Jovanovic     virtual void SAL_CALL startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException);
4104e7b0f82SDamjan Jovanovic     virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException);
4114e7b0f82SDamjan Jovanovic     virtual void SAL_CALL endFastElement( sal_Int32 Element ) throw (SAXException, RuntimeException);
4124e7b0f82SDamjan Jovanovic     virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) throw (SAXException, RuntimeException);
4134e7b0f82SDamjan Jovanovic     virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 Element, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException);
4144e7b0f82SDamjan Jovanovic     virtual Reference< XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException);
4154e7b0f82SDamjan Jovanovic     virtual void SAL_CALL characters( const OUString& aChars ) throw (SAXException, RuntimeException);
4164e7b0f82SDamjan Jovanovic     virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) throw (SAXException, RuntimeException);
4174e7b0f82SDamjan Jovanovic     virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) throw (SAXException, RuntimeException);
4184e7b0f82SDamjan Jovanovic 
getLastError()4194e7b0f82SDamjan Jovanovic     OUString& getLastError() { return lastError; }
4204e7b0f82SDamjan Jovanovic 
4214e7b0f82SDamjan Jovanovic private:
4224e7b0f82SDamjan Jovanovic     void parseKeyData( const AttributeList& attribs ) throw (SAXException, RuntimeException);
4234e7b0f82SDamjan Jovanovic     void parseDataIntegrity( const AttributeList& attribs ) throw (SAXException, RuntimeException);
4244e7b0f82SDamjan Jovanovic     void parseEncryptedKey( const AttributeList& attribs ) throw (SAXException, RuntimeException);
4254e7b0f82SDamjan Jovanovic 
4264e7b0f82SDamjan Jovanovic     vector< sal_Int32 > stack;
4274e7b0f82SDamjan Jovanovic     OUString lastError;
4284e7b0f82SDamjan Jovanovic     AgileKeyData &keyData;
4294e7b0f82SDamjan Jovanovic     AgileDataIntegrity &dataIntegrity;
4304e7b0f82SDamjan Jovanovic     AgilePasswordKeyEncryptor &passwordKeyEncryptor;
4314e7b0f82SDamjan Jovanovic };
4324e7b0f82SDamjan Jovanovic 
startDocument()4334e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startDocument()
4344e7b0f82SDamjan Jovanovic     throw ( SAXException, RuntimeException )
4354e7b0f82SDamjan Jovanovic {
4364e7b0f82SDamjan Jovanovic }
4374e7b0f82SDamjan Jovanovic 
endDocument()4384e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endDocument()
4394e7b0f82SDamjan Jovanovic     throw ( SAXException, RuntimeException )
4404e7b0f82SDamjan Jovanovic {
4414e7b0f82SDamjan Jovanovic }
4424e7b0f82SDamjan Jovanovic 
setDocumentLocator(const Reference<XLocator> &)4434e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::setDocumentLocator( const Reference< XLocator >& )
4444e7b0f82SDamjan Jovanovic     throw ( SAXException, RuntimeException )
4454e7b0f82SDamjan Jovanovic {
4464e7b0f82SDamjan Jovanovic }
4474e7b0f82SDamjan Jovanovic 
startFastElement(sal_Int32 nElement,const Reference<XFastAttributeList> & attribs)4484e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& attribs )
4494e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
4504e7b0f82SDamjan Jovanovic {
4514e7b0f82SDamjan Jovanovic     switch ( nElement )
4524e7b0f82SDamjan Jovanovic     {
4534e7b0f82SDamjan Jovanovic         case ENCRYPTION_TOKEN( encryption ):
4544e7b0f82SDamjan Jovanovic         break;
4554e7b0f82SDamjan Jovanovic 
4564e7b0f82SDamjan Jovanovic         case ENCRYPTION_TOKEN( keyData ):
4574e7b0f82SDamjan Jovanovic             if ( stack.size() == 1 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) )
4584e7b0f82SDamjan Jovanovic                 parseKeyData( AttributeList( attribs ) );
4594e7b0f82SDamjan Jovanovic         break;
4604e7b0f82SDamjan Jovanovic 
4614e7b0f82SDamjan Jovanovic         case ENCRYPTION_TOKEN( dataIntegrity ):
4624e7b0f82SDamjan Jovanovic             if ( stack.size() == 1 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) )
4634e7b0f82SDamjan Jovanovic                 parseDataIntegrity( AttributeList ( attribs ) );
4644e7b0f82SDamjan Jovanovic         break;
4654e7b0f82SDamjan Jovanovic 
4664e7b0f82SDamjan Jovanovic         case ENCRYPTION_TOKEN( keyEncryptors ):
4674e7b0f82SDamjan Jovanovic         break;
4684e7b0f82SDamjan Jovanovic 
4694e7b0f82SDamjan Jovanovic         case ENCRYPTION_TOKEN( keyEncryptor ):
4704e7b0f82SDamjan Jovanovic         break;
4714e7b0f82SDamjan Jovanovic 
4724e7b0f82SDamjan Jovanovic         case KEY_ENCRYPTOR_PASSWORD_TOKEN( encryptedKey ):
4734e7b0f82SDamjan Jovanovic             if ( stack.size() == 3
4744e7b0f82SDamjan Jovanovic                 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption ))
4754e7b0f82SDamjan Jovanovic                 && (stack[ 1 ] == ENCRYPTION_TOKEN( keyEncryptors ))
4764e7b0f82SDamjan Jovanovic                 && (stack[ 2 ] == ENCRYPTION_TOKEN( keyEncryptor )) )
4774e7b0f82SDamjan Jovanovic                 parseEncryptedKey( AttributeList ( attribs ) );
4784e7b0f82SDamjan Jovanovic         break;
4794e7b0f82SDamjan Jovanovic     }
4804e7b0f82SDamjan Jovanovic     stack.push_back( nElement );
4814e7b0f82SDamjan Jovanovic }
4824e7b0f82SDamjan Jovanovic 
startUnknownElement(const OUString &,const OUString &,const Reference<XFastAttributeList> &)4834e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& )
4844e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
4854e7b0f82SDamjan Jovanovic {
4864e7b0f82SDamjan Jovanovic     stack.push_back( -1 );
4874e7b0f82SDamjan Jovanovic }
4884e7b0f82SDamjan Jovanovic 
endFastElement(sal_Int32 nElement)4894e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endFastElement( sal_Int32 nElement )
4904e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
4914e7b0f82SDamjan Jovanovic {
4924e7b0f82SDamjan Jovanovic     stack.pop_back();
4934e7b0f82SDamjan Jovanovic }
4944e7b0f82SDamjan Jovanovic 
endUnknownElement(const OUString &,const OUString &)4954e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endUnknownElement( const OUString&, const OUString& )
4964e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
4974e7b0f82SDamjan Jovanovic {
4984e7b0f82SDamjan Jovanovic     stack.pop_back();
4994e7b0f82SDamjan Jovanovic }
5004e7b0f82SDamjan Jovanovic 
createFastChildContext(sal_Int32,const Reference<XFastAttributeList> &)5014e7b0f82SDamjan Jovanovic Reference< XFastContextHandler > AgileEncryptionHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& )
5024e7b0f82SDamjan Jovanovic     throw (SAXException, RuntimeException)
5034e7b0f82SDamjan Jovanovic {
5044e7b0f82SDamjan Jovanovic     return this;
5054e7b0f82SDamjan Jovanovic }
5064e7b0f82SDamjan Jovanovic 
createUnknownChildContext(const OUString &,const OUString &,const Reference<XFastAttributeList> &)5074e7b0f82SDamjan Jovanovic Reference< XFastContextHandler > AgileEncryptionHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& )
5084e7b0f82SDamjan Jovanovic     throw (SAXException, RuntimeException)
5094e7b0f82SDamjan Jovanovic {
5104e7b0f82SDamjan Jovanovic     return this;
5114e7b0f82SDamjan Jovanovic }
5124e7b0f82SDamjan Jovanovic 
characters(const::rtl::OUString & rStr)5134e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::characters( const ::rtl::OUString& rStr )
5144e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
5154e7b0f82SDamjan Jovanovic {
5164e7b0f82SDamjan Jovanovic }
5174e7b0f82SDamjan Jovanovic 
ignorableWhitespace(const::rtl::OUString & str)5184e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::ignorableWhitespace( const ::rtl::OUString& str )
5194e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
5204e7b0f82SDamjan Jovanovic {
5214e7b0f82SDamjan Jovanovic }
5224e7b0f82SDamjan Jovanovic 
processingInstruction(const::rtl::OUString & aTarget,const::rtl::OUString & aData)5234e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData )
5244e7b0f82SDamjan Jovanovic     throw( SAXException, RuntimeException )
5254e7b0f82SDamjan Jovanovic {
5264e7b0f82SDamjan Jovanovic }
5274e7b0f82SDamjan Jovanovic 
parseKeyData(const AttributeList & attribs)5284e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::parseKeyData( const AttributeList& attribs )
5294e7b0f82SDamjan Jovanovic     throw ( SAXException, RuntimeException )
5304e7b0f82SDamjan Jovanovic {
5314e7b0f82SDamjan Jovanovic     keyData.saltSize = attribs.getInteger( XML_saltSize, 0 );
5324e7b0f82SDamjan Jovanovic     keyData.blockSize = attribs.getInteger( XML_blockSize, 0 );
5334e7b0f82SDamjan Jovanovic     keyData.keyBits = attribs.getInteger( XML_keyBits, 0 );
5344e7b0f82SDamjan Jovanovic     keyData.hashSize = attribs.getInteger( XML_hashSize, 0 );
5354e7b0f82SDamjan Jovanovic     keyData.cipherAlgorithm = attribs.getString( XML_cipherAlgorithm, OUString() );
5364e7b0f82SDamjan Jovanovic     keyData.cipherChaining = attribs.getString( XML_cipherChaining, OUString() );
5374e7b0f82SDamjan Jovanovic     keyData.hashAlgorithm = attribs.getString( XML_hashAlgorithm, OUString() );
5384e7b0f82SDamjan Jovanovic 
5394e7b0f82SDamjan Jovanovic     OUString saltValue = attribs.getString( XML_saltValue, OUString() );
5404e7b0f82SDamjan Jovanovic     if( !decodeBase64( saltValue, keyData.saltValue ) )
5414e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the keyData.saltValue " ) + saltValue;
5424e7b0f82SDamjan Jovanovic }
5434e7b0f82SDamjan Jovanovic 
parseDataIntegrity(const AttributeList & attribs)5444e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::parseDataIntegrity( const AttributeList& attribs )
5454e7b0f82SDamjan Jovanovic     throw ( SAXException, RuntimeException )
5464e7b0f82SDamjan Jovanovic {
5474e7b0f82SDamjan Jovanovic     OUString encryptedHmacKey = attribs.getString( XML_encryptedHmacKey, OUString() );
5484e7b0f82SDamjan Jovanovic     if( !decodeBase64( encryptedHmacKey, dataIntegrity.encryptedHmacKey ) )
5494e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the dataIntegrity.encryptedHmacKey " ) + encryptedHmacKey;
5504e7b0f82SDamjan Jovanovic     OUString encryptedHmacValue = attribs.getString( XML_encryptedHmacValue, OUString() );
5514e7b0f82SDamjan Jovanovic     if( !decodeBase64( encryptedHmacValue, dataIntegrity.encryptedHmacValue ) )
5524e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the dataIntegrity.encryptedHmacValue " ) + encryptedHmacValue;
5534e7b0f82SDamjan Jovanovic }
5544e7b0f82SDamjan Jovanovic 
parseEncryptedKey(const AttributeList & attribs)5554e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::parseEncryptedKey( const AttributeList& attribs )
5564e7b0f82SDamjan Jovanovic     throw ( SAXException, RuntimeException )
5574e7b0f82SDamjan Jovanovic {
5584e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.spinCount = attribs.getInteger( XML_spinCount, 0 );
5594e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.saltSize = attribs.getInteger( XML_saltSize, 0 );
5604e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.blockSize = attribs.getInteger( XML_blockSize, 0 );
5614e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.keyBits = attribs.getInteger( XML_keyBits, 0 );
5624e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.hashSize = attribs.getInteger( XML_hashSize, 0 );
5634e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.cipherAlgorithm = attribs.getString( XML_cipherAlgorithm, OUString() );
5644e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.cipherChaining = attribs.getString( XML_cipherChaining, OUString() );
5654e7b0f82SDamjan Jovanovic     passwordKeyEncryptor.hashAlgorithm = attribs.getString( XML_hashAlgorithm, OUString() );
5664e7b0f82SDamjan Jovanovic     OUString saltValue = attribs.getString( XML_saltValue, OUString() );
5674e7b0f82SDamjan Jovanovic     if( !decodeBase64( saltValue, passwordKeyEncryptor.saltValue ) )
5684e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.saltValue " ) + saltValue;
5694e7b0f82SDamjan Jovanovic     OUString encryptedVerifierHashInput = attribs.getString( XML_encryptedVerifierHashInput, OUString() );
5704e7b0f82SDamjan Jovanovic     if( !decodeBase64( encryptedVerifierHashInput, passwordKeyEncryptor.encryptedVerifierHashInput ) )
5714e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedVerifierHashInput " ) + encryptedVerifierHashInput;
5724e7b0f82SDamjan Jovanovic     OUString encryptedVerifierHashValue = attribs.getString( XML_encryptedVerifierHashValue, OUString() );
5734e7b0f82SDamjan Jovanovic     if( !decodeBase64( encryptedVerifierHashValue, passwordKeyEncryptor.encryptedVerifierHashValue ) )
5744e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedVerifierHashValue " ) + encryptedVerifierHashValue;
5754e7b0f82SDamjan Jovanovic     OUString encryptedKeyValue = attribs.getString( XML_encryptedKeyValue, OUString() );
5764e7b0f82SDamjan Jovanovic     if( !decodeBase64( encryptedKeyValue, passwordKeyEncryptor.encryptedKeyValue ) )
5774e7b0f82SDamjan Jovanovic         lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedKeyValue " ) + encryptedKeyValue;
5784e7b0f82SDamjan Jovanovic }
5794e7b0f82SDamjan Jovanovic 
readUInt16LE(Reference<XInputStream> & inputStream)5804e7b0f82SDamjan Jovanovic static sal_uInt16 readUInt16LE( Reference< XInputStream >& inputStream ) throw ( Exception )
5814e7b0f82SDamjan Jovanovic {
5824e7b0f82SDamjan Jovanovic     Sequence< sal_Int8 > bytes( 2 );
5834e7b0f82SDamjan Jovanovic     sal_Int32 bytesRead = inputStream->readBytes( bytes, 2 );
5844e7b0f82SDamjan Jovanovic     if( bytesRead < 2 )
5854e7b0f82SDamjan Jovanovic         throw new Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() failed, early end of file" ), Reference< XInterface >() );
5864e7b0f82SDamjan Jovanovic     return (sal_uInt16) ( bytes[0] | (bytes[1] << 8) );
5874e7b0f82SDamjan Jovanovic }
5884e7b0f82SDamjan Jovanovic 
readUInt32LE(Reference<XInputStream> & inputStream)5894e7b0f82SDamjan Jovanovic static sal_uInt32 readUInt32LE( Reference< XInputStream >& inputStream ) throw ( Exception )
5904e7b0f82SDamjan Jovanovic {
5914e7b0f82SDamjan Jovanovic     Sequence< sal_Int8 > bytes( 4 );
5924e7b0f82SDamjan Jovanovic     sal_Int32 bytesRead = inputStream->readBytes( bytes, 4 );
5934e7b0f82SDamjan Jovanovic     if( bytesRead < 4 )
5944e7b0f82SDamjan Jovanovic         throw new Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() failed, early end of file" ), Reference< XInterface >() );
5954e7b0f82SDamjan Jovanovic     return (sal_uInt32) ( bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24) );
5964e7b0f82SDamjan Jovanovic }
5974e7b0f82SDamjan Jovanovic 
AgileEncryptionInfo(const Reference<XComponentContext> & context,Reference<XInputStream> & inputStream)5984e7b0f82SDamjan Jovanovic AgileEncryptionInfo::AgileEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) throw ( Exception )
5994e7b0f82SDamjan Jovanovic {
6004e7b0f82SDamjan Jovanovic     sal_uInt32 nReserved = readUInt32LE( inputStream );
6014e7b0f82SDamjan Jovanovic     if( nReserved != 0x40 )
6024e7b0f82SDamjan Jovanovic         throw new Exception( OUString::createFromAscii( "reserved field isn't 0x40" ), Reference< XInterface >() );
6034e7b0f82SDamjan Jovanovic     AgileEncryptionHandler *agileEncryptionHandler = new AgileEncryptionHandler( keyData, dataIntegrity, passwordKeyEncryptor );
6044e7b0f82SDamjan Jovanovic     Reference< XFastDocumentHandler > documentHandler( agileEncryptionHandler );
6054e7b0f82SDamjan Jovanovic     FastParser fastParser( context );
6064e7b0f82SDamjan Jovanovic     fastParser.registerNamespace( NMSP_encryption );
6074e7b0f82SDamjan Jovanovic     fastParser.registerNamespace( NMSP_keyEncryptorPassword );
6084e7b0f82SDamjan Jovanovic     fastParser.setDocumentHandler( documentHandler );
6094e7b0f82SDamjan Jovanovic     fastParser.parseStream( inputStream, OUString::createFromAscii( "EncryptionInfo" ), false );
6104e7b0f82SDamjan Jovanovic     if( !agileEncryptionHandler->getLastError().isEmpty() )
6114e7b0f82SDamjan Jovanovic         throw new Exception( agileEncryptionHandler->getLastError(), Reference< XInterface >() );
6124e7b0f82SDamjan Jovanovic }
6134e7b0f82SDamjan Jovanovic 
toOpenSSLDigestAlgorithm(const OUString & hashAlgorithm)6144e7b0f82SDamjan Jovanovic static const EVP_MD* toOpenSSLDigestAlgorithm( const OUString& hashAlgorithm  ) throw ( Exception )
6154e7b0f82SDamjan Jovanovic {
6164e7b0f82SDamjan Jovanovic     if( hashAlgorithm.equalsAscii( "SHA-1" ) )
6174e7b0f82SDamjan Jovanovic         return EVP_sha1();
6184e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "SHA1" ) ) // Typical Microsoft. The specification says "SHA-1", but documents use "SHA1".
6194e7b0f82SDamjan Jovanovic         return EVP_sha1();
6204e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "SHA256" ) )
6214e7b0f82SDamjan Jovanovic         return EVP_sha256();
6224e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "SHA384" ) )
6234e7b0f82SDamjan Jovanovic         return EVP_sha384();
6244e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "SHA512" ) )
6254e7b0f82SDamjan Jovanovic         return EVP_sha512();
6264e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "MD5" ) )
6274e7b0f82SDamjan Jovanovic         return EVP_md5();
6284e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "MD4" ) )
6294e7b0f82SDamjan Jovanovic         return EVP_md4();
6304e7b0f82SDamjan Jovanovic #if !defined(OPENSSL_NO_MD2)
6314e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "MD2" ) )
6324e7b0f82SDamjan Jovanovic         return EVP_md2();
6334e7b0f82SDamjan Jovanovic #endif
6344e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "RIPEMD-160" ) )
6354e7b0f82SDamjan Jovanovic         return EVP_ripemd160();
6364e7b0f82SDamjan Jovanovic     else if( hashAlgorithm.equalsAscii( "WHIRLPOOL" ) )
6374e7b0f82SDamjan Jovanovic         return EVP_whirlpool();
6384e7b0f82SDamjan Jovanovic     char buffer[ 256 ];
6394e7b0f82SDamjan Jovanovic     ::rtl::OString str = ::rtl::OUStringToOString( hashAlgorithm, RTL_TEXTENCODING_UTF8 );
6404e7b0f82SDamjan Jovanovic     snprintf( buffer, sizeof( buffer ), "Unsupported digest algorithm %s", str.getStr() );
6414e7b0f82SDamjan Jovanovic     throw Exception( OUString::createFromAscii( buffer ), Reference< XInterface >() );
6424e7b0f82SDamjan Jovanovic }
6434e7b0f82SDamjan Jovanovic 
toOpenSSLCipherAlgorithm(const OUString & cipherName,sal_uInt32 keyBits,const OUString & chainingMode)6444e7b0f82SDamjan Jovanovic static const EVP_CIPHER* toOpenSSLCipherAlgorithm( const OUString& cipherName, sal_uInt32 keyBits, const OUString &chainingMode ) throw ( Exception )
6454e7b0f82SDamjan Jovanovic {
6464e7b0f82SDamjan Jovanovic     if( cipherName.equalsAscii( "AES" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6474e7b0f82SDamjan Jovanovic         return EVP_aes_128_cbc();
6484e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "AES" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6494e7b0f82SDamjan Jovanovic         return EVP_aes_128_cfb();
6504e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "AES" ) && keyBits == 192 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6514e7b0f82SDamjan Jovanovic         return EVP_aes_192_cbc();
6524e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "AES" ) && keyBits == 192 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6534e7b0f82SDamjan Jovanovic         return EVP_aes_192_cfb();
6544e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "AES" ) && keyBits == 256 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6554e7b0f82SDamjan Jovanovic         return EVP_aes_256_cbc();
6564e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "AES" ) && keyBits == 256 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6574e7b0f82SDamjan Jovanovic         return EVP_aes_256_cfb();
6584e7b0f82SDamjan Jovanovic #if !defined(OPENSSL_NO_RC2)
6594e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "RC2" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6604e7b0f82SDamjan Jovanovic         return EVP_rc2_cbc();
6614e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "RC2" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6624e7b0f82SDamjan Jovanovic         return EVP_rc2_cfb();
6634e7b0f82SDamjan Jovanovic #endif
6644e7b0f82SDamjan Jovanovic #if !defined(OPENSSL_NO_DES)
6654e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "DES" ) && keyBits == 56 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6664e7b0f82SDamjan Jovanovic         return EVP_des_cbc();
6674e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "DES" ) && keyBits == 56 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6684e7b0f82SDamjan Jovanovic         return EVP_des_cfb();
6694e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "DESX" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6704e7b0f82SDamjan Jovanovic         return EVP_desx_cbc();
6714e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "3DES" ) && keyBits == 168 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6724e7b0f82SDamjan Jovanovic         return EVP_des_ede3_cbc();
6734e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "3DES" ) && keyBits == 168 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6744e7b0f82SDamjan Jovanovic         return EVP_des_ede3_cfb();
6754e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "3DES_112" ) && keyBits == 112 && chainingMode.equalsAscii( "ChainingModeCBC" ) )
6764e7b0f82SDamjan Jovanovic         return EVP_des_ede_cbc();
6774e7b0f82SDamjan Jovanovic     else if( cipherName.equalsAscii( "3DES_112" ) && keyBits == 112 && chainingMode.equalsAscii( "ChainingModeCFB" ) )
6784e7b0f82SDamjan Jovanovic         return EVP_des_ede_cfb();
6794e7b0f82SDamjan Jovanovic #endif
6804e7b0f82SDamjan Jovanovic     char buffer[ 256 ];
6814e7b0f82SDamjan Jovanovic     ::rtl::OString cipherNameUtf8 = ::rtl::OUStringToOString( cipherName, RTL_TEXTENCODING_UTF8 );
6824e7b0f82SDamjan Jovanovic     ::rtl::OString chainingModeUtf8 = ::rtl::OUStringToOString( chainingMode, RTL_TEXTENCODING_UTF8 );
6834e7b0f82SDamjan Jovanovic     snprintf( buffer, sizeof( buffer ), "Unsupported cipher with name=%s, keyBits=%u, chainingMode=%s", cipherNameUtf8.getStr(), keyBits, chainingModeUtf8.getStr() );
6844e7b0f82SDamjan Jovanovic     throw Exception( OUString::createFromAscii( buffer ), Reference< XInterface >() );
6854e7b0f82SDamjan Jovanovic }
6864e7b0f82SDamjan Jovanovic 
6874e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword().
hashPassword(const OUString & password,const EVP_MD * digestAlgorithm,vector<sal_uInt8> & salt,sal_uInt32 spinCount)6884e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > hashPassword( const OUString& password, const EVP_MD *digestAlgorithm, vector< sal_uInt8 >& salt, sal_uInt32 spinCount ) throw ( Exception )
6894e7b0f82SDamjan Jovanovic {
6904e7b0f82SDamjan Jovanovic     OpenSSLDigest digest;
6914e7b0f82SDamjan Jovanovic     digest.initialize( digestAlgorithm );
6924e7b0f82SDamjan Jovanovic     size_t digestSize = digest.digestSize();
6934e7b0f82SDamjan Jovanovic 
6944e7b0f82SDamjan Jovanovic     // Convert to little-endian UTF-16
6954e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > passwordLE( 2 * password.getLength() );
6964e7b0f82SDamjan Jovanovic     for ( int i = 0; i < password.getLength(); i++ )
6974e7b0f82SDamjan Jovanovic         ByteOrderConverter::writeLittleEndian( &passwordLE[ 2 * i ], static_cast< sal_uInt16 >( password[ i ] ) );
6984e7b0f82SDamjan Jovanovic 
6994e7b0f82SDamjan Jovanovic     vector< sal_uInt8> digestBuffer( digestSize );
700d5436bf6SDamjan Jovanovic     digest.update( &salt[ 0 ], salt.size() );
701d5436bf6SDamjan Jovanovic     digest.update( &passwordLE[ 0 ], passwordLE.size() );
702d5436bf6SDamjan Jovanovic     digest.final( &digestBuffer[ 0 ], NULL );
7034e7b0f82SDamjan Jovanovic 
7044e7b0f82SDamjan Jovanovic     char iteratorBuffer[ 4 ];
7054e7b0f82SDamjan Jovanovic     for (sal_uInt32 i = 0; i < spinCount; i++)
7064e7b0f82SDamjan Jovanovic     {
7074e7b0f82SDamjan Jovanovic         digest.initialize( digestAlgorithm );
7084e7b0f82SDamjan Jovanovic         ByteOrderConverter::writeLittleEndian( &iteratorBuffer, i );
7094e7b0f82SDamjan Jovanovic         digest.update( iteratorBuffer, sizeof( iteratorBuffer ) );
710d5436bf6SDamjan Jovanovic         digest.update( &digestBuffer[ 0 ], digestSize );
711d5436bf6SDamjan Jovanovic         digest.final( &digestBuffer[ 0 ], NULL );
7124e7b0f82SDamjan Jovanovic     }
7134e7b0f82SDamjan Jovanovic     return digestBuffer;
7144e7b0f82SDamjan Jovanovic }
7154e7b0f82SDamjan Jovanovic 
7164e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.getBlock36().
toBlock36(vector<sal_uInt8> & digest,sal_uInt32 size)7174e7b0f82SDamjan Jovanovic static void toBlock36( vector< sal_uInt8 >& digest, sal_uInt32 size )
7184e7b0f82SDamjan Jovanovic {
7194e7b0f82SDamjan Jovanovic     if( digest.size() < size )
7204e7b0f82SDamjan Jovanovic     {
7214e7b0f82SDamjan Jovanovic         sal_uInt32 i = digest.size();
7224e7b0f82SDamjan Jovanovic         digest.resize( size );
7234e7b0f82SDamjan Jovanovic         for (; i < size; i++)
7244e7b0f82SDamjan Jovanovic             digest[ i ] = 0x36;
7254e7b0f82SDamjan Jovanovic     }
7264e7b0f82SDamjan Jovanovic     else
7274e7b0f82SDamjan Jovanovic         digest.resize( size );
7284e7b0f82SDamjan Jovanovic }
7294e7b0f82SDamjan Jovanovic 
7304e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0().
toBlock0(vector<sal_uInt8> & digest,sal_uInt32 size)7314e7b0f82SDamjan Jovanovic static void toBlock0( vector< sal_uInt8 >& digest, sal_uInt32 size )
7324e7b0f82SDamjan Jovanovic {
7334e7b0f82SDamjan Jovanovic     if( digest.size() < size )
7344e7b0f82SDamjan Jovanovic     {
7354e7b0f82SDamjan Jovanovic         sal_uInt32 i = digest.size();
7364e7b0f82SDamjan Jovanovic         digest.resize( size );
7374e7b0f82SDamjan Jovanovic         for (; i < size; i++)
7384e7b0f82SDamjan Jovanovic             digest[ i ] = 0;
7394e7b0f82SDamjan Jovanovic     }
7404e7b0f82SDamjan Jovanovic     else
7414e7b0f82SDamjan Jovanovic         digest.resize( size );
7424e7b0f82SDamjan Jovanovic }
7434e7b0f82SDamjan Jovanovic 
7444e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateKey().
generateKey(const vector<sal_uInt8> & passwordHash,const EVP_MD * digestAlgorithm,const vector<sal_uInt8> & blockKey,sal_uInt32 keySize)7454e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > generateKey( const vector< sal_uInt8 >& passwordHash,
7464e7b0f82SDamjan Jovanovic                                         const EVP_MD *digestAlgorithm,
7474e7b0f82SDamjan Jovanovic                                         const vector< sal_uInt8 >& blockKey,
7484e7b0f82SDamjan Jovanovic                                         sal_uInt32 keySize )
7494e7b0f82SDamjan Jovanovic     throw ( Exception )
7504e7b0f82SDamjan Jovanovic {
7514e7b0f82SDamjan Jovanovic     OpenSSLDigest digest;
7524e7b0f82SDamjan Jovanovic     digest.initialize( digestAlgorithm );
753d5436bf6SDamjan Jovanovic     digest.update( &passwordHash[ 0 ], passwordHash.size() );
754d5436bf6SDamjan Jovanovic     digest.update( &blockKey[ 0 ], blockKey.size() );
7554e7b0f82SDamjan Jovanovic     vector< sal_uInt8> key( digest.digestSize() );
756d5436bf6SDamjan Jovanovic     digest.final( &key[ 0 ], NULL );
7574e7b0f82SDamjan Jovanovic     toBlock36( key, keySize );
7584e7b0f82SDamjan Jovanovic     return key;
7594e7b0f82SDamjan Jovanovic }
7604e7b0f82SDamjan Jovanovic 
7614e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateIv().
generateIv(const vector<sal_uInt8> & salt,sal_uInt32 blockSize)7624e7b0f82SDamjan Jovanovic static vector< sal_uInt8> generateIv( const vector< sal_uInt8 >& salt,
7634e7b0f82SDamjan Jovanovic                                       sal_uInt32 blockSize )
7644e7b0f82SDamjan Jovanovic     throw ( Exception )
7654e7b0f82SDamjan Jovanovic {
7664e7b0f82SDamjan Jovanovic     vector< sal_uInt8> iv( salt );
7674e7b0f82SDamjan Jovanovic     toBlock36( iv, blockSize );
7684e7b0f82SDamjan Jovanovic     return iv;
7694e7b0f82SDamjan Jovanovic }
7704e7b0f82SDamjan Jovanovic 
7714e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateIv().
generateIv(const EVP_MD * digestAlgorithm,const vector<sal_uInt8> & salt,const vector<sal_uInt8> & blockKey,sal_uInt32 blockSize)7724e7b0f82SDamjan Jovanovic static vector< sal_uInt8> generateIv( const EVP_MD *digestAlgorithm,
7734e7b0f82SDamjan Jovanovic                                       const vector< sal_uInt8 >& salt,
7744e7b0f82SDamjan Jovanovic                                       const vector< sal_uInt8 >& blockKey,
7754e7b0f82SDamjan Jovanovic                                       sal_uInt32 blockSize )
7764e7b0f82SDamjan Jovanovic     throw ( Exception )
7774e7b0f82SDamjan Jovanovic {
7784e7b0f82SDamjan Jovanovic     OpenSSLDigest digest;
7794e7b0f82SDamjan Jovanovic     digest.initialize( digestAlgorithm );
780d5436bf6SDamjan Jovanovic     digest.update( &salt[ 0 ], salt.size() );
781d5436bf6SDamjan Jovanovic     digest.update( &blockKey[ 0 ], blockKey.size() );
7824e7b0f82SDamjan Jovanovic     vector< sal_uInt8> iv( digest.digestSize() );
783d5436bf6SDamjan Jovanovic     digest.final( &iv[ 0 ], NULL );
7844e7b0f82SDamjan Jovanovic     toBlock36( iv, blockSize );
7854e7b0f82SDamjan Jovanovic     return iv;
7864e7b0f82SDamjan Jovanovic }
7874e7b0f82SDamjan Jovanovic 
7884e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.getNextBlockSize().
getNextBlockSize(sal_uInt32 totalSize,sal_uInt32 blockSize)7894e7b0f82SDamjan Jovanovic static sal_uInt32 getNextBlockSize( sal_uInt32 totalSize, sal_uInt32 blockSize )
7904e7b0f82SDamjan Jovanovic {
7914e7b0f82SDamjan Jovanovic     sal_uInt32 numberOfBlocks = ( totalSize + ( blockSize - 1 ) ) / blockSize;
7924e7b0f82SDamjan Jovanovic     return numberOfBlocks * blockSize;
7934e7b0f82SDamjan Jovanovic }
7944e7b0f82SDamjan Jovanovic 
decryptAll(const EVP_CIPHER * cipherAlgorithm,const sal_uInt8 * iv,const sal_uInt8 * key,const sal_uInt8 * encryptedData,sal_uInt32 encryptedDataLength)7954e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > decryptAll( const EVP_CIPHER* cipherAlgorithm,
7964e7b0f82SDamjan Jovanovic                                        const sal_uInt8* iv,
7974e7b0f82SDamjan Jovanovic                                        const sal_uInt8* key,
7984e7b0f82SDamjan Jovanovic                                        const sal_uInt8* encryptedData,
7994e7b0f82SDamjan Jovanovic                                        sal_uInt32 encryptedDataLength )
8004e7b0f82SDamjan Jovanovic     throw ( Exception )
8014e7b0f82SDamjan Jovanovic {
8024e7b0f82SDamjan Jovanovic     OpenSSLCipher cipher;
8034e7b0f82SDamjan Jovanovic     cipher.initialize( cipherAlgorithm, key, iv, 0 );
8044e7b0f82SDamjan Jovanovic     cipher.setPadding( 0 );
805*31bd0d21SDamjan Jovanovic     const int blockSize = OpenSSLCipher::blockSize( cipherAlgorithm );
8064e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > decryptedData( encryptedDataLength + 2*blockSize );
8074e7b0f82SDamjan Jovanovic 
8084e7b0f82SDamjan Jovanovic     int decryptedDataLength;
809d5436bf6SDamjan Jovanovic     cipher.update( encryptedData, encryptedDataLength, &decryptedData[ 0 ], &decryptedDataLength );
8104e7b0f82SDamjan Jovanovic     int finalDataLength;
8114e7b0f82SDamjan Jovanovic     cipher.final( &decryptedData[ decryptedDataLength ], &finalDataLength );
8124e7b0f82SDamjan Jovanovic     decryptedDataLength += finalDataLength;
8134e7b0f82SDamjan Jovanovic     decryptedData.resize( decryptedDataLength );
8144e7b0f82SDamjan Jovanovic     return decryptedData;
8154e7b0f82SDamjan Jovanovic }
8164e7b0f82SDamjan Jovanovic 
8174e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.hashInput().
hashInput(const vector<sal_uInt8> & passwordHash,const vector<sal_uInt8> & salt,const EVP_MD * digestAlgorithm,const vector<sal_uInt8> & blockKey,const vector<sal_uInt8> & inputKey,const EVP_CIPHER * decryptionAlgorithm,sal_uInt32 keySize,sal_uInt32 blockSize)8184e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > hashInput( const vector< sal_uInt8 >& passwordHash,
8194e7b0f82SDamjan Jovanovic                                       const vector< sal_uInt8 >& salt,
8204e7b0f82SDamjan Jovanovic                                       const EVP_MD *digestAlgorithm,
8214e7b0f82SDamjan Jovanovic                                       const vector< sal_uInt8 >& blockKey,
8224e7b0f82SDamjan Jovanovic                                       const vector< sal_uInt8 >& inputKey,
8234e7b0f82SDamjan Jovanovic                                       const EVP_CIPHER *decryptionAlgorithm,
8244e7b0f82SDamjan Jovanovic                                       sal_uInt32 keySize,
8254e7b0f82SDamjan Jovanovic                                       sal_uInt32 blockSize )
8264e7b0f82SDamjan Jovanovic     throw ( Exception )
8274e7b0f82SDamjan Jovanovic {
8284e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > intermediateKey = generateKey( passwordHash, digestAlgorithm, blockKey, keySize );
8294e7b0f82SDamjan Jovanovic     vector< sal_uInt8> iv = generateIv( salt, blockSize );
8304e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > zeroedInput( inputKey.size() );
8314e7b0f82SDamjan Jovanovic     zeroedInput = inputKey;
8324e7b0f82SDamjan Jovanovic     toBlock0( zeroedInput, getNextBlockSize( zeroedInput.size(), blockSize ) );
833d5436bf6SDamjan Jovanovic     return decryptAll( decryptionAlgorithm, &iv[ 0 ], &intermediateKey[ 0 ], &zeroedInput[ 0 ], zeroedInput.size() );
8344e7b0f82SDamjan Jovanovic }
8354e7b0f82SDamjan Jovanovic 
8364e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.verifyPassword().
verifyPassword(const OUString & password)8374e7b0f82SDamjan Jovanovic Sequence< NamedValue > AgileEncryptionInfo::verifyPassword( const OUString& password )
8384e7b0f82SDamjan Jovanovic     throw ( Exception )
8394e7b0f82SDamjan Jovanovic {
8404e7b0f82SDamjan Jovanovic     const EVP_MD *digestAlgorithm = toOpenSSLDigestAlgorithm( passwordKeyEncryptor.hashAlgorithm );
8414e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > passwordHash = hashPassword( password, digestAlgorithm, passwordKeyEncryptor.saltValue, passwordKeyEncryptor.spinCount );
8424e7b0f82SDamjan Jovanovic 
8434e7b0f82SDamjan Jovanovic     static const sal_uInt8 verifierInputBlockData[] = { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
8444e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > verifierInputBlock( &verifierInputBlockData[ 0 ], &verifierInputBlockData[ sizeof( verifierInputBlockData ) ] );
8454e7b0f82SDamjan Jovanovic     const EVP_CIPHER* cipher = toOpenSSLCipherAlgorithm( passwordKeyEncryptor.cipherAlgorithm, passwordKeyEncryptor.keyBits, passwordKeyEncryptor.cipherChaining );
8464e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > encryptedVerifierHash = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, verifierInputBlock,
8474e7b0f82SDamjan Jovanovic                                                            passwordKeyEncryptor.encryptedVerifierHashInput, cipher, passwordKeyEncryptor.keyBits,
8484e7b0f82SDamjan Jovanovic                                                            passwordKeyEncryptor.blockSize );
8494e7b0f82SDamjan Jovanovic     const EVP_MD *verifierDigestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm );
8504e7b0f82SDamjan Jovanovic     OpenSSLDigest verifierDigest;
8514e7b0f82SDamjan Jovanovic     verifierDigest.initialize( verifierDigestAlgorithm );
852d5436bf6SDamjan Jovanovic     verifierDigest.update( &encryptedVerifierHash[ 0 ], encryptedVerifierHash.size() );
8534e7b0f82SDamjan Jovanovic     encryptedVerifierHash.resize( verifierDigest.digestSize() );
854d5436bf6SDamjan Jovanovic     verifierDigest.final( &encryptedVerifierHash[ 0 ], NULL );
8554e7b0f82SDamjan Jovanovic 
8564e7b0f82SDamjan Jovanovic     static const sal_uInt8 verifierHashBlockData[] = { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
8574e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > verifierHashBlock( &verifierHashBlockData[ 0 ], &verifierHashBlockData[ sizeof( verifierHashBlockData ) ] );
8584e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > verifierHashDec = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, verifierHashBlock,
8594e7b0f82SDamjan Jovanovic                                                      passwordKeyEncryptor.encryptedVerifierHashValue, cipher, passwordKeyEncryptor.keyBits,
8604e7b0f82SDamjan Jovanovic                                                      passwordKeyEncryptor.blockSize );
8614e7b0f82SDamjan Jovanovic     toBlock0( verifierHashDec, verifierDigest.digestSize() );
8624e7b0f82SDamjan Jovanovic 
8634e7b0f82SDamjan Jovanovic     if( encryptedVerifierHash != verifierHashDec )
8644e7b0f82SDamjan Jovanovic         return Sequence< NamedValue >();
8654e7b0f82SDamjan Jovanovic 
8664e7b0f82SDamjan Jovanovic     // Password is correct. Decrypt and store the encryption key.
8674e7b0f82SDamjan Jovanovic     static const sal_uInt8 cryptoKeyBlockData[] = { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
8684e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > cryptoKeyBlock( &cryptoKeyBlockData[ 0 ], &cryptoKeyBlockData[ sizeof( cryptoKeyBlockData ) ] );
8694e7b0f82SDamjan Jovanovic     encryptionKey = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, cryptoKeyBlock,
8704e7b0f82SDamjan Jovanovic                                passwordKeyEncryptor.encryptedKeyValue, cipher, passwordKeyEncryptor.keyBits,
8714e7b0f82SDamjan Jovanovic                                passwordKeyEncryptor.blockSize );
8724e7b0f82SDamjan Jovanovic     toBlock0( encryptionKey, passwordKeyEncryptor.keyBits / 8 );
8734e7b0f82SDamjan Jovanovic 
8744e7b0f82SDamjan Jovanovic     // Also decrypt the dataIntegrity fields for stream validation. Note that they are optional.
8754e7b0f82SDamjan Jovanovic     if( !dataIntegrity.encryptedHmacKey.empty() && !dataIntegrity.encryptedHmacValue.empty() )
8764e7b0f82SDamjan Jovanovic     {
8774e7b0f82SDamjan Jovanovic         const EVP_MD* keyDataDigestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm );
8784e7b0f82SDamjan Jovanovic         const EVP_CIPHER* keyDataCipher = toOpenSSLCipherAlgorithm( keyData.cipherAlgorithm, keyData.keyBits, keyData.cipherChaining );
8794e7b0f82SDamjan Jovanovic         static const sal_uInt8 integrityKeyBlockData[] = { 0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, 0xf6 };
8804e7b0f82SDamjan Jovanovic         vector< sal_uInt8 > integrityKeyBlock( &integrityKeyBlockData[ 0 ], &integrityKeyBlockData[ sizeof( integrityKeyBlockData ) ] );
8814e7b0f82SDamjan Jovanovic         vector< sal_uInt8 > integrityKeyIv = generateIv( keyDataDigestAlgorithm, keyData.saltValue, integrityKeyBlock, keyData.blockSize );
882d5436bf6SDamjan Jovanovic         hmacKey = decryptAll( keyDataCipher, &integrityKeyIv[ 0 ], &encryptionKey[ 0 ], &dataIntegrity.encryptedHmacKey[ 0 ], dataIntegrity.encryptedHmacKey.size() );
8834e7b0f82SDamjan Jovanovic         toBlock0( hmacKey, OpenSSLDigest::digestSize( keyDataDigestAlgorithm ) );
8844e7b0f82SDamjan Jovanovic 
8854e7b0f82SDamjan Jovanovic         static const sal_uInt8 integrityValueBlockData[] = { 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, 0x33 };
8864e7b0f82SDamjan Jovanovic         vector< sal_uInt8 > integrityValueBlock( &integrityValueBlockData[ 0 ], &integrityValueBlockData[ sizeof( integrityValueBlockData ) ] );
8874e7b0f82SDamjan Jovanovic         vector< sal_uInt8 > integrityValueIv = generateIv( keyDataDigestAlgorithm, keyData.saltValue, integrityValueBlock, keyData.blockSize );
888d5436bf6SDamjan Jovanovic         hmacValue = decryptAll( keyDataCipher, &integrityValueIv[ 0 ], &encryptionKey[ 0 ], &dataIntegrity.encryptedHmacValue[ 0 ], dataIntegrity.encryptedHmacValue.size() );
8894e7b0f82SDamjan Jovanovic         toBlock0( hmacValue, OpenSSLDigest::digestSize( keyDataDigestAlgorithm ) );
8904e7b0f82SDamjan Jovanovic     }
8914e7b0f82SDamjan Jovanovic 
8924e7b0f82SDamjan Jovanovic     // On success, MUST populate something into the encryption data, even though we'll never use it.
8934e7b0f82SDamjan Jovanovic     SequenceAsHashMap encryptionData;
8944e7b0f82SDamjan Jovanovic     encryptionData[ CREATE_OUSTRING( "OOXMLAgileEncryptionPasswordVerified" ) ] <<= sal_True;
8954e7b0f82SDamjan Jovanovic     return encryptionData.getAsConstNamedValueList();
8964e7b0f82SDamjan Jovanovic }
8974e7b0f82SDamjan Jovanovic 
verifyEncryptionData(const Sequence<NamedValue> & rEncryptionData)8984e7b0f82SDamjan Jovanovic bool AgileEncryptionInfo::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
8994e7b0f82SDamjan Jovanovic     throw ( Exception )
9004e7b0f82SDamjan Jovanovic {
9014e7b0f82SDamjan Jovanovic     // OpenGrok shows how only main/comphelper/source/misc/docpasswordhelper.cxx calls IDocPasswordVerifier::verifyEncryptionData(),
9024e7b0f82SDamjan Jovanovic     // and only when the password is wrong and the rMediaEncData non-empty, which presumably allows other forms of encryption
9034e7b0f82SDamjan Jovanovic     // (eg. by certificate) to be used. We only support password for now.
9044e7b0f82SDamjan Jovanovic     return false;
9054e7b0f82SDamjan Jovanovic }
9064e7b0f82SDamjan Jovanovic 
9074e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.initCipherForBlock().
decryptStream(BinaryXInputStream & aEncryptedPackage,BinaryXOutputStream & aDecryptedPackage)9084e7b0f82SDamjan Jovanovic void AgileEncryptionInfo::decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage )
9094e7b0f82SDamjan Jovanovic     throw ( Exception )
9104e7b0f82SDamjan Jovanovic {
9114e7b0f82SDamjan Jovanovic     if( encryptionKey.empty() )
9124e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( "Encryption key not set, was the password wrong?" ), Reference< XInterface >() );
9134e7b0f82SDamjan Jovanovic     const EVP_CIPHER* cipherAlgorithm = toOpenSSLCipherAlgorithm( keyData.cipherAlgorithm, keyData.keyBits, keyData.cipherChaining );
9144e7b0f82SDamjan Jovanovic     const EVP_MD* digestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm );
9154e7b0f82SDamjan Jovanovic     OpenSSLCipher cipher;
9164e7b0f82SDamjan Jovanovic 
9174e7b0f82SDamjan Jovanovic     const sal_uInt64 decryptedSize = aEncryptedPackage.readuInt64();
9184e7b0f82SDamjan Jovanovic 
9194e7b0f82SDamjan Jovanovic     sal_uInt8 inputBuffer[ 4096 ];
920*31bd0d21SDamjan Jovanovic     vector< sal_uInt8 > outputBuffer( 4096 + 2*OpenSSLCipher::blockSize( cipherAlgorithm ) );
9214e7b0f82SDamjan Jovanovic     sal_Int32 bytesIn;
9224e7b0f82SDamjan Jovanovic     int bytesOut;
9234e7b0f82SDamjan Jovanovic     int finalBytesOut;
9244e7b0f82SDamjan Jovanovic     sal_uInt64 totalBytesWritten = 0;
9254e7b0f82SDamjan Jovanovic 
9264e7b0f82SDamjan Jovanovic     vector< sal_uInt8 > blockBytes( 4 );
9274e7b0f82SDamjan Jovanovic     bool done = false;
9284e7b0f82SDamjan Jovanovic     for ( sal_uInt32 block = 0; !done; block++ )
9294e7b0f82SDamjan Jovanovic     {
930d5436bf6SDamjan Jovanovic         ByteOrderConverter::writeLittleEndian( &blockBytes[ 0 ], block );
9314e7b0f82SDamjan Jovanovic         vector< sal_uInt8 > iv = generateIv( digestAlgorithm, keyData.saltValue, blockBytes, keyData.blockSize );
932d5436bf6SDamjan Jovanovic         cipher.initialize( cipherAlgorithm, &encryptionKey[ 0 ], &iv[ 0 ], 0 );
9334e7b0f82SDamjan Jovanovic         cipher.setPadding( 0 );
9344e7b0f82SDamjan Jovanovic 
9354e7b0f82SDamjan Jovanovic         bytesIn = aEncryptedPackage.readMemory( inputBuffer, sizeof( inputBuffer ) );
9364e7b0f82SDamjan Jovanovic         if( bytesIn > 0 )
9374e7b0f82SDamjan Jovanovic         {
938d5436bf6SDamjan Jovanovic             cipher.update( inputBuffer, bytesIn, &outputBuffer[ 0 ], &bytesOut );
9394e7b0f82SDamjan Jovanovic             cipher.final( &outputBuffer[ bytesOut ], &finalBytesOut );
9404e7b0f82SDamjan Jovanovic             bytesOut += finalBytesOut;
9414e7b0f82SDamjan Jovanovic             if( decryptedSize < (totalBytesWritten + bytesOut) )
9424e7b0f82SDamjan Jovanovic             {
9434e7b0f82SDamjan Jovanovic                 bytesOut = decryptedSize % sizeof( inputBuffer );
9444e7b0f82SDamjan Jovanovic                 done = true;
9454e7b0f82SDamjan Jovanovic             }
946d5436bf6SDamjan Jovanovic             aDecryptedPackage.writeMemory( &outputBuffer[ 0 ], bytesOut );
9474e7b0f82SDamjan Jovanovic             totalBytesWritten += bytesOut;
9484e7b0f82SDamjan Jovanovic         } else
9494e7b0f82SDamjan Jovanovic             done = true;
9504e7b0f82SDamjan Jovanovic     }
9514e7b0f82SDamjan Jovanovic 
9524e7b0f82SDamjan Jovanovic     aDecryptedPackage.flush();
9534e7b0f82SDamjan Jovanovic }
9544e7b0f82SDamjan Jovanovic 
readEncryptionInfo(const Reference<XComponentContext> & context,Reference<XInputStream> & inputStream)9554e7b0f82SDamjan Jovanovic EncryptionInfo* EncryptionInfo::readEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream )
9564e7b0f82SDamjan Jovanovic     throw ( Exception )
9574e7b0f82SDamjan Jovanovic {
9584e7b0f82SDamjan Jovanovic     sal_uInt16 nVersionMajor = readUInt16LE( inputStream );
9594e7b0f82SDamjan Jovanovic     sal_uInt16 nVersionMinor = readUInt16LE( inputStream );
9604e7b0f82SDamjan Jovanovic     if( ( nVersionMajor == 2 && nVersionMinor == 2 ) ||
9614e7b0f82SDamjan Jovanovic         ( nVersionMajor == 3 && nVersionMinor == 2 ) ||
9624e7b0f82SDamjan Jovanovic         ( nVersionMajor == 4 && nVersionMinor == 2 ) )
9634e7b0f82SDamjan Jovanovic     {
9644e7b0f82SDamjan Jovanovic         // 2.3.4.5 Standard Encryption
9654e7b0f82SDamjan Jovanovic         BinaryXInputStream aInfoStrm( inputStream, false );
9664e7b0f82SDamjan Jovanovic         return new StandardEncryptionInfo( aInfoStrm );
9674e7b0f82SDamjan Jovanovic     }
9684e7b0f82SDamjan Jovanovic     else if ( nVersionMajor == 4 && nVersionMajor == 4 )
9694e7b0f82SDamjan Jovanovic     {
9704e7b0f82SDamjan Jovanovic         // 2.3.4.10 Agile Encryption
9714e7b0f82SDamjan Jovanovic         return new AgileEncryptionInfo( context, inputStream );
9724e7b0f82SDamjan Jovanovic     }
9734e7b0f82SDamjan Jovanovic     else
9744e7b0f82SDamjan Jovanovic     {
9754e7b0f82SDamjan Jovanovic         char msg[ 1024 ];
9764e7b0f82SDamjan Jovanovic         snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: unsupported EncryptionVersionInfo header with major=%hu minor=%hu",
9774e7b0f82SDamjan Jovanovic             nVersionMajor, nVersionMinor );
9784e7b0f82SDamjan Jovanovic         throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() );
9794e7b0f82SDamjan Jovanovic     }
9804e7b0f82SDamjan Jovanovic }
9814e7b0f82SDamjan Jovanovic 
9824e7b0f82SDamjan Jovanovic // ============================================================================
9834e7b0f82SDamjan Jovanovic 
9844e7b0f82SDamjan Jovanovic } // namespace core
9854e7b0f82SDamjan Jovanovic } // namespace oox
986