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🏢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.stahl@allotropia.de>
This commit is contained in:
Michael Stahl 2023-12-19 19:13:00 +01:00
parent 70ef230aae
commit 2f512aaa6c
23 changed files with 428 additions and 70 deletions

View file

@ -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 \

View file

@ -0,0 +1,32 @@
From 48829f87ebafbb9938d23a8f0bff4d11d770690e Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@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

View file

@ -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:

View file

@ -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 \

View file

@ -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

View file

@ -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: */

View file

@ -42,6 +42,7 @@ $(eval $(call gb_Library_use_libraries,package2,\
$(eval $(call gb_Library_use_externals,package2,\
boost_headers \
argon2 \
zlib \
))

View file

@ -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\002\005"
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: */

View file

@ -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)
{}
};

View file

@ -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;

View file

@ -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;

View file

@ -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()

View file

@ -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

View file

@ -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);

View file

@ -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: */

View file

@ -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() );

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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)
{

View file

@ -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 );
}

View file

@ -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;

View file

@ -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
{