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 .
21 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
22 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
23 #include <com/sun/star/xml/sax/XAttributeList.hpp>
24 #include <com/sun/star/xml/crypto/DigestID.hpp>
25 #include <com/sun/star/xml/crypto/CipherID.hpp>
26 #include <com/sun/star/beans/PropertyValue.hpp>
27 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <ManifestDefines.hxx>
30 #include <ManifestExport.hxx>
31 #include <sax/tools/converter.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <comphelper/documentconstants.hxx>
35 #include <comphelper/attributelist.hxx>
37 using namespace ::com::sun::star
;
40 ManifestExport::ManifestExport( uno::Reference
< xml::sax::XDocumentHandler
> xHandler
, const uno::Sequence
< uno::Sequence
< beans::PropertyValue
> >& rManList
)
42 const OUString
sFileEntryElement ( ELEMENT_FILE_ENTRY
);
43 const OUString
sManifestElement ( ELEMENT_MANIFEST
);
44 const OUString
sEncryptionDataElement( ELEMENT_ENCRYPTION_DATA
);
45 const OUString
sAlgorithmElement ( ELEMENT_ALGORITHM
);
46 const OUString
sStartKeyGenerationElement ( ELEMENT_START_KEY_GENERATION
);
47 const OUString
sKeyDerivationElement ( ELEMENT_KEY_DERIVATION
);
49 const OUString
sCdataAttribute ( ATTRIBUTE_CDATA
);
50 const OUString
sMediaTypeAttribute ( ATTRIBUTE_MEDIA_TYPE
);
51 const OUString
sVersionAttribute ( ATTRIBUTE_VERSION
);
52 const OUString
sFullPathAttribute ( ATTRIBUTE_FULL_PATH
);
53 const OUString
sSizeAttribute ( ATTRIBUTE_SIZE
);
54 const OUString
sKeySizeAttribute ( ATTRIBUTE_KEY_SIZE
);
55 const OUString
sSaltAttribute ( ATTRIBUTE_SALT
);
56 const OUString
sInitialisationVectorAttribute ( ATTRIBUTE_INITIALISATION_VECTOR
);
57 const OUString
sIterationCountAttribute ( ATTRIBUTE_ITERATION_COUNT
);
58 const OUString
sAlgorithmNameAttribute ( ATTRIBUTE_ALGORITHM_NAME
);
59 const OUString
sStartKeyGenerationNameAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME
);
60 const OUString
sKeyDerivationNameAttribute ( ATTRIBUTE_KEY_DERIVATION_NAME
);
61 const OUString
sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE
);
62 const OUString
sChecksumAttribute ( ATTRIBUTE_CHECKSUM
);
64 const OUString
sFullPathProperty ( "FullPath" );
65 const OUString
sVersionProperty ( "Version" );
66 const OUString
sMediaTypeProperty ( "MediaType" );
67 const OUString
sIterationCountProperty ( "IterationCount" );
68 const OUString
sDerivedKeySizeProperty ( "DerivedKeySize" );
69 const OUString
sSaltProperty ( "Salt" );
70 const OUString
sInitialisationVectorProperty( "InitialisationVector" );
71 const OUString
sSizeProperty ( "Size" );
72 const OUString
sDigestProperty ( "Digest" );
73 const OUString
sEncryptionAlgProperty ( "EncryptionAlgorithm" );
74 const OUString
sStartKeyAlgProperty ( "StartKeyAlgorithm" );
75 const OUString
sDigestAlgProperty ( "DigestAlgorithm" );
77 const OUString
sWhiteSpace ( " " );
79 const OUString
sSHA256_URL ( SHA256_URL
);
80 const OUString
sSHA1_Name ( SHA1_NAME
);
82 const OUString
sSHA1_1k_Name ( SHA1_1K_NAME
);
83 const OUString
sSHA256_1k_URL ( SHA256_1K_URL
);
85 const OUString
sBlowfish_Name ( BLOWFISH_NAME
);
86 const OUString
sAES256_URL ( AES256_URL
);
88 const OUString
sPBKDF2_Name ( PBKDF2_NAME
);
90 ::comphelper::AttributeList
* pRootAttrList
= new ::comphelper::AttributeList
;
91 const uno::Sequence
< beans::PropertyValue
> *pSequence
= rManList
.getConstArray();
92 const sal_uInt32 nManLength
= rManList
.getLength();
94 // find the mediatype of the document if any
95 OUString aDocMediaType
;
97 for (sal_uInt32 nInd
= 0; nInd
< nManLength
; nInd
++ )
103 const beans::PropertyValue
*pValue
= pSequence
[nInd
].getConstArray();
104 for (sal_uInt32 j
= 0, nNum
= pSequence
[nInd
].getLength(); j
< nNum
; j
++, pValue
++)
106 if (pValue
->Name
.equals (sMediaTypeProperty
) )
108 pValue
->Value
>>= aMediaType
;
110 else if (pValue
->Name
.equals (sFullPathProperty
) )
112 pValue
->Value
>>= aPath
;
114 else if (pValue
->Name
.equals (sVersionProperty
) )
116 pValue
->Value
>>= aVersion
;
119 if ( !aPath
.isEmpty() && !aMediaType
.isEmpty() && !aVersion
.isEmpty() )
125 aDocMediaType
= aMediaType
;
126 aDocVersion
= aVersion
;
131 sal_Bool bProvideDTD
= sal_False
;
132 sal_Bool bAcceptNonemptyVersion
= sal_False
;
133 sal_Bool bStoreStartKeyGeneration
= sal_False
;
134 if ( !aDocMediaType
.isEmpty() )
136 if ( aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
137 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
138 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
139 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
140 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
141 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
142 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
143 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
144 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
145 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
146 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
147 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
148 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
149 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
150 || aDocMediaType
== MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII
)
154 pRootAttrList
->AddAttribute ( ATTRIBUTE_XMLNS
,
156 MANIFEST_OASIS_NAMESPACE
);
157 bAcceptNonemptyVersion
= sal_True
;
158 if ( aDocVersion
.compareTo( ODFVER_012_TEXT
) >= 0 )
160 // this is ODF12 generation, let encrypted streams contain start-key-generation entry
161 bStoreStartKeyGeneration
= sal_True
;
162 pRootAttrList
->AddAttribute ( sVersionAttribute
, sCdataAttribute
, aDocVersion
);
167 // even if it is no SO6 format the namespace must be specified
168 // thus SO6 format is used as default one
169 pRootAttrList
->AddAttribute ( ATTRIBUTE_XMLNS
,
171 MANIFEST_NAMESPACE
);
173 bProvideDTD
= sal_True
;
177 uno::Reference
< xml::sax::XAttributeList
> xRootAttrList (pRootAttrList
);
179 xHandler
->startDocument();
180 uno::Reference
< xml::sax::XExtendedDocumentHandler
> xExtHandler ( xHandler
, uno::UNO_QUERY
);
181 if ( xExtHandler
.is() && bProvideDTD
)
183 OUString
aDocType ( MANIFEST_DOCTYPE
);
184 xExtHandler
->unknown ( aDocType
);
185 xHandler
->ignorableWhitespace ( sWhiteSpace
);
187 xHandler
->startElement( sManifestElement
, xRootAttrList
);
189 for (sal_uInt32 i
= 0 ; i
< nManLength
; i
++)
191 ::comphelper::AttributeList
*pAttrList
= new ::comphelper::AttributeList
;
192 const beans::PropertyValue
*pValue
= pSequence
[i
].getConstArray();
194 const uno::Any
*pVector
= NULL
, *pSalt
= NULL
, *pIterationCount
= NULL
, *pDigest
= NULL
, *pDigestAlg
= NULL
, *pEncryptAlg
= NULL
, *pStartKeyAlg
= NULL
, *pDerivedKeySize
= NULL
;
195 for (sal_uInt32 j
= 0, nNum
= pSequence
[i
].getLength(); j
< nNum
; j
++, pValue
++)
197 if (pValue
->Name
.equals (sMediaTypeProperty
) )
199 pValue
->Value
>>= aString
;
200 pAttrList
->AddAttribute ( sMediaTypeAttribute
, sCdataAttribute
, aString
);
202 else if (pValue
->Name
.equals (sVersionProperty
) )
204 pValue
->Value
>>= aString
;
205 // the version is stored only if it is not empty
206 if ( bAcceptNonemptyVersion
&& !aString
.isEmpty() )
207 pAttrList
->AddAttribute ( sVersionAttribute
, sCdataAttribute
, aString
);
209 else if (pValue
->Name
.equals (sFullPathProperty
) )
211 pValue
->Value
>>= aString
;
212 pAttrList
->AddAttribute ( sFullPathAttribute
, sCdataAttribute
, aString
);
214 else if (pValue
->Name
.equals (sSizeProperty
) )
217 pValue
->Value
>>= nSize
;
218 OUStringBuffer aBuffer
;
219 aBuffer
.append ( nSize
);
220 pAttrList
->AddAttribute ( sSizeAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
222 else if (pValue
->Name
.equals (sInitialisationVectorProperty
) )
223 pVector
= &pValue
->Value
;
224 else if (pValue
->Name
.equals (sSaltProperty
) )
225 pSalt
= &pValue
->Value
;
226 else if (pValue
->Name
.equals (sIterationCountProperty
) )
227 pIterationCount
= &pValue
->Value
;
228 else if (pValue
->Name
.equals ( sDigestProperty
) )
229 pDigest
= &pValue
->Value
;
230 else if (pValue
->Name
.equals ( sDigestAlgProperty
) )
231 pDigestAlg
= &pValue
->Value
;
232 else if (pValue
->Name
.equals ( sEncryptionAlgProperty
) )
233 pEncryptAlg
= &pValue
->Value
;
234 else if (pValue
->Name
.equals ( sStartKeyAlgProperty
) )
235 pStartKeyAlg
= &pValue
->Value
;
236 else if (pValue
->Name
.equals ( sDerivedKeySizeProperty
) )
237 pDerivedKeySize
= &pValue
->Value
;
240 xHandler
->ignorableWhitespace ( sWhiteSpace
);
241 uno::Reference
< xml::sax::XAttributeList
> xAttrList ( pAttrList
);
242 xHandler
->startElement( sFileEntryElement
, xAttrList
);
243 if ( pVector
&& pSalt
&& pIterationCount
&& pDigest
&& pDigestAlg
&& pEncryptAlg
&& pStartKeyAlg
&& pDerivedKeySize
)
245 // ==== Encryption Data
246 ::comphelper::AttributeList
* pNewAttrList
= new ::comphelper::AttributeList
;
247 uno::Reference
< xml::sax::XAttributeList
> xNewAttrList (pNewAttrList
);
248 OUStringBuffer aBuffer
;
249 uno::Sequence
< sal_Int8
> aSequence
;
251 xHandler
->ignorableWhitespace ( sWhiteSpace
);
254 OUString sChecksumType
;
255 sal_Int32 nDigestAlgID
= 0;
256 *pDigestAlg
>>= nDigestAlgID
;
257 if ( nDigestAlgID
== xml::crypto::DigestID::SHA256_1K
)
258 sChecksumType
= sSHA256_1k_URL
;
259 else if ( nDigestAlgID
== xml::crypto::DigestID::SHA1_1K
)
260 sChecksumType
= sSHA1_1k_Name
;
262 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected digest algorithm is provided!", uno::Reference
< uno::XInterface
>() );
264 pNewAttrList
->AddAttribute ( sChecksumTypeAttribute
, sCdataAttribute
, sChecksumType
);
265 *pDigest
>>= aSequence
;
266 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
267 pNewAttrList
->AddAttribute ( sChecksumAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
269 xHandler
->startElement( sEncryptionDataElement
, xNewAttrList
);
272 pNewAttrList
= new ::comphelper::AttributeList
;
273 xNewAttrList
= pNewAttrList
;
275 sal_Int32 nEncAlgID
= 0;
276 sal_Int32 nDerivedKeySize
= 0;
277 *pEncryptAlg
>>= nEncAlgID
;
278 *pDerivedKeySize
>>= nDerivedKeySize
;
280 OUString sEncAlgName
;
281 if ( nEncAlgID
== xml::crypto::CipherID::AES_CBC_W3C_PADDING
)
283 OSL_ENSURE( nDerivedKeySize
, "Unexpected key size is provided!" );
284 if ( nDerivedKeySize
!= 32 )
285 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected key size is provided!", uno::Reference
< uno::XInterface
>() );
287 sEncAlgName
= sAES256_URL
;
289 else if ( nEncAlgID
== xml::crypto::CipherID::BLOWFISH_CFB_8
)
291 sEncAlgName
= sBlowfish_Name
;
294 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected encryption algorithm is provided!", uno::Reference
< uno::XInterface
>() );
296 pNewAttrList
->AddAttribute ( sAlgorithmNameAttribute
, sCdataAttribute
, sEncAlgName
);
298 *pVector
>>= aSequence
;
299 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
300 pNewAttrList
->AddAttribute ( sInitialisationVectorAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
302 xHandler
->ignorableWhitespace ( sWhiteSpace
);
303 xHandler
->startElement( sAlgorithmElement
, xNewAttrList
);
304 xHandler
->ignorableWhitespace ( sWhiteSpace
);
305 xHandler
->endElement( sAlgorithmElement
);
307 // ==== Key Derivation
308 pNewAttrList
= new ::comphelper::AttributeList
;
309 xNewAttrList
= pNewAttrList
;
311 pNewAttrList
->AddAttribute ( sKeyDerivationNameAttribute
, sCdataAttribute
, sPBKDF2_Name
);
313 if ( bStoreStartKeyGeneration
)
315 aBuffer
.append( nDerivedKeySize
);
316 pNewAttrList
->AddAttribute ( sKeySizeAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
319 sal_Int32 nCount
= 0;
320 *pIterationCount
>>= nCount
;
321 aBuffer
.append (nCount
);
322 pNewAttrList
->AddAttribute ( sIterationCountAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
324 *pSalt
>>= aSequence
;
325 ::sax::Converter::encodeBase64(aBuffer
, aSequence
);
326 pNewAttrList
->AddAttribute ( sSaltAttribute
, sCdataAttribute
, aBuffer
.makeStringAndClear() );
328 xHandler
->ignorableWhitespace ( sWhiteSpace
);
329 xHandler
->startElement( sKeyDerivationElement
, xNewAttrList
);
330 xHandler
->ignorableWhitespace ( sWhiteSpace
);
331 xHandler
->endElement( sKeyDerivationElement
);
333 // we have to store start-key-generation element as the last one to workaround the parsing problem
334 // in OOo3.1 and older versions
335 if ( bStoreStartKeyGeneration
)
337 // ==== Start Key Generation
338 pNewAttrList
= new ::comphelper::AttributeList
;
339 xNewAttrList
= pNewAttrList
;
341 OUString sStartKeyAlg
;
342 OUString sStartKeySize
;
343 sal_Int32 nStartKeyAlgID
= 0;
344 *pStartKeyAlg
>>= nStartKeyAlgID
;
345 if ( nStartKeyAlgID
== xml::crypto::DigestID::SHA256
)
347 sStartKeyAlg
= sSHA256_URL
;
348 aBuffer
.append( (sal_Int32
)32 );
349 sStartKeySize
= aBuffer
.makeStringAndClear();
351 else if ( nStartKeyAlgID
== xml::crypto::DigestID::SHA1
)
353 sStartKeyAlg
= sSHA1_Name
;
354 aBuffer
.append( (sal_Int32
)20 );
355 sStartKeySize
= aBuffer
.makeStringAndClear();
358 throw uno::RuntimeException( OSL_LOG_PREFIX
"Unexpected start key algorithm is provided!", uno::Reference
< uno::XInterface
>() );
360 pNewAttrList
->AddAttribute ( sStartKeyGenerationNameAttribute
, sCdataAttribute
, sStartKeyAlg
);
361 pNewAttrList
->AddAttribute ( sKeySizeAttribute
, sCdataAttribute
, sStartKeySize
);
363 xHandler
->ignorableWhitespace ( sWhiteSpace
);
364 xHandler
->startElement( sStartKeyGenerationElement
, xNewAttrList
);
365 xHandler
->ignorableWhitespace ( sWhiteSpace
);
366 xHandler
->endElement( sStartKeyGenerationElement
);
369 xHandler
->ignorableWhitespace ( sWhiteSpace
);
370 xHandler
->endElement( sEncryptionDataElement
);
372 xHandler
->ignorableWhitespace ( sWhiteSpace
);
373 xHandler
->endElement( sFileEntryElement
);
375 xHandler
->ignorableWhitespace ( sWhiteSpace
);
376 xHandler
->endElement( sManifestElement
);
377 xHandler
->endDocument();
380 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */