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