diff options
-rw-r--r-- | comphelper/source/misc/docpasswordhelper.cxx | 40 | ||||
-rw-r--r-- | oox/source/token/properties.txt | 1 | ||||
-rw-r--r-- | sc/qa/uitest/calc_tests9/tdf115933.py | 32 | ||||
-rw-r--r-- | sc/qa/uitest/data/tdf115933.xlsx | bin | 0 -> 9291 bytes | |||
-rw-r--r-- | sc/source/filter/oox/workbooksettings.cxx | 15 |
5 files changed, 79 insertions, 9 deletions
diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx index cd7090944dc0..980faff14698 100644 --- a/comphelper/source/misc/docpasswordhelper.cxx +++ b/comphelper/source/misc/docpasswordhelper.cxx @@ -116,8 +116,7 @@ bool DocPasswordHelper::IsModifyPasswordCorrect( std::u16string_view aPassword, if ( !aPassword.empty() && aInfo.hasElements() ) { OUString sAlgorithm; - uno::Sequence< sal_Int8 > aSalt; - uno::Sequence< sal_Int8 > aHash; + uno::Any aSalt, aHash; sal_Int32 nCount = 0; for ( const auto & prop : aInfo ) @@ -125,20 +124,43 @@ bool DocPasswordHelper::IsModifyPasswordCorrect( std::u16string_view aPassword, if ( prop.Name == "algorithm-name" ) prop.Value >>= sAlgorithm; else if ( prop.Name == "salt" ) - prop.Value >>= aSalt; + aSalt = prop.Value; else if ( prop.Name == "iteration-count" ) prop.Value >>= nCount; else if ( prop.Name == "hash" ) - prop.Value >>= aHash; + aHash = prop.Value; } - if ( sAlgorithm == "PBKDF2" && aSalt.hasElements() && nCount > 0 && aHash.hasElements() ) + if ( sAlgorithm == "PBKDF2" ) { - uno::Sequence< sal_Int8 > aNewHash = GeneratePBKDF2Hash( aPassword, aSalt, nCount, aHash.getLength() ); - for ( sal_Int32 nInd = 0; nInd < aNewHash.getLength() && nInd < aHash.getLength() && aNewHash[nInd] == aHash[nInd]; nInd ++ ) + uno::Sequence<sal_Int8> aIntSalt, aIntHash; + aSalt >>= aIntSalt; + aHash >>= aIntHash; + if (aIntSalt.hasElements() && nCount > 0 && aIntHash.hasElements()) { - if ( nInd == aNewHash.getLength() - 1 && nInd == aHash.getLength() - 1 ) - bResult = true; + uno::Sequence<sal_Int8> aNewHash + = GeneratePBKDF2Hash(aPassword, aIntSalt, nCount, aIntHash.getLength()); + for (sal_Int32 nInd = 0; nInd < aNewHash.getLength() && nInd < aIntHash.getLength() + && aNewHash[nInd] == aIntHash[nInd]; + nInd++) + { + if (nInd == aNewHash.getLength() - 1 && nInd == aIntHash.getLength() - 1) + bResult = true; + } + } + } + else if (nCount > 0) + { + OUString sSalt, sHash; + aSalt >>= sSalt; + aHash >>= sHash; + if (!sSalt.isEmpty() && !sHash.isEmpty()) + { + const OUString aNewHash(GetOoxHashAsBase64(OUString(aPassword), sSalt, nCount, + comphelper::Hash::IterCount::APPEND, + sAlgorithm)); + if (!aNewHash.isEmpty()) + bResult = aNewHash == sHash; } } } diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt index 808df85533ff..2c56d0f46804 100644 --- a/oox/source/token/properties.txt +++ b/oox/source/token/properties.txt @@ -337,6 +337,7 @@ MirroredY MissingValueTreatment Model ModifyPasswordHash +ModifyPasswordInfo MoveProtect MovingAveragePeriod MultiLine diff --git a/sc/qa/uitest/calc_tests9/tdf115933.py b/sc/qa/uitest/calc_tests9/tdf115933.py new file mode 100644 index 000000000000..be7719487958 --- /dev/null +++ b/sc/qa/uitest/calc_tests9/tdf115933.py @@ -0,0 +1,32 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +from uitest.framework import UITestCase +from uitest.uihelper.common import get_url_for_data_file +from libreoffice.uno.propertyvalue import mkPropertyValues + +#Bug 115933 - XLSX <fileSharing> password protected with algorithmName, hashValue, saltValue and spinCount + +class tdf115933(UITestCase): + + def test_tdf115933(self): + with self.ui_test.load_file(get_url_for_data_file("tdf115933.xlsx")): + #The document was created in Excel. + calcDoc = self.xUITest.getTopFocusWindow() + gridwin = calcDoc.getChild("grid_window") + + document = self.ui_test.get_component() + + self.assertTrue(document.isReadonly()) + + #Without the fix in place, this dialog wouldn't have been displayed + with self.ui_test.execute_dialog_through_action(gridwin, "TYPE", mkPropertyValues({"KEYCODE": "CTRL+SHIFT+M"})) as xDialog: + xPassword = xDialog.getChild("newpassEntry") + xPassword.executeAction("TYPE", mkPropertyValues({"TEXT": "a"})) + + self.assertFalse(document.isReadonly()) + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sc/qa/uitest/data/tdf115933.xlsx b/sc/qa/uitest/data/tdf115933.xlsx Binary files differnew file mode 100644 index 000000000000..a6073a76e506 --- /dev/null +++ b/sc/qa/uitest/data/tdf115933.xlsx diff --git a/sc/source/filter/oox/workbooksettings.cxx b/sc/source/filter/oox/workbooksettings.cxx index a7ab887bf967..ae2aa82e1a31 100644 --- a/sc/source/filter/oox/workbooksettings.cxx +++ b/sc/source/filter/oox/workbooksettings.cxx @@ -210,6 +210,21 @@ void WorkbookSettings::finalizeImport() if (maFileSharing.mbRecommendReadOnly || !maFileSharing.maHashValue.isEmpty()) aSettingsProp.setProperty( PROP_LoadReadonly, true ); + if (!maFileSharing.maHashValue.isEmpty()) + { + Sequence<PropertyValue> aResult; + aResult.realloc(4); + aResult[0].Name = "algorithm-name"; + aResult[0].Value <<= maFileSharing.maAlgorithmName; + aResult[1].Name = "salt"; + aResult[1].Value <<= maFileSharing.maSaltValue; + aResult[2].Name = "iteration-count"; + aResult[2].Value <<= maFileSharing.mnSpinCount; + aResult[3].Name = "hash"; + aResult[3].Value <<= maFileSharing.maHashValue; + aSettingsProp.setProperty(PROP_ModifyPasswordInfo, aResult); + } + if( maFileSharing.mnPasswordHash != 0 ) aSettingsProp.setProperty( PROP_ModifyPasswordHash, static_cast< sal_Int32 >( maFileSharing.mnPasswordHash ) ); } |