officecfg/registry/schema/org/openoffice/Office/Common.xcs |    6 +
 svl/source/passwordcontainer/passwordcontainer.cxx         |   41 ++++++++++++-
 svl/source/passwordcontainer/passwordcontainer.hxx         |    6 +
 uui/source/iahndl-authentication.cxx                       |    5 -
 4 files changed, 55 insertions(+), 3 deletions(-)

New commits:
commit 078a07a46a88b8ec22f65db7aba1eabb38a112e2
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Mon Mar 21 20:58:34 2022 +0000
Commit:     Stephan Bergmann <sberg...@redhat.com>
CommitDate: Fri Mar 25 08:30:20 2022 +0100

    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 <sberg...@redhat.com>

diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index dac495521742..a7e5adf6a78f 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -943,6 +943,12 @@
         </info>
         <value>false</value>
       </prop>
+      <prop oor:name="StorageVersion" oor:type="xs:int" oor:nillable="false">
+        <info>
+          <desc>Specifies what version of encoding scheme the password 
container uses.</desc>
+        </info>
+        <value>0</value>
+      </prop>
       <prop oor:name="HasMaster" oor:type="xs:boolean" oor:nillable="false">
         <info>
           <desc>Specifies if there is a valid master password.</desc>
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 <sal/config.h>
+#include <sal/log.hxx>
 
 #include <string_view>
 
@@ -256,6 +257,24 @@ bool StorageItem::useStorage()
 }
 
 
+sal_Int32 StorageItem::getStorageVersion()
+{
+    Sequence<OUString> 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<char>(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 );
diff --git a/uui/source/iahndl-authentication.cxx 
b/uui/source/iahndl-authentication.cxx
index 4ec2f734be6b..ed8150997a30 100644
--- a/uui/source/iahndl-authentication.cxx
+++ b/uui/source/iahndl-authentication.cxx
@@ -437,8 +437,9 @@ executeMasterPasswordDialog(
     OUStringBuffer aBuffer;
     for (sal_uInt8 i : aKey)
     {
-        aBuffer.append(static_cast< sal_Unicode >('a' + (i >> 4)));
-        aBuffer.append(static_cast< sal_Unicode >('a' + (i & 15)));
+        // match PasswordContainer::DecodePasswords aMasterPasswd.copy(index * 
2, 2).toUInt32(16));
+        aBuffer.append(OUString::number(i >> 4, 16));
+        aBuffer.append(OUString::number(i & 15, 16));
     }
     rInfo.SetPassword(aBuffer.makeStringAndClear());
 }

Reply via email to