1*4e7b0f82SDamjan Jovanovic /************************************************************** 2*4e7b0f82SDamjan Jovanovic * 3*4e7b0f82SDamjan Jovanovic * Licensed to the Apache Software Foundation (ASF) under one 4*4e7b0f82SDamjan Jovanovic * or more contributor license agreements. See the NOTICE file 5*4e7b0f82SDamjan Jovanovic * distributed with this work for additional information 6*4e7b0f82SDamjan Jovanovic * regarding copyright ownership. The ASF licenses this file 7*4e7b0f82SDamjan Jovanovic * to you under the Apache License, Version 2.0 (the 8*4e7b0f82SDamjan Jovanovic * "License"); you may not use this file except in compliance 9*4e7b0f82SDamjan Jovanovic * with the License. You may obtain a copy of the License at 10*4e7b0f82SDamjan Jovanovic * 11*4e7b0f82SDamjan Jovanovic * http://www.apache.org/licenses/LICENSE-2.0 12*4e7b0f82SDamjan Jovanovic * 13*4e7b0f82SDamjan Jovanovic * Unless required by applicable law or agreed to in writing, 14*4e7b0f82SDamjan Jovanovic * software distributed under the License is distributed on an 15*4e7b0f82SDamjan Jovanovic * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*4e7b0f82SDamjan Jovanovic * KIND, either express or implied. See the License for the 17*4e7b0f82SDamjan Jovanovic * specific language governing permissions and limitations 18*4e7b0f82SDamjan Jovanovic * under the License. 19*4e7b0f82SDamjan Jovanovic * 20*4e7b0f82SDamjan Jovanovic *************************************************************/ 21*4e7b0f82SDamjan Jovanovic 22*4e7b0f82SDamjan Jovanovic 23*4e7b0f82SDamjan Jovanovic 24*4e7b0f82SDamjan Jovanovic #include "oox/core/encryption.hxx" 25*4e7b0f82SDamjan Jovanovic #include "oox/core/fastparser.hxx" 26*4e7b0f82SDamjan Jovanovic #include "oox/helper/attributelist.hxx" 27*4e7b0f82SDamjan Jovanovic #include "oox/helper/helper.hxx" 28*4e7b0f82SDamjan Jovanovic #include "oox/helper/openssl_wrapper.hxx" 29*4e7b0f82SDamjan Jovanovic 30*4e7b0f82SDamjan Jovanovic #include <rtl/digest.h> 31*4e7b0f82SDamjan Jovanovic #include <cppuhelper/implbase1.hxx> 32*4e7b0f82SDamjan Jovanovic #include <openssl/evp.h> 33*4e7b0f82SDamjan Jovanovic 34*4e7b0f82SDamjan Jovanovic #include <com/sun/star/io/XStream.hpp> 35*4e7b0f82SDamjan Jovanovic 36*4e7b0f82SDamjan Jovanovic 37*4e7b0f82SDamjan Jovanovic 38*4e7b0f82SDamjan Jovanovic namespace oox { 39*4e7b0f82SDamjan Jovanovic namespace core { 40*4e7b0f82SDamjan Jovanovic 41*4e7b0f82SDamjan Jovanovic // ============================================================================ 42*4e7b0f82SDamjan Jovanovic 43*4e7b0f82SDamjan Jovanovic using namespace ::com::sun::star::beans; 44*4e7b0f82SDamjan Jovanovic using namespace ::com::sun::star::uno; 45*4e7b0f82SDamjan Jovanovic using namespace ::com::sun::star::xml::sax; 46*4e7b0f82SDamjan Jovanovic 47*4e7b0f82SDamjan Jovanovic using ::com::sun::star::io::XInputStream; 48*4e7b0f82SDamjan Jovanovic using ::comphelper::SequenceAsHashMap; 49*4e7b0f82SDamjan Jovanovic using ::rtl::OUString; 50*4e7b0f82SDamjan Jovanovic using ::std::vector; 51*4e7b0f82SDamjan Jovanovic 52*4e7b0f82SDamjan Jovanovic // ============================================================================ 53*4e7b0f82SDamjan Jovanovic 54*4e7b0f82SDamjan Jovanovic 55*4e7b0f82SDamjan Jovanovic /* =========================================================================== */ 56*4e7b0f82SDamjan Jovanovic /* Kudos to Caolan McNamara who provided the core decryption implementation */ 57*4e7b0f82SDamjan Jovanovic /* of Standard Encryption (MS-OFFCRYPTO section 2.3.4.5). */ 58*4e7b0f82SDamjan Jovanovic /* =========================================================================== */ 59*4e7b0f82SDamjan Jovanovic 60*4e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_CRYPTOAPI 0x00000004U 61*4e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_DOCPROPS 0x00000008U 62*4e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_EXTERNAL 0x00000010U 63*4e7b0f82SDamjan Jovanovic #define ENCRYPTINFO_AES 0x00000020U 64*4e7b0f82SDamjan Jovanovic 65*4e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_AES128 0x0000660EU 66*4e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_AES192 0x0000660FU 67*4e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_AES256 0x00006610U 68*4e7b0f82SDamjan Jovanovic #define ENCRYPT_ALGO_RC4 0x00006801U 69*4e7b0f82SDamjan Jovanovic 70*4e7b0f82SDamjan Jovanovic #define ENCRYPT_HASH_SHA1 0x00008004U 71*4e7b0f82SDamjan Jovanovic 72*4e7b0f82SDamjan Jovanovic class StandardEncryptionInfo : public EncryptionInfo 73*4e7b0f82SDamjan Jovanovic { 74*4e7b0f82SDamjan Jovanovic public: 75*4e7b0f82SDamjan Jovanovic StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception ); 76*4e7b0f82SDamjan Jovanovic ~StandardEncryptionInfo() {} 77*4e7b0f82SDamjan Jovanovic bool isImplemented(); 78*4e7b0f82SDamjan Jovanovic Sequence< NamedValue > verifyPassword( const OUString& rPassword ) throw ( Exception ); 79*4e7b0f82SDamjan Jovanovic bool verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception ); 80*4e7b0f82SDamjan 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 ); 81*4e7b0f82SDamjan Jovanovic void decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception ); 82*4e7b0f82SDamjan Jovanovic 83*4e7b0f82SDamjan Jovanovic private: 84*4e7b0f82SDamjan Jovanovic sal_uInt8 mpnSalt[ 16 ]; 85*4e7b0f82SDamjan Jovanovic sal_uInt8 mpnEncrVerifier[ 16 ]; 86*4e7b0f82SDamjan Jovanovic sal_uInt8 mpnEncrVerifierHash[ 32 ]; 87*4e7b0f82SDamjan Jovanovic sal_uInt32 mnFlags; 88*4e7b0f82SDamjan Jovanovic sal_uInt32 mnAlgorithmId; 89*4e7b0f82SDamjan Jovanovic sal_uInt32 mnAlgorithmIdHash; 90*4e7b0f82SDamjan Jovanovic sal_uInt32 mnKeySize; 91*4e7b0f82SDamjan Jovanovic sal_uInt32 mnSaltSize; 92*4e7b0f82SDamjan Jovanovic sal_uInt32 mnVerifierHashSize; 93*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> encryptionKey; 94*4e7b0f82SDamjan Jovanovic }; 95*4e7b0f82SDamjan Jovanovic 96*4e7b0f82SDamjan Jovanovic StandardEncryptionInfo::StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception ) 97*4e7b0f82SDamjan Jovanovic { 98*4e7b0f82SDamjan Jovanovic char msg[ 1024 ]; 99*4e7b0f82SDamjan Jovanovic rStrm >> mnFlags; 100*4e7b0f82SDamjan Jovanovic if( getFlag( mnFlags, ENCRYPTINFO_EXTERNAL ) ) 101*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: \"Extensible encryption\" is not currently supported, please report" ), Reference< XInterface >() ); 102*4e7b0f82SDamjan Jovanovic 103*4e7b0f82SDamjan Jovanovic sal_uInt32 nHeaderSize, nRepeatedFlags; 104*4e7b0f82SDamjan Jovanovic rStrm >> nHeaderSize >> nRepeatedFlags; 105*4e7b0f82SDamjan Jovanovic if( nHeaderSize < 20 ) 106*4e7b0f82SDamjan Jovanovic { 107*4e7b0f82SDamjan Jovanovic snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: header size %u is too short", nHeaderSize ); 108*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() ); 109*4e7b0f82SDamjan Jovanovic } 110*4e7b0f82SDamjan Jovanovic if( nRepeatedFlags != mnFlags ) 111*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: flags don't match" ), Reference< XInterface>() ); 112*4e7b0f82SDamjan Jovanovic 113*4e7b0f82SDamjan Jovanovic rStrm.skip( 4 ); 114*4e7b0f82SDamjan Jovanovic rStrm >> mnAlgorithmId >> mnAlgorithmIdHash >> mnKeySize; 115*4e7b0f82SDamjan Jovanovic rStrm.skip( nHeaderSize - 20 ); 116*4e7b0f82SDamjan Jovanovic rStrm >> mnSaltSize; 117*4e7b0f82SDamjan Jovanovic if( mnSaltSize != 16 ) 118*4e7b0f82SDamjan Jovanovic { 119*4e7b0f82SDamjan Jovanovic snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: salt size is %u instead of 16", mnSaltSize ); 120*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() ); 121*4e7b0f82SDamjan Jovanovic } 122*4e7b0f82SDamjan Jovanovic 123*4e7b0f82SDamjan Jovanovic rStrm.readMemory( mpnSalt, 16 ); 124*4e7b0f82SDamjan Jovanovic rStrm.readMemory( mpnEncrVerifier, 16 ); 125*4e7b0f82SDamjan Jovanovic rStrm >> mnVerifierHashSize; 126*4e7b0f82SDamjan Jovanovic rStrm.readMemory( mpnEncrVerifierHash, 32 ); 127*4e7b0f82SDamjan Jovanovic if( rStrm.isEof() ) 128*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: standard encryption header too short" ), Reference< XInterface >() ); 129*4e7b0f82SDamjan Jovanovic } 130*4e7b0f82SDamjan Jovanovic 131*4e7b0f82SDamjan Jovanovic bool StandardEncryptionInfo::isImplemented() 132*4e7b0f82SDamjan Jovanovic { 133*4e7b0f82SDamjan Jovanovic return getFlag( mnFlags, ENCRYPTINFO_CRYPTOAPI ) && 134*4e7b0f82SDamjan Jovanovic getFlag( mnFlags, ENCRYPTINFO_AES ) && 135*4e7b0f82SDamjan Jovanovic // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set 136*4e7b0f82SDamjan Jovanovic ( ( mnAlgorithmId == 0 ) || ( mnAlgorithmId == ENCRYPT_ALGO_AES128 ) ) && 137*4e7b0f82SDamjan Jovanovic // hash algorithm ID 0 defaults to SHA-1 too 138*4e7b0f82SDamjan Jovanovic ( ( mnAlgorithmIdHash == 0 ) || ( mnAlgorithmIdHash == ENCRYPT_HASH_SHA1 ) ) && 139*4e7b0f82SDamjan Jovanovic ( mnVerifierHashSize == 20 ); 140*4e7b0f82SDamjan Jovanovic } 141*4e7b0f82SDamjan Jovanovic 142*4e7b0f82SDamjan Jovanovic static void deriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen ) 143*4e7b0f82SDamjan Jovanovic { 144*4e7b0f82SDamjan Jovanovic sal_uInt8 pnBuffer[ 64 ]; 145*4e7b0f82SDamjan Jovanovic memset( pnBuffer, 0x36, sizeof( pnBuffer ) ); 146*4e7b0f82SDamjan Jovanovic for( sal_uInt32 i = 0; i < nHashLen; ++i ) 147*4e7b0f82SDamjan Jovanovic pnBuffer[ i ] ^= pnHash[ i ]; 148*4e7b0f82SDamjan Jovanovic 149*4e7b0f82SDamjan Jovanovic rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 150*4e7b0f82SDamjan Jovanovic rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) ); 151*4e7b0f82SDamjan Jovanovic sal_uInt8 pnX1[ RTL_DIGEST_LENGTH_SHA1 ]; 152*4e7b0f82SDamjan Jovanovic aError = rtl_digest_get( aDigest, pnX1, RTL_DIGEST_LENGTH_SHA1 ); 153*4e7b0f82SDamjan Jovanovic rtl_digest_destroy( aDigest ); 154*4e7b0f82SDamjan Jovanovic 155*4e7b0f82SDamjan Jovanovic memset( pnBuffer, 0x5C, sizeof( pnBuffer ) ); 156*4e7b0f82SDamjan Jovanovic for( sal_uInt32 i = 0; i < nHashLen; ++i ) 157*4e7b0f82SDamjan Jovanovic pnBuffer[ i ] ^= pnHash[ i ]; 158*4e7b0f82SDamjan Jovanovic 159*4e7b0f82SDamjan Jovanovic aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 160*4e7b0f82SDamjan Jovanovic aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) ); 161*4e7b0f82SDamjan Jovanovic sal_uInt8 pnX2[ RTL_DIGEST_LENGTH_SHA1 ]; 162*4e7b0f82SDamjan Jovanovic aError = rtl_digest_get( aDigest, pnX2, RTL_DIGEST_LENGTH_SHA1 ); 163*4e7b0f82SDamjan Jovanovic rtl_digest_destroy( aDigest ); 164*4e7b0f82SDamjan Jovanovic 165*4e7b0f82SDamjan Jovanovic if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 ) 166*4e7b0f82SDamjan Jovanovic { 167*4e7b0f82SDamjan Jovanovic memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 ); 168*4e7b0f82SDamjan Jovanovic nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1; 169*4e7b0f82SDamjan Jovanovic } 170*4e7b0f82SDamjan Jovanovic memcpy( pnKeyDerived, pnX1, nRequiredKeyLen ); 171*4e7b0f82SDamjan Jovanovic } 172*4e7b0f82SDamjan Jovanovic 173*4e7b0f82SDamjan Jovanovic Sequence< NamedValue > StandardEncryptionInfo::verifyPassword( const OUString& rPassword ) throw ( Exception ) 174*4e7b0f82SDamjan Jovanovic { 175*4e7b0f82SDamjan Jovanovic size_t nBufferSize = mnSaltSize + 2 * rPassword.getLength(); 176*4e7b0f82SDamjan Jovanovic sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ]; 177*4e7b0f82SDamjan Jovanovic memcpy( pnBuffer, mpnSalt, mnSaltSize ); 178*4e7b0f82SDamjan Jovanovic 179*4e7b0f82SDamjan Jovanovic sal_uInt8* pnPasswordLoc = pnBuffer + mnSaltSize; 180*4e7b0f82SDamjan Jovanovic const sal_Unicode* pStr = rPassword.getStr(); 181*4e7b0f82SDamjan Jovanovic for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 ) 182*4e7b0f82SDamjan Jovanovic ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) ); 183*4e7b0f82SDamjan Jovanovic 184*4e7b0f82SDamjan Jovanovic rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 185*4e7b0f82SDamjan Jovanovic rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, nBufferSize ); 186*4e7b0f82SDamjan Jovanovic delete[] pnBuffer; 187*4e7b0f82SDamjan Jovanovic 188*4e7b0f82SDamjan Jovanovic size_t nHashSize = RTL_DIGEST_LENGTH_SHA1 + 4; 189*4e7b0f82SDamjan Jovanovic sal_uInt8* pnHash = new sal_uInt8[ nHashSize ]; 190*4e7b0f82SDamjan Jovanovic aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 ); 191*4e7b0f82SDamjan Jovanovic rtl_digest_destroy( aDigest ); 192*4e7b0f82SDamjan Jovanovic 193*4e7b0f82SDamjan Jovanovic for( sal_uInt32 i = 0; i < 50000; ++i ) 194*4e7b0f82SDamjan Jovanovic { 195*4e7b0f82SDamjan Jovanovic ByteOrderConverter::writeLittleEndian( pnHash, i ); 196*4e7b0f82SDamjan Jovanovic aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 197*4e7b0f82SDamjan Jovanovic aError = rtl_digest_update( aDigest, pnHash, nHashSize ); 198*4e7b0f82SDamjan Jovanovic aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 ); 199*4e7b0f82SDamjan Jovanovic rtl_digest_destroy( aDigest ); 200*4e7b0f82SDamjan Jovanovic } 201*4e7b0f82SDamjan Jovanovic 202*4e7b0f82SDamjan Jovanovic memmove( pnHash, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 ); 203*4e7b0f82SDamjan Jovanovic memset( pnHash + RTL_DIGEST_LENGTH_SHA1, 0, 4 ); 204*4e7b0f82SDamjan Jovanovic aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 205*4e7b0f82SDamjan Jovanovic aError = rtl_digest_update( aDigest, pnHash, nHashSize ); 206*4e7b0f82SDamjan Jovanovic aError = rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 ); 207*4e7b0f82SDamjan Jovanovic rtl_digest_destroy( aDigest ); 208*4e7b0f82SDamjan Jovanovic 209*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > key( mnKeySize / 8 ); 210*4e7b0f82SDamjan Jovanovic deriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, key.data(), key.size() ); 211*4e7b0f82SDamjan Jovanovic delete[] pnHash; 212*4e7b0f82SDamjan Jovanovic 213*4e7b0f82SDamjan Jovanovic Sequence< NamedValue > aResult; 214*4e7b0f82SDamjan Jovanovic if( checkEncryptionData( key.data(), key.size(), mpnEncrVerifier, sizeof( mpnEncrVerifier ), mpnEncrVerifierHash, sizeof( mpnEncrVerifierHash ) ) ) 215*4e7b0f82SDamjan Jovanovic { 216*4e7b0f82SDamjan Jovanovic SequenceAsHashMap aEncryptionData; 217*4e7b0f82SDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionKey" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( key.data() ), key.size() ); 218*4e7b0f82SDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionSalt" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnSalt ), mnSaltSize ); 219*4e7b0f82SDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifier" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnEncrVerifier ), sizeof( mpnEncrVerifier ) ); 220*4e7b0f82SDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifierHash" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnEncrVerifierHash ), sizeof( mpnEncrVerifierHash ) ); 221*4e7b0f82SDamjan Jovanovic encryptionKey = key; 222*4e7b0f82SDamjan Jovanovic aResult = aEncryptionData.getAsConstNamedValueList(); 223*4e7b0f82SDamjan Jovanovic } 224*4e7b0f82SDamjan Jovanovic 225*4e7b0f82SDamjan Jovanovic return aResult; 226*4e7b0f82SDamjan Jovanovic } 227*4e7b0f82SDamjan Jovanovic 228*4e7b0f82SDamjan Jovanovic bool StandardEncryptionInfo::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception ) 229*4e7b0f82SDamjan Jovanovic { 230*4e7b0f82SDamjan Jovanovic SequenceAsHashMap aHashData( rEncryptionData ); 231*4e7b0f82SDamjan Jovanovic Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionKey" ), Sequence< sal_Int8 >() ); 232*4e7b0f82SDamjan Jovanovic Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifier" ), Sequence< sal_Int8 >() ); 233*4e7b0f82SDamjan Jovanovic Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifierHash" ), Sequence< sal_Int8 >() ); 234*4e7b0f82SDamjan Jovanovic const sal_uInt8 *pnKey = reinterpret_cast< const sal_uInt8* >( aKey.getConstArray() ); 235*4e7b0f82SDamjan Jovanovic sal_uInt32 nKeySize = aKey.getLength(); 236*4e7b0f82SDamjan Jovanovic const sal_uInt8 *pnVerifier = reinterpret_cast< const sal_uInt8* >( aVerifier.getConstArray() ); 237*4e7b0f82SDamjan Jovanovic sal_uInt32 nVerifierSize = aVerifier.getLength(); 238*4e7b0f82SDamjan Jovanovic const sal_uInt8 *pnVerifierHash = reinterpret_cast< const sal_uInt8* >( aVerifierHash.getConstArray() ); 239*4e7b0f82SDamjan Jovanovic sal_uInt32 nVerifierHashSize = aVerifierHash.getLength(); 240*4e7b0f82SDamjan Jovanovic if( checkEncryptionData( pnKey, nKeySize, pnVerifier, nVerifierSize, pnVerifierHash, nVerifierHashSize ) ) 241*4e7b0f82SDamjan Jovanovic { 242*4e7b0f82SDamjan Jovanovic encryptionKey = vector< sal_uInt8 >( &pnKey[ 0 ], &pnKey[ nKeySize ] ); 243*4e7b0f82SDamjan Jovanovic return true; 244*4e7b0f82SDamjan Jovanovic } 245*4e7b0f82SDamjan Jovanovic else 246*4e7b0f82SDamjan Jovanovic return false; 247*4e7b0f82SDamjan Jovanovic } 248*4e7b0f82SDamjan Jovanovic 249*4e7b0f82SDamjan 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 ) 250*4e7b0f82SDamjan Jovanovic { 251*4e7b0f82SDamjan Jovanovic bool bResult = false; 252*4e7b0f82SDamjan Jovanovic 253*4e7b0f82SDamjan Jovanovic // the only currently supported algorithm needs key size 128 254*4e7b0f82SDamjan Jovanovic if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 ) 255*4e7b0f82SDamjan Jovanovic { 256*4e7b0f82SDamjan Jovanovic // check password 257*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX *aes_ctx; 258*4e7b0f82SDamjan Jovanovic aes_ctx = EVP_CIPHER_CTX_new(); 259*4e7b0f82SDamjan Jovanovic if ( aes_ctx == NULL ) 260*4e7b0f82SDamjan Jovanovic return false; 261*4e7b0f82SDamjan Jovanovic EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); 262*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX_set_padding( aes_ctx, 0 ); 263*4e7b0f82SDamjan Jovanovic int nOutLen = 0; 264*4e7b0f82SDamjan Jovanovic sal_uInt8 pnTmpVerifier[ 16 ]; 265*4e7b0f82SDamjan Jovanovic (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) ); 266*4e7b0f82SDamjan Jovanovic 267*4e7b0f82SDamjan Jovanovic /*int*/ EVP_DecryptUpdate( aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize ); 268*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX_free( aes_ctx ); 269*4e7b0f82SDamjan Jovanovic 270*4e7b0f82SDamjan Jovanovic aes_ctx = EVP_CIPHER_CTX_new(); 271*4e7b0f82SDamjan Jovanovic if ( aes_ctx == NULL ) 272*4e7b0f82SDamjan Jovanovic return false; 273*4e7b0f82SDamjan Jovanovic EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); 274*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX_set_padding( aes_ctx, 0 ); 275*4e7b0f82SDamjan Jovanovic sal_uInt8 pnTmpVerifierHash[ 32 ]; 276*4e7b0f82SDamjan Jovanovic (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) ); 277*4e7b0f82SDamjan Jovanovic 278*4e7b0f82SDamjan Jovanovic /*int*/ EVP_DecryptUpdate( aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize ); 279*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX_free( aes_ctx ); 280*4e7b0f82SDamjan Jovanovic 281*4e7b0f82SDamjan Jovanovic rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 282*4e7b0f82SDamjan Jovanovic rtlDigestError aError = rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) ); 283*4e7b0f82SDamjan Jovanovic sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ]; 284*4e7b0f82SDamjan Jovanovic aError = rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 ); 285*4e7b0f82SDamjan Jovanovic rtl_digest_destroy( aDigest ); 286*4e7b0f82SDamjan Jovanovic 287*4e7b0f82SDamjan Jovanovic bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 ); 288*4e7b0f82SDamjan Jovanovic } 289*4e7b0f82SDamjan Jovanovic 290*4e7b0f82SDamjan Jovanovic return bResult; 291*4e7b0f82SDamjan Jovanovic } 292*4e7b0f82SDamjan Jovanovic 293*4e7b0f82SDamjan Jovanovic void StandardEncryptionInfo::decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception ) 294*4e7b0f82SDamjan Jovanovic { 295*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX *aes_ctx; 296*4e7b0f82SDamjan Jovanovic aes_ctx = EVP_CIPHER_CTX_new(); 297*4e7b0f82SDamjan Jovanovic if ( aes_ctx == NULL ) 298*4e7b0f82SDamjan Jovanovic throw Exception(); 299*4e7b0f82SDamjan Jovanovic EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, encryptionKey.data(), 0 ); 300*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX_set_padding( aes_ctx, 0 ); 301*4e7b0f82SDamjan Jovanovic 302*4e7b0f82SDamjan Jovanovic sal_uInt8 pnInBuffer[ 1024 ]; 303*4e7b0f82SDamjan Jovanovic sal_uInt8 pnOutBuffer[ 1024 ]; 304*4e7b0f82SDamjan Jovanovic sal_Int32 nInLen; 305*4e7b0f82SDamjan Jovanovic int nOutLen; 306*4e7b0f82SDamjan Jovanovic aEncryptedPackage.skip( 8 ); // decrypted size 307*4e7b0f82SDamjan Jovanovic while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 ) 308*4e7b0f82SDamjan Jovanovic { 309*4e7b0f82SDamjan Jovanovic EVP_DecryptUpdate( aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen ); 310*4e7b0f82SDamjan Jovanovic aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen ); 311*4e7b0f82SDamjan Jovanovic } 312*4e7b0f82SDamjan Jovanovic EVP_DecryptFinal_ex( aes_ctx, pnOutBuffer, &nOutLen ); 313*4e7b0f82SDamjan Jovanovic aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen ); 314*4e7b0f82SDamjan Jovanovic 315*4e7b0f82SDamjan Jovanovic EVP_CIPHER_CTX_free( aes_ctx ); 316*4e7b0f82SDamjan Jovanovic aDecryptedPackage.flush(); 317*4e7b0f82SDamjan Jovanovic } 318*4e7b0f82SDamjan Jovanovic 319*4e7b0f82SDamjan Jovanovic // ============================================================================ 320*4e7b0f82SDamjan Jovanovic // "Agile" encryption, 2.3.4.10 of MS-OFFCRYPTO 321*4e7b0f82SDamjan Jovanovic // ============================================================================ 322*4e7b0f82SDamjan Jovanovic 323*4e7b0f82SDamjan Jovanovic struct AgileKeyData 324*4e7b0f82SDamjan Jovanovic { 325*4e7b0f82SDamjan Jovanovic sal_Int32 saltSize; 326*4e7b0f82SDamjan Jovanovic sal_Int32 blockSize; 327*4e7b0f82SDamjan Jovanovic sal_Int32 keyBits; 328*4e7b0f82SDamjan Jovanovic sal_Int32 hashSize; 329*4e7b0f82SDamjan Jovanovic OUString cipherAlgorithm; 330*4e7b0f82SDamjan Jovanovic OUString cipherChaining; 331*4e7b0f82SDamjan Jovanovic OUString hashAlgorithm; 332*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > saltValue; 333*4e7b0f82SDamjan Jovanovic }; 334*4e7b0f82SDamjan Jovanovic 335*4e7b0f82SDamjan Jovanovic struct AgileDataIntegrity 336*4e7b0f82SDamjan Jovanovic { 337*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > encryptedHmacKey; 338*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > encryptedHmacValue; 339*4e7b0f82SDamjan Jovanovic }; 340*4e7b0f82SDamjan Jovanovic 341*4e7b0f82SDamjan Jovanovic struct AgilePasswordKeyEncryptor 342*4e7b0f82SDamjan Jovanovic { 343*4e7b0f82SDamjan Jovanovic sal_Int32 saltSize; 344*4e7b0f82SDamjan Jovanovic sal_Int32 blockSize; 345*4e7b0f82SDamjan Jovanovic sal_Int32 keyBits; 346*4e7b0f82SDamjan Jovanovic sal_Int32 hashSize; 347*4e7b0f82SDamjan Jovanovic OUString cipherAlgorithm; 348*4e7b0f82SDamjan Jovanovic OUString cipherChaining; 349*4e7b0f82SDamjan Jovanovic OUString hashAlgorithm; 350*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > saltValue; 351*4e7b0f82SDamjan Jovanovic sal_Int32 spinCount; 352*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > encryptedVerifierHashInput; 353*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > encryptedVerifierHashValue; 354*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > encryptedKeyValue; 355*4e7b0f82SDamjan Jovanovic }; 356*4e7b0f82SDamjan Jovanovic 357*4e7b0f82SDamjan Jovanovic static bool decodeBase64( OUString& base64, vector< sal_uInt8 >& bytes ) 358*4e7b0f82SDamjan Jovanovic { 359*4e7b0f82SDamjan Jovanovic ::rtl::OString base64Ascii = ::rtl::OUStringToOString( base64, RTL_TEXTENCODING_UTF8 ); 360*4e7b0f82SDamjan Jovanovic const sal_uInt32 len = base64Ascii.getLength(); 361*4e7b0f82SDamjan Jovanovic bytes.resize( (len + 3) / 4 * 3 ); 362*4e7b0f82SDamjan Jovanovic int decodedSize = EVP_DecodeBlock( bytes.data(), reinterpret_cast< sal_uInt8 const * >( base64Ascii.getStr() ), len ); 363*4e7b0f82SDamjan Jovanovic if ( decodedSize < 0 ) 364*4e7b0f82SDamjan Jovanovic return false; 365*4e7b0f82SDamjan Jovanovic if ( len >= 2 && base64Ascii[ len-1 ] == '=' && base64Ascii[ len-2 ] == '=' ) 366*4e7b0f82SDamjan Jovanovic decodedSize -= 2; 367*4e7b0f82SDamjan Jovanovic else if ( len >= 1 && base64Ascii[ len-1] == '=' ) 368*4e7b0f82SDamjan Jovanovic decodedSize--; 369*4e7b0f82SDamjan Jovanovic bytes.resize( decodedSize ); 370*4e7b0f82SDamjan Jovanovic return true; 371*4e7b0f82SDamjan Jovanovic } 372*4e7b0f82SDamjan Jovanovic 373*4e7b0f82SDamjan Jovanovic class AgileEncryptionInfo : public EncryptionInfo 374*4e7b0f82SDamjan Jovanovic { 375*4e7b0f82SDamjan Jovanovic public: 376*4e7b0f82SDamjan Jovanovic AgileEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) throw ( Exception ); 377*4e7b0f82SDamjan Jovanovic ~AgileEncryptionInfo() {} 378*4e7b0f82SDamjan Jovanovic bool isImplemented() { return true; } // FIXME 379*4e7b0f82SDamjan Jovanovic Sequence< NamedValue > verifyPassword( const OUString& rPassword ) throw ( Exception ); 380*4e7b0f82SDamjan Jovanovic bool verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception ); 381*4e7b0f82SDamjan Jovanovic void decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception ); 382*4e7b0f82SDamjan Jovanovic 383*4e7b0f82SDamjan Jovanovic private: 384*4e7b0f82SDamjan Jovanovic AgileKeyData keyData; 385*4e7b0f82SDamjan Jovanovic AgileDataIntegrity dataIntegrity; 386*4e7b0f82SDamjan Jovanovic AgilePasswordKeyEncryptor passwordKeyEncryptor; 387*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> encryptionKey; 388*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> hmacKey; 389*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> hmacValue; 390*4e7b0f82SDamjan Jovanovic }; 391*4e7b0f82SDamjan Jovanovic 392*4e7b0f82SDamjan Jovanovic // A SAX handler that parses the XML from the "XmlEncryptionDescriptor" in the EncryptionInfo stream. 393*4e7b0f82SDamjan Jovanovic class AgileEncryptionHandler : public ::cppu::WeakImplHelper1< XFastDocumentHandler > 394*4e7b0f82SDamjan Jovanovic { 395*4e7b0f82SDamjan Jovanovic public: 396*4e7b0f82SDamjan Jovanovic AgileEncryptionHandler( AgileKeyData &aKeyData, AgileDataIntegrity &aDataIntegrity, AgilePasswordKeyEncryptor &aPasswordKeyEncryptor ) 397*4e7b0f82SDamjan Jovanovic : keyData( aKeyData ), 398*4e7b0f82SDamjan Jovanovic dataIntegrity( aDataIntegrity ), 399*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor( aPasswordKeyEncryptor ) 400*4e7b0f82SDamjan Jovanovic { 401*4e7b0f82SDamjan Jovanovic } 402*4e7b0f82SDamjan Jovanovic 403*4e7b0f82SDamjan Jovanovic // XFastDocumentHandler 404*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL startDocument() throw (SAXException, RuntimeException); 405*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL endDocument() throw (SAXException, RuntimeException); 406*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) throw (SAXException, RuntimeException); 407*4e7b0f82SDamjan Jovanovic 408*4e7b0f82SDamjan Jovanovic // XFastContextHandler 409*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 410*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 411*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL endFastElement( sal_Int32 Element ) throw (SAXException, RuntimeException); 412*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) throw (SAXException, RuntimeException); 413*4e7b0f82SDamjan Jovanovic virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 Element, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 414*4e7b0f82SDamjan Jovanovic virtual Reference< XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 415*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL characters( const OUString& aChars ) throw (SAXException, RuntimeException); 416*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) throw (SAXException, RuntimeException); 417*4e7b0f82SDamjan Jovanovic virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) throw (SAXException, RuntimeException); 418*4e7b0f82SDamjan Jovanovic 419*4e7b0f82SDamjan Jovanovic OUString& getLastError() { return lastError; } 420*4e7b0f82SDamjan Jovanovic 421*4e7b0f82SDamjan Jovanovic private: 422*4e7b0f82SDamjan Jovanovic void parseKeyData( const AttributeList& attribs ) throw (SAXException, RuntimeException); 423*4e7b0f82SDamjan Jovanovic void parseDataIntegrity( const AttributeList& attribs ) throw (SAXException, RuntimeException); 424*4e7b0f82SDamjan Jovanovic void parseEncryptedKey( const AttributeList& attribs ) throw (SAXException, RuntimeException); 425*4e7b0f82SDamjan Jovanovic 426*4e7b0f82SDamjan Jovanovic vector< sal_Int32 > stack; 427*4e7b0f82SDamjan Jovanovic OUString lastError; 428*4e7b0f82SDamjan Jovanovic AgileKeyData &keyData; 429*4e7b0f82SDamjan Jovanovic AgileDataIntegrity &dataIntegrity; 430*4e7b0f82SDamjan Jovanovic AgilePasswordKeyEncryptor &passwordKeyEncryptor; 431*4e7b0f82SDamjan Jovanovic }; 432*4e7b0f82SDamjan Jovanovic 433*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startDocument() 434*4e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 435*4e7b0f82SDamjan Jovanovic { 436*4e7b0f82SDamjan Jovanovic } 437*4e7b0f82SDamjan Jovanovic 438*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endDocument() 439*4e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 440*4e7b0f82SDamjan Jovanovic { 441*4e7b0f82SDamjan Jovanovic } 442*4e7b0f82SDamjan Jovanovic 443*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::setDocumentLocator( const Reference< XLocator >& ) 444*4e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 445*4e7b0f82SDamjan Jovanovic { 446*4e7b0f82SDamjan Jovanovic } 447*4e7b0f82SDamjan Jovanovic 448*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& attribs ) 449*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 450*4e7b0f82SDamjan Jovanovic { 451*4e7b0f82SDamjan Jovanovic switch ( nElement ) 452*4e7b0f82SDamjan Jovanovic { 453*4e7b0f82SDamjan Jovanovic case ENCRYPTION_TOKEN( encryption ): 454*4e7b0f82SDamjan Jovanovic break; 455*4e7b0f82SDamjan Jovanovic 456*4e7b0f82SDamjan Jovanovic case ENCRYPTION_TOKEN( keyData ): 457*4e7b0f82SDamjan Jovanovic if ( stack.size() == 1 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) ) 458*4e7b0f82SDamjan Jovanovic parseKeyData( AttributeList( attribs ) ); 459*4e7b0f82SDamjan Jovanovic break; 460*4e7b0f82SDamjan Jovanovic 461*4e7b0f82SDamjan Jovanovic case ENCRYPTION_TOKEN( dataIntegrity ): 462*4e7b0f82SDamjan Jovanovic if ( stack.size() == 1 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) ) 463*4e7b0f82SDamjan Jovanovic parseDataIntegrity( AttributeList ( attribs ) ); 464*4e7b0f82SDamjan Jovanovic break; 465*4e7b0f82SDamjan Jovanovic 466*4e7b0f82SDamjan Jovanovic case ENCRYPTION_TOKEN( keyEncryptors ): 467*4e7b0f82SDamjan Jovanovic break; 468*4e7b0f82SDamjan Jovanovic 469*4e7b0f82SDamjan Jovanovic case ENCRYPTION_TOKEN( keyEncryptor ): 470*4e7b0f82SDamjan Jovanovic break; 471*4e7b0f82SDamjan Jovanovic 472*4e7b0f82SDamjan Jovanovic case KEY_ENCRYPTOR_PASSWORD_TOKEN( encryptedKey ): 473*4e7b0f82SDamjan Jovanovic if ( stack.size() == 3 474*4e7b0f82SDamjan Jovanovic && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) 475*4e7b0f82SDamjan Jovanovic && (stack[ 1 ] == ENCRYPTION_TOKEN( keyEncryptors )) 476*4e7b0f82SDamjan Jovanovic && (stack[ 2 ] == ENCRYPTION_TOKEN( keyEncryptor )) ) 477*4e7b0f82SDamjan Jovanovic parseEncryptedKey( AttributeList ( attribs ) ); 478*4e7b0f82SDamjan Jovanovic break; 479*4e7b0f82SDamjan Jovanovic } 480*4e7b0f82SDamjan Jovanovic stack.push_back( nElement ); 481*4e7b0f82SDamjan Jovanovic } 482*4e7b0f82SDamjan Jovanovic 483*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) 484*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 485*4e7b0f82SDamjan Jovanovic { 486*4e7b0f82SDamjan Jovanovic stack.push_back( -1 ); 487*4e7b0f82SDamjan Jovanovic } 488*4e7b0f82SDamjan Jovanovic 489*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endFastElement( sal_Int32 nElement ) 490*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 491*4e7b0f82SDamjan Jovanovic { 492*4e7b0f82SDamjan Jovanovic stack.pop_back(); 493*4e7b0f82SDamjan Jovanovic } 494*4e7b0f82SDamjan Jovanovic 495*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::endUnknownElement( const OUString&, const OUString& ) 496*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 497*4e7b0f82SDamjan Jovanovic { 498*4e7b0f82SDamjan Jovanovic stack.pop_back(); 499*4e7b0f82SDamjan Jovanovic } 500*4e7b0f82SDamjan Jovanovic 501*4e7b0f82SDamjan Jovanovic Reference< XFastContextHandler > AgileEncryptionHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& ) 502*4e7b0f82SDamjan Jovanovic throw (SAXException, RuntimeException) 503*4e7b0f82SDamjan Jovanovic { 504*4e7b0f82SDamjan Jovanovic return this; 505*4e7b0f82SDamjan Jovanovic } 506*4e7b0f82SDamjan Jovanovic 507*4e7b0f82SDamjan Jovanovic Reference< XFastContextHandler > AgileEncryptionHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) 508*4e7b0f82SDamjan Jovanovic throw (SAXException, RuntimeException) 509*4e7b0f82SDamjan Jovanovic { 510*4e7b0f82SDamjan Jovanovic return this; 511*4e7b0f82SDamjan Jovanovic } 512*4e7b0f82SDamjan Jovanovic 513*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::characters( const ::rtl::OUString& rStr ) 514*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 515*4e7b0f82SDamjan Jovanovic { 516*4e7b0f82SDamjan Jovanovic } 517*4e7b0f82SDamjan Jovanovic 518*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::ignorableWhitespace( const ::rtl::OUString& str ) 519*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 520*4e7b0f82SDamjan Jovanovic { 521*4e7b0f82SDamjan Jovanovic } 522*4e7b0f82SDamjan Jovanovic 523*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) 524*4e7b0f82SDamjan Jovanovic throw( SAXException, RuntimeException ) 525*4e7b0f82SDamjan Jovanovic { 526*4e7b0f82SDamjan Jovanovic } 527*4e7b0f82SDamjan Jovanovic 528*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::parseKeyData( const AttributeList& attribs ) 529*4e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 530*4e7b0f82SDamjan Jovanovic { 531*4e7b0f82SDamjan Jovanovic keyData.saltSize = attribs.getInteger( XML_saltSize, 0 ); 532*4e7b0f82SDamjan Jovanovic keyData.blockSize = attribs.getInteger( XML_blockSize, 0 ); 533*4e7b0f82SDamjan Jovanovic keyData.keyBits = attribs.getInteger( XML_keyBits, 0 ); 534*4e7b0f82SDamjan Jovanovic keyData.hashSize = attribs.getInteger( XML_hashSize, 0 ); 535*4e7b0f82SDamjan Jovanovic keyData.cipherAlgorithm = attribs.getString( XML_cipherAlgorithm, OUString() ); 536*4e7b0f82SDamjan Jovanovic keyData.cipherChaining = attribs.getString( XML_cipherChaining, OUString() ); 537*4e7b0f82SDamjan Jovanovic keyData.hashAlgorithm = attribs.getString( XML_hashAlgorithm, OUString() ); 538*4e7b0f82SDamjan Jovanovic 539*4e7b0f82SDamjan Jovanovic OUString saltValue = attribs.getString( XML_saltValue, OUString() ); 540*4e7b0f82SDamjan Jovanovic if( !decodeBase64( saltValue, keyData.saltValue ) ) 541*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the keyData.saltValue " ) + saltValue; 542*4e7b0f82SDamjan Jovanovic } 543*4e7b0f82SDamjan Jovanovic 544*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::parseDataIntegrity( const AttributeList& attribs ) 545*4e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 546*4e7b0f82SDamjan Jovanovic { 547*4e7b0f82SDamjan Jovanovic OUString encryptedHmacKey = attribs.getString( XML_encryptedHmacKey, OUString() ); 548*4e7b0f82SDamjan Jovanovic if( !decodeBase64( encryptedHmacKey, dataIntegrity.encryptedHmacKey ) ) 549*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the dataIntegrity.encryptedHmacKey " ) + encryptedHmacKey; 550*4e7b0f82SDamjan Jovanovic OUString encryptedHmacValue = attribs.getString( XML_encryptedHmacValue, OUString() ); 551*4e7b0f82SDamjan Jovanovic if( !decodeBase64( encryptedHmacValue, dataIntegrity.encryptedHmacValue ) ) 552*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the dataIntegrity.encryptedHmacValue " ) + encryptedHmacValue; 553*4e7b0f82SDamjan Jovanovic } 554*4e7b0f82SDamjan Jovanovic 555*4e7b0f82SDamjan Jovanovic void AgileEncryptionHandler::parseEncryptedKey( const AttributeList& attribs ) 556*4e7b0f82SDamjan Jovanovic throw ( SAXException, RuntimeException ) 557*4e7b0f82SDamjan Jovanovic { 558*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.spinCount = attribs.getInteger( XML_spinCount, 0 ); 559*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.saltSize = attribs.getInteger( XML_saltSize, 0 ); 560*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.blockSize = attribs.getInteger( XML_blockSize, 0 ); 561*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.keyBits = attribs.getInteger( XML_keyBits, 0 ); 562*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.hashSize = attribs.getInteger( XML_hashSize, 0 ); 563*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.cipherAlgorithm = attribs.getString( XML_cipherAlgorithm, OUString() ); 564*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.cipherChaining = attribs.getString( XML_cipherChaining, OUString() ); 565*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.hashAlgorithm = attribs.getString( XML_hashAlgorithm, OUString() ); 566*4e7b0f82SDamjan Jovanovic OUString saltValue = attribs.getString( XML_saltValue, OUString() ); 567*4e7b0f82SDamjan Jovanovic if( !decodeBase64( saltValue, passwordKeyEncryptor.saltValue ) ) 568*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.saltValue " ) + saltValue; 569*4e7b0f82SDamjan Jovanovic OUString encryptedVerifierHashInput = attribs.getString( XML_encryptedVerifierHashInput, OUString() ); 570*4e7b0f82SDamjan Jovanovic if( !decodeBase64( encryptedVerifierHashInput, passwordKeyEncryptor.encryptedVerifierHashInput ) ) 571*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedVerifierHashInput " ) + encryptedVerifierHashInput; 572*4e7b0f82SDamjan Jovanovic OUString encryptedVerifierHashValue = attribs.getString( XML_encryptedVerifierHashValue, OUString() ); 573*4e7b0f82SDamjan Jovanovic if( !decodeBase64( encryptedVerifierHashValue, passwordKeyEncryptor.encryptedVerifierHashValue ) ) 574*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedVerifierHashValue " ) + encryptedVerifierHashValue; 575*4e7b0f82SDamjan Jovanovic OUString encryptedKeyValue = attribs.getString( XML_encryptedKeyValue, OUString() ); 576*4e7b0f82SDamjan Jovanovic if( !decodeBase64( encryptedKeyValue, passwordKeyEncryptor.encryptedKeyValue ) ) 577*4e7b0f82SDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedKeyValue " ) + encryptedKeyValue; 578*4e7b0f82SDamjan Jovanovic } 579*4e7b0f82SDamjan Jovanovic 580*4e7b0f82SDamjan Jovanovic static sal_uInt16 readUInt16LE( Reference< XInputStream >& inputStream ) throw ( Exception ) 581*4e7b0f82SDamjan Jovanovic { 582*4e7b0f82SDamjan Jovanovic Sequence< sal_Int8 > bytes( 2 ); 583*4e7b0f82SDamjan Jovanovic sal_Int32 bytesRead = inputStream->readBytes( bytes, 2 ); 584*4e7b0f82SDamjan Jovanovic if( bytesRead < 2 ) 585*4e7b0f82SDamjan Jovanovic throw new Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() failed, early end of file" ), Reference< XInterface >() ); 586*4e7b0f82SDamjan Jovanovic return (sal_uInt16) ( bytes[0] | (bytes[1] << 8) ); 587*4e7b0f82SDamjan Jovanovic } 588*4e7b0f82SDamjan Jovanovic 589*4e7b0f82SDamjan Jovanovic static sal_uInt32 readUInt32LE( Reference< XInputStream >& inputStream ) throw ( Exception ) 590*4e7b0f82SDamjan Jovanovic { 591*4e7b0f82SDamjan Jovanovic Sequence< sal_Int8 > bytes( 4 ); 592*4e7b0f82SDamjan Jovanovic sal_Int32 bytesRead = inputStream->readBytes( bytes, 4 ); 593*4e7b0f82SDamjan Jovanovic if( bytesRead < 4 ) 594*4e7b0f82SDamjan Jovanovic throw new Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() failed, early end of file" ), Reference< XInterface >() ); 595*4e7b0f82SDamjan Jovanovic return (sal_uInt32) ( bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24) ); 596*4e7b0f82SDamjan Jovanovic } 597*4e7b0f82SDamjan Jovanovic 598*4e7b0f82SDamjan Jovanovic AgileEncryptionInfo::AgileEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) throw ( Exception ) 599*4e7b0f82SDamjan Jovanovic { 600*4e7b0f82SDamjan Jovanovic sal_uInt32 nReserved = readUInt32LE( inputStream ); 601*4e7b0f82SDamjan Jovanovic if( nReserved != 0x40 ) 602*4e7b0f82SDamjan Jovanovic throw new Exception( OUString::createFromAscii( "reserved field isn't 0x40" ), Reference< XInterface >() ); 603*4e7b0f82SDamjan Jovanovic AgileEncryptionHandler *agileEncryptionHandler = new AgileEncryptionHandler( keyData, dataIntegrity, passwordKeyEncryptor ); 604*4e7b0f82SDamjan Jovanovic Reference< XFastDocumentHandler > documentHandler( agileEncryptionHandler ); 605*4e7b0f82SDamjan Jovanovic FastParser fastParser( context ); 606*4e7b0f82SDamjan Jovanovic fastParser.registerNamespace( NMSP_encryption ); 607*4e7b0f82SDamjan Jovanovic fastParser.registerNamespace( NMSP_keyEncryptorPassword ); 608*4e7b0f82SDamjan Jovanovic fastParser.setDocumentHandler( documentHandler ); 609*4e7b0f82SDamjan Jovanovic fastParser.parseStream( inputStream, OUString::createFromAscii( "EncryptionInfo" ), false ); 610*4e7b0f82SDamjan Jovanovic if( !agileEncryptionHandler->getLastError().isEmpty() ) 611*4e7b0f82SDamjan Jovanovic throw new Exception( agileEncryptionHandler->getLastError(), Reference< XInterface >() ); 612*4e7b0f82SDamjan Jovanovic } 613*4e7b0f82SDamjan Jovanovic 614*4e7b0f82SDamjan Jovanovic static const EVP_MD* toOpenSSLDigestAlgorithm( const OUString& hashAlgorithm ) throw ( Exception ) 615*4e7b0f82SDamjan Jovanovic { 616*4e7b0f82SDamjan Jovanovic if( hashAlgorithm.equalsAscii( "SHA-1" ) ) 617*4e7b0f82SDamjan Jovanovic return EVP_sha1(); 618*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA1" ) ) // Typical Microsoft. The specification says "SHA-1", but documents use "SHA1". 619*4e7b0f82SDamjan Jovanovic return EVP_sha1(); 620*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA256" ) ) 621*4e7b0f82SDamjan Jovanovic return EVP_sha256(); 622*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA384" ) ) 623*4e7b0f82SDamjan Jovanovic return EVP_sha384(); 624*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA512" ) ) 625*4e7b0f82SDamjan Jovanovic return EVP_sha512(); 626*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "MD5" ) ) 627*4e7b0f82SDamjan Jovanovic return EVP_md5(); 628*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "MD4" ) ) 629*4e7b0f82SDamjan Jovanovic return EVP_md4(); 630*4e7b0f82SDamjan Jovanovic #if !defined(OPENSSL_NO_MD2) 631*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "MD2" ) ) 632*4e7b0f82SDamjan Jovanovic return EVP_md2(); 633*4e7b0f82SDamjan Jovanovic #endif 634*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "RIPEMD-160" ) ) 635*4e7b0f82SDamjan Jovanovic return EVP_ripemd160(); 636*4e7b0f82SDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "WHIRLPOOL" ) ) 637*4e7b0f82SDamjan Jovanovic return EVP_whirlpool(); 638*4e7b0f82SDamjan Jovanovic char buffer[ 256 ]; 639*4e7b0f82SDamjan Jovanovic ::rtl::OString str = ::rtl::OUStringToOString( hashAlgorithm, RTL_TEXTENCODING_UTF8 ); 640*4e7b0f82SDamjan Jovanovic snprintf( buffer, sizeof( buffer ), "Unsupported digest algorithm %s", str.getStr() ); 641*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( buffer ), Reference< XInterface >() ); 642*4e7b0f82SDamjan Jovanovic } 643*4e7b0f82SDamjan Jovanovic 644*4e7b0f82SDamjan Jovanovic static const EVP_CIPHER* toOpenSSLCipherAlgorithm( const OUString& cipherName, sal_uInt32 keyBits, const OUString &chainingMode ) throw ( Exception ) 645*4e7b0f82SDamjan Jovanovic { 646*4e7b0f82SDamjan Jovanovic if( cipherName.equalsAscii( "AES" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 647*4e7b0f82SDamjan Jovanovic return EVP_aes_128_cbc(); 648*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 649*4e7b0f82SDamjan Jovanovic return EVP_aes_128_cfb(); 650*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 192 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 651*4e7b0f82SDamjan Jovanovic return EVP_aes_192_cbc(); 652*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 192 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 653*4e7b0f82SDamjan Jovanovic return EVP_aes_192_cfb(); 654*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 256 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 655*4e7b0f82SDamjan Jovanovic return EVP_aes_256_cbc(); 656*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 256 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 657*4e7b0f82SDamjan Jovanovic return EVP_aes_256_cfb(); 658*4e7b0f82SDamjan Jovanovic #if !defined(OPENSSL_NO_RC2) 659*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "RC2" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 660*4e7b0f82SDamjan Jovanovic return EVP_rc2_cbc(); 661*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "RC2" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 662*4e7b0f82SDamjan Jovanovic return EVP_rc2_cfb(); 663*4e7b0f82SDamjan Jovanovic #endif 664*4e7b0f82SDamjan Jovanovic #if !defined(OPENSSL_NO_DES) 665*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "DES" ) && keyBits == 56 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 666*4e7b0f82SDamjan Jovanovic return EVP_des_cbc(); 667*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "DES" ) && keyBits == 56 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 668*4e7b0f82SDamjan Jovanovic return EVP_des_cfb(); 669*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "DESX" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 670*4e7b0f82SDamjan Jovanovic return EVP_desx_cbc(); 671*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "3DES" ) && keyBits == 168 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 672*4e7b0f82SDamjan Jovanovic return EVP_des_ede3_cbc(); 673*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "3DES" ) && keyBits == 168 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 674*4e7b0f82SDamjan Jovanovic return EVP_des_ede3_cfb(); 675*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "3DES_112" ) && keyBits == 112 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 676*4e7b0f82SDamjan Jovanovic return EVP_des_ede_cbc(); 677*4e7b0f82SDamjan Jovanovic else if( cipherName.equalsAscii( "3DES_112" ) && keyBits == 112 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 678*4e7b0f82SDamjan Jovanovic return EVP_des_ede_cfb(); 679*4e7b0f82SDamjan Jovanovic #endif 680*4e7b0f82SDamjan Jovanovic char buffer[ 256 ]; 681*4e7b0f82SDamjan Jovanovic ::rtl::OString cipherNameUtf8 = ::rtl::OUStringToOString( cipherName, RTL_TEXTENCODING_UTF8 ); 682*4e7b0f82SDamjan Jovanovic ::rtl::OString chainingModeUtf8 = ::rtl::OUStringToOString( chainingMode, RTL_TEXTENCODING_UTF8 ); 683*4e7b0f82SDamjan Jovanovic snprintf( buffer, sizeof( buffer ), "Unsupported cipher with name=%s, keyBits=%u, chainingMode=%s", cipherNameUtf8.getStr(), keyBits, chainingModeUtf8.getStr() ); 684*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( buffer ), Reference< XInterface >() ); 685*4e7b0f82SDamjan Jovanovic } 686*4e7b0f82SDamjan Jovanovic 687*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword(). 688*4e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > hashPassword( const OUString& password, const EVP_MD *digestAlgorithm, vector< sal_uInt8 >& salt, sal_uInt32 spinCount ) throw ( Exception ) 689*4e7b0f82SDamjan Jovanovic { 690*4e7b0f82SDamjan Jovanovic OpenSSLDigest digest; 691*4e7b0f82SDamjan Jovanovic digest.initialize( digestAlgorithm ); 692*4e7b0f82SDamjan Jovanovic size_t digestSize = digest.digestSize(); 693*4e7b0f82SDamjan Jovanovic 694*4e7b0f82SDamjan Jovanovic // Convert to little-endian UTF-16 695*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > passwordLE( 2 * password.getLength() ); 696*4e7b0f82SDamjan Jovanovic for ( int i = 0; i < password.getLength(); i++ ) 697*4e7b0f82SDamjan Jovanovic ByteOrderConverter::writeLittleEndian( &passwordLE[ 2 * i ], static_cast< sal_uInt16 >( password[ i ] ) ); 698*4e7b0f82SDamjan Jovanovic 699*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> digestBuffer( digestSize ); 700*4e7b0f82SDamjan Jovanovic digest.update( salt.data(), salt.size() ); 701*4e7b0f82SDamjan Jovanovic digest.update( passwordLE.data(), passwordLE.size() ); 702*4e7b0f82SDamjan Jovanovic digest.final( digestBuffer.data(), NULL ); 703*4e7b0f82SDamjan Jovanovic 704*4e7b0f82SDamjan Jovanovic char iteratorBuffer[ 4 ]; 705*4e7b0f82SDamjan Jovanovic for (sal_uInt32 i = 0; i < spinCount; i++) 706*4e7b0f82SDamjan Jovanovic { 707*4e7b0f82SDamjan Jovanovic digest.initialize( digestAlgorithm ); 708*4e7b0f82SDamjan Jovanovic ByteOrderConverter::writeLittleEndian( &iteratorBuffer, i ); 709*4e7b0f82SDamjan Jovanovic digest.update( iteratorBuffer, sizeof( iteratorBuffer ) ); 710*4e7b0f82SDamjan Jovanovic digest.update( digestBuffer.data(), digestSize ); 711*4e7b0f82SDamjan Jovanovic digest.final( digestBuffer.data(), NULL ); 712*4e7b0f82SDamjan Jovanovic } 713*4e7b0f82SDamjan Jovanovic return digestBuffer; 714*4e7b0f82SDamjan Jovanovic } 715*4e7b0f82SDamjan Jovanovic 716*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.getBlock36(). 717*4e7b0f82SDamjan Jovanovic static void toBlock36( vector< sal_uInt8 >& digest, sal_uInt32 size ) 718*4e7b0f82SDamjan Jovanovic { 719*4e7b0f82SDamjan Jovanovic if( digest.size() < size ) 720*4e7b0f82SDamjan Jovanovic { 721*4e7b0f82SDamjan Jovanovic sal_uInt32 i = digest.size(); 722*4e7b0f82SDamjan Jovanovic digest.resize( size ); 723*4e7b0f82SDamjan Jovanovic for (; i < size; i++) 724*4e7b0f82SDamjan Jovanovic digest[ i ] = 0x36; 725*4e7b0f82SDamjan Jovanovic } 726*4e7b0f82SDamjan Jovanovic else 727*4e7b0f82SDamjan Jovanovic digest.resize( size ); 728*4e7b0f82SDamjan Jovanovic } 729*4e7b0f82SDamjan Jovanovic 730*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0(). 731*4e7b0f82SDamjan Jovanovic static void toBlock0( vector< sal_uInt8 >& digest, sal_uInt32 size ) 732*4e7b0f82SDamjan Jovanovic { 733*4e7b0f82SDamjan Jovanovic if( digest.size() < size ) 734*4e7b0f82SDamjan Jovanovic { 735*4e7b0f82SDamjan Jovanovic sal_uInt32 i = digest.size(); 736*4e7b0f82SDamjan Jovanovic digest.resize( size ); 737*4e7b0f82SDamjan Jovanovic for (; i < size; i++) 738*4e7b0f82SDamjan Jovanovic digest[ i ] = 0; 739*4e7b0f82SDamjan Jovanovic } 740*4e7b0f82SDamjan Jovanovic else 741*4e7b0f82SDamjan Jovanovic digest.resize( size ); 742*4e7b0f82SDamjan Jovanovic } 743*4e7b0f82SDamjan Jovanovic 744*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateKey(). 745*4e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > generateKey( const vector< sal_uInt8 >& passwordHash, 746*4e7b0f82SDamjan Jovanovic const EVP_MD *digestAlgorithm, 747*4e7b0f82SDamjan Jovanovic const vector< sal_uInt8 >& blockKey, 748*4e7b0f82SDamjan Jovanovic sal_uInt32 keySize ) 749*4e7b0f82SDamjan Jovanovic throw ( Exception ) 750*4e7b0f82SDamjan Jovanovic { 751*4e7b0f82SDamjan Jovanovic OpenSSLDigest digest; 752*4e7b0f82SDamjan Jovanovic digest.initialize( digestAlgorithm ); 753*4e7b0f82SDamjan Jovanovic digest.update( passwordHash.data(), passwordHash.size() ); 754*4e7b0f82SDamjan Jovanovic digest.update( blockKey.data(), blockKey.size() ); 755*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> key( digest.digestSize() ); 756*4e7b0f82SDamjan Jovanovic digest.final( key.data(), NULL ); 757*4e7b0f82SDamjan Jovanovic toBlock36( key, keySize ); 758*4e7b0f82SDamjan Jovanovic return key; 759*4e7b0f82SDamjan Jovanovic } 760*4e7b0f82SDamjan Jovanovic 761*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateIv(). 762*4e7b0f82SDamjan Jovanovic static vector< sal_uInt8> generateIv( const vector< sal_uInt8 >& salt, 763*4e7b0f82SDamjan Jovanovic sal_uInt32 blockSize ) 764*4e7b0f82SDamjan Jovanovic throw ( Exception ) 765*4e7b0f82SDamjan Jovanovic { 766*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> iv( salt ); 767*4e7b0f82SDamjan Jovanovic toBlock36( iv, blockSize ); 768*4e7b0f82SDamjan Jovanovic return iv; 769*4e7b0f82SDamjan Jovanovic } 770*4e7b0f82SDamjan Jovanovic 771*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateIv(). 772*4e7b0f82SDamjan Jovanovic static vector< sal_uInt8> generateIv( const EVP_MD *digestAlgorithm, 773*4e7b0f82SDamjan Jovanovic const vector< sal_uInt8 >& salt, 774*4e7b0f82SDamjan Jovanovic const vector< sal_uInt8 >& blockKey, 775*4e7b0f82SDamjan Jovanovic sal_uInt32 blockSize ) 776*4e7b0f82SDamjan Jovanovic throw ( Exception ) 777*4e7b0f82SDamjan Jovanovic { 778*4e7b0f82SDamjan Jovanovic OpenSSLDigest digest; 779*4e7b0f82SDamjan Jovanovic digest.initialize( digestAlgorithm ); 780*4e7b0f82SDamjan Jovanovic digest.update( salt.data(), salt.size() ); 781*4e7b0f82SDamjan Jovanovic digest.update( blockKey.data(), blockKey.size() ); 782*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> iv( digest.digestSize() ); 783*4e7b0f82SDamjan Jovanovic digest.final( iv.data(), NULL ); 784*4e7b0f82SDamjan Jovanovic toBlock36( iv, blockSize ); 785*4e7b0f82SDamjan Jovanovic return iv; 786*4e7b0f82SDamjan Jovanovic } 787*4e7b0f82SDamjan Jovanovic 788*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.getNextBlockSize(). 789*4e7b0f82SDamjan Jovanovic static sal_uInt32 getNextBlockSize( sal_uInt32 totalSize, sal_uInt32 blockSize ) 790*4e7b0f82SDamjan Jovanovic { 791*4e7b0f82SDamjan Jovanovic sal_uInt32 numberOfBlocks = ( totalSize + ( blockSize - 1 ) ) / blockSize; 792*4e7b0f82SDamjan Jovanovic return numberOfBlocks * blockSize; 793*4e7b0f82SDamjan Jovanovic } 794*4e7b0f82SDamjan Jovanovic 795*4e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > decryptAll( const EVP_CIPHER* cipherAlgorithm, 796*4e7b0f82SDamjan Jovanovic const sal_uInt8* iv, 797*4e7b0f82SDamjan Jovanovic const sal_uInt8* key, 798*4e7b0f82SDamjan Jovanovic const sal_uInt8* encryptedData, 799*4e7b0f82SDamjan Jovanovic sal_uInt32 encryptedDataLength ) 800*4e7b0f82SDamjan Jovanovic throw ( Exception ) 801*4e7b0f82SDamjan Jovanovic { 802*4e7b0f82SDamjan Jovanovic OpenSSLCipher cipher; 803*4e7b0f82SDamjan Jovanovic cipher.initialize( cipherAlgorithm, key, iv, 0 ); 804*4e7b0f82SDamjan Jovanovic cipher.setPadding( 0 ); 805*4e7b0f82SDamjan Jovanovic const int blockSize = cipher.blockSize(); 806*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > decryptedData( encryptedDataLength + 2*blockSize ); 807*4e7b0f82SDamjan Jovanovic 808*4e7b0f82SDamjan Jovanovic int decryptedDataLength; 809*4e7b0f82SDamjan Jovanovic cipher.update( encryptedData, encryptedDataLength, decryptedData.data(), &decryptedDataLength ); 810*4e7b0f82SDamjan Jovanovic int finalDataLength; 811*4e7b0f82SDamjan Jovanovic cipher.final( &decryptedData[ decryptedDataLength ], &finalDataLength ); 812*4e7b0f82SDamjan Jovanovic decryptedDataLength += finalDataLength; 813*4e7b0f82SDamjan Jovanovic decryptedData.resize( decryptedDataLength ); 814*4e7b0f82SDamjan Jovanovic return decryptedData; 815*4e7b0f82SDamjan Jovanovic } 816*4e7b0f82SDamjan Jovanovic 817*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.hashInput(). 818*4e7b0f82SDamjan Jovanovic static vector< sal_uInt8 > hashInput( const vector< sal_uInt8 >& passwordHash, 819*4e7b0f82SDamjan Jovanovic const vector< sal_uInt8 >& salt, 820*4e7b0f82SDamjan Jovanovic const EVP_MD *digestAlgorithm, 821*4e7b0f82SDamjan Jovanovic const vector< sal_uInt8 >& blockKey, 822*4e7b0f82SDamjan Jovanovic const vector< sal_uInt8 >& inputKey, 823*4e7b0f82SDamjan Jovanovic const EVP_CIPHER *decryptionAlgorithm, 824*4e7b0f82SDamjan Jovanovic sal_uInt32 keySize, 825*4e7b0f82SDamjan Jovanovic sal_uInt32 blockSize ) 826*4e7b0f82SDamjan Jovanovic throw ( Exception ) 827*4e7b0f82SDamjan Jovanovic { 828*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > intermediateKey = generateKey( passwordHash, digestAlgorithm, blockKey, keySize ); 829*4e7b0f82SDamjan Jovanovic vector< sal_uInt8> iv = generateIv( salt, blockSize ); 830*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > zeroedInput( inputKey.size() ); 831*4e7b0f82SDamjan Jovanovic zeroedInput = inputKey; 832*4e7b0f82SDamjan Jovanovic toBlock0( zeroedInput, getNextBlockSize( zeroedInput.size(), blockSize ) ); 833*4e7b0f82SDamjan Jovanovic return decryptAll( decryptionAlgorithm, iv.data(), intermediateKey.data(), zeroedInput.data(), zeroedInput.size() ); 834*4e7b0f82SDamjan Jovanovic } 835*4e7b0f82SDamjan Jovanovic 836*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.verifyPassword(). 837*4e7b0f82SDamjan Jovanovic Sequence< NamedValue > AgileEncryptionInfo::verifyPassword( const OUString& password ) 838*4e7b0f82SDamjan Jovanovic throw ( Exception ) 839*4e7b0f82SDamjan Jovanovic { 840*4e7b0f82SDamjan Jovanovic const EVP_MD *digestAlgorithm = toOpenSSLDigestAlgorithm( passwordKeyEncryptor.hashAlgorithm ); 841*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > passwordHash = hashPassword( password, digestAlgorithm, passwordKeyEncryptor.saltValue, passwordKeyEncryptor.spinCount ); 842*4e7b0f82SDamjan Jovanovic 843*4e7b0f82SDamjan Jovanovic static const sal_uInt8 verifierInputBlockData[] = { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 }; 844*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > verifierInputBlock( &verifierInputBlockData[ 0 ], &verifierInputBlockData[ sizeof( verifierInputBlockData ) ] ); 845*4e7b0f82SDamjan Jovanovic const EVP_CIPHER* cipher = toOpenSSLCipherAlgorithm( passwordKeyEncryptor.cipherAlgorithm, passwordKeyEncryptor.keyBits, passwordKeyEncryptor.cipherChaining ); 846*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > encryptedVerifierHash = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, verifierInputBlock, 847*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.encryptedVerifierHashInput, cipher, passwordKeyEncryptor.keyBits, 848*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.blockSize ); 849*4e7b0f82SDamjan Jovanovic const EVP_MD *verifierDigestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm ); 850*4e7b0f82SDamjan Jovanovic OpenSSLDigest verifierDigest; 851*4e7b0f82SDamjan Jovanovic verifierDigest.initialize( verifierDigestAlgorithm ); 852*4e7b0f82SDamjan Jovanovic verifierDigest.update( encryptedVerifierHash.data(), encryptedVerifierHash.size() ); 853*4e7b0f82SDamjan Jovanovic encryptedVerifierHash.resize( verifierDigest.digestSize() ); 854*4e7b0f82SDamjan Jovanovic verifierDigest.final( encryptedVerifierHash.data(), NULL ); 855*4e7b0f82SDamjan Jovanovic 856*4e7b0f82SDamjan Jovanovic static const sal_uInt8 verifierHashBlockData[] = { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e }; 857*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > verifierHashBlock( &verifierHashBlockData[ 0 ], &verifierHashBlockData[ sizeof( verifierHashBlockData ) ] ); 858*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > verifierHashDec = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, verifierHashBlock, 859*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.encryptedVerifierHashValue, cipher, passwordKeyEncryptor.keyBits, 860*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.blockSize ); 861*4e7b0f82SDamjan Jovanovic toBlock0( verifierHashDec, verifierDigest.digestSize() ); 862*4e7b0f82SDamjan Jovanovic 863*4e7b0f82SDamjan Jovanovic if( encryptedVerifierHash != verifierHashDec ) 864*4e7b0f82SDamjan Jovanovic return Sequence< NamedValue >(); 865*4e7b0f82SDamjan Jovanovic 866*4e7b0f82SDamjan Jovanovic // Password is correct. Decrypt and store the encryption key. 867*4e7b0f82SDamjan Jovanovic static const sal_uInt8 cryptoKeyBlockData[] = { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 }; 868*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > cryptoKeyBlock( &cryptoKeyBlockData[ 0 ], &cryptoKeyBlockData[ sizeof( cryptoKeyBlockData ) ] ); 869*4e7b0f82SDamjan Jovanovic encryptionKey = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, cryptoKeyBlock, 870*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.encryptedKeyValue, cipher, passwordKeyEncryptor.keyBits, 871*4e7b0f82SDamjan Jovanovic passwordKeyEncryptor.blockSize ); 872*4e7b0f82SDamjan Jovanovic toBlock0( encryptionKey, passwordKeyEncryptor.keyBits / 8 ); 873*4e7b0f82SDamjan Jovanovic 874*4e7b0f82SDamjan Jovanovic // Also decrypt the dataIntegrity fields for stream validation. Note that they are optional. 875*4e7b0f82SDamjan Jovanovic if( !dataIntegrity.encryptedHmacKey.empty() && !dataIntegrity.encryptedHmacValue.empty() ) 876*4e7b0f82SDamjan Jovanovic { 877*4e7b0f82SDamjan Jovanovic const EVP_MD* keyDataDigestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm ); 878*4e7b0f82SDamjan Jovanovic const EVP_CIPHER* keyDataCipher = toOpenSSLCipherAlgorithm( keyData.cipherAlgorithm, keyData.keyBits, keyData.cipherChaining ); 879*4e7b0f82SDamjan Jovanovic static const sal_uInt8 integrityKeyBlockData[] = { 0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, 0xf6 }; 880*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > integrityKeyBlock( &integrityKeyBlockData[ 0 ], &integrityKeyBlockData[ sizeof( integrityKeyBlockData ) ] ); 881*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > integrityKeyIv = generateIv( keyDataDigestAlgorithm, keyData.saltValue, integrityKeyBlock, keyData.blockSize ); 882*4e7b0f82SDamjan Jovanovic hmacKey = decryptAll( keyDataCipher, integrityKeyIv.data(), encryptionKey.data(), dataIntegrity.encryptedHmacKey.data(), dataIntegrity.encryptedHmacKey.size() ); 883*4e7b0f82SDamjan Jovanovic toBlock0( hmacKey, OpenSSLDigest::digestSize( keyDataDigestAlgorithm ) ); 884*4e7b0f82SDamjan Jovanovic 885*4e7b0f82SDamjan Jovanovic static const sal_uInt8 integrityValueBlockData[] = { 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, 0x33 }; 886*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > integrityValueBlock( &integrityValueBlockData[ 0 ], &integrityValueBlockData[ sizeof( integrityValueBlockData ) ] ); 887*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > integrityValueIv = generateIv( keyDataDigestAlgorithm, keyData.saltValue, integrityValueBlock, keyData.blockSize ); 888*4e7b0f82SDamjan Jovanovic hmacValue = decryptAll( keyDataCipher, integrityValueIv.data(), encryptionKey.data(), dataIntegrity.encryptedHmacValue.data(), dataIntegrity.encryptedHmacValue.size() ); 889*4e7b0f82SDamjan Jovanovic toBlock0( hmacValue, OpenSSLDigest::digestSize( keyDataDigestAlgorithm ) ); 890*4e7b0f82SDamjan Jovanovic } 891*4e7b0f82SDamjan Jovanovic 892*4e7b0f82SDamjan Jovanovic // On success, MUST populate something into the encryption data, even though we'll never use it. 893*4e7b0f82SDamjan Jovanovic SequenceAsHashMap encryptionData; 894*4e7b0f82SDamjan Jovanovic encryptionData[ CREATE_OUSTRING( "OOXMLAgileEncryptionPasswordVerified" ) ] <<= sal_True; 895*4e7b0f82SDamjan Jovanovic return encryptionData.getAsConstNamedValueList(); 896*4e7b0f82SDamjan Jovanovic } 897*4e7b0f82SDamjan Jovanovic 898*4e7b0f82SDamjan Jovanovic bool AgileEncryptionInfo::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) 899*4e7b0f82SDamjan Jovanovic throw ( Exception ) 900*4e7b0f82SDamjan Jovanovic { 901*4e7b0f82SDamjan Jovanovic // OpenGrok shows how only main/comphelper/source/misc/docpasswordhelper.cxx calls IDocPasswordVerifier::verifyEncryptionData(), 902*4e7b0f82SDamjan Jovanovic // and only when the password is wrong and the rMediaEncData non-empty, which presumably allows other forms of encryption 903*4e7b0f82SDamjan Jovanovic // (eg. by certificate) to be used. We only support password for now. 904*4e7b0f82SDamjan Jovanovic return false; 905*4e7b0f82SDamjan Jovanovic } 906*4e7b0f82SDamjan Jovanovic 907*4e7b0f82SDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.initCipherForBlock(). 908*4e7b0f82SDamjan Jovanovic void AgileEncryptionInfo::decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) 909*4e7b0f82SDamjan Jovanovic throw ( Exception ) 910*4e7b0f82SDamjan Jovanovic { 911*4e7b0f82SDamjan Jovanovic if( encryptionKey.empty() ) 912*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( "Encryption key not set, was the password wrong?" ), Reference< XInterface >() ); 913*4e7b0f82SDamjan Jovanovic const EVP_CIPHER* cipherAlgorithm = toOpenSSLCipherAlgorithm( keyData.cipherAlgorithm, keyData.keyBits, keyData.cipherChaining ); 914*4e7b0f82SDamjan Jovanovic const EVP_MD* digestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm ); 915*4e7b0f82SDamjan Jovanovic OpenSSLCipher cipher; 916*4e7b0f82SDamjan Jovanovic 917*4e7b0f82SDamjan Jovanovic const sal_uInt64 decryptedSize = aEncryptedPackage.readuInt64(); 918*4e7b0f82SDamjan Jovanovic 919*4e7b0f82SDamjan Jovanovic sal_uInt8 inputBuffer[ 4096 ]; 920*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > outputBuffer( 4096 + 2*cipher.blockSize() ); 921*4e7b0f82SDamjan Jovanovic sal_Int32 bytesIn; 922*4e7b0f82SDamjan Jovanovic int bytesOut; 923*4e7b0f82SDamjan Jovanovic int finalBytesOut; 924*4e7b0f82SDamjan Jovanovic sal_uInt64 totalBytesWritten = 0; 925*4e7b0f82SDamjan Jovanovic 926*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > blockBytes( 4 ); 927*4e7b0f82SDamjan Jovanovic bool done = false; 928*4e7b0f82SDamjan Jovanovic for ( sal_uInt32 block = 0; !done; block++ ) 929*4e7b0f82SDamjan Jovanovic { 930*4e7b0f82SDamjan Jovanovic ByteOrderConverter::writeLittleEndian( blockBytes.data(), block ); 931*4e7b0f82SDamjan Jovanovic vector< sal_uInt8 > iv = generateIv( digestAlgorithm, keyData.saltValue, blockBytes, keyData.blockSize ); 932*4e7b0f82SDamjan Jovanovic cipher.initialize( cipherAlgorithm, encryptionKey.data(), iv.data(), 0 ); 933*4e7b0f82SDamjan Jovanovic cipher.setPadding( 0 ); 934*4e7b0f82SDamjan Jovanovic 935*4e7b0f82SDamjan Jovanovic bytesIn = aEncryptedPackage.readMemory( inputBuffer, sizeof( inputBuffer ) ); 936*4e7b0f82SDamjan Jovanovic if( bytesIn > 0 ) 937*4e7b0f82SDamjan Jovanovic { 938*4e7b0f82SDamjan Jovanovic cipher.update( inputBuffer, bytesIn, outputBuffer.data(), &bytesOut ); 939*4e7b0f82SDamjan Jovanovic cipher.final( &outputBuffer[ bytesOut ], &finalBytesOut ); 940*4e7b0f82SDamjan Jovanovic bytesOut += finalBytesOut; 941*4e7b0f82SDamjan Jovanovic if( decryptedSize < (totalBytesWritten + bytesOut) ) 942*4e7b0f82SDamjan Jovanovic { 943*4e7b0f82SDamjan Jovanovic bytesOut = decryptedSize % sizeof( inputBuffer ); 944*4e7b0f82SDamjan Jovanovic done = true; 945*4e7b0f82SDamjan Jovanovic } 946*4e7b0f82SDamjan Jovanovic aDecryptedPackage.writeMemory( outputBuffer.data(), bytesOut ); 947*4e7b0f82SDamjan Jovanovic totalBytesWritten += bytesOut; 948*4e7b0f82SDamjan Jovanovic } else 949*4e7b0f82SDamjan Jovanovic done = true; 950*4e7b0f82SDamjan Jovanovic } 951*4e7b0f82SDamjan Jovanovic 952*4e7b0f82SDamjan Jovanovic aDecryptedPackage.flush(); 953*4e7b0f82SDamjan Jovanovic } 954*4e7b0f82SDamjan Jovanovic 955*4e7b0f82SDamjan Jovanovic EncryptionInfo* EncryptionInfo::readEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) 956*4e7b0f82SDamjan Jovanovic throw ( Exception ) 957*4e7b0f82SDamjan Jovanovic { 958*4e7b0f82SDamjan Jovanovic sal_uInt16 nVersionMajor = readUInt16LE( inputStream ); 959*4e7b0f82SDamjan Jovanovic sal_uInt16 nVersionMinor = readUInt16LE( inputStream ); 960*4e7b0f82SDamjan Jovanovic if( ( nVersionMajor == 2 && nVersionMinor == 2 ) || 961*4e7b0f82SDamjan Jovanovic ( nVersionMajor == 3 && nVersionMinor == 2 ) || 962*4e7b0f82SDamjan Jovanovic ( nVersionMajor == 4 && nVersionMinor == 2 ) ) 963*4e7b0f82SDamjan Jovanovic { 964*4e7b0f82SDamjan Jovanovic // 2.3.4.5 Standard Encryption 965*4e7b0f82SDamjan Jovanovic BinaryXInputStream aInfoStrm( inputStream, false ); 966*4e7b0f82SDamjan Jovanovic return new StandardEncryptionInfo( aInfoStrm ); 967*4e7b0f82SDamjan Jovanovic } 968*4e7b0f82SDamjan Jovanovic else if ( nVersionMajor == 4 && nVersionMajor == 4 ) 969*4e7b0f82SDamjan Jovanovic { 970*4e7b0f82SDamjan Jovanovic // 2.3.4.10 Agile Encryption 971*4e7b0f82SDamjan Jovanovic return new AgileEncryptionInfo( context, inputStream ); 972*4e7b0f82SDamjan Jovanovic } 973*4e7b0f82SDamjan Jovanovic else 974*4e7b0f82SDamjan Jovanovic { 975*4e7b0f82SDamjan Jovanovic char msg[ 1024 ]; 976*4e7b0f82SDamjan Jovanovic snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: unsupported EncryptionVersionInfo header with major=%hu minor=%hu", 977*4e7b0f82SDamjan Jovanovic nVersionMajor, nVersionMinor ); 978*4e7b0f82SDamjan Jovanovic throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() ); 979*4e7b0f82SDamjan Jovanovic } 980*4e7b0f82SDamjan Jovanovic } 981*4e7b0f82SDamjan Jovanovic 982*4e7b0f82SDamjan Jovanovic // ============================================================================ 983*4e7b0f82SDamjan Jovanovic 984*4e7b0f82SDamjan Jovanovic } // namespace core 985*4e7b0f82SDamjan Jovanovic } // namespace oox 986