summaryrefslogtreecommitdiff
path: root/comphelper
diff options
context:
space:
mode:
authorThorsten Behrens <Thorsten.Behrens@CIB.de>2017-12-10 23:40:00 +0100
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2018-01-13 14:17:48 +0100
commit01c7a60c051ac4562e3a317dde3c29c507f3f40b (patch)
tree0b7104b75ba3910ed0363b46bc66b4b5afaede3e /comphelper
parent3271e8b90f5d522fdfe1de46b77e7f67cdaa75af (diff)
tdf#114550: load back PGP encrypted files
This squashes the following commits from master: gpg4libre: import PGP encryption manifest Change-Id: Iadd7f8f1194299cb50907d8594114c89c668ebd0 gpg4libre: open encrypted files also via gpg Change-Id: I1f626143e6c8443b4ad0c4fc5bdbd5ab8d56a451 tdf#114550 use 32 bit random session key for gpg encryption Change-Id: I7303be71fd855aa454d07fcae04d7f42e3c9cd9c tdf#114550 recognize sym key & init vec as valid f/ decrypt Change-Id: Ie366f086a3c14d6b54b91b4edee8cfef1a42c44b tdf#114550 don't use PBKDF2 in package for gpg encryption Change-Id: Ic96b2193f8541bbd109795fb9c0212a0a10c7344 gpg4libre: add initial unit test for encryption Change-Id: Id782dd865878ae7b8a60c7c80821b1370f6ac7e7 Change-Id: Id77b67a275bf91614ab62b65fdc69e4872247ffc Reviewed-on: https://gerrit.libreoffice.org/47784 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Katarina Behrens <Katarina.Behrens@cib.de> Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'comphelper')
-rw-r--r--comphelper/source/misc/docpasswordhelper.cxx96
-rw-r--r--comphelper/source/misc/storagehelper.cxx4
2 files changed, 98 insertions, 2 deletions
diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx
index 7d761bb9c740..81fe3bc5268c 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -17,11 +17,15 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <config_gpgme.h>
+
#include <algorithm>
#include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/storagehelper.hxx>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <osl/time.h>
#include <osl/diagnose.h>
@@ -29,6 +33,13 @@
#include <rtl/random.h>
#include <string.h>
+#if HAVE_FEATURE_GPGME
+# include <gpgme.h>
+# include <context.h>
+# include <data.h>
+# include <decryptionresult.h>
+#endif
+
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::uno::Reference;
@@ -420,6 +431,91 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
return (eResult == DocPasswordVerifierResult::OK) ? aEncData : uno::Sequence< beans::NamedValue >();
}
+/*static*/ uno::Sequence< css::beans::NamedValue >
+ DocPasswordHelper::decryptGpgSession(
+ const uno::Sequence< uno::Sequence< beans::NamedValue > >& rGpgProperties )
+{
+#if HAVE_FEATURE_GPGME
+ if ( !rGpgProperties.hasElements() )
+ return uno::Sequence< beans::NamedValue >();
+
+ uno::Sequence< beans::NamedValue > aEncryptionData(1);
+ std::unique_ptr<GpgME::Context> ctx;
+ GpgME::initializeLibrary();
+ GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
+ if (err)
+ throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
+
+ ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) );
+ if (ctx == nullptr)
+ throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
+ ctx->setArmor(false);
+
+ const uno::Sequence < beans::NamedValue > *pSequence = rGpgProperties.getConstArray();
+ const sal_Int32 nLength = rGpgProperties.getLength();
+ for ( sal_Int32 i = 0; i < nLength ; i++, pSequence++ )
+ {
+ const beans::NamedValue *pValues = pSequence->getConstArray();
+ if ( pSequence->getLength() == 3 )
+ {
+ // take CipherValue and try to decrypt that - stop after
+ // the first successful decryption
+
+ // ctx is setup now, let's decrypt the lot!
+ uno::Sequence < sal_Int8 > aVector;
+ pValues[2].Value >>= aVector;
+
+ GpgME::Data cipher(
+ reinterpret_cast<const char*>(aVector.getConstArray()),
+ size_t(aVector.getLength()), false);
+ GpgME::Data plain;
+
+ GpgME::DecryptionResult crypt_res = ctx->decrypt(
+ cipher, plain);
+
+ // NO_SECKEY -> skip
+ // BAD_PASSPHRASE -> retry?
+
+ off_t result = plain.seek(0,SEEK_SET);
+ (void) result;
+ assert(result == 0);
+ int len=0, curr=0; char buf;
+ while( (curr=plain.read(&buf, 1)) )
+ len += curr;
+
+ if(crypt_res.error() || !len)
+ continue; // can't use this key, take next one
+
+ uno::Sequence < sal_Int8 > aKeyValue(len);
+ result = plain.seek(0,SEEK_SET);
+ assert(result == 0);
+ if( plain.read(aKeyValue.getArray(), len) != len )
+ throw uno::RuntimeException("The GpgME library failed to read the encrypted value.");
+
+ SAL_INFO("comphelper.crypto", "Extracted gpg session key of length: " << len);
+
+ aEncryptionData[0].Name = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
+ aEncryptionData[0].Value <<= aKeyValue;
+ break;
+ }
+ }
+
+ if ( aEncryptionData[0].Value.hasValue() )
+ {
+ uno::Sequence< beans::NamedValue > aContainer(2);
+ aContainer[0].Name = "GpgInfos";
+ aContainer[0].Value <<= rGpgProperties;
+ aContainer[1].Name = "EncryptionKey";
+ aContainer[1].Value <<= aEncryptionData;
+
+ return aContainer;
+ }
+#else
+ (void)rGpgProperties;
+#endif
+ return uno::Sequence< beans::NamedValue >();
+}
+
} // namespace comphelper
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx
index d51055211e8a..27e72b784e10 100644
--- a/comphelper/source/misc/storagehelper.cxx
+++ b/comphelper/source/misc/storagehelper.cxx
@@ -442,8 +442,8 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat
rtlRandomPool aRandomPool = rtl_random_createPool();
rtl_random_addBytes(aRandomPool, &aTime, 8);
- // get 16 random chars out of it
- uno::Sequence < sal_Int8 > aVector(16);
+ // get 32 random chars out of it
+ uno::Sequence < sal_Int8 > aVector(32);
rtl_random_getBytes( aRandomPool, aVector.getArray(), aVector.getLength() );
rtl_random_destroyPool(aRandomPool);