1 //**********************************************************************************
2 //EncryptPad Copyright 2015 Evgeny Pokhilko
3 //<evpomail@gmail.com> <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 <string>
21 #include <cstdio>
22 #include <iostream>
23 #include <fstream>
24 #include <utility>
25 #include <tuple>
26 #include "gtest/gtest.h"
27 #include "encryptor.h"
28 
29 
30 using namespace std;
31 using namespace EncryptPadEncryptor;
32 using namespace Botan;
33 using namespace EncryptPad;
34 
35 class EncryptorFixtureBase
36 {
37 protected:
38 	Encryptor encryptor_; // encryptor should go first because it has Botan library initializer
39 	SecureVector<byte> initial_string_;
40 	SecureVector<byte> buffer_;
41     PacketMetadata metadata_;
42 	static const string text_to_encrypt_;
43 	static const string temp_file_;
44 	static const string x2_key_file_;
45 
SetUpBase()46 	void SetUpBase()
47 	{
48         initial_string_ = SecureVector<byte>(text_to_encrypt_.begin(),
49                 text_to_encrypt_.end());
50         metadata_= PacketMetadata();
51         metadata_.cipher_algo = kDefaultCipherAlgo;
52         metadata_.hash_algo = kDefaultHashAlgo;
53         metadata_.compression = kDefaultCompression;
54         metadata_.iterations = kDefaultIterations;
55         metadata_.persist_key_path = false;
56         metadata_.is_binary = true;
57         metadata_.file_name = "_CONSOLE";
58 	}
59 
TearDownBase()60 	void TearDownBase()
61 	{
62 		encryptor_.SetIsPlainText();
63 		buffer_.clear();
64 		remove(temp_file_.c_str());
65 	}
66 };
67 
68 
69 const string EncryptorFixtureBase::text_to_encrypt_ = "Hello World";
70 const string EncryptorFixtureBase::temp_file_ = "file.epad";
71 const string EncryptorFixtureBase::x2_key_file_ = "x2.key";
72 
73 class EncryptorFixture : public EncryptorFixtureBase, public ::testing::Test
74 {
75 protected:
SetUp()76 	virtual void SetUp()
77 	{
78 		SetUpBase();
79 	}
80 
TearDown()81 	virtual void TearDown()
82 	{
83 		TearDownBase();
84 	}
85 
86 };
87 
88 namespace {
FromSecureVectorToString(const SecureVector<byte> & sec_vec)89 	string FromSecureVectorToString(const SecureVector<byte> &sec_vec)
90 	{
91 		const char *sec_vec_buf = reinterpret_cast<const char *>(sec_vec.data());
92 		return string(sec_vec_buf, sec_vec_buf + sec_vec.size());
93 	}
94 
CopyFile(string file_from,string file_to)95 	bool CopyFile(string file_from, string file_to)
96 	{
97 		ifstream src_stm(file_from, ifstream::binary);
98 		if(src_stm.fail())
99 			return false;
100 		ofstream dst_stm(file_to, ofstream::binary);
101 		if(dst_stm.fail())
102 			return false;
103         if(dst_stm << src_stm.rdbuf())
104             return true;
105         else
106             return false;
107     }
108 
CreateFile(string fileName,string content)109 	void CreateFile(string fileName, string content)
110 	{
111 		remove(fileName.c_str());
112 		ofstream stm(fileName);
113 		stm << content;
114 	}
115 }
116 
TEST_F(EncryptorFixture,When_plain_text_without_X2_File_is_saved_in_plain_text)117 TEST_F(EncryptorFixture, When_plain_text_without_X2_File_is_saved_in_plain_text)
118 {
119 	// Arrange
120 
121 	// Act
122 	EpadResult save_result = encryptor_.Save(temp_file_, initial_string_,
123            "", false, &metadata_);
124 
125 	// Assert
126 	ifstream stm(temp_file_);
127 	string str;
128 	getline(stm, str, '\0');
129 
130 	ASSERT_EQ(EpadResult::Success, save_result);
131 	ASSERT_EQ(text_to_encrypt_, str);
132 }
133 
TEST_F(EncryptorFixture,When_file_is_plain_text_File_is_loaded_without_passphrase_and_X2)134 TEST_F(EncryptorFixture, When_file_is_plain_text_File_is_loaded_without_passphrase_and_X2)
135 {
136 	// Arrange
137 	ofstream stm(temp_file_);
138 	stm << text_to_encrypt_;
139 	stm.close();
140 
141 	// Act
142 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_);
143 
144 	// Assert
145 	ASSERT_EQ(EpadResult::Success, load_result);
146 	ASSERT_EQ(text_to_encrypt_, FromSecureVectorToString(buffer_));
147 }
148 
149 
150 // Exceptions
151 
TEST_F(EncryptorFixture,When_passphrase_is_wrong_and_without_X2_Encryption_error)152 TEST_F(EncryptorFixture, When_passphrase_is_wrong_and_without_X2_Encryption_error)
153 {
154 	// Arrange
155 	encryptor_.SetPassphrase("123", &metadata_);
156 	// encryptor_.Save(temp_file_, initial_string_);
157 	// encryptor_.SetPassphrase("321", &metadata_);
158     //
159 	// // Act
160 	// EpadResult load_result = encryptor_.Load(temp_file_, buffer_);
161     //
162 	// // Assert
163 	// ASSERT_EQ(EpadResult::EncryptionError, load_result);
164 }
165 
TEST_F(EncryptorFixture,When_passphrase_is_correct_and_X2_file_does_not_exist_X2_key_IO_error)166 TEST_F(EncryptorFixture, When_passphrase_is_correct_and_X2_file_does_not_exist_X2_key_IO_error)
167 {
168 	// Arrange
169 	encryptor_.SetPassphrase("123", &metadata_);
170 	bool persist_x2_location = false;
171 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persist_x2_location,
172             &metadata_);
173 
174 	// Act
175 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, "i_dont_exist.key",
176             nullptr, &metadata_);
177 
178 	// Assert
179 	ASSERT_EQ(EpadResult::IOErrorKeyFile, load_result);
180 }
181 
TEST_F(EncryptorFixture,When_passphrase_is_correct_and_X2_file_persisted_and_does_not_exist_X2_IO_error)182 TEST_F(EncryptorFixture, When_passphrase_is_correct_and_X2_file_persisted_and_does_not_exist_X2_IO_error)
183 {
184 	// Arrange
185 	encryptor_.SetPassphrase("123", &metadata_);
186 	bool persist_x2_location = true;
187 	remove("x2_copy.key");
188 	CopyFile(x2_key_file_, "x2_copy.key");
189 	encryptor_.Save(temp_file_, initial_string_, "x2_copy.key", persist_x2_location, &metadata_);
190 	remove("x2_copy.key");
191 
192 	// Act
193 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_,
194             "", nullptr, &metadata_);
195 
196 	// Assert
197 	ASSERT_EQ(EpadResult::IOErrorKeyFile, load_result);
198 }
199 
TEST_F(EncryptorFixture,When_passphrase_is_correct_and_X2_file_is_wrong_Encryption_error)200 TEST_F(EncryptorFixture, When_passphrase_is_correct_and_X2_file_is_wrong_Encryption_error)
201 {
202 	// Arrange
203 	encryptor_.SetPassphrase("123", &metadata_);
204 	CreateFile("x2-invalid.key", "FKeYEq3z3S8krxeWX+gFRnmkTzRTjwyjRxgOFw+eP3s=");
205 
206 
207 	bool persist_x2_location = true;
208 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persist_x2_location, &metadata_);
209 
210 
211 	// Act
212 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, "x2-invalid.key", nullptr,
213             &metadata_);
214 	remove("x2-invalid.key");
215 
216 	// Assert
217     ASSERT_EQ(EpadResult::InvalidKeyFile, load_result);
218 }
219 
TEST_F(EncryptorFixture,When_invalid_X2_file_Save_result_is_invalid_X2_file)220 TEST_F(EncryptorFixture, When_invalid_X2_file_Save_result_is_invalid_X2_file)
221 {
222 	// Arrange
223 	encryptor_.SetPassphrase("123", &metadata_);
224 	// CreateFile("x2-invalid.key", "ICANTBEAKEY     DFSFSDFSDF\t\r\n^*&%*&^*&^*(&^");
225 	CreateFile("x2-invalid.key", "");
226 	bool persist_x2_location = false;
227 
228 	// Act
229 	EpadResult save_result = encryptor_.Save(temp_file_, initial_string_, "x2-invalid.key", persist_x2_location, &metadata_);
230 	remove("x2-invalid.key");
231 
232 	// Assert
233 	ASSERT_EQ(EpadResult::InvalidKeyFile, save_result);
234 }
235 
TEST_F(EncryptorFixture,When_passphrase_is_correct_and_X2_file_is_invalid_Invalid_X2_file)236 TEST_F(EncryptorFixture, When_passphrase_is_correct_and_X2_file_is_invalid_Invalid_X2_file)
237 {
238 	// Arrange
239 
240 	encryptor_.SetPassphrase("123", &metadata_);
241 	CreateFile("x2-invalid.key", "ICANTBEAKEY     DFSFSDFSDF\t\r\n^*&%*&^*&^*(&^");
242 	bool persist_x2_location = false;
243 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persist_x2_location, &metadata_);
244 
245 	// Act
246 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, "x2-invalid.key", nullptr,
247             &metadata_);
248 	remove("x2-invalid.key");
249 
250 	// Assert
251 	ASSERT_EQ(EpadResult::InvalidKeyFile, load_result);
252 }
253 
TEST_F(EncryptorFixture,When_plain_text_and_invalid_X2_file_Load_result_is_invalid_X2_file)254 TEST_F(EncryptorFixture, When_plain_text_and_invalid_X2_file_Load_result_is_invalid_X2_file)
255 {
256 	// Arrange
257 	encryptor_.SetIsPlainText();
258 	CreateFile("x2-invalid.key", "ICANTBEAKEY     DFSFSDFSDF\t\r\n^*&%*&^*&^*(&^");
259 	bool persist_x2_location = false;
260 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persist_x2_location,
261             &metadata_);
262 
263 	// Act
264 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, "x2-invalid.key",
265             nullptr, &metadata_);
266 	remove("x2-invalid.key");
267 
268 	// Assert
269 	ASSERT_EQ(EpadResult::InvalidKeyFile, load_result);
270 }
271 
TEST_F(EncryptorFixture,When_passphrase_and_X2_and_X2_not_persisted_and_loaded_without_X2_Result_is_X2_required)272 TEST_F(EncryptorFixture, When_passphrase_and_X2_and_X2_not_persisted_and_loaded_without_X2_Result_is_X2_required)
273 {
274 	// Arrange
275 	encryptor_.SetPassphrase("123", &metadata_);
276 	bool persiste_x2_location = false;
277 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persiste_x2_location,
278             &metadata_);
279 
280 	// Act
281 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, "", nullptr,
282             &metadata_);
283 
284 	// Assert
285 	ASSERT_EQ(EpadResult::KeyFileNotSpecified, load_result);
286 }
287 
288 // Disable the test because this test is done in loadFile before coming to Load. However, we leave the test
289 // because this logic may need to move to Encryptor::Load
290 // TEST_F(EncryptorFixture, When_plain_text_and_X2_and_X2_not_persisted_and_loaded_without_X2_Result_is_X2_required)
291 // {
292 // 	// Arrange
293 // 	encryptor_.SetIsPlainText();
294 // 	bool persiste_x2_location = false;
295 // 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persiste_x2_location,
296 //             &metadata_);
297 //
298 // 	// Act
299 // 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, "", nullptr,
300 //             &metadata_);
301 //
302 // 	// Assert
303 // 	ASSERT_EQ(EpadResult::KeyFileNotSpecified, load_result);
304 // }
305 
TEST_F(EncryptorFixture,When_passphrase_used_and_saved_without_key_The_result_of_load_with_key_and_passphrase_is_OK)306 TEST_F(EncryptorFixture, When_passphrase_used_and_saved_without_key_The_result_of_load_with_key_and_passphrase_is_OK)
307 {
308 	// Arrange
309 	encryptor_.SetPassphrase("123", &metadata_);
310 	encryptor_.Save(temp_file_, initial_string_, "", false, &metadata_);
311 
312 	// Act
313 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_, x2_key_file_,
314             nullptr, &metadata_);
315 
316 	// Assert
317 	ASSERT_EQ(EpadResult::Success, load_result);
318 }
319 
TEST_F(EncryptorFixture,When_passphrase_used_with_persisted_key_Key_information_is_available_after_load)320 TEST_F(EncryptorFixture, When_passphrase_used_with_persisted_key_Key_information_is_available_after_load)
321 {
322 	// Arrange
323 	encryptor_.SetPassphrase("123", &metadata_);
324 	bool persistX2KeyLocation = true;
325 	encryptor_.Save(temp_file_, initial_string_, x2_key_file_, persistX2KeyLocation,
326             &metadata_);
327 
328 	// Act
329 	EpadResult load_result = encryptor_.Load(temp_file_, buffer_,
330             "", nullptr, &metadata_);
331 
332 	// Assert
333     ASSERT_EQ(EpadResult::Success, load_result);
334 	ASSERT_EQ(x2_key_file_, encryptor_.GetX2KeyLocation());
335 }
336 
337 // Test different combinations saving with key
338 
339 struct TestParam
340 {
341 	string passphrase;
342 	bool usePassphrase;
343 	bool useX2;
344 	bool persistX2;
345 	bool useX2ParameterInLoad;
346 };
347 
348 class EncryptorFixtureWithParam : public EncryptorFixtureBase, public ::testing::TestWithParam<TestParam>
349 {
350 public:
351 	static TestParam ParameterCombination[];
352 
353 protected:
SetUp()354 	virtual void SetUp()
355 	{
356 		SetUpBase();
357 	}
358 
TearDown()359 	virtual void TearDown()
360 	{
361 		TearDownBase();
362 	}
363 };
364 
365 TestParam EncryptorFixtureWithParam::ParameterCombination[] =
366 {
367 	//pwd	usePassphrase	useX2	persistX2	useX2ParameterInLoad
368 	{"123",	true,		false,	false,		false},
369 	{"123",	true,		true,	false,		true},
370 	{"123",	true,		true,	true,		false},
371 	{"123",	true,		true,	true,		true},
372 	{"",	false,		false,	false,		false},
373 	{"",	false,		true,	false,		true},
374     // File type identification happens before calling Load
375     // see the comment in
376     // When_plain_text_and_X2_and_X2_not_persisted_and_loaded_without_X2_Result_is_X2_required
377 	// {"",	false,		true,	true,		false},
378 	{"",	false,		true,	true,		true}
379 };
380 
TEST_P(EncryptorFixtureWithParam,When_combination_of_pwd_X2_persist_File_is_saved_and_loaded)381 TEST_P(EncryptorFixtureWithParam, When_combination_of_pwd_X2_persist_File_is_saved_and_loaded)
382 {
383 	// Arrange
384 	const TestParam &testParam = GetParam();
385 	if(!testParam.passphrase.empty())
386 		encryptor_.SetPassphrase(testParam.passphrase.c_str(), &metadata_);
387 	else
388 		encryptor_.SetIsPlainText();
389 
390 	// Act
391 	EpadResult save_result = encryptor_.Save(
392 		temp_file_,
393 		initial_string_,
394 		testParam.useX2 ? x2_key_file_ : "",
395 		testParam.persistX2,
396         &metadata_);
397 
398 	EpadResult load_result = encryptor_.Load(
399 		temp_file_,
400 		buffer_,
401 		testParam.useX2ParameterInLoad ? x2_key_file_ : "",
402         nullptr,
403         &metadata_);
404 
405 	string str = FromSecureVectorToString(buffer_);
406 
407 	// Assert
408 	ASSERT_EQ(EpadResult::Success, save_result);
409 	ASSERT_EQ(EpadResult::Success, load_result);
410 	ASSERT_EQ(text_to_encrypt_, str);
411 }
412 
413 INSTANTIATE_TEST_CASE_P(Common, EncryptorFixtureWithParam,
414 						::testing::ValuesIn(EncryptorFixtureWithParam::ParameterCombination));
415