1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <rtl/ustrbuf.hxx>
33 #include <comphelper/documentconstants.hxx>
34 #include <comphelper/attributelist.hxx>
36 using namespace ::com::sun::star
;
38 ManifestExport::ManifestExport( uno::Reference
< xml::sax::XDocumentHandler
> xHandler
, const uno::Sequence
< uno::Sequence
< beans::PropertyValue
> >& rManList
)
40 const OUString
sFileEntryElement ( ELEMENT_FILE_ENTRY
);
41 const OUString
sManifestElement ( ELEMENT_MANIFEST
);
42 const OUString
sEncryptionDataElement( ELEMENT_ENCRYPTION_DATA
);
43 const OUString
sAlgorithmElement ( ELEMENT_ALGORITHM
);
44 const OUString
sStartKeyGenerationElement ( ELEMENT_START_KEY_GENERATION
);
45 const OUString
sKeyDerivationElement ( ELEMENT_KEY_DERIVATION
);
47 const OUString
sCdataAttribute ( ATTRIBUTE_CDATA
);
48 const OUString
sMediaTypeAttribute ( ATTRIBUTE_MEDIA_TYPE
);
49 const OUString
sVersionAttribute ( ATTRIBUTE_VERSION
);
50 const OUString
sFullPathAttribute ( ATTRIBUTE_FULL_PATH
);
51 const OUString
sSizeAttribute ( ATTRIBUTE_SIZE
);
52 const OUString
sKeySizeAttribute ( ATTRIBUTE_KEY_SIZE
);
53 const OUString
sSaltAttribute ( ATTRIBUTE_SALT
);
54 const OUString
sInitialisationVectorAttribute ( ATTRIBUTE_INITIALISATION_VECTOR
);
55 const OUString
sIterationCountAttribute ( ATTRIBUTE_ITERATION_COUNT
);
56 const OUString
sAlgorithmNameAttribute ( ATTRIBUTE_ALGORITHM_NAME
);
57 const OUString
sStartKeyGenerationNameAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME
);
58 const OUString
sKeyDerivationNameAttribute ( ATTRIBUTE_KEY_DERIVATION_NAME
);
59 const OUString
sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE
);
60 const OUString
sChecksumAttribute ( ATTRIBUTE_CHECKSUM
);
62 const OUString
sFullPathProperty ( "FullPath" );
63 const OUString
sVersionProperty ( "Version" );
64 const OUString
sMediaTypeProperty ( "MediaType" );
65 const OUString
sIterationCountProperty ( "IterationCount" );
66 const OUString
sDerivedKeySizeProperty ( "DerivedKeySize" );
67 const OUString
sSaltProperty ( "Salt" );
68 const OUString
sInitialisationVectorProperty( "InitialisationVector" );
69 const OUString
sSizeProperty ( "Size" );
70 const OUString
sDigestProperty ( "Digest" );
71 const OUString
sEncryptionAlgProperty ( "EncryptionAlgorithm" );
72 const OUString
sStartKeyAlgProperty ( "StartKeyAlgorithm" );
73 const OUString
sDigestAlgProperty ( "DigestAlgorithm" );
75 const OUString
sWhiteSpace ( " " );
77 const OUString
sSHA256_URL ( SHA256_URL
);
78 const OUString
sSHA1_Name ( SHA1_NAME
);
80 const OUString
sSHA1_1k_Name ( SHA1_1K_NAME
);
81 const OUString
sSHA256_1k_URL ( SHA256_1K_URL
);
83 const OUString
sBlowfish_Name ( BLOWFISH_NAME
);
84 const OUString
sAES256_URL ( AES256_URL
);
86 const OUString
sPBKDF2_Name ( PBKDF2_NAME
);
88 ::comphelper::AttributeList
* pRootAttrList
= new ::comphelper::AttributeList
;
89 const uno::Sequence
< beans::PropertyValue
> *pSequence
= rManList
.getConstArray();
90 const sal_uInt32 nManLength
= rManList
.getLength();
92 // find the mediatype of the document if any
93 OUString aDocMediaType
;
95 for (sal_uInt32 nInd
= 0; nInd
< nManLength
; nInd
++ )
101 const beans::PropertyValue
*pValue
= pSequence
[nInd
].getConstArray();
102 for (sal_uInt32 j
= 0, nNum
= pSequence
[nInd
].getLength(); j
< nNum
; j
++, pValue
++)
104 if (pValue
->Name
.equals (sMediaTypeProperty
) )
106 pValue
->Value
>>= aMediaType
;
108 else if (pValue
->Name
.equals (sFullPathProperty
) )
110 pValue
->Value
>>= aPath
;
112 else if (pValue
->Name
.equals (sVersionProperty
) )
114 pValue
->Value
>>= aVersion
;
117 if ( !aPath
.isEmpty() && !aMediaType
.isEmpty() && !aVersion
.isEmpty() )
123 aDocMediaType
= aMediaType
;
124 aDocVersion
= aVersion
;
129 sal_Bool bProvideDTD
= sal_False
;
130 sal_Bool bAcceptNonemptyVersion
= sal_False
;
131 sal_Bool bStoreStartKeyGeneration
= sal_False
;
132 if ( !aDocMediaType
.isEmpty() )
134 if ( aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
135 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
136 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
137 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
138 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
139 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
140 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
141 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
142 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
143 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
144 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
145 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
146 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
147 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
148 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII
)
152 pRootAttrList
->AddAttribute ( ATTRIBUTE_XMLNS
,
154 MANIFEST_OASIS_NAMESPACE
);
155 bAcceptNonemptyVersion
= sal_True
;
156 if ( aDocVersion
.compareTo( ODFVER_012_TEXT
) >= 0 )
158 // this is ODF12 generation, let encrypted streams contain start-key-generation entry
159 bStoreStartKeyGeneration
= sal_True
;
160 pRootAttrList
->AddAttribute ( sVersionAttribute
, sCdataAttribute
, aDocVersion
);
165 // even if it is no SO6 format the namespace must be specified
166 // thus SO6 format is used as default one
167 pRootAttrList
->AddAttribute ( ATTRIBUTE_XMLNS
,
169 MANIFEST_NAMESPACE
);
171 bProvideDTD
= sal_True
;
175 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList (pRootAttrList
);
177 xHandler
->startDocument();
178 uno::Reference
< xml::sax::XExtendedDocumentHandler
> xExtHandler ( xHandler
, uno::UNO_QUERY
);
179 if ( xExtHandler
.is() && bProvideDTD
)
181 OUString
aDocType ( MANIFEST_DOCTYPE
);
182 xExtHandler
->unknown ( aDocType
);
183 xHandler
->ignorableWhitespace ( sWhiteSpace
);
185 xHandler
->startElement( sManifestElement
, xRootAttrList
);
187 for (sal_uInt32 i
= 0 ; i
< nManLength
; i
++)
189 ::comphelper::AttributeList
*pAttrList
= new ::comphelper::AttributeList
;
190 const beans::PropertyValue
*pValue
= pSequence
[i
].getConstArray();
192 const uno::Any
*pVector
= NULL
, *pSalt
= NULL
, *pIterationCount
= NULL
, *pDigest
= NULL
, *pDigestAlg
= NULL
, *pEncryptAlg
= NULL
, *pStartKeyAlg
= NULL
, *pDerivedKeySize
= NULL
;
193 for (sal_uInt32 j
= 0, nNum
= pSequence
[i
].getLength(); j
< nNum
; j
++, pValue
++)
195 if (pValue
->Name
.equals (sMediaTypeProperty
) )
197 pValue
->Value
>>= aString
;
198 pAttrList
->AddAttribute ( sMediaTypeAttribute
, sCdataAttribute
, aString
);
200 else if (pValue
->Name
.equals (sVersionProperty
) )
202 pValue
->Value
>>= aString
;
203 // the version is stored only if it is not empty
204 if ( bAcceptNonemptyVersion
&& !aString
.isEmpty() )
205 pAttrList
->AddAttribute ( sVersionAttribute
, sCdataAttribute
, aString
);
207 else if (pValue
->Name
.equals (sFullPathProperty
) )
209 pValue
->Value
>>= aString
;
210 pAttrList
->AddAttribute ( sFullPathAttribute
, sCdataAttribute
, aString
);
212 else if (pValue
->Name
.equals (sSizeProperty
) )
215 pValue
->Value
>>= nSize
;
216 OUStringBuffer aBuffer
;
217 aBuffer
.append ( nSize
);
218 pAttrList
->AddAttribute ( sSizeAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
220 else if (pValue
->Name
.equals (sInitialisationVectorProperty
) )
221 pVector
= &pValue
->Value
;
222 else if (pValue
->Name
.equals (sSaltProperty
) )
223 pSalt
= &pValue
->Value
;
224 else if (pValue
->Name
.equals (sIterationCountProperty
) )
225 pIterationCount
= &pValue
->Value
;
226 else if (pValue
->Name
.equals ( sDigestProperty
) )
227 pDigest
= &pValue
->Value
;
228 else if (pValue
->Name
.equals ( sDigestAlgProperty
) )
229 pDigestAlg
= &pValue
->Value
;
230 else if (pValue
->Name
.equals ( sEncryptionAlgProperty
) )
231 pEncryptAlg
= &pValue
->Value
;
232 else if (pValue
->Name
.equals ( sStartKeyAlgProperty
) )
233 pStartKeyAlg
= &pValue
->Value
;
234 else if (pValue
->Name
.equals ( sDerivedKeySizeProperty
) )
235 pDerivedKeySize
= &pValue
->Value
;
238 xHandler
->ignorableWhitespace ( sWhiteSpace
);
239 uno::Reference
< xml::sax::XAttributeList
> xAttrList ( pAttrList
);
240 xHandler
->startElement( sFileEntryElement
, xAttrList
);
241 if ( pVector
&& pSalt
&& pIterationCount
&& pDigest
&& pDigestAlg
&& pEncryptAlg
&& pStartKeyAlg
&& pDerivedKeySize
)
243 // ==== Encryption Data
244 ::comphelper::AttributeList
* pNewAttrList
= new ::comphelper::AttributeList
;
245 uno::Reference
< xml::sax::XAttributeList
> xNewAttrList (pNewAttrList
);
246 OUStringBuffer aBuffer
;
247 uno::Sequence
< sal_Int8
> aSequence
;
249 xHandler
->ignorableWhitespace ( sWhiteSpace
);
252 OUString sChecksumType
;
253 sal_Int32 nDigestAlgID
= 0;
254 *pDigestAlg
>>= nDigestAlgID
;
255 if ( nDigestAlgID
== xml::crypto::DigestID::SHA256_1K
)
256 sChecksumType
= sSHA256_1k_URL
;
257 else if ( nDigestAlgID
== xml::crypto::DigestID::SHA1_1K
)
258 sChecksumType
= sSHA1_1k_Name
;
260 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected digest algorithm is provided!", uno::Reference
< uno::XInterface
>() );
262 pNewAttrList
->AddAttribute ( sChecksumTypeAttribute
, sCdataAttribute
, sChecksumType
);
263 *pDigest
>>= aSequence
;
264 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
265 pNewAttrList
->AddAttribute ( sChecksumAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
267 xHandler
->startElement( sEncryptionDataElement
, xNewAttrList
);
270 pNewAttrList
= new ::comphelper::AttributeList
;
271 xNewAttrList
= pNewAttrList
;
273 sal_Int32 nEncAlgID
= 0;
274 sal_Int32 nDerivedKeySize
= 0;
275 *pEncryptAlg
>>= nEncAlgID
;
276 *pDerivedKeySize
>>= nDerivedKeySize
;
278 OUString sEncAlgName
;
279 if ( nEncAlgID
== xml::crypto::CipherID::AES_CBC_W3C_PADDING
)
281 OSL_ENSURE( nDerivedKeySize
, "Unexpected key size is provided!" );
282 if ( nDerivedKeySize
!= 32 )
283 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected key size is provided!", uno::Reference
< uno::XInterface
>() );
285 sEncAlgName
= sAES256_URL
;
287 else if ( nEncAlgID
== xml::crypto::CipherID::BLOWFISH_CFB_8
)
289 sEncAlgName
= sBlowfish_Name
;
292 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected encryption algorithm is provided!", uno::Reference
< uno::XInterface
>() );
294 pNewAttrList
->AddAttribute ( sAlgorithmNameAttribute
, sCdataAttribute
, sEncAlgName
);
296 *pVector
>>= aSequence
;
297 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
298 pNewAttrList
->AddAttribute ( sInitialisationVectorAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
300 xHandler
->ignorableWhitespace ( sWhiteSpace
);
301 xHandler
->startElement( sAlgorithmElement
, xNewAttrList
);
302 xHandler
->ignorableWhitespace ( sWhiteSpace
);
303 xHandler
->endElement( sAlgorithmElement
);
305 // ==== Key Derivation
306 pNewAttrList
= new ::comphelper::AttributeList
;
307 xNewAttrList
= pNewAttrList
;
309 pNewAttrList
->AddAttribute ( sKeyDerivationNameAttribute
, sCdataAttribute
, sPBKDF2_Name
);
311 if ( bStoreStartKeyGeneration
)
313 aBuffer
.append( nDerivedKeySize
);
314 pNewAttrList
->AddAttribute ( sKeySizeAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
317 sal_Int32 nCount
= 0;
318 *pIterationCount
>>= nCount
;
319 aBuffer
.append (nCount
);
320 pNewAttrList
->AddAttribute ( sIterationCountAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
322 *pSalt
>>= aSequence
;
323 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
324 pNewAttrList
->AddAttribute ( sSaltAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
326 xHandler
->ignorableWhitespace ( sWhiteSpace
);
327 xHandler
->startElement( sKeyDerivationElement
, xNewAttrList
);
328 xHandler
->ignorableWhitespace ( sWhiteSpace
);
329 xHandler
->endElement( sKeyDerivationElement
);
331 // we have to store start-key-generation element as the last one to workaround the parsing problem
332 // in OOo3.1 and older versions
333 if ( bStoreStartKeyGeneration
)
335 // ==== Start Key Generation
336 pNewAttrList
= new ::comphelper::AttributeList
;
337 xNewAttrList
= pNewAttrList
;
339 OUString sStartKeyAlg
;
340 OUString sStartKeySize
;
341 sal_Int32 nStartKeyAlgID
= 0;
342 *pStartKeyAlg
>>= nStartKeyAlgID
;
343 if ( nStartKeyAlgID
== xml::crypto::DigestID::SHA256
)
345 sStartKeyAlg
= sSHA256_URL
;
346 aBuffer
.append( (sal_Int32
)32 );
347 sStartKeySize
= aBuffer
.makeStringAndClear();
349 else if ( nStartKeyAlgID
== xml::crypto::DigestID::SHA1
)
351 sStartKeyAlg
= sSHA1_Name
;
352 aBuffer
.append( (sal_Int32
)20 );
353 sStartKeySize
= aBuffer
.makeStringAndClear();
356 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected start key algorithm is provided!", uno::Reference
< uno::XInterface
>() );
358 pNewAttrList
->AddAttribute ( sStartKeyGenerationNameAttribute
, sCdataAttribute
, sStartKeyAlg
);
359 pNewAttrList
->AddAttribute ( sKeySizeAttribute
, sCdataAttribute
, sStartKeySize
);
361 xHandler
->ignorableWhitespace ( sWhiteSpace
);
362 xHandler
->startElement( sStartKeyGenerationElement
, xNewAttrList
);
363 xHandler
->ignorableWhitespace ( sWhiteSpace
);
364 xHandler
->endElement( sStartKeyGenerationElement
);
367 xHandler
->ignorableWhitespace ( sWhiteSpace
);
368 xHandler
->endElement( sEncryptionDataElement
);
370 xHandler
->ignorableWhitespace ( sWhiteSpace
);
371 xHandler
->endElement( sFileEntryElement
);
373 xHandler
->ignorableWhitespace ( sWhiteSpace
);
374 xHandler
->endElement( sManifestElement
);
375 xHandler
->endDocument();
378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */