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