11using System ;
22using System . Collections . Generic ;
3+ using System . IO ;
34using System . Reflection ;
45using System . Security . Cryptography ;
56using System . Windows . Forms ;
7+ using KeePass . Resources ;
8+ using KeePass . Util ;
69using KeePassLib ;
710using KeePassLib . Cryptography ;
811using KeePassLib . Cryptography . Cipher ;
@@ -29,6 +32,7 @@ public class QuickUnlockOldKeyInfo
2932 public ProtectedString QuickUnlockKey = ProtectedString . EmptyEx ;
3033 public ProtectedBinary pwHash = null ;
3134 public string keyFile = string . Empty ;
35+ public ProtectedBinary pbKeyFile = null ;
3236 public string CustomKeyProviderName = string . Empty ;
3337 public ProtectedBinary CustomKeyProviderData = null ;
3438 public bool account = false ;
@@ -80,13 +84,14 @@ public override byte[] GetKey(KeyProviderQueryContext ctx)
8084 Tools . ShowError ( PluginTranslate . KeyProvNoQuickUnlock ) ;
8185 return null ;
8286 }
83-
87+
8488 int iAttempt = 0 ;
8589 int iMaxFailed = 1 ;
8690 m_DBSpecificUnlockAttempts . TryGetValue ( ctx . DatabasePath , out iMaxFailed ) ;
8791 while ( iAttempt ++ < iMaxFailed )
8892 {
8993 var fQuickUnlock = new UnlockForm ( ) ;
94+ fQuickUnlock . SetAttempts ( iMaxFailed , iAttempt ) ;
9095 if ( KeePass . UI . UIUtil . ShowDialogNotValue ( fQuickUnlock , DialogResult . OK ) ) return null ;
9196 ProtectedString psQuickUnlockKey = fQuickUnlock . QuickUnlockKey ;
9297 KeePass . UI . UIUtil . DestroyForm ( fQuickUnlock ) ;
@@ -130,10 +135,24 @@ private static void RestoreOldMasterKeyInternal(PwDatabase db, IOConnectionInfo
130135 ck . AddUserKey ( p ) ;
131136 lMsg . Add ( "Add password to masterkey: " + ( bRestoreSuccess ? "Password decrypted and restored" : "Password restore failed, empty password set" ) ) ;
132137 }
138+ bool bFileError = false ;
133139 if ( ! string . IsNullOrEmpty ( quOldKey . keyFile ) )
134140 {
135- ck . AddUserKey ( new KcpKeyFile ( quOldKey . keyFile ) ) ;
136- lMsg . Add ( "Add key file to masterkey" ) ;
141+ var kfRestored = RestoreKeyFile ( quOldKey , lMsg , out bFileError ) ;
142+ if ( kfRestored != null )
143+ {
144+ ck . AddUserKey ( kfRestored ) ;
145+ lMsg . Add ( "Add key file to masterkey" ) ;
146+ }
147+ else
148+ {
149+ lMsg . Add ( "Error adding key file to masterkey" ) ;
150+ string sKeyFileError = KPRes . KeyFileError ;
151+ if ( sKeyFileError . EndsWith ( "." ) ) sKeyFileError = sKeyFileError . Substring ( 0 , sKeyFileError . Length - 1 ) ;
152+ sKeyFileError += ": " + quOldKey . keyFile ;
153+ MessageService . ShowWarning ( new string [ ] { sKeyFileError , KPRes . MasterKeyChangeInfo } ) ;
154+ bFileError = true ;
155+ }
137156 }
138157 if ( ! string . IsNullOrEmpty ( quOldKey . CustomKeyProviderName ) )
139158 {
@@ -154,8 +173,62 @@ private static void RestoreOldMasterKeyInternal(PwDatabase db, IOConnectionInfo
154173 }
155174 KeePass . Program . Config . Defaults . SetKeySources ( ioConnection , ck ) ;
156175 lMsg . Add ( "Set database key sources" ) ;
157- if ( bRestoreSuccess ) PluginDebug . AddSuccess ( "Restore old masterkey" , 0 , lMsg . ToArray ( ) ) ;
176+ if ( bRestoreSuccess && ! bFileError ) PluginDebug . AddSuccess ( "Restore old masterkey" , 0 , lMsg . ToArray ( ) ) ;
177+ else if ( bRestoreSuccess && bFileError ) PluginDebug . AddWarning ( "Restore old masterkey" , 0 , lMsg . ToArray ( ) ) ;
158178 else PluginDebug . AddError ( "Restore old masterkey" , 0 , lMsg . ToArray ( ) ) ;
179+ if ( bFileError ) ShowChangeMasterKeyForm ( db ) ;
180+ }
181+
182+ private static MethodInfo m_miChangeMasterKey = null ;
183+ private static void ShowChangeMasterKeyForm ( PwDatabase db )
184+ {
185+ if ( m_miChangeMasterKey == null )
186+ {
187+ m_miChangeMasterKey = KeePass . Program . MainForm . GetType ( ) . GetMethod ( "ChangeMasterKey" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
188+ }
189+ if ( m_miChangeMasterKey != null ) m_miChangeMasterKey . Invoke ( KeePass . Program . MainForm , new object [ ] { db } ) ;
190+ }
191+
192+ private static KcpKeyFile RestoreKeyFile ( QuickUnlockOldKeyInfo quOldKey , List < string > lErrors , out bool bFileError )
193+ {
194+ bFileError = false ;
195+ KcpKeyFile kf = RestoreKeyFileFromBuffer ( quOldKey , lErrors ) ;
196+ if ( kf != null ) return kf ;
197+ try
198+ {
199+ return new KcpKeyFile ( quOldKey . keyFile ) ;
200+ }
201+ catch ( Exception ex ) { lErrors . Add ( "Access to key file not possible: " + ex . Message ) ; }
202+ bFileError = true ;
203+ return null ;
204+ }
205+
206+ private static KcpKeyFile m_kcpKeyFileHelp = null ;
207+ private static KcpKeyFile RestoreKeyFileFromBuffer ( QuickUnlockOldKeyInfo quOldKey , List < string > lErrors )
208+ {
209+ if ( m_kcpKeyFileHelp == null )
210+ {
211+ string strFile = Path . GetTempFileName ( ) ;
212+ File . WriteAllText ( strFile , Guid . NewGuid ( ) . ToString ( ) ) ;
213+ m_kcpKeyFileHelp = new KcpKeyFile ( strFile ) ;
214+ File . Delete ( strFile ) ;
215+ }
216+
217+ var fi = m_kcpKeyFileHelp . GetType ( ) . GetField ( "m_pbKeyData" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
218+ if ( fi == null )
219+ {
220+ lErrors . Add ( "Can't restore m_pbKeyData" ) ;
221+ return null ;
222+ }
223+ fi . SetValue ( m_kcpKeyFileHelp , quOldKey . pbKeyFile ) ;
224+ fi = m_kcpKeyFileHelp . GetType ( ) . GetField ( "m_strPath" , BindingFlags . Instance | BindingFlags . NonPublic ) ;
225+ if ( fi == null )
226+ {
227+ lErrors . Add ( "Can't restore m_strPath" ) ;
228+ return null ;
229+ }
230+ fi . SetValue ( m_kcpKeyFileHelp , quOldKey . keyFile ) ;
231+ return m_kcpKeyFileHelp ;
159232 }
160233
161234 internal static void RestoreOldMasterKey ( PwDatabase db , QuickUnlockOldKeyInfo quOldKey )
@@ -222,7 +295,10 @@ private static void AddOldMasterKey(PwDatabase db, ProtectedString QuickUnlockKe
222295 quOldKey . pwHash = EncryptKey ( QuickUnlockKey , pbPasswordSerialized ) ;
223296 }
224297 if ( db . MasterKey . ContainsType ( typeof ( KcpKeyFile ) ) )
298+ {
225299 quOldKey . keyFile = ( db . MasterKey . GetUserKey ( typeof ( KcpKeyFile ) ) as KcpKeyFile ) . Path ;
300+ quOldKey . pbKeyFile = ( db . MasterKey . GetUserKey ( typeof ( KcpKeyFile ) ) as KcpKeyFile ) . KeyData ;
301+ }
226302 if ( db . MasterKey . ContainsType ( typeof ( KcpCustomKey ) ) )
227303 {
228304 quOldKey . CustomKeyProviderName = ( db . MasterKey . GetUserKey ( typeof ( KcpCustomKey ) ) as KcpCustomKey ) . Name ;
0 commit comments