This is an automated email from the ASF dual-hosted git repository. cmarcum pushed a commit to branch AOO41X in repository https://gitbox.apache.org/repos/asf/openoffice.git
The following commit(s) were added to refs/heads/AOO41X by this push: new 7598b8d426 fix the encoding of the master password and generate IV's for stored passwords. Patch-By: Arrigo Marchiori 7598b8d426 is described below commit 7598b8d42640282cc1a812795a4f4f44cd75ec6d Author: cbmarcum <carl.mar...@codebuilders.net> AuthorDate: Fri Jun 24 11:58:10 2022 -0400 fix the encoding of the master password and generate IV's for stored passwords. Patch-By: Arrigo Marchiori --- main/svl/source/inc/passwordcontainer.hxx | 37 ++++- .../source/passwordcontainer/passwordcontainer.cxx | 178 +++++++++++++++------ 2 files changed, 163 insertions(+), 52 deletions(-) diff --git a/main/svl/source/inc/passwordcontainer.hxx b/main/svl/source/inc/passwordcontainer.hxx index 5136b60f4f..871cad23ce 100644 --- a/main/svl/source/inc/passwordcontainer.hxx +++ b/main/svl/source/inc/passwordcontainer.hxx @@ -249,6 +249,8 @@ private: StorageItem* m_pStorageFile; ::osl::Mutex mMutex; ::rtl::OUString m_aMasterPasswd; // master password is set when the string is not empty + /// True if we detected the older password encoding (pre-4.1.13) + bool mOldPasswordEncoding; ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > mComponent; SysCredentialsConfig mUrlContainer; @@ -268,7 +270,7 @@ private: const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& Handler ) throw(::com::sun::star::uno::RuntimeException); bool createUrlRecord( - const PassMap::iterator & rIter, + const PairUrlRecord & rPair, bool bName, const ::rtl::OUString & aName, const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& aHandler, @@ -300,12 +302,39 @@ bool createUrlRecord( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& Handler ) throw(::com::sun::star::uno::RuntimeException); - ::std::vector< ::rtl::OUString > DecodePasswords( const ::rtl::OUString& aLine, const ::rtl::OUString& aMasterPassword ) + /** Decode passwords on a line with the given master password. + * + * @param aName name for the passwords. It can be a user name, for example. + * @param aLine line with passwords to decode. + * @param aMasterPassword master password to use. + * + * The encoding is selected by mOldPasswordEncoding. + * + * @return the decoded passwords. + */ + ::std::vector< ::rtl::OUString > DecodePasswords( const ::rtl::OUString& aName, const ::rtl::OUString& aLine, const ::rtl::OUString& aMasterPassword ) throw(::com::sun::star::uno::RuntimeException); - ::rtl::OUString EncodePasswords( ::std::vector< ::rtl::OUString > lines, const ::rtl::OUString& aMasterPassword ) + /** Encode passwords on a line with the given master password. + * + * @param aName name for the passwords. It can be a user name, for example. + * @param lines lines with passwords to decode. + * @param aMasterPassword master password to use. + * + * The encoding is selected by mOldPasswordEncoding. + * + * @return the decoded passwords. + */ + ::rtl::OUString EncodePasswords( const ::rtl::OUString& aName, ::std::vector< ::rtl::OUString > lines, const ::rtl::OUString& aMasterPassword ) throw(::com::sun::star::uno::RuntimeException); - + + /** Actually change the master password, re-encoding all stored passwords. + * + * @param apass new password to set. + * + * Updates m_aMasterPasswd. + */ + void doChangeMasterPassword(const ::rtl::OUString& aPass); public: PasswordContainer( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& ); ~PasswordContainer(); diff --git a/main/svl/source/passwordcontainer/passwordcontainer.cxx b/main/svl/source/passwordcontainer/passwordcontainer.cxx index 572879de40..ff7f3da14a 100644 --- a/main/svl/source/passwordcontainer/passwordcontainer.cxx +++ b/main/svl/source/passwordcontainer/passwordcontainer.cxx @@ -427,7 +427,7 @@ void StorageItem::Commit() //------------------------------------------------------------------------- PasswordContainer::PasswordContainer( const Reference<XMultiServiceFactory>& xServiceFactory ): - m_pStorageFile( NULL ) + m_pStorageFile( NULL ), mOldPasswordEncoding(false) { // m_pStorageFile->Notify() can be called ::osl::MutexGuard aGuard( mMutex ); @@ -481,7 +481,50 @@ void SAL_CALL PasswordContainer::disposing( const EventObject& ) throw(RuntimeEx //------------------------------------------------------------------------- -vector< ::rtl::OUString > PasswordContainer::DecodePasswords( const ::rtl::OUString& aLine, const ::rtl::OUString& aMasterPasswd ) throw(RuntimeException) +/** + * @brief Decode a master password. + * + * @param aMasterPassword master password to decode. + * It must contain RTL_DIGEST_LENGTH_MD5 * 2 characters. + * @param code buffer to hold the decoded password. + * It must contain RTL_DIGEST_LENGTH_MD5 characters. + * @param oldEncoding use the encoding pre-AOO-4.1.12 if true + */ +static void decodeMasterPassword(const ::rtl::OUString& aMasterPasswd, + unsigned char *code, bool oldEncoding) +{ + OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!\n" ); + const sal_Unicode *aMasterBuf = aMasterPasswd.getStr(); + for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ ) { + if (!oldEncoding) { + code[ ind ] = (char)((((aMasterBuf[ind * 2] - 'a') & 15) << 4) | + ((aMasterBuf[ind * 2 + 1] - 'a') & 15)); + } else { + code[ ind ] = (char)(aMasterPasswd.copy( ind*2, 2 ).toInt32(16)); + } + } +} + +//------------------------------------------------------------------------- + +/** Prepare the IV. + * + * @param iv vector to prepare. Its contents are destroyed. + * @param masterPasswdCode master password as output from decodeMasterPassword. + * @param name name of the password to decrypt. + */ +static void prepareIV(std::vector<sal_uInt8>& iv, const unsigned char *masterPasswordCode, const ::rtl::OUString &aName) { + std::vector<sal_uInt8> ivSource; + ivSource.assign(masterPasswordCode, masterPasswordCode + RTL_DIGEST_LENGTH_MD5); + ::rtl::OString encodedName = ::rtl::OUStringToOString(aName, RTL_TEXTENCODING_UTF8 ); + ivSource.insert(ivSource.end(), encodedName.getStr(), encodedName.getStr() + encodedName.getLength()); + iv.resize(RTL_DIGEST_LENGTH_MD5); + rtl_digest_MD5(&ivSource[0], ivSource.size(), + &iv[0], iv.size()); +} + +//------------------------------------------------------------------------- +vector< ::rtl::OUString > PasswordContainer::DecodePasswords(const ::rtl::OUString& aName, const ::rtl::OUString& aLine, const ::rtl::OUString& aMasterPasswd ) throw(RuntimeException) { if( aMasterPasswd.getLength() ) { @@ -490,16 +533,17 @@ vector< ::rtl::OUString > PasswordContainer::DecodePasswords( const ::rtl::OUStr if( aDecoder ) { - OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!\n" ); - + std::vector<sal_uInt8> iv; unsigned char code[RTL_DIGEST_LENGTH_MD5]; - for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ ) - code[ ind ] = (char)(aMasterPasswd.copy( ind*2, 2 ).toInt32(16)); + decodeMasterPassword(aMasterPasswd, code, mOldPasswordEncoding); + if (!mOldPasswordEncoding) { + prepareIV(iv, code, aName); + } rtlCipherError result = rtl_cipher_init ( aDecoder, rtl_Cipher_DirectionDecode, - code, RTL_DIGEST_LENGTH_MD5, NULL, 0 ); - + code, RTL_DIGEST_LENGTH_MD5, (iv.size()? &iv[0] : NULL), + iv.size() ); if( result == rtl_Cipher_E_None ) { ::rtl::ByteSequence aSeq = getBufFromAsciiLine( aLine ); @@ -533,7 +577,7 @@ vector< ::rtl::OUString > PasswordContainer::DecodePasswords( const ::rtl::OUStr //------------------------------------------------------------------------- -::rtl::OUString PasswordContainer::EncodePasswords( vector< ::rtl::OUString > lines, const ::rtl::OUString& aMasterPasswd ) throw(RuntimeException) +::rtl::OUString PasswordContainer::EncodePasswords( const ::rtl::OUString& aName, vector< ::rtl::OUString > lines, const ::rtl::OUString& aMasterPasswd ) throw(RuntimeException) { if( aMasterPasswd.getLength() ) { @@ -544,15 +588,17 @@ vector< ::rtl::OUString > PasswordContainer::DecodePasswords( const ::rtl::OUStr if( aEncoder ) { - OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!\n" ); - + std::vector<sal_uInt8> iv; unsigned char code[RTL_DIGEST_LENGTH_MD5]; - for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ ) - code[ ind ] = (char)(aMasterPasswd.copy( ind*2, 2 ).toInt32(16)); + decodeMasterPassword(aMasterPasswd, code, false); + if (!mOldPasswordEncoding) { + prepareIV(iv, code, aName); + } rtlCipherError result = rtl_cipher_init ( aEncoder, rtl_Cipher_DirectionEncode, - code, RTL_DIGEST_LENGTH_MD5, NULL, 0 ); + code, RTL_DIGEST_LENGTH_MD5, (iv.size()? &iv[0] : NULL), + iv.size() ); if( result == rtl_Cipher_E_None ) { @@ -612,6 +658,38 @@ vector< ::rtl::OUString > PasswordContainer::DecodePasswords( const ::rtl::OUStr //------------------------------------------------------------------------- + +/** Return the "name" to use for the master password. */ +static const ::rtl::OUString& getMasterPasswordName(void) { + static const ::rtl::OUString value = ::rtl::OUString::createFromAscii( "Master" ); + return value; +} + +//------------------------------------------------------------------------- + +void PasswordContainer::doChangeMasterPassword(const ::rtl::OUString& aPass) { + // get all the persistent entries if it is possible + Sequence< UrlRecord > aPersistent = getAllPersistent( uno::Reference< task::XInteractionHandler >() ); + + // remove the master password and the entries persistence + removeMasterPassword(); + + // store the new master password + m_aMasterPasswd = aPass; + vector< ::rtl::OUString > aMaster( 1, m_aMasterPasswd ); + m_pStorageFile->setEncodedMP( EncodePasswords( getMasterPasswordName(), aMaster, m_aMasterPasswd ) ); + + // store all the entries with the new password + for ( int nURLInd = 0; nURLInd < aPersistent.getLength(); nURLInd++ ) + for ( int nNameInd = 0; nNameInd< aPersistent[nURLInd].UserList.getLength(); nNameInd++ ) + addPersistent( aPersistent[nURLInd].Url, + aPersistent[nURLInd].UserList[nNameInd].UserName, + aPersistent[nURLInd].UserList[nNameInd].Passwords, + uno::Reference< task::XInteractionHandler >() ); +} + +//------------------------------------------------------------------------- + void PasswordContainer::UpdateVector( const ::rtl::OUString& aURL, list< NamePassRecord >& toUpdate, NamePassRecord& aRecord, sal_Bool writeFile ) throw(RuntimeException) { for( list< NamePassRecord >::iterator aNPIter = toUpdate.begin(); aNPIter != toUpdate.end(); aNPIter++ ) @@ -656,7 +734,7 @@ UserRecord PasswordContainer::CopyToUserRecord( const NamePassRecord& aRecord, s { try { - ::std::vector< ::rtl::OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersPasswords(), GetMasterPassword( aHandler ) ); + ::std::vector< ::rtl::OUString > aDecodedPasswords = DecodePasswords( aRecord.GetUserName(), aRecord.GetPersPasswords(), GetMasterPassword( aHandler ) ); aPasswords.insert( aPasswords.end(), aDecodedPasswords.begin(), aDecodedPasswords.end() ); } catch( NoMasterException& ) @@ -713,7 +791,7 @@ void PasswordContainer::PrivateAdd( const ::rtl::OUString& Url, const ::rtl::OUS ::std::vector< ::rtl::OUString > aStorePass = copySequenceToVector( Passwords ); if( Mode == PERSISTENT_RECORD ) - aRecord.SetPersPasswords( EncodePasswords( aStorePass, GetMasterPassword( aHandler ) ) ); + aRecord.SetPersPasswords( EncodePasswords( aRecord.GetUserName(), aStorePass, GetMasterPassword( aHandler ) ) ); else if( Mode == MEMORY_RECORD ) aRecord.SetMemPasswords( aStorePass ); else @@ -781,7 +859,7 @@ Sequence< UserRecord > PasswordContainer::FindUsr( const list< NamePassRecord >& //------------------------------------------------------------------------- bool PasswordContainer::createUrlRecord( - const PassMap::iterator & rIter, + const PairUrlRecord & rPair, bool bName, const ::rtl::OUString & aName, const Reference< XInteractionHandler >& aHandler, @@ -791,18 +869,18 @@ bool PasswordContainer::createUrlRecord( if ( bName ) { Sequence< UserRecord > aUsrRec - = FindUsr( rIter->second, aName, aHandler ); + = FindUsr( rPair.second, aName, aHandler ); if( aUsrRec.getLength() ) { - rRec = UrlRecord( rIter->first, aUsrRec ); + rRec = UrlRecord( rPair.first, aUsrRec ); return true; } } else { rRec = UrlRecord( - rIter->first, - CopyToUserRecordSequence( rIter->second, aHandler ) ); + rPair.first, + CopyToUserRecordSequence( rPair.second, aHandler ) ); return true; } return false; @@ -828,10 +906,14 @@ UrlRecord PasswordContainer::find( { // first look for <url>/somename and then look for <url>/somename/... PassMap::iterator aIter = m_aContainer.find( aUrl ); + // Note that this iterator may be invalidated by the + // side-effects of createUrlRecord(), so we have to work with a + // copy of the pointed elements if( aIter != m_aContainer.end() ) { + const PairUrlRecord rPairUrlRecord = *aIter; UrlRecord aRec; - if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) ) + if ( createUrlRecord( rPairUrlRecord, bName, aName, aHandler, aRec ) ) return aRec; } else @@ -843,8 +925,9 @@ UrlRecord PasswordContainer::find( aIter = m_aContainer.lower_bound( tmpUrl ); if( aIter != m_aContainer.end() && aIter->first.match( tmpUrl ) ) { + const PairUrlRecord rPairUrlRecord = *aIter; UrlRecord aRec; - if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) ) + if ( createUrlRecord( rPairUrlRecord, bName, aName, aHandler, aRec ) ) return aRec; } } @@ -930,11 +1013,28 @@ UrlRecord PasswordContainer::find( m_aMasterPasswd = aPass; vector< ::rtl::OUString > aMaster( 1, m_aMasterPasswd ); - m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) ); + m_pStorageFile->setEncodedMP( EncodePasswords( getMasterPasswordName(), aMaster, m_aMasterPasswd ) ); } else { - vector< ::rtl::OUString > aRM( DecodePasswords( aEncodedMP, aPass ) ); + vector< ::rtl::OUString > aRM( DecodePasswords( getMasterPasswordName(), aEncodedMP, aPass ) ); + if( !aRM.size() || !aPass.equals( aRM[0] ) ) + { + // Try the old encoding + mOldPasswordEncoding = true; + try { + aRM = DecodePasswords( getMasterPasswordName(), aEncodedMP, aPass ); + if (aRM.size() && aPass.equals(aRM[0])) { + // Update all passwords to the new encoding + m_aMasterPasswd = aPass; + doChangeMasterPassword(aPass); + } + mOldPasswordEncoding = false; + } catch (...) { + mOldPasswordEncoding = false; + throw; + } + } if( !aRM.size() || !aPass.equals( aRM[0] ) ) { bAskAgain = sal_True; @@ -1061,9 +1161,6 @@ void SAL_CALL PasswordContainer::removeAllPersistent() throw(RuntimeException) { // TODO/LATER: should the password be converted to MemoryPassword? aNPIter->RemovePasswords( PERSISTENT_RECORD ); - - if ( m_pStorageFile ) - m_pStorageFile->remove( aIter->first, aNPIter->GetUserName() ); // remove record ( aURL, aName ) } if( !aNPIter->HasPasswords( MEMORY_RECORD ) ) @@ -1101,7 +1198,7 @@ Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Refere { sal_Int32 oldLen = aUsers.getLength(); aUsers.realloc( oldLen + 1 ); - aUsers[ oldLen ] = UserRecord( aNPIter->GetUserName(), copyVectorToSequence( DecodePasswords( aNPIter->GetPersPasswords(), GetMasterPassword( xHandler ) ) ) ); + aUsers[ oldLen ] = UserRecord( aNPIter->GetUserName(), copyVectorToSequence( DecodePasswords( aNPIter->GetUserName(), aNPIter->GetPersPasswords(), GetMasterPassword( xHandler ) ) ) ); } if( aUsers.getLength() ) @@ -1199,25 +1296,7 @@ sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference< if ( aPass.getLength() ) { - // get all the persistent entries if it is possible - Sequence< UrlRecord > aPersistent = getAllPersistent( uno::Reference< task::XInteractionHandler >() ); - - // remove the master password and the entries persistence - removeMasterPassword(); - - // store the new master password - m_aMasterPasswd = aPass; - vector< ::rtl::OUString > aMaster( 1, m_aMasterPasswd ); - m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) ); - - // store all the entries with the new password - for ( int nURLInd = 0; nURLInd < aPersistent.getLength(); nURLInd++ ) - for ( int nNameInd = 0; nNameInd< aPersistent[nURLInd].UserList.getLength(); nNameInd++ ) - addPersistent( aPersistent[nURLInd].Url, - aPersistent[nURLInd].UserList[nNameInd].UserName, - aPersistent[nURLInd].UserList[nNameInd].Passwords, - uno::Reference< task::XInteractionHandler >() ); - + doChangeMasterPassword(aPass); bResult = sal_True; } } @@ -1233,6 +1312,9 @@ void SAL_CALL PasswordContainer::removeMasterPassword() // remove all the stored passwords and the master password removeAllPersistent(); + // Make sure we will not use the older encoding in the future + mOldPasswordEncoding = false; + ::osl::MutexGuard aGuard( mMutex ); if ( m_pStorageFile ) {