Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/package/source/manifest/ManifestExport.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
21
#include <com/sun/star/xml/crypto/DigestID.hpp>
22
#include <com/sun/star/xml/crypto/CipherID.hpp>
23
#include <com/sun/star/xml/crypto/KDFID.hpp>
24
#include <com/sun/star/beans/PropertyValue.hpp>
25
#include <com/sun/star/beans/NamedValue.hpp>
26
#include <com/sun/star/uno/RuntimeException.hpp>
27
28
#include "ManifestDefines.hxx"
29
#include "ManifestExport.hxx"
30
31
#include <osl/diagnose.h>
32
#include <rtl/ustrbuf.hxx>
33
#include <rtl/ref.hxx>
34
#include <sal/log.hxx>
35
#include <comphelper/base64.hxx>
36
#include <comphelper/documentconstants.hxx>
37
#include <comphelper/attributelist.hxx>
38
39
using namespace ::com::sun::star;
40
41
ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > const & xHandler,  const uno::Sequence< uno::Sequence < beans::PropertyValue > >& rManList )
42
0
{
43
0
    static constexpr OUString sKeyInfo                      ( u"KeyInfo"_ustr );
44
0
    static constexpr OUString sPgpKeyIDProperty             ( u"KeyId"_ustr );
45
0
    static constexpr OUString sPgpKeyPacketProperty         ( u"KeyPacket"_ustr );
46
0
    static constexpr OUString sCipherValueProperty          ( u"CipherValue"_ustr );
47
0
    static constexpr OUString sFullPathProperty             ( u"FullPath"_ustr );
48
0
    static constexpr OUString sVersionProperty              ( u"Version"_ustr );
49
0
    static constexpr OUString sMediaTypeProperty            ( u"MediaType"_ustr );
50
0
    static constexpr OUString sIterationCountProperty       ( u"IterationCount"_ustr );
51
0
    static constexpr OUString sDerivedKeySizeProperty       ( u"DerivedKeySize"_ustr );
52
0
    static constexpr OUString sSaltProperty                 ( u"Salt"_ustr );
53
0
    static constexpr OUString sInitialisationVectorProperty ( u"InitialisationVector"_ustr );
54
0
    static constexpr OUString sSizeProperty                 ( u"Size"_ustr );
55
0
    static constexpr OUString sDigestProperty               ( u"Digest"_ustr );
56
0
    static constexpr OUString sEncryptionAlgProperty        ( u"EncryptionAlgorithm"_ustr );
57
0
    static constexpr OUString sStartKeyAlgProperty          ( u"StartKeyAlgorithm"_ustr );
58
0
    static constexpr OUString sDigestAlgProperty            ( u"DigestAlgorithm"_ustr );
59
60
0
    static constexpr OUString sWhiteSpace                   ( u" "_ustr );
61
62
0
    rtl::Reference<::comphelper::AttributeList> pRootAttrList = new ::comphelper::AttributeList;
63
64
    // find the mediatype of the document if any
65
0
    OUString aDocMediaType;
66
0
    OUString aDocVersion;
67
0
    bool isWholesomeEncryption(false);
68
0
    const uno::Sequence<beans::PropertyValue>* pRootFolderPropSeq = nullptr;
69
0
    for (const uno::Sequence < beans::PropertyValue >& rSequence : rManList)
70
0
    {
71
0
        OUString aMediaType;
72
0
        OUString aPath;
73
0
        OUString aVersion;
74
75
0
        for (const beans::PropertyValue& rValue : rSequence)
76
0
        {
77
0
            if (rValue.Name == sMediaTypeProperty )
78
0
            {
79
0
                rValue.Value >>= aMediaType;
80
0
            }
81
0
            else if (rValue.Name == sFullPathProperty )
82
0
            {
83
0
                rValue.Value >>= aPath;
84
0
            }
85
0
            else if (rValue.Name == sVersionProperty )
86
0
            {
87
0
                rValue.Value >>= aVersion;
88
0
            }
89
90
0
            if ( !aPath.isEmpty() && !aMediaType.isEmpty() && !aVersion.isEmpty() )
91
0
                break;
92
0
        }
93
94
0
        if ( aPath == "/" )
95
0
        {
96
0
            assert(aDocMediaType.isEmpty());
97
            // unfortunately no aMediaType in some cases where non-documents
98
            // are stored as StorageFormats::PACKAGE instead of sensible
99
            // StorageFormats::ZIP, such as SvxXMLXTableExportComponent and
100
            // SwXMLTextBlocks, which results in an empty "mimetype" etc but
101
            // can't be easily fixed; try to exclude these cases by checking
102
            // for aVersion, but of course then forgetting to set both version
103
            // and type on an actual document can't be found :(
104
0
            assert(!aMediaType.isEmpty() || aVersion.isEmpty());
105
0
            aDocMediaType = aMediaType;
106
0
            aDocVersion = aVersion;
107
0
            pRootFolderPropSeq = &rSequence;
108
0
        }
109
110
0
        if (aPath == "encrypted-package")
111
0
        {
112
0
            isWholesomeEncryption = true;
113
0
            assert(aDocMediaType.isEmpty() || aDocMediaType == aMediaType);
114
0
        }
115
0
    }
116
0
    assert(pRootFolderPropSeq);
117
118
0
    bool bProvideDTD = false;
119
0
    bool bAcceptNonemptyVersion = false;
120
0
    bool bStoreStartKeyGeneration = false;
121
0
    if ( !aDocMediaType.isEmpty() )
122
0
    {
123
0
        if ( aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT
124
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB
125
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL
126
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING
127
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION
128
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET
129
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART
130
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DATABASE
131
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA
132
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE
133
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE
134
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE
135
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE
136
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE
137
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE
138
0
          || aDocMediaType == MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE )
139
140
0
        {
141
            // oasis format
142
0
            pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
143
0
                                        MANIFEST_OASIS_NAMESPACE );
144
0
            bAcceptNonemptyVersion = true;
145
0
            if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
146
0
            {
147
                // this is ODF12 or later generation, let encrypted
148
                // streams contain start-key-generation entry
149
0
                bStoreStartKeyGeneration = true;
150
0
                pRootAttrList->AddAttribute ( ATTRIBUTE_VERSION, aDocVersion );
151
                // plus gpg4libre extensions - loext NS for that
152
0
                pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS_LOEXT,
153
0
                                              MANIFEST_LOEXT_NAMESPACE );
154
0
            }
155
0
        }
156
0
        else
157
0
        {
158
            // even if it is no SO6 format the namespace must be specified
159
            // thus SO6 format is used as default one
160
0
            pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS,
161
0
                                        MANIFEST_NAMESPACE );
162
163
0
            bProvideDTD = true;
164
0
        }
165
0
    }
166
167
0
    xHandler->startDocument();
168
0
    uno::Reference < xml::sax::XExtendedDocumentHandler > xExtHandler ( xHandler, uno::UNO_QUERY );
169
0
    if ( xExtHandler.is() && bProvideDTD )
170
0
    {
171
0
        xExtHandler->unknown ( MANIFEST_DOCTYPE );
172
0
        xHandler->ignorableWhitespace ( sWhiteSpace );
173
0
    }
174
0
    xHandler->startElement( ELEMENT_MANIFEST, pRootAttrList );
175
176
0
    const uno::Any *pKeyInfoProperty = nullptr;
177
0
    if ( pRootFolderPropSeq )
178
0
    {
179
        // do we have package-wide encryption info?
180
0
        for (const beans::PropertyValue& rValue : *pRootFolderPropSeq)
181
0
        {
182
0
            if (rValue.Name == sKeyInfo )
183
0
                pKeyInfoProperty = &rValue.Value;
184
0
        }
185
186
0
        if ( pKeyInfoProperty )
187
0
        {
188
            // no start-key-generation needed, our session key has
189
            // max size already
190
0
            bStoreStartKeyGeneration = false;
191
192
            // yeah, so that goes directly below the manifest:manifest
193
            // element
194
0
            OUStringBuffer aBuffer;
195
196
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
197
198
            // ==== manifest:keyinfo & children
199
0
            bool const isODF13(aDocVersion.compareTo(ODFVER_013_TEXT) >= 0);
200
0
            if (!isODF13)
201
0
            {
202
0
                xHandler->startElement(ELEMENT_MANIFEST_KEYINFO, nullptr);
203
0
            }
204
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
205
206
0
            uno::Sequence< uno::Sequence < beans::NamedValue > > aKeyInfoSequence;
207
0
            *pKeyInfoProperty >>= aKeyInfoSequence;
208
0
            for (const uno::Sequence<beans::NamedValue>& rKeyInfoSequence : aKeyInfoSequence)
209
0
            {
210
0
                uno::Sequence < sal_Int8 > aPgpKeyID;
211
0
                uno::Sequence < sal_Int8 > aPgpKeyPacket;
212
0
                uno::Sequence < sal_Int8 > aCipherValue;
213
0
                for (const beans::NamedValue& rNValue : rKeyInfoSequence)
214
0
                {
215
0
                    if (rNValue.Name == sPgpKeyIDProperty )
216
0
                        rNValue.Value >>= aPgpKeyID;
217
0
                    else if (rNValue.Name == sPgpKeyPacketProperty )
218
0
                        rNValue.Value >>= aPgpKeyPacket;
219
0
                    else if (rNValue.Name == sCipherValueProperty )
220
0
                        rNValue.Value >>= aCipherValue;
221
0
                }
222
223
0
                if (aPgpKeyID.hasElements() && aCipherValue.hasElements() )
224
0
                {
225
                    // ==== manifest:encrypted-key & children - one for each recipient
226
0
                    xHandler->startElement(isODF13 ? ELEMENT_ENCRYPTEDKEY13 : ELEMENT_ENCRYPTEDKEY, nullptr);
227
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
228
229
0
                    rtl::Reference<::comphelper::AttributeList> pNewAttrList = new ::comphelper::AttributeList;
230
                    // TODO: the algorithm should rather be configurable
231
0
                    pNewAttrList->AddAttribute(
232
0
                        isODF13 ? ATTRIBUTE_ALGORITHM13 : ATTRIBUTE_ALGORITHM,
233
0
                                                 u"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"_ustr );
234
0
                    xHandler->startElement(isODF13 ? ELEMENT_ENCRYPTIONMETHOD13 : ELEMENT_ENCRYPTIONMETHOD, pNewAttrList);
235
0
                    xHandler->endElement(isODF13 ? ELEMENT_ENCRYPTIONMETHOD13 : ELEMENT_ENCRYPTIONMETHOD);
236
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
237
238
                    // note: the mismatch here corresponds to ODF 1.3 cs01 schema
239
0
                    xHandler->startElement(isODF13 ? ELEMENT_MANIFEST13_KEYINFO : ELEMENT_MANIFEST_KEYINFO, nullptr);
240
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
241
242
0
                    xHandler->startElement(isODF13 ? ELEMENT_PGPDATA13 : ELEMENT_PGPDATA, nullptr);
243
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
244
245
0
                    xHandler->startElement(isODF13 ? ELEMENT_PGPKEYID13 : ELEMENT_PGPKEYID, nullptr);
246
0
                    ::comphelper::Base64::encode(aBuffer, aPgpKeyID);
247
0
                    xHandler->characters( aBuffer.makeStringAndClear() );
248
0
                    xHandler->endElement(isODF13 ? ELEMENT_PGPKEYID13 : ELEMENT_PGPKEYID);
249
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
250
251
                    // key packet is optional
252
0
                    if (aPgpKeyPacket.hasElements())
253
0
                    {
254
0
                        xHandler->startElement(isODF13 ? ELEMENT_PGPKEYPACKET13 : ELEMENT_PGPKEYPACKET, nullptr);
255
0
                        ::comphelper::Base64::encode(aBuffer, aPgpKeyPacket);
256
0
                        xHandler->characters( aBuffer.makeStringAndClear() );
257
0
                        xHandler->endElement(isODF13 ? ELEMENT_PGPKEYPACKET13 : ELEMENT_PGPKEYPACKET);
258
0
                        xHandler->ignorableWhitespace ( sWhiteSpace );
259
0
                    }
260
261
0
                    xHandler->endElement(isODF13 ? ELEMENT_PGPDATA13 : ELEMENT_PGPDATA);
262
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
263
264
0
                    xHandler->endElement(isODF13 ? ELEMENT_MANIFEST13_KEYINFO : ELEMENT_MANIFEST_KEYINFO);
265
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
266
267
0
                    xHandler->startElement(isODF13 ? ELEMENT_CIPHERDATA13 : ELEMENT_CIPHERDATA, nullptr);
268
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
269
270
0
                    xHandler->startElement(isODF13 ? ELEMENT_CIPHERVALUE13 : ELEMENT_CIPHERVALUE, nullptr);
271
0
                    ::comphelper::Base64::encode(aBuffer, aCipherValue);
272
0
                    xHandler->characters( aBuffer.makeStringAndClear() );
273
0
                    xHandler->endElement(isODF13 ? ELEMENT_CIPHERVALUE13 : ELEMENT_CIPHERVALUE);
274
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
275
276
0
                    xHandler->endElement(isODF13 ? ELEMENT_CIPHERDATA13 : ELEMENT_CIPHERDATA);
277
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
278
279
0
                    xHandler->endElement(isODF13 ? ELEMENT_ENCRYPTEDKEY13 : ELEMENT_ENCRYPTEDKEY);
280
0
                    xHandler->ignorableWhitespace ( sWhiteSpace );
281
0
                }
282
0
            }
283
284
0
            if (!isODF13)
285
0
            {
286
0
                xHandler->endElement(ELEMENT_MANIFEST_KEYINFO);
287
0
            }
288
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
289
0
        }
290
0
    }
291
292
    // now write individual file entries
293
0
    for (const uno::Sequence<beans::PropertyValue>& rSequence : rManList)
294
0
    {
295
0
        if (&rSequence == pRootFolderPropSeq && isWholesomeEncryption)
296
0
        {
297
0
            continue; // no root document, but embedded package => omit
298
0
        }
299
0
        rtl::Reference<::comphelper::AttributeList> pAttrList = new ::comphelper::AttributeList;
300
0
        OUString fullPath;
301
0
        OUString aString;
302
0
        const uno::Any *pVector = nullptr, *pSalt = nullptr, *pIterationCount = nullptr, *pDigest = nullptr, *pDigestAlg = nullptr, *pEncryptAlg = nullptr, *pStartKeyAlg = nullptr, *pDerivedKeySize = nullptr;
303
0
        uno::Any const* pKDF = nullptr;
304
0
        uno::Any const* pArgon2Args = nullptr;
305
0
        for (const beans::PropertyValue& rValue : rSequence)
306
0
        {
307
0
            if (rValue.Name == sMediaTypeProperty )
308
0
            {
309
0
                rValue.Value >>= aString;
310
0
                pAttrList->AddAttribute ( ATTRIBUTE_MEDIA_TYPE, aString );
311
0
            }
312
0
            else if (rValue.Name == sVersionProperty )
313
0
            {
314
0
                rValue.Value >>= aString;
315
                // the version is stored only if it is not empty
316
0
                if ( bAcceptNonemptyVersion && !aString.isEmpty() )
317
0
                    pAttrList->AddAttribute ( ATTRIBUTE_VERSION, aString );
318
0
            }
319
0
            else if (rValue.Name == sFullPathProperty )
320
0
            {
321
0
                rValue.Value >>= fullPath;
322
0
                pAttrList->AddAttribute(ATTRIBUTE_FULL_PATH, fullPath);
323
0
            }
324
0
            else if (rValue.Name == sSizeProperty )
325
0
            {
326
0
                sal_Int64 nSize = 0;
327
0
                rValue.Value >>= nSize;
328
0
                pAttrList->AddAttribute ( ATTRIBUTE_SIZE, OUString::number( nSize ) );
329
0
            }
330
0
            else if (rValue.Name == sInitialisationVectorProperty )
331
0
                pVector = &rValue.Value;
332
0
            else if (rValue.Name == sSaltProperty )
333
0
                pSalt = &rValue.Value;
334
0
            else if (rValue.Name == sIterationCountProperty )
335
0
                pIterationCount = &rValue.Value;
336
0
            else if (rValue.Name == sDigestProperty )
337
0
                pDigest = &rValue.Value;
338
0
            else if (rValue.Name == sDigestAlgProperty )
339
0
                pDigestAlg = &rValue.Value;
340
0
            else if (rValue.Name == sEncryptionAlgProperty )
341
0
                pEncryptAlg = &rValue.Value;
342
0
            else if (rValue.Name == sStartKeyAlgProperty )
343
0
                pStartKeyAlg = &rValue.Value;
344
0
            else if (rValue.Name == sDerivedKeySizeProperty )
345
0
                pDerivedKeySize = &rValue.Value;
346
0
            else if (rValue.Name == "KeyDerivationFunction") {
347
0
                pKDF = &rValue.Value;
348
0
            } else if (rValue.Name == "Argon2Args") {
349
0
                pArgon2Args = &rValue.Value;
350
0
            }
351
0
        }
352
0
        assert(!fullPath.isEmpty());
353
0
        if (isWholesomeEncryption)
354
0
        {   // there may be signatures in META-INF too
355
0
            assert(fullPath == "encrypted-package" || fullPath.startsWith("META-INF/"));
356
0
        }
357
358
0
        xHandler->ignorableWhitespace ( sWhiteSpace );
359
0
        xHandler->startElement( ELEMENT_FILE_ENTRY , pAttrList);
360
0
        if (pVector && pEncryptAlg && pDerivedKeySize && pKDF
361
0
            && ((pSalt && pStartKeyAlg && (pIterationCount || pArgon2Args))
362
0
                || pKeyInfoProperty))
363
0
        {
364
            // ==== Encryption Data
365
0
            rtl::Reference<::comphelper::AttributeList> pNewAttrList = new ::comphelper::AttributeList;
366
0
            OUStringBuffer aBuffer;
367
0
            uno::Sequence < sal_Int8 > aSequence;
368
369
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
370
371
            // ==== Digest
372
0
            if (pDigest && pDigestAlg && pDigestAlg->hasValue())
373
0
            {
374
0
                OUString sChecksumType;
375
0
                sal_Int32 nDigestAlgID = 0;
376
0
                *pDigestAlg >>= nDigestAlgID;
377
0
                if ( nDigestAlgID == xml::crypto::DigestID::SHA256_1K )
378
0
                    sChecksumType = SHA256_1K_URL;
379
0
                else if ( nDigestAlgID == xml::crypto::DigestID::SHA1_1K )
380
0
                    sChecksumType = SHA1_1K_NAME;
381
0
                else
382
0
                    throw uno::RuntimeException( u"Unexpected digest algorithm is provided!"_ustr );
383
384
0
                pNewAttrList->AddAttribute(ATTRIBUTE_CHECKSUM_TYPE, sChecksumType);
385
0
                *pDigest >>= aSequence;
386
0
                ::comphelper::Base64::encode(aBuffer, aSequence);
387
0
                pNewAttrList->AddAttribute(ATTRIBUTE_CHECKSUM, aBuffer.makeStringAndClear());
388
0
            }
389
390
0
            xHandler->startElement( ELEMENT_ENCRYPTION_DATA , pNewAttrList);
391
392
            // ==== Algorithm
393
0
            pNewAttrList = new ::comphelper::AttributeList;
394
395
0
            sal_Int32 nEncAlgID = 0;
396
0
            sal_Int32 nDerivedKeySize = 0;
397
0
            *pEncryptAlg >>= nEncAlgID;
398
0
            *pDerivedKeySize >>= nDerivedKeySize;
399
400
0
            OUString sEncAlgName;
401
0
            if ( nEncAlgID == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
402
0
            {
403
0
                OSL_ENSURE( nDerivedKeySize, "Unexpected key size is provided!" );
404
0
                if ( nDerivedKeySize != 32 )
405
0
                    throw uno::RuntimeException( u"Unexpected key size is provided!"_ustr );
406
407
0
                sEncAlgName = AES256_URL;
408
0
            }
409
0
            else if (nEncAlgID == xml::crypto::CipherID::AES_GCM_W3C)
410
0
            {
411
0
                assert(bStoreStartKeyGeneration || pKeyInfoProperty);
412
0
                SAL_WARN_IF(nDerivedKeySize != 32, "package.manifest", "Unexpected key size is provided!");
413
0
                if (nDerivedKeySize != 32)
414
0
                {
415
0
                    throw uno::RuntimeException(u"Unexpected key size is provided!"_ustr);
416
0
                }
417
0
                sEncAlgName = AESGCM256_URL;
418
0
            }
419
0
            else if ( nEncAlgID == xml::crypto::CipherID::BLOWFISH_CFB_8 )
420
0
            {
421
0
                sEncAlgName = BLOWFISH_NAME;
422
0
            }
423
0
            else
424
0
                throw uno::RuntimeException( u"Unexpected encryption algorithm is provided!"_ustr );
425
426
0
            pNewAttrList->AddAttribute ( ATTRIBUTE_ALGORITHM_NAME, sEncAlgName );
427
428
0
            *pVector >>= aSequence;
429
0
            ::comphelper::Base64::encode(aBuffer, aSequence);
430
0
            pNewAttrList->AddAttribute ( ATTRIBUTE_INITIALISATION_VECTOR, aBuffer.makeStringAndClear() );
431
432
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
433
0
            xHandler->startElement( ELEMENT_ALGORITHM , pNewAttrList);
434
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
435
0
            xHandler->endElement( ELEMENT_ALGORITHM );
436
437
0
            if ( bStoreStartKeyGeneration )
438
0
            {
439
                // ==== Start Key Generation
440
0
                pNewAttrList = new ::comphelper::AttributeList;
441
442
0
                OUString sStartKeyAlg;
443
0
                OUString sStartKeySize;
444
0
                sal_Int32 nStartKeyAlgID = 0;
445
0
                *pStartKeyAlg >>= nStartKeyAlgID;
446
0
                if ( nStartKeyAlgID == xml::crypto::DigestID::SHA256 )
447
0
                {
448
0
                    if (nEncAlgID == xml::crypto::CipherID::AES_GCM_W3C)
449
0
                    {   // new encryption is incompatible anyway, use W3C URL
450
0
                        sStartKeyAlg = SHA256_URL;
451
0
                    }
452
0
                    else // to interop with ODF <= 1.4 consumers use bad ODF URL
453
0
                    {
454
0
                        sStartKeyAlg = SHA256_URL_ODF12;
455
0
                    }
456
0
                    aBuffer.append( sal_Int32(32) );
457
0
                    sStartKeySize = aBuffer.makeStringAndClear();
458
0
                }
459
0
                else if ( nStartKeyAlgID == xml::crypto::DigestID::SHA1 )
460
0
                {
461
0
                    sStartKeyAlg = SHA1_NAME;
462
0
                    aBuffer.append( sal_Int32(20) );
463
0
                    sStartKeySize = aBuffer.makeStringAndClear();
464
0
                }
465
0
                else
466
0
                    throw uno::RuntimeException( u"Unexpected start key algorithm is provided!"_ustr );
467
468
0
                pNewAttrList->AddAttribute ( ATTRIBUTE_START_KEY_GENERATION_NAME, sStartKeyAlg );
469
0
                pNewAttrList->AddAttribute ( ATTRIBUTE_KEY_SIZE, sStartKeySize );
470
471
0
                xHandler->ignorableWhitespace ( sWhiteSpace );
472
0
                xHandler->startElement( ELEMENT_START_KEY_GENERATION , pNewAttrList);
473
0
                xHandler->ignorableWhitespace ( sWhiteSpace );
474
0
                xHandler->endElement( ELEMENT_START_KEY_GENERATION );
475
0
            }
476
477
            // ==== Key Derivation
478
0
            pNewAttrList = new ::comphelper::AttributeList;
479
480
0
            if (pKeyInfoProperty)
481
0
            {
482
0
                assert(pKDF->get<sal_Int32>() == xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P);
483
0
                pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
484
0
                                           PGP_NAME);
485
0
            }
486
0
            else
487
0
            {
488
0
                if (pKDF->get<sal_Int32>() == xml::crypto::KDFID::Argon2id)
489
0
                {
490
0
                    pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
491
0
                                               ARGON2ID_URL_LO);
492
493
0
                    uno::Sequence<sal_Int32> args;
494
0
                    *pArgon2Args >>= args;
495
0
                    assert(args.getLength() == 3);
496
0
                    pNewAttrList->AddAttribute(ATTRIBUTE_ARGON2_T_LO, OUString::number(args[0]));
497
0
                    pNewAttrList->AddAttribute(ATTRIBUTE_ARGON2_M_LO, OUString::number(args[1]));
498
0
                    pNewAttrList->AddAttribute(ATTRIBUTE_ARGON2_P_LO, OUString::number(args[2]));
499
0
                }
500
0
                else
501
0
                {
502
0
                    assert(pKDF->get<sal_Int32>() == xml::crypto::KDFID::PBKDF2);
503
0
                    pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
504
0
                                               PBKDF2_NAME);
505
506
0
                    sal_Int32 nCount = 0;
507
0
                    *pIterationCount >>= nCount;
508
0
                    aBuffer.append(nCount);
509
0
                    pNewAttrList->AddAttribute(ATTRIBUTE_ITERATION_COUNT, aBuffer.makeStringAndClear());
510
0
                }
511
512
0
                *pSalt >>= aSequence;
513
0
                ::comphelper::Base64::encode(aBuffer, aSequence);
514
0
                pNewAttrList->AddAttribute ( ATTRIBUTE_SALT, aBuffer.makeStringAndClear() );
515
0
            }
516
517
            // ODF 1.3 specifies the default as 16 so have to write it for PGP
518
0
            if (bStoreStartKeyGeneration || pKeyInfoProperty)
519
0
            {
520
0
                aBuffer.append(nDerivedKeySize);
521
0
                pNewAttrList->AddAttribute(ATTRIBUTE_KEY_SIZE, aBuffer.makeStringAndClear());
522
0
            }
523
524
0
            xHandler->ignorableWhitespace(sWhiteSpace);
525
0
            xHandler->startElement(ELEMENT_KEY_DERIVATION, pNewAttrList);
526
0
            xHandler->ignorableWhitespace(sWhiteSpace);
527
0
            xHandler->endElement(ELEMENT_KEY_DERIVATION);
528
529
0
            xHandler->ignorableWhitespace ( sWhiteSpace );
530
0
            xHandler->endElement( ELEMENT_ENCRYPTION_DATA );
531
0
        }
532
0
        xHandler->ignorableWhitespace ( sWhiteSpace );
533
0
        xHandler->endElement( ELEMENT_FILE_ENTRY );
534
0
    }
535
0
    xHandler->ignorableWhitespace ( sWhiteSpace );
536
0
    xHandler->endElement( ELEMENT_MANIFEST );
537
0
    xHandler->endDocument();
538
0
}
539
540
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */