From 517f7347c49629cb5713388db6dc1e2a80891d68 Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Mon, 21 Mar 2022 20:58:34 +0000 Subject: make hash encoding match decoding Seeing as old versions of the hash may be in the users config, add a StorageVersion field to the office config Passwords section which defaults to 0 to indicate the old hash is in use. Try the old varient when StorageVersion is 0. When a new encoded master password it set write StorageVersion of 1 to indicate a new hash is in use and use the new style when StorageVersion is 1. Change-Id: I3174c37a5891bfc849984e0ec5c2c392b9c6e7b1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132041 Tested-by: Jenkins Reviewed-by: Stephan Bergmann --- svl/source/passwordcontainer/passwordcontainer.cxx | 41 +++++++++++++++++++++- svl/source/passwordcontainer/passwordcontainer.hxx | 6 ++++ 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'svl') diff --git a/svl/source/passwordcontainer/passwordcontainer.cxx b/svl/source/passwordcontainer/passwordcontainer.cxx index 54fa34ce93f0..e8f521c28014 100644 --- a/svl/source/passwordcontainer/passwordcontainer.cxx +++ b/svl/source/passwordcontainer/passwordcontainer.cxx @@ -18,6 +18,7 @@ */ #include +#include #include @@ -256,6 +257,24 @@ bool StorageItem::useStorage() } +sal_Int32 StorageItem::getStorageVersion() +{ + Sequence aNodeNames { "StorageVersion" }; + + Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames ); + + if( aPropertyValues.getLength() != aNodeNames.getLength() ) + { + OSL_FAIL( "Problems during reading" ); + return 0; + } + + sal_Int32 nResult = 0; + aPropertyValues[0] >>= nResult; + + return nResult; +} + bool StorageItem::getEncodedMasterPassword( OUString& aResult ) { if( hasEncoded ) @@ -288,7 +307,8 @@ void StorageItem::setEncodedMasterPassword( const OUString& aEncoded, bool bAcce bool bHasMaster = ( !aEncoded.isEmpty() || bAcceptEmpty ); ConfigItem::SetModified(); - ConfigItem::PutProperties( { "HasMaster", "Master" }, { uno::Any(bHasMaster), uno::Any(aEncoded) } ); + ConfigItem::PutProperties( { "HasMaster", "Master", "StorageVersion" }, + { uno::Any(bHasMaster), uno::Any(aEncoded), uno::Any(nCurrentStorageVersion) } ); hasEncoded = bHasMaster; mEncoded = aEncoded; @@ -772,6 +792,18 @@ OUString PasswordContainer::RequestPasswordFromUser( PasswordRequestMode aRMode, return aResult; } +// Mangle the key to match an old bug +static OUString ReencodeAsOldHash(const OUString& rPass) +{ + OUStringBuffer aBuffer; + for (int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ++ind) + { + unsigned char i = static_cast(rPass.copy(ind * 2, 2).toUInt32(16)); + aBuffer.append(static_cast< sal_Unicode >('a' + (i >> 4))); + aBuffer.append(static_cast< sal_Unicode >('a' + (i & 15))); + } + return aBuffer.makeStringAndClear(); +} OUString const & PasswordContainer::GetMasterPassword( const Reference< XInteractionHandler >& aHandler ) { @@ -810,6 +842,9 @@ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInterac } else { + if (m_xStorageFile->getStorageVersion() == 0) + aPass = ReencodeAsOldHash(aPass); + std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass, aRMode ) ); if( aRM.empty() || aPass != aRM[0] ) { @@ -1014,6 +1049,10 @@ sal_Bool SAL_CALL PasswordContainer::authorizateWithMasterPassword( const uno::R do { aPass = RequestPasswordFromUser( aRMode, xTmpHandler ); + + if (m_xStorageFile->getStorageVersion() == 0) + aPass = ReencodeAsOldHash(aPass); + bResult = ( !aPass.isEmpty() && aPass == m_aMasterPassword ); aRMode = PasswordRequestMode_PASSWORD_REENTER; // further questions with error notification } while( !bResult && !aPass.isEmpty() ); diff --git a/svl/source/passwordcontainer/passwordcontainer.hxx b/svl/source/passwordcontainer/passwordcontainer.hxx index 8bafeaa2d6fc..52d185c9dc6f 100644 --- a/svl/source/passwordcontainer/passwordcontainer.hxx +++ b/svl/source/passwordcontainer/passwordcontainer.hxx @@ -167,6 +167,10 @@ public: typedef ::std::pair< const OUString, ::std::vector< NamePasswordRecord > > PairUrlRecord; typedef ::std::map< OUString, ::std::vector< NamePasswordRecord > > PasswordMap; +// org.openoffice.Office.Common/Passwords/StorageVersion bump if details of +// how password details are saved changes. Enables migration from previous +// schemes. +constexpr sal_Int32 nCurrentStorageVersion = 1; class PasswordContainer; @@ -195,6 +199,8 @@ public: void remove( const OUString& url, const OUString& rec ); void clear(); + sal_Int32 getStorageVersion(); + bool getEncodedMasterPassword( OUString& aResult ); void setEncodedMasterPassword( const OUString& aResult, bool bAcceptEmpty = false ); void setUseStorage( bool bUse ); -- cgit