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