bin/lo-all-static-libs                                                         
 |    1 
 
external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch 
|   32 +++
 external/argon2/UnpackedTarball_argon2.mk                                      
 |    6 
 offapi/UnoApi_offapi.mk                                                        
 |    1 
 offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl                      
 |    8 
 offapi/com/sun/star/xml/crypto/KDFID.idl                                       
 |   47 +++++
 package/Library_package2.mk                                                    
 |    1 
 package/inc/EncryptedDataHeader.hxx                                            
 |    9 
 package/inc/EncryptionData.hxx                                                 
 |   10 -
 package/inc/PackageConstants.hxx                                               
 |    5 
 package/inc/ZipPackage.hxx                                                     
 |    1 
 package/inc/ZipPackageEntry.hxx                                                
 |    5 
 package/inc/ZipPackageFolder.hxx                                               
 |    6 
 package/inc/ZipPackageStream.hxx                                               
 |   14 +
 package/source/manifest/ManifestDefines.hxx                                    
 |    5 
 package/source/manifest/ManifestExport.cxx                                     
 |   43 +++-
 package/source/manifest/ManifestImport.cxx                                     
 |   47 ++++-
 package/source/zipapi/XUnbufferedStream.cxx                                    
 |    2 
 package/source/zipapi/ZipFile.cxx                                              
 |   94 +++++++++-
 package/source/zippackage/ZipPackage.cxx                                       
 |   77 +++++++-
 package/source/zippackage/ZipPackageFolder.cxx                                 
 |   20 +-
 package/source/zippackage/ZipPackageStream.cxx                                 
 |   56 ++++-
 sfx2/source/doc/objstor.cxx                                                    
 |    8 
 23 files changed, 428 insertions(+), 70 deletions(-)

New commits:
commit 4995e0669da0e499743b21c60da1ca8b14a1c78c
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Dec 19 19:13:00 2023 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Dec 20 22:23:20 2023 +0100

    tdf#105844 offapi,package,sfx2: use Argon2 for wholesome ODF encryption
    
    https://www.rfc-editor.org/rfc/rfc9106.html
    
    * add css::xml::crypto::KDFID constant group
    * add "KeyDerivationFunction" to setEncryptionAlgorithms sequence
    * Argon2 is used by default for wholesome ODF encryption, but
      $LO_ARGON2_DISABLE can be set to use PBKDF2
    * extend various structs in package
    * use 3 new ODF attributes "loext:argon2-iterations" "loext:argon2-memory"
      "loext:argon2-lanes" to store the arguments
    * use this URL for now:
      "urn:org:documentfoundation:names:experimental:office:manifest:argon2id"
    * use default arguments according to second recommendation from "7.4.
      Recommendations" of RFC9106; 64 MiB RAM should hopefully not be too
      much even for 32 bit builds
    
    Change-Id: I683118cc5e0706bd6544db6fb909096768ac9920
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161009
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 2f512aaa6c39390a5a0eb1d1e37f070127d068a4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161024

diff --git a/bin/lo-all-static-libs b/bin/lo-all-static-libs
index 009ddce23730..dd85567f188d 100755
--- a/bin/lo-all-static-libs
+++ b/bin/lo-all-static-libs
@@ -110,6 +110,7 @@ echo $INSTDIR/$LIBO_LIB_FOLDER/lib*.a \
      $foolibs \
      $WORKDIR/LinkTarget/StaticLibrary/lib*.a \
      $oslibs \
+     $WORKDIR/UnpackedTarball/argon2/libargon2.a \
      $WORKDIR/UnpackedTarball/icu/source/lib/*.a \
      $WORKDIR/UnpackedTarball/liblangtag/liblangtag/.libs/*.a \
      $WORKDIR/UnpackedTarball/lcms2/src/.libs/*.a \
diff --git 
a/external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch
 
b/external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch
new file mode 100644
index 000000000000..538b41e3ec9f
--- /dev/null
+++ 
b/external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch
@@ -0,0 +1,32 @@
+From 48829f87ebafbb9938d23a8f0bff4d11d770690e Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <p...@pks.im>
+Date: Thu, 20 Feb 2020 17:37:32 +0100
+Subject: [PATCH] Fix possible compiler error due to undefined _MSC_VER
+
+In order to determine how to set up the ARGON2_PUBLIC and ARGON2_LOCAL
+macros, we check for various different environments via preprocessor
+defines. For Microsoft Visual Studio, we check that the macro _MSC_VER
+evaluates to non-zero via `#elif _MSC_VER`. This may raise a compile
+error when compiling with "-Werror=undef" if the variable isn't defined.
+
+Fix the issue by using `#elif defined(_MSC_VER)` instead.
+---
+ include/argon2.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/argon2.h b/include/argon2.h
+index fc8682c..1b471f6 100644
+--- a/include/argon2.h
++++ b/include/argon2.h
+@@ -30,7 +30,7 @@ extern "C" {
+ #ifdef A2_VISCTL
+ #define ARGON2_PUBLIC __attribute__((visibility("default")))
+ #define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
+-#elif _MSC_VER
++#elif defined(_MSC_VER)
+ #define ARGON2_PUBLIC __declspec(dllexport)
+ #define ARGON2_LOCAL
+ #else
+-- 
+2.43.0
+
diff --git a/external/argon2/UnpackedTarball_argon2.mk 
b/external/argon2/UnpackedTarball_argon2.mk
index 1d314cfb08d9..0b35c2f58caf 100644
--- a/external/argon2/UnpackedTarball_argon2.mk
+++ b/external/argon2/UnpackedTarball_argon2.mk
@@ -11,4 +11,10 @@ $(eval $(call gb_UnpackedTarball_UnpackedTarball,argon2))
 
 $(eval $(call gb_UnpackedTarball_set_tarball,argon2,$(ARGON2_TARBALL)))
 
+$(eval $(call gb_UnpackedTarball_set_patchlevel,argon2,1))
+
+$(eval $(call gb_UnpackedTarball_add_patches,argon2,\
+       
external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch 
\
+))
+
 # vim: set noet sw=4 ts=4:
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 2e2ee40aa8b4..186c68d500fb 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -4276,6 +4276,7 @@ $(eval $(call 
gb_UnoApi_add_idlfiles,offapi,com/sun/star/xml,\
 $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/xml/crypto,\
        CipherID \
        DigestID \
+       KDFID \
        SecurityOperationStatus \
        XCertificateCreator \
        XCipherContext \
diff --git a/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl 
b/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl
index 71c5695f482f..da14714c6223 100644
--- a/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl
+++ b/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl
@@ -48,6 +48,14 @@ interface XEncryptionProtectedStorage: 
XEncryptionProtectedSource2
                     error; it should take values from
                     com::sun::star::xml:crypto::DigestID.
             </dd>
+            <dt>KeyDerivationFunction</dt>
+            <dd>
+                    specifies the algorithm that was used to derive the
+                    encryption key from the password; it is applied to
+                    the result of the StartKeyGenerationAlgorithm;
+                    it should take values from
+                    com::sun::star::xml:crypto::KDFID.
+            </dd>
             <dt>EncryptionAlgorithm</dt>
             <dd>
                     specifies the algorithm that should be used to
diff --git a/offapi/com/sun/star/xml/crypto/KDFID.idl 
b/offapi/com/sun/star/xml/crypto/KDFID.idl
new file mode 100644
index 000000000000..dc58e6b7463e
--- /dev/null
+++ b/offapi/com/sun/star/xml/crypto/KDFID.idl
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+module com { module sun { module star { module xml { module crypto {
+
+/** Constants to identify Key Derivation Function
+    @since LibreOffice 24.2
+ */
+constants KDFID
+{
+    /** PBKDF2
+
+        Derive key material from password. When used with ODF, the
+        "StartKeyGenerationAlgorithm" is applied to the password and the
+        result is passed to KDF.
+     */
+    const long PBKDF2 = 1;
+
+    /** OpenPGP/GnuPG
+
+        Of course this is public key encryption, but it does produce
+        key material for symmetric encryption. When used with ODF, the
+        "StartKeyGenerationAlgorithm" digest is not used, as the input
+        is not a password.
+     */
+    const long PGP_RSA_OAEP_MGF1P = 2;
+
+    /** Argon2id
+
+        Derive key material from password. When used with ODF, the
+        "StartKeyGenerationAlgorithm" is applied to the password and the
+        result is passed to KDF.
+
+        @see https://www.rfc-editor.org/rfc/rfc9106.html
+     */
+    const long Argon2id = 3;
+};
+
+}; }; }; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/package/Library_package2.mk b/package/Library_package2.mk
index 6f29bf002a6b..2ddbc31caf85 100644
--- a/package/Library_package2.mk
+++ b/package/Library_package2.mk
@@ -42,6 +42,7 @@ $(eval $(call gb_Library_use_libraries,package2,\
 
 $(eval $(call gb_Library_use_externals,package2,\
        boost_headers \
+       argon2 \
        zlib \
 ))
 
diff --git a/package/inc/EncryptedDataHeader.hxx 
b/package/inc/EncryptedDataHeader.hxx
index 6860c50abb48..2f92dea60a28 100644
--- a/package/inc/EncryptedDataHeader.hxx
+++ b/package/inc/EncryptedDataHeader.hxx
@@ -25,7 +25,10 @@
 
    Header signature  4 bytes
    Version number    2 bytes
-   Iteration count   4 bytes
+   PBKDF2 Iteration count   4 bytes
+   Argon2 t_cost     4 bytes
+   Argon2 m_cost     4 bytes
+   Argon2 lanes      4 bytes
    Size              4 bytes
    EncAlgorithm      4 bytes
    DigestAlgorithm   4 bytes
@@ -43,8 +46,8 @@
 */
 const sal_uInt32 n_ConstHeader = 0x05024d4dL; // "MM"
 const sal_Int32 n_ConstHeaderSize
-    = 38; // + salt length + iv length + digest length + mediatype length
-const sal_Int16 n_ConstCurrentVersion = 1;
+    = 50; // + salt length + iv length + digest length + mediatype length
+const sal_Int16 n_ConstCurrentVersion = 2;
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/package/inc/EncryptionData.hxx b/package/inc/EncryptionData.hxx
index f2d5c0b126b0..b505b9c2277a 100644
--- a/package/inc/EncryptionData.hxx
+++ b/package/inc/EncryptionData.hxx
@@ -23,6 +23,7 @@
 #include <cppuhelper/weak.hxx>
 
 #include <optional>
+#include <tuple>
 
 class BaseEncryptionData : public cppu::OWeakObject
 {
@@ -30,17 +31,20 @@ public:
     css::uno::Sequence< sal_Int8 > m_aSalt;
     css::uno::Sequence< sal_Int8 > m_aInitVector;
     css::uno::Sequence< sal_Int8 > m_aDigest;
-    sal_Int32 m_nIterationCount;
+    ::std::optional<sal_Int32> m_oPBKDFIterationCount;
+    ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> 
m_oArgon2Args;
 
     BaseEncryptionData()
-    : m_nIterationCount ( 0 ){}
+    {
+    }
 
     BaseEncryptionData( const BaseEncryptionData& aData )
     : cppu::OWeakObject()
     , m_aSalt( aData.m_aSalt )
     , m_aInitVector( aData.m_aInitVector )
     , m_aDigest( aData.m_aDigest )
-    , m_nIterationCount( aData.m_nIterationCount )
+    , m_oPBKDFIterationCount(aData.m_oPBKDFIterationCount)
+    , m_oArgon2Args(aData.m_oArgon2Args)
     {}
 };
 
diff --git a/package/inc/PackageConstants.hxx b/package/inc/PackageConstants.hxx
index 31c0928e3c30..ce89204b4348 100644
--- a/package/inc/PackageConstants.hxx
+++ b/package/inc/PackageConstants.hxx
@@ -31,6 +31,7 @@ const sal_Int32 n_ConstDigestLength = 1024;
 const sal_Int32 n_ConstDigestDecrypt = 1056; // 1024 + 32
 
 // the constants related to the manifest.xml entries
+// these primarily exist so that ManifestImport can directly write into 
Sequence
 #define PKG_MNFST_FULLPATH 0 //FullPath (Put full-path property first for MBA)
 #define PKG_MNFST_VERSION 1 //Version
 #define PKG_MNFST_MEDIATYPE 2 //MediaType
@@ -44,9 +45,11 @@ const sal_Int32 n_ConstDigestDecrypt = 1056; // 1024 + 32
 #define PKG_MNFST_STARTALG 9 //StartKeyAlgorithm
 #define PKG_MNFST_DIGESTALG 10 //DigestAlgorithm
 #define PKG_MNFST_DERKEYSIZE 11 //DerivedKeySize
+#define PKG_MNFST_KDF 12 // KeyDerivationFunction
+#define PKG_MNFST_ARGON2ARGS 13 // Argon2 arguments
 
 #define PKG_SIZE_NOENCR_MNFST 3
-#define PKG_SIZE_ENCR_MNFST 12
+#define PKG_SIZE_ENCR_MNFST 14 // max size
 
 // the properties related constants
 inline constexpr OUString ENCRYPTION_KEY_PROPERTY = u"EncryptionKey"_ustr;
diff --git a/package/inc/ZipPackage.hxx b/package/inc/ZipPackage.hxx
index 5d196fe7cdaa..dbfbfe1bc17d 100644
--- a/package/inc/ZipPackage.hxx
+++ b/package/inc/ZipPackage.hxx
@@ -79,6 +79,7 @@ class ZipPackage final : public cppu::WeakImplHelper
 
     sal_Int32         m_nStartKeyGenerationID;
     ::std::optional<sal_Int32> m_oChecksumDigestID;
+    sal_Int32         m_nKeyDerivationFunctionID;
     sal_Int32         m_nCommonEncryptionID;
     bool          m_bHasEncryptedEntries;
     bool          m_bHasNonEncryptedEntries;
diff --git a/package/inc/ZipPackageEntry.hxx b/package/inc/ZipPackageEntry.hxx
index 27ad017aa859..f25cdc19bdc9 100644
--- a/package/inc/ZipPackageEntry.hxx
+++ b/package/inc/ZipPackageEntry.hxx
@@ -29,6 +29,8 @@
 #include <cppuhelper/implbase.hxx>
 
 #include <vector>
+#include <optional>
+#include <tuple>
 
 typedef void* rtlRandomPool;
 class ZipOutputStream;
@@ -66,7 +68,8 @@ public:
                             std::vector < css::uno::Sequence < 
css::beans::PropertyValue > > &rManList,
                             ZipOutputStream & rZipOut,
                             const css::uno::Sequence < sal_Int8 >& 
rEncryptionKey,
-                            sal_Int32 nPBKDF2IterationCount,
+                            ::std::optional<sal_Int32> oPBKDF2IterationCount,
+                            ::std::optional<::std::tuple<sal_Int32, sal_Int32, 
sal_Int32>> oArgon2Args,
                             const rtlRandomPool &rRandomPool ) = 0;
 
     void clearParent()
diff --git a/package/inc/ZipPackageFolder.hxx b/package/inc/ZipPackageFolder.hxx
index edc46e9c386b..2b1b98191302 100644
--- a/package/inc/ZipPackageFolder.hxx
+++ b/package/inc/ZipPackageFolder.hxx
@@ -98,7 +98,8 @@ public:
                             std::vector < css::uno::Sequence < 
css::beans::PropertyValue > > &rManList,
                             ZipOutputStream & rZipOut,
                             const css::uno::Sequence < sal_Int8 >& 
rEncryptionKey,
-                            sal_Int32 nPBKDF2IterationCount,
+                            ::std::optional<sal_Int32> oPBKDF2IterationCount,
+                            ::std::optional<::std::tuple<sal_Int32, sal_Int32, 
sal_Int32>> oArgon2Args,
                             const rtlRandomPool &rRandomPool ) override;
 
     // Recursive functions
@@ -108,7 +109,8 @@ public:
             std::vector < css::uno::Sequence < css::beans::PropertyValue > > 
&rManList,
             ZipOutputStream & rZipOut,
             const css::uno::Sequence< sal_Int8 > &rEncryptionKey,
-            sal_Int32 nPBKDF2IterationCount,
+            ::std::optional<sal_Int32> oPBKDF2IterationCount,
+            ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> 
oArgon2Args,
             const rtlRandomPool & rRandomPool) const;
 
     // XNameContainer
diff --git a/package/inc/ZipPackageStream.hxx b/package/inc/ZipPackageStream.hxx
index b39c59e633e9..0cb52e88c892 100644
--- a/package/inc/ZipPackageStream.hxx
+++ b/package/inc/ZipPackageStream.hxx
@@ -29,7 +29,6 @@
 
 #include "EncryptionData.hxx"
 
-#include <optional>
 
 #define PACKAGE_STREAM_NOTSET           0
 #define PACKAGE_STREAM_PACKAGEMEMBER    1
@@ -115,8 +114,14 @@ public:
     { m_xBaseEncryptionData->m_aSalt = rNewSalt;}
     void setDigest (const css::uno::Sequence < sal_Int8 >& rNewDigest )
     { m_xBaseEncryptionData->m_aDigest = rNewDigest;}
-    void setIterationCount (const sal_Int32 nNewCount)
-    { m_xBaseEncryptionData->m_nIterationCount = nNewCount;}
+    void setIterationCount(::std::optional<sal_Int32> const oNewCount)
+    {
+        m_xBaseEncryptionData->m_oPBKDFIterationCount = oNewCount;
+    }
+    void setArgon2Args(::std::optional<::std::tuple<sal_Int32, sal_Int32, 
sal_Int32>> const oArgon2Args)
+    {
+        m_xBaseEncryptionData->m_oArgon2Args = oArgon2Args;
+    }
     void setSize (const sal_Int64 nNewSize);
 
     ZipPackageStream( ZipPackage & rNewPackage,
@@ -133,7 +138,8 @@ public:
                             std::vector < css::uno::Sequence < 
css::beans::PropertyValue > > &rManList,
                             ZipOutputStream & rZipOut,
                             const css::uno::Sequence < sal_Int8 >& 
rEncryptionKey,
-                            sal_Int32 nPBKDF2IterationCount,
+                            ::std::optional<sal_Int32> oPBKDF2IterationCount,
+                            ::std::optional<::std::tuple<sal_Int32, sal_Int32, 
sal_Int32>> oArgon2Args,
                             const rtlRandomPool &rRandomPool ) override;
 
     void setZipEntryOnLoading( const ZipEntry &rInEntry);
diff --git a/package/source/manifest/ManifestDefines.hxx 
b/package/source/manifest/ManifestDefines.hxx
index ae2095f5aab5..dbe7b985b8c0 100644
--- a/package/source/manifest/ManifestDefines.hxx
+++ b/package/source/manifest/ManifestDefines.hxx
@@ -70,6 +70,9 @@ inline constexpr OUString ELEMENT_KEY_DERIVATION = 
u"manifest:key-derivation"_us
 inline constexpr OUString ATTRIBUTE_KEY_DERIVATION_NAME  = 
u"manifest:key-derivation-name"_ustr;
 inline constexpr OUString ATTRIBUTE_SALT  = u"manifest:salt"_ustr;
 inline constexpr OUString ATTRIBUTE_ITERATION_COUNT = 
u"manifest:iteration-count"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_T_LO= 
u"loext:argon2-iterations"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_M_LO= u"loext:argon2-memory"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_P_LO= u"loext:argon2-lanes"_ustr;
 
 /// OFFICE-3708: wrong URL cited in ODF 1.2 and used since OOo 3.4 beta
 inline constexpr OUString SHA256_URL_ODF12 = 
u"http://www.w3.org/2000/09/xmldsig#sha256"_ustr;
@@ -93,5 +96,7 @@ inline constexpr OUString AESGCM256_URL = 
u"http://www.w3.org/2009/xmlenc11#aes2
 inline constexpr OUString PBKDF2_NAME = u"PBKDF2"_ustr;
 inline constexpr OUString PGP_NAME = u"PGP"_ustr;
 inline constexpr OUString PBKDF2_URL = 
u"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0#pbkdf2"_ustr;
+inline constexpr OUString ARGON2ID_URL = 
u"urn:oasis:names:tc:opendocument:xmlns:manifest:1.5#argon2id"_ustr;
+inline constexpr OUString ARGON2ID_URL_LO = 
u"urn:org:documentfoundation:names:experimental:office:manifest:argon2id"_ustr;
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/package/source/manifest/ManifestExport.cxx 
b/package/source/manifest/ManifestExport.cxx
index a15ae0118277..ba6dd79b5dd0 100644
--- a/package/source/manifest/ManifestExport.cxx
+++ b/package/source/manifest/ManifestExport.cxx
@@ -20,6 +20,7 @@
 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
 #include <com/sun/star/xml/crypto/CipherID.hpp>
+#include <com/sun/star/xml/crypto/KDFID.hpp>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/uno/RuntimeException.hpp>
@@ -317,6 +318,8 @@ ManifestExport::ManifestExport( uno::Reference< 
xml::sax::XDocumentHandler > con
         OUString fullPath;
         OUString aString;
         const uno::Any *pVector = nullptr, *pSalt = nullptr, *pIterationCount 
= nullptr, *pDigest = nullptr, *pDigestAlg = nullptr, *pEncryptAlg = nullptr, 
*pStartKeyAlg = nullptr, *pDerivedKeySize = nullptr;
+        uno::Any const* pKDF = nullptr;
+        uno::Any const* pArgon2Args = nullptr;
         for (const beans::PropertyValue& rValue : rSequence)
         {
             if (rValue.Name == sMediaTypeProperty )
@@ -358,6 +361,11 @@ ManifestExport::ManifestExport( uno::Reference< 
xml::sax::XDocumentHandler > con
                 pStartKeyAlg = &rValue.Value;
             else if (rValue.Name == sDerivedKeySizeProperty )
                 pDerivedKeySize = &rValue.Value;
+            else if (rValue.Name == "KeyDerivationFunction") {
+                pKDF = &rValue.Value;
+            } else if (rValue.Name == "Argon2Args") {
+                pArgon2Args = &rValue.Value;
+            }
         }
         assert(!fullPath.isEmpty());
         if (isWholesomeEncryption)
@@ -367,7 +375,9 @@ ManifestExport::ManifestExport( uno::Reference< 
xml::sax::XDocumentHandler > con
 
         xHandler->ignorableWhitespace ( sWhiteSpace );
         xHandler->startElement( ELEMENT_FILE_ENTRY , pAttrList);
-        if (pVector && pSalt && pIterationCount && pEncryptAlg && pStartKeyAlg 
&& pDerivedKeySize)
+        if (pVector && pEncryptAlg && pDerivedKeySize && pKDF
+            && ((pSalt && pStartKeyAlg && (pIterationCount || pArgon2Args))
+                || pKeyInfoProperty))
         {
             // ==== Encryption Data
             rtl::Reference<::comphelper::AttributeList> pNewAttrList = new 
::comphelper::AttributeList;
@@ -487,13 +497,35 @@ ManifestExport::ManifestExport( uno::Reference< 
xml::sax::XDocumentHandler > con
 
             if (pKeyInfoProperty)
             {
+                assert(pKDF->get<sal_Int32>() == 
xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P);
                 pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
                                            sPGP_Name);
             }
             else
             {
-                pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
-                                           sPBKDF2_Name);
+                if (pKDF->get<sal_Int32>() == xml::crypto::KDFID::Argon2id)
+                {
+                    pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
+                                               ARGON2ID_URL_LO);
+
+                    uno::Sequence<sal_Int32> args;
+                    *pArgon2Args >>= args;
+                    assert(args.getLength() == 3);
+                    pNewAttrList->AddAttribute(ATTRIBUTE_ARGON2_T_LO, 
OUString::number(args[0]));
+                    pNewAttrList->AddAttribute(ATTRIBUTE_ARGON2_M_LO, 
OUString::number(args[1]));
+                    pNewAttrList->AddAttribute(ATTRIBUTE_ARGON2_P_LO, 
OUString::number(args[2]));
+                }
+                else
+                {
+                    assert(pKDF->get<sal_Int32>() == 
xml::crypto::KDFID::PBKDF2);
+                    pNewAttrList->AddAttribute(ATTRIBUTE_KEY_DERIVATION_NAME,
+                                               sPBKDF2_Name);
+
+                    sal_Int32 nCount = 0;
+                    *pIterationCount >>= nCount;
+                    aBuffer.append(nCount);
+                    pNewAttrList->AddAttribute(ATTRIBUTE_ITERATION_COUNT, 
aBuffer.makeStringAndClear());
+                }
 
                 if (bStoreStartKeyGeneration)
                 {
@@ -501,11 +533,6 @@ ManifestExport::ManifestExport( uno::Reference< 
xml::sax::XDocumentHandler > con
                     pNewAttrList->AddAttribute ( ATTRIBUTE_KEY_SIZE, 
aBuffer.makeStringAndClear() );
                 }
 
-                sal_Int32 nCount = 0;
-                *pIterationCount >>= nCount;
-                aBuffer.append(nCount);
-                pNewAttrList->AddAttribute ( ATTRIBUTE_ITERATION_COUNT, 
aBuffer.makeStringAndClear() );
-
                 *pSalt >>= aSequence;
                 ::comphelper::Base64::encode(aBuffer, aSequence);
                 pNewAttrList->AddAttribute ( ATTRIBUTE_SALT, 
aBuffer.makeStringAndClear() );
diff --git a/package/source/manifest/ManifestImport.cxx 
b/package/source/manifest/ManifestImport.cxx
index 0458eb9c4b8e..f0f2b8841a5e 100644
--- a/package/source/manifest/ManifestImport.cxx
+++ b/package/source/manifest/ManifestImport.cxx
@@ -25,6 +25,7 @@
 #include <com/sun/star/xml/sax/XAttributeList.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
 #include <com/sun/star/xml/crypto/CipherID.hpp>
+#include <com/sun/star/xml/crypto/KDFID.hpp>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <comphelper/base64.hxx>
 #include <comphelper/sequence.hxx>
@@ -189,7 +190,6 @@ void ManifestImport::doAlgorithm(StringHashMap 
&rConvertedAttribs)
         aSequence[PKG_MNFST_ENCALG].Name = gsEncryptionAlgProperty;
         aSequence[PKG_MNFST_ENCALG].Value <<= 
xml::crypto::CipherID::AES_GCM_W3C;
         SAL_INFO_IF(nDerivedKeySize != 0 && nDerivedKeySize != 32, 
"package.manifest", "Unexpected derived key length!");
-        SAL_WARN_IF(nDerivedKeySize != 0 && nDerivedKeySize != 32, 
"package.manifest", "Unexpected derived key length!");
         nDerivedKeySize = 32;
     } else if (aString == AESGCM192_URL) {
         aSequence[PKG_MNFST_ENCALG].Name = gsEncryptionAlgProperty;
@@ -234,17 +234,46 @@ void ManifestImport::doKeyDerivation(StringHashMap 
&rConvertedAttribs)
         return;
 
     OUString aString = rConvertedAttribs[ATTRIBUTE_KEY_DERIVATION_NAME];
-    if ( aString == PBKDF2_NAME || aString == PBKDF2_URL ) {
+    if (aString == PBKDF2_NAME || aString == PBKDF2_URL
+        || aString == ARGON2ID_URL || aString == ARGON2ID_URL_LO)
+    {
+        aSequence[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
+        if (aString == ARGON2ID_URL || aString == ARGON2ID_URL_LO)
+        {
+            aSequence[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::Argon2id;
+
+            aString = rConvertedAttribs[ATTRIBUTE_ARGON2_T_LO];
+            sal_Int32 const t(aString.toInt32());
+            aString = rConvertedAttribs[ATTRIBUTE_ARGON2_M_LO];
+            sal_Int32 const m(aString.toInt32());
+            aString = rConvertedAttribs[ATTRIBUTE_ARGON2_P_LO];
+            sal_Int32 const p(aString.toInt32());
+            if (0 < t && 0 < m && 0 < p)
+            {
+                aSequence[PKG_MNFST_ARGON2ARGS].Name = "Argon2Args";
+                aSequence[PKG_MNFST_ARGON2ARGS].Value <<= uno::Sequence{t,m,p};
+            }
+            else
+            {
+                SAL_INFO("package.manifest", "invalid argon2 arguments");
+                bIgnoreEncryptData = true;
+            }
+        }
+        else
+        {
+            aSequence[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::PBKDF2;
+
+            aString = rConvertedAttribs[ATTRIBUTE_ITERATION_COUNT];
+            aSequence[PKG_MNFST_ITERATION].Name = gsIterationCountProperty;
+            aSequence[PKG_MNFST_ITERATION].Value <<= aString.toInt32();
+        }
+
         aString = rConvertedAttribs[ATTRIBUTE_SALT];
         uno::Sequence < sal_Int8 > aDecodeBuffer;
         ::comphelper::Base64::decode(aDecodeBuffer, aString);
         aSequence[PKG_MNFST_SALT].Name = gsSaltProperty;
         aSequence[PKG_MNFST_SALT].Value <<= aDecodeBuffer;
 
-        aString = rConvertedAttribs[ATTRIBUTE_ITERATION_COUNT];
-        aSequence[PKG_MNFST_ITERATION].Name = gsIterationCountProperty;
-        aSequence[PKG_MNFST_ITERATION].Value <<= aString.toInt32();
-
         aString = rConvertedAttribs[ATTRIBUTE_KEY_SIZE];
         if ( aString.getLength() ) {
             sal_Int32 nKey = aString.toInt32();
@@ -258,8 +287,12 @@ void ManifestImport::doKeyDerivation(StringHashMap 
&rConvertedAttribs)
         aSequence[PKG_MNFST_DERKEYSIZE].Name = gsDerivedKeySizeProperty;
         aSequence[PKG_MNFST_DERKEYSIZE].Value <<= nDerivedKeySize;
     } else if ( bPgpEncryption ) {
-        if ( aString != "PGP" )
+        if (aString == "PGP") {
+            aSequence[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
+            aSequence[PKG_MNFST_KDF].Value <<= 
xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P;
+        } else {
             bIgnoreEncryptData = true;
+        }
     } else
         bIgnoreEncryptData = true;
 }
diff --git a/package/source/zipapi/XUnbufferedStream.cxx 
b/package/source/zipapi/XUnbufferedStream.cxx
index 350f142c25ba..8b628b14ddfe 100644
--- a/package/source/zipapi/XUnbufferedStream.cxx
+++ b/package/source/zipapi/XUnbufferedStream.cxx
@@ -85,7 +85,7 @@ XUnbufferedStream::XUnbufferedStream(
         throw ZipIOException("Integer-overflow");
 
     bool bHaveEncryptData = rData.is() && rData->m_aInitVector.hasElements() &&
-        ((rData->m_aSalt.hasElements() && rData->m_nIterationCount != 0)
+        ((rData->m_aSalt.hasElements() && (rData->m_oPBKDFIterationCount || 
rData->m_oArgon2Args))
          ||
          rData->m_aKey.hasElements());
     bool bMustDecrypt = nStreamMode == UNBUFF_STREAM_DATA && bHaveEncryptData 
&& bIsEncrypted;
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index bdcd8610be60..6137e3a0bb0a 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -34,6 +34,7 @@
 #include <comphelper/bytereader.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/processfactory.hxx>
+#include <comphelper/threadpool.hxx>
 #include <rtl/digest.h>
 #include <sal/log.hxx>
 #include <o3tl/safeint.hxx>
@@ -44,6 +45,8 @@
 #include <utility>
 #include <vector>
 
+#include <argon2.h>
+
 #include "blowfishcontext.hxx"
 #include "sha1context.hxx"
 #include <ZipFile.hxx>
@@ -173,20 +176,52 @@ uno::Reference< xml::crypto::XCipherContext > 
ZipFile::StaticGetCipher( const un
     }
 
     uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize 
);
-    if ( !xEncryptionData->m_nIterationCount &&
-         xEncryptionData->m_nDerivedKeySize == 
xEncryptionData->m_aKey.getLength() )
+    if (!xEncryptionData->m_oPBKDFIterationCount && 
!xEncryptionData->m_oArgon2Args
+        && xEncryptionData->m_nDerivedKeySize == 
xEncryptionData->m_aKey.getLength())
     {
         // gpg4libre: no need to derive key, m_aKey is already
         // usable as symmetric session key
         aDerivedKey = xEncryptionData->m_aKey;
     }
+    else if (xEncryptionData->m_oArgon2Args)
+    {
+        // apparently multiple lanes cannot be processed in parallel (the
+        // implementation will clamp), but it doesn't make sense to have more
+        // threads than CPUs
+        uint32_t const 
threads(::comphelper::ThreadPool::getPreferredConcurrency());
+        // need to use context to set a fixed version
+        argon2_context context = {
+            .out = reinterpret_cast<uint8_t *>(aDerivedKey.getArray()),
+            .outlen = 
::sal::static_int_cast<uint32_t>(aDerivedKey.getLength()),
+            .pwd = reinterpret_cast<uint8_t 
*>(xEncryptionData->m_aKey.getArray()),
+            .pwdlen = 
::sal::static_int_cast<uint32_t>(xEncryptionData->m_aKey.getLength()),
+            .salt = reinterpret_cast<uint8_t 
*>(xEncryptionData->m_aSalt.getArray()),
+            .saltlen = 
::sal::static_int_cast<uint32_t>(xEncryptionData->m_aSalt.getLength()),
+            .secret = nullptr, .secretlen = 0,
+            .ad = nullptr, .adlen = 0,
+            .t_cost = 
::sal::static_int_cast<uint32_t>(::std::get<0>(*xEncryptionData->m_oArgon2Args)),
+            .m_cost = 
::sal::static_int_cast<uint32_t>(::std::get<1>(*xEncryptionData->m_oArgon2Args)),
+            .lanes = 
::sal::static_int_cast<uint32_t>(::std::get<2>(*xEncryptionData->m_oArgon2Args)),
+            .threads = threads,
+            .version = ARGON2_VERSION_13,
+            .allocate_cbk = nullptr, .free_cbk = nullptr,
+            .flags = ARGON2_DEFAULT_FLAGS
+        };
+        // libargon2 validates all the arguments so don't need to do it here
+        int const rc = argon2id_ctx(&context);
+        if (rc != ARGON2_OK)
+        {
+            SAL_WARN("package", "argon2id_ctx failed to derive key: " << 
argon2_error_message(rc));
+            throw ZipIOException("argon2id_ctx failed to derive key");
+        }
+    }
     else if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< 
sal_uInt8* >( aDerivedKey.getArray() ),
                         aDerivedKey.getLength(),
                         reinterpret_cast< const sal_uInt8 * > 
(xEncryptionData->m_aKey.getConstArray() ),
                         xEncryptionData->m_aKey.getLength(),
                         reinterpret_cast< const sal_uInt8 * > ( 
xEncryptionData->m_aSalt.getConstArray() ),
                         xEncryptionData->m_aSalt.getLength(),
-                        xEncryptionData->m_nIterationCount ) )
+                        *xEncryptionData->m_oPBKDFIterationCount) )
     {
         throw ZipIOException("Can not create derived key!" );
     }
@@ -236,12 +271,30 @@ void ZipFile::StaticFillHeader( const ::rtl::Reference< 
EncryptionData >& rData,
     *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF;
 
     // Then the iteration Count
-    sal_Int32 nIterationCount = rData->m_nIterationCount;
+    sal_Int32 const nIterationCount = rData->m_oPBKDFIterationCount ? 
*rData->m_oPBKDFIterationCount : 0;
     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF);
     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF);
     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF);
     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF);
 
+    sal_Int32 const nArgon2t = rData->m_oArgon2Args ? 
::std::get<0>(*rData->m_oArgon2Args) : 0;
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2t >> 0) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2t >> 8) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2t >> 16) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2t >> 24) & 0xFF);
+
+    sal_Int32 const nArgon2m = rData->m_oArgon2Args ? 
::std::get<1>(*rData->m_oArgon2Args) : 0;
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2m >> 0) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2m >> 8) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2m >> 16) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2m >> 24) & 0xFF);
+
+    sal_Int32 const nArgon2p = rData->m_oArgon2Args ? 
::std::get<2>(*rData->m_oArgon2Args) : 0;
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2p >> 0) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2p >> 8) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2p >> 16) & 0xFF);
+    *(pHeader++) = static_cast<sal_Int8>((nArgon2p >> 24) & 0xFF);
+
     // FIXME64: need to handle larger sizes
     // Then the size:
     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF);
@@ -334,7 +387,38 @@ bool ZipFile::StaticFillData (  ::rtl::Reference< 
BaseEncryptionData > const & r
             nCount |= ( pBuffer[nPos++] & 0xFF ) << 8;
             nCount |= ( pBuffer[nPos++] & 0xFF ) << 16;
             nCount |= ( pBuffer[nPos++] & 0xFF ) << 24;
-            rData->m_nIterationCount = nCount;
+            if (nCount != 0)
+            {
+                rData->m_oPBKDFIterationCount.emplace(nCount);
+            }
+            else
+            {
+                rData->m_oPBKDFIterationCount.reset();
+            }
+
+            sal_Int32 nArgon2t = pBuffer[nPos++] & 0xFF;
+            nArgon2t |= ( pBuffer[nPos++] & 0xFF ) << 8;
+            nArgon2t |= ( pBuffer[nPos++] & 0xFF ) << 16;
+            nArgon2t |= ( pBuffer[nPos++] & 0xFF ) << 24;
+
+            sal_Int32 nArgon2m = pBuffer[nPos++] & 0xFF;
+            nArgon2m |= ( pBuffer[nPos++] & 0xFF ) << 8;
+            nArgon2m |= ( pBuffer[nPos++] & 0xFF ) << 16;
+            nArgon2m |= ( pBuffer[nPos++] & 0xFF ) << 24;
+
+            sal_Int32 nArgon2p = pBuffer[nPos++] & 0xFF;
+            nArgon2p |= ( pBuffer[nPos++] & 0xFF ) << 8;
+            nArgon2p |= ( pBuffer[nPos++] & 0xFF ) << 16;
+            nArgon2p |= ( pBuffer[nPos++] & 0xFF ) << 24;
+
+            if (nArgon2t != 0 && nArgon2m != 0 && nArgon2p != 0)
+            {
+                rData->m_oArgon2Args.emplace(nArgon2t, nArgon2m, nArgon2p);
+            }
+            else
+            {
+                rData->m_oArgon2Args.reset();
+            }
 
             rSize  =   pBuffer[nPos++] & 0xFF;
             rSize |= ( pBuffer[nPos++] & 0xFF ) << 8;
diff --git a/package/source/zippackage/ZipPackage.cxx 
b/package/source/zippackage/ZipPackage.cxx
index 54b8099e38d1..02f7cf71e8af 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -57,6 +57,7 @@
 #include <com/sun/star/embed/StorageFormats.hpp>
 #include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
+#include <com/sun/star/xml/crypto/KDFID.hpp>
 #include <cppuhelper/implbase.hxx>
 #include <rtl/uri.hxx>
 #include <rtl/random.h>
@@ -140,6 +141,7 @@ ZipPackage::ZipPackage ( uno::Reference < XComponentContext 
> xContext )
 : m_aMutexHolder( new comphelper::RefCountedMutex )
 , m_nStartKeyGenerationID( xml::crypto::DigestID::SHA1 )
 , m_oChecksumDigestID( xml::crypto::DigestID::SHA1_1K )
+, m_nKeyDerivationFunctionID(xml::crypto::KDFID::PBKDF2)
 , m_nCommonEncryptionID( xml::crypto::CipherID::BLOWFISH_CFB_8 )
 , m_bHasEncryptedEntries ( false )
 , m_bHasNonEncryptedEntries ( false )
@@ -207,6 +209,8 @@ void ZipPackage::parseManifest()
                     {
                         OUString sPath, sMediaType, sVersion;
                         const Any *pSalt = nullptr, *pVector = nullptr, 
*pCount = nullptr, *pSize = nullptr, *pDigest = nullptr, *pDigestAlg = nullptr, 
*pEncryptionAlg = nullptr, *pStartKeyAlg = nullptr, *pDerivedKeySize = nullptr;
+                        uno::Any const* pKDF = nullptr;
+                        uno::Any const* pArgon2Args = nullptr;
                         for ( const PropertyValue& rValue : rSequence )
                         {
                             if ( rValue.Name == sPropFullPath )
@@ -235,6 +239,11 @@ void ZipPackage::parseManifest()
                                 pDerivedKeySize = &( rValue.Value );
                             else if ( rValue.Name == sKeyInfo )
                                 pKeyInfo = &( rValue.Value );
+                            else if (rValue.Name == "KeyDerivationFunction") {
+                                pKDF = &rValue.Value;
+                            } else if (rValue.Name == "Argon2Args") {
+                                pArgon2Args = &rValue.Value;
+                            }
                         }
 
                         if ( !sPath.isEmpty() && hasByHierarchicalName ( sPath 
) )
@@ -254,6 +263,7 @@ void ZipPackage::parseManifest()
 
                                 if (pKeyInfo
                                     && pVector && pSize && pEncryptionAlg
+                                    && pKDF && pKDF->has<sal_Int32>() && 
pKDF->get<sal_Int32>() == xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P
                                     && ((pEncryptionAlg->has<sal_Int32>()
                                             && 
pEncryptionAlg->get<sal_Int32>() == xml::crypto::CipherID::AES_GCM_W3C)
                                         || (pDigest && pDigestAlg)))
@@ -289,7 +299,8 @@ void ZipPackage::parseManifest()
                                     pStream->SetToBeCompressed ( true );
                                     pStream->SetToBeEncrypted ( true );
                                     pStream->SetIsEncrypted ( true );
-                                    pStream->setIterationCount(0);
+                                    
pStream->setIterationCount(::std::optional<sal_Int32>());
+                                    
pStream->setArgon2Args(::std::optional<::std::tuple<sal_Int32, sal_Int32, 
sal_Int32>>());
 
                                     // clamp to default SHA256 start key magic 
value,
                                     // c.f. 
ZipPackageStream::GetEncryptionKey()
@@ -303,12 +314,16 @@ void ZipPackage::parseManifest()
                                     {
                                         m_bHasEncryptedEntries = true;
                                         m_oChecksumDigestID = oDigestAlg;
+                                        m_nKeyDerivationFunctionID = 
xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P;
                                         m_nCommonEncryptionID = nEncryptionAlg;
                                         m_nStartKeyGenerationID = nStartKeyAlg;
                                     }
                                 }
-                                else if (pSalt && pCount
+                                else if (pSalt
                                     && pVector && pSize && pEncryptionAlg
+                                    && pKDF && pKDF->has<sal_Int32>()
+                                    && ((pKDF->get<sal_Int32>() == 
xml::crypto::KDFID::PBKDF2 && pCount)
+                                        || (pKDF->get<sal_Int32>() == 
xml::crypto::KDFID::Argon2id && pArgon2Args))
                                     && ((pEncryptionAlg->has<sal_Int32>()
                                             && 
pEncryptionAlg->get<sal_Int32>() == xml::crypto::CipherID::AES_GCM_W3C)
                                         || (pDigest && pDigestAlg)))
@@ -317,6 +332,7 @@ void ZipPackage::parseManifest()
                                     uno::Sequence < sal_Int8 > aSequence;
                                     sal_Int64 nSize = 0;
                                     ::std::optional<sal_Int32> oDigestAlg;
+                                    sal_Int32 nKDF = 0;
                                     sal_Int32 nEncryptionAlg = 0;
                                     sal_Int32 nCount = 0;
                                     sal_Int32 nDerivedKeySize = 16, 
nStartKeyAlg = xml::crypto::DigestID::SHA1;
@@ -329,8 +345,23 @@ void ZipPackage::parseManifest()
                                     *pVector >>= aSequence;
                                     pStream->setInitialisationVector ( 
aSequence );
 
-                                    *pCount >>= nCount;
-                                    pStream->setIterationCount ( nCount );
+                                    *pKDF >>= nKDF;
+
+                                    if (pCount)
+                                    {
+                                        *pCount >>= nCount;
+                                        
pStream->setIterationCount(::std::optional<sal_Int32>(nCount));
+                                    }
+
+                                    if (pArgon2Args)
+                                    {
+                                        uno::Sequence<sal_Int32> args;
+                                        *pArgon2Args >>= args;
+                                        assert(args.getLength() == 3);
+                                        
::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> oArgs;
+                                        oArgs.emplace(args[0], args[1], 
args[2]);
+                                        pStream->setArgon2Args(oArgs);
+                                    }
 
                                     *pSize >>= nSize;
                                     pStream->setSize ( nSize );
@@ -365,6 +396,7 @@ void ZipPackage::parseManifest()
                                     {
                                         m_bHasEncryptedEntries = true;
                                         m_nStartKeyGenerationID = nStartKeyAlg;
+                                        m_nKeyDerivationFunctionID = nKDF;
                                         m_oChecksumDigestID = oDigestAlg;
                                         m_nCommonEncryptionID = nEncryptionAlg;
                                     }
@@ -1309,12 +1341,25 @@ uno::Reference< io::XInputStream > 
ZipPackage::writeTempFile()
             // for encrypted streams
             RandomPool aRandomPool;
 
-            // if there is only one KDF invocation, increase the safety margin
-            sal_Int32 const nPBKDF2IterationCount =
-                officecfg::Office::Common::Misc::ExperimentalMode::get() ? 
600000 : 100000;
+            ::std::optional<sal_Int32> oPBKDF2IterationCount;
+            ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> 
oArgon2Args;
 
-            // call saveContents ( it will recursively save sub-directories
-            m_xRootFolder->saveContents("", aManList, aZipOut, 
GetEncryptionKey(), bIsGpgEncrypt ? 0 : nPBKDF2IterationCount, 
aRandomPool.get());
+            if (!bIsGpgEncrypt)
+            {
+                if (m_nKeyDerivationFunctionID == xml::crypto::KDFID::PBKDF2)
+                {   // if there is only one KDF invocation, increase the 
safety margin
+                    
oPBKDF2IterationCount.emplace(officecfg::Office::Common::Misc::ExperimentalMode::get()
 ? 600000 : 100000);
+                }
+                else
+                {
+                    assert(m_nKeyDerivationFunctionID == 
xml::crypto::KDFID::Argon2id);
+                    oArgon2Args.emplace(3, (1<<16), 4);
+                }
+            }
+
+            // call saveContents - it will recursively save sub-directories
+            m_xRootFolder->saveContents("", aManList, aZipOut, 
GetEncryptionKey(),
+                oPBKDF2IterationCount, oArgon2Args, aRandomPool.get());
         }
 
         if( m_nFormat == embed::StorageFormats::PACKAGE )
@@ -1757,6 +1802,18 @@ void SAL_CALL ZipPackage::setPropertyValue( const 
OUString& aPropertyName, const
 
                 m_nStartKeyGenerationID = nID;
             }
+            else if (rAlgorithm.Name == "KeyDerivationFunction")
+            {
+                sal_Int32 nID = 0;
+                if (!(rAlgorithm.Value >>= nID)
+                  || (nID != xml::crypto::KDFID::PBKDF2
+                      && nID != xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P
+                      && nID != xml::crypto::KDFID::Argon2id))
+                {
+                    throw IllegalArgumentException(THROW_WHERE "Unexpected key 
derivation function provided!", uno::Reference<uno::XInterface>(), 2);
+                }
+                m_nKeyDerivationFunctionID = nID;
+            }
             else if ( rAlgorithm.Name == "EncryptionAlgorithm" )
             {
                 sal_Int32 nID = 0;
@@ -1807,6 +1864,7 @@ void SAL_CALL ZipPackage::setPropertyValue( const 
OUString& aPropertyName, const
         // defaults) with reasonable values
         // note: these should be overridden by SfxObjectShell::SetupStorage()
         m_nStartKeyGenerationID = 0; // this is unused for PGP
+        m_nKeyDerivationFunctionID = xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P;
         m_nCommonEncryptionID = xml::crypto::CipherID::AES_CBC_W3C_PADDING;
         m_oChecksumDigestID.emplace(xml::crypto::DigestID::SHA512_1K);
     }
@@ -1828,6 +1886,7 @@ Any SAL_CALL ZipPackage::getPropertyValue( const 
OUString& PropertyName )
     {
         ::comphelper::SequenceAsHashMap aAlgorithms;
         aAlgorithms["StartKeyGenerationAlgorithm"] <<= m_nStartKeyGenerationID;
+        aAlgorithms["KeyDerivationFunction"] <<= m_nKeyDerivationFunctionID;
         aAlgorithms["EncryptionAlgorithm"] <<= m_nCommonEncryptionID;
         if (m_oChecksumDigestID)
         {
diff --git a/package/source/zippackage/ZipPackageFolder.cxx 
b/package/source/zippackage/ZipPackageFolder.cxx
index 21c71b14cf09..bca4e46e1bc2 100644
--- a/package/source/zippackage/ZipPackageFolder.cxx
+++ b/package/source/zippackage/ZipPackageFolder.cxx
@@ -231,7 +231,8 @@ bool ZipPackageFolder::saveChild(
         std::vector < uno::Sequence < PropertyValue > > &rManList,
         ZipOutputStream & rZipOut,
         const uno::Sequence < sal_Int8 >& rEncryptionKey,
-        sal_Int32 nPBKDF2IterationCount,
+        ::std::optional<sal_Int32> const oPBKDF2IterationCount,
+        ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> const 
oArgon2Args,
         const rtlRandomPool &rRandomPool)
 {
     uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
@@ -250,7 +251,7 @@ bool ZipPackageFolder::saveChild(
     else
         aPropSet.realloc( 0 );
 
-    saveContents( sTempName, rManList, rZipOut, rEncryptionKey, 
nPBKDF2IterationCount, rRandomPool);
+    saveContents(sTempName, rManList, rZipOut, rEncryptionKey, 
oPBKDF2IterationCount, oArgon2Args, rRandomPool);
 
     // folder can have a mediatype only in package format
     if ( aPropSet.hasElements() && ( m_nFormat == 
embed::StorageFormats::PACKAGE ) )
@@ -264,7 +265,8 @@ void ZipPackageFolder::saveContents(
         std::vector < uno::Sequence < PropertyValue > > &rManList,
         ZipOutputStream & rZipOut,
         const uno::Sequence < sal_Int8 >& rEncryptionKey,
-        sal_Int32 nPBKDF2IterationCount,
+        ::std::optional<sal_Int32> const oPBKDF2IterationCount,
+        ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> const 
oArgon2Args,
         const rtlRandomPool &rRandomPool ) const
 {
     if ( maContents.empty() && !rPath.isEmpty() && m_nFormat != 
embed::StorageFormats::OFOPXML )
@@ -300,8 +302,8 @@ void ZipPackageFolder::saveContents(
         if ( aIter != maContents.end() && !(*aIter).second.bFolder )
         {
             bMimeTypeStreamStored = true;
-            if( !aIter->second.pStream->saveChild(
-                rPath + aIter->first, rManList, rZipOut, rEncryptionKey, 
nPBKDF2IterationCount, rRandomPool ))
+            if (!aIter->second.pStream->saveChild(rPath + aIter->first, 
rManList, rZipOut,
+                    rEncryptionKey, oPBKDF2IterationCount, oArgon2Args, 
rRandomPool))
             {
                 throw uno::RuntimeException( THROW_WHERE );
             }
@@ -314,16 +316,16 @@ void ZipPackageFolder::saveContents(
         {
             if (rInfo.bFolder)
             {
-                if( !rInfo.pFolder->saveChild(
-                    rPath + rShortName, rManList, rZipOut, rEncryptionKey, 
nPBKDF2IterationCount, rRandomPool ))
+                if (!rInfo.pFolder->saveChild(rPath + rShortName, rManList, 
rZipOut,
+                        rEncryptionKey, oPBKDF2IterationCount, oArgon2Args, 
rRandomPool))
                 {
                     throw uno::RuntimeException( THROW_WHERE );
                 }
             }
             else
             {
-                if( !rInfo.pStream->saveChild(
-                    rPath + rShortName, rManList, rZipOut, rEncryptionKey, 
nPBKDF2IterationCount, rRandomPool ))
+                if (!rInfo.pStream->saveChild(rPath + rShortName, rManList, 
rZipOut,
+                        rEncryptionKey, oPBKDF2IterationCount, oArgon2Args, 
rRandomPool))
                 {
                     throw uno::RuntimeException( THROW_WHERE );
                 }
diff --git a/package/source/zippackage/ZipPackageStream.cxx 
b/package/source/zippackage/ZipPackageStream.cxx
index 6ef2241d464a..d3068a666519 100644
--- a/package/source/zippackage/ZipPackageStream.cxx
+++ b/package/source/zippackage/ZipPackageStream.cxx
@@ -35,6 +35,7 @@
 #include <com/sun/star/io/XSeekable.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
 #include <com/sun/star/xml/crypto/CipherID.hpp>
+#include <com/sun/star/xml/crypto/KDFID.hpp>
 
 #include <CRC32.hxx>
 #include <ZipOutputEntry.hxx>
@@ -450,7 +451,8 @@ bool ZipPackageStream::saveChild(
         std::vector < uno::Sequence < beans::PropertyValue > > &rManList,
         ZipOutputStream & rZipOut,
         const uno::Sequence < sal_Int8 >& rEncryptionKey,
-        sal_Int32 nPBKDF2IterationCount,
+        ::std::optional<sal_Int32> const oPBKDF2IterationCount,
+        ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> const 
oArgon2Args,
         const rtlRandomPool &rRandomPool)
 {
     bool bSuccess = true;
@@ -600,7 +602,8 @@ bool ZipPackageStream::saveChild(
 
                 setInitialisationVector ( aVector );
                 setSalt ( aSalt );
-                setIterationCount(nPBKDF2IterationCount);
+                setIterationCount(oPBKDF2IterationCount);
+                setArgon2Args(oArgon2Args);
             }
 
             // last property is digest, which is inserted later if we didn't 
have
@@ -611,8 +614,29 @@ bool ZipPackageStream::saveChild(
             pPropSet[PKG_MNFST_INIVECTOR].Value <<= 
m_xBaseEncryptionData->m_aInitVector;
             pPropSet[PKG_MNFST_SALT].Name = "Salt";
             pPropSet[PKG_MNFST_SALT].Value <<= m_xBaseEncryptionData->m_aSalt;
-            pPropSet[PKG_MNFST_ITERATION].Name = "IterationCount";
-            pPropSet[PKG_MNFST_ITERATION].Value <<= 
m_xBaseEncryptionData->m_nIterationCount;
+            if (m_xBaseEncryptionData->m_oArgon2Args)
+            {
+                pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
+                pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::Argon2id;
+                pPropSet[PKG_MNFST_ARGON2ARGS].Name = "Argon2Args";
+                uno::Sequence<sal_Int32> const args{
+                    ::std::get<0>(*m_xBaseEncryptionData->m_oArgon2Args),
+                    ::std::get<1>(*m_xBaseEncryptionData->m_oArgon2Args),
+                    ::std::get<2>(*m_xBaseEncryptionData->m_oArgon2Args) };
+                pPropSet[PKG_MNFST_ARGON2ARGS].Value <<= args;
+            }
+            else if (m_xBaseEncryptionData->m_oPBKDFIterationCount)
+            {
+                pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
+                pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::PBKDF2;
+                pPropSet[PKG_MNFST_ITERATION].Name = "IterationCount";
+                pPropSet[PKG_MNFST_ITERATION].Value <<= 
*m_xBaseEncryptionData->m_oPBKDFIterationCount;
+            }
+            else
+            {
+                pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
+                pPropSet[PKG_MNFST_KDF].Value <<= 
xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P;
+            }
 
             // Need to store the uncompressed size in the manifest
             OSL_ENSURE( m_nOwnStreamOrigSize >= 0, "The stream size was not 
correctly initialized!" );
@@ -625,19 +649,16 @@ bool ZipPackageStream::saveChild(
                 if ( !xEncData.is() )
                     throw uno::RuntimeException();
 
-                pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
-                if (xEncData->m_oCheckAlg)
-                {
-                    pPropSet[PKG_MNFST_DIGEST].Value <<= 
m_xBaseEncryptionData->m_aDigest;
-                }
                 pPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
                 pPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
                 pPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
                 pPropSet[PKG_MNFST_STARTALG].Value <<= 
xEncData->m_nStartKeyGenID;
-                pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
                 if (xEncData->m_oCheckAlg)
                 {
                     assert(xEncData->m_nEncAlg != 
xml::crypto::CipherID::AES_GCM_W3C);
+                    pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
+                    pPropSet[PKG_MNFST_DIGEST].Value <<= 
m_xBaseEncryptionData->m_aDigest;
+                    pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
                     pPropSet[PKG_MNFST_DIGESTALG].Value <<= 
*xEncData->m_oCheckAlg;
                 }
                 pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
@@ -823,19 +844,22 @@ bool ZipPackageStream::saveChild(
             if ( !xEncData.is() )
                 throw uno::RuntimeException();
 
-            pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
-            if (xEncData->m_oCheckAlg)
-            {
-                pPropSet[PKG_MNFST_DIGEST].Value <<= 
m_xBaseEncryptionData->m_aDigest;
-            }
+            // very confusing: half the encryption properties are
+            // unconditionally added above and the other half conditionally;
+            // assert that we have the expected group and not duplicates
+            assert(std::any_of(aPropSet.begin(), aPropSet.end(), [](auto 
const& it){ return it.Name == "Salt"; }));
+            assert(!std::any_of(aPropSet.begin(), aPropSet.end(), [](auto 
const& it){ return it.Name == sEncryptionAlgProperty; }));
+
             pPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
             pPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
             pPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
             pPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
-            pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
             if (xEncData->m_oCheckAlg)
             {
                 assert(xEncData->m_nEncAlg != 
xml::crypto::CipherID::AES_GCM_W3C);
+                pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
+                pPropSet[PKG_MNFST_DIGEST].Value <<= 
m_xBaseEncryptionData->m_aDigest;
+                pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
                 pPropSet[PKG_MNFST_DIGESTALG].Value <<= *xEncData->m_oCheckAlg;
             }
             pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index 40449b004713..ea1063ea81c1 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -58,6 +58,7 @@
 #include <com/sun/star/text/XTextRange.hpp>
 #include <com/sun/star/xml/crypto/CipherID.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
+#include <com/sun/star/xml/crypto/KDFID.hpp>
 
 #include <com/sun/star/document/XDocumentProperties.hpp>
 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
@@ -336,7 +337,8 @@ void SfxObjectShell::SetupStorage( const uno::Reference< 
embed::XStorage >& xSto
     {
         { "StartKeyGenerationAlgorithm", 
css::uno::Any(xml::crypto::DigestID::SHA1) },
         { "EncryptionAlgorithm", 
css::uno::Any(xml::crypto::CipherID::BLOWFISH_CFB_8) },
-        { "ChecksumAlgorithm", css::uno::Any(xml::crypto::DigestID::SHA1_1K) }
+        { "ChecksumAlgorithm", css::uno::Any(xml::crypto::DigestID::SHA1_1K) },
+        { "KeyDerivationFunction", css::uno::Any(xml::crypto::KDFID::PBKDF2) },
     };
 
     if (nDefVersion >= SvtSaveOptions::ODFSVER_012)
@@ -367,6 +369,10 @@ void SfxObjectShell::SetupStorage( const uno::Reference< 
embed::XStorage >& xSto
         {
             pEncryptionAlgs[1].Value <<= xml::crypto::CipherID::AES_GCM_W3C;
             pEncryptionAlgs[2].Value.clear();
+            if (!getenv("LO_ARGON2_DISABLE"))
+            {
+                pEncryptionAlgs[3].Value <<= xml::crypto::KDFID::Argon2id;
+            }
         }
         else
         {

Reply via email to