1 //********************************************************************************** 2 //EncryptPad Copyright 2016 Evgeny Pokhilko 3 //<http://www.evpo.net/encryptpad> 4 // 5 //This file is part of EncryptPad 6 // 7 //EncryptPad is free software: you can redistribute it and/or modify 8 //it under the terms of the GNU General Public License as published by 9 //the Free Software Foundation, either version 2 of the License, or 10 //(at your option) any later version. 11 // 12 //EncryptPad is distributed in the hope that it will be useful, 13 //but WITHOUT ANY WARRANTY; without even the implied warranty of 14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 //GNU General Public License for more details. 16 // 17 //You should have received a copy of the GNU General Public License 18 //along with EncryptPad. If not, see <http://www.gnu.org/licenses/>. 19 //********************************************************************************** 20 #include "load_save_handler.h" 21 #include <QtGui> 22 #include <QtGlobal> 23 #include <QString> 24 #include <QObject> 25 #include <QMessageBox> 26 #include <QDialog> 27 #include <QFile> 28 #include "file_encryption.h" 29 #include "file_name_helper.h" 30 #include "get_passphrase_dialog.h" 31 #include "confirm_passphrase_dialog.h" 32 #include "get_passphrase_dialog.h" 33 #include "set_encryption_key.h" 34 #include "get_passphrase_or_key_dialog.h" 35 #include "plog/Log.h" 36 37 namespace EncryptPad 38 { 39 const char *kKeyFilePassphraseWindowTitle = QT_TRANSLATE_NOOP("LoadSaveHandler", "Passphrase for Key File"); 40 LoadFile(const QString & fileName,bool force_kf_passphrase_request)41 bool LoadHandler::LoadFile(const QString &fileName, bool force_kf_passphrase_request) 42 { 43 bool can_be_passphrase_protected = true; 44 45 bool is_wad_file = false; 46 std::string key_file; 47 bool isGpg = IsGpgFormat(fileName); 48 49 if(!QFile::exists(fileName)) 50 { 51 QMessageBox::warning( 52 parent, 53 "EncryptPad", 54 qApp->translate("LoadSaveHandler", "Cannot open the file because it does not exist")); 55 56 return false; 57 } 58 59 // Only check if it's an encrypt pad format 60 if(!isGpg) 61 { 62 can_be_passphrase_protected = EncryptPad::CheckIfPassphraseProtected( 63 fileName.toStdString(), is_wad_file, key_file); 64 } 65 66 assert(!can_be_passphrase_protected || !is_wad_file); 67 68 bool isPwd = !client.IsPassphraseNotSet(); 69 bool isKey = !client.EncryptionKeyFile().isEmpty(); 70 71 if(!can_be_passphrase_protected && !is_wad_file && (isPwd || isKey)) 72 { 73 // this is an unencrypted file or a corrupted encrypted file. Reset encryption parameters. 74 client.SetIsPlainText(); 75 client.PersistEncryptionKeyPath(false); 76 client.EncryptionKeyFile(""); 77 client.UpdateEncryptionKeyStatus(); 78 } 79 80 std::string passphrase; 81 if(isGpg) 82 { 83 // Passphrase and key file are both or none. We need to display the key or passphrase dialog. 84 if(!(isPwd ^ isKey)) 85 { 86 GetPassphraseOrKeyDialog dlg(parent, client.GetFileRequestService()); 87 if(dlg.exec() == QDialog::Rejected) 88 return false; 89 90 client.EncryptionKeyFile(""); 91 client.PersistEncryptionKeyPath(false); 92 client.SetIsPlainText(); 93 94 if(dlg.IsPassphraseSelected()) 95 { 96 QString pwdString = dlg.GetPassphrase(); 97 QByteArray byte_array = pwdString.toUtf8(); 98 const char *pwd = byte_array.constData(); 99 passphrase = pwd; 100 if(passphrase.size() > 0) 101 client.SetPassphrase(pwd, metadata); 102 } 103 else 104 { 105 client.EncryptionKeyFile(dlg.GetKeyFilePath()); 106 client.PersistEncryptionKeyPath(dlg.GetPersistKeyPath()); 107 } 108 109 client.UpdateEncryptionKeyStatus(); 110 } 111 } 112 else if(client.IsPassphraseNotSet() && can_be_passphrase_protected && !OpenPassphraseDialog(false, &passphrase)) 113 { 114 return false; 115 } 116 117 if(is_wad_file) 118 { 119 if(!key_file.empty()) 120 { 121 client.EncryptionKeyFile(QString::fromStdString(key_file)); 122 client.PersistEncryptionKeyPath(true); 123 client.UpdateEncryptionKeyStatus(); 124 } 125 else if(client.EncryptionKeyFile().isEmpty() && !OpenSetEncryptionKeyDialogue()) 126 { 127 return false; 128 } 129 } 130 131 isPwd = !client.IsPassphraseNotSet(); 132 isKey = !client.EncryptionKeyFile().isEmpty(); 133 134 std::string kf_passphrase; 135 if((isKey && !client.HasKeyFilePassphrase() && CheckIfKeyFileMayRequirePassphrase(client.EncryptionKeyFile().toStdString())) 136 || force_kf_passphrase_request) 137 { 138 if(!OpenPassphraseDialog(false, &kf_passphrase, false, qApp->translate("LoadSaveHandler", kKeyFilePassphraseWindowTitle))) 139 return false; 140 } 141 142 if(!isPwd && isKey) 143 { 144 metadata.key_only = true; 145 } 146 147 client.StartLoad(fileName, client.EncryptionKeyFile(), passphrase, metadata, kf_passphrase); 148 std::fill(std::begin(passphrase), std::end(passphrase), '0'); 149 std::fill(std::begin(kf_passphrase), std::end(kf_passphrase), '0'); 150 return true; 151 } 152 SaveFile(const QString & fileName)153 bool LoadHandler::SaveFile(const QString &fileName) 154 { 155 bool passphraseSet = !client.IsPassphraseNotSet(); 156 bool isGpg = IsGpgFormat(fileName); 157 bool isArmor = IsArmorFormat(fileName); 158 159 bool isEncryptedFormat = IsEncryptPadFormat(fileName) || isGpg; 160 161 if(isGpg) 162 { 163 if(client.PersistEncryptionKeyPath()) 164 { 165 auto ret = QMessageBox::warning( 166 parent, 167 "EncryptPad", 168 qApp->translate("LoadSaveHandler", "GPG format does not support persistent key path.") 169 + QString("\n") + 170 qApp->translate("LoadSaveHandler", "Do you want to disable it?"), 171 QMessageBox::Ok | QMessageBox::Cancel 172 ); 173 174 if(ret == QMessageBox::Cancel) 175 return false; 176 177 client.PersistEncryptionKeyPath(false); 178 client.UpdateEncryptionKeyStatus(); 179 } 180 181 if(passphraseSet && !client.EncryptionKeyFile().isEmpty()) 182 { 183 QMessageBox::warning( 184 parent, 185 "EncryptPad", 186 qApp->translate("LoadSaveHandler", "GPG format does not support double protection by passphrase and key file.") 187 + QString("\n") + 188 qApp->translate( "LoadSaveHandler", "Use EPD format or disable either passphrase or key protection.")); 189 190 return false; 191 } 192 else if(!passphraseSet && client.EncryptionKeyFile().isEmpty() && !OpenPassphraseDialog(true)) 193 { 194 return false; 195 } 196 197 assert(client.IsPassphraseNotSet() || client.EncryptionKeyFile().isEmpty()); 198 assert(!client.PersistEncryptionKeyPath()); 199 } 200 else if(!passphraseSet && isEncryptedFormat && !OpenPassphraseDialog(true)) 201 { 202 return false; 203 } 204 205 passphraseSet = !client.IsPassphraseNotSet(); 206 207 if(isEncryptedFormat && !passphraseSet && client.EncryptionKeyFile().isEmpty()) 208 { 209 auto ret = QMessageBox::warning( 210 parent, 211 "EncryptPad", 212 qApp->translate("LoadSaveHandler", "Neither a key file nor passphrase is set. The file is going to be saved UNENCRYPTED."), 213 QMessageBox::Ok | QMessageBox::Cancel 214 ); 215 216 if(ret == QMessageBox::Cancel) 217 return false; 218 } 219 220 std::string kf_passphrase; 221 222 if(!client.EncryptionKeyFile().isEmpty() && !client.HasKeyFilePassphrase() && 223 CheckIfKeyFileMayRequirePassphrase(client.EncryptionKeyFile().toStdString()) && 224 !OpenPassphraseDialog(false, &kf_passphrase, false, qApp->translate("LoadSaveHandler", kKeyFilePassphraseWindowTitle))) 225 { 226 return false; 227 } 228 229 metadata.cannot_use_wad = isGpg; 230 metadata.is_armor = (isGpg && isArmor); 231 232 LOG_INFO << "call StartSave"; 233 client.StartSave(fileName, kf_passphrase); 234 std::fill(std::begin(kf_passphrase), std::end(kf_passphrase), '0'); 235 return true; 236 } 237 OpenPassphraseDialog(bool confirmationEnabled,std::string * passphrase,bool set_client_passphrase,const QString & title)238 bool LoadHandler::OpenPassphraseDialog(bool confirmationEnabled, std::string *passphrase, bool set_client_passphrase, const QString &title) 239 { 240 if(passphrase) 241 passphrase->clear(); 242 243 QString pwdString; 244 if(confirmationEnabled) 245 { 246 ConfirmPassphraseDialog dlg(parent); 247 if(!title.isEmpty()) 248 dlg.setWindowTitle(title); 249 if(dlg.exec() == QDialog::Rejected) 250 return false; 251 pwdString = dlg.GetPassphrase(); 252 } 253 else 254 { 255 GetPassphraseDialog dlg(parent); 256 if(!title.isEmpty()) 257 dlg.setWindowTitle(title); 258 if(dlg.exec() == QDialog::Rejected) 259 return false; 260 pwdString = dlg.GetPassphrase(); 261 } 262 263 if(pwdString.isEmpty()) 264 { 265 if(set_client_passphrase) 266 client.SetIsPlainText(); 267 return true; 268 } 269 270 QByteArray byte_array = pwdString.toUtf8(); 271 const char *pwd = byte_array.constData(); 272 273 if(set_client_passphrase) 274 client.SetPassphrase(pwd, metadata); 275 276 if(passphrase) 277 *passphrase = pwd; 278 return true; 279 } 280 OpenSetEncryptionKeyDialogue()281 bool LoadHandler::OpenSetEncryptionKeyDialogue() 282 { 283 EncryptionKeySelectionResult selection; 284 if(!SetEncryptionKey(parent, client.EncryptionKeyFile(), client.PersistEncryptionKeyPath(), 285 client.GetFileRequestService(), selection)) 286 { 287 return false; 288 } 289 290 client.EncryptionKeyFile(selection.key_file_path); 291 client.PersistEncryptionKeyPath(selection.persist_key_path); 292 293 client.UpdateEncryptionKeyStatus(); 294 295 return true; 296 } 297 } 298