1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.ComponentModel; 23 using System.Diagnostics; 24 using System.Drawing; 25 using System.IO; 26 using System.Text; 27 using System.Windows.Forms; 28 29 using KeePass.App; 30 using KeePass.Resources; 31 using KeePass.UI; 32 using KeePass.Util; 33 34 using KeePassLib; 35 using KeePassLib.Cryptography; 36 using KeePassLib.Keys; 37 using KeePassLib.Native; 38 using KeePassLib.Resources; 39 using KeePassLib.Security; 40 using KeePassLib.Serialization; 41 using KeePassLib.Utility; 42 43 namespace KeePass.Forms 44 { 45 public partial class KeyCreationForm : Form 46 { 47 private CompositeKey m_pKey = null; 48 private bool m_bCreatingNew = false; 49 private IOConnectionInfo m_ioInfo = new IOConnectionInfo(); 50 51 private PwInputControlGroup m_icgPassword = new PwInputControlGroup(); 52 private Image m_imgKeyFileWarning = null; 53 private Image m_imgAccWarning = null; 54 // private uint m_uBlockUpdate = 0; 55 56 public CompositeKey CompositeKey 57 { 58 get 59 { 60 Debug.Assert(m_pKey != null); 61 return m_pKey; 62 } 63 } 64 KeyCreationForm()65 public KeyCreationForm() 66 { 67 InitializeComponent(); 68 69 SecureTextBoxEx.InitEx(ref m_tbPassword); 70 SecureTextBoxEx.InitEx(ref m_tbRepeatPassword); 71 72 GlobalWindowManager.InitializeForm(this); 73 } 74 InitEx(IOConnectionInfo ioInfo, bool bCreatingNew)75 public void InitEx(IOConnectionInfo ioInfo, bool bCreatingNew) 76 { 77 if(ioInfo != null) m_ioInfo = ioInfo; 78 79 m_bCreatingNew = bCreatingNew; 80 } 81 OnFormLoad(object sender, EventArgs e)82 private void OnFormLoad(object sender, EventArgs e) 83 { 84 // The password text box should not be focused by default 85 // in order to avoid a Caps Lock warning tooltip bug; 86 // https://sourceforge.net/p/keepass/bugs/1807/ 87 Debug.Assert((m_tbPassword.TabIndex >= 2) && !m_tbPassword.Focused); 88 89 GlobalWindowManager.AddWindow(this); 90 91 BannerFactory.CreateBannerEx(this, m_bannerImage, 92 Properties.Resources.B48x48_KGPG_Sign, KPRes.CreateMasterKey, 93 m_ioInfo.GetDisplayName()); 94 this.Icon = AppIcons.Default; 95 this.Text = KPRes.CreateMasterKey; 96 97 FontUtil.SetDefaultFont(m_cbPassword); 98 FontUtil.AssignDefaultBold(m_cbPassword); 99 FontUtil.AssignDefaultBold(m_cbKeyFile); 100 FontUtil.AssignDefaultBold(m_cbUserAccount); 101 102 m_imgKeyFileWarning = UIUtil.IconToBitmap(SystemIcons.Warning, 103 DpiUtil.ScaleIntX(16), DpiUtil.ScaleIntY(16)); 104 m_imgAccWarning = (Image)m_imgKeyFileWarning.Clone(); 105 m_picKeyFileWarning.Image = m_imgKeyFileWarning; 106 m_picAccWarning.Image = m_imgAccWarning; 107 108 UIUtil.ConfigureToolTip(m_ttRect); 109 UIUtil.SetToolTip(m_ttRect, m_tbRepeatPassword, KPRes.PasswordRepeatHint, false); 110 UIUtil.SetToolTip(m_ttRect, m_btnSaveKeyFile, KPRes.KeyFileCreate, false); 111 UIUtil.SetToolTip(m_ttRect, m_btnOpenKeyFile, KPRes.KeyFileUseExisting, false); 112 113 UIUtil.AccSetName(m_tbPassword, m_cbPassword); 114 UIUtil.AccSetName(m_cmbKeyFile, m_cbKeyFile); 115 UIUtil.AccSetName(m_picKeyFileWarning, KPRes.Warning); 116 UIUtil.AccSetName(m_picAccWarning, KPRes.Warning); 117 118 Debug.Assert(!m_lblIntro.AutoSize); // For RTL support 119 if(!m_bCreatingNew) 120 m_lblIntro.Text = KPRes.ChangeMasterKeyIntroShort; 121 122 m_icgPassword.Attach(m_tbPassword, m_cbHidePassword, m_lblRepeatPassword, 123 m_tbRepeatPassword, m_lblEstimatedQuality, m_pbPasswordQuality, 124 m_lblQualityInfo, m_ttRect, this, true, false); 125 126 m_cmbKeyFile.Items.Add(KPRes.NoKeyFileSpecifiedMeta); 127 foreach(KeyProvider prov in Program.KeyProviderPool) 128 m_cmbKeyFile.Items.Add(prov.Name); 129 130 m_cmbKeyFile.SelectedIndex = 0; 131 132 m_cbPassword.Checked = true; 133 UIUtil.ApplyKeyUIFlags(Program.Config.UI.KeyCreationFlags, 134 m_cbPassword, m_cbKeyFile, m_cbUserAccount, m_cbHidePassword); 135 136 if(WinUtil.IsWindows9x || NativeLib.IsUnix()) 137 { 138 UIUtil.SetChecked(m_cbUserAccount, false); 139 UIUtil.SetEnabled(m_cbUserAccount, false); 140 UIUtil.SetEnabled(m_lblWindowsAccDesc, false); 141 UIUtil.SetEnabled(m_lblWindowsAccDesc2, false); 142 } 143 144 EnableUserControls(); 145 // UIUtil.SetFocus(m_tbPassword, this); // See OnFormShown 146 } 147 OnFormShown(object sender, EventArgs e)148 private void OnFormShown(object sender, EventArgs e) 149 { 150 // Focusing doesn't always work in OnFormLoad; 151 // https://sourceforge.net/p/keepass/feature-requests/1735/ 152 if(m_tbPassword.CanFocus) UIUtil.ResetFocus(m_tbPassword, this, true); 153 else if(m_cmbKeyFile.CanFocus) UIUtil.SetFocus(m_cmbKeyFile, this, true); 154 else if(m_btnCreate.CanFocus) UIUtil.SetFocus(m_btnCreate, this, true); 155 else { Debug.Assert(false); } 156 } 157 CleanUpEx()158 private void CleanUpEx() 159 { 160 if(m_imgKeyFileWarning != null) 161 { 162 m_picKeyFileWarning.Image = null; 163 m_imgKeyFileWarning.Dispose(); 164 m_imgKeyFileWarning = null; 165 } 166 167 if(m_imgAccWarning != null) 168 { 169 m_picAccWarning.Image = null; 170 m_imgAccWarning.Dispose(); 171 m_imgAccWarning = null; 172 } 173 174 m_icgPassword.Release(); 175 } 176 CreateCompositeKey()177 private bool CreateCompositeKey() 178 { 179 m_pKey = new CompositeKey(); 180 181 if(m_cbPassword.Checked) // Use a password 182 { 183 if(!m_icgPassword.ValidateData(true)) return false; 184 185 byte[] pb = m_icgPassword.GetPasswordUtf8(); 186 try 187 { 188 uint uPwLen = (uint)m_tbPassword.TextLength; 189 uint uPwBits = QualityEstimation.EstimatePasswordBits(pb); 190 191 uint uMinLen = Program.Config.Security.MasterPassword.MinimumLength; 192 if(uPwLen < uMinLen) 193 { 194 string strML = KPRes.MasterPasswordMinLengthFailed; 195 strML = strML.Replace(@"{PARAM}", uMinLen.ToString()); 196 MessageService.ShowWarning(strML); 197 return false; 198 } 199 200 uint uMinQual = Program.Config.Security.MasterPassword.MinimumQuality; 201 if(uPwBits < uMinQual) 202 { 203 string strMQ = KPRes.MasterPasswordMinQualityFailed; 204 strMQ = strMQ.Replace(@"{PARAM}", uMinQual.ToString()); 205 MessageService.ShowWarning(strMQ); 206 return false; 207 } 208 209 string strValRes = Program.KeyValidatorPool.Validate(pb, 210 KeyValidationType.MasterPassword); 211 if(strValRes != null) 212 { 213 MessageService.ShowWarning(strValRes); 214 return false; 215 } 216 217 if(uPwLen == 0) 218 { 219 if(!MessageService.AskYesNo(KPRes.EmptyMasterPw + 220 MessageService.NewParagraph + KPRes.EmptyMasterPwHint + 221 MessageService.NewParagraph + KPRes.EmptyMasterPwQuestion, 222 null, false)) 223 return false; 224 } 225 226 if(uPwBits <= PwDefs.QualityBitsWeak) 227 { 228 string strMQ = KPRes.MasterPasswordWeak + MessageService.NewParagraph + 229 KPRes.MasterPasswordConfirm; 230 if(!MessageService.AskYesNo(strMQ, null, false, 231 MessageBoxIcon.Warning)) 232 return false; 233 } 234 235 m_pKey.AddUserKey(new KcpPassword(pb, 236 Program.Config.Security.MasterPassword.RememberWhileOpen)); 237 } 238 finally { MemUtil.ZeroByteArray(pb); } 239 } 240 241 string strKeyFile = m_cmbKeyFile.Text; 242 bool bIsKeyProv = Program.KeyProviderPool.IsKeyProvider(strKeyFile); 243 244 if(m_cbKeyFile.Checked && (!strKeyFile.Equals(KPRes.NoKeyFileSpecifiedMeta)) && 245 !bIsKeyProv) 246 { 247 try { m_pKey.AddUserKey(new KcpKeyFile(strKeyFile, true)); } 248 catch(Exception exKF) 249 { 250 MessageService.ShowWarning(strKeyFile, KLRes.FileLoadFailed, exKF); 251 return false; 252 } 253 } 254 else if(m_cbKeyFile.Checked && (!strKeyFile.Equals(KPRes.NoKeyFileSpecifiedMeta)) && 255 bIsKeyProv) 256 { 257 KeyProviderQueryContext ctxKP = new KeyProviderQueryContext( 258 m_ioInfo, true, false); 259 260 bool bPerformHash; 261 byte[] pbCustomKey = Program.KeyProviderPool.GetKey(strKeyFile, ctxKP, 262 out bPerformHash); 263 if((pbCustomKey != null) && (pbCustomKey.Length > 0)) 264 { 265 try { m_pKey.AddUserKey(new KcpCustomKey(strKeyFile, pbCustomKey, bPerformHash)); } 266 catch(Exception exCKP) 267 { 268 MessageService.ShowWarning(exCKP); 269 return false; 270 } 271 272 MemUtil.ZeroByteArray(pbCustomKey); 273 } 274 else return false; // Provider has shown error message 275 } 276 277 if(m_cbUserAccount.Checked) 278 { 279 try { m_pKey.AddUserKey(new KcpUserAccount()); } 280 catch(Exception exUA) 281 { 282 MessageService.ShowWarning(exUA); 283 return false; 284 } 285 } 286 287 return true; 288 } 289 EnableUserControls()290 private void EnableUserControls() 291 { 292 // Must support recursive call, see m_cbExpert.Checked 293 // if(m_uBlockUpdate != 0) return; 294 // ++m_uBlockUpdate; 295 296 m_icgPassword.Enabled = m_cbPassword.Checked; 297 298 bool bKeyFile = m_cbKeyFile.Checked; 299 m_cmbKeyFile.Enabled = bKeyFile; 300 301 string strKeyFile = m_cmbKeyFile.Text; 302 bool bKeyProv = (!strKeyFile.Equals(KPRes.NoKeyFileSpecifiedMeta) && 303 Program.KeyProviderPool.IsKeyProvider(strKeyFile)); 304 m_btnOpenKeyFile.Enabled = m_btnSaveKeyFile.Enabled = 305 (bKeyFile && !bKeyProv); 306 307 bool bUserAccount = m_cbUserAccount.Checked; 308 if(!m_cbPassword.Checked && !bKeyFile && !bUserAccount) 309 m_btnCreate.Enabled = false; 310 else if(bKeyFile && strKeyFile.Equals(KPRes.NoKeyFileSpecifiedMeta)) 311 m_btnCreate.Enabled = false; 312 else m_btnCreate.Enabled = true; 313 314 UIUtil.SetToolTip(m_ttRect, m_cmbKeyFile, strKeyFile, false); 315 316 bool bExpert = m_cbExpert.Checked; 317 bool bShowKF = (bExpert || bKeyFile); 318 bool bShowUA = (bExpert || bUserAccount); 319 320 Control[] vKeyFile = new Control[] { 321 m_cbKeyFile, m_cmbKeyFile, m_btnOpenKeyFile, m_btnSaveKeyFile, 322 m_lblKeyFileInfo, m_picKeyFileWarning, m_lblKeyFileWarning, 323 m_lnkKeyFile 324 }; 325 foreach(Control c in vKeyFile) c.Visible = bShowKF; 326 327 Control[] vUserAccount = new Control[] { 328 m_cbUserAccount, m_lblWindowsAccDesc, m_picAccWarning, 329 m_lblWindowsAccDesc2, m_lnkUserAccount 330 }; 331 foreach(Control c in vUserAccount) c.Visible = bShowUA; 332 333 if(bKeyFile || bUserAccount) 334 { 335 if(!m_cbExpert.Checked) 336 m_cbExpert.Checked = true; // Recursive, once 337 338 m_cbExpert.Enabled = false; 339 } 340 else m_cbExpert.Enabled = true; 341 342 // --m_uBlockUpdate; 343 } 344 OnCheckedPassword(object sender, EventArgs e)345 private void OnCheckedPassword(object sender, EventArgs e) 346 { 347 EnableUserControls(); 348 349 if(m_cbPassword.Checked) UIUtil.SetFocus(m_tbPassword, this); 350 } 351 OnCheckedKeyFile(object sender, EventArgs e)352 private void OnCheckedKeyFile(object sender, EventArgs e) 353 { 354 EnableUserControls(); 355 } 356 OnBtnOK(object sender, EventArgs e)357 private void OnBtnOK(object sender, EventArgs e) 358 { 359 if(!CreateCompositeKey()) this.DialogResult = DialogResult.None; 360 } 361 OnBtnCancel(object sender, EventArgs e)362 private void OnBtnCancel(object sender, EventArgs e) 363 { 364 m_pKey = null; 365 } 366 OnClickKeyFileCreate(object sender, EventArgs e)367 private void OnClickKeyFileCreate(object sender, EventArgs e) 368 { 369 KeyFileCreationForm dlg = new KeyFileCreationForm(); 370 dlg.InitEx(m_ioInfo); 371 372 if(dlg.ShowDialog() == DialogResult.OK) 373 { 374 string strFile = dlg.ResultFile; 375 if(!string.IsNullOrEmpty(strFile)) 376 { 377 m_cmbKeyFile.Items.Add(strFile); 378 m_cmbKeyFile.SelectedIndex = m_cmbKeyFile.Items.Count - 1; 379 } 380 else { Debug.Assert(false); } 381 } 382 383 UIUtil.DestroyForm(dlg); 384 EnableUserControls(); 385 } 386 OnClickKeyFileBrowse(object sender, EventArgs e)387 private void OnClickKeyFileBrowse(object sender, EventArgs e) 388 { 389 string strFilter = AppDefs.GetKeyFileFilter(); 390 OpenFileDialogEx ofd = UIUtil.CreateOpenFileDialog(KPRes.KeyFileUseExisting, 391 strFilter, 1, null, false, AppDefs.FileDialogContext.KeyFile); 392 393 if(ofd.ShowDialog() != DialogResult.OK) return; 394 395 string strFile = ofd.FileName; 396 397 try 398 { 399 // Test whether we can read the file 400 IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); 401 IOConnection.OpenRead(ioc).Close(); 402 403 // Check the file size? 404 } 405 catch(Exception ex) { MessageService.ShowWarning(ex); return; } 406 407 if(!KfxFile.CanLoad(strFile)) 408 { 409 if(!MessageService.AskYesNo(strFile + MessageService.NewParagraph + 410 KPRes.KeyFileNoXml + MessageService.NewParagraph + 411 KPRes.KeyFileUseAnywayQ, null, false)) 412 return; 413 } 414 415 m_cmbKeyFile.Items.Add(strFile); 416 m_cmbKeyFile.SelectedIndex = m_cmbKeyFile.Items.Count - 1; 417 418 EnableUserControls(); 419 } 420 OnWinUserCheckedChanged(object sender, EventArgs e)421 private void OnWinUserCheckedChanged(object sender, EventArgs e) 422 { 423 EnableUserControls(); 424 } 425 OnFormClosed(object sender, FormClosedEventArgs e)426 private void OnFormClosed(object sender, FormClosedEventArgs e) 427 { 428 GlobalWindowManager.RemoveWindow(this); 429 } 430 OnBtnHelp(object sender, EventArgs e)431 private void OnBtnHelp(object sender, EventArgs e) 432 { 433 AppHelp.ShowHelp(AppDefs.HelpTopics.KeySources, null); 434 } 435 OnKeyFileSelectedIndexChanged(object sender, EventArgs e)436 private void OnKeyFileSelectedIndexChanged(object sender, EventArgs e) 437 { 438 EnableUserControls(); 439 } 440 OnFormClosing(object sender, FormClosingEventArgs e)441 private void OnFormClosing(object sender, FormClosingEventArgs e) 442 { 443 CleanUpEx(); 444 } 445 OnKeyFileLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)446 private void OnKeyFileLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 447 { 448 AppHelp.ShowHelp(AppDefs.HelpTopics.KeySources, 449 AppDefs.HelpTopics.KeySourcesKeyFile); 450 } 451 OnUserAccountLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)452 private void OnUserAccountLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 453 { 454 AppHelp.ShowHelp(AppDefs.HelpTopics.KeySources, 455 AppDefs.HelpTopics.KeySourcesUserAccount); 456 } 457 OnExpertCheckedChanged(object sender, EventArgs e)458 private void OnExpertCheckedChanged(object sender, EventArgs e) 459 { 460 EnableUserControls(); 461 } 462 } 463 } 464