[Libreoffice-commits] core.git: 10 commits - comphelper/Library_comphelper.mk comphelper/source external/gpgmepp fpicker/source include/sal offapi/com package/inc package/source sfx2/source vcl/unx xmlsecurity/inc xmlsecurity/source

Thorsten Behrens Thorsten.Behrens at CIB.de
Thu Dec 7 17:23:25 UTC 2017


 comphelper/Library_comphelper.mk                            |    1 
 comphelper/source/misc/storagehelper.cxx                    |  118 +++++++-
 external/gpgmepp/ExternalProject_gpgmepp.mk                 |    5 
 fpicker/source/office/OfficeControlAccess.cxx               |    1 
 fpicker/source/win32/filepicker/VistaFilePicker.cxx         |    2 
 fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx     |    8 
 fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx     |    1 
 fpicker/source/win32/misc/resourceprovider.cxx              |    3 
 include/sal/log-areas.dox                                   |    1 
 offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl   |   31 ++
 offapi/com/sun/star/security/XDocumentDigitalSignatures.idl |    2 
 package/inc/PackageConstants.hxx                            |    1 
 package/inc/ZipPackage.hxx                                  |    1 
 package/source/manifest/ManifestDefines.hxx                 |   13 
 package/source/manifest/ManifestExport.cxx                  |  175 +++++++++++-
 package/source/xstor/xstorage.cxx                           |   60 ++++
 package/source/xstor/xstorage.hxx                           |    1 
 package/source/zippackage/ZipPackage.cxx                    |   25 +
 sfx2/source/dialog/filedlghelper.cxx                        |   22 +
 vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx                    |    4 
 vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx                    |    1 
 vcl/unx/gtk/fpicker/resourceprovider.cxx                    |    1 
 vcl/unx/kde4/KDE4FilePicker.cxx                             |    6 
 xmlsecurity/inc/certificatechooser.hxx                      |    2 
 xmlsecurity/source/component/documentdigitalsignatures.cxx  |   32 +-
 xmlsecurity/source/component/documentdigitalsignatures.hxx  |    4 
 xmlsecurity/source/dialogs/certificatechooser.cxx           |   38 +-
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx      |   14 
 xmlsecurity/source/gpg/CertificateImpl.cxx                  |    6 
 29 files changed, 514 insertions(+), 65 deletions(-)

New commits:
commit ed50a0a2ce51584fa3a8fba0094220a4bf25c650
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Thu Dec 7 18:18:47 2017 +0100

    gpg4libre: handle unavailable gpg crypto tools more gracefully
    
    Change-Id: I58af9d38ea8d202d2bda64cdf45204646ac9fd29

diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 9d1244973de7..dd7de2c3bafe 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -349,7 +349,7 @@ DocumentDigitalSignatures::ImplVerifySignatures(
                     rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
                 }
             }
-            else // GPG
+            else if (xGpgSecEnv.is()) // GPG
             {
                 // TODO not ideal to retrieve cert by keyID, might
                 // collide, or PGPKeyID format might change - can't we
commit 1e12447f7ea601e158808290f4f67d84efba06e2
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Thu Dec 7 14:31:36 2017 +0100

    gpg4libre: return key fingerprint / hashes including null character
    
    Change-Id: I6b32444bab6848e2b5ddec02fd949c71114a66b2

diff --git a/xmlsecurity/source/gpg/CertificateImpl.cxx b/xmlsecurity/source/gpg/CertificateImpl.cxx
index 16eeda80441f..c831011ca50e 100644
--- a/xmlsecurity/source/gpg/CertificateImpl.cxx
+++ b/xmlsecurity/source/gpg/CertificateImpl.cxx
@@ -158,7 +158,7 @@ Sequence< sal_Int8 > SAL_CALL CertificateImpl::getSHA1Thumbprint()
     // This is mapped to the fingerprint for gpg
     const char* keyId = m_pKey.primaryFingerprint();
     return comphelper::arrayToSequence<sal_Int8>(
-        keyId, strlen(keyId));
+        keyId, strlen(keyId)+1);
 }
 
 Sequence<sal_Int8> CertificateImpl::getSHA256Thumbprint()
@@ -167,7 +167,7 @@ Sequence<sal_Int8> CertificateImpl::getSHA256Thumbprint()
     // SHA1 actually)
     const char* keyId = m_pKey.primaryFingerprint();
     return comphelper::arrayToSequence<sal_Int8>(
-        keyId, strlen(keyId));
+        keyId, strlen(keyId)+1);
 }
 
 Sequence< sal_Int8 > SAL_CALL CertificateImpl::getMD5Thumbprint()
@@ -175,7 +175,7 @@ Sequence< sal_Int8 > SAL_CALL CertificateImpl::getMD5Thumbprint()
     // This is mapped to the shorter keyID for gpg
     const char* keyId = m_pKey.keyID();
     return comphelper::arrayToSequence<sal_Int8>(
-        keyId, strlen(keyId));
+        keyId, strlen(keyId)+1);
 }
 
 CertificateKind SAL_CALL CertificateImpl::getCertificateKind()
commit 626e73eafe953b102107031721a0b145fb713e9d
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Thu Dec 7 05:11:15 2017 +0100

    gpg4libre: permit multi-select encrypt cert
    
    And pass down all necessary parameters everywhere
    
    Change-Id: I152b9d84c0e35be9e5193a9a6f67de9fb86133b0

diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx
index a05fb1358f3f..7fa46554b595 100644
--- a/comphelper/source/misc/storagehelper.cxx
+++ b/comphelper/source/misc/storagehelper.cxx
@@ -17,6 +17,8 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include <config_gpgme.h>
+
 #include <com/sun/star/embed/ElementModes.hpp>
 #include <com/sun/star/embed/XEncryptionProtectedSource2.hpp>
 #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp>
@@ -459,6 +461,9 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat
     uno::Sequence< uno::Reference< security::XCertificate > > xSignCertificates=
         xSigner->chooseEncryptionCertificate();
 
+    if (!xSignCertificates.hasElements())
+        return uno::Sequence< beans::NamedValue >(); // user cancelled
+
     // generate one encrypted key entry for each recipient
     // ---------------------------------------------------
 
@@ -478,13 +483,13 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat
     {
         uno::Sequence < sal_Int8 > aKeyID;
         if (pCerts->is())
-            aKeyID = (*pCerts)->getSHA256Thumbprint();
+            aKeyID = (*pCerts)->getSHA1Thumbprint();
 
         std::vector<GpgME::Key> keys;
         keys.push_back(
             ctx->key(
                 reinterpret_cast<const char*>(aKeyID.getConstArray()),
-                err, true));
+                err, false));
 
         // ctx is setup now, let's encrypt the lot!
         GpgME::Data plain(
@@ -504,7 +509,9 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat
             len += curr;
 
         if(crypt_res.error() || !len)
-            throw uno::RuntimeException("The GpgME library failed to encrypt.");
+            throw lang::IllegalArgumentException(
+                "Not a suitable key, or failed to encrypt.",
+                css::uno::Reference<css::uno::XInterface>(), i);
 
         uno::Sequence < sal_Int8 > aCipherValue(len);
         result = cipher.seek(0,SEEK_SET);
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 1df274126d87..3858ea12175b 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -94,6 +94,7 @@ certain functionality.
 @li @c comphelper
 @li @c comphelper.backupfilehelper
 @li @c comphelper.container - EmbeddedObjectContainer
+ at li @c comphelper.crypto
 
 @section cppu
 
diff --git a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
index 85507940d316..519f77cb62dd 100644
--- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
+++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
@@ -148,7 +148,7 @@ interface XDocumentDigitalSignatures : com::sun::star::uno::XInterface
 
          @since LibreOffice 6.0
      */
-    com::sun::star::security::XCertificate chooseEncryptionCertificate( [out] string Description );
+    sequence< com::sun::star::security::XCertificate > chooseEncryptionCertificate( );
 
     /**  This method shows the CertificateChooser dialog, used by document and PDF signing
          Shows only private certificates and returns usage string in addition to description.
diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx
index 4482d2887c41..84e248bfa390 100644
--- a/sfx2/source/dialog/filedlghelper.cxx
+++ b/sfx2/source/dialog/filedlghelper.cxx
@@ -1521,8 +1521,26 @@ ErrCode FileDialogHelper_Impl::execute( std::vector<OUString>& rpURLList,
                 bool bGpg = false;
                 if ( ( aValue >>= bGpg ) && bGpg )
                 {
-                    // ask for a key
-                    rpSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( ::comphelper::OStorageHelper::CreateGpgPackageEncryptionData() ) ) );
+                    uno::Sequence< beans::NamedValue > aEncryptionData;
+                    while(true)
+                    {
+                        try
+                        {
+                            // ask for keys
+                            aEncryptionData = ::comphelper::OStorageHelper::CreateGpgPackageEncryptionData();
+                            break; // user cancelled or we've some keys now
+                        }
+                        catch( const IllegalArgumentException& )
+                        {
+                            ScopedVclPtrInstance< MessageDialog > aBox(
+                                mpPreferredParentWindow,
+                                SfxResId(RID_SVXSTR_INCORRECT_PASSWORD));
+                            aBox->Execute();
+                        }
+                    }
+
+                    if ( aEncryptionData.hasElements() )
+                        rpSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData) ) );
                 }
             }
             catch( const IllegalArgumentException& ){}
diff --git a/xmlsecurity/inc/certificatechooser.hxx b/xmlsecurity/inc/certificatechooser.hxx
index 3834dfb111a1..2ae3c1822b1f 100644
--- a/xmlsecurity/inc/certificatechooser.hxx
+++ b/xmlsecurity/inc/certificatechooser.hxx
@@ -92,7 +92,7 @@ public:
 
     short Execute() override;
 
-    css::uno::Reference< css::security::XCertificate > GetSelectedCertificate();
+    css::uno::Sequence<css::uno::Reference< css::security::XCertificate > > GetSelectedCertificates();
     css::uno::Reference< css::xml::crypto::XXMLSecurityContext > GetSelectedSecurityContext();
     /// Gets the description string provided when selecting the certificate.
     OUString GetDescription();
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index bc52bdb30ff1..9d1244973de7 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -456,7 +456,7 @@ sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
     return bFound;
 }
 
-Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificateImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction)
+uno::Sequence< Reference< css::security::XCertificate > > DocumentDigitalSignatures::chooseCertificatesImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction)
 {
     std::vector< Reference< css::xml::crypto::XXMLSecurityContext > > xSecContexts;
 
@@ -468,17 +468,17 @@ Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertif
 
     ScopedVclPtrInstance< CertificateChooser > aChooser(nullptr, mxCtx, xSecContexts, eAction);
 
+    uno::Sequence< Reference< css::security::XCertificate > > xCerts(1);
+    xCerts[0] = Reference< css::security::XCertificate >(nullptr);
+
     if (aChooser->Execute() != RET_OK)
-        return Reference< css::security::XCertificate >(nullptr);
+        return xCerts;
 
-    Reference< css::security::XCertificate > xCert = aChooser->GetSelectedCertificate();
+    xCerts = aChooser->GetSelectedCertificates();
     rProperties["Description"] = aChooser->GetDescription();
     rProperties["Usage"] = aChooser->GetUsageText();
 
-    if ( !xCert.is() )
-        return Reference< css::security::XCertificate >(nullptr);
-
-    return xCert;
+    return xCerts;
 }
 
 Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificate(OUString& rDescription)
@@ -489,23 +489,27 @@ Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertif
 Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseSigningCertificate(OUString& rDescription)
 {
     std::map<OUString, OUString> aProperties;
-    Reference< css::security::XCertificate > xCert = chooseCertificateImpl( aProperties, UserAction::Sign );
+    Reference< css::security::XCertificate > xCert = chooseCertificatesImpl( aProperties, UserAction::Sign )[0];
     rDescription = aProperties["Description"];
     return xCert;
 }
 
-Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseEncryptionCertificate(OUString& rDescription)
+css::uno::Sequence< Reference< css::security::XCertificate > > DocumentDigitalSignatures::chooseEncryptionCertificate()
 {
     std::map<OUString, OUString> aProperties;
-    Reference< css::security::XCertificate > xCert = chooseCertificateImpl( aProperties, UserAction::Encrypt );
-    rDescription = aProperties["Description"];
-    return xCert;
+    uno::Sequence< Reference< css::security::XCertificate > > aCerts=
+        chooseCertificatesImpl( aProperties, UserAction::Encrypt );
+    if (aCerts.getLength() == 1 && !aCerts[0].is())
+        // our error case contract is: empty sequence, so map that!
+        return uno::Sequence< Reference< css::security::XCertificate > >();
+    else
+        return aCerts;
 }
 
 css::uno::Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificateWithProps(Sequence<::com::sun::star::beans::PropertyValue>& rProperties)
 {
     std::map<OUString, OUString> aProperties;
-    auto xCert = chooseCertificateImpl( aProperties, UserAction::Sign );
+    auto xCert = chooseCertificatesImpl( aProperties, UserAction::Sign )[0];
 
     std::vector<css::beans::PropertyValue> vec;
     for (const auto& pair : aProperties)
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.hxx b/xmlsecurity/source/component/documentdigitalsignatures.hxx
index 2dbc55685929..9ef24ab36e5e 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.hxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.hxx
@@ -63,7 +63,7 @@ private:
     /// @throws css::uno::RuntimeException
     css::uno::Sequence< css::security::DocumentSignatureInformation > ImplVerifySignatures( const css::uno::Reference< css::embed::XStorage >& rxStorage, const ::com::sun::star::uno::Reference< css::io::XInputStream >& xSignStream, DocumentSignatureMode eMode );
 
-    css::uno::Reference< css::security::XCertificate > chooseCertificateImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction);
+    css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > chooseCertificatesImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction);
 
 public:
     explicit DocumentDigitalSignatures( const css::uno::Reference< css::uno::XComponentContext>& rxCtx );
@@ -106,7 +106,7 @@ public:
 
     css::uno::Reference< css::security::XCertificate > SAL_CALL chooseCertificate(OUString& rDescription) override;
     css::uno::Reference< css::security::XCertificate > SAL_CALL chooseSigningCertificate(OUString& rDescription) override;
-    css::uno::Reference< css::security::XCertificate > SAL_CALL chooseEncryptionCertificate(OUString& rDescription) override;
+    css::uno::Sequence<css::uno::Reference< css::security::XCertificate > > SAL_CALL chooseEncryptionCertificate() override;
     css::uno::Reference< css::security::XCertificate > SAL_CALL chooseCertificateWithProps(css::uno::Sequence<::com::sun::star::beans::PropertyValue>& Properties) override;
 };
 
diff --git a/xmlsecurity/source/dialogs/certificatechooser.cxx b/xmlsecurity/source/dialogs/certificatechooser.cxx
index 08a897f9f0ba..a334e0250225 100644
--- a/xmlsecurity/source/dialogs/certificatechooser.cxx
+++ b/xmlsecurity/source/dialogs/certificatechooser.cxx
@@ -228,15 +228,33 @@ void CertificateChooser::ImplInitialize()
 }
 
 
-uno::Reference< css::security::XCertificate > CertificateChooser::GetSelectedCertificate()
+uno::Sequence<uno::Reference< css::security::XCertificate > > CertificateChooser::GetSelectedCertificates()
 {
+    std::vector< uno::Reference< css::security::XCertificate > > aRet;
     SvTreeListEntry* pSel = m_pCertLB->FirstSelected();
-    if( !pSel )
-        return uno::Reference< css::security::XCertificate >();
 
-    UserData* userData = static_cast<UserData*>(pSel->GetUserData());
-    uno::Reference<security::XCertificate> xCert = userData->xCertificate;
-    return xCert;
+    if (meAction == UserAction::Encrypt)
+    {
+        // for encryption, multiselection is enabled
+        while(pSel)
+        {
+            UserData* userData = static_cast<UserData*>(pSel->GetUserData());
+            aRet.push_back( userData->xCertificate );
+            pSel = m_pCertLB->NextSelected(pSel);
+        }
+    }
+    else
+    {
+        uno::Reference< css::security::XCertificate > xCert;
+        if( pSel )
+        {
+            UserData* userData = static_cast<UserData*>(pSel->GetUserData());
+            xCert = userData->xCertificate;
+        }
+        aRet.push_back( xCert );
+    }
+
+    return comphelper::containerToSequence(aRet);
 }
 
 uno::Reference<xml::crypto::XXMLSecurityContext> CertificateChooser::GetSelectedSecurityContext()
@@ -257,13 +275,15 @@ OUString CertificateChooser::GetDescription()
 
 OUString CertificateChooser::GetUsageText()
 {
-    uno::Reference<css::security::XCertificate> xCert = GetSelectedCertificate();
-    return xCert.is() ? UsageInClearText(xCert->getCertificateUsage()) : OUString();
+    uno::Sequence< uno::Reference<css::security::XCertificate> > xCerts =
+        GetSelectedCertificates();
+    return (xCerts.hasElements() && xCerts[0].is()) ?
+        UsageInClearText(xCerts[0]->getCertificateUsage()) : OUString();
 }
 
 IMPL_LINK_NOARG(CertificateChooser, CertificateHighlightHdl, SvTreeListBox*, void)
 {
-    bool bEnable = GetSelectedCertificate().is();
+    bool bEnable = m_pCertLB->GetSelectionCount() > 0;
     m_pViewBtn->Enable( bEnable );
     m_pOKBtn->Enable( bEnable );
     m_pDescriptionED->Enable(bEnable);
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index 42ca15d05faf..195c74ec5c3e 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -406,7 +406,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void)
         if ( aChooser->Execute() == RET_OK )
         {
             sal_Int32 nSecurityId;
-            if (!maSignatureManager.add(aChooser->GetSelectedCertificate(), aChooser->GetSelectedSecurityContext(),
+            if (!maSignatureManager.add(aChooser->GetSelectedCertificates()[0], aChooser->GetSelectedSecurityContext(),
                                         aChooser->GetDescription(), nSecurityId, m_bAdESCompliant))
                 return;
             mbSignaturesChanged = true;
commit 5d0f3cc3f9e6fc687ba6a40cebf2096d70e4f811
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Thu Dec 7 05:08:37 2017 +0100

    gpg4libre: pass proper debug flags down to gpgmepp
    
    Change-Id: Ide3f6e9fa218bcd26deaadbbdbed0c8905e66db9

diff --git a/external/gpgmepp/ExternalProject_gpgmepp.mk b/external/gpgmepp/ExternalProject_gpgmepp.mk
index 73a0ad68e6cd..a10d41556b0c 100644
--- a/external/gpgmepp/ExternalProject_gpgmepp.mk
+++ b/external/gpgmepp/ExternalProject_gpgmepp.mk
@@ -59,6 +59,11 @@ $(call gb_ExternalProject_get_state_target,gpgmepp,build):
 					$(gb_COMPILEROPTFLAGS),$(gb_COMPILERNOOPTFLAGS)) \
 				$(if $(ENABLE_DEBUG),$(gb_DEBUG_CFLAGS)) \
 				$(if $(filter $(true),$(gb_SYMBOL)),$(gb_DEBUGINFO_FLAGS))' \
+		   CXXFLAGS='$(CXXFLAGS) \
+				$(if $(ENABLE_OPTIMIZED), \
+					$(gb_COMPILEROPTFLAGS),$(gb_COMPILERNOOPTFLAGS)) \
+				$(if $(ENABLE_DEBUG),$(gb_DEBUG_CXXFLAGS) -D_GLIBCXX_DEBUG) \
+				$(if $(filter $(true),$(gb_SYMBOL)),$(gb_DEBUGINFO_FLAGS))' \
 		   $(if $(filter LINUX,$(OS)), \
 				'LDFLAGS=-Wl$(COMMA)-z$(COMMA)origin \
 					-Wl$(COMMA)-rpath$(COMMA)\$$$$ORIGIN') \
commit 757087a9829941bade8259673b57507d48cbdfc6
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Wed Dec 6 15:20:54 2017 +0100

    gpg4libre: add KDE4 fpicker gpg crypt chechbox
    
    Change-Id: Iba8fb0e0ac732f36cd1d880884bde1121e6b1eab

diff --git a/vcl/unx/kde4/KDE4FilePicker.cxx b/vcl/unx/kde4/KDE4FilePicker.cxx
index 7268bac1dc02..4488d04489b5 100644
--- a/vcl/unx/kde4/KDE4FilePicker.cxx
+++ b/vcl/unx/kde4/KDE4FilePicker.cxx
@@ -533,6 +533,9 @@ void KDE4FilePicker::addCustomControl(sal_Int16 controlId)
         case CHECKBOX_PASSWORD:
             resId = STR_FPICKER_PASSWORD;
             break;
+        case CHECKBOX_GPGENCRYPTION:
+            resId = STR_FPICKER_GPGENCRYPT;
+            break;
         case CHECKBOX_FILTEROPTIONS:
             resId = STR_FPICKER_FILTER_OPTIONS;
             break;
@@ -571,6 +574,7 @@ void KDE4FilePicker::addCustomControl(sal_Int16 controlId)
     {
         case CHECKBOX_AUTOEXTENSION:
         case CHECKBOX_PASSWORD:
+        case CHECKBOX_GPGENCRYPTION:
         case CHECKBOX_FILTEROPTIONS:
         case CHECKBOX_READONLY:
         case CHECKBOX_LINK:
@@ -657,6 +661,7 @@ void SAL_CALL KDE4FilePicker::initialize( const uno::Sequence<uno::Any> &args )
         {
             operationMode = KFileDialog::Saving;
             addCustomControl( CHECKBOX_PASSWORD );
+            addCustomControl( CHECKBOX_GPGENCRYPTION );
             break;
         }
         case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
@@ -664,6 +669,7 @@ void SAL_CALL KDE4FilePicker::initialize( const uno::Sequence<uno::Any> &args )
             operationMode = KFileDialog::Saving;
             addCustomControl( CHECKBOX_AUTOEXTENSION );
             addCustomControl( CHECKBOX_PASSWORD );
+            addCustomControl( CHECKBOX_GPGENCRYPTION );
             addCustomControl( CHECKBOX_FILTEROPTIONS );
             break;
         }
commit 9992fe1051d7dea3fddeb1d45b0e2a0a3f43ab08
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Mon Dec 4 02:22:09 2017 +0100

    gpg4libre: add gtk fpicker gpg crypt chechbox
    
    Change-Id: I27b494530a2b61eb37c4a9f7c3e1f9845f045e66

diff --git a/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx b/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx
index 8a71c2de712e..dfc5274bbb63 100644
--- a/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx
+++ b/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx
@@ -161,6 +161,7 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext
         switch( i ) {
         LABEL_TOGGLE( AUTOEXTENSION );
         LABEL_TOGGLE( PASSWORD );
+        LABEL_TOGGLE( GPGENCRYPTION );
         LABEL_TOGGLE( FILTEROPTIONS );
         LABEL_TOGGLE( READONLY );
         LABEL_TOGGLE( LINK );
@@ -1069,6 +1070,7 @@ GtkWidget *SalGtkFilePicker::getWidget( sal_Int16 nControlId, GType *pType )
     {
         MAP_TOGGLE( AUTOEXTENSION );
         MAP_TOGGLE( PASSWORD );
+        MAP_TOGGLE( GPGENCRYPTION );
         MAP_TOGGLE( FILTEROPTIONS );
         MAP_TOGGLE( READONLY );
         MAP_TOGGLE( LINK );
@@ -1611,12 +1613,14 @@ void SAL_CALL SalGtkFilePicker::initialize( const uno::Sequence<uno::Any>& aArgu
             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
             first_button_text = GTK_STOCK_SAVE;
             mbToggleVisibility[PASSWORD] = true;
+            mbToggleVisibility[GPGENCRYPTION] = true;
             // TODO
             break;
         case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
             first_button_text = GTK_STOCK_SAVE;
             mbToggleVisibility[PASSWORD] = true;
+            mbToggleVisibility[GPGENCRYPTION] = true;
             mbToggleVisibility[FILTEROPTIONS] = true;
             // TODO
                 break;
diff --git a/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx b/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx
index 4c24307e7fd2..1266ac5cfdd3 100644
--- a/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx
+++ b/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx
@@ -166,6 +166,7 @@ class SalGtkFilePicker : public SalGtkPicker, public SalGtkFilePicker_Base
             LINK,
             PREVIEW,
             SELECTION,
+            GPGENCRYPTION,
             TOGGLE_LAST
               };
 
diff --git a/vcl/unx/gtk/fpicker/resourceprovider.cxx b/vcl/unx/gtk/fpicker/resourceprovider.cxx
index e41c7bf5fd25..3e5469a7c392 100644
--- a/vcl/unx/gtk/fpicker/resourceprovider.cxx
+++ b/vcl/unx/gtk/fpicker/resourceprovider.cxx
@@ -38,6 +38,7 @@ static const struct
 } CtrlIdToResIdTable[] = {
     { CHECKBOX_AUTOEXTENSION,                   STR_FPICKER_AUTO_EXTENSION },
     { CHECKBOX_PASSWORD,                        STR_FPICKER_PASSWORD },
+    { CHECKBOX_GPGENCRYPTION,                   STR_FPICKER_GPGENCRYPT },
     { CHECKBOX_FILTEROPTIONS,                   STR_FPICKER_FILTER_OPTIONS },
     { CHECKBOX_READONLY,                        STR_FPICKER_READONLY },
     { CHECKBOX_LINK,                            STR_FPICKER_INSERT_AS_LINK },
commit 926dc6c984a4224cf895596504dca1a814a0cb43
Author: Thorsten Behrens <thorsten.behrens at cib.de>
Date:   Thu Nov 23 23:28:13 2017 +0100

    gpg4libre: add gpg encrypt checbox to win32 filepicker
    
    Change-Id: Ia6315e8b1f04228984afd2fbca3c059df9589497

diff --git a/fpicker/source/office/OfficeControlAccess.cxx b/fpicker/source/office/OfficeControlAccess.cxx
index 1b30f285734b..be9a91f212af 100644
--- a/fpicker/source/office/OfficeControlAccess.cxx
+++ b/fpicker/source/office/OfficeControlAccess.cxx
@@ -77,6 +77,7 @@ namespace svt
             { "FilterList",             LISTBOX_FILTER,                 PROPERTY_FLAGS_COMMON                               },
             { "FilterListLabel",        LISTBOX_FILTER_LABEL,           PROPERTY_FLAGS_COMMON | PropFlags::Text          },
             { "FilterOptionsBox",       CHECKBOX_FILTEROPTIONS,         PROPERTY_FLAGS_COMMON | PROPERTY_FLAGS_CHECKBOX     },
+            { "GpgPassword",            CHECKBOX_GPGENCRYPTION,         PROPERTY_FLAGS_COMMON | PROPERTY_FLAGS_CHECKBOX     },
             { "HelpButton",             PUSHBUTTON_HELP,                PROPERTY_FLAGS_COMMON | PropFlags::Text          },
             { "ImageTemplateList",      LISTBOX_IMAGE_TEMPLATE,         PROPERTY_FLAGS_COMMON | PROPERTY_FLAGS_LISTBOX      },
             { "ImageTemplateListLabel", LISTBOX_IMAGE_TEMPLATE_LABEL,   PROPERTY_FLAGS_COMMON | PropFlags::Text          },
diff --git a/fpicker/source/win32/filepicker/VistaFilePicker.cxx b/fpicker/source/win32/filepicker/VistaFilePicker.cxx
index 449be62fb848..54ff672579ff 100644
--- a/fpicker/source/win32/filepicker/VistaFilePicker.cxx
+++ b/fpicker/source/win32/filepicker/VistaFilePicker.cxx
@@ -396,6 +396,7 @@ void SAL_CALL VistaFilePicker::initialize(const css::uno::Sequence< css::uno::An
             bFileOpenDialog  = false;
             nFeatures        |= FEATURE_AUTOEXTENSION;
             nFeatures        |= FEATURE_PASSWORD;
+            nFeatures        |= FEATURE_GPGPASSWORD;
         }
         break;
 
@@ -405,6 +406,7 @@ void SAL_CALL VistaFilePicker::initialize(const css::uno::Sequence< css::uno::An
             nFeatures        |= FEATURE_AUTOEXTENSION;
             nFeatures        |= FEATURE_PASSWORD;
             nFeatures        |= FEATURE_FILTEROPTIONS;
+            nFeatures        |= FEATURE_GPGPASSWORD;
         }
         break;
 
diff --git a/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx b/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx
index 2b0fffe337d7..35be52b6101a 100644
--- a/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx
+++ b/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx
@@ -590,6 +590,13 @@ void VistaFilePickerImpl::impl_sta_enableFeatures(::sal_Int32 nFeatures, ::sal_I
         setLabelToControl(iCustom, nControlId);
     }
 
+    if ((nFeatures & FEATURE_GPGPASSWORD) == FEATURE_GPGPASSWORD)
+    {
+        nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION;
+        iCustom->AddCheckButton (nControlId, L"GpgPassword", false);
+        setLabelToControl(iCustom, nControlId);
+    }
+
     if ((nFeatures & FEATURE_READONLY) == FEATURE_READONLY)
     {
         nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY;
@@ -1110,6 +1117,7 @@ void VistaFilePickerImpl::impl_sta_GetControlValue(const RequestRef& rRequest)
         switch (nId)
         {
         case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
+        case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION :
         case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY :
         case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
         case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK :
diff --git a/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx b/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx
index 70272ad8c1c0..5161d787e767 100644
--- a/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx
+++ b/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx
@@ -67,6 +67,7 @@ static const ::sal_Int32 FEATURE_IMAGETEMPLATE  =  128;
 static const ::sal_Int32 FEATURE_PLAY           =  256;
 static const ::sal_Int32 FEATURE_READONLY       =  512;
 static const ::sal_Int32 FEATURE_VERSION        = 1024;
+static const ::sal_Int32 FEATURE_GPGPASSWORD    = 2048;
 
 static const OUString PROP_PICKER_LISTENER("picker_listener"   ); // [XFilePickerListenert]
 static const OUString PROP_DIALOG_SHOW_RESULT("dialog_show_result" ); // [sal_Bool] true=OK, false=CANCEL
diff --git a/fpicker/source/win32/misc/resourceprovider.cxx b/fpicker/source/win32/misc/resourceprovider.cxx
index bc9c270774b5..b7b70d4d45de 100644
--- a/fpicker/source/win32/misc/resourceprovider.cxx
+++ b/fpicker/source/win32/misc/resourceprovider.cxx
@@ -61,7 +61,8 @@ Entry const CtrlIdToResIdTable[] = {
     { LISTBOX_IMAGE_TEMPLATE_LABEL,             STR_SVT_FILEPICKER_IMAGE_TEMPLATE },
     { CHECKBOX_SELECTION,                       STR_SVT_FILEPICKER_SELECTION },
     { FOLDERPICKER_TITLE,                       STR_SVT_FOLDERPICKER_DEFAULT_TITLE },
-    { FOLDER_PICKER_DEF_DESCRIPTION,            STR_SVT_FOLDERPICKER_DEFAULT_DESCRIPTION }
+    { FOLDER_PICKER_DEF_DESCRIPTION,            STR_SVT_FOLDERPICKER_DEFAULT_DESCRIPTION },
+    { CHECKBOX_GPGENCRYPTION,                   STR_SVT_FILEPICKER_GPGENCRYPT }
 };
 
 const sal_Int32 SIZE_TABLE = SAL_N_ELEMENTS( CtrlIdToResIdTable );
commit c22236d733eff274cbd18e72109ff440177fab67
Author: Thorsten Behrens <thorsten.behrens at cib.de>
Date:   Thu Nov 23 22:18:09 2017 +0100

    gpg4libre: find keymanager executable on Windows
    
    Change-Id: If93c06ad90d708b0fbaf476bda6fdb902bd77b1e

diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index ba726e04d0a5..42ca15d05faf 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -468,9 +468,17 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void)
 
 IMPL_STATIC_LINK_NOARG(DigitalSignaturesDialog, CertMgrButtonHdl, Button*, void)
 {
-    const OUString aGUIServers[] = {  OUString("kleopatra"), OUString("seahorse"),  OUString("gpa"), OUString("kgpg") };
-    // FIXME: the same for Windows + registry search for gpg4win
+#ifdef _WIN32
+    // FIXME: call GpgME::dirInfo("bindir") somewhere in
+    // SecurityEnvironmentGpg or whatnot
+    // FIXME: perhaps poke GpgME for uiserver, and hope it returns something useful?
+    const OUString aGUIServers[] = { OUString("kleopatra.exe"), OUString("launch-gpa.exe"), OUString("gpa.exe"),
+                                     OUString("bin\\kleopatra.exe"), OUString("bin\\launch-gpa.exe"), OUString("bin\\gpa.exe") };
+    const char* cPath = "C:\\Program Files (x86)\\GNU\\GnuPG";
+#else
+    const OUString aGUIServers[] = { OUString("kleopatra"), OUString("seahorse"),  OUString("gpa"), OUString("kgpg") };
     const char* cPath = getenv("PATH");
+#endif
 
     if (cPath)
     {
commit 0a58fdfdf48ec95295eca195b07424e98381af3f
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Sun Aug 20 03:38:05 2017 +0200

    gpg4libre: [API CHANGE] add storage helper for GPG encryption data
    
    OpenPGP encryption needs to pass down slightly different meta data
    to package / zip storage.
    
    Change-Id: Idba9ad7a821cb33070cf5e5a0f79ae55db99b276

diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk
index e997bd5e6f32..4a24d65da15c 100644
--- a/comphelper/Library_comphelper.mk
+++ b/comphelper/Library_comphelper.mk
@@ -37,6 +37,7 @@ $(eval $(call gb_Library_add_defs,comphelper,\
 ))
 
 $(eval $(call gb_Library_use_externals,comphelper,\
+	gpgmepp \
     boost_headers \
     icuuc \
     icu_headers \
diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx
index 166955d3b226..a05fb1358f3f 100644
--- a/comphelper/source/misc/storagehelper.cxx
+++ b/comphelper/source/misc/storagehelper.cxx
@@ -19,6 +19,7 @@
 
 #include <com/sun/star/embed/ElementModes.hpp>
 #include <com/sun/star/embed/XEncryptionProtectedSource2.hpp>
+#include <com/sun/star/embed/XEncryptionProtectedStorage.hpp>
 #include <com/sun/star/embed/XStorage.hpp>
 #include <com/sun/star/embed/XTransactedObject.hpp>
 #include <com/sun/star/embed/StorageFactory.hpp>
@@ -43,6 +44,7 @@
 #include <rtl/random.h>
 #include <osl/time.h>
 #include <osl/diagnose.h>
+#include <sax/tools/converter.hxx>
 
 #include <ucbhelper/content.hxx>
 
@@ -50,6 +52,15 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/documentconstants.hxx>
 #include <comphelper/storagehelper.hxx>
+#include <comphelper/sequence.hxx>
+
+#if GPGME_HAVE_GPGME
+# include <gpgme.h>
+# include <context.h>
+# include <encryptionresult.h>
+# include <key.h>
+# include <data.h>
+#endif
 
 using namespace ::com::sun::star;
 
@@ -194,11 +205,21 @@ void OStorageHelper::SetCommonStorageEncryptionData(
             const uno::Reference< embed::XStorage >& xStorage,
             const uno::Sequence< beans::NamedValue >& aEncryptionData )
 {
-    uno::Reference< embed::XEncryptionProtectedSource2 > xEncrSet( xStorage, uno::UNO_QUERY );
+    uno::Reference< embed::XEncryptionProtectedStorage > xEncrSet( xStorage, uno::UNO_QUERY );
     if ( !xEncrSet.is() )
         throw io::IOException(); // TODO
 
-    xEncrSet->setEncryptionData( aEncryptionData );
+    if ( aEncryptionData.getLength() == 2 &&
+         aEncryptionData[0].Name == "GpgInfos" &&
+         aEncryptionData[1].Name == "EncryptionKey" )
+    {
+        xEncrSet->setGpgProperties(
+            aEncryptionData[0].Value.get< uno::Sequence< uno::Sequence< beans::NamedValue > > >() );
+        xEncrSet->setEncryptionData(
+            aEncryptionData[1].Value.get< uno::Sequence< beans::NamedValue > >() );
+    }
+    else
+        xEncrSet->setEncryptionData( aEncryptionData );
 }
 
 
@@ -409,6 +430,7 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreatePackageEncryptionData(
 
 uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionData()
 {
+#if GPGME_HAVE_GPGME
     // generate session key
     // --------------------
 
@@ -425,34 +447,95 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat
     rtl_random_destroyPool(aRandomPool);
 
     uno::Sequence< beans::NamedValue > aContainer(2);
-    uno::Sequence< beans::NamedValue > aGpgEncryptionData(3);
+    std::vector< uno::Sequence< beans::NamedValue > > aGpgEncryptions;
+    uno::Sequence< beans::NamedValue > aGpgEncryptionEntry(3);
     uno::Sequence< beans::NamedValue > aEncryptionData(1);
 
-    // TODO fire certificate chooser dialog
     uno::Reference< security::XDocumentDigitalSignatures > xSigner(
         security::DocumentDigitalSignatures::createWithVersion(
             comphelper::getProcessComponentContext(), "1.2" ) );
 
-    // The user may provide a description while choosing a certificate.
-    OUString aDescription;
-    uno::Reference< security::XCertificate > xSignCertificate=
-        xSigner->chooseEncryptionCertificate(aDescription);
+    // fire up certificate chooser dialog - user can multi-select!
+    uno::Sequence< uno::Reference< security::XCertificate > > xSignCertificates=
+        xSigner->chooseEncryptionCertificate();
+
+    // generate one encrypted key entry for each recipient
+    // ---------------------------------------------------
+
+    std::unique_ptr<GpgME::Context> ctx;
+    GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
+    if (err)
+        throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
+
+    ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) );
+    if (ctx == nullptr)
+        throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
+    ctx->setArmor(false);
 
-    uno::Sequence < sal_Int8 > aKeyID;
-    if (xSignCertificate.is())
+    // TODO: add self-encryption key from user config
+    const uno::Reference< security::XCertificate >* pCerts=xSignCertificates.getConstArray();
+    for (sal_uInt32 i = 0, nNum = xSignCertificates.getLength(); i < nNum; i++, pCerts++)
     {
-        aKeyID = xSignCertificate->getSHA1Thumbprint();
+        uno::Sequence < sal_Int8 > aKeyID;
+        if (pCerts->is())
+            aKeyID = (*pCerts)->getSHA256Thumbprint();
+
+        std::vector<GpgME::Key> keys;
+        keys.push_back(
+            ctx->key(
+                reinterpret_cast<const char*>(aKeyID.getConstArray()),
+                err, true));
+
+        // ctx is setup now, let's encrypt the lot!
+        GpgME::Data plain(
+            reinterpret_cast<const char*>(aVector.getConstArray()),
+            aVector.getLength(), false);
+        GpgME::Data cipher;
+
+        GpgME::EncryptionResult crypt_res = ctx->encrypt(
+            keys, plain,
+            cipher, GpgME::Context::NoCompress);
+
+        off_t result = cipher.seek(0,SEEK_SET);
+        (void) result;
+        assert(result == 0);
+        int len=0, curr=0; char buf;
+        while( (curr=cipher.read(&buf, 1)) )
+            len += curr;
+
+        if(crypt_res.error() || !len)
+            throw uno::RuntimeException("The GpgME library failed to encrypt.");
+
+        uno::Sequence < sal_Int8 > aCipherValue(len);
+        result = cipher.seek(0,SEEK_SET);
+        assert(result == 0);
+        if( cipher.read(aCipherValue.getArray(), len) != len )
+            throw uno::RuntimeException("The GpgME library failed to read the encrypted value.");
+
+        SAL_INFO("comphelper.crypto", "Generated gpg crypto of length: " << len);
+
+        aGpgEncryptionEntry[0].Name = "KeyId";
+        aGpgEncryptionEntry[0].Value <<= aKeyID;
+        aGpgEncryptionEntry[1].Name = "KeyPacket";
+        aGpgEncryptionEntry[1].Value <<= aKeyID;
+        aGpgEncryptionEntry[2].Name = "CipherValue";
+        aGpgEncryptionEntry[2].Value <<= aCipherValue;
+
+        aGpgEncryptions.push_back(aGpgEncryptionEntry);
     }
 
-    aGpgEncryptionData[0].Name = "KeyId";
-    aGpgEncryptionData[0].Value <<= aKeyID;
+    aEncryptionData[0].Name = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
+    aEncryptionData[0].Value <<= aVector;
 
     aContainer[0].Name = "GpgInfos";
-    aContainer[0].Value <<= aGpgEncryptionData;
+    aContainer[0].Value <<= comphelper::containerToSequence(aGpgEncryptions);
     aContainer[1].Name = "EncryptionKey";
     aContainer[1].Value <<= aEncryptionData;
 
     return aContainer;
+#else
+    return uno::Sequence< beans::NamedValue >();
+#endif
 }
 
 bool OStorageHelper::IsValidZipEntryFileName( const OUString& aName, bool bSlashAllowed )
diff --git a/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl b/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl
index 5ddcc6831844..ecba64d51995 100644
--- a/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl
+++ b/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl
@@ -84,6 +84,37 @@ interface XEncryptionProtectedStorage: XEncryptionProtectedSource2
     /** allows to get the encryption algorithms of the object.
      */
     sequence< ::com::sun::star::beans::NamedValue > getEncryptionAlgorithms();
+
+    /** set OpenPGP-specific encryption properties
+
+        <p>
+        When provided, switch ODF package encryption to OpenPGP.
+        </p>
+        <p>
+        For each recipient, add one sequence of named values, each of
+        the same structure. The following values could be part of that
+        provided sequence:
+        </p>
+        <dl>
+            <dt>KeyId</dt>
+            <dd>
+                    specifies OpenPGP key ID or fingerprint of the public
+                    key used to encrypt this session key against
+            </dd>
+            <dt>KeyPacket</dt>
+            <dd>
+                    (optional) public key packet of the key used to encrypt
+            </dd>
+            <dt>CipherValue</dt>
+            <dd>
+                    OpenPGP-encrypted session key for this recipient
+            </dd>
+        </dl>
+
+        @since LibreOffice 6.0
+     */
+    void setGpgProperties( [in] sequence< sequence< ::com::sun::star::beans::NamedValue > > aProps )
+        raises( ::com::sun::star::lang::IllegalArgumentException );
 };
 
 
diff --git a/package/inc/PackageConstants.hxx b/package/inc/PackageConstants.hxx
index df7bebcf6bd4..b81c0dd0a904 100644
--- a/package/inc/PackageConstants.hxx
+++ b/package/inc/PackageConstants.hxx
@@ -51,6 +51,7 @@ const sal_Int32 n_ConstDigestDecrypt = 1056; // 1024 + 32
 #define ENCRYPTION_KEY_PROPERTY "EncryptionKey"
 #define STORAGE_ENCRYPTION_KEYS_PROPERTY "StorageEncryptionKeys"
 #define ENCRYPTION_ALGORITHMS_PROPERTY "EncryptionAlgorithms"
+#define ENCRYPTION_GPG_PROPERTIES "EncryptionGpGProperties"
 #define HAS_ENCRYPTED_ENTRIES_PROPERTY "HasEncryptedEntries"
 #define HAS_NONENCRYPTED_ENTRIES_PROPERTY "HasNonEncryptedEntries"
 #define IS_INCONSISTENT_PROPERTY "IsInconsistent"
diff --git a/package/inc/ZipPackage.hxx b/package/inc/ZipPackage.hxx
index 61b0fc883575..f46eb33b0172 100644
--- a/package/inc/ZipPackage.hxx
+++ b/package/inc/ZipPackage.hxx
@@ -72,6 +72,7 @@ class ZipPackage final : public cppu::WeakImplHelper
 
     css::uno::Sequence< css::beans::NamedValue > m_aStorageEncryptionKeys;
     css::uno::Sequence< sal_Int8 > m_aEncryptionKey;
+    css::uno::Sequence< css::uno::Sequence< css::beans::NamedValue > > m_aGpgProps;
 
     FolderHash        m_aRecent;
     OUString   m_aURL;
diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx
index cbcceece39ea..66678d7c378d 100644
--- a/package/source/xstor/xstorage.cxx
+++ b/package/source/xstor/xstorage.cxx
@@ -4205,6 +4205,66 @@ void SAL_CALL OStorage::setEncryptionAlgorithms( const uno::Sequence< beans::Nam
     }
 }
 
+void SAL_CALL OStorage::setGpgProperties( const uno::Sequence< uno::Sequence< beans::NamedValue > >& aProps )
+{
+    ::osl::MutexGuard aGuard( m_pData->m_xSharedMutex->GetMutex() );
+
+    if ( !m_pImpl )
+    {
+        SAL_INFO("package.xstor", THROW_WHERE "Disposed!");
+        throw lang::DisposedException( THROW_WHERE );
+    }
+
+    if ( m_pData->m_nStorageType != embed::StorageFormats::PACKAGE )
+        throw uno::RuntimeException( THROW_WHERE ); // the interface must be visible only for package storage
+
+    if ( !aProps.getLength() )
+        throw uno::RuntimeException( THROW_WHERE "Unexpected empty encryption algorithms list!" );
+
+    SAL_WARN_IF( !m_pData->m_bIsRoot, "package.xstor", "setGpgProperties() method is not available for nonroot storages!" );
+    if ( m_pData->m_bIsRoot )
+    {
+        try {
+            m_pImpl->ReadContents();
+        }
+        catch ( const uno::RuntimeException& aRuntimeException )
+        {
+            SAL_INFO("package.xstor", "Rethrow: " << aRuntimeException.Message);
+            throw;
+        }
+        catch ( const uno::Exception& aException )
+        {
+            SAL_INFO("package.xstor", "Rethrow: " << aException.Message);
+
+            uno::Any aCaught( ::cppu::getCaughtException() );
+            throw lang::WrappedTargetRuntimeException( THROW_WHERE "Can not open package!",
+                                                static_cast< OWeakObject* >( this ),
+                                                aCaught );
+        }
+
+        uno::Reference< beans::XPropertySet > xPackPropSet( m_pImpl->m_xPackage, uno::UNO_QUERY_THROW );
+        try
+        {
+            xPackPropSet->setPropertyValue( ENCRYPTION_GPG_PROPERTIES,
+                                            uno::makeAny( aProps ) );
+        }
+        catch ( const uno::RuntimeException& aRuntimeException )
+        {
+            SAL_INFO("package.xstor", "Rethrow: " << aRuntimeException.Message);
+            throw;
+        }
+        catch( const uno::Exception& aException )
+        {
+            SAL_INFO("package.xstor", "Rethrow: " << aException.Message);
+
+            uno::Any aCaught( ::cppu::getCaughtException() );
+            throw lang::WrappedTargetRuntimeException( THROW_WHERE "Can not open package!",
+                                                static_cast< OWeakObject* >( this ),
+                                                aCaught );
+        }
+    }
+}
+
 uno::Sequence< beans::NamedValue > SAL_CALL OStorage::getEncryptionAlgorithms()
 {
     ::osl::MutexGuard aGuard( m_pData->m_xSharedMutex->GetMutex() );
diff --git a/package/source/xstor/xstorage.hxx b/package/source/xstor/xstorage.hxx
index 262b317e4def..82cffa69a2fe 100644
--- a/package/source/xstor/xstorage.hxx
+++ b/package/source/xstor/xstorage.hxx
@@ -459,6 +459,7 @@ public:
     //  XEncryptionProtectedStorage
 
     virtual void SAL_CALL setEncryptionAlgorithms( const css::uno::Sequence< css::beans::NamedValue >& aAlgorithms ) override;
+    virtual void SAL_CALL setGpgProperties( const css::uno::Sequence< css::uno::Sequence< css::beans::NamedValue > >& aCryptProps ) override;
 
     virtual css::uno::Sequence< css::beans::NamedValue > SAL_CALL getEncryptionAlgorithms() override;
 
diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx
index 7eef97c5341f..769c7f662bba 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -1208,7 +1208,9 @@ uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
 
         if ( m_nFormat == embed::StorageFormats::PACKAGE )
         {
-            uno::Sequence < PropertyValue > aPropSeq( PKG_SIZE_NOENCR_MNFST );
+            bool bIsGpgEncrypt = m_aGpgProps.hasElements();
+            uno::Sequence < PropertyValue > aPropSeq(
+                bIsGpgEncrypt ? PKG_SIZE_NOENCR_MNFST+1 : PKG_SIZE_NOENCR_MNFST );
             aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType;
             aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_xRootFolder->GetMediaType();
             aPropSeq [PKG_MNFST_VERSION].Name = sVersion;
@@ -1216,6 +1218,11 @@ uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
             aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath;
             aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString("/");
 
+            if( bIsGpgEncrypt )
+            {
+                aPropSeq[PKG_SIZE_NOENCR_MNFST].Name = "KeyInfo";
+                aPropSeq[PKG_SIZE_NOENCR_MNFST].Value <<= m_aGpgProps;
+            }
             aManList.push_back( aPropSeq );
         }
 
@@ -1751,6 +1758,22 @@ void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const
             }
         }
     }
+    else if ( aPropertyName == ENCRYPTION_GPG_PROPERTIES )
+    {
+        uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProps;
+        if ( m_pZipFile || !( aValue >>= aGpgProps ) || aGpgProps.getLength() == 0 )
+        {
+            throw IllegalArgumentException(THROW_WHERE "unexpected Gpg properties are provided.", uno::Reference< uno::XInterface >(), 2 );
+        }
+
+        m_aGpgProps = aGpgProps;
+
+        // override algorithm defaults (which are some legacy ODF
+        // defaults) with reasonable values
+        m_nStartKeyGenerationID = 0; // this is unused for PGP
+        m_nCommonEncryptionID = xml::crypto::CipherID::AES_CBC_W3C_PADDING;
+        m_nChecksumDigestID = xml::crypto::DigestID::SHA512_1K;
+    }
     else
         throw UnknownPropertyException(THROW_WHERE );
 }
commit 3f775118a6d9e6cbd49edf7d5309e29edeeaff47
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Fri Aug 18 21:34:11 2017 +0200

    gpg4libre: add manifest entries for gpg encryption
    
    Change-Id: I71bd7e2c6c73d997fa1ed5bb36fdc2873daca10c

diff --git a/package/source/manifest/ManifestDefines.hxx b/package/source/manifest/ManifestDefines.hxx
index 968aed648e6a..c68c241c7514 100644
--- a/package/source/manifest/ManifestDefines.hxx
+++ b/package/source/manifest/ManifestDefines.hxx
@@ -24,8 +24,10 @@
 #define MANIFEST_NSPREFIX "manifest:"
 #define ELEMENT_MANIFEST "manifest:manifest"
 #define ATTRIBUTE_XMLNS "xmlns:manifest"
+#define ATTRIBUTE_XMLNS_LOEXT "xmlns:loext"
 #define MANIFEST_NAMESPACE "http://openoffice.org/2001/manifest"
 #define MANIFEST_OASIS_NAMESPACE "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
+#define MANIFEST_LOEXT_NAMESPACE "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 #define MANIFEST_DOCTYPE "<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">"
 #define ATTRIBUTE_CDATA "CDATA"
 
@@ -34,6 +36,16 @@
 #define ATTRIBUTE_VERSION "manifest:version"
 #define ATTRIBUTE_MEDIA_TYPE "manifest:media-type"
 #define ATTRIBUTE_SIZE "manifest:size"
+#define ELEMENT_MANIFEST_KEYINFO "loext:keyinfo"
+#define ELEMENT_ENCRYPTED_KEYINFO "loext:KeyInfo"
+#define ELEMENT_ENCRYPTEDKEY "loext:encrypted-key"
+#define ELEMENT_ENCRYPTIONMETHOD "loext:encryption-method"
+#define ELEMENT_PGPDATA "loext:PGPData"
+#define ELEMENT_PGPKEYID "loext:PGPKeyID"
+#define ELEMENT_PGPKEYPACKET "loext:PGPKeyPacket"
+#define ATTRIBUTE_ALGORITHM "loext:PGPAlgorithm"
+#define ELEMENT_CIPHERDATA "loext:CipherData"
+#define ELEMENT_CIPHERVALUE "loext:CipherValue"
 
 #define ELEMENT_ENCRYPTION_DATA "manifest:encryption-data"
 #define ATTRIBUTE_CHECKSUM_TYPE "manifest:checksum-type"
@@ -69,6 +81,7 @@
 #define AES256_URL "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
 
 #define PBKDF2_NAME "PBKDF2"
+#define PGP_NAME "PGP"
 #define PBKDF2_URL "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0#pbkdf2"
 
 #endif
diff --git a/package/source/manifest/ManifestExport.cxx b/package/source/manifest/ManifestExport.cxx
index 60a5128e945d..5cf87334ca62 100644
--- a/package/source/manifest/ManifestExport.cxx
+++ b/package/source/manifest/ManifestExport.cxx
@@ -23,6 +23,7 @@
 #include <com/sun/star/xml/crypto/DigestID.hpp>
 #include <com/sun/star/xml/crypto/CipherID.hpp>
 #include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/uno/RuntimeException.hpp>
 
 #include "ManifestDefines.hxx"
@@ -66,11 +67,25 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
     const OUString sChecksumTypeAttribute    ( ATTRIBUTE_CHECKSUM_TYPE );
     const OUString sChecksumAttribute    ( ATTRIBUTE_CHECKSUM);
 
+    const OUString sKeyInfoElement              ( ELEMENT_ENCRYPTED_KEYINFO );
+    const OUString sManifestKeyInfoElement      ( ELEMENT_MANIFEST_KEYINFO );
+    const OUString sEncryptedKeyElement         ( ELEMENT_ENCRYPTEDKEY );
+    const OUString sEncryptionMethodElement     ( ELEMENT_ENCRYPTIONMETHOD );
+    const OUString sPgpDataElement              ( ELEMENT_PGPDATA );
+    const OUString sPgpKeyIDElement             ( ELEMENT_PGPKEYID );
+    const OUString sPGPKeyPacketElement         ( ELEMENT_PGPKEYPACKET );
+    const OUString sAlgorithmAttribute          ( ATTRIBUTE_ALGORITHM );
+    const OUString sCipherDataElement           ( ELEMENT_CIPHERDATA );
+    const OUString sCipherValueElement          ( ELEMENT_CIPHERVALUE );
+    const OUString sKeyInfo                     ( "KeyInfo" );
+    const OUString sPgpKeyIDProperty            ( "KeyId" );
+    const OUString sPgpKeyPacketProperty        ( "KeyPacket" );
+    const OUString sCipherValueProperty         ( "CipherValue" );
     const OUString sFullPathProperty     ( "FullPath" );
     const OUString sVersionProperty  ( "Version" );
     const OUString sMediaTypeProperty    ( "MediaType" );
     const OUString sIterationCountProperty   ( "IterationCount" );
-    const OUString  sDerivedKeySizeProperty  ( "DerivedKeySize" );
+    const OUString sDerivedKeySizeProperty  ( "DerivedKeySize" );
     const OUString sSaltProperty         ( "Salt" );
     const OUString sInitialisationVectorProperty( "InitialisationVector" );
     const OUString sSizeProperty         ( "Size" );
@@ -92,6 +107,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
     const OUString  sAES256_URL          ( AES256_URL );
 
     const OUString  sPBKDF2_Name         ( PBKDF2_NAME );
+    const OUString  sPGP_Name            ( PGP_NAME );
 
     ::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList;
     const uno::Sequence < beans::PropertyValue > *pSequence = rManList.getConstArray();
@@ -100,6 +116,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
     // find the mediatype of the document if any
     OUString aDocMediaType;
     OUString aDocVersion;
+    sal_Int32 nRootFolderPropIndex=-1;
     for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ )
     {
         OUString aMediaType;
@@ -130,6 +147,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
         {
             aDocMediaType = aMediaType;
             aDocVersion = aVersion;
+            nRootFolderPropIndex = nInd;
             break;
         }
     }
@@ -164,9 +182,14 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
             bAcceptNonemptyVersion = true;
             if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
             {
-                // this is ODF12 generation, let encrypted streams contain start-key-generation entry
+                // this is ODF12 or later generation, let encrypted
+                // streams contain start-key-generation entry
                 bStoreStartKeyGeneration = true;
                 pRootAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aDocVersion );
+                // plus gpg4libre extensions - loext NS for that
+                pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS_LOEXT,
+                                              sCdataAttribute,
+                                              MANIFEST_LOEXT_NAMESPACE );
             }
         }
         else
@@ -192,6 +215,116 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
     }
     xHandler->startElement( sManifestElement, xRootAttrList );
 
+    const uno::Any *pKeyInfoProperty = nullptr;
+    if ( nRootFolderPropIndex >= 0 )
+    {
+        // do we have package-wide encryption info?
+        const beans::PropertyValue *pValue =
+            pSequence[nRootFolderPropIndex].getConstArray();
+        for (sal_uInt32 j = 0, nNum = pSequence[nRootFolderPropIndex].getLength(); j < nNum; j++, pValue++)
+        {
+            if (pValue->Name == sKeyInfo )
+                pKeyInfoProperty = &pValue->Value;
+        }
+
+        if ( pKeyInfoProperty )
+        {
+            // yeah, so that goes directly below the manifest:manifest
+            // element
+            ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList;
+            uno::Reference < xml::sax::XAttributeList > xNewAttrList (pNewAttrList);
+            OUStringBuffer aBuffer;
+
+            xHandler->ignorableWhitespace ( sWhiteSpace );
+
+            // ==== manifest:keyinfo & children
+            xHandler->startElement( sManifestKeyInfoElement, nullptr );
+            xHandler->ignorableWhitespace ( sWhiteSpace );
+
+            uno::Sequence< uno::Sequence < beans::NamedValue > > aKeyInfoSequence;
+            *pKeyInfoProperty >>= aKeyInfoSequence;
+            const uno::Sequence < beans::NamedValue > *pKeyInfoSequence = aKeyInfoSequence.getConstArray();
+            const sal_uInt32 nKeyInfoLength = aKeyInfoSequence.getLength();
+            for (sal_uInt32 nInd = 0; nInd < nKeyInfoLength ; nInd++ )
+            {
+                uno::Sequence < sal_Int8 > aPgpKeyID;
+                uno::Sequence < sal_Int8 > aPgpKeyPacket;
+                uno::Sequence < sal_Int8 > aCipherValue;
+                const beans::NamedValue *pNValue = pKeyInfoSequence[nInd].getConstArray();
+                for (sal_uInt32 j = 0, nNum = pKeyInfoSequence[nInd].getLength(); j < nNum; j++, pNValue++)
+                {
+                    if (pNValue->Name == sPgpKeyIDProperty )
+                        pNValue->Value >>= aPgpKeyID;
+                    else if (pNValue->Name == sPgpKeyPacketProperty )
+                        pNValue->Value >>= aPgpKeyPacket;
+                    else if (pNValue->Name == sCipherValueProperty )
+                        pNValue->Value >>= aCipherValue;
+                }
+
+                if (aPgpKeyID.hasElements() && aCipherValue.hasElements() )
+                {
+                    // ==== manifest:encrypted-key & children - one for each recipient
+                    xHandler->startElement( sEncryptedKeyElement, nullptr );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    // TODO: the algorithm should rather be configurable
+                    pNewAttrList->AddAttribute ( sAlgorithmAttribute, sCdataAttribute,
+                                                 "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" );
+                    xHandler->startElement( sEncryptionMethodElement, xNewAttrList );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+                    xHandler->endElement( sEncryptionMethodElement );
+
+                    xHandler->startElement( sKeyInfoElement, nullptr );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->startElement( sPgpDataElement, nullptr );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->startElement( sPgpKeyIDElement, nullptr );
+                    ::sax::Converter::encodeBase64(aBuffer, aPgpKeyID);
+                    xHandler->characters( aBuffer.makeStringAndClear() );
+                    xHandler->endElement( sPgpKeyIDElement );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    // key packet is optional
+                    if (aPgpKeyPacket.hasElements())
+                    {
+                        xHandler->startElement( sPGPKeyPacketElement, nullptr );
+                        ::sax::Converter::encodeBase64(aBuffer, aPgpKeyPacket);
+                        xHandler->characters( aBuffer.makeStringAndClear() );
+                        xHandler->endElement( sPGPKeyPacketElement );
+                        xHandler->ignorableWhitespace ( sWhiteSpace );
+                    }
+
+                    xHandler->endElement( sPgpDataElement );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->endElement( sKeyInfoElement );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->startElement( sCipherDataElement, nullptr );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->startElement( sCipherValueElement, nullptr );
+                    ::sax::Converter::encodeBase64(aBuffer, aCipherValue);
+                    xHandler->characters( aBuffer.makeStringAndClear() );
+                    xHandler->endElement( sCipherValueElement );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->endElement( sCipherDataElement );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+
+                    xHandler->endElement( sEncryptedKeyElement );
+                    xHandler->ignorableWhitespace ( sWhiteSpace );
+                }
+            }
+
+            xHandler->endElement( sManifestKeyInfoElement );
+            xHandler->ignorableWhitespace ( sWhiteSpace );
+        }
+    }
+
+    // now write individual file entries
     for (sal_uInt32 i = 0 ; i < nManLength ; i++)
     {
         ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList;
@@ -314,22 +447,36 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
             pNewAttrList = new ::comphelper::AttributeList;
             xNewAttrList = pNewAttrList;
 
-            pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2_Name );
-
-            if ( bStoreStartKeyGeneration )
+            if ( pKeyInfoProperty )
             {
-                aBuffer.append( nDerivedKeySize );
-                pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+                pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute,
+                                             sCdataAttribute,
+                                             sPGP_Name );
+                // no start-key-generation needed, our session key has
+                // max size already
+                bStoreStartKeyGeneration = false;
             }
+            else
+            {
+                pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute,
+                                             sCdataAttribute,
+                                             sPBKDF2_Name );
+
+                if ( bStoreStartKeyGeneration )
+                {
+                    aBuffer.append( nDerivedKeySize );
+                    pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+                }
 
-            sal_Int32 nCount = 0;
-            *pIterationCount >>= nCount;
-            aBuffer.append (nCount);
-            pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+                sal_Int32 nCount = 0;
+                *pIterationCount >>= nCount;
+                aBuffer.append (nCount);
+                pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
 
-            *pSalt >>= aSequence;
-            ::sax::Converter::encodeBase64(aBuffer, aSequence);
-            pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+                *pSalt >>= aSequence;
+                ::sax::Converter::encodeBase64(aBuffer, aSequence);
+                pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() );
+            }
 
             xHandler->ignorableWhitespace ( sWhiteSpace );
             xHandler->startElement( sKeyDerivationElement , xNewAttrList);


More information about the Libreoffice-commits mailing list