Bump version to 5.0-14
[LibreOffice.git] / package / source / manifest / ManifestExport.cxx
blobb7a6acb9864a4b1f00613a0095e515a1f90c3643
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
21 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
22 #include <com/sun/star/xml/sax/XAttributeList.hpp>
23 #include <com/sun/star/xml/crypto/DigestID.hpp>
24 #include <com/sun/star/xml/crypto/CipherID.hpp>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/uno/RuntimeException.hpp>
28 #include <ManifestDefines.hxx>
29 #include <ManifestExport.hxx>
30 #include <sax/tools/converter.hxx>
32 #include <osl/diagnose.h>
33 #include <rtl/ustrbuf.hxx>
34 #include <comphelper/documentconstants.hxx>
35 #include <comphelper/attributelist.hxx>
37 using namespace ::com::sun::star;
39 #if OSL_DEBUG_LEVEL > 0
40 #define THROW_WHERE SAL_WHERE
41 #else
42 #define THROW_WHERE ""
43 #endif
45 ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > xHandler, const uno::Sequence< uno::Sequence < beans::PropertyValue > >& rManList )
47 const OUString sFileEntryElement ( ELEMENT_FILE_ENTRY );
48 const OUString sManifestElement ( ELEMENT_MANIFEST );
49 const OUString sEncryptionDataElement( ELEMENT_ENCRYPTION_DATA );
50 const OUString sAlgorithmElement ( ELEMENT_ALGORITHM );
51 const OUString sStartKeyGenerationElement ( ELEMENT_START_KEY_GENERATION );
52 const OUString sKeyDerivationElement ( ELEMENT_KEY_DERIVATION );
54 const OUString sCdataAttribute ( ATTRIBUTE_CDATA );
55 const OUString sMediaTypeAttribute ( ATTRIBUTE_MEDIA_TYPE );
56 const OUString sVersionAttribute ( ATTRIBUTE_VERSION );
57 const OUString sFullPathAttribute ( ATTRIBUTE_FULL_PATH );
58 const OUString sSizeAttribute ( ATTRIBUTE_SIZE );
59 const OUString sKeySizeAttribute ( ATTRIBUTE_KEY_SIZE );
60 const OUString sSaltAttribute ( ATTRIBUTE_SALT );
61 const OUString sInitialisationVectorAttribute ( ATTRIBUTE_INITIALISATION_VECTOR );
62 const OUString sIterationCountAttribute ( ATTRIBUTE_ITERATION_COUNT );
63 const OUString sAlgorithmNameAttribute ( ATTRIBUTE_ALGORITHM_NAME );
64 const OUString sStartKeyGenerationNameAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME );
65 const OUString sKeyDerivationNameAttribute ( ATTRIBUTE_KEY_DERIVATION_NAME );
66 const OUString sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE );
67 const OUString sChecksumAttribute ( ATTRIBUTE_CHECKSUM);
69 const OUString sFullPathProperty ( "FullPath" );
70 const OUString sVersionProperty ( "Version" );
71 const OUString sMediaTypeProperty ( "MediaType" );
72 const OUString sIterationCountProperty ( "IterationCount" );
73 const OUString sDerivedKeySizeProperty ( "DerivedKeySize" );
74 const OUString sSaltProperty ( "Salt" );
75 const OUString sInitialisationVectorProperty( "InitialisationVector" );
76 const OUString sSizeProperty ( "Size" );
77 const OUString sDigestProperty ( "Digest" );
78 const OUString sEncryptionAlgProperty ( "EncryptionAlgorithm" );
79 const OUString sStartKeyAlgProperty ( "StartKeyAlgorithm" );
80 const OUString sDigestAlgProperty ( "DigestAlgorithm" );
82 const OUString sWhiteSpace ( " " );
84 const OUString sSHA256_URL ( SHA256_URL );
85 const OUString sSHA1_Name ( SHA1_NAME );
87 const OUString sSHA1_1k_Name ( SHA1_1K_NAME );
88 const OUString sSHA256_1k_URL ( SHA256_1K_URL );
90 const OUString sBlowfish_Name ( BLOWFISH_NAME );
91 const OUString sAES256_URL ( AES256_URL );
93 const OUString sPBKDF2_Name ( PBKDF2_NAME );
95 ::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList;
96 const uno::Sequence < beans::PropertyValue > *pSequence = rManList.getConstArray();
97 const sal_uInt32 nManLength = rManList.getLength();
99 // find the mediatype of the document if any
100 OUString aDocMediaType;
101 OUString aDocVersion;
102 for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ )
104 OUString aMediaType;
105 OUString aPath;
106 OUString aVersion;
108 const beans::PropertyValue *pValue = pSequence[nInd].getConstArray();
109 for (sal_uInt32 j = 0, nNum = pSequence[nInd].getLength(); j < nNum; j++, pValue++)
111 if (pValue->Name.equals (sMediaTypeProperty) )
113 pValue->Value >>= aMediaType;
115 else if (pValue->Name.equals (sFullPathProperty) )
117 pValue->Value >>= aPath;
119 else if (pValue->Name.equals (sVersionProperty) )
121 pValue->Value >>= aVersion;
124 if ( !aPath.isEmpty() && !aMediaType.isEmpty() && !aVersion.isEmpty() )
125 break;
128 if ( aPath == "/" )
130 aDocMediaType = aMediaType;
131 aDocVersion = aVersion;
132 break;
136 bool bProvideDTD = false;
137 bool bAcceptNonemptyVersion = false;
138 bool bStoreStartKeyGeneration = false;
139 if ( !aDocMediaType.isEmpty() )
141 if ( aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
142 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
143 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
144 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
145 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
146 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
147 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
148 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
149 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
150 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
151 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII
152 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
153 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
154 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
155 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
156 || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII )
159 // oasis format
160 pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
161 sCdataAttribute,
162 MANIFEST_OASIS_NAMESPACE );
163 bAcceptNonemptyVersion = true;
164 if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
166 // this is ODF12 generation, let encrypted streams contain start-key-generation entry
167 bStoreStartKeyGeneration = true;
168 pRootAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aDocVersion );
171 else
173 // even if it is no SO6 format the namespace must be specified
174 // thus SO6 format is used as default one
175 pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
176 sCdataAttribute,
177 MANIFEST_NAMESPACE );
179 bProvideDTD = true;
183 uno::Reference < xml::sax::XAttributeList > xRootAttrList (pRootAttrList);
185 xHandler->startDocument();
186 uno::Reference < xml::sax::XExtendedDocumentHandler > xExtHandler ( xHandler, uno::UNO_QUERY );
187 if ( xExtHandler.is() && bProvideDTD )
189 OUString aDocType ( MANIFEST_DOCTYPE );
190 xExtHandler->unknown ( aDocType );
191 xHandler->ignorableWhitespace ( sWhiteSpace );
193 xHandler->startElement( sManifestElement, xRootAttrList );
195 for (sal_uInt32 i = 0 ; i < nManLength ; i++)
197 ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList;
198 const beans::PropertyValue *pValue = pSequence[i].getConstArray();
199 OUString aString;
200 const uno::Any *pVector = NULL, *pSalt = NULL, *pIterationCount = NULL, *pDigest = NULL, *pDigestAlg = NULL, *pEncryptAlg = NULL, *pStartKeyAlg = NULL, *pDerivedKeySize = NULL;
201 for (sal_uInt32 j = 0, nNum = pSequence[i].getLength(); j < nNum; j++, pValue++)
203 if (pValue->Name.equals (sMediaTypeProperty) )
205 pValue->Value >>= aString;
206 pAttrList->AddAttribute ( sMediaTypeAttribute, sCdataAttribute, aString );
208 else if (pValue->Name.equals (sVersionProperty) )
210 pValue->Value >>= aString;
211 // the version is stored only if it is not empty
212 if ( bAcceptNonemptyVersion && !aString.isEmpty() )
213 pAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aString );
215 else if (pValue->Name.equals (sFullPathProperty) )
217 pValue->Value >>= aString;
218 pAttrList->AddAttribute ( sFullPathAttribute, sCdataAttribute, aString );
220 else if (pValue->Name.equals (sSizeProperty) )
222 sal_Int64 nSize = 0;
223 pValue->Value >>= nSize;
224 OUStringBuffer aBuffer;
225 aBuffer.append ( nSize );
226 pAttrList->AddAttribute ( sSizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
228 else if (pValue->Name.equals (sInitialisationVectorProperty) )
229 pVector = &pValue->Value;
230 else if (pValue->Name.equals (sSaltProperty) )
231 pSalt = &pValue->Value;
232 else if (pValue->Name.equals (sIterationCountProperty) )
233 pIterationCount = &pValue->Value;
234 else if (pValue->Name.equals ( sDigestProperty ) )
235 pDigest = &pValue->Value;
236 else if (pValue->Name.equals ( sDigestAlgProperty ) )
237 pDigestAlg = &pValue->Value;
238 else if (pValue->Name.equals ( sEncryptionAlgProperty ) )
239 pEncryptAlg = &pValue->Value;
240 else if (pValue->Name.equals ( sStartKeyAlgProperty ) )
241 pStartKeyAlg = &pValue->Value;
242 else if (pValue->Name.equals ( sDerivedKeySizeProperty ) )
243 pDerivedKeySize = &pValue->Value;
246 xHandler->ignorableWhitespace ( sWhiteSpace );
247 uno::Reference < xml::sax::XAttributeList > xAttrList ( pAttrList );
248 xHandler->startElement( sFileEntryElement , xAttrList);
249 if ( pVector && pSalt && pIterationCount && pDigest && pDigestAlg && pEncryptAlg && pStartKeyAlg && pDerivedKeySize )
251 // ==== Encryption Data
252 ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList;
253 uno::Reference < xml::sax::XAttributeList > xNewAttrList (pNewAttrList);
254 OUStringBuffer aBuffer;
255 uno::Sequence < sal_Int8 > aSequence;
257 xHandler->ignorableWhitespace ( sWhiteSpace );
259 // ==== Digest
260 OUString sChecksumType;
261 sal_Int32 nDigestAlgID = 0;
262 *pDigestAlg >>= nDigestAlgID;
263 if ( nDigestAlgID == xml::crypto::DigestID::SHA256_1K )
264 sChecksumType = sSHA256_1k_URL;
265 else if ( nDigestAlgID == xml::crypto::DigestID::SHA1_1K )
266 sChecksumType = sSHA1_1k_Name;
267 else
268 throw uno::RuntimeException( THROW_WHERE "Unexpected digest algorithm is provided!" );
270 pNewAttrList->AddAttribute ( sChecksumTypeAttribute, sCdataAttribute, sChecksumType );
271 *pDigest >>= aSequence;
272 ::sax::Converter::encodeBase64(aBuffer, aSequence);
273 pNewAttrList->AddAttribute ( sChecksumAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
275 xHandler->startElement( sEncryptionDataElement , xNewAttrList);
277 // ==== Algorithm
278 pNewAttrList = new ::comphelper::AttributeList;
279 xNewAttrList = pNewAttrList;
281 sal_Int32 nEncAlgID = 0;
282 sal_Int32 nDerivedKeySize = 0;
283 *pEncryptAlg >>= nEncAlgID;
284 *pDerivedKeySize >>= nDerivedKeySize;
286 OUString sEncAlgName;
287 if ( nEncAlgID == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
289 OSL_ENSURE( nDerivedKeySize, "Unexpected key size is provided!" );
290 if ( nDerivedKeySize != 32 )
291 throw uno::RuntimeException( THROW_WHERE "Unexpected key size is provided!" );
293 sEncAlgName = sAES256_URL;
295 else if ( nEncAlgID == xml::crypto::CipherID::BLOWFISH_CFB_8 )
297 sEncAlgName = sBlowfish_Name;
299 else
300 throw uno::RuntimeException( THROW_WHERE "Unexpected encryption algorithm is provided!" );
302 pNewAttrList->AddAttribute ( sAlgorithmNameAttribute, sCdataAttribute, sEncAlgName );
304 *pVector >>= aSequence;
305 ::sax::Converter::encodeBase64(aBuffer, aSequence);
306 pNewAttrList->AddAttribute ( sInitialisationVectorAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
308 xHandler->ignorableWhitespace ( sWhiteSpace );
309 xHandler->startElement( sAlgorithmElement , xNewAttrList);
310 xHandler->ignorableWhitespace ( sWhiteSpace );
311 xHandler->endElement( sAlgorithmElement );
313 // ==== Key Derivation
314 pNewAttrList = new ::comphelper::AttributeList;
315 xNewAttrList = pNewAttrList;
317 pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2_Name );
319 if ( bStoreStartKeyGeneration )
321 aBuffer.append( nDerivedKeySize );
322 pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
325 sal_Int32 nCount = 0;
326 *pIterationCount >>= nCount;
327 aBuffer.append (nCount);
328 pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
330 *pSalt >>= aSequence;
331 ::sax::Converter::encodeBase64(aBuffer, aSequence);
332 pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
334 xHandler->ignorableWhitespace ( sWhiteSpace );
335 xHandler->startElement( sKeyDerivationElement , xNewAttrList);
336 xHandler->ignorableWhitespace ( sWhiteSpace );
337 xHandler->endElement( sKeyDerivationElement );
339 // we have to store start-key-generation element as the last one to workaround the parsing problem
340 // in OOo3.1 and older versions
341 if ( bStoreStartKeyGeneration )
343 // ==== Start Key Generation
344 pNewAttrList = new ::comphelper::AttributeList;
345 xNewAttrList = pNewAttrList;
347 OUString sStartKeyAlg;
348 OUString sStartKeySize;
349 sal_Int32 nStartKeyAlgID = 0;
350 *pStartKeyAlg >>= nStartKeyAlgID;
351 if ( nStartKeyAlgID == xml::crypto::DigestID::SHA256 )
353 sStartKeyAlg = sSHA256_URL;
354 aBuffer.append( (sal_Int32)32 );
355 sStartKeySize = aBuffer.makeStringAndClear();
357 else if ( nStartKeyAlgID == xml::crypto::DigestID::SHA1 )
359 sStartKeyAlg = sSHA1_Name;
360 aBuffer.append( (sal_Int32)20 );
361 sStartKeySize = aBuffer.makeStringAndClear();
363 else
364 throw uno::RuntimeException( THROW_WHERE "Unexpected start key algorithm is provided!" );
366 pNewAttrList->AddAttribute ( sStartKeyGenerationNameAttribute, sCdataAttribute, sStartKeyAlg );
367 pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, sStartKeySize );
369 xHandler->ignorableWhitespace ( sWhiteSpace );
370 xHandler->startElement( sStartKeyGenerationElement , xNewAttrList);
371 xHandler->ignorableWhitespace ( sWhiteSpace );
372 xHandler->endElement( sStartKeyGenerationElement );
375 xHandler->ignorableWhitespace ( sWhiteSpace );
376 xHandler->endElement( sEncryptionDataElement );
378 xHandler->ignorableWhitespace ( sWhiteSpace );
379 xHandler->endElement( sFileEntryElement );
381 xHandler->ignorableWhitespace ( sWhiteSpace );
382 xHandler->endElement( sManifestElement );
383 xHandler->endDocument();
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */