xref: /trunk/main/oox/source/core/encryption.cxx (revision 506fa58b1970084a0caacb50b3a805e469be4756)
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