1506fa58bSDamjan Jovanovic /************************************************************** 2506fa58bSDamjan Jovanovic * 3506fa58bSDamjan Jovanovic * Licensed to the Apache Software Foundation (ASF) under one 4506fa58bSDamjan Jovanovic * or more contributor license agreements. See the NOTICE file 5506fa58bSDamjan Jovanovic * distributed with this work for additional information 6506fa58bSDamjan Jovanovic * regarding copyright ownership. The ASF licenses this file 7506fa58bSDamjan Jovanovic * to you under the Apache License, Version 2.0 (the 8506fa58bSDamjan Jovanovic * "License"); you may not use this file except in compliance 9506fa58bSDamjan Jovanovic * with the License. You may obtain a copy of the License at 10506fa58bSDamjan Jovanovic * 11506fa58bSDamjan Jovanovic * http://www.apache.org/licenses/LICENSE-2.0 12506fa58bSDamjan Jovanovic * 13506fa58bSDamjan Jovanovic * Unless required by applicable law or agreed to in writing, 14506fa58bSDamjan Jovanovic * software distributed under the License is distributed on an 15506fa58bSDamjan Jovanovic * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16506fa58bSDamjan Jovanovic * KIND, either express or implied. See the License for the 17506fa58bSDamjan Jovanovic * specific language governing permissions and limitations 18506fa58bSDamjan Jovanovic * under the License. 19506fa58bSDamjan Jovanovic * 20506fa58bSDamjan Jovanovic *************************************************************/ 21506fa58bSDamjan Jovanovic 22506fa58bSDamjan Jovanovic 23506fa58bSDamjan Jovanovic 24506fa58bSDamjan Jovanovic #include "oox/core/encryption.hxx" 25506fa58bSDamjan Jovanovic #include "oox/core/fastparser.hxx" 26506fa58bSDamjan Jovanovic #include "oox/helper/attributelist.hxx" 27506fa58bSDamjan Jovanovic #include "oox/helper/helper.hxx" 28506fa58bSDamjan Jovanovic #include "oox/helper/openssl_wrapper.hxx" 29506fa58bSDamjan Jovanovic 30506fa58bSDamjan Jovanovic #include <rtl/digest.h> 31506fa58bSDamjan Jovanovic #include <cppuhelper/implbase1.hxx> 32506fa58bSDamjan Jovanovic #include <openssl/evp.h> 33506fa58bSDamjan Jovanovic 34506fa58bSDamjan Jovanovic #include <com/sun/star/io/XStream.hpp> 35506fa58bSDamjan Jovanovic 36506fa58bSDamjan Jovanovic 37506fa58bSDamjan Jovanovic 38506fa58bSDamjan Jovanovic namespace oox { 39506fa58bSDamjan Jovanovic namespace core { 40506fa58bSDamjan Jovanovic 41506fa58bSDamjan Jovanovic // ============================================================================ 42506fa58bSDamjan Jovanovic 43506fa58bSDamjan Jovanovic using namespace ::com::sun::star::beans; 44506fa58bSDamjan Jovanovic using namespace ::com::sun::star::uno; 45506fa58bSDamjan Jovanovic using namespace ::com::sun::star::xml::sax; 46506fa58bSDamjan Jovanovic 47506fa58bSDamjan Jovanovic using ::com::sun::star::io::XInputStream; 48506fa58bSDamjan Jovanovic using ::comphelper::SequenceAsHashMap; 49506fa58bSDamjan Jovanovic using ::rtl::OUString; 50506fa58bSDamjan Jovanovic using ::std::vector; 51506fa58bSDamjan Jovanovic 52506fa58bSDamjan Jovanovic // ============================================================================ 53506fa58bSDamjan Jovanovic 54506fa58bSDamjan Jovanovic 55506fa58bSDamjan Jovanovic /* =========================================================================== */ 56506fa58bSDamjan Jovanovic /* Kudos to Caolan McNamara who provided the core decryption implementation */ 57506fa58bSDamjan Jovanovic /* of Standard Encryption (MS-OFFCRYPTO section 2.3.4.5). */ 58506fa58bSDamjan Jovanovic /* =========================================================================== */ 59506fa58bSDamjan Jovanovic 60506fa58bSDamjan Jovanovic #define ENCRYPTINFO_CRYPTOAPI 0x00000004U 61506fa58bSDamjan Jovanovic #define ENCRYPTINFO_DOCPROPS 0x00000008U 62506fa58bSDamjan Jovanovic #define ENCRYPTINFO_EXTERNAL 0x00000010U 63506fa58bSDamjan Jovanovic #define ENCRYPTINFO_AES 0x00000020U 64506fa58bSDamjan Jovanovic 65506fa58bSDamjan Jovanovic #define ENCRYPT_ALGO_AES128 0x0000660EU 66506fa58bSDamjan Jovanovic #define ENCRYPT_ALGO_AES192 0x0000660FU 67506fa58bSDamjan Jovanovic #define ENCRYPT_ALGO_AES256 0x00006610U 68506fa58bSDamjan Jovanovic #define ENCRYPT_ALGO_RC4 0x00006801U 69506fa58bSDamjan Jovanovic 70506fa58bSDamjan Jovanovic #define ENCRYPT_HASH_SHA1 0x00008004U 71506fa58bSDamjan Jovanovic 72506fa58bSDamjan Jovanovic class StandardEncryptionInfo : public EncryptionInfo 73506fa58bSDamjan Jovanovic { 74506fa58bSDamjan Jovanovic public: 75506fa58bSDamjan Jovanovic StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception ); 76506fa58bSDamjan Jovanovic ~StandardEncryptionInfo() {} 77506fa58bSDamjan Jovanovic bool isImplemented(); 78506fa58bSDamjan Jovanovic Sequence< NamedValue > verifyPassword( const OUString& rPassword ) throw ( Exception ); 79506fa58bSDamjan Jovanovic bool verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception ); 80506fa58bSDamjan 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 ); 81506fa58bSDamjan Jovanovic void decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception ); 82506fa58bSDamjan Jovanovic 83506fa58bSDamjan Jovanovic private: 84506fa58bSDamjan Jovanovic sal_uInt8 mpnSalt[ 16 ]; 85506fa58bSDamjan Jovanovic sal_uInt8 mpnEncrVerifier[ 16 ]; 86506fa58bSDamjan Jovanovic sal_uInt8 mpnEncrVerifierHash[ 32 ]; 87506fa58bSDamjan Jovanovic sal_uInt32 mnFlags; 88506fa58bSDamjan Jovanovic sal_uInt32 mnAlgorithmId; 89506fa58bSDamjan Jovanovic sal_uInt32 mnAlgorithmIdHash; 90506fa58bSDamjan Jovanovic sal_uInt32 mnKeySize; 91506fa58bSDamjan Jovanovic sal_uInt32 mnSaltSize; 92506fa58bSDamjan Jovanovic sal_uInt32 mnVerifierHashSize; 93506fa58bSDamjan Jovanovic vector< sal_uInt8> encryptionKey; 94506fa58bSDamjan Jovanovic }; 95506fa58bSDamjan Jovanovic 96506fa58bSDamjan Jovanovic StandardEncryptionInfo::StandardEncryptionInfo( BinaryInputStream& rStrm ) throw ( Exception ) 97506fa58bSDamjan Jovanovic { 98506fa58bSDamjan Jovanovic char msg[ 1024 ]; 99506fa58bSDamjan Jovanovic rStrm >> mnFlags; 100*42c0a318SDamjan Jovanovic if( getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_EXTERNAL ) ) 101506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: \"Extensible encryption\" is not currently supported, please report" ), Reference< XInterface >() ); 102506fa58bSDamjan Jovanovic 103506fa58bSDamjan Jovanovic sal_uInt32 nHeaderSize, nRepeatedFlags; 104506fa58bSDamjan Jovanovic rStrm >> nHeaderSize >> nRepeatedFlags; 105506fa58bSDamjan Jovanovic if( nHeaderSize < 20 ) 106506fa58bSDamjan Jovanovic { 107506fa58bSDamjan Jovanovic snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: header size %u is too short", nHeaderSize ); 108506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() ); 109506fa58bSDamjan Jovanovic } 110506fa58bSDamjan Jovanovic if( nRepeatedFlags != mnFlags ) 111506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: flags don't match" ), Reference< XInterface>() ); 112506fa58bSDamjan Jovanovic 113506fa58bSDamjan Jovanovic rStrm.skip( 4 ); 114506fa58bSDamjan Jovanovic rStrm >> mnAlgorithmId >> mnAlgorithmIdHash >> mnKeySize; 115506fa58bSDamjan Jovanovic rStrm.skip( nHeaderSize - 20 ); 116506fa58bSDamjan Jovanovic rStrm >> mnSaltSize; 117506fa58bSDamjan Jovanovic if( mnSaltSize != 16 ) 118506fa58bSDamjan Jovanovic { 119506fa58bSDamjan Jovanovic snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: salt size is %u instead of 16", mnSaltSize ); 120506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() ); 121506fa58bSDamjan Jovanovic } 122506fa58bSDamjan Jovanovic 123506fa58bSDamjan Jovanovic rStrm.readMemory( mpnSalt, 16 ); 124506fa58bSDamjan Jovanovic rStrm.readMemory( mpnEncrVerifier, 16 ); 125506fa58bSDamjan Jovanovic rStrm >> mnVerifierHashSize; 126506fa58bSDamjan Jovanovic rStrm.readMemory( mpnEncrVerifierHash, 32 ); 127506fa58bSDamjan Jovanovic if( rStrm.isEof() ) 128506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() error: standard encryption header too short" ), Reference< XInterface >() ); 129506fa58bSDamjan Jovanovic } 130506fa58bSDamjan Jovanovic 131506fa58bSDamjan Jovanovic bool StandardEncryptionInfo::isImplemented() 132506fa58bSDamjan Jovanovic { 133*42c0a318SDamjan Jovanovic return getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_CRYPTOAPI ) && 134*42c0a318SDamjan Jovanovic getFlag( mnFlags, (sal_uInt32) ENCRYPTINFO_AES ) && 135506fa58bSDamjan Jovanovic // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set 136506fa58bSDamjan Jovanovic ( ( mnAlgorithmId == 0 ) || ( mnAlgorithmId == ENCRYPT_ALGO_AES128 ) ) && 137506fa58bSDamjan Jovanovic // hash algorithm ID 0 defaults to SHA-1 too 138506fa58bSDamjan Jovanovic ( ( mnAlgorithmIdHash == 0 ) || ( mnAlgorithmIdHash == ENCRYPT_HASH_SHA1 ) ) && 139506fa58bSDamjan Jovanovic ( mnVerifierHashSize == 20 ); 140506fa58bSDamjan Jovanovic } 141506fa58bSDamjan Jovanovic 142506fa58bSDamjan Jovanovic static void deriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen ) 143506fa58bSDamjan Jovanovic { 144506fa58bSDamjan Jovanovic sal_uInt8 pnBuffer[ 64 ]; 145506fa58bSDamjan Jovanovic memset( pnBuffer, 0x36, sizeof( pnBuffer ) ); 146506fa58bSDamjan Jovanovic for( sal_uInt32 i = 0; i < nHashLen; ++i ) 147506fa58bSDamjan Jovanovic pnBuffer[ i ] ^= pnHash[ i ]; 148506fa58bSDamjan Jovanovic 149506fa58bSDamjan Jovanovic rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 150506fa58bSDamjan Jovanovic rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) ); 151506fa58bSDamjan Jovanovic sal_uInt8 pnX1[ RTL_DIGEST_LENGTH_SHA1 ]; 152506fa58bSDamjan Jovanovic aError = rtl_digest_get( aDigest, pnX1, RTL_DIGEST_LENGTH_SHA1 ); 153506fa58bSDamjan Jovanovic rtl_digest_destroy( aDigest ); 154506fa58bSDamjan Jovanovic 155506fa58bSDamjan Jovanovic memset( pnBuffer, 0x5C, sizeof( pnBuffer ) ); 156506fa58bSDamjan Jovanovic for( sal_uInt32 i = 0; i < nHashLen; ++i ) 157506fa58bSDamjan Jovanovic pnBuffer[ i ] ^= pnHash[ i ]; 158506fa58bSDamjan Jovanovic 159506fa58bSDamjan Jovanovic aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 160506fa58bSDamjan Jovanovic aError = rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) ); 161506fa58bSDamjan Jovanovic sal_uInt8 pnX2[ RTL_DIGEST_LENGTH_SHA1 ]; 162506fa58bSDamjan Jovanovic aError = rtl_digest_get( aDigest, pnX2, RTL_DIGEST_LENGTH_SHA1 ); 163506fa58bSDamjan Jovanovic rtl_digest_destroy( aDigest ); 164506fa58bSDamjan Jovanovic 165506fa58bSDamjan Jovanovic if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 ) 166506fa58bSDamjan Jovanovic { 167506fa58bSDamjan Jovanovic memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 ); 168506fa58bSDamjan Jovanovic nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1; 169506fa58bSDamjan Jovanovic } 170506fa58bSDamjan Jovanovic memcpy( pnKeyDerived, pnX1, nRequiredKeyLen ); 171506fa58bSDamjan Jovanovic } 172506fa58bSDamjan Jovanovic 173506fa58bSDamjan Jovanovic Sequence< NamedValue > StandardEncryptionInfo::verifyPassword( const OUString& rPassword ) throw ( Exception ) 174506fa58bSDamjan Jovanovic { 175506fa58bSDamjan Jovanovic size_t nBufferSize = mnSaltSize + 2 * rPassword.getLength(); 176506fa58bSDamjan Jovanovic sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ]; 177506fa58bSDamjan Jovanovic memcpy( pnBuffer, mpnSalt, mnSaltSize ); 178506fa58bSDamjan Jovanovic 179506fa58bSDamjan Jovanovic sal_uInt8* pnPasswordLoc = pnBuffer + mnSaltSize; 180506fa58bSDamjan Jovanovic const sal_Unicode* pStr = rPassword.getStr(); 181506fa58bSDamjan Jovanovic for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 ) 182506fa58bSDamjan Jovanovic ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) ); 183506fa58bSDamjan Jovanovic 184506fa58bSDamjan Jovanovic rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 185506fa58bSDamjan Jovanovic rtlDigestError aError = rtl_digest_update( aDigest, pnBuffer, nBufferSize ); 186506fa58bSDamjan Jovanovic delete[] pnBuffer; 187506fa58bSDamjan Jovanovic 188506fa58bSDamjan Jovanovic size_t nHashSize = RTL_DIGEST_LENGTH_SHA1 + 4; 189506fa58bSDamjan Jovanovic sal_uInt8* pnHash = new sal_uInt8[ nHashSize ]; 190506fa58bSDamjan Jovanovic aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 ); 191506fa58bSDamjan Jovanovic rtl_digest_destroy( aDigest ); 192506fa58bSDamjan Jovanovic 193506fa58bSDamjan Jovanovic for( sal_uInt32 i = 0; i < 50000; ++i ) 194506fa58bSDamjan Jovanovic { 195506fa58bSDamjan Jovanovic ByteOrderConverter::writeLittleEndian( pnHash, i ); 196506fa58bSDamjan Jovanovic aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 197506fa58bSDamjan Jovanovic aError = rtl_digest_update( aDigest, pnHash, nHashSize ); 198506fa58bSDamjan Jovanovic aError = rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 ); 199506fa58bSDamjan Jovanovic rtl_digest_destroy( aDigest ); 200506fa58bSDamjan Jovanovic } 201506fa58bSDamjan Jovanovic 202506fa58bSDamjan Jovanovic memmove( pnHash, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 ); 203506fa58bSDamjan Jovanovic memset( pnHash + RTL_DIGEST_LENGTH_SHA1, 0, 4 ); 204506fa58bSDamjan Jovanovic aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 205506fa58bSDamjan Jovanovic aError = rtl_digest_update( aDigest, pnHash, nHashSize ); 206506fa58bSDamjan Jovanovic aError = rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 ); 207506fa58bSDamjan Jovanovic rtl_digest_destroy( aDigest ); 208506fa58bSDamjan Jovanovic 209506fa58bSDamjan Jovanovic vector< sal_uInt8 > key( mnKeySize / 8 ); 210f65b4e32SDamjan Jovanovic deriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, &key[ 0 ], key.size() ); 211506fa58bSDamjan Jovanovic delete[] pnHash; 212506fa58bSDamjan Jovanovic 213506fa58bSDamjan Jovanovic Sequence< NamedValue > aResult; 214f65b4e32SDamjan Jovanovic if( checkEncryptionData( &key[ 0 ], key.size(), mpnEncrVerifier, sizeof( mpnEncrVerifier ), mpnEncrVerifierHash, sizeof( mpnEncrVerifierHash ) ) ) 215506fa58bSDamjan Jovanovic { 216506fa58bSDamjan Jovanovic SequenceAsHashMap aEncryptionData; 217f65b4e32SDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionKey" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( &key[ 0 ] ), key.size() ); 218506fa58bSDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionSalt" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnSalt ), mnSaltSize ); 219506fa58bSDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifier" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnEncrVerifier ), sizeof( mpnEncrVerifier ) ); 220506fa58bSDamjan Jovanovic aEncryptionData[ CREATE_OUSTRING( "AES128EncryptionVerifierHash" ) ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( mpnEncrVerifierHash ), sizeof( mpnEncrVerifierHash ) ); 221506fa58bSDamjan Jovanovic encryptionKey = key; 222506fa58bSDamjan Jovanovic aResult = aEncryptionData.getAsConstNamedValueList(); 223506fa58bSDamjan Jovanovic } 224506fa58bSDamjan Jovanovic 225506fa58bSDamjan Jovanovic return aResult; 226506fa58bSDamjan Jovanovic } 227506fa58bSDamjan Jovanovic 228506fa58bSDamjan Jovanovic bool StandardEncryptionInfo::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception ) 229506fa58bSDamjan Jovanovic { 230506fa58bSDamjan Jovanovic SequenceAsHashMap aHashData( rEncryptionData ); 231506fa58bSDamjan Jovanovic Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionKey" ), Sequence< sal_Int8 >() ); 232506fa58bSDamjan Jovanovic Sequence< sal_Int8 > aVerifier = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifier" ), Sequence< sal_Int8 >() ); 233506fa58bSDamjan Jovanovic Sequence< sal_Int8 > aVerifierHash = aHashData.getUnpackedValueOrDefault( CREATE_OUSTRING( "AES128EncryptionVerifierHash" ), Sequence< sal_Int8 >() ); 234506fa58bSDamjan Jovanovic const sal_uInt8 *pnKey = reinterpret_cast< const sal_uInt8* >( aKey.getConstArray() ); 235506fa58bSDamjan Jovanovic sal_uInt32 nKeySize = aKey.getLength(); 236506fa58bSDamjan Jovanovic const sal_uInt8 *pnVerifier = reinterpret_cast< const sal_uInt8* >( aVerifier.getConstArray() ); 237506fa58bSDamjan Jovanovic sal_uInt32 nVerifierSize = aVerifier.getLength(); 238506fa58bSDamjan Jovanovic const sal_uInt8 *pnVerifierHash = reinterpret_cast< const sal_uInt8* >( aVerifierHash.getConstArray() ); 239506fa58bSDamjan Jovanovic sal_uInt32 nVerifierHashSize = aVerifierHash.getLength(); 240506fa58bSDamjan Jovanovic if( checkEncryptionData( pnKey, nKeySize, pnVerifier, nVerifierSize, pnVerifierHash, nVerifierHashSize ) ) 241506fa58bSDamjan Jovanovic { 242506fa58bSDamjan Jovanovic encryptionKey = vector< sal_uInt8 >( &pnKey[ 0 ], &pnKey[ nKeySize ] ); 243506fa58bSDamjan Jovanovic return true; 244506fa58bSDamjan Jovanovic } 245506fa58bSDamjan Jovanovic else 246506fa58bSDamjan Jovanovic return false; 247506fa58bSDamjan Jovanovic } 248506fa58bSDamjan Jovanovic 249506fa58bSDamjan 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 ) 250506fa58bSDamjan Jovanovic { 251506fa58bSDamjan Jovanovic bool bResult = false; 252506fa58bSDamjan Jovanovic 253506fa58bSDamjan Jovanovic // the only currently supported algorithm needs key size 128 254506fa58bSDamjan Jovanovic if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 ) 255506fa58bSDamjan Jovanovic { 256506fa58bSDamjan Jovanovic // check password 257506fa58bSDamjan Jovanovic EVP_CIPHER_CTX *aes_ctx; 258506fa58bSDamjan Jovanovic aes_ctx = EVP_CIPHER_CTX_new(); 259506fa58bSDamjan Jovanovic if ( aes_ctx == NULL ) 260506fa58bSDamjan Jovanovic return false; 261506fa58bSDamjan Jovanovic EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); 262506fa58bSDamjan Jovanovic EVP_CIPHER_CTX_set_padding( aes_ctx, 0 ); 263506fa58bSDamjan Jovanovic int nOutLen = 0; 264506fa58bSDamjan Jovanovic sal_uInt8 pnTmpVerifier[ 16 ]; 265506fa58bSDamjan Jovanovic (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) ); 266506fa58bSDamjan Jovanovic 267506fa58bSDamjan Jovanovic /*int*/ EVP_DecryptUpdate( aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize ); 268506fa58bSDamjan Jovanovic EVP_CIPHER_CTX_free( aes_ctx ); 269506fa58bSDamjan Jovanovic 270506fa58bSDamjan Jovanovic aes_ctx = EVP_CIPHER_CTX_new(); 271506fa58bSDamjan Jovanovic if ( aes_ctx == NULL ) 272506fa58bSDamjan Jovanovic return false; 273506fa58bSDamjan Jovanovic EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 ); 274506fa58bSDamjan Jovanovic EVP_CIPHER_CTX_set_padding( aes_ctx, 0 ); 275506fa58bSDamjan Jovanovic sal_uInt8 pnTmpVerifierHash[ 32 ]; 276506fa58bSDamjan Jovanovic (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) ); 277506fa58bSDamjan Jovanovic 278506fa58bSDamjan Jovanovic /*int*/ EVP_DecryptUpdate( aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize ); 279506fa58bSDamjan Jovanovic EVP_CIPHER_CTX_free( aes_ctx ); 280506fa58bSDamjan Jovanovic 281506fa58bSDamjan Jovanovic rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 ); 282506fa58bSDamjan Jovanovic rtlDigestError aError = rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) ); 283506fa58bSDamjan Jovanovic sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ]; 284506fa58bSDamjan Jovanovic aError = rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 ); 285506fa58bSDamjan Jovanovic rtl_digest_destroy( aDigest ); 286506fa58bSDamjan Jovanovic 287506fa58bSDamjan Jovanovic bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 ); 288506fa58bSDamjan Jovanovic } 289506fa58bSDamjan Jovanovic 290506fa58bSDamjan Jovanovic return bResult; 291506fa58bSDamjan Jovanovic } 292506fa58bSDamjan Jovanovic 293506fa58bSDamjan Jovanovic void StandardEncryptionInfo::decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception ) 294506fa58bSDamjan Jovanovic { 295506fa58bSDamjan Jovanovic EVP_CIPHER_CTX *aes_ctx; 296506fa58bSDamjan Jovanovic aes_ctx = EVP_CIPHER_CTX_new(); 297506fa58bSDamjan Jovanovic if ( aes_ctx == NULL ) 298506fa58bSDamjan Jovanovic throw Exception(); 299f65b4e32SDamjan Jovanovic EVP_DecryptInit_ex( aes_ctx, EVP_aes_128_ecb(), 0, &encryptionKey[ 0 ], 0 ); 300506fa58bSDamjan Jovanovic EVP_CIPHER_CTX_set_padding( aes_ctx, 0 ); 301506fa58bSDamjan Jovanovic 302506fa58bSDamjan Jovanovic sal_uInt8 pnInBuffer[ 1024 ]; 303506fa58bSDamjan Jovanovic sal_uInt8 pnOutBuffer[ 1024 ]; 304506fa58bSDamjan Jovanovic sal_Int32 nInLen; 305506fa58bSDamjan Jovanovic int nOutLen; 306506fa58bSDamjan Jovanovic aEncryptedPackage.skip( 8 ); // decrypted size 307506fa58bSDamjan Jovanovic while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 ) 308506fa58bSDamjan Jovanovic { 309506fa58bSDamjan Jovanovic EVP_DecryptUpdate( aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen ); 310506fa58bSDamjan Jovanovic aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen ); 311506fa58bSDamjan Jovanovic } 312506fa58bSDamjan Jovanovic EVP_DecryptFinal_ex( aes_ctx, pnOutBuffer, &nOutLen ); 313506fa58bSDamjan Jovanovic aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen ); 314506fa58bSDamjan Jovanovic 315506fa58bSDamjan Jovanovic EVP_CIPHER_CTX_free( aes_ctx ); 316506fa58bSDamjan Jovanovic aDecryptedPackage.flush(); 317506fa58bSDamjan Jovanovic } 318506fa58bSDamjan Jovanovic 319506fa58bSDamjan Jovanovic // ============================================================================ 320506fa58bSDamjan Jovanovic // "Agile" encryption, 2.3.4.10 of MS-OFFCRYPTO 321506fa58bSDamjan Jovanovic // ============================================================================ 322506fa58bSDamjan Jovanovic 323506fa58bSDamjan Jovanovic struct AgileKeyData 324506fa58bSDamjan Jovanovic { 325506fa58bSDamjan Jovanovic sal_Int32 saltSize; 326506fa58bSDamjan Jovanovic sal_Int32 blockSize; 327506fa58bSDamjan Jovanovic sal_Int32 keyBits; 328506fa58bSDamjan Jovanovic sal_Int32 hashSize; 329506fa58bSDamjan Jovanovic OUString cipherAlgorithm; 330506fa58bSDamjan Jovanovic OUString cipherChaining; 331506fa58bSDamjan Jovanovic OUString hashAlgorithm; 332506fa58bSDamjan Jovanovic vector< sal_uInt8 > saltValue; 333506fa58bSDamjan Jovanovic }; 334506fa58bSDamjan Jovanovic 335506fa58bSDamjan Jovanovic struct AgileDataIntegrity 336506fa58bSDamjan Jovanovic { 337506fa58bSDamjan Jovanovic vector< sal_uInt8 > encryptedHmacKey; 338506fa58bSDamjan Jovanovic vector< sal_uInt8 > encryptedHmacValue; 339506fa58bSDamjan Jovanovic }; 340506fa58bSDamjan Jovanovic 341506fa58bSDamjan Jovanovic struct AgilePasswordKeyEncryptor 342506fa58bSDamjan Jovanovic { 343506fa58bSDamjan Jovanovic sal_Int32 saltSize; 344506fa58bSDamjan Jovanovic sal_Int32 blockSize; 345506fa58bSDamjan Jovanovic sal_Int32 keyBits; 346506fa58bSDamjan Jovanovic sal_Int32 hashSize; 347506fa58bSDamjan Jovanovic OUString cipherAlgorithm; 348506fa58bSDamjan Jovanovic OUString cipherChaining; 349506fa58bSDamjan Jovanovic OUString hashAlgorithm; 350506fa58bSDamjan Jovanovic vector< sal_uInt8 > saltValue; 351506fa58bSDamjan Jovanovic sal_Int32 spinCount; 352506fa58bSDamjan Jovanovic vector< sal_uInt8 > encryptedVerifierHashInput; 353506fa58bSDamjan Jovanovic vector< sal_uInt8 > encryptedVerifierHashValue; 354506fa58bSDamjan Jovanovic vector< sal_uInt8 > encryptedKeyValue; 355506fa58bSDamjan Jovanovic }; 356506fa58bSDamjan Jovanovic 357506fa58bSDamjan Jovanovic static bool decodeBase64( OUString& base64, vector< sal_uInt8 >& bytes ) 358506fa58bSDamjan Jovanovic { 359506fa58bSDamjan Jovanovic ::rtl::OString base64Ascii = ::rtl::OUStringToOString( base64, RTL_TEXTENCODING_UTF8 ); 360506fa58bSDamjan Jovanovic const sal_uInt32 len = base64Ascii.getLength(); 361506fa58bSDamjan Jovanovic bytes.resize( (len + 3) / 4 * 3 ); 362f65b4e32SDamjan Jovanovic int decodedSize = EVP_DecodeBlock( &bytes[ 0 ], reinterpret_cast< sal_uInt8 const * >( base64Ascii.getStr() ), len ); 363506fa58bSDamjan Jovanovic if ( decodedSize < 0 ) 364506fa58bSDamjan Jovanovic return false; 365506fa58bSDamjan Jovanovic if ( len >= 2 && base64Ascii[ len-1 ] == '=' && base64Ascii[ len-2 ] == '=' ) 366506fa58bSDamjan Jovanovic decodedSize -= 2; 367506fa58bSDamjan Jovanovic else if ( len >= 1 && base64Ascii[ len-1] == '=' ) 368506fa58bSDamjan Jovanovic decodedSize--; 369506fa58bSDamjan Jovanovic bytes.resize( decodedSize ); 370506fa58bSDamjan Jovanovic return true; 371506fa58bSDamjan Jovanovic } 372506fa58bSDamjan Jovanovic 373506fa58bSDamjan Jovanovic class AgileEncryptionInfo : public EncryptionInfo 374506fa58bSDamjan Jovanovic { 375506fa58bSDamjan Jovanovic public: 376506fa58bSDamjan Jovanovic AgileEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) throw ( Exception ); 377506fa58bSDamjan Jovanovic ~AgileEncryptionInfo() {} 378506fa58bSDamjan Jovanovic bool isImplemented() { return true; } // FIXME 379506fa58bSDamjan Jovanovic Sequence< NamedValue > verifyPassword( const OUString& rPassword ) throw ( Exception ); 380506fa58bSDamjan Jovanovic bool verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) throw ( Exception ); 381506fa58bSDamjan Jovanovic void decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) throw ( Exception ); 382506fa58bSDamjan Jovanovic 383506fa58bSDamjan Jovanovic private: 384506fa58bSDamjan Jovanovic AgileKeyData keyData; 385506fa58bSDamjan Jovanovic AgileDataIntegrity dataIntegrity; 386506fa58bSDamjan Jovanovic AgilePasswordKeyEncryptor passwordKeyEncryptor; 387506fa58bSDamjan Jovanovic vector< sal_uInt8> encryptionKey; 388506fa58bSDamjan Jovanovic vector< sal_uInt8> hmacKey; 389506fa58bSDamjan Jovanovic vector< sal_uInt8> hmacValue; 390506fa58bSDamjan Jovanovic }; 391506fa58bSDamjan Jovanovic 392506fa58bSDamjan Jovanovic // A SAX handler that parses the XML from the "XmlEncryptionDescriptor" in the EncryptionInfo stream. 393506fa58bSDamjan Jovanovic class AgileEncryptionHandler : public ::cppu::WeakImplHelper1< XFastDocumentHandler > 394506fa58bSDamjan Jovanovic { 395506fa58bSDamjan Jovanovic public: 396506fa58bSDamjan Jovanovic AgileEncryptionHandler( AgileKeyData &aKeyData, AgileDataIntegrity &aDataIntegrity, AgilePasswordKeyEncryptor &aPasswordKeyEncryptor ) 397506fa58bSDamjan Jovanovic : keyData( aKeyData ), 398506fa58bSDamjan Jovanovic dataIntegrity( aDataIntegrity ), 399506fa58bSDamjan Jovanovic passwordKeyEncryptor( aPasswordKeyEncryptor ) 400506fa58bSDamjan Jovanovic { 401506fa58bSDamjan Jovanovic } 402506fa58bSDamjan Jovanovic 403506fa58bSDamjan Jovanovic // XFastDocumentHandler 404506fa58bSDamjan Jovanovic virtual void SAL_CALL startDocument() throw (SAXException, RuntimeException); 405506fa58bSDamjan Jovanovic virtual void SAL_CALL endDocument() throw (SAXException, RuntimeException); 406506fa58bSDamjan Jovanovic virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) throw (SAXException, RuntimeException); 407506fa58bSDamjan Jovanovic 408506fa58bSDamjan Jovanovic // XFastContextHandler 409506fa58bSDamjan Jovanovic virtual void SAL_CALL startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 410506fa58bSDamjan Jovanovic virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 411506fa58bSDamjan Jovanovic virtual void SAL_CALL endFastElement( sal_Int32 Element ) throw (SAXException, RuntimeException); 412506fa58bSDamjan Jovanovic virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) throw (SAXException, RuntimeException); 413506fa58bSDamjan Jovanovic virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 Element, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 414506fa58bSDamjan Jovanovic virtual Reference< XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs ) throw (SAXException, RuntimeException); 415506fa58bSDamjan Jovanovic virtual void SAL_CALL characters( const OUString& aChars ) throw (SAXException, RuntimeException); 416506fa58bSDamjan Jovanovic virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) throw (SAXException, RuntimeException); 417506fa58bSDamjan Jovanovic virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) throw (SAXException, RuntimeException); 418506fa58bSDamjan Jovanovic 419506fa58bSDamjan Jovanovic OUString& getLastError() { return lastError; } 420506fa58bSDamjan Jovanovic 421506fa58bSDamjan Jovanovic private: 422506fa58bSDamjan Jovanovic void parseKeyData( const AttributeList& attribs ) throw (SAXException, RuntimeException); 423506fa58bSDamjan Jovanovic void parseDataIntegrity( const AttributeList& attribs ) throw (SAXException, RuntimeException); 424506fa58bSDamjan Jovanovic void parseEncryptedKey( const AttributeList& attribs ) throw (SAXException, RuntimeException); 425506fa58bSDamjan Jovanovic 426506fa58bSDamjan Jovanovic vector< sal_Int32 > stack; 427506fa58bSDamjan Jovanovic OUString lastError; 428506fa58bSDamjan Jovanovic AgileKeyData &keyData; 429506fa58bSDamjan Jovanovic AgileDataIntegrity &dataIntegrity; 430506fa58bSDamjan Jovanovic AgilePasswordKeyEncryptor &passwordKeyEncryptor; 431506fa58bSDamjan Jovanovic }; 432506fa58bSDamjan Jovanovic 433506fa58bSDamjan Jovanovic void AgileEncryptionHandler::startDocument() 434506fa58bSDamjan Jovanovic throw ( SAXException, RuntimeException ) 435506fa58bSDamjan Jovanovic { 436506fa58bSDamjan Jovanovic } 437506fa58bSDamjan Jovanovic 438506fa58bSDamjan Jovanovic void AgileEncryptionHandler::endDocument() 439506fa58bSDamjan Jovanovic throw ( SAXException, RuntimeException ) 440506fa58bSDamjan Jovanovic { 441506fa58bSDamjan Jovanovic } 442506fa58bSDamjan Jovanovic 443506fa58bSDamjan Jovanovic void AgileEncryptionHandler::setDocumentLocator( const Reference< XLocator >& ) 444506fa58bSDamjan Jovanovic throw ( SAXException, RuntimeException ) 445506fa58bSDamjan Jovanovic { 446506fa58bSDamjan Jovanovic } 447506fa58bSDamjan Jovanovic 448506fa58bSDamjan Jovanovic void AgileEncryptionHandler::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& attribs ) 449506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 450506fa58bSDamjan Jovanovic { 451506fa58bSDamjan Jovanovic switch ( nElement ) 452506fa58bSDamjan Jovanovic { 453506fa58bSDamjan Jovanovic case ENCRYPTION_TOKEN( encryption ): 454506fa58bSDamjan Jovanovic break; 455506fa58bSDamjan Jovanovic 456506fa58bSDamjan Jovanovic case ENCRYPTION_TOKEN( keyData ): 457506fa58bSDamjan Jovanovic if ( stack.size() == 1 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) ) 458506fa58bSDamjan Jovanovic parseKeyData( AttributeList( attribs ) ); 459506fa58bSDamjan Jovanovic break; 460506fa58bSDamjan Jovanovic 461506fa58bSDamjan Jovanovic case ENCRYPTION_TOKEN( dataIntegrity ): 462506fa58bSDamjan Jovanovic if ( stack.size() == 1 && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) ) 463506fa58bSDamjan Jovanovic parseDataIntegrity( AttributeList ( attribs ) ); 464506fa58bSDamjan Jovanovic break; 465506fa58bSDamjan Jovanovic 466506fa58bSDamjan Jovanovic case ENCRYPTION_TOKEN( keyEncryptors ): 467506fa58bSDamjan Jovanovic break; 468506fa58bSDamjan Jovanovic 469506fa58bSDamjan Jovanovic case ENCRYPTION_TOKEN( keyEncryptor ): 470506fa58bSDamjan Jovanovic break; 471506fa58bSDamjan Jovanovic 472506fa58bSDamjan Jovanovic case KEY_ENCRYPTOR_PASSWORD_TOKEN( encryptedKey ): 473506fa58bSDamjan Jovanovic if ( stack.size() == 3 474506fa58bSDamjan Jovanovic && (stack[ 0 ] == ENCRYPTION_TOKEN( encryption )) 475506fa58bSDamjan Jovanovic && (stack[ 1 ] == ENCRYPTION_TOKEN( keyEncryptors )) 476506fa58bSDamjan Jovanovic && (stack[ 2 ] == ENCRYPTION_TOKEN( keyEncryptor )) ) 477506fa58bSDamjan Jovanovic parseEncryptedKey( AttributeList ( attribs ) ); 478506fa58bSDamjan Jovanovic break; 479506fa58bSDamjan Jovanovic } 480506fa58bSDamjan Jovanovic stack.push_back( nElement ); 481506fa58bSDamjan Jovanovic } 482506fa58bSDamjan Jovanovic 483506fa58bSDamjan Jovanovic void AgileEncryptionHandler::startUnknownElement( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) 484506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 485506fa58bSDamjan Jovanovic { 486506fa58bSDamjan Jovanovic stack.push_back( -1 ); 487506fa58bSDamjan Jovanovic } 488506fa58bSDamjan Jovanovic 489506fa58bSDamjan Jovanovic void AgileEncryptionHandler::endFastElement( sal_Int32 nElement ) 490506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 491506fa58bSDamjan Jovanovic { 492506fa58bSDamjan Jovanovic stack.pop_back(); 493506fa58bSDamjan Jovanovic } 494506fa58bSDamjan Jovanovic 495506fa58bSDamjan Jovanovic void AgileEncryptionHandler::endUnknownElement( const OUString&, const OUString& ) 496506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 497506fa58bSDamjan Jovanovic { 498506fa58bSDamjan Jovanovic stack.pop_back(); 499506fa58bSDamjan Jovanovic } 500506fa58bSDamjan Jovanovic 501506fa58bSDamjan Jovanovic Reference< XFastContextHandler > AgileEncryptionHandler::createFastChildContext( sal_Int32, const Reference< XFastAttributeList >& ) 502506fa58bSDamjan Jovanovic throw (SAXException, RuntimeException) 503506fa58bSDamjan Jovanovic { 504506fa58bSDamjan Jovanovic return this; 505506fa58bSDamjan Jovanovic } 506506fa58bSDamjan Jovanovic 507506fa58bSDamjan Jovanovic Reference< XFastContextHandler > AgileEncryptionHandler::createUnknownChildContext( const OUString&, const OUString&, const Reference< XFastAttributeList >& ) 508506fa58bSDamjan Jovanovic throw (SAXException, RuntimeException) 509506fa58bSDamjan Jovanovic { 510506fa58bSDamjan Jovanovic return this; 511506fa58bSDamjan Jovanovic } 512506fa58bSDamjan Jovanovic 513506fa58bSDamjan Jovanovic void AgileEncryptionHandler::characters( const ::rtl::OUString& rStr ) 514506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 515506fa58bSDamjan Jovanovic { 516506fa58bSDamjan Jovanovic } 517506fa58bSDamjan Jovanovic 518506fa58bSDamjan Jovanovic void AgileEncryptionHandler::ignorableWhitespace( const ::rtl::OUString& str ) 519506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 520506fa58bSDamjan Jovanovic { 521506fa58bSDamjan Jovanovic } 522506fa58bSDamjan Jovanovic 523506fa58bSDamjan Jovanovic void AgileEncryptionHandler::processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) 524506fa58bSDamjan Jovanovic throw( SAXException, RuntimeException ) 525506fa58bSDamjan Jovanovic { 526506fa58bSDamjan Jovanovic } 527506fa58bSDamjan Jovanovic 528506fa58bSDamjan Jovanovic void AgileEncryptionHandler::parseKeyData( const AttributeList& attribs ) 529506fa58bSDamjan Jovanovic throw ( SAXException, RuntimeException ) 530506fa58bSDamjan Jovanovic { 531506fa58bSDamjan Jovanovic keyData.saltSize = attribs.getInteger( XML_saltSize, 0 ); 532506fa58bSDamjan Jovanovic keyData.blockSize = attribs.getInteger( XML_blockSize, 0 ); 533506fa58bSDamjan Jovanovic keyData.keyBits = attribs.getInteger( XML_keyBits, 0 ); 534506fa58bSDamjan Jovanovic keyData.hashSize = attribs.getInteger( XML_hashSize, 0 ); 535506fa58bSDamjan Jovanovic keyData.cipherAlgorithm = attribs.getString( XML_cipherAlgorithm, OUString() ); 536506fa58bSDamjan Jovanovic keyData.cipherChaining = attribs.getString( XML_cipherChaining, OUString() ); 537506fa58bSDamjan Jovanovic keyData.hashAlgorithm = attribs.getString( XML_hashAlgorithm, OUString() ); 538506fa58bSDamjan Jovanovic 539506fa58bSDamjan Jovanovic OUString saltValue = attribs.getString( XML_saltValue, OUString() ); 540506fa58bSDamjan Jovanovic if( !decodeBase64( saltValue, keyData.saltValue ) ) 541506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the keyData.saltValue " ) + saltValue; 542506fa58bSDamjan Jovanovic } 543506fa58bSDamjan Jovanovic 544506fa58bSDamjan Jovanovic void AgileEncryptionHandler::parseDataIntegrity( const AttributeList& attribs ) 545506fa58bSDamjan Jovanovic throw ( SAXException, RuntimeException ) 546506fa58bSDamjan Jovanovic { 547506fa58bSDamjan Jovanovic OUString encryptedHmacKey = attribs.getString( XML_encryptedHmacKey, OUString() ); 548506fa58bSDamjan Jovanovic if( !decodeBase64( encryptedHmacKey, dataIntegrity.encryptedHmacKey ) ) 549506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the dataIntegrity.encryptedHmacKey " ) + encryptedHmacKey; 550506fa58bSDamjan Jovanovic OUString encryptedHmacValue = attribs.getString( XML_encryptedHmacValue, OUString() ); 551506fa58bSDamjan Jovanovic if( !decodeBase64( encryptedHmacValue, dataIntegrity.encryptedHmacValue ) ) 552506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the dataIntegrity.encryptedHmacValue " ) + encryptedHmacValue; 553506fa58bSDamjan Jovanovic } 554506fa58bSDamjan Jovanovic 555506fa58bSDamjan Jovanovic void AgileEncryptionHandler::parseEncryptedKey( const AttributeList& attribs ) 556506fa58bSDamjan Jovanovic throw ( SAXException, RuntimeException ) 557506fa58bSDamjan Jovanovic { 558506fa58bSDamjan Jovanovic passwordKeyEncryptor.spinCount = attribs.getInteger( XML_spinCount, 0 ); 559506fa58bSDamjan Jovanovic passwordKeyEncryptor.saltSize = attribs.getInteger( XML_saltSize, 0 ); 560506fa58bSDamjan Jovanovic passwordKeyEncryptor.blockSize = attribs.getInteger( XML_blockSize, 0 ); 561506fa58bSDamjan Jovanovic passwordKeyEncryptor.keyBits = attribs.getInteger( XML_keyBits, 0 ); 562506fa58bSDamjan Jovanovic passwordKeyEncryptor.hashSize = attribs.getInteger( XML_hashSize, 0 ); 563506fa58bSDamjan Jovanovic passwordKeyEncryptor.cipherAlgorithm = attribs.getString( XML_cipherAlgorithm, OUString() ); 564506fa58bSDamjan Jovanovic passwordKeyEncryptor.cipherChaining = attribs.getString( XML_cipherChaining, OUString() ); 565506fa58bSDamjan Jovanovic passwordKeyEncryptor.hashAlgorithm = attribs.getString( XML_hashAlgorithm, OUString() ); 566506fa58bSDamjan Jovanovic OUString saltValue = attribs.getString( XML_saltValue, OUString() ); 567506fa58bSDamjan Jovanovic if( !decodeBase64( saltValue, passwordKeyEncryptor.saltValue ) ) 568506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.saltValue " ) + saltValue; 569506fa58bSDamjan Jovanovic OUString encryptedVerifierHashInput = attribs.getString( XML_encryptedVerifierHashInput, OUString() ); 570506fa58bSDamjan Jovanovic if( !decodeBase64( encryptedVerifierHashInput, passwordKeyEncryptor.encryptedVerifierHashInput ) ) 571506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedVerifierHashInput " ) + encryptedVerifierHashInput; 572506fa58bSDamjan Jovanovic OUString encryptedVerifierHashValue = attribs.getString( XML_encryptedVerifierHashValue, OUString() ); 573506fa58bSDamjan Jovanovic if( !decodeBase64( encryptedVerifierHashValue, passwordKeyEncryptor.encryptedVerifierHashValue ) ) 574506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedVerifierHashValue " ) + encryptedVerifierHashValue; 575506fa58bSDamjan Jovanovic OUString encryptedKeyValue = attribs.getString( XML_encryptedKeyValue, OUString() ); 576506fa58bSDamjan Jovanovic if( !decodeBase64( encryptedKeyValue, passwordKeyEncryptor.encryptedKeyValue ) ) 577506fa58bSDamjan Jovanovic lastError = OUString::createFromAscii( "Failed to base64 decode the passwordKeyEncryptor.encryptedKeyValue " ) + encryptedKeyValue; 578506fa58bSDamjan Jovanovic } 579506fa58bSDamjan Jovanovic 580506fa58bSDamjan Jovanovic static sal_uInt16 readUInt16LE( Reference< XInputStream >& inputStream ) throw ( Exception ) 581506fa58bSDamjan Jovanovic { 582506fa58bSDamjan Jovanovic Sequence< sal_Int8 > bytes( 2 ); 583506fa58bSDamjan Jovanovic sal_Int32 bytesRead = inputStream->readBytes( bytes, 2 ); 584506fa58bSDamjan Jovanovic if( bytesRead < 2 ) 585506fa58bSDamjan Jovanovic throw new Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() failed, early end of file" ), Reference< XInterface >() ); 586506fa58bSDamjan Jovanovic return (sal_uInt16) ( bytes[0] | (bytes[1] << 8) ); 587506fa58bSDamjan Jovanovic } 588506fa58bSDamjan Jovanovic 589506fa58bSDamjan Jovanovic static sal_uInt32 readUInt32LE( Reference< XInputStream >& inputStream ) throw ( Exception ) 590506fa58bSDamjan Jovanovic { 591506fa58bSDamjan Jovanovic Sequence< sal_Int8 > bytes( 4 ); 592506fa58bSDamjan Jovanovic sal_Int32 bytesRead = inputStream->readBytes( bytes, 4 ); 593506fa58bSDamjan Jovanovic if( bytesRead < 4 ) 594506fa58bSDamjan Jovanovic throw new Exception( OUString::createFromAscii( "EncryptionInfo::readEncryptionInfo() failed, early end of file" ), Reference< XInterface >() ); 595506fa58bSDamjan Jovanovic return (sal_uInt32) ( bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24) ); 596506fa58bSDamjan Jovanovic } 597506fa58bSDamjan Jovanovic 598506fa58bSDamjan Jovanovic AgileEncryptionInfo::AgileEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) throw ( Exception ) 599506fa58bSDamjan Jovanovic { 600506fa58bSDamjan Jovanovic sal_uInt32 nReserved = readUInt32LE( inputStream ); 601506fa58bSDamjan Jovanovic if( nReserved != 0x40 ) 602506fa58bSDamjan Jovanovic throw new Exception( OUString::createFromAscii( "reserved field isn't 0x40" ), Reference< XInterface >() ); 603506fa58bSDamjan Jovanovic AgileEncryptionHandler *agileEncryptionHandler = new AgileEncryptionHandler( keyData, dataIntegrity, passwordKeyEncryptor ); 604506fa58bSDamjan Jovanovic Reference< XFastDocumentHandler > documentHandler( agileEncryptionHandler ); 605506fa58bSDamjan Jovanovic FastParser fastParser( context ); 606506fa58bSDamjan Jovanovic fastParser.registerNamespace( NMSP_encryption ); 607506fa58bSDamjan Jovanovic fastParser.registerNamespace( NMSP_keyEncryptorPassword ); 608506fa58bSDamjan Jovanovic fastParser.setDocumentHandler( documentHandler ); 609506fa58bSDamjan Jovanovic fastParser.parseStream( inputStream, OUString::createFromAscii( "EncryptionInfo" ), false ); 610506fa58bSDamjan Jovanovic if( !agileEncryptionHandler->getLastError().isEmpty() ) 611506fa58bSDamjan Jovanovic throw new Exception( agileEncryptionHandler->getLastError(), Reference< XInterface >() ); 612506fa58bSDamjan Jovanovic } 613506fa58bSDamjan Jovanovic 614506fa58bSDamjan Jovanovic static const EVP_MD* toOpenSSLDigestAlgorithm( const OUString& hashAlgorithm ) throw ( Exception ) 615506fa58bSDamjan Jovanovic { 616506fa58bSDamjan Jovanovic if( hashAlgorithm.equalsAscii( "SHA-1" ) ) 617506fa58bSDamjan Jovanovic return EVP_sha1(); 618506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA1" ) ) // Typical Microsoft. The specification says "SHA-1", but documents use "SHA1". 619506fa58bSDamjan Jovanovic return EVP_sha1(); 620506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA256" ) ) 621506fa58bSDamjan Jovanovic return EVP_sha256(); 622506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA384" ) ) 623506fa58bSDamjan Jovanovic return EVP_sha384(); 624506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "SHA512" ) ) 625506fa58bSDamjan Jovanovic return EVP_sha512(); 626506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "MD5" ) ) 627506fa58bSDamjan Jovanovic return EVP_md5(); 628506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "MD4" ) ) 629506fa58bSDamjan Jovanovic return EVP_md4(); 630506fa58bSDamjan Jovanovic #if !defined(OPENSSL_NO_MD2) 631506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "MD2" ) ) 632506fa58bSDamjan Jovanovic return EVP_md2(); 633506fa58bSDamjan Jovanovic #endif 634506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "RIPEMD-160" ) ) 635506fa58bSDamjan Jovanovic return EVP_ripemd160(); 636506fa58bSDamjan Jovanovic else if( hashAlgorithm.equalsAscii( "WHIRLPOOL" ) ) 637506fa58bSDamjan Jovanovic return EVP_whirlpool(); 638506fa58bSDamjan Jovanovic char buffer[ 256 ]; 639506fa58bSDamjan Jovanovic ::rtl::OString str = ::rtl::OUStringToOString( hashAlgorithm, RTL_TEXTENCODING_UTF8 ); 640506fa58bSDamjan Jovanovic snprintf( buffer, sizeof( buffer ), "Unsupported digest algorithm %s", str.getStr() ); 641506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( buffer ), Reference< XInterface >() ); 642506fa58bSDamjan Jovanovic } 643506fa58bSDamjan Jovanovic 644506fa58bSDamjan Jovanovic static const EVP_CIPHER* toOpenSSLCipherAlgorithm( const OUString& cipherName, sal_uInt32 keyBits, const OUString &chainingMode ) throw ( Exception ) 645506fa58bSDamjan Jovanovic { 646506fa58bSDamjan Jovanovic if( cipherName.equalsAscii( "AES" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 647506fa58bSDamjan Jovanovic return EVP_aes_128_cbc(); 648506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 649506fa58bSDamjan Jovanovic return EVP_aes_128_cfb(); 650506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 192 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 651506fa58bSDamjan Jovanovic return EVP_aes_192_cbc(); 652506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 192 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 653506fa58bSDamjan Jovanovic return EVP_aes_192_cfb(); 654506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 256 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 655506fa58bSDamjan Jovanovic return EVP_aes_256_cbc(); 656506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "AES" ) && keyBits == 256 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 657506fa58bSDamjan Jovanovic return EVP_aes_256_cfb(); 658506fa58bSDamjan Jovanovic #if !defined(OPENSSL_NO_RC2) 659506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "RC2" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 660506fa58bSDamjan Jovanovic return EVP_rc2_cbc(); 661506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "RC2" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 662506fa58bSDamjan Jovanovic return EVP_rc2_cfb(); 663506fa58bSDamjan Jovanovic #endif 664506fa58bSDamjan Jovanovic #if !defined(OPENSSL_NO_DES) 665506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "DES" ) && keyBits == 56 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 666506fa58bSDamjan Jovanovic return EVP_des_cbc(); 667506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "DES" ) && keyBits == 56 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 668506fa58bSDamjan Jovanovic return EVP_des_cfb(); 669506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "DESX" ) && keyBits == 128 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 670506fa58bSDamjan Jovanovic return EVP_desx_cbc(); 671506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "3DES" ) && keyBits == 168 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 672506fa58bSDamjan Jovanovic return EVP_des_ede3_cbc(); 673506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "3DES" ) && keyBits == 168 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 674506fa58bSDamjan Jovanovic return EVP_des_ede3_cfb(); 675506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "3DES_112" ) && keyBits == 112 && chainingMode.equalsAscii( "ChainingModeCBC" ) ) 676506fa58bSDamjan Jovanovic return EVP_des_ede_cbc(); 677506fa58bSDamjan Jovanovic else if( cipherName.equalsAscii( "3DES_112" ) && keyBits == 112 && chainingMode.equalsAscii( "ChainingModeCFB" ) ) 678506fa58bSDamjan Jovanovic return EVP_des_ede_cfb(); 679506fa58bSDamjan Jovanovic #endif 680506fa58bSDamjan Jovanovic char buffer[ 256 ]; 681506fa58bSDamjan Jovanovic ::rtl::OString cipherNameUtf8 = ::rtl::OUStringToOString( cipherName, RTL_TEXTENCODING_UTF8 ); 682506fa58bSDamjan Jovanovic ::rtl::OString chainingModeUtf8 = ::rtl::OUStringToOString( chainingMode, RTL_TEXTENCODING_UTF8 ); 683506fa58bSDamjan Jovanovic snprintf( buffer, sizeof( buffer ), "Unsupported cipher with name=%s, keyBits=%u, chainingMode=%s", cipherNameUtf8.getStr(), keyBits, chainingModeUtf8.getStr() ); 684506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( buffer ), Reference< XInterface >() ); 685506fa58bSDamjan Jovanovic } 686506fa58bSDamjan Jovanovic 687506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.hashPassword(). 688506fa58bSDamjan Jovanovic static vector< sal_uInt8 > hashPassword( const OUString& password, const EVP_MD *digestAlgorithm, vector< sal_uInt8 >& salt, sal_uInt32 spinCount ) throw ( Exception ) 689506fa58bSDamjan Jovanovic { 690506fa58bSDamjan Jovanovic OpenSSLDigest digest; 691506fa58bSDamjan Jovanovic digest.initialize( digestAlgorithm ); 692506fa58bSDamjan Jovanovic size_t digestSize = digest.digestSize(); 693506fa58bSDamjan Jovanovic 694506fa58bSDamjan Jovanovic // Convert to little-endian UTF-16 695506fa58bSDamjan Jovanovic vector< sal_uInt8 > passwordLE( 2 * password.getLength() ); 696506fa58bSDamjan Jovanovic for ( int i = 0; i < password.getLength(); i++ ) 697506fa58bSDamjan Jovanovic ByteOrderConverter::writeLittleEndian( &passwordLE[ 2 * i ], static_cast< sal_uInt16 >( password[ i ] ) ); 698506fa58bSDamjan Jovanovic 699506fa58bSDamjan Jovanovic vector< sal_uInt8> digestBuffer( digestSize ); 700f65b4e32SDamjan Jovanovic digest.update( &salt[ 0 ], salt.size() ); 701f65b4e32SDamjan Jovanovic digest.update( &passwordLE[ 0 ], passwordLE.size() ); 702f65b4e32SDamjan Jovanovic digest.final( &digestBuffer[ 0 ], NULL ); 703506fa58bSDamjan Jovanovic 704506fa58bSDamjan Jovanovic char iteratorBuffer[ 4 ]; 705506fa58bSDamjan Jovanovic for (sal_uInt32 i = 0; i < spinCount; i++) 706506fa58bSDamjan Jovanovic { 707506fa58bSDamjan Jovanovic digest.initialize( digestAlgorithm ); 708506fa58bSDamjan Jovanovic ByteOrderConverter::writeLittleEndian( &iteratorBuffer, i ); 709506fa58bSDamjan Jovanovic digest.update( iteratorBuffer, sizeof( iteratorBuffer ) ); 710f65b4e32SDamjan Jovanovic digest.update( &digestBuffer[ 0 ], digestSize ); 711f65b4e32SDamjan Jovanovic digest.final( &digestBuffer[ 0 ], NULL ); 712506fa58bSDamjan Jovanovic } 713506fa58bSDamjan Jovanovic return digestBuffer; 714506fa58bSDamjan Jovanovic } 715506fa58bSDamjan Jovanovic 716506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.getBlock36(). 717506fa58bSDamjan Jovanovic static void toBlock36( vector< sal_uInt8 >& digest, sal_uInt32 size ) 718506fa58bSDamjan Jovanovic { 719506fa58bSDamjan Jovanovic if( digest.size() < size ) 720506fa58bSDamjan Jovanovic { 721506fa58bSDamjan Jovanovic sal_uInt32 i = digest.size(); 722506fa58bSDamjan Jovanovic digest.resize( size ); 723506fa58bSDamjan Jovanovic for (; i < size; i++) 724506fa58bSDamjan Jovanovic digest[ i ] = 0x36; 725506fa58bSDamjan Jovanovic } 726506fa58bSDamjan Jovanovic else 727506fa58bSDamjan Jovanovic digest.resize( size ); 728506fa58bSDamjan Jovanovic } 729506fa58bSDamjan Jovanovic 730506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.getBlock0(). 731506fa58bSDamjan Jovanovic static void toBlock0( vector< sal_uInt8 >& digest, sal_uInt32 size ) 732506fa58bSDamjan Jovanovic { 733506fa58bSDamjan Jovanovic if( digest.size() < size ) 734506fa58bSDamjan Jovanovic { 735506fa58bSDamjan Jovanovic sal_uInt32 i = digest.size(); 736506fa58bSDamjan Jovanovic digest.resize( size ); 737506fa58bSDamjan Jovanovic for (; i < size; i++) 738506fa58bSDamjan Jovanovic digest[ i ] = 0; 739506fa58bSDamjan Jovanovic } 740506fa58bSDamjan Jovanovic else 741506fa58bSDamjan Jovanovic digest.resize( size ); 742506fa58bSDamjan Jovanovic } 743506fa58bSDamjan Jovanovic 744506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateKey(). 745506fa58bSDamjan Jovanovic static vector< sal_uInt8 > generateKey( const vector< sal_uInt8 >& passwordHash, 746506fa58bSDamjan Jovanovic const EVP_MD *digestAlgorithm, 747506fa58bSDamjan Jovanovic const vector< sal_uInt8 >& blockKey, 748506fa58bSDamjan Jovanovic sal_uInt32 keySize ) 749506fa58bSDamjan Jovanovic throw ( Exception ) 750506fa58bSDamjan Jovanovic { 751506fa58bSDamjan Jovanovic OpenSSLDigest digest; 752506fa58bSDamjan Jovanovic digest.initialize( digestAlgorithm ); 753f65b4e32SDamjan Jovanovic digest.update( &passwordHash[ 0 ], passwordHash.size() ); 754f65b4e32SDamjan Jovanovic digest.update( &blockKey[ 0 ], blockKey.size() ); 755506fa58bSDamjan Jovanovic vector< sal_uInt8> key( digest.digestSize() ); 756f65b4e32SDamjan Jovanovic digest.final( &key[ 0 ], NULL ); 757506fa58bSDamjan Jovanovic toBlock36( key, keySize ); 758506fa58bSDamjan Jovanovic return key; 759506fa58bSDamjan Jovanovic } 760506fa58bSDamjan Jovanovic 761506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateIv(). 762506fa58bSDamjan Jovanovic static vector< sal_uInt8> generateIv( const vector< sal_uInt8 >& salt, 763506fa58bSDamjan Jovanovic sal_uInt32 blockSize ) 764506fa58bSDamjan Jovanovic throw ( Exception ) 765506fa58bSDamjan Jovanovic { 766506fa58bSDamjan Jovanovic vector< sal_uInt8> iv( salt ); 767506fa58bSDamjan Jovanovic toBlock36( iv, blockSize ); 768506fa58bSDamjan Jovanovic return iv; 769506fa58bSDamjan Jovanovic } 770506fa58bSDamjan Jovanovic 771506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.CryptoFunctions.generateIv(). 772506fa58bSDamjan Jovanovic static vector< sal_uInt8> generateIv( const EVP_MD *digestAlgorithm, 773506fa58bSDamjan Jovanovic const vector< sal_uInt8 >& salt, 774506fa58bSDamjan Jovanovic const vector< sal_uInt8 >& blockKey, 775506fa58bSDamjan Jovanovic sal_uInt32 blockSize ) 776506fa58bSDamjan Jovanovic throw ( Exception ) 777506fa58bSDamjan Jovanovic { 778506fa58bSDamjan Jovanovic OpenSSLDigest digest; 779506fa58bSDamjan Jovanovic digest.initialize( digestAlgorithm ); 780f65b4e32SDamjan Jovanovic digest.update( &salt[ 0 ], salt.size() ); 781f65b4e32SDamjan Jovanovic digest.update( &blockKey[ 0 ], blockKey.size() ); 782506fa58bSDamjan Jovanovic vector< sal_uInt8> iv( digest.digestSize() ); 783f65b4e32SDamjan Jovanovic digest.final( &iv[ 0 ], NULL ); 784506fa58bSDamjan Jovanovic toBlock36( iv, blockSize ); 785506fa58bSDamjan Jovanovic return iv; 786506fa58bSDamjan Jovanovic } 787506fa58bSDamjan Jovanovic 788506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.getNextBlockSize(). 789506fa58bSDamjan Jovanovic static sal_uInt32 getNextBlockSize( sal_uInt32 totalSize, sal_uInt32 blockSize ) 790506fa58bSDamjan Jovanovic { 791506fa58bSDamjan Jovanovic sal_uInt32 numberOfBlocks = ( totalSize + ( blockSize - 1 ) ) / blockSize; 792506fa58bSDamjan Jovanovic return numberOfBlocks * blockSize; 793506fa58bSDamjan Jovanovic } 794506fa58bSDamjan Jovanovic 795506fa58bSDamjan Jovanovic static vector< sal_uInt8 > decryptAll( const EVP_CIPHER* cipherAlgorithm, 796506fa58bSDamjan Jovanovic const sal_uInt8* iv, 797506fa58bSDamjan Jovanovic const sal_uInt8* key, 798506fa58bSDamjan Jovanovic const sal_uInt8* encryptedData, 799506fa58bSDamjan Jovanovic sal_uInt32 encryptedDataLength ) 800506fa58bSDamjan Jovanovic throw ( Exception ) 801506fa58bSDamjan Jovanovic { 802506fa58bSDamjan Jovanovic OpenSSLCipher cipher; 803506fa58bSDamjan Jovanovic cipher.initialize( cipherAlgorithm, key, iv, 0 ); 804506fa58bSDamjan Jovanovic cipher.setPadding( 0 ); 805506fa58bSDamjan Jovanovic const int blockSize = cipher.blockSize(); 806506fa58bSDamjan Jovanovic vector< sal_uInt8 > decryptedData( encryptedDataLength + 2*blockSize ); 807506fa58bSDamjan Jovanovic 808506fa58bSDamjan Jovanovic int decryptedDataLength; 809f65b4e32SDamjan Jovanovic cipher.update( encryptedData, encryptedDataLength, &decryptedData[ 0 ], &decryptedDataLength ); 810506fa58bSDamjan Jovanovic int finalDataLength; 811506fa58bSDamjan Jovanovic cipher.final( &decryptedData[ decryptedDataLength ], &finalDataLength ); 812506fa58bSDamjan Jovanovic decryptedDataLength += finalDataLength; 813506fa58bSDamjan Jovanovic decryptedData.resize( decryptedDataLength ); 814506fa58bSDamjan Jovanovic return decryptedData; 815506fa58bSDamjan Jovanovic } 816506fa58bSDamjan Jovanovic 817506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.hashInput(). 818506fa58bSDamjan Jovanovic static vector< sal_uInt8 > hashInput( const vector< sal_uInt8 >& passwordHash, 819506fa58bSDamjan Jovanovic const vector< sal_uInt8 >& salt, 820506fa58bSDamjan Jovanovic const EVP_MD *digestAlgorithm, 821506fa58bSDamjan Jovanovic const vector< sal_uInt8 >& blockKey, 822506fa58bSDamjan Jovanovic const vector< sal_uInt8 >& inputKey, 823506fa58bSDamjan Jovanovic const EVP_CIPHER *decryptionAlgorithm, 824506fa58bSDamjan Jovanovic sal_uInt32 keySize, 825506fa58bSDamjan Jovanovic sal_uInt32 blockSize ) 826506fa58bSDamjan Jovanovic throw ( Exception ) 827506fa58bSDamjan Jovanovic { 828506fa58bSDamjan Jovanovic vector< sal_uInt8 > intermediateKey = generateKey( passwordHash, digestAlgorithm, blockKey, keySize ); 829506fa58bSDamjan Jovanovic vector< sal_uInt8> iv = generateIv( salt, blockSize ); 830506fa58bSDamjan Jovanovic vector< sal_uInt8 > zeroedInput( inputKey.size() ); 831506fa58bSDamjan Jovanovic zeroedInput = inputKey; 832506fa58bSDamjan Jovanovic toBlock0( zeroedInput, getNextBlockSize( zeroedInput.size(), blockSize ) ); 833f65b4e32SDamjan Jovanovic return decryptAll( decryptionAlgorithm, &iv[ 0 ], &intermediateKey[ 0 ], &zeroedInput[ 0 ], zeroedInput.size() ); 834506fa58bSDamjan Jovanovic } 835506fa58bSDamjan Jovanovic 836506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.verifyPassword(). 837506fa58bSDamjan Jovanovic Sequence< NamedValue > AgileEncryptionInfo::verifyPassword( const OUString& password ) 838506fa58bSDamjan Jovanovic throw ( Exception ) 839506fa58bSDamjan Jovanovic { 840506fa58bSDamjan Jovanovic const EVP_MD *digestAlgorithm = toOpenSSLDigestAlgorithm( passwordKeyEncryptor.hashAlgorithm ); 841506fa58bSDamjan Jovanovic vector< sal_uInt8 > passwordHash = hashPassword( password, digestAlgorithm, passwordKeyEncryptor.saltValue, passwordKeyEncryptor.spinCount ); 842506fa58bSDamjan Jovanovic 843506fa58bSDamjan Jovanovic static const sal_uInt8 verifierInputBlockData[] = { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 }; 844506fa58bSDamjan Jovanovic vector< sal_uInt8 > verifierInputBlock( &verifierInputBlockData[ 0 ], &verifierInputBlockData[ sizeof( verifierInputBlockData ) ] ); 845506fa58bSDamjan Jovanovic const EVP_CIPHER* cipher = toOpenSSLCipherAlgorithm( passwordKeyEncryptor.cipherAlgorithm, passwordKeyEncryptor.keyBits, passwordKeyEncryptor.cipherChaining ); 846506fa58bSDamjan Jovanovic vector< sal_uInt8 > encryptedVerifierHash = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, verifierInputBlock, 847506fa58bSDamjan Jovanovic passwordKeyEncryptor.encryptedVerifierHashInput, cipher, passwordKeyEncryptor.keyBits, 848506fa58bSDamjan Jovanovic passwordKeyEncryptor.blockSize ); 849506fa58bSDamjan Jovanovic const EVP_MD *verifierDigestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm ); 850506fa58bSDamjan Jovanovic OpenSSLDigest verifierDigest; 851506fa58bSDamjan Jovanovic verifierDigest.initialize( verifierDigestAlgorithm ); 852f65b4e32SDamjan Jovanovic verifierDigest.update( &encryptedVerifierHash[ 0 ], encryptedVerifierHash.size() ); 853506fa58bSDamjan Jovanovic encryptedVerifierHash.resize( verifierDigest.digestSize() ); 854f65b4e32SDamjan Jovanovic verifierDigest.final( &encryptedVerifierHash[ 0 ], NULL ); 855506fa58bSDamjan Jovanovic 856506fa58bSDamjan Jovanovic static const sal_uInt8 verifierHashBlockData[] = { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e }; 857506fa58bSDamjan Jovanovic vector< sal_uInt8 > verifierHashBlock( &verifierHashBlockData[ 0 ], &verifierHashBlockData[ sizeof( verifierHashBlockData ) ] ); 858506fa58bSDamjan Jovanovic vector< sal_uInt8 > verifierHashDec = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, verifierHashBlock, 859506fa58bSDamjan Jovanovic passwordKeyEncryptor.encryptedVerifierHashValue, cipher, passwordKeyEncryptor.keyBits, 860506fa58bSDamjan Jovanovic passwordKeyEncryptor.blockSize ); 861506fa58bSDamjan Jovanovic toBlock0( verifierHashDec, verifierDigest.digestSize() ); 862506fa58bSDamjan Jovanovic 863506fa58bSDamjan Jovanovic if( encryptedVerifierHash != verifierHashDec ) 864506fa58bSDamjan Jovanovic return Sequence< NamedValue >(); 865506fa58bSDamjan Jovanovic 866506fa58bSDamjan Jovanovic // Password is correct. Decrypt and store the encryption key. 867506fa58bSDamjan Jovanovic static const sal_uInt8 cryptoKeyBlockData[] = { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 }; 868506fa58bSDamjan Jovanovic vector< sal_uInt8 > cryptoKeyBlock( &cryptoKeyBlockData[ 0 ], &cryptoKeyBlockData[ sizeof( cryptoKeyBlockData ) ] ); 869506fa58bSDamjan Jovanovic encryptionKey = hashInput( passwordHash, passwordKeyEncryptor.saltValue, digestAlgorithm, cryptoKeyBlock, 870506fa58bSDamjan Jovanovic passwordKeyEncryptor.encryptedKeyValue, cipher, passwordKeyEncryptor.keyBits, 871506fa58bSDamjan Jovanovic passwordKeyEncryptor.blockSize ); 872506fa58bSDamjan Jovanovic toBlock0( encryptionKey, passwordKeyEncryptor.keyBits / 8 ); 873506fa58bSDamjan Jovanovic 874506fa58bSDamjan Jovanovic // Also decrypt the dataIntegrity fields for stream validation. Note that they are optional. 875506fa58bSDamjan Jovanovic if( !dataIntegrity.encryptedHmacKey.empty() && !dataIntegrity.encryptedHmacValue.empty() ) 876506fa58bSDamjan Jovanovic { 877506fa58bSDamjan Jovanovic const EVP_MD* keyDataDigestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm ); 878506fa58bSDamjan Jovanovic const EVP_CIPHER* keyDataCipher = toOpenSSLCipherAlgorithm( keyData.cipherAlgorithm, keyData.keyBits, keyData.cipherChaining ); 879506fa58bSDamjan Jovanovic static const sal_uInt8 integrityKeyBlockData[] = { 0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, 0xf6 }; 880506fa58bSDamjan Jovanovic vector< sal_uInt8 > integrityKeyBlock( &integrityKeyBlockData[ 0 ], &integrityKeyBlockData[ sizeof( integrityKeyBlockData ) ] ); 881506fa58bSDamjan Jovanovic vector< sal_uInt8 > integrityKeyIv = generateIv( keyDataDigestAlgorithm, keyData.saltValue, integrityKeyBlock, keyData.blockSize ); 882f65b4e32SDamjan Jovanovic hmacKey = decryptAll( keyDataCipher, &integrityKeyIv[ 0 ], &encryptionKey[ 0 ], &dataIntegrity.encryptedHmacKey[ 0 ], dataIntegrity.encryptedHmacKey.size() ); 883506fa58bSDamjan Jovanovic toBlock0( hmacKey, OpenSSLDigest::digestSize( keyDataDigestAlgorithm ) ); 884506fa58bSDamjan Jovanovic 885506fa58bSDamjan Jovanovic static const sal_uInt8 integrityValueBlockData[] = { 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, 0x33 }; 886506fa58bSDamjan Jovanovic vector< sal_uInt8 > integrityValueBlock( &integrityValueBlockData[ 0 ], &integrityValueBlockData[ sizeof( integrityValueBlockData ) ] ); 887506fa58bSDamjan Jovanovic vector< sal_uInt8 > integrityValueIv = generateIv( keyDataDigestAlgorithm, keyData.saltValue, integrityValueBlock, keyData.blockSize ); 888f65b4e32SDamjan Jovanovic hmacValue = decryptAll( keyDataCipher, &integrityValueIv[ 0 ], &encryptionKey[ 0 ], &dataIntegrity.encryptedHmacValue[ 0 ], dataIntegrity.encryptedHmacValue.size() ); 889506fa58bSDamjan Jovanovic toBlock0( hmacValue, OpenSSLDigest::digestSize( keyDataDigestAlgorithm ) ); 890506fa58bSDamjan Jovanovic } 891506fa58bSDamjan Jovanovic 892506fa58bSDamjan Jovanovic // On success, MUST populate something into the encryption data, even though we'll never use it. 893506fa58bSDamjan Jovanovic SequenceAsHashMap encryptionData; 894506fa58bSDamjan Jovanovic encryptionData[ CREATE_OUSTRING( "OOXMLAgileEncryptionPasswordVerified" ) ] <<= sal_True; 895506fa58bSDamjan Jovanovic return encryptionData.getAsConstNamedValueList(); 896506fa58bSDamjan Jovanovic } 897506fa58bSDamjan Jovanovic 898506fa58bSDamjan Jovanovic bool AgileEncryptionInfo::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData ) 899506fa58bSDamjan Jovanovic throw ( Exception ) 900506fa58bSDamjan Jovanovic { 901506fa58bSDamjan Jovanovic // OpenGrok shows how only main/comphelper/source/misc/docpasswordhelper.cxx calls IDocPasswordVerifier::verifyEncryptionData(), 902506fa58bSDamjan Jovanovic // and only when the password is wrong and the rMediaEncData non-empty, which presumably allows other forms of encryption 903506fa58bSDamjan Jovanovic // (eg. by certificate) to be used. We only support password for now. 904506fa58bSDamjan Jovanovic return false; 905506fa58bSDamjan Jovanovic } 906506fa58bSDamjan Jovanovic 907506fa58bSDamjan Jovanovic // Ported from Apache POI's org.apache.poi.poifs.crypt.agile.AgileDecryptor.initCipherForBlock(). 908506fa58bSDamjan Jovanovic void AgileEncryptionInfo::decryptStream( BinaryXInputStream &aEncryptedPackage, BinaryXOutputStream &aDecryptedPackage ) 909506fa58bSDamjan Jovanovic throw ( Exception ) 910506fa58bSDamjan Jovanovic { 911506fa58bSDamjan Jovanovic if( encryptionKey.empty() ) 912506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( "Encryption key not set, was the password wrong?" ), Reference< XInterface >() ); 913506fa58bSDamjan Jovanovic const EVP_CIPHER* cipherAlgorithm = toOpenSSLCipherAlgorithm( keyData.cipherAlgorithm, keyData.keyBits, keyData.cipherChaining ); 914506fa58bSDamjan Jovanovic const EVP_MD* digestAlgorithm = toOpenSSLDigestAlgorithm( keyData.hashAlgorithm ); 915506fa58bSDamjan Jovanovic OpenSSLCipher cipher; 916506fa58bSDamjan Jovanovic 917506fa58bSDamjan Jovanovic const sal_uInt64 decryptedSize = aEncryptedPackage.readuInt64(); 918506fa58bSDamjan Jovanovic 919506fa58bSDamjan Jovanovic sal_uInt8 inputBuffer[ 4096 ]; 920506fa58bSDamjan Jovanovic vector< sal_uInt8 > outputBuffer( 4096 + 2*cipher.blockSize() ); 921506fa58bSDamjan Jovanovic sal_Int32 bytesIn; 922506fa58bSDamjan Jovanovic int bytesOut; 923506fa58bSDamjan Jovanovic int finalBytesOut; 924506fa58bSDamjan Jovanovic sal_uInt64 totalBytesWritten = 0; 925506fa58bSDamjan Jovanovic 926506fa58bSDamjan Jovanovic vector< sal_uInt8 > blockBytes( 4 ); 927506fa58bSDamjan Jovanovic bool done = false; 928506fa58bSDamjan Jovanovic for ( sal_uInt32 block = 0; !done; block++ ) 929506fa58bSDamjan Jovanovic { 930f65b4e32SDamjan Jovanovic ByteOrderConverter::writeLittleEndian( &blockBytes[ 0 ], block ); 931506fa58bSDamjan Jovanovic vector< sal_uInt8 > iv = generateIv( digestAlgorithm, keyData.saltValue, blockBytes, keyData.blockSize ); 932f65b4e32SDamjan Jovanovic cipher.initialize( cipherAlgorithm, &encryptionKey[ 0 ], &iv[ 0 ], 0 ); 933506fa58bSDamjan Jovanovic cipher.setPadding( 0 ); 934506fa58bSDamjan Jovanovic 935506fa58bSDamjan Jovanovic bytesIn = aEncryptedPackage.readMemory( inputBuffer, sizeof( inputBuffer ) ); 936506fa58bSDamjan Jovanovic if( bytesIn > 0 ) 937506fa58bSDamjan Jovanovic { 938f65b4e32SDamjan Jovanovic cipher.update( inputBuffer, bytesIn, &outputBuffer[ 0 ], &bytesOut ); 939506fa58bSDamjan Jovanovic cipher.final( &outputBuffer[ bytesOut ], &finalBytesOut ); 940506fa58bSDamjan Jovanovic bytesOut += finalBytesOut; 941506fa58bSDamjan Jovanovic if( decryptedSize < (totalBytesWritten + bytesOut) ) 942506fa58bSDamjan Jovanovic { 943506fa58bSDamjan Jovanovic bytesOut = decryptedSize % sizeof( inputBuffer ); 944506fa58bSDamjan Jovanovic done = true; 945506fa58bSDamjan Jovanovic } 946f65b4e32SDamjan Jovanovic aDecryptedPackage.writeMemory( &outputBuffer[ 0 ], bytesOut ); 947506fa58bSDamjan Jovanovic totalBytesWritten += bytesOut; 948506fa58bSDamjan Jovanovic } else 949506fa58bSDamjan Jovanovic done = true; 950506fa58bSDamjan Jovanovic } 951506fa58bSDamjan Jovanovic 952506fa58bSDamjan Jovanovic aDecryptedPackage.flush(); 953506fa58bSDamjan Jovanovic } 954506fa58bSDamjan Jovanovic 955506fa58bSDamjan Jovanovic EncryptionInfo* EncryptionInfo::readEncryptionInfo( const Reference< XComponentContext >& context, Reference< XInputStream >& inputStream ) 956506fa58bSDamjan Jovanovic throw ( Exception ) 957506fa58bSDamjan Jovanovic { 958506fa58bSDamjan Jovanovic sal_uInt16 nVersionMajor = readUInt16LE( inputStream ); 959506fa58bSDamjan Jovanovic sal_uInt16 nVersionMinor = readUInt16LE( inputStream ); 960506fa58bSDamjan Jovanovic if( ( nVersionMajor == 2 && nVersionMinor == 2 ) || 961506fa58bSDamjan Jovanovic ( nVersionMajor == 3 && nVersionMinor == 2 ) || 962506fa58bSDamjan Jovanovic ( nVersionMajor == 4 && nVersionMinor == 2 ) ) 963506fa58bSDamjan Jovanovic { 964506fa58bSDamjan Jovanovic // 2.3.4.5 Standard Encryption 965506fa58bSDamjan Jovanovic BinaryXInputStream aInfoStrm( inputStream, false ); 966506fa58bSDamjan Jovanovic return new StandardEncryptionInfo( aInfoStrm ); 967506fa58bSDamjan Jovanovic } 968506fa58bSDamjan Jovanovic else if ( nVersionMajor == 4 && nVersionMajor == 4 ) 969506fa58bSDamjan Jovanovic { 970506fa58bSDamjan Jovanovic // 2.3.4.10 Agile Encryption 971506fa58bSDamjan Jovanovic return new AgileEncryptionInfo( context, inputStream ); 972506fa58bSDamjan Jovanovic } 973506fa58bSDamjan Jovanovic else 974506fa58bSDamjan Jovanovic { 975506fa58bSDamjan Jovanovic char msg[ 1024 ]; 976506fa58bSDamjan Jovanovic snprintf( msg, sizeof( msg ), "EncryptionInfo::readEncryptionInfo() error: unsupported EncryptionVersionInfo header with major=%hu minor=%hu", 977506fa58bSDamjan Jovanovic nVersionMajor, nVersionMinor ); 978506fa58bSDamjan Jovanovic throw Exception( OUString::createFromAscii( msg ), Reference< XInterface >() ); 979506fa58bSDamjan Jovanovic } 980506fa58bSDamjan Jovanovic } 981506fa58bSDamjan Jovanovic 982506fa58bSDamjan Jovanovic // ============================================================================ 983506fa58bSDamjan Jovanovic 984506fa58bSDamjan Jovanovic } // namespace core 985506fa58bSDamjan Jovanovic } // namespace oox 986