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:
parent
70ef230aae
commit
2f512aaa6c
23 changed files with 428 additions and 70 deletions
|
@ -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 \
|
||||
|
|
32
external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch
vendored
Normal file
32
external/argon2/0001-Fix-possible-compiler-error-due-to-undefined-_MSC_VE.patch
vendored
Normal 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
|
||||
|
6
external/argon2/UnpackedTarball_argon2.mk
vendored
6
external/argon2/UnpackedTarball_argon2.mk
vendored
|
@ -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:
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
47
offapi/com/sun/star/xml/crypto/KDFID.idl
Normal file
47
offapi/com/sun/star/xml/crypto/KDFID.idl
Normal 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: */
|
|
@ -42,6 +42,7 @@ $(eval $(call gb_Library_use_libraries,package2,\
|
|||
|
||||
$(eval $(call gb_Library_use_externals,package2,\
|
||||
boost_headers \
|
||||
argon2 \
|
||||
zlib \
|
||||
))
|
||||
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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)
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue