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