diff options
Diffstat (limited to 'comphelper/source/misc/docpasswordhelper.cxx')
-rw-r--r-- | comphelper/source/misc/docpasswordhelper.cxx | 152 |
1 files changed, 105 insertions, 47 deletions
diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx index 71f92db48d00..084fb0d36601 100644 --- a/comphelper/source/misc/docpasswordhelper.cxx +++ b/comphelper/source/misc/docpasswordhelper.cxx @@ -51,7 +51,6 @@ using ::com::sun::star::task::PasswordRequestMode; using ::com::sun::star::task::PasswordRequestMode_PASSWORD_ENTER; using ::com::sun::star::task::PasswordRequestMode_PASSWORD_REENTER; using ::com::sun::star::task::XInteractionHandler; -using ::com::sun::star::task::XInteractionRequest; using namespace ::com::sun::star; @@ -96,10 +95,10 @@ uno::Sequence< beans::PropertyValue > DocPasswordHelper::GenerateNewModifyPasswo uno::Sequence< sal_Int8 > aNewHash = GeneratePBKDF2Hash(aPassword, aSalt, nPBKDF2IterationCount, 16); if ( aNewHash.hasElements() ) { - aResult = { comphelper::makePropertyValue("algorithm-name", OUString( "PBKDF2" )), - comphelper::makePropertyValue("salt", aSalt), - comphelper::makePropertyValue("iteration-count", nPBKDF2IterationCount), - comphelper::makePropertyValue("hash", aNewHash) }; + aResult = { comphelper::makePropertyValue(u"algorithm-name"_ustr, u"PBKDF2"_ustr), + comphelper::makePropertyValue(u"salt"_ustr, aSalt), + comphelper::makePropertyValue(u"iteration-count"_ustr, nPBKDF2IterationCount), + comphelper::makePropertyValue(u"hash"_ustr, aNewHash) }; } return aResult; @@ -111,23 +110,83 @@ DocPasswordHelper::GenerateNewModifyPasswordInfoOOXML(std::u16string_view aPassw { uno::Sequence<beans::PropertyValue> aResult; - uno::Sequence<sal_Int8> aSalt = GenerateRandomByteSequence(16); - OUStringBuffer aBuffer; - comphelper::Base64::encode(aBuffer, aSalt); - OUString sSalt = aBuffer.toString(); + if (!aPassword.empty()) + { + uno::Sequence<sal_Int8> aSalt = GenerateRandomByteSequence(16); + OUStringBuffer aBuffer(22); + comphelper::Base64::encode(aBuffer, aSalt); + OUString sSalt = aBuffer.makeStringAndClear(); + + sal_Int32 const nIterationCount = 100000; + OUString sAlgorithm(u"SHA-512"_ustr); + + const OUString sHash(GetOoxHashAsBase64(OUString(aPassword), sSalt, nIterationCount, + comphelper::Hash::IterCount::APPEND, sAlgorithm)); + + if (!sHash.isEmpty()) + { + aResult = { comphelper::makePropertyValue(u"algorithm-name"_ustr, sAlgorithm), + comphelper::makePropertyValue(u"salt"_ustr, sSalt), + comphelper::makePropertyValue(u"iteration-count"_ustr, nIterationCount), + comphelper::makePropertyValue(u"hash"_ustr, sHash) }; + } + } + + return aResult; +} - sal_Int32 const nIterationCount = 100000; - OUString sAlgorithm("SHA-512"); - const OUString sHash(GetOoxHashAsBase64(OUString(aPassword), sSalt, nIterationCount, - comphelper::Hash::IterCount::APPEND, sAlgorithm)); +uno::Sequence< beans::PropertyValue > DocPasswordHelper::ConvertPasswordInfo( const uno::Sequence< beans::PropertyValue >& aInfo ) +{ + uno::Sequence< beans::PropertyValue > aResult; + OUString sAlgorithm, sHash, sSalt, sCount; + sal_Int32 nAlgorithm = 0; + + for ( const auto & prop : aInfo ) + { + if ( prop.Name == "cryptAlgorithmSid" ) + { + prop.Value >>= sAlgorithm; + nAlgorithm = sAlgorithm.toInt32(); + } + else if ( prop.Name == "salt" ) + prop.Value >>= sSalt; + else if ( prop.Name == "cryptSpinCount" ) + prop.Value >>= sCount; + else if ( prop.Name == "hash" ) + prop.Value >>= sHash; + } - if (!sHash.isEmpty()) + if (nAlgorithm == 1) + sAlgorithm = "MD2"; + else if (nAlgorithm == 2) + sAlgorithm = "MD4"; + else if (nAlgorithm == 3) + sAlgorithm = "MD5"; + else if (nAlgorithm == 4) + sAlgorithm = "SHA-1"; + else if (nAlgorithm == 5) + sAlgorithm = "MAC"; + else if (nAlgorithm == 6) + sAlgorithm = "RIPEMD"; + else if (nAlgorithm == 7) + sAlgorithm = "RIPEMD-160"; + else if (nAlgorithm == 9) + sAlgorithm = "HMAC"; + else if (nAlgorithm == 12) + sAlgorithm = "SHA-256"; + else if (nAlgorithm == 13) + sAlgorithm = "SHA-384"; + else if (nAlgorithm == 14) + sAlgorithm = "SHA-512"; + + if ( !sCount.isEmpty() ) { - aResult = { comphelper::makePropertyValue("algorithm-name", sAlgorithm), - comphelper::makePropertyValue("salt", sSalt), - comphelper::makePropertyValue("iteration-count", nIterationCount), - comphelper::makePropertyValue("hash", sHash) }; + sal_Int32 nCount = sCount.toInt32(); + aResult = { comphelper::makePropertyValue(u"algorithm-name"_ustr, sAlgorithm), + comphelper::makePropertyValue(u"salt"_ustr, sSalt), + comphelper::makePropertyValue(u"iteration-count"_ustr, nCount), + comphelper::makePropertyValue(u"hash"_ustr, sHash) }; } return aResult; @@ -194,7 +253,7 @@ bool DocPasswordHelper::IsModifyPasswordCorrect( std::u16string_view aPassword, sal_uInt32 DocPasswordHelper::GetWordHashAsUINT32( - const OUString& aUString ) + std::u16string_view aUString ) { static const sal_uInt16 pInitialCode[] = { 0xE1F0, // 1 @@ -233,7 +292,7 @@ sal_uInt32 DocPasswordHelper::GetWordHashAsUINT32( }; sal_uInt32 nResult = 0; - sal_uInt32 nLen = aUString.getLength(); + size_t nLen = aUString.size(); if ( nLen ) { @@ -243,7 +302,7 @@ sal_uInt32 DocPasswordHelper::GetWordHashAsUINT32( sal_uInt16 nHighResult = pInitialCode[nLen - 1]; sal_uInt16 nLowResult = 0; - for ( sal_uInt32 nInd = 0; nInd < nLen; nInd++ ) + for ( size_t nInd = 0; nInd < nLen; nInd++ ) { // NO Encoding during conversion! // The specification says that the low byte should be used in case it is not NULL @@ -314,6 +373,8 @@ std::vector<unsigned char> DocPasswordHelper::GetOoxHashAsVector( eType = comphelper::HashType::SHA512; else if (rAlgorithmName == u"SHA-256" || rAlgorithmName == u"SHA256") eType = comphelper::HashType::SHA256; + else if (rAlgorithmName == u"SHA-384" || rAlgorithmName == u"SHA384") + eType = comphelper::HashType::SHA384; else if (rAlgorithmName == u"SHA-1" || rAlgorithmName == u"SHA1") // "SHA1" might be in the wild eType = comphelper::HashType::SHA1; else if (rAlgorithmName == u"MD5") @@ -327,13 +388,13 @@ std::vector<unsigned char> DocPasswordHelper::GetOoxHashAsVector( css::uno::Sequence<sal_Int8> DocPasswordHelper::GetOoxHashAsSequence( const OUString& rPassword, - const OUString& rSaltValue, + std::u16string_view rSaltValue, sal_uInt32 nSpinCount, comphelper::Hash::IterCount eIterCount, std::u16string_view rAlgorithmName) { std::vector<unsigned char> aSaltVec; - if (!rSaltValue.isEmpty()) + if (!rSaltValue.empty()) { css::uno::Sequence<sal_Int8> aSaltSeq; comphelper::Base64::decode( aSaltSeq, rSaltValue); @@ -347,7 +408,7 @@ css::uno::Sequence<sal_Int8> DocPasswordHelper::GetOoxHashAsSequence( OUString DocPasswordHelper::GetOoxHashAsBase64( const OUString& rPassword, - const OUString& rSaltValue, + std::u16string_view rSaltValue, sal_uInt32 nSpinCount, comphelper::Hash::IterCount eIterCount, std::u16string_view rAlgorithmName) @@ -365,23 +426,24 @@ OUString DocPasswordHelper::GetOoxHashAsBase64( { uno::Sequence< sal_Int8 > aResult( nLength ); - rtlRandomPool aRandomPool = rtl_random_createPool (); - rtl_random_getBytes ( aRandomPool, aResult.getArray(), nLength ); - rtl_random_destroyPool ( aRandomPool ); + if (rtl_random_getBytes(nullptr, aResult.getArray(), nLength) != rtl_Random_E_None) + { + throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr); + } return aResult; } -/*static*/ uno::Sequence< sal_Int8 > DocPasswordHelper::GenerateStd97Key( const OUString& aPassword, const uno::Sequence< sal_Int8 >& aDocId ) +/*static*/ uno::Sequence< sal_Int8 > DocPasswordHelper::GenerateStd97Key( std::u16string_view aPassword, const uno::Sequence< sal_Int8 >& aDocId ) { uno::Sequence< sal_Int8 > aResultKey; - if ( !aPassword.isEmpty() && aDocId.getLength() == 16 ) + if ( !aPassword.empty() && aDocId.getLength() == 16 ) { sal_uInt16 pPassData[16] = {}; - sal_Int32 nPassLen = std::min< sal_Int32 >( aPassword.getLength(), 15 ); - memcpy( pPassData, aPassword.getStr(), nPassLen * sizeof(pPassData[0]) ); + sal_Int32 nPassLen = std::min< sal_Int32 >( aPassword.size(), 15 ); + memcpy( pPassData, aPassword.data(), nPassLen * sizeof(pPassData[0]) ); aResultKey = GenerateStd97Key( pPassData, aDocId ); } @@ -562,11 +624,10 @@ OUString DocPasswordHelper::GetOoxHashAsBase64( if (eResult == DocPasswordVerifierResult::OK && !aPassword.isEmpty()) { - if (std::find_if(std::cbegin(aEncData), std::cend(aEncData), + if (std::none_of(std::cbegin(aEncData), std::cend(aEncData), [](const css::beans::NamedValue& val) { return val.Name == PACKAGE_ENCRYPTIONDATA_SHA256UTF8; - }) - == std::cend(aEncData)) + })) { // tdf#118639: We need ODF encryption data for autorecovery, where password // will already be unavailable, so generate and append it here @@ -584,9 +645,9 @@ OUString DocPasswordHelper::GetOoxHashAsBase64( // 2. Add MS binary and OOXML encryption data to result aEncData = comphelper::concatSequences( aEncData, std::initializer_list<beans::NamedValue>{ - { "STD97EncryptionKey", css::uno::Any(aEnc97Key) }, - { "STD97UniqueID", css::uno::Any(aUniqueID) }, - { "OOXPassword", css::uno::Any(aPassword) }, + { u"STD97EncryptionKey"_ustr, css::uno::Any(aEnc97Key) }, + { u"STD97UniqueID"_ustr, css::uno::Any(aUniqueID) }, + { u"OOXPassword"_ustr, css::uno::Any(aPassword) }, }); } } @@ -607,26 +668,23 @@ OUString DocPasswordHelper::GetOoxHashAsBase64( GpgME::initializeLibrary(); GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP); if (err) - throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol."); + throw uno::RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr); ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) ); if (ctx == nullptr) - throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol."); + throw uno::RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr); 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++ ) + for (auto& rSequence : rGpgProperties) { - const beans::NamedValue *pValues = pSequence->getConstArray(); - if ( pSequence->getLength() == 3 ) + if (rSequence.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; + rSequence[2].Value >>= aVector; GpgME::Data cipher( reinterpret_cast<const char*>(aVector.getConstArray()), @@ -653,7 +711,7 @@ OUString DocPasswordHelper::GetOoxHashAsBase64( 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."); + throw uno::RuntimeException(u"The GpgME library failed to read the encrypted value."_ustr); SAL_INFO("comphelper.crypto", "Extracted gpg session key of length: " << len); @@ -665,7 +723,7 @@ OUString DocPasswordHelper::GetOoxHashAsBase64( if ( aEncryptionData.hasElements() ) { uno::Sequence< beans::NamedValue > aContainer{ - { "GpgInfos", uno::Any(rGpgProperties) }, { "EncryptionKey", uno::Any(aEncryptionData) } + { u"GpgInfos"_ustr, uno::Any(rGpgProperties) }, { u"EncryptionKey"_ustr, uno::Any(aEncryptionData) } }; return aContainer; |