diff options
author | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2017-12-14 13:23:04 +0100 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2018-01-13 14:32:48 +0100 |
commit | ca6f3d7a56a3a028618413a811775328449264bf (patch) | |
tree | fcfe17231a51af1407458bf5ad96505f5eedd211 /comphelper | |
parent | d17bff6e0324dfa013681efd7e0107d3cd5ad2be (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.cxx | 96 |
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: */ |