summaryrefslogtreecommitdiff
path: root/comphelper
diff options
context:
space:
mode:
authorThorsten Behrens <Thorsten.Behrens@CIB.de>2017-12-14 13:23:04 +0100
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2018-01-13 14:32:48 +0100
commitca6f3d7a56a3a028618413a811775328449264bf (patch)
treefcfe17231a51af1407458bf5ad96505f5eedd211 /comphelper
parentd17bff6e0324dfa013681efd7e0107d3cd5ad2be (diff)
gpg4libre: open encrypted files also via gpg
Adds code to sfx2 and package to try gpg4libre for extracting session keys, and use them in turn to decrypt odf storage. Change-Id: I1f626143e6c8443b4ad0c4fc5bdbd5ab8d56a451 Reviewed-on: https://gerrit.libreoffice.org/47780 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'comphelper')
-rw-r--r--comphelper/source/misc/docpasswordhelper.cxx96
1 files changed, 96 insertions, 0 deletions
diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx
index 13ab45f043af..81e1e996816f 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -17,17 +17,28 @@
* 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/diagnose.h>
#include <rtl/digest.h>
#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;
@@ -418,6 +429,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: */