GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Xcloner_Encryption::encrypt_file()   F
last analyzed

Complexity

Conditions 20
Paths 1088

Size

Total Lines 107
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 20
eloc 56
c 3
b 1
f 0
nc 1088
nop 7
dl 0
loc 107
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: thinkovi
5
 * Date: 2018-11-27
6
 * Time: 12:11
7
 */
8
9
//namespace XCloner;
10
11
class Xcloner_Encryption
12
{
13
	const FILE_ENCRYPTION_BLOCKS = 1024 * 1024;
14
	const FILE_ENCRYPTION_SUFFIX = ".encrypted";
15
	const FILE_DECRYPTION_SUFFIX = ".decrypted";
16
17
	private $xcloner_settings;
18
	private $logger;
19
	private $xcloner_container;
20
	private $verification = false;
21
22
	/**
23
	 * Xcloner_Encryption constructor.
24
	 * @param Xcloner $xcloner_container
25
	 */
26
	public function __construct(Xcloner $xcloner_container)
27
	{
28
		$this->xcloner_container = $xcloner_container;
29
		if (property_exists($xcloner_container, 'xcloner_settings')) {
30
			$this->xcloner_settings = $xcloner_container->get_xcloner_settings();
31
		} else {
32
			$this->xcloner_settings = "";
33
		}
34
35
		if (property_exists($xcloner_container, 'xcloner_logger')) {
36
			$this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_encryption");
37
		} else {
38
			$this->logger = "";
39
		}
40
	}
41
42
	/**
43
	 * Returns the backup encryption key
44
	 *
45
	 * @return string|null
46
	 */
47
	public function get_backup_encryption_key()
48
	{
49
		if (is_object($this->xcloner_settings)) {
50
			return $this->xcloner_settings->get_xcloner_encryption_key();
51
		}
52
53
		return null;
54
55
	}
56
57
	/**
58
	 * Check if provided filename has encrypted suffix
59
	 *
60
	 * @param $filename
61
	 * @return bool
62
	 */
63
	public function is_encrypted_file($filename) {
64
		$fp = fopen($this->get_xcloner_path().$filename, 'r');
65
		if (is_resource($fp)) {
66
			$encryption_length = fread($fp, 16);
67
			fclose($fp);
68
			if (is_numeric($encryption_length)) {
69
				return true;
70
			}
71
		}
72
73
		return false;
74
75
	}
76
77
	/**
78
	 * Returns the filename with encrypted suffix
79
	 *
80
	 * @param string $filename
81
	 * @return string
82
	 */
83
	public function get_encrypted_target_backup_file_name($filename) {
84
85
		return str_replace(self::FILE_DECRYPTION_SUFFIX, "", $filename).self::FILE_ENCRYPTION_SUFFIX;
86
	}
87
88
	/**
89
	 * Returns the filename without encrypted suffix
90
	 *
91
	 * @param string $filename
92
	 * @return string
93
	 */
94
	public function get_decrypted_target_backup_file_name($filename) {
95
96
		return str_replace(self::FILE_ENCRYPTION_SUFFIX, "", $filename).self::FILE_DECRYPTION_SUFFIX;
97
	}
98
99
	/**
100
	 * Encrypt the passed file and saves the result in a new file with ".enc" as suffix.
101
	 *
102
	 * @param string $source Path to file that should be encrypted
103
	 * @param string $dest   File name where the encryped file should be written to.
104
	 * @param string $key    The key used for the encryption
105
	 * @param int $start   Start position for reading when doing incremental mode.
106
	 * @param string $iv   The IV key to use.
107
	 * @param bool $verification   Weather we should we try to verify the decryption.
108
	 * @return array|false  Returns array or FALSE if an error occured
109
     * @throws Exception
110
	 */
111
	public function encrypt_file($source, $dest = "", $key = "", $start = 0, $iv = 0, $verification = true, $recursive = false)
112
	{
113
		if (is_object($this->logger)) {
114
			$this->logger->info(sprintf('Encrypting file %s at position %d IV %s', $source, $start, base64_encode($iv)));
115
		}
116
117
		//$key = substr(sha1($key, true), 0, 16);
118
		if (!$key) {
119
			$key = $this->get_backup_encryption_key();
120
		}
121
		$key_digest = openssl_digest($key, "md5", true);
122
123
		$keep_local = 1;
124
		if (!$dest) {
125
			$dest = $this->get_encrypted_target_backup_file_name($source);
126
			$keep_local = 0;
127
		}
128
129
		if (!$iv || !$start) {
130
			//$iv = openssl_random_pseudo_bytes(16);
131
			$iv = str_pad(self::FILE_ENCRYPTION_BLOCKS, 16, "0000000000000000", STR_PAD_LEFT);
132
		}
133
134
		if (!$start) {
135
			$fpOut = fopen($this->get_xcloner_path().$dest, 'w');
136
		} else {
137
			$fpOut = fopen($this->get_xcloner_path().$dest, 'a');
138
		}
139
140
		if (is_resource($fpOut)) {
141
142
			// Put the initialization vector to the beginning of the file
143
			if (!$start) {
144
				fwrite($fpOut, $iv);
145
			}
146
147
			if (file_exists($this->get_xcloner_path().$source) &&
148
				$fpIn = fopen($this->get_xcloner_path().$source, 'rb')) {
149
150
				fseek($fpIn, (int)$start);
151
152
				if (!feof($fpIn)) {
153
154
					$plaintext = fread($fpIn, 16 * self::FILE_ENCRYPTION_BLOCKS);
155
					$ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key_digest, OPENSSL_RAW_DATA, $iv);
156
157
					// Use the first 16 bytes of the ciphertext as the next initialization vector
158
					$iv = substr($ciphertext, 0, 16);
159
					//$iv = openssl_random_pseudo_bytes(16);
160
161
					fwrite($fpOut, $ciphertext);
162
163
					$start = ftell($fpIn);
164
165
					fclose($fpOut);
166
167
                    unset($ciphertext);
168
                    unset($plaintext);
169
170
					if (!feof($fpIn)) {
171
						fclose($fpIn);
172
						//echo "\n NEW:".$key.md5($iv);
173
						//self::encryptFile($source, $dest, $key, $start, $iv);
174
						if ($recursive) {
175
							$this->encrypt_file($source, $dest, $key, $start, ($iv), $verification, $recursive);
176
						} else {
177
178
							if (($iv) != base64_decode(base64_encode($iv)))
179
							{
180
								throw new \Exception('Could not encode IV for transport');
181
							}
182
183
							return array(
184
								"start" => $start,
185
								"iv" => base64_encode($iv),
186
								"target_file" => $dest,
187
								"finished" => 0
188
							);
189
						}
190
					}
191
192
				}
193
			} else {
194
				if (is_object($this->logger)) {
195
					$this->logger->error('Unable to read source file for encryption.');
196
				}
197
				throw new \Exception("Unable to read source file for encryption.");
198
			}
199
		} else {
200
			if (is_object($this->logger)) {
201
				$this->logger->error('Unable to write destination file for encryption.');
202
			}
203
			throw new \Exception("Unable to write destination file for encryption.");
204
		}
205
206
		if ($verification) {
207
			$this->verify_encrypted_file($dest);
208
		}
209
210
		//we replace the original backup with the encrypted one
211
		if (!$keep_local && copy($this->get_xcloner_path().$dest,
212
			 $this->get_xcloner_path().$source)) {
213
			unlink($this->get_xcloner_path().$dest);
214
		}
215
216
217
		return array("target_file" => $dest, "finished" => 1);
218
	}
219
220
	/**
221
	 * @param string $file
222
	 */
223
	public function verify_encrypted_file($file) {
224
		if (is_object($this->logger)) {
225
			$this->logger->info(sprintf('Verifying encrypted file %s', $file));
226
		}
227
228
		$this->verification = true;
229
		$this->decrypt_file($file);
230
		$this->verification = false;
231
	}
232
233
	/**
234
	 * Dencrypt the passed file and saves the result in a new file, removing the
235
	 * last 4 characters from file name.
236
	 *
237
	 * @param string $source Path to file that should be decrypted
238
	 * @param string $dest   File name where the decryped file should be written to.
239
	 * @param string $key    The key used for the decryption (must be the same as for encryption)
240
	 * @param int $start   Start position for reading when doing incremental mode.
241
	 * @param string $iv   The IV key to use.
242
	 * @return array|false  Returns array or FALSE if an error occured
243
     * @throws Exception
244
	 */
245
	public function decrypt_file($source, $dest = "", $key = "", $start = 0, $iv = 0, $recursive = false)
246
	{
247
		if (is_object($this->logger)) {
248
			$this->logger->info(sprintf('Decrypting file %s at position %d with IV %s', $source, $start, base64_encode($iv)));
249
		}
250
251
		//$key = substr(sha1($key, true), 0, 16);
252
		if (!$key) {
253
			$key = $this->get_backup_encryption_key();
254
		}
255
256
		$key_digest = openssl_digest($key, "md5", true);
257
258
		$keep_local = 1;
259
		if (!$dest) {
260
			$dest = $this->get_decrypted_target_backup_file_name($source);
261
			$keep_local = 0;
262
		}
263
264
		if (!$start) {
265
			if ($this->verification) {
266
				$fpOut = fopen("php://stdout", 'w');
267
			} else {
268
				$fpOut = fopen($this->get_xcloner_path().$dest, 'w');
269
			}
270
		} else {
271
			if ($this->verification) {
272
				$fpOut = fopen("php://stdout", 'a');
273
			} else {
274
				$fpOut = fopen($this->get_xcloner_path().$dest, 'a');
275
			}
276
		}
277
278
		if (is_resource($fpOut)) {
279
			if (file_exists($this->get_xcloner_path().$source) &&
280
				$fpIn = fopen($this->get_xcloner_path().$source, 'rb')) {
281
282
				$encryption_length = (int)fread($fpIn, 16);
283
				if (!$encryption_length) {
284
					$encryption_length = self::FILE_ENCRYPTION_BLOCKS;
285
				}
286
287
				fseek($fpIn, (int)$start);
288
289
				// Get the initialzation vector from the beginning of the file
290
				if (!$iv) {
291
					$iv = fread($fpIn, 16);
292
				}
293
294
				if (!feof($fpIn)) {
295
296
					// we have to read one block more for decrypting than for encrypting
297
					$ciphertext = fread($fpIn, 16 * ($encryption_length + 1));
298
					$plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key_digest, OPENSSL_RAW_DATA, $iv);
299
300
					if (!$plaintext) {
301
						unlink($this->get_xcloner_path().$dest);
302
						if (is_object($this->logger)) {
303
							$this->logger->error('Backup decryption failed, please check your provided Encryption Key.');
304
						}
305
						throw new \Exception("Backup decryption failed, please check your provided Encryption Key.");
306
					}
307
308
					// Use the first 16 bytes of the ciphertext as the next initialization vector
309
					$iv = substr($ciphertext, 0, 16);
310
311
					if (!$this->verification) {
312
						fwrite($fpOut, $plaintext);
313
					}
314
315
					$start = ftell($fpIn);
316
317
					fclose($fpOut);
318
319
					if (!feof($fpIn)) {
320
						fclose($fpIn);
321
						if ($this->verification || $recursive) {
322
							unset($ciphertext);
323
							unset($plaintext);
324
							$this->decrypt_file($source, $dest, $key, $start, $iv, $recursive);
325
						} else {
326
							if (($iv) != base64_decode(base64_encode($iv)))
327
							{
328
								throw new \Exception('Could not encode IV for transport');
329
							}
330
331
							return array(
332
								"start" => $start,
333
								"encryption_length" => $encryption_length,
334
								"iv" => base64_encode($iv),
335
								"target_file" => $dest,
336
								"finished" => 0
337
							);
338
					}
339
					}
340
341
				}
342
			} else {
343
				if (is_object($this->logger)) {
344
					$this->logger->error('Unable to read source file for decryption');
345
				}
346
				throw new \Exception("Unable to read source file for decryption");
347
			}
348
		} else {
349
			if (is_object($this->logger)) {
350
				$this->logger->error('Unable to write destination file for decryption');
351
			}
352
			throw new \Exception("Unable to write destination file for decryption");
353
		}
354
355
		//we replace the original backup with the encrypted one
356
		if (!$keep_local && !$this->verification && copy($this->get_xcloner_path().$dest,
357
			$this->get_xcloner_path().$source)) {
358
			unlink($this->get_xcloner_path().$dest);
359
		}
360
361
		return array("target_file" => $dest, "finished" => 1);
362
	}
363
364
	public function get_xcloner_path() {
365
		if (is_object($this->xcloner_settings)) {
366
			return $this->xcloner_settings->get_xcloner_store_path().DS;
367
		}
368
369
		return null;
370
	}
371
372
}
373
374
375
try {
376
377
	if (isset($argv[1])) {
378
379
		class Xcloner {
380
			/**
381
			 * Xcloner constructor.
382
			 */
383
			public function __construct()
384
			{
385
			}
386
		}
387
		$xcloner_encryption = new Xcloner_Encryption(new Xcloner());
388
389
		if ($argv[1] == "-e") {
390
			$xcloner_encryption->encrypt_file($argv[2], $argv[2].".enc", $argv[4], 0, 0, false, true);
391
		} elseif ($argv[1] == "-d") {
392
			$xcloner_encryption->decrypt_file($argv[2], $argv[2].".dec", $argv[4], 0, 0, true);
393
		}
394
	}
395
}catch (\Exception $e) {
396
	echo "CAUGHT: ".$e->getMessage();
397
}
398