Blame SOURCES/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch

461f4a
From a3046cfa58bdfa2a1b9ea6287a021230830f056f Mon Sep 17 00:00:00 2001
461f4a
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
461f4a
Date: Tue, 22 Mar 2022 17:22:22 +0000
461f4a
Subject: [PATCH] add Initialization Vectors to password storage
461f4a
461f4a
old ones default to the current all zero case and continue to work
461f4a
as before
461f4a
461f4a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131974
461f4a
Tested-by: Jenkins
461f4a
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
461f4a
(cherry picked from commit 192fa1e3bfc6269f2ebb91716471485a56074aea)
461f4a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132306
461f4a
Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
461f4a
(cherry picked from commit ab77587ec300f5c30084471000663c46ddf25dad)
461f4a
461f4a
Change-Id: I6fe3b02fafcce1b5e7133e77e76a5118177d77af
461f4a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133907
461f4a
Tested-by: Michael Stahl <michael.stahl@allotropia.de>
461f4a
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
461f4a
---
461f4a
 .../schema/org/openoffice/Office/Common.xcs   |  10 ++
461f4a
 .../passwordcontainer/passwordcontainer.cxx   | 127 ++++++++++++------
461f4a
 .../passwordcontainer/passwordcontainer.hxx   |  63 +++++++--
461f4a
 3 files changed, 151 insertions(+), 49 deletions(-)
461f4a
461f4a
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
461f4a
index b033b29b60d7..e57d26ab3366 100644
461f4a
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
461f4a
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
461f4a
@@ -27,6 +27,11 @@
461f4a
       <info>
461f4a
         <desc>Contains a container for passwords.</desc>
461f4a
       </info>
461f4a
+      <prop oor:name="InitializationVector" oor:type="xs:string">
461f4a
+        <info>
461f4a
+          <desc>Contains an initialization vector for the password encryption.</desc>
461f4a
+        </info>
461f4a
+      </prop>
461f4a
       <prop oor:name="Password" oor:type="xs:string" oor:localized="false">
461f4a
         <info>
461f4a
           <desc>Contains a password encoded with the master password.</desc>
461f4a
@@ -923,6 +928,11 @@
461f4a
         </info>
461f4a
         <value>false</value>
461f4a
       </prop>
461f4a
+      <prop oor:name="MasterInitializationVector" oor:type="xs:string">
461f4a
+        <info>
461f4a
+          <desc>Contains an initialization vector for the master password encryption.</desc>
461f4a
+        </info>
461f4a
+      </prop>
461f4a
       <prop oor:name="Master" oor:type="xs:string" oor:nillable="false">
461f4a
         <info>
461f4a
           <desc>Contains the master password encrypted by itself.</desc>
461f4a
diff --git a/svl/source/passwordcontainer/passwordcontainer.cxx b/svl/source/passwordcontainer/passwordcontainer.cxx
461f4a
index ff0b40df4016..380188ef495c 100644
461f4a
--- a/svl/source/passwordcontainer/passwordcontainer.cxx
461f4a
+++ b/svl/source/passwordcontainer/passwordcontainer.cxx
461f4a
@@ -184,15 +184,18 @@ PassMap StorageItem::getInfo()
461f4a
 
461f4a
     Sequence< OUString > aNodeNames     = ConfigItem::GetNodeNames( "Store" );
461f4a
     sal_Int32 aNodeCount = aNodeNames.getLength();
461f4a
-    Sequence< OUString > aPropNames( aNodeCount );
461f4a
+    Sequence< OUString > aPropNames( aNodeCount * 2);
461f4a
 
461f4a
     std::transform(aNodeNames.begin(), aNodeNames.end(), aPropNames.begin(),
461f4a
         [](const OUString& rName) -> OUString {
461f4a
             return "Store/Passwordstorage['" + rName + "']/Password"; });
461f4a
+    std::transform(aNodeNames.begin(), aNodeNames.end(), aPropNames.getArray() + aNodeCount,
461f4a
+        [](const OUString& rName) -> OUString {
461f4a
+            return "Store/Passwordstorage['" + rName + "']/InitializationVector"; });
461f4a
 
461f4a
     Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aPropNames );
461f4a
 
461f4a
-    if( aPropertyValues.getLength() != aNodeCount )
461f4a
+    if( aPropertyValues.getLength() != aNodeCount * 2)
461f4a
     {
461f4a
         OSL_FAIL( "Problems during reading" );
461f4a
         return aResult;
461f4a
@@ -208,14 +211,16 @@ PassMap StorageItem::getInfo()
461f4a
             OUString aName = aUrlUsr[1];
461f4a
 
461f4a
             OUString aEPasswd;
461f4a
+            OUString aIV;
461f4a
             aPropertyValues[aNodeInd] >>= aEPasswd;
461f4a
+            aPropertyValues[aNodeInd + aNodeCount] >>= aIV;
461f4a
 
461f4a
             PassMap::iterator aIter = aResult.find( aUrl );
461f4a
             if( aIter != aResult.end() )
461f4a
-                aIter->second.emplace_back( aName, aEPasswd );
461f4a
+                aIter->second.emplace_back( aName, aEPasswd, aIV );
461f4a
             else
461f4a
             {
461f4a
-                NamePassRecord aNewRecord( aName, aEPasswd );
461f4a
+                NamePassRecord aNewRecord( aName, aEPasswd, aIV );
461f4a
                 std::vector< NamePassRecord > listToAdd( 1, aNewRecord );
461f4a
 
461f4a
                 aResult.insert( PairUrlRecord( aUrl, listToAdd ) );
461f4a
@@ -279,17 +284,19 @@ sal_Int32 StorageItem::getStorageVersion()
461f4a
     return nResult;
461f4a
 }
461f4a
 
461f4a
-bool StorageItem::getEncodedMP( OUString& aResult )
461f4a
+bool StorageItem::getEncodedMP( OUString& aResult, OUString& aResultIV )
461f4a
 {
461f4a
     if( hasEncoded )
461f4a
     {
461f4a
         aResult = mEncoded;
461f4a
+        aResultIV = mEncodedIV;
461f4a
         return true;
461f4a
     }
461f4a
 
461f4a
-    Sequence< OUString > aNodeNames( 2 );
461f4a
+    Sequence< OUString > aNodeNames( 3 );
461f4a
     aNodeNames[0] = "HasMaster";
461f4a
     aNodeNames[1] = "Master";
461f4a
+    aNodeNames[2] = "MasterInitializationVector";
461f4a
 
461f4a
     Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
461f4a
 
461f4a
@@ -301,32 +308,37 @@ bool StorageItem::getEncodedMP( OUString& aResult )
461f4a
 
461f4a
     aPropertyValues[0] >>= hasEncoded;
461f4a
     aPropertyValues[1] >>= mEncoded;
461f4a
+    aPropertyValues[2] >>= mEncodedIV;
461f4a
 
461f4a
     aResult = mEncoded;
461f4a
+    aResultIV = mEncodedIV;
461f4a
 
461f4a
     return hasEncoded;
461f4a
 }
461f4a
 
461f4a
 
461f4a
-void StorageItem::setEncodedMP( const OUString& aEncoded, bool bAcceptEmpty )
461f4a
+void StorageItem::setEncodedMP( const OUString& aEncoded, const OUString& aEncodedIV, bool bAcceptEmpty )
461f4a
 {
461f4a
-    Sequence< OUString > sendNames(3);
461f4a
-    Sequence< uno::Any > sendVals(3);
461f4a
+    Sequence< OUString > sendNames(4);
461f4a
+    Sequence< uno::Any > sendVals(4);
461f4a
 
461f4a
     sendNames[0] = "HasMaster";
461f4a
     sendNames[1] = "Master";
461f4a
-    sendNames[2] = "StorageVersion";
461f4a
+    sendNames[2] = "MasterInitializationVector";
461f4a
+    sendNames[3] = "StorageVersion";
461f4a
 
461f4a
     bool bHasMaster = ( !aEncoded.isEmpty() || bAcceptEmpty );
461f4a
     sendVals[0] <<= bHasMaster;
461f4a
     sendVals[1] <<= aEncoded;
461f4a
-    sendVals[2] <<= nCurrentStorageVersion;
461f4a
+    sendVals[2] <<= aEncodedIV;
461f4a
+    sendVals[3] <<= nCurrentStorageVersion;
461f4a
 
461f4a
     ConfigItem::SetModified();
461f4a
     ConfigItem::PutProperties( sendNames, sendVals );
461f4a
 
461f4a
     hasEncoded = bHasMaster;
461f4a
     mEncoded = aEncoded;
461f4a
+    mEncodedIV = aEncodedIV;
461f4a
 }
461f4a
 
461f4a
 
461f4a
@@ -362,11 +374,13 @@ void StorageItem::update( const OUString& aURL, const NamePassRecord& aRecord )
461f4a
     forIndex.push_back( aURL );
461f4a
     forIndex.push_back( aRecord.GetUserName() );
461f4a
 
461f4a
-    Sequence< beans::PropertyValue > sendSeq(1);
461f4a
+    Sequence< beans::PropertyValue > sendSeq(2);
461f4a
 
461f4a
-    sendSeq[0].Name  = "Store/Passwordstorage['" + createIndex( forIndex ) + "']/Password";
461f4a
+    sendSeq[0].Name  = "Store/Passwordstorage['" + createIndex( { aURL, aRecord.GetUserName() } ) + "']/InitializationVector";
461f4a
+    sendSeq[0].Value <<= aRecord.GetPersistentIV();
461f4a
 
461f4a
-    sendSeq[0].Value <<= aRecord.GetPersPasswords();
461f4a
+    sendSeq[1].Name  = "Store/Passwordstorage['" + createIndex( forIndex ) + "']/Password";
461f4a
+    sendSeq[1].Value <<= aRecord.GetPersPasswords();
461f4a
 
461f4a
     ConfigItem::SetModified();
461f4a
     ConfigItem::SetSetProperties( "Store", sendSeq );
461f4a
@@ -427,7 +441,7 @@ void SAL_CALL PasswordContainer::disposing( const EventObject& )
461f4a
     }
461f4a
 }
461f4a
 
461f4a
-std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLine, const OUString& aMasterPasswd, css::task::PasswordRequestMode mode )
461f4a
+std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLine, const OUString& aIV, const OUString& aMasterPasswd, css::task::PasswordRequestMode mode )
461f4a
 {
461f4a
     if( !aMasterPasswd.isEmpty() )
461f4a
     {
461f4a
@@ -442,9 +456,16 @@ std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLin
461f4a
             for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
461f4a
                 code[ ind ] = static_cast<char>(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
461f4a
 
461f4a
+            unsigned char iv[RTL_DIGEST_LENGTH_MD5] = {0};
461f4a
+            if (!aIV.isEmpty())
461f4a
+            {
461f4a
+                for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
461f4a
+                    iv[ ind ] = static_cast<char>(aIV.copy( ind*2, 2 ).toUInt32(16));
461f4a
+            }
461f4a
+
461f4a
             rtlCipherError result = rtl_cipher_init (
461f4a
                     aDecoder, rtl_Cipher_DirectionDecode,
461f4a
-                    code, RTL_DIGEST_LENGTH_MD5, nullptr, 0 );
461f4a
+                    code, RTL_DIGEST_LENGTH_MD5, iv, RTL_DIGEST_LENGTH_MD5 );
461f4a
 
461f4a
             if( result == rtl_Cipher_E_None )
461f4a
             {
461f4a
@@ -477,7 +498,7 @@ std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLin
461f4a
         "Can't decode!", css::uno::Reference<css::uno::XInterface>(), mode);
461f4a
 }
461f4a
 
461f4a
-OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines, const OUString& aMasterPasswd )
461f4a
+OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines, const OUString& aIV, const OUString& aMasterPasswd)
461f4a
 {
461f4a
     if( !aMasterPasswd.isEmpty() )
461f4a
     {
461f4a
@@ -494,9 +515,16 @@ OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines
461f4a
             for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
461f4a
                 code[ ind ] = static_cast<char>(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
461f4a
 
461f4a
+            unsigned char iv[RTL_DIGEST_LENGTH_MD5] = {0};
461f4a
+            if (!aIV.isEmpty())
461f4a
+            {
461f4a
+                for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
461f4a
+                    iv[ ind ] = static_cast<char>(aIV.copy( ind*2, 2 ).toUInt32(16));
461f4a
+            }
461f4a
+
461f4a
             rtlCipherError result = rtl_cipher_init (
461f4a
                     aEncoder, rtl_Cipher_DirectionEncode,
461f4a
-                    code, RTL_DIGEST_LENGTH_MD5, nullptr, 0 );
461f4a
+                    code, RTL_DIGEST_LENGTH_MD5, iv, RTL_DIGEST_LENGTH_MD5 );
461f4a
 
461f4a
             if( result == rtl_Cipher_E_None )
461f4a
             {
461f4a
@@ -564,7 +592,7 @@ void PasswordContainer::UpdateVector( const OUString& aURL, std::vector< NamePas
461f4a
 
461f4a
             if( aRecord.HasPasswords( PERSISTENT_RECORD ) )
461f4a
             {
461f4a
-                aNPIter.SetPersPasswords( aRecord.GetPersPasswords() );
461f4a
+                aNPIter.SetPersPasswords( aRecord.GetPersPasswords(), aRecord.GetPersistentIV() );
461f4a
 
461f4a
                 if( writeFile )
461f4a
                 {
461f4a
@@ -597,7 +625,8 @@ UserRecord PasswordContainer::CopyToUserRecord( const NamePassRecord& aRecord, b
461f4a
     {
461f4a
         try
461f4a
         {
461f4a
-            ::std::vector< OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersPasswords(), GetMasterPassword( aHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER );
461f4a
+            ::std::vector< OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersPasswords(), aRecord.GetPersistentIV(),
461f4a
+                                                                           GetMasterPassword( aHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER );
461f4a
             aPasswords.insert( aPasswords.end(), aDecodedPasswords.begin(), aDecodedPasswords.end() );
461f4a
         }
461f4a
         catch( NoMasterException& )
461f4a
@@ -642,6 +671,19 @@ void SAL_CALL PasswordContainer::addPersistent( const OUString& Url, const OUStr
461f4a
     PrivateAdd( Url, UserName, Passwords, PERSISTENT_RECORD, aHandler );
461f4a
 }
461f4a
 
461f4a
+OUString PasswordContainer::createIV()
461f4a
+{
461f4a
+    rtlRandomPool randomPool = mRandomPool.get();
461f4a
+    unsigned char iv[RTL_DIGEST_LENGTH_MD5];
461f4a
+    rtl_random_getBytes(randomPool, iv, RTL_DIGEST_LENGTH_MD5);
461f4a
+    OUStringBuffer aBuffer;
461f4a
+    for (sal_uInt8 i : iv)
461f4a
+    {
461f4a
+        aBuffer.append(OUString::number(i >> 4, 16));
461f4a
+        aBuffer.append(OUString::number(i & 15, 16));
461f4a
+    }
461f4a
+    return aBuffer.makeStringAndClear();
461f4a
+}
461f4a
 
461f4a
 void PasswordContainer::PrivateAdd( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, char Mode, const Reference< XInteractionHandler >& aHandler )
461f4a
 {
461f4a
@@ -649,7 +691,11 @@ void PasswordContainer::PrivateAdd( const OUString& Url, const OUString& UserNam
461f4a
     ::std::vector< OUString > aStorePass = comphelper::sequenceToContainer< std::vector<OUString> >( Passwords );
461f4a
 
461f4a
     if( Mode == PERSISTENT_RECORD )
461f4a
-        aRecord.SetPersPasswords( EncodePasswords( aStorePass, GetMasterPassword( aHandler ) ) );
461f4a
+    {
461f4a
+        OUString sIV = createIV();
461f4a
+        OUString sEncodedPasswords = EncodePasswords( aStorePass, sIV, GetMasterPassword( aHandler ) );
461f4a
+        aRecord.SetPersPasswords( sEncodedPasswords, sIV );
461f4a
+    }
461f4a
     else if( Mode == MEMORY_RECORD )
461f4a
         aRecord.SetMemPasswords( aStorePass );
461f4a
     else
461f4a
@@ -842,10 +888,10 @@ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInterac
461f4a
 
461f4a
     if( m_aMasterPasswd.isEmpty() && aHandler.is() )
461f4a
     {
461f4a
-        OUString aEncodedMP;
461f4a
+        OUString aEncodedMP, aEncodedMPIV;
461f4a
         bool bDefaultPassword = false;
461f4a
 
461f4a
-        if( !m_pStorageFile->getEncodedMP( aEncodedMP ) )
461f4a
+        if( !m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) )
461f4a
             aRMode = PasswordRequestMode_PASSWORD_CREATE;
461f4a
         else if ( aEncodedMP.isEmpty() )
461f4a
         {
461f4a
@@ -867,14 +913,15 @@ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInterac
461f4a
                         m_aMasterPasswd = aPass;
461f4a
                         std::vector< OUString > aMaster( 1, m_aMasterPasswd );
461f4a
 
461f4a
-                        m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) );
461f4a
+                        OUString sIV = createIV();
461f4a
+                        m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, sIV, m_aMasterPasswd ), sIV );
461f4a
                     }
461f4a
                     else
461f4a
                     {
461f4a
                         if (m_pStorageFile->getStorageVersion() == 0)
461f4a
                             aPass = ReencodeAsOldHash(aPass);
461f4a
 
461f4a
-                        std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass, aRMode ) );
461f4a
+                        std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aEncodedMPIV, aPass, aRMode ) );
461f4a
                         if( aRM.empty() || aPass != aRM[0] )
461f4a
                         {
461f4a
                             bAskAgain = true;
461f4a
@@ -1031,7 +1078,8 @@ Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Refere
461f4a
             {
461f4a
                 sal_Int32 oldLen = aUsers.getLength();
461f4a
                 aUsers.realloc( oldLen + 1 );
461f4a
-                aUsers[ oldLen ] = UserRecord( aNP.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP.GetPersPasswords(), GetMasterPassword( xHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER ) ) );
461f4a
+                aUsers[ oldLen ] = UserRecord( aNP.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP.GetPersPasswords(), aNP.GetPersistentIV(),
461f4a
+                                                                                                                    GetMasterPassword( xHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER ) ) );
461f4a
             }
461f4a
 
461f4a
         if( aUsers.hasElements() )
461f4a
@@ -1048,12 +1096,12 @@ Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Refere
461f4a
 sal_Bool SAL_CALL PasswordContainer::authorizateWithMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
461f4a
 {
461f4a
     bool bResult = false;
461f4a
-    OUString aEncodedMP;
461f4a
+    OUString aEncodedMP, aEncodedMPIV;
461f4a
     uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
461f4a
     ::osl::MutexGuard aGuard( mMutex );
461f4a
 
461f4a
     // the method should fail if there is no master password
461f4a
-    if( m_pStorageFile && m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) )
461f4a
+    if( m_pStorageFile && m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) )
461f4a
     {
461f4a
         if ( aEncodedMP.isEmpty() )
461f4a
         {
461f4a
@@ -1122,8 +1170,8 @@ sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference<
461f4a
 
461f4a
         bool bCanChangePassword = true;
461f4a
         // if there is already a stored master password it should be entered by the user before the change happen
461f4a
-        OUString aEncodedMP;
461f4a
-        if( !m_aMasterPasswd.isEmpty() || m_pStorageFile->getEncodedMP( aEncodedMP ) )
461f4a
+        OUString aEncodedMP, aEncodedMPIV;
461f4a
+        if( !m_aMasterPasswd.isEmpty() || m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) )
461f4a
             bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
461f4a
 
461f4a
         if ( bCanChangePassword )
461f4a
@@ -1142,7 +1190,8 @@ sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference<
461f4a
                 // store the new master password
461f4a
                 m_aMasterPasswd = aPass;
461f4a
                 std::vector< OUString > aMaster( 1, m_aMasterPasswd );
461f4a
-                m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) );
461f4a
+                OUString aIV = createIV();
461f4a
+                m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, aIV, m_aMasterPasswd ), aIV );
461f4a
 
461f4a
                 // store all the entries with the new password
461f4a
                 for ( const auto& rURL : aPersistent )
461f4a
@@ -1167,7 +1216,7 @@ void SAL_CALL PasswordContainer::removeMasterPassword()
461f4a
     if ( m_pStorageFile )
461f4a
     {
461f4a
         m_aMasterPasswd.clear();
461f4a
-        m_pStorageFile->setEncodedMP( OUString() ); // let the master password be removed from configuration
461f4a
+        m_pStorageFile->setEncodedMP( OUString(), OUString() ); // let the master password be removed from configuration
461f4a
     }
461f4a
 }
461f4a
 
461f4a
@@ -1178,8 +1227,8 @@ sal_Bool SAL_CALL PasswordContainer::hasMasterPassword(  )
461f4a
     if ( !m_pStorageFile )
461f4a
         throw uno::RuntimeException();
461f4a
 
461f4a
-    OUString aEncodedMP;
461f4a
-    return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) );
461f4a
+    OUString aEncodedMP, aEncodedMPIV;
461f4a
+    return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) );
461f4a
 }
461f4a
 
461f4a
 sal_Bool SAL_CALL PasswordContainer::allowPersistentStoring( sal_Bool bAllow )
461f4a
@@ -1226,8 +1275,8 @@ sal_Bool SAL_CALL PasswordContainer::useDefaultMasterPassword( const uno::Refere
461f4a
 
461f4a
         bool bCanChangePassword = true;
461f4a
         // if there is already a stored nondefault master password it should be entered by the user before the change happen
461f4a
-        OUString aEncodedMP;
461f4a
-        if( m_pStorageFile->getEncodedMP( aEncodedMP ) && !aEncodedMP.isEmpty() )
461f4a
+        OUString aEncodedMP, aEncodedMPIV;
461f4a
+        if( m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) && !aEncodedMP.isEmpty() )
461f4a
             bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
461f4a
 
461f4a
         if ( bCanChangePassword )
461f4a
@@ -1244,7 +1293,7 @@ sal_Bool SAL_CALL PasswordContainer::useDefaultMasterPassword( const uno::Refere
461f4a
 
461f4a
                 // store the empty string to flag the default master password
461f4a
                 m_aMasterPasswd = aPass;
461f4a
-                m_pStorageFile->setEncodedMP( OUString(), true );
461f4a
+                m_pStorageFile->setEncodedMP( OUString(), OUString(), true );
461f4a
 
461f4a
                 // store all the entries with the new password
461f4a
                 for ( const auto& rURL : aPersistent )
461f4a
@@ -1268,8 +1317,8 @@ sal_Bool SAL_CALL PasswordContainer::isDefaultMasterPasswordUsed()
461f4a
     if ( !m_pStorageFile )
461f4a
         throw uno::RuntimeException();
461f4a
 
461f4a
-    OUString aEncodedMP;
461f4a
-    return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) && aEncodedMP.isEmpty() );
461f4a
+    OUString aEncodedMP, aEncodedMPIV;
461f4a
+    return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) && aEncodedMP.isEmpty() );
461f4a
 }
461f4a
 
461f4a
 
461f4a
diff --git a/svl/source/passwordcontainer/passwordcontainer.hxx b/svl/source/passwordcontainer/passwordcontainer.hxx
461f4a
index cf5c717d0c9e..4e3a6629139e 100644
461f4a
--- a/svl/source/passwordcontainer/passwordcontainer.hxx
461f4a
+++ b/svl/source/passwordcontainer/passwordcontainer.hxx
461f4a
@@ -33,6 +33,7 @@
461f4a
 #include <unotools/configitem.hxx>
461f4a
 #include <ucbhelper/interactionrequest.hxx>
461f4a
 
461f4a
+#include <rtl/random.h>
461f4a
 #include <rtl/ref.hxx>
461f4a
 #include <osl/mutex.hxx>
461f4a
 
461f4a
@@ -51,11 +52,12 @@ class NamePassRecord
461f4a
     ::std::vector< OUString >                      m_aMemPass;
461f4a
 
461f4a
     // persistent passwords are encrypted in one string
461f4a
-    bool                                                  m_bHasPersPass;
461f4a
+    bool                                           m_bHasPersPass;
461f4a
     OUString                                       m_aPersPass;
461f4a
+    OUString                                       m_aPersistentIV;
461f4a
 
461f4a
     void InitArrays( bool bHasMemoryList, const ::std::vector< OUString >& aMemoryList,
461f4a
-                     bool bHasPersistentList, const OUString& aPersistentList )
461f4a
+                     bool bHasPersistentList, const OUString& aPersistentList, const OUString& aPersistentIV )
461f4a
     {
461f4a
         m_bHasMemPass = bHasMemoryList;
461f4a
         if ( bHasMemoryList )
461f4a
@@ -63,7 +65,10 @@ class NamePassRecord
461f4a
 
461f4a
         m_bHasPersPass = bHasPersistentList;
461f4a
         if ( bHasPersistentList )
461f4a
+        {
461f4a
             m_aPersPass = aPersistentList;
461f4a
+            m_aPersistentIV = aPersistentIV;
461f4a
+        }
461f4a
     }
461f4a
 
461f4a
 public:
461f4a
@@ -75,11 +80,12 @@ public:
461f4a
     {
461f4a
     }
461f4a
 
461f4a
-    NamePassRecord( const OUString& aName, const OUString& aPersistentList )
461f4a
+    NamePassRecord( const OUString& aName, const OUString& aPersistentList, const OUString& aPersistentIV )
461f4a
         : m_aName( aName )
461f4a
         , m_bHasMemPass( false )
461f4a
         , m_bHasPersPass( true )
461f4a
         , m_aPersPass( aPersistentList )
461f4a
+        , m_aPersistentIV( aPersistentIV )
461f4a
     {
461f4a
     }
461f4a
 
461f4a
@@ -88,7 +94,8 @@ public:
461f4a
         , m_bHasMemPass( false )
461f4a
         , m_bHasPersPass( false )
461f4a
     {
461f4a
-        InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass, aRecord.m_bHasPersPass, aRecord.m_aPersPass );
461f4a
+        InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass,
461f4a
+                    aRecord.m_bHasPersPass, aRecord.m_aPersPass, aRecord.m_aPersistentIV );
461f4a
     }
461f4a
 
461f4a
     NamePassRecord& operator=( const NamePassRecord& aRecord )
461f4a
@@ -99,7 +106,9 @@ public:
461f4a
 
461f4a
             m_aMemPass.clear();
461f4a
             m_aPersPass.clear();
461f4a
-            InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass, aRecord.m_bHasPersPass, aRecord.m_aPersPass );
461f4a
+            m_aPersistentIV.clear();
461f4a
+            InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass,
461f4a
+                        aRecord.m_bHasPersPass, aRecord.m_aPersPass, aRecord.m_aPersistentIV );
461f4a
         }
461f4a
         return *this;
461f4a
     }
461f4a
@@ -135,15 +144,24 @@ public:
461f4a
         return OUString();
461f4a
     }
461f4a
 
461f4a
+    OUString GetPersistentIV() const
461f4a
+    {
461f4a
+        if ( m_bHasPersPass )
461f4a
+            return m_aPersistentIV;
461f4a
+
461f4a
+        return OUString();
461f4a
+    }
461f4a
+
461f4a
     void SetMemPasswords( const ::std::vector< OUString >& aMemList )
461f4a
     {
461f4a
         m_aMemPass = aMemList;
461f4a
         m_bHasMemPass = true;
461f4a
     }
461f4a
 
461f4a
-    void SetPersPasswords( const OUString& aPersList )
461f4a
+    void SetPersPasswords( const OUString& aPersList, const OUString& aPersIV )
461f4a
     {
461f4a
         m_aPersPass = aPersList;
461f4a
+        m_aPersistentIV = aPersIV;
461f4a
         m_bHasPersPass = true;
461f4a
     }
461f4a
 
461f4a
@@ -158,6 +176,7 @@ public:
461f4a
         {
461f4a
             m_bHasPersPass = false;
461f4a
             m_aPersPass.clear();
461f4a
+            m_aPersistentIV.clear();
461f4a
         }
461f4a
     }
461f4a
 
461f4a
@@ -181,6 +200,7 @@ private:
461f4a
     PasswordContainer*     mainCont;
461f4a
     bool                   hasEncoded;
461f4a
     OUString        mEncoded;
461f4a
+    OUString        mEncodedIV;
461f4a
 
461f4a
     virtual void            ImplCommit() override;
461f4a
 
461f4a
@@ -201,8 +221,8 @@ public:
461f4a
 
461f4a
     sal_Int32 getStorageVersion();
461f4a
 
461f4a
-    bool getEncodedMP( OUString& aResult );
461f4a
-    void setEncodedMP( const OUString& aResult, bool bAcceptEnmpty = false );
461f4a
+    bool getEncodedMP( OUString& aResult, OUString& aResultIV );
461f4a
+    void setEncodedMP( const OUString& aResult, const OUString& aResultIV, bool bAcceptEmpty = false );
461f4a
     void setUseStorage( bool bUse );
461f4a
     bool useStorage();
461f4a
 
461f4a
@@ -223,6 +243,29 @@ private:
461f4a
     css::uno::Reference< css::lang::XComponent > mComponent;
461f4a
     SysCredentialsConfig mUrlContainer;
461f4a
 
461f4a
+    class RandomPool
461f4a
+    {
461f4a
+    private:
461f4a
+        rtlRandomPool m_aRandomPool;
461f4a
+    public:
461f4a
+        RandomPool() : m_aRandomPool(rtl_random_createPool())
461f4a
+        {
461f4a
+        }
461f4a
+        rtlRandomPool get()
461f4a
+        {
461f4a
+            return m_aRandomPool;
461f4a
+        }
461f4a
+        ~RandomPool()
461f4a
+        {
461f4a
+            // Clean up random pool memory
461f4a
+            rtl_random_destroyPool(m_aRandomPool);
461f4a
+        }
461f4a
+    };
461f4a
+
461f4a
+    RandomPool mRandomPool;
461f4a
+
461f4a
+    OUString createIV();
461f4a
+
461f4a
     /// @throws css::uno::RuntimeException
461f4a
     css::uno::Sequence< css::task::UserRecord > CopyToUserRecordSequence(
461f4a
                                         const ::std::vector< NamePassRecord >& original,
461f4a
@@ -273,10 +316,10 @@ css::task::UrlRecord find(
461f4a
                               const css::uno::Reference< css::task::XInteractionHandler >& Handler );
461f4a
 
461f4a
     /// @throws css::uno::RuntimeException
461f4a
-    static ::std::vector< OUString > DecodePasswords( const OUString& aLine, const OUString& aMasterPassword, css::task::PasswordRequestMode mode );
461f4a
+    static ::std::vector< OUString > DecodePasswords( const OUString& aLine, const OUString& aIV, const OUString& aMasterPassword, css::task::PasswordRequestMode mode );
461f4a
 
461f4a
     /// @throws css::uno::RuntimeException
461f4a
-    static OUString EncodePasswords(const std::vector< OUString >& lines, const OUString& aMasterPassword );
461f4a
+    static OUString EncodePasswords(const std::vector< OUString >& lines, const OUString& aIV, const OUString& aMasterPassword );
461f4a
 
461f4a
 public:
461f4a
     PasswordContainer( const css::uno::Reference< css::lang::XMultiServiceFactory >& );
461f4a
-- 
461f4a
2.37.1
461f4a