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 33 using KeePassLib.Keys; 34 using KeePassLib.Serialization; 35 using KeePassLib.Utility; 36 37 namespace KeePass.Forms 38 { 39 public partial class KeyFileCreationForm : Form 40 { 41 private sealed class KfcfInfo 42 { 43 public readonly ulong Version; 44 public readonly string Name; 45 KfcfInfo(ulong uVersion, string strName)46 public KfcfInfo(ulong uVersion, string strName) 47 { 48 this.Version = uVersion; 49 this.Name = strName; 50 } 51 } 52 53 private IOConnectionInfo m_ioInfo = new IOConnectionInfo(); 54 55 private int m_cBlockUIUpdate = 0; 56 57 private readonly KfcfInfo[] m_vNewFormat = new KfcfInfo[] { 58 new KfcfInfo(0x0002000000000000, "2.0 (" + KPRes.Recommended + ")"), 59 new KfcfInfo(0x0001000000000000, "1.0 (" + KPRes.CompatWithOldVer + ")") 60 }; 61 private readonly KfcfInfo[] m_vRecFormat = new KfcfInfo[] { 62 new KfcfInfo(0x0002000000000000, "2.0"), 63 new KfcfInfo(0x0001000000000000, "1.0") 64 }; 65 66 private string m_strResultFile = null; 67 public string ResultFile 68 { 69 get { return m_strResultFile; } 70 } 71 KeyFileCreationForm()72 public KeyFileCreationForm() 73 { 74 InitializeComponent(); 75 GlobalWindowManager.InitializeForm(this); 76 } 77 InitEx(IOConnectionInfo ioInfo)78 public void InitEx(IOConnectionInfo ioInfo) 79 { 80 if(ioInfo != null) m_ioInfo = ioInfo; 81 } 82 OnFormLoad(object sender, EventArgs e)83 private void OnFormLoad(object sender, EventArgs e) 84 { 85 ++m_cBlockUIUpdate; 86 87 GlobalWindowManager.AddWindow(this); 88 89 BannerFactory.CreateBannerEx(this, m_bannerImage, 90 KeePass.Properties.Resources.B48x48_KGPG_Gen, 91 KPRes.KeyFileCreateTitle, KPRes.KeyFileCreate + "."); 92 this.Icon = AppIcons.Default; 93 this.Text = KPRes.KeyFileCreateTitle; 94 95 FontUtil.AssignDefaultBold(m_rbCreate); 96 FontUtil.AssignDefaultBold(m_rbRecreate); 97 FontUtil.AssignDefaultMono(m_tbRecKeyHash, false); 98 FontUtil.AssignDefaultMono(m_tbRecKey, false); 99 100 m_rbCreate.Checked = true; 101 m_cbNewEntropy.Checked = true; 102 103 Debug.Assert(!m_cmbNewFormat.Sorted); 104 foreach(KfcfInfo kfi in m_vNewFormat) 105 m_cmbNewFormat.Items.Add(kfi.Name); 106 m_cmbNewFormat.SelectedIndex = 0; 107 108 Debug.Assert(!m_cmbRecFormat.Sorted); 109 foreach(KfcfInfo kfi in m_vRecFormat) 110 m_cmbRecFormat.Items.Add(kfi.Name); 111 m_cmbRecFormat.SelectedIndex = 0; 112 113 m_rbCreate.CheckedChanged += this.OnShouldUpdateUIState; 114 m_rbRecreate.CheckedChanged += this.OnShouldUpdateUIState; 115 m_cmbRecFormat.SelectedIndexChanged += this.OnShouldUpdateUIState; 116 m_tbRecKey.TextChanged += this.OnShouldUpdateUIState; 117 118 --m_cBlockUIUpdate; 119 UpdateUIState(); 120 } 121 OnFormClosed(object sender, FormClosedEventArgs e)122 private void OnFormClosed(object sender, FormClosedEventArgs e) 123 { 124 GlobalWindowManager.RemoveWindow(this); 125 } 126 UpdateUIState()127 private void UpdateUIState() 128 { 129 if(m_cBlockUIUpdate > 0) return; 130 131 bool bCreate = m_rbCreate.Checked; 132 bool bRecreate = m_rbRecreate.Checked; 133 KfcfInfo kfiRec = m_vRecFormat[m_cmbRecFormat.SelectedIndex]; 134 135 UIUtil.SetEnabledFast(bCreate, m_lblNewFormat, m_cmbNewFormat, 136 m_cbNewEntropy); 137 138 UIUtil.SetEnabledFast(bRecreate, m_lblRecFormat, m_cmbRecFormat, 139 m_lblRecKey, m_tbRecKey); 140 UIUtil.SetEnabledFast(bRecreate && (kfiRec.Version == 0x0002000000000000), 141 m_lblRecKeyHash, m_tbRecKeyHash); 142 143 UIUtil.SetEnabledFast(bCreate || (bRecreate && 144 (m_tbRecKey.Text.Trim().Length != 0)), m_btnOK); 145 } 146 OnShouldUpdateUIState(object sender, EventArgs e)147 private void OnShouldUpdateUIState(object sender, EventArgs e) 148 { 149 UpdateUIState(); 150 } 151 OnBtnOK(object sender, EventArgs e)152 private void OnBtnOK(object sender, EventArgs e) 153 { 154 string strResultFile = null; 155 156 try 157 { 158 if(m_rbCreate.Checked) 159 strResultFile = CreateKeyFile(); 160 else if(m_rbRecreate.Checked) 161 strResultFile = RecreateKeyFile(); 162 else { Debug.Assert(false); throw new NotSupportedException(); } 163 } 164 catch(Exception ex) { MessageService.ShowWarning(ex); } 165 166 if(string.IsNullOrEmpty(strResultFile)) 167 this.DialogResult = DialogResult.None; 168 else m_strResultFile = strResultFile; 169 } 170 GetKeyFilePath()171 private string GetKeyFilePath() 172 { 173 string strExt = AppDefs.FileExtension.KeyFile; 174 string strFilter = AppDefs.GetKeyFileFilter(); 175 176 string strName = UrlUtil.StripExtension(UrlUtil.GetFileName(m_ioInfo.Path)); 177 if(string.IsNullOrEmpty(strName)) strName = KPRes.KeyFileSafe; 178 179 SaveFileDialogEx sfd = UIUtil.CreateSaveFileDialog(KPRes.KeyFileCreateTitle, 180 strName + "." + strExt, strFilter, 1, strExt, AppDefs.FileDialogContext.KeyFile); 181 182 if(sfd.ShowDialog() == DialogResult.OK) return sfd.FileName; 183 return null; 184 } 185 CreateKeyFile()186 private string CreateKeyFile() 187 { 188 byte[] pbEntropy = null; 189 if(m_cbNewEntropy.Checked) 190 { 191 EntropyForm dlg = new EntropyForm(); 192 if(dlg.ShowDialog() == DialogResult.OK) 193 pbEntropy = dlg.GeneratedEntropy; 194 UIUtil.DestroyForm(dlg); 195 196 if(pbEntropy == null) return null; 197 } 198 199 string strFilePath = GetKeyFilePath(); 200 if(string.IsNullOrEmpty(strFilePath)) return null; 201 202 KcpKeyFile.Create(strFilePath, pbEntropy, m_vNewFormat[ 203 m_cmbNewFormat.SelectedIndex].Version); 204 return strFilePath; 205 } 206 RecreateKeyFile()207 private string RecreateKeyFile() 208 { 209 ulong uVersion = m_vRecFormat[m_cmbRecFormat.SelectedIndex].Version; 210 211 string strHash = StrUtil.RemoveWhiteSpace(m_tbRecKeyHash.Text); 212 // If the hash is empty, set it to null in order to generate one 213 if(strHash.Length == 0) strHash = null; 214 215 KfxFile kf = KfxFile.Create(uVersion, m_tbRecKey.Text, strHash); 216 217 // Ask for the file path after verifying the key hash 218 string strFilePath = GetKeyFilePath(); 219 if(string.IsNullOrEmpty(strFilePath)) return null; 220 221 IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath); 222 using(Stream s = IOConnection.OpenWrite(ioc)) 223 { 224 kf.Save(s); 225 } 226 227 return strFilePath; 228 } 229 } 230 } 231