diff options
author | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2017-12-10 23:40:00 +0100 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2018-01-13 14:17:48 +0100 |
commit | 01c7a60c051ac4562e3a317dde3c29c507f3f40b (patch) | |
tree | 0b7104b75ba3910ed0363b46bc66b4b5afaede3e /comphelper | |
parent | 3271e8b90f5d522fdfe1de46b77e7f67cdaa75af (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.cxx | 96 | ||||
-rw-r--r-- | comphelper/source/misc/storagehelper.cxx | 4 |
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); |