summaryrefslogtreecommitdiffstats
path: root/debian/patches/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch')
-rw-r--r--debian/patches/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch583
1 files changed, 583 insertions, 0 deletions
diff --git a/debian/patches/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch b/debian/patches/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch
new file mode 100644
index 000000000..b65b3530c
--- /dev/null
+++ b/debian/patches/0003-CVE-2022-26306-add-Initialization-Vectors-to-passwor.patch
@@ -0,0 +1,583 @@
+From e809625c2ca9f0c026aab9b5c2d13ced628c13e9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
+Date: Tue, 22 Mar 2022 17:22:22 +0000
+Subject: [PATCH 3/4] CVE-2022-26306 add Initialization Vectors to password
+ storage
+
+old ones default to the current all zero case and continue to work
+as before
+
+Change-Id: I6fe3b02fafcce1b5e7133e77e76a5118177d77af
+Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131974
+Tested-by: Jenkins
+Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
+(cherry picked from commit 192fa1e3bfc6269f2ebb91716471485a56074aea)
+Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132306
+Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
+(cherry picked from commit ab77587ec300f5c30084471000663c46ddf25dad)
+---
+ .../schema/org/openoffice/Office/Common.xcs | 10 ++
+ .../passwordcontainer/passwordcontainer.cxx | 127 ++++++++++++------
+ .../passwordcontainer/passwordcontainer.hxx | 63 +++++++--
+ 3 files changed, 151 insertions(+), 49 deletions(-)
+
+diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+index 922efc33cca7..8d87d00d5369 100644
+--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
++++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+@@ -27,6 +27,11 @@
+ <info>
+ <desc>Contains a container for passwords.</desc>
+ </info>
++ <prop oor:name="InitializationVector" oor:type="xs:string">
++ <info>
++ <desc>Contains an initialization vector for the password encryption.</desc>
++ </info>
++ </prop>
+ <prop oor:name="Password" oor:type="xs:string" oor:localized="false">
+ <info>
+ <desc>Contains a password encoded with the master password.</desc>
+@@ -954,6 +959,11 @@
+ </info>
+ <value>false</value>
+ </prop>
++ <prop oor:name="MasterInitializationVector" oor:type="xs:string">
++ <info>
++ <desc>Contains an initialization vector for the master password encryption.</desc>
++ </info>
++ </prop>
+ <prop oor:name="Master" oor:type="xs:string" oor:nillable="false">
+ <info>
+ <desc>Contains the master password encrypted by itself.</desc>
+diff --git a/svl/source/passwordcontainer/passwordcontainer.cxx b/svl/source/passwordcontainer/passwordcontainer.cxx
+index b674844f91d3..ef79470a2cb6 100644
+--- a/svl/source/passwordcontainer/passwordcontainer.cxx
++++ b/svl/source/passwordcontainer/passwordcontainer.cxx
+@@ -181,15 +181,18 @@ PassMap StorageItem::getInfo()
+
+ Sequence< OUString > aNodeNames = ConfigItem::GetNodeNames( "Store" );
+ sal_Int32 aNodeCount = aNodeNames.getLength();
+- Sequence< OUString > aPropNames( aNodeCount );
++ Sequence< OUString > aPropNames( aNodeCount * 2);
+
+ std::transform(aNodeNames.begin(), aNodeNames.end(), aPropNames.begin(),
+ [](const OUString& rName) -> OUString {
+ return "Store/Passwordstorage['" + rName + "']/Password"; });
++ std::transform(aNodeNames.begin(), aNodeNames.end(), aPropNames.getArray() + aNodeCount,
++ [](const OUString& rName) -> OUString {
++ return "Store/Passwordstorage['" + rName + "']/InitializationVector"; });
+
+ Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aPropNames );
+
+- if( aPropertyValues.getLength() != aNodeCount )
++ if( aPropertyValues.getLength() != aNodeCount * 2)
+ {
+ OSL_FAIL( "Problems during reading" );
+ return aResult;
+@@ -205,14 +208,16 @@ PassMap StorageItem::getInfo()
+ OUString aName = aUrlUsr[1];
+
+ OUString aEPasswd;
++ OUString aIV;
+ aPropertyValues[aNodeInd] >>= aEPasswd;
++ aPropertyValues[aNodeInd + aNodeCount] >>= aIV;
+
+ PassMap::iterator aIter = aResult.find( aUrl );
+ if( aIter != aResult.end() )
+- aIter->second.emplace_back( aName, aEPasswd );
++ aIter->second.emplace_back( aName, aEPasswd, aIV );
+ else
+ {
+- NamePassRecord aNewRecord( aName, aEPasswd );
++ NamePassRecord aNewRecord( aName, aEPasswd, aIV );
+ std::vector< NamePassRecord > listToAdd( 1, aNewRecord );
+
+ aResult.insert( PairUrlRecord( aUrl, listToAdd ) );
+@@ -276,17 +281,19 @@ sal_Int32 StorageItem::getStorageVersion()
+ return nResult;
+ }
+
+-bool StorageItem::getEncodedMP( OUString& aResult )
++bool StorageItem::getEncodedMP( OUString& aResult, OUString& aResultIV )
+ {
+ if( hasEncoded )
+ {
+ aResult = mEncoded;
++ aResultIV = mEncodedIV;
+ return true;
+ }
+
+- Sequence< OUString > aNodeNames( 2 );
++ Sequence< OUString > aNodeNames( 3 );
+ aNodeNames[0] = "HasMaster";
+ aNodeNames[1] = "Master";
++ aNodeNames[2] = "MasterInitializationVector";
+
+ Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
+
+@@ -298,32 +305,37 @@ bool StorageItem::getEncodedMP( OUString& aResult )
+
+ aPropertyValues[0] >>= hasEncoded;
+ aPropertyValues[1] >>= mEncoded;
++ aPropertyValues[2] >>= mEncodedIV;
+
+ aResult = mEncoded;
++ aResultIV = mEncodedIV;
+
+ return hasEncoded;
+ }
+
+
+-void StorageItem::setEncodedMP( const OUString& aEncoded, bool bAcceptEmpty )
++void StorageItem::setEncodedMP( const OUString& aEncoded, const OUString& aEncodedIV, bool bAcceptEmpty )
+ {
+- Sequence< OUString > sendNames(3);
+- Sequence< uno::Any > sendVals(3);
++ Sequence< OUString > sendNames(4);
++ Sequence< uno::Any > sendVals(4);
+
+ sendNames[0] = "HasMaster";
+ sendNames[1] = "Master";
+- sendNames[2] = "StorageVersion";
++ sendNames[2] = "MasterInitializationVector";
++ sendNames[3] = "StorageVersion";
+
+ bool bHasMaster = ( !aEncoded.isEmpty() || bAcceptEmpty );
+ sendVals[0] <<= bHasMaster;
+ sendVals[1] <<= aEncoded;
+- sendVals[2] <<= nCurrentStorageVersion;
++ sendVals[2] <<= aEncodedIV;
++ sendVals[3] <<= nCurrentStorageVersion;
+
+ ConfigItem::SetModified();
+ ConfigItem::PutProperties( sendNames, sendVals );
+
+ hasEncoded = bHasMaster;
+ mEncoded = aEncoded;
++ mEncodedIV = aEncodedIV;
+ }
+
+
+@@ -359,11 +371,13 @@ void StorageItem::update( const OUString& aURL, const NamePassRecord& aRecord )
+ forIndex.push_back( aURL );
+ forIndex.push_back( aRecord.GetUserName() );
+
+- Sequence< beans::PropertyValue > sendSeq(1);
++ Sequence< beans::PropertyValue > sendSeq(2);
+
+- sendSeq[0].Name = "Store/Passwordstorage['" + createIndex( forIndex ) + "']/Password";
++ sendSeq[0].Name = "Store/Passwordstorage['" + createIndex( forIndex ) + "']/InitializationVector";
++ sendSeq[0].Value <<= aRecord.GetPersistentIV();
+
+- sendSeq[0].Value <<= aRecord.GetPersPasswords();
++ sendSeq[1].Name = "Store/Passwordstorage['" + createIndex( forIndex ) + "']/Password";
++ sendSeq[1].Value <<= aRecord.GetPersPasswords();
+
+ ConfigItem::SetModified();
+ ConfigItem::SetSetProperties( "Store", sendSeq );
+@@ -424,7 +438,7 @@ void SAL_CALL PasswordContainer::disposing( const EventObject& )
+ }
+ }
+
+-std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLine, const OUString& aMasterPasswd, css::task::PasswordRequestMode mode )
++std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLine, const OUString& aIV, const OUString& aMasterPasswd, css::task::PasswordRequestMode mode )
+ {
+ if( !aMasterPasswd.isEmpty() )
+ {
+@@ -439,9 +453,16 @@ std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLin
+ for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
+ code[ ind ] = static_cast<char>(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
+
++ unsigned char iv[RTL_DIGEST_LENGTH_MD5] = {0};
++ if (!aIV.isEmpty())
++ {
++ for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
++ iv[ ind ] = static_cast<char>(aIV.copy( ind*2, 2 ).toUInt32(16));
++ }
++
+ rtlCipherError result = rtl_cipher_init (
+ aDecoder, rtl_Cipher_DirectionDecode,
+- code, RTL_DIGEST_LENGTH_MD5, nullptr, 0 );
++ code, RTL_DIGEST_LENGTH_MD5, iv, RTL_DIGEST_LENGTH_MD5 );
+
+ if( result == rtl_Cipher_E_None )
+ {
+@@ -474,7 +495,7 @@ std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLin
+ "Can't decode!", css::uno::Reference<css::uno::XInterface>(), mode);
+ }
+
+-OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines, const OUString& aMasterPasswd )
++OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines, const OUString& aIV, const OUString& aMasterPasswd)
+ {
+ if( !aMasterPasswd.isEmpty() )
+ {
+@@ -491,9 +512,16 @@ OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines
+ for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
+ code[ ind ] = static_cast<char>(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
+
++ unsigned char iv[RTL_DIGEST_LENGTH_MD5] = {0};
++ if (!aIV.isEmpty())
++ {
++ for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
++ iv[ ind ] = static_cast<char>(aIV.copy( ind*2, 2 ).toUInt32(16));
++ }
++
+ rtlCipherError result = rtl_cipher_init (
+ aEncoder, rtl_Cipher_DirectionEncode,
+- code, RTL_DIGEST_LENGTH_MD5, nullptr, 0 );
++ code, RTL_DIGEST_LENGTH_MD5, iv, RTL_DIGEST_LENGTH_MD5 );
+
+ if( result == rtl_Cipher_E_None )
+ {
+@@ -561,7 +589,7 @@ void PasswordContainer::UpdateVector( const OUString& aURL, std::vector< NamePas
+
+ if( aRecord.HasPasswords( PERSISTENT_RECORD ) )
+ {
+- aNPIter.SetPersPasswords( aRecord.GetPersPasswords() );
++ aNPIter.SetPersPasswords( aRecord.GetPersPasswords(), aRecord.GetPersistentIV() );
+
+ if( writeFile )
+ {
+@@ -594,7 +622,8 @@ UserRecord PasswordContainer::CopyToUserRecord( const NamePassRecord& aRecord, b
+ {
+ try
+ {
+- ::std::vector< OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersPasswords(), GetMasterPassword( aHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER );
++ ::std::vector< OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersPasswords(), aRecord.GetPersistentIV(),
++ GetMasterPassword( aHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER );
+ aPasswords.insert( aPasswords.end(), aDecodedPasswords.begin(), aDecodedPasswords.end() );
+ }
+ catch( NoMasterException& )
+@@ -639,6 +668,19 @@ void SAL_CALL PasswordContainer::addPersistent( const OUString& Url, const OUStr
+ PrivateAdd( Url, UserName, Passwords, PERSISTENT_RECORD, aHandler );
+ }
+
++OUString PasswordContainer::createIV()
++{
++ rtlRandomPool randomPool = mRandomPool.get();
++ unsigned char iv[RTL_DIGEST_LENGTH_MD5];
++ rtl_random_getBytes(randomPool, iv, RTL_DIGEST_LENGTH_MD5);
++ OUStringBuffer aBuffer;
++ for (sal_uInt8 i : iv)
++ {
++ aBuffer.append(OUString::number(i >> 4, 16));
++ aBuffer.append(OUString::number(i & 15, 16));
++ }
++ return aBuffer.makeStringAndClear();
++}
+
+ void PasswordContainer::PrivateAdd( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, char Mode, const Reference< XInteractionHandler >& aHandler )
+ {
+@@ -646,7 +688,11 @@ void PasswordContainer::PrivateAdd( const OUString& Url, const OUString& UserNam
+ ::std::vector< OUString > aStorePass = comphelper::sequenceToContainer< std::vector<OUString> >( Passwords );
+
+ if( Mode == PERSISTENT_RECORD )
+- aRecord.SetPersPasswords( EncodePasswords( aStorePass, GetMasterPassword( aHandler ) ) );
++ {
++ OUString sIV = createIV();
++ OUString sEncodedPasswords = EncodePasswords( aStorePass, sIV, GetMasterPassword( aHandler ) );
++ aRecord.SetPersPasswords( sEncodedPasswords, sIV );
++ }
+ else if( Mode == MEMORY_RECORD )
+ aRecord.SetMemPasswords( aStorePass );
+ else
+@@ -839,10 +885,10 @@ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInterac
+
+ if( m_aMasterPasswd.isEmpty() && aHandler.is() )
+ {
+- OUString aEncodedMP;
++ OUString aEncodedMP, aEncodedMPIV;
+ bool bDefaultPassword = false;
+
+- if( !m_pStorageFile->getEncodedMP( aEncodedMP ) )
++ if( !m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) )
+ aRMode = PasswordRequestMode_PASSWORD_CREATE;
+ else if ( aEncodedMP.isEmpty() )
+ {
+@@ -864,14 +910,15 @@ OUString const & PasswordContainer::GetMasterPassword( const Reference< XInterac
+ m_aMasterPasswd = aPass;
+ std::vector< OUString > aMaster( 1, m_aMasterPasswd );
+
+- m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) );
++ OUString sIV = createIV();
++ m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, sIV, m_aMasterPasswd ), sIV );
+ }
+ else
+ {
+ if (m_pStorageFile->getStorageVersion() == 0)
+ aPass = ReencodeAsOldHash(aPass);
+
+- std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass, aRMode ) );
++ std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aEncodedMPIV, aPass, aRMode ) );
+ if( aRM.empty() || aPass != aRM[0] )
+ {
+ bAskAgain = true;
+@@ -1028,7 +1075,8 @@ Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Refere
+ {
+ sal_Int32 oldLen = aUsers.getLength();
+ aUsers.realloc( oldLen + 1 );
+- aUsers[ oldLen ] = UserRecord( aNP.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP.GetPersPasswords(), GetMasterPassword( xHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER ) ) );
++ aUsers[ oldLen ] = UserRecord( aNP.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP.GetPersPasswords(), aNP.GetPersistentIV(),
++ GetMasterPassword( xHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER ) ) );
+ }
+
+ if( aUsers.hasElements() )
+@@ -1045,12 +1093,12 @@ Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Refere
+ sal_Bool SAL_CALL PasswordContainer::authorizateWithMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
+ {
+ bool bResult = false;
+- OUString aEncodedMP;
++ OUString aEncodedMP, aEncodedMPIV;
+ uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
+ ::osl::MutexGuard aGuard( mMutex );
+
+ // the method should fail if there is no master password
+- if( m_pStorageFile && m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) )
++ if( m_pStorageFile && m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) )
+ {
+ if ( aEncodedMP.isEmpty() )
+ {
+@@ -1118,8 +1166,8 @@ sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference<
+
+ bool bCanChangePassword = true;
+ // if there is already a stored master password it should be entered by the user before the change happen
+- OUString aEncodedMP;
+- if( !m_aMasterPasswd.isEmpty() || m_pStorageFile->getEncodedMP( aEncodedMP ) )
++ OUString aEncodedMP, aEncodedMPIV;
++ if( !m_aMasterPasswd.isEmpty() || m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) )
+ bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
+
+ if ( bCanChangePassword )
+@@ -1138,7 +1186,8 @@ sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference<
+ // store the new master password
+ m_aMasterPasswd = aPass;
+ std::vector< OUString > aMaster( 1, m_aMasterPasswd );
+- m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) );
++ OUString aIV = createIV();
++ m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, aIV, m_aMasterPasswd ), aIV );
+
+ // store all the entries with the new password
+ for ( const auto& rURL : aPersistent )
+@@ -1163,7 +1212,7 @@ void SAL_CALL PasswordContainer::removeMasterPassword()
+ if ( m_pStorageFile )
+ {
+ m_aMasterPasswd.clear();
+- m_pStorageFile->setEncodedMP( OUString() ); // let the master password be removed from configuration
++ m_pStorageFile->setEncodedMP( OUString(), OUString() ); // let the master password be removed from configuration
+ }
+ }
+
+@@ -1174,8 +1223,8 @@ sal_Bool SAL_CALL PasswordContainer::hasMasterPassword( )
+ if ( !m_pStorageFile )
+ throw uno::RuntimeException();
+
+- OUString aEncodedMP;
+- return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) );
++ OUString aEncodedMP, aEncodedMPIV;
++ return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) );
+ }
+
+ sal_Bool SAL_CALL PasswordContainer::allowPersistentStoring( sal_Bool bAllow )
+@@ -1222,8 +1271,8 @@ sal_Bool SAL_CALL PasswordContainer::useDefaultMasterPassword( const uno::Refere
+
+ bool bCanChangePassword = true;
+ // if there is already a stored nondefault master password it should be entered by the user before the change happen
+- OUString aEncodedMP;
+- if( m_pStorageFile->getEncodedMP( aEncodedMP ) && !aEncodedMP.isEmpty() )
++ OUString aEncodedMP, aEncodedMPIV;
++ if( m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) && !aEncodedMP.isEmpty() )
+ bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
+
+ if ( bCanChangePassword )
+@@ -1240,7 +1289,7 @@ sal_Bool SAL_CALL PasswordContainer::useDefaultMasterPassword( const uno::Refere
+
+ // store the empty string to flag the default master password
+ m_aMasterPasswd = aPass;
+- m_pStorageFile->setEncodedMP( OUString(), true );
++ m_pStorageFile->setEncodedMP( OUString(), OUString(), true );
+
+ // store all the entries with the new password
+ for ( const auto& rURL : aPersistent )
+@@ -1264,8 +1313,8 @@ sal_Bool SAL_CALL PasswordContainer::isDefaultMasterPasswordUsed()
+ if ( !m_pStorageFile )
+ throw uno::RuntimeException();
+
+- OUString aEncodedMP;
+- return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) && aEncodedMP.isEmpty() );
++ OUString aEncodedMP, aEncodedMPIV;
++ return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP, aEncodedMPIV ) && aEncodedMP.isEmpty() );
+ }
+
+
+diff --git a/svl/source/passwordcontainer/passwordcontainer.hxx b/svl/source/passwordcontainer/passwordcontainer.hxx
+index bf43b5903602..0454437b9dc2 100644
+--- a/svl/source/passwordcontainer/passwordcontainer.hxx
++++ b/svl/source/passwordcontainer/passwordcontainer.hxx
+@@ -34,6 +34,7 @@
+ #include <unotools/configitem.hxx>
+ #include <ucbhelper/interactionrequest.hxx>
+
++#include <rtl/random.h>
+ #include <rtl/ref.hxx>
+ #include <osl/mutex.hxx>
+
+@@ -52,11 +53,12 @@ class NamePassRecord
+ ::std::vector< OUString > m_aMemPass;
+
+ // persistent passwords are encrypted in one string
+- bool m_bHasPersPass;
++ bool m_bHasPersPass;
+ OUString m_aPersPass;
++ OUString m_aPersistentIV;
+
+ void InitArrays( bool bHasMemoryList, const ::std::vector< OUString >& aMemoryList,
+- bool bHasPersistentList, const OUString& aPersistentList )
++ bool bHasPersistentList, const OUString& aPersistentList, const OUString& aPersistentIV )
+ {
+ m_bHasMemPass = bHasMemoryList;
+ if ( bHasMemoryList )
+@@ -64,7 +66,10 @@ class NamePassRecord
+
+ m_bHasPersPass = bHasPersistentList;
+ if ( bHasPersistentList )
++ {
+ m_aPersPass = aPersistentList;
++ m_aPersistentIV = aPersistentIV;
++ }
+ }
+
+ public:
+@@ -76,11 +81,12 @@ public:
+ {
+ }
+
+- NamePassRecord( const OUString& aName, const OUString& aPersistentList )
++ NamePassRecord( const OUString& aName, const OUString& aPersistentList, const OUString& aPersistentIV )
+ : m_aName( aName )
+ , m_bHasMemPass( false )
+ , m_bHasPersPass( true )
+ , m_aPersPass( aPersistentList )
++ , m_aPersistentIV( aPersistentIV )
+ {
+ }
+
+@@ -89,7 +95,8 @@ public:
+ , m_bHasMemPass( false )
+ , m_bHasPersPass( false )
+ {
+- InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass, aRecord.m_bHasPersPass, aRecord.m_aPersPass );
++ InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass,
++ aRecord.m_bHasPersPass, aRecord.m_aPersPass, aRecord.m_aPersistentIV );
+ }
+
+ NamePassRecord& operator=( const NamePassRecord& aRecord )
+@@ -100,7 +107,9 @@ public:
+
+ m_aMemPass.clear();
+ m_aPersPass.clear();
+- InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass, aRecord.m_bHasPersPass, aRecord.m_aPersPass );
++ m_aPersistentIV.clear();
++ InitArrays( aRecord.m_bHasMemPass, aRecord.m_aMemPass,
++ aRecord.m_bHasPersPass, aRecord.m_aPersPass, aRecord.m_aPersistentIV );
+ }
+ return *this;
+ }
+@@ -136,15 +145,24 @@ public:
+ return OUString();
+ }
+
++ OUString GetPersistentIV() const
++ {
++ if ( m_bHasPersPass )
++ return m_aPersistentIV;
++
++ return OUString();
++ }
++
+ void SetMemPasswords( const ::std::vector< OUString >& aMemList )
+ {
+ m_aMemPass = aMemList;
+ m_bHasMemPass = true;
+ }
+
+- void SetPersPasswords( const OUString& aPersList )
++ void SetPersPasswords( const OUString& aPersList, const OUString& aPersIV )
+ {
+ m_aPersPass = aPersList;
++ m_aPersistentIV = aPersIV;
+ m_bHasPersPass = true;
+ }
+
+@@ -159,6 +177,7 @@ public:
+ {
+ m_bHasPersPass = false;
+ m_aPersPass.clear();
++ m_aPersistentIV.clear();
+ }
+ }
+
+@@ -182,6 +201,7 @@ private:
+ PasswordContainer* mainCont;
+ bool hasEncoded;
+ OUString mEncoded;
++ OUString mEncodedIV;
+
+ virtual void ImplCommit() override;
+
+@@ -201,8 +201,8 @@
+
+ sal_Int32 getStorageVersion();
+
+- bool getEncodedMP( OUString& aResult );
+- void setEncodedMP( const OUString& aResult, bool bAcceptEnmpty = false );
++ bool getEncodedMP( OUString& aResult, OUString& aResultIV );
++ void setEncodedMP( const OUString& aResult, const OUString& aResultIV, bool bAcceptEmpty = false );
+ void setUseStorage( bool bUse );
+ bool useStorage();
+
+@@ -224,6 +244,29 @@ private:
+ css::uno::Reference< css::lang::XComponent > mComponent;
+ SysCredentialsConfig mUrlContainer;
+
++ class RandomPool
++ {
++ private:
++ rtlRandomPool m_aRandomPool;
++ public:
++ RandomPool() : m_aRandomPool(rtl_random_createPool())
++ {
++ }
++ rtlRandomPool get()
++ {
++ return m_aRandomPool;
++ }
++ ~RandomPool()
++ {
++ // Clean up random pool memory
++ rtl_random_destroyPool(m_aRandomPool);
++ }
++ };
++
++ RandomPool mRandomPool;
++
++ OUString createIV();
++
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence< css::task::UserRecord > CopyToUserRecordSequence(
+ const ::std::vector< NamePassRecord >& original,
+@@ -274,10 +317,10 @@ css::task::UrlRecord find(
+ const css::uno::Reference< css::task::XInteractionHandler >& Handler );
+
+ /// @throws css::uno::RuntimeException
+- static ::std::vector< OUString > DecodePasswords( const OUString& aLine, const OUString& aMasterPassword, css::task::PasswordRequestMode mode );
++ static ::std::vector< OUString > DecodePasswords( const OUString& aLine, const OUString& aIV, const OUString& aMasterPassword, css::task::PasswordRequestMode mode );
+
+ /// @throws css::uno::RuntimeException
+- static OUString EncodePasswords(const std::vector< OUString >& lines, const OUString& aMasterPassword );
++ static OUString EncodePasswords(const std::vector< OUString >& lines, const OUString& aIV, const OUString& aMasterPassword );
+
+ public:
+ PasswordContainer( const css::uno::Reference< css::lang::XMultiServiceFactory >& );
+--
+2.37.1
+