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 ); 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 964e7b0f82SDamjan Jovanovic StandardEncryptionInfo::StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception ) 974e7b0f82SDamjan Jovanovic { 984e7b0f82SDamjan Jovanovic char msg[ 1024 ]; 994e7b0f82SDamjan Jovanovic rStrm >> mnFlags; 100*ae7dce1fSDamjan 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 1314e7b0f82SDamjan Jovanovic bool StandardEncryptionInfo::isImplemented() 1324e7b0f82SDamjan Jovanovic { 133*ae7dce1fSDamjan Jovanovic return getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_CRYPTOAPI ) && 134*ae7dce1fSDamjan 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 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 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 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 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 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 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 ); 3774e7b0f82SDamjan Jovanovic ~AgileEncryptionInfo() {} 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: 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 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 4334e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startDocument() 4344e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 4354e7b0f82SDamjan Jovanovic { 4364e7b0f82SDamjan Jovanovic } 4374e7b0f82SDamjan Jovanovic 4384e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endDocument() 4394e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 4404e7b0f82SDamjan Jovanovic { 4414e7b0f82SDamjan Jovanovic } 4424e7b0f82SDamjan Jovanovic 4434e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::setDocumentLocator( const Reference< XLocator >& ) 4444e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 4454e7b0f82SDamjan Jovanovic { 4464e7b0f82SDamjan Jovanovic } 4474e7b0f82SDamjan Jovanovic 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 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 4894e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endFastElement( sal_Int32 nElement ) 4904e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 4914e7b0f82SDamjan Jovanovic { 4924e7b0f82SDamjan Jovanovic stack.pop_back(); 4934e7b0f82SDamjan Jovanovic } 4944e7b0f82SDamjan Jovanovic 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 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 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 5134e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::characters( const ::rtl::OUString& rStr ) 5144e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 5154e7b0f82SDamjan Jovanovic { 5164e7b0f82SDamjan Jovanovic } 5174e7b0f82SDamjan Jovanovic 5184e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::ignorableWhitespace( const ::rtl::OUString& str ) 5194e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 5204e7b0f82SDamjan Jovanovic { 5214e7b0f82SDamjan Jovanovic } 5224e7b0f82SDamjan Jovanovic 5234e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) 5244e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 5254e7b0f82SDamjan Jovanovic { 5264e7b0f82SDamjan Jovanovic } 5274e7b0f82SDamjan Jovanovic 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 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 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 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 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 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 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 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(). 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(). 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(). 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(). 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(). 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(). 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(). 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 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 ); 8054e7b0f82SDamjan Jovanovic const int blockSize = cipher.blockSize(); 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(). 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(). 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 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(). 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 ]; 9204e7b0f82SDamjan Jovanovic vector< sal_uInt8 > outputBuffer( 4096 + 2*cipher.blockSize() ); 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 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