Version Description
- New: SFTP support for backups and clone
- Fix: Database dump for backup tasks with defined socket path or port number in wp-config.php
- Fix: Optimize Wordpress tables before backup
- Fix: Compatibility with Better WP Security
- Fix: Not adding jQuery on front page while using branding option
Download this release
Release Info
Developer | freediver |
Plugin | ManageWP Worker |
Version | 3.9.27 |
Comparing to | |
See all releases |
Code changes from version 3.9.26 to 3.9.27
- backup.class.php +1620 -1423
- init.php +2 -2
- installer.class.php +1 -1
- lib/PHPSecLib/Crypt/AES.php +540 -0
- lib/PHPSecLib/Crypt/Blowfish.php +1468 -0
- lib/PHPSecLib/Crypt/DES.php +2536 -0
- lib/PHPSecLib/Crypt/Hash.php +823 -0
- lib/PHPSecLib/Crypt/RC4.php +492 -0
- lib/PHPSecLib/Crypt/RSA.php +2693 -0
- lib/PHPSecLib/Crypt/Random.php +249 -0
- lib/PHPSecLib/Crypt/Rijndael.php +2062 -0
- lib/PHPSecLib/Crypt/TripleDES.php +842 -0
- lib/PHPSecLib/Crypt/Twofish.php +1664 -0
- lib/PHPSecLib/File/ANSI.php +560 -0
- lib/PHPSecLib/File/ASN1.php +1293 -0
- lib/PHPSecLib/File/X509.php +4351 -0
- lib/PHPSecLib/Math/BigInteger.php +2123 -0
backup.class.php
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
<?php
|
2 |
/*************************************************************
|
3 |
-
*
|
4 |
* backup.class.php
|
5 |
-
*
|
6 |
* Manage Backups
|
7 |
-
*
|
8 |
-
*
|
9 |
* Copyright (c) 2011 Prelovac Media
|
10 |
* www.prelovac.com
|
11 |
**************************************************************/
|
@@ -16,6 +16,9 @@ endif;
|
|
16 |
define('MWP_BACKUP_DIR', WP_CONTENT_DIR . '/managewp/backups');
|
17 |
define('MWP_DB_DIR', MWP_BACKUP_DIR . '/mwp_db');
|
18 |
|
|
|
|
|
|
|
19 |
$zip_errors = array(
|
20 |
'No error',
|
21 |
'No error',
|
@@ -59,7 +62,7 @@ $unzip_errors = array(
|
|
59 |
|
60 |
/**
|
61 |
* The main class for processing database and full backups on ManageWP worker.
|
62 |
-
*
|
63 |
* @copyright 2011-2012 Prelovac Media
|
64 |
* @version 3.9.24
|
65 |
* @package ManageWP
|
@@ -74,22 +77,22 @@ class MMB_Backup extends MMB_Core {
|
|
74 |
var $ftp;
|
75 |
var $dropbox;
|
76 |
var $google_drive;
|
77 |
-
|
78 |
/**
|
79 |
* Initializes site_name, statuses, and tasks attributes.
|
80 |
-
*
|
81 |
* @return void
|
82 |
*/
|
83 |
function __construct() {
|
84 |
parent::__construct();
|
85 |
-
|
86 |
"_",
|
87 |
"/",
|
88 |
-
|
89 |
), array(
|
90 |
"",
|
91 |
"-",
|
92 |
-
|
93 |
), rtrim($this->remove_http(get_bloginfo('url')), "/"));
|
94 |
$this->statuses = array(
|
95 |
'db_dump' => 1,
|
@@ -99,79 +102,79 @@ class MMB_Backup extends MMB_Core {
|
|
99 |
'dropbox' => 5,
|
100 |
'ftp' => 6,
|
101 |
'email' => 7,
|
102 |
-
|
103 |
'finished' => 100
|
104 |
);
|
105 |
$this->tasks = get_option('mwp_backup_tasks');
|
106 |
}
|
107 |
-
|
108 |
/**
|
109 |
* Tries to increase memory limit to 384M and execution time to 600s.
|
110 |
-
*
|
111 |
* @return array an array with two keys for execution time and memory limit (0 - if not changed, 1 - if succesfully)
|
112 |
*/
|
113 |
-
function set_memory() {
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
function get_backup_settings() {
|
145 |
$backup_settings = get_option('mwp_backup_tasks');
|
146 |
-
|
147 |
if (!empty($backup_settings))
|
148 |
return $backup_settings;
|
149 |
else
|
150 |
return false;
|
151 |
}
|
152 |
-
|
153 |
/**
|
154 |
* Sets backup task defined from master, if task name is "Backup Now" this function fires processing backup.
|
155 |
-
*
|
156 |
* @param mixed $params parameters sent from master
|
157 |
* @return mixed|boolean $this->tasks variable if success, array with error message if error has ocurred, false if $params are empty
|
158 |
*/
|
159 |
function set_backup_task($params) {
|
160 |
//$params => [$task_name, $args, $error]
|
161 |
if (!empty($params)) {
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
extract($params);
|
169 |
-
|
170 |
//$before = $this->get_backup_settings();
|
171 |
$before = $this->tasks;
|
172 |
if (!$before || empty($before))
|
173 |
$before = array();
|
174 |
-
|
175 |
if (isset($args['remove'])) {
|
176 |
unset($before[$task_name]);
|
177 |
$return = array(
|
@@ -181,14 +184,14 @@ class MMB_Backup extends MMB_Core {
|
|
181 |
if (isset($params['account_info']) && is_array($params['account_info'])) { //only if sends from master first time(secure data)
|
182 |
$args['account_info'] = $account_info;
|
183 |
}
|
184 |
-
|
185 |
$before[$task_name]['task_args'] = $args;
|
186 |
if (strlen($args['schedule']))
|
187 |
$before[$task_name]['task_args']['next'] = $this->schedule_next($args['type'], $args['schedule']);
|
188 |
-
|
189 |
$return = $before[$task_name];
|
190 |
}
|
191 |
-
|
192 |
//Update with error
|
193 |
if (isset($error)) {
|
194 |
if (is_array($error)) {
|
@@ -197,43 +200,43 @@ class MMB_Backup extends MMB_Core {
|
|
197 |
$before[$task_name]['task_results'][count($before[$task_name]['task_results'])]['error'] = $error;
|
198 |
}
|
199 |
}
|
200 |
-
|
201 |
if (isset($time) && $time) { //set next result time before backup
|
202 |
if (is_array($before[$task_name]['task_results'])) {
|
203 |
$before[$task_name]['task_results'] = array_values($before[$task_name]['task_results']);
|
204 |
}
|
205 |
$before[$task_name]['task_results'][count($before[$task_name]['task_results'])]['time'] = $time;
|
206 |
}
|
207 |
-
|
208 |
$this->update_tasks($before);
|
209 |
//update_option('mwp_backup_tasks', $before);
|
210 |
-
|
211 |
if ($task_name == 'Backup Now') {
|
212 |
-
|
213 |
$backup_settings = $this->tasks;
|
214 |
-
|
215 |
if (is_array($result) && array_key_exists('error', $result)) {
|
216 |
-
|
217 |
} else {
|
218 |
$return = $backup_settings[$task_name];
|
219 |
}
|
220 |
}
|
221 |
return $return;
|
222 |
}
|
223 |
-
|
224 |
return false;
|
225 |
}
|
226 |
-
|
227 |
/**
|
228 |
* Checks if scheduled task is ready for execution,
|
229 |
* if it is ready master sends google_drive_token, failed_emails, success_emails if are needed.
|
230 |
-
*
|
231 |
* @return void
|
232 |
*/
|
233 |
function check_backup_tasks() {
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
$settings = $this->tasks;
|
238 |
if (is_array($settings) && !empty($settings)) {
|
239 |
foreach ($settings as $task_name => $setting) {
|
@@ -245,139 +248,139 @@ class MMB_Backup extends MMB_Core {
|
|
245 |
'task_name' => $task_name,
|
246 |
'task_id' => $setting['task_args']['task_id'],
|
247 |
'site_key' => $setting['task_args']['site_key'],
|
248 |
-
|
249 |
);
|
250 |
-
|
251 |
if (isset($setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'])) {
|
252 |
-
|
253 |
}
|
254 |
-
|
255 |
$check = $this->validate_task($check_data, $setting['task_args']['url']);
|
256 |
if($check == 'paused' || $check == 'deleted'){
|
257 |
continue;
|
258 |
}
|
259 |
$worker_upto_3_9_22 = (MMB_WORKER_VERSION <= '3.9.22'); // worker version is less or equals to 3.9.22
|
260 |
-
|
261 |
// This is the patch done in worker 3.9.22 because old worked provided message in the following format:
|
262 |
// token - not found or token - {...json...}
|
263 |
// The new message is a serialized string with google_drive_token or message.
|
264 |
if ($worker_upto_3_9_22) {
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
} else {
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
}
|
279 |
-
|
280 |
}
|
281 |
-
|
282 |
$update = array(
|
283 |
'task_name' => $task_name,
|
284 |
-
'args' => $settings[$task_name]['task_args']
|
285 |
);
|
286 |
-
|
287 |
if ($check != 'paused') {
|
288 |
-
|
289 |
}
|
290 |
-
|
291 |
//Update task with next schedule
|
292 |
$this->set_backup_task($update);
|
293 |
-
|
294 |
-
|
295 |
$error = '';
|
296 |
-
|
297 |
if (is_array($result) && array_key_exists('error', $result)) {
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
} else {
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
}
|
327 |
-
|
328 |
break; //Only one backup per cron
|
329 |
}
|
330 |
}
|
331 |
}
|
332 |
-
|
333 |
}
|
334 |
-
|
335 |
/**
|
336 |
* Runs backup task invoked from ManageWP master.
|
337 |
-
*
|
338 |
* @param string $task_name name of backup task
|
339 |
* @param string|bool[optional] $google_drive_token false if backup destination is not Google Drive, json of Google Drive token if it is remote destination (default: false)
|
340 |
* @return mixed array with backup statistics if successful, array with error message if not
|
341 |
*/
|
342 |
function task_now($task_name, $google_drive_token = false) {
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
}
|
375 |
-
|
376 |
/**
|
377 |
* Backup a full wordpress instance, including a database dump, which is placed in mwp_db dir in root folder.
|
378 |
* All backups are compressed by zip and placed in wp-content/managewp/backups folder.
|
379 |
*
|
380 |
-
* @param string $args arguments passed from master
|
381 |
* [type] -> db, full
|
382 |
* [what] -> daily, weekly, monthly
|
383 |
* [account_info] -> remote destinations ftp, amazons3, dropbox, google_drive, email with their parameters
|
@@ -389,85 +392,85 @@ class MMB_Backup extends MMB_Core {
|
|
389 |
function backup($args, $task_name = false) {
|
390 |
if (!$args || empty($args))
|
391 |
return false;
|
392 |
-
|
393 |
extract($args); //extract settings
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
//Try increase memory limit and execution time
|
410 |
-
|
411 |
-
|
412 |
//Remove old backup(s)
|
413 |
$removed = $this->remove_old_backups($task_name);
|
414 |
if (is_array($removed) && isset($removed['error'])) {
|
415 |
-
|
416 |
-
|
417 |
}
|
418 |
-
|
419 |
$new_file_path = MWP_BACKUP_DIR;
|
420 |
-
|
421 |
if (!file_exists($new_file_path)) {
|
422 |
if (!mkdir($new_file_path, 0755, true))
|
423 |
-
|
424 |
return array(
|
425 |
-
|
426 |
);
|
427 |
}
|
428 |
-
|
429 |
@file_put_contents($new_file_path . '/index.php', ''); //safe
|
430 |
-
|
431 |
//Prepare .zip file name
|
432 |
$hash = md5(time());
|
433 |
$label = $type ? $type : 'manual';
|
434 |
$backup_file = $new_file_path . '/' . $this->site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') . '_' . $hash . '.zip';
|
435 |
$backup_url = WP_CONTENT_URL . '/managewp/backups/' . $this->site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') . '_' . $hash . '.zip';
|
436 |
-
|
437 |
$begin_compress = microtime(true);
|
438 |
-
|
439 |
//Optimize tables?
|
440 |
if (isset($optimize_tables) && !empty($optimize_tables)) {
|
441 |
$this->optimize_tables();
|
442 |
}
|
443 |
-
|
444 |
//What to backup - db or full?
|
445 |
if (trim($what) == 'db') {
|
446 |
$db_backup = $this->backup_db_compress($task_name, $backup_file);
|
447 |
if (is_array($db_backup) && array_key_exists('error', $db_backup)) {
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
}
|
453 |
} elseif (trim($what) == 'full') {
|
454 |
if (!$exclude) {
|
455 |
-
|
456 |
}
|
457 |
if (!$include) {
|
458 |
-
|
459 |
}
|
460 |
-
|
461 |
if (is_array($content_backup) && array_key_exists('error', $content_backup)) {
|
462 |
-
|
463 |
-
|
464 |
'error' => $error_message
|
465 |
);
|
466 |
}
|
467 |
}
|
468 |
-
|
469 |
$end_compress = microtime(true);
|
470 |
-
|
471 |
//Update backup info
|
472 |
if ($task_name) {
|
473 |
//backup task (scheduled)
|
@@ -475,15 +478,15 @@ class MMB_Backup extends MMB_Core {
|
|
475 |
$paths = array();
|
476 |
$size = ceil(filesize($backup_file) / 1024);
|
477 |
$duration = round($end_compress - $begin_compress, 2);
|
478 |
-
|
479 |
if ($size > 1000) {
|
480 |
$paths['size'] = ceil($size / 1024) . "mb";
|
481 |
} else {
|
482 |
$paths['size'] = $size . 'kb';
|
483 |
}
|
484 |
-
|
485 |
$paths['duration'] = $duration . 's';
|
486 |
-
|
487 |
if ($task_name != 'Backup Now') {
|
488 |
$paths['server'] = array(
|
489 |
'file_path' => $backup_file,
|
@@ -495,56 +498,59 @@ class MMB_Backup extends MMB_Core {
|
|
495 |
'file_url' => $backup_url
|
496 |
);
|
497 |
}
|
498 |
-
|
499 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_ftp'])) {
|
500 |
$paths['ftp'] = basename($backup_url);
|
501 |
}
|
502 |
-
|
|
|
|
|
|
|
503 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
|
504 |
$paths['amazons3'] = basename($backup_url);
|
505 |
}
|
506 |
-
|
507 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
|
508 |
$paths['dropbox'] = basename($backup_url);
|
509 |
}
|
510 |
-
|
511 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_email'])) {
|
512 |
$paths['email'] = basename($backup_url);
|
513 |
}
|
514 |
-
|
515 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_google_drive'])) {
|
516 |
-
|
517 |
}
|
518 |
-
|
519 |
$temp = $backup_settings[$task_name]['task_results'];
|
520 |
$temp = array_values($temp);
|
521 |
$paths['time'] = time();
|
522 |
-
|
523 |
if ($task_name != 'Backup Now') {
|
524 |
$paths['status'] = $temp[count($temp) - 1]['status'];
|
525 |
$temp[count($temp) - 1] = $paths;
|
526 |
-
|
527 |
} else {
|
528 |
$temp[count($temp)] = $paths;
|
529 |
}
|
530 |
-
|
531 |
$backup_settings[$task_name]['task_results'] = $temp;
|
532 |
$this->update_tasks($backup_settings);
|
533 |
//update_option('mwp_backup_tasks', $backup_settings);
|
534 |
}
|
535 |
-
|
536 |
// If there are not remote destination, set up task status to finished
|
537 |
if (@count($backup_settings[$task_name]['task_args']['account_info']) == 0) {
|
538 |
-
|
539 |
}
|
540 |
-
|
541 |
return true;
|
542 |
}
|
543 |
-
|
544 |
/**
|
545 |
* Backup a full wordpress instance, including a database dump, which is placed in mwp_db dir in root folder.
|
546 |
* All backups are compressed by zip and placed in wp-content/managewp/backups folder.
|
547 |
-
*
|
548 |
* @param string $task_name the name of backup task, which backup is done
|
549 |
* @param string $backup_file relative path to file which backup is stored
|
550 |
* @param array[optional] $exclude the list of files and folders, which are excluded from backup (default: array())
|
@@ -552,9 +558,9 @@ class MMB_Backup extends MMB_Core {
|
|
552 |
* @return bool|array true if backup is successful, or an array with error message if is failed
|
553 |
*/
|
554 |
function backup_full($task_name, $backup_file, $exclude = array(), $include = array()) {
|
555 |
-
|
556 |
$db_result = $this->backup_db();
|
557 |
-
|
558 |
if ($db_result == false) {
|
559 |
return array(
|
560 |
'error' => 'Failed to backup database.'
|
@@ -564,112 +570,112 @@ class MMB_Backup extends MMB_Core {
|
|
564 |
'error' => $db_result['error']
|
565 |
);
|
566 |
}
|
567 |
-
|
568 |
$this->update_status($task_name, $this->statuses['db_dump'], true);
|
569 |
$this->update_status($task_name, $this->statuses['db_zip']);
|
570 |
-
|
571 |
@file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
|
572 |
$zip_db_result = $this->zip_backup_db($task_name, $backup_file);
|
573 |
-
|
574 |
if (!$zip_db_result) {
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
|
589 |
if($archive->error_code!=''){
|
590 |
$archive->error_code = 'pclZip error ('.$archive->error_code . '): .';
|
591 |
}
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
}
|
598 |
-
|
599 |
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
600 |
@unlink($db_result);
|
601 |
@rmdir(MWP_DB_DIR);
|
602 |
-
|
603 |
$remove = array(
|
604 |
-
|
605 |
-
|
606 |
);
|
607 |
$exclude = array_merge($exclude, $remove);
|
608 |
-
|
609 |
$this->update_status($task_name, $this->statuses['db_zip'], true);
|
610 |
$this->update_status($task_name, $this->statuses['files_zip']);
|
611 |
-
|
612 |
$zip_result = $this->zip_backup($task_name, $backup_file, $exclude, $include);
|
613 |
-
|
614 |
if (isset($zip_result['error'])) {
|
615 |
-
|
616 |
}
|
617 |
-
|
618 |
if (!$zip_result) {
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
}
|
642 |
-
|
643 |
//Reconnect
|
644 |
$this->wpdb_reconnect();
|
645 |
-
|
646 |
$this->update_status($task_name, $this->statuses['files_zip'], true);
|
647 |
return true;
|
648 |
}
|
649 |
-
|
650 |
/**
|
651 |
* Zipping database dump and index.php in folder mwp_db by system zip command, requires zip installed on OS.
|
652 |
-
*
|
653 |
* @param string $task_name the name of backup task
|
654 |
* @param string $backup_file absolute path to zip file
|
655 |
* @return bool is compress successful or not
|
656 |
*/
|
657 |
function zip_backup_db($task_name, $backup_file) {
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
}
|
672 |
-
|
673 |
/**
|
674 |
* Zipping database dump and index.php in folder mwp_db by ZipArchive class, requires php zip extension.
|
675 |
*
|
@@ -679,23 +685,23 @@ class MMB_Backup extends MMB_Core {
|
|
679 |
* @return bool is compress successful or not
|
680 |
*/
|
681 |
function zip_archive_backup_db($task_name, $db_result, $backup_file) {
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
}
|
698 |
-
|
699 |
/**
|
700 |
* Zipping database dump and index.php in folder mwp_db by PclZip library.
|
701 |
*
|
@@ -704,20 +710,20 @@ class MMB_Backup extends MMB_Core {
|
|
704 |
* @return bool is compress successful or not
|
705 |
*/
|
706 |
function pclzip_backup_db($task_name, $backup_file) {
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
}
|
720 |
-
|
721 |
/**
|
722 |
* Zipping whole site root folder and append to backup file with database dump
|
723 |
* by system zip command, requires zip installed on OS.
|
@@ -829,7 +835,7 @@ class MMB_Backup extends MMB_Core {
|
|
829 |
|
830 |
return true;
|
831 |
}
|
832 |
-
|
833 |
/**
|
834 |
* Zipping whole site root folder and append to backup file with database dump
|
835 |
* by ZipArchive class, requires php zip extension.
|
@@ -841,30 +847,30 @@ class MMB_Backup extends MMB_Core {
|
|
841 |
* @return array|bool true if successful or an array with error message if not
|
842 |
*/
|
843 |
function zip_archive_backup($task_name, $backup_file, $exclude, $include, $overwrite = false) {
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
}
|
867 |
-
|
868 |
/**
|
869 |
* Zipping whole site root folder and append to backup file with database dump
|
870 |
* by PclZip library.
|
@@ -876,90 +882,90 @@ class MMB_Backup extends MMB_Core {
|
|
876 |
* @return array|bool true if successful or an array with error message if not
|
877 |
*/
|
878 |
function pclzip_backup($task_name, $backup_file, $exclude, $include) {
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
}
|
929 |
-
|
930 |
/**
|
931 |
* Gets an array of relative paths of all files in site root recursively.
|
932 |
* By default, there are all files from root folder, all files from folders wp-admin, wp-content, wp-includes recursively.
|
933 |
* Parameter $include adds other folders from site root, and excludes any file or folder by relative path to site's root.
|
934 |
-
*
|
935 |
* @param array $exclude array of files of folders to exclude, relative to site's root
|
936 |
* @param array $include array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
|
937 |
* @return array array with all files in site root dir
|
938 |
*/
|
939 |
function get_backup_files($exclude, $include) {
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
}
|
962 |
-
|
963 |
/**
|
964 |
* Backup a database dump of WordPress site.
|
965 |
* All backups are compressed by zip and placed in wp-content/managewp/backups folder.
|
@@ -969,55 +975,55 @@ class MMB_Backup extends MMB_Core {
|
|
969 |
* @return bool|array true if backup is successful, or an array with error message if is failed
|
970 |
*/
|
971 |
function backup_db_compress($task_name, $backup_file) {
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
}
|
1020 |
-
|
1021 |
/**
|
1022 |
* Creates database dump and places it in mwp_db folder in site's root.
|
1023 |
* This function dispatches if OS mysql command does not work calls a php alternative.
|
@@ -1032,15 +1038,15 @@ class MMB_Backup extends MMB_Core {
|
|
1032 |
'error' => 'Error creating database backup folder (' . $db_folder . '). Make sure you have corrrect write permissions.'
|
1033 |
);
|
1034 |
}
|
1035 |
-
|
1036 |
$file = $db_folder . DB_NAME . '.sql';
|
1037 |
$result = $this->backup_db_dump($file); // try mysqldump always then fallback to php dump
|
1038 |
return $result;
|
1039 |
}
|
1040 |
-
|
1041 |
/**
|
1042 |
* Creates database dump by system mysql command.
|
1043 |
-
*
|
1044 |
* @param string $file absolute path to file in which dump should be placed
|
1045 |
* @return string|array path to dump file if successful, or an array with error message if is failed
|
1046 |
*/
|
@@ -1083,13 +1089,13 @@ class MMB_Backup extends MMB_Core {
|
|
1083 |
ob_start();
|
1084 |
$result = $this->mmb_exec($command);
|
1085 |
ob_get_clean();
|
1086 |
-
|
1087 |
if (!$result) { // Fallback to php
|
1088 |
-
|
1089 |
$result = $this->backup_db_php($file);
|
1090 |
return $result;
|
1091 |
}
|
1092 |
-
|
1093 |
if (filesize($file) == 0 || !is_file($file) || !$result) {
|
1094 |
@unlink($file);
|
1095 |
return false;
|
@@ -1097,14 +1103,14 @@ class MMB_Backup extends MMB_Core {
|
|
1097 |
return $file;
|
1098 |
}
|
1099 |
}
|
1100 |
-
|
1101 |
/**
|
1102 |
* Creates database dump by php functions.
|
1103 |
*
|
1104 |
* @param string $file absolute path to file in which dump should be placed
|
1105 |
* @return string|array path to dump file if successful, or an array with error message if is failed
|
1106 |
*/
|
1107 |
-
|
1108 |
global $wpdb;
|
1109 |
$tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
|
1110 |
foreach ($tables as $table) {
|
@@ -1115,13 +1121,13 @@ class MMB_Backup extends MMB_Core {
|
|
1115 |
$create_table = $wpdb->get_row("SHOW CREATE TABLE $table[0]", ARRAY_N);
|
1116 |
$dump_data = "\n\n" . $create_table[1] . ";\n\n";
|
1117 |
file_put_contents($file, $dump_data, FILE_APPEND);
|
1118 |
-
|
1119 |
$count = $wpdb->get_var("SELECT count(*) FROM $table[0]");
|
1120 |
if ($count > 100)
|
1121 |
$count = ceil($count / 100);
|
1122 |
-
else if ($count > 0)
|
1123 |
-
$count = 1;
|
1124 |
-
|
1125 |
for ($i = 0; $i < $count; $i++) {
|
1126 |
$low_limit = $i * 100;
|
1127 |
$qry = "SELECT * FROM $table[0] LIMIT $low_limit, 100";
|
@@ -1146,24 +1152,24 @@ class MMB_Backup extends MMB_Core {
|
|
1146 |
}
|
1147 |
$dump_data = "\n\n\n";
|
1148 |
file_put_contents($file, $dump_data, FILE_APPEND);
|
1149 |
-
|
1150 |
unset($rows);
|
1151 |
unset($dump_data);
|
1152 |
}
|
1153 |
-
|
1154 |
if (filesize($file) == 0 || !is_file($file)) {
|
1155 |
@unlink($file);
|
1156 |
return array(
|
1157 |
'error' => 'Database backup failed. Try to enable MySQL dump on your server.'
|
1158 |
);
|
1159 |
}
|
1160 |
-
|
1161 |
return $file;
|
1162 |
}
|
1163 |
-
|
1164 |
/**
|
1165 |
* Restores full WordPress site or database only form backup zip file.
|
1166 |
-
*
|
1167 |
* @param array array of arguments passed to backup restore
|
1168 |
* [task_name] -> name of backup task
|
1169 |
* [result_id] -> id of baskup task result, which should be restored
|
@@ -1177,12 +1183,12 @@ class MMB_Backup extends MMB_Core {
|
|
1177 |
}
|
1178 |
extract($args);
|
1179 |
if (isset($google_drive_token)) {
|
1180 |
-
|
1181 |
}
|
1182 |
$this->set_memory();
|
1183 |
-
|
1184 |
$unlink_file = true; //Delete file after restore
|
1185 |
-
|
1186 |
//Detect source
|
1187 |
if ($backup_url) {
|
1188 |
//This is for clone (overwrite)
|
@@ -1205,29 +1211,42 @@ class MMB_Backup extends MMB_Core {
|
|
1205 |
$args = $task['task_args']['account_info']['mwp_ftp'];
|
1206 |
$args['backup_file'] = $ftp_file;
|
1207 |
$backup_file = $this->get_ftp_backup($args);
|
1208 |
-
|
1209 |
if ($backup_file == false) {
|
1210 |
return array(
|
1211 |
'error' => 'Failed to download file from FTP.'
|
1212 |
);
|
1213 |
}
|
1214 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1215 |
$amazons3_file = $task['task_results'][$result_id]['amazons3'];
|
1216 |
$args = $task['task_args']['account_info']['mwp_amazon_s3'];
|
1217 |
$args['backup_file'] = $amazons3_file;
|
1218 |
$backup_file = $this->get_amazons3_backup($args);
|
1219 |
-
|
1220 |
if ($backup_file == false) {
|
1221 |
return array(
|
1222 |
'error' => 'Failed to download file from Amazon S3.'
|
1223 |
);
|
1224 |
}
|
1225 |
} elseif(isset($task['task_results'][$result_id]['dropbox'])){
|
1226 |
-
|
1227 |
$args = $task['task_args']['account_info']['mwp_dropbox'];
|
1228 |
$args['backup_file'] = $dropbox_file;
|
1229 |
$backup_file = $this->get_dropbox_backup($args);
|
1230 |
-
|
1231 |
if ($backup_file == false) {
|
1232 |
return array(
|
1233 |
'error' => 'Failed to download file from Dropbox.'
|
@@ -1238,23 +1257,23 @@ class MMB_Backup extends MMB_Core {
|
|
1238 |
$args = $task['task_args']['account_info']['mwp_google_drive'];
|
1239 |
$args['backup_file'] = $google_drive_file;
|
1240 |
$backup_file = $this->get_google_drive_backup($args);
|
1241 |
-
|
1242 |
if (is_array($backup_file) && isset($backup_file['error'])) {
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
} elseif ($backup_file == false) {
|
1247 |
return array(
|
1248 |
'error' => 'Failed to download file from Google Drive.'
|
1249 |
);
|
1250 |
}
|
1251 |
}
|
1252 |
-
|
1253 |
$what = $tasks[$task_name]['task_args']['what'];
|
1254 |
}
|
1255 |
-
|
1256 |
$this->wpdb_reconnect();
|
1257 |
-
|
1258 |
if ($backup_file && file_exists($backup_file)) {
|
1259 |
if ($overwrite) {
|
1260 |
//Keep old db credentials before overwrite
|
@@ -1267,13 +1286,13 @@ class MMB_Backup extends MMB_Core {
|
|
1267 |
If you are unsure on how to do this yourself, you can ask your hosting provider for help.'
|
1268 |
);
|
1269 |
}
|
1270 |
-
|
1271 |
$db_host = DB_HOST;
|
1272 |
$db_user = DB_USER;
|
1273 |
$db_password = DB_PASSWORD;
|
1274 |
$home = rtrim(get_option('home'), "/");
|
1275 |
$site_url = get_option('site_url');
|
1276 |
-
|
1277 |
$clone_options = array();
|
1278 |
if (trim($clone_from_url) || trim($mwp_clone)) {
|
1279 |
$clone_options['_worker_nossl_key'] = get_option('_worker_nossl_key');
|
@@ -1282,63 +1301,64 @@ class MMB_Backup extends MMB_Core {
|
|
1282 |
}
|
1283 |
$clone_options['upload_path'] = get_option('upload_path');
|
1284 |
$clone_options['upload_url_path'] = get_option('upload_url_path');
|
|
|
1285 |
|
1286 |
$clone_options['mwp_backup_tasks'] = maybe_serialize(get_option('mwp_backup_tasks'));
|
1287 |
$clone_options['mwp_notifications'] = maybe_serialize(get_option('mwp_notifications'));
|
1288 |
$clone_options['mwp_pageview_alerts'] = maybe_serialize(get_option('mwp_pageview_alerts'));
|
1289 |
} else {
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
$restore_options['mwp_backup_tasks'] = get_option('mwp_backup_tasks');
|
1295 |
}
|
1296 |
-
|
1297 |
chdir(ABSPATH);
|
1298 |
$unzip = $this->get_unzip();
|
1299 |
$command = "$unzip -o $backup_file";
|
1300 |
ob_start();
|
1301 |
$result = $this->mmb_exec($command);
|
1302 |
ob_get_clean();
|
1303 |
-
|
1304 |
if (!$result) { //fallback to pclzip
|
1305 |
-
|
1306 |
define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
|
1307 |
require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
|
1308 |
$archive = new PclZip($backup_file);
|
1309 |
$result = $archive->extract(PCLZIP_OPT_PATH, ABSPATH, PCLZIP_OPT_REPLACE_NEWER);
|
1310 |
}
|
1311 |
-
|
1312 |
if ($unlink_file) {
|
1313 |
@unlink($backup_file);
|
1314 |
}
|
1315 |
-
|
1316 |
if (!$result) {
|
1317 |
return array(
|
1318 |
'error' => 'Failed to unzip files. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
|
1319 |
);
|
1320 |
}
|
1321 |
-
|
1322 |
-
$db_result = $this->restore_db();
|
1323 |
-
|
1324 |
if (!$db_result) {
|
1325 |
return array(
|
1326 |
'error' => 'Error restoring database.'
|
1327 |
);
|
1328 |
} else if(is_array($db_result) && isset($db_result['error'])){
|
1329 |
-
|
1330 |
'error' => $db_result['error']
|
1331 |
);
|
1332 |
}
|
1333 |
-
|
1334 |
} else {
|
1335 |
return array(
|
1336 |
'error' => 'Error restoring. Cannot find backup file.'
|
1337 |
);
|
1338 |
}
|
1339 |
-
|
1340 |
$this->wpdb_reconnect();
|
1341 |
-
|
1342 |
//Replace options and content urls
|
1343 |
if ($overwrite) {
|
1344 |
//Get New Table prefix
|
@@ -1347,16 +1367,16 @@ class MMB_Backup extends MMB_Core {
|
|
1347 |
@unlink(ABSPATH . 'wp-config.php');
|
1348 |
//Replace table prefix
|
1349 |
$lines = file(ABSPATH . 'mwp-temp-wp-config.php');
|
1350 |
-
|
1351 |
foreach ($lines as $line) {
|
1352 |
if (strstr($line, '$table_prefix')) {
|
1353 |
$line = '$table_prefix = "' . $new_table_prefix . '";' . PHP_EOL;
|
1354 |
}
|
1355 |
file_put_contents(ABSPATH . 'wp-config.php', $line, FILE_APPEND);
|
1356 |
}
|
1357 |
-
|
1358 |
@unlink(ABSPATH . 'mwp-temp-wp-config.php');
|
1359 |
-
|
1360 |
//Replace options
|
1361 |
$query = "SELECT option_value FROM " . $new_table_prefix . "options WHERE option_name = 'home'";
|
1362 |
$old = $wpdb->get_var($query);
|
@@ -1370,7 +1390,7 @@ class MMB_Backup extends MMB_Core {
|
|
1370 |
$regexp2 = 'href="(.*)$old(.*)"';
|
1371 |
$query = "UPDATE " . $new_table_prefix . "posts SET post_content = REPLACE (post_content, %s,%s) WHERE post_content REGEXP %s OR post_content REGEXP %s";
|
1372 |
$wpdb->query($wpdb->prepare($query, array($old, $home, $regexp1, $regexp2)));
|
1373 |
-
|
1374 |
if (trim($new_password)) {
|
1375 |
$new_password = wp_hash_password($new_password);
|
1376 |
}
|
@@ -1386,7 +1406,7 @@ class MMB_Backup extends MMB_Core {
|
|
1386 |
$wpdb->query($wpdb->prepare($query, $new_password, $new_user));
|
1387 |
}
|
1388 |
}
|
1389 |
-
|
1390 |
if ($mwp_clone) {
|
1391 |
if ($admin_email) {
|
1392 |
//Clean Install
|
@@ -1398,11 +1418,11 @@ class MMB_Backup extends MMB_Core {
|
|
1398 |
$query = "UPDATE " . $new_table_prefix . "users SET user_email=%s, user_login = %s, user_pass = %s WHERE user_login = %s";
|
1399 |
$wpdb->query($wpdb->prepare($query, $admin_email, $new_user, $new_password, $temp_user->user_login));
|
1400 |
}
|
1401 |
-
|
1402 |
}
|
1403 |
}
|
1404 |
}
|
1405 |
-
|
1406 |
if (is_array($clone_options) && !empty($clone_options)) {
|
1407 |
foreach ($clone_options as $key => $option) {
|
1408 |
if (!empty($key)) {
|
@@ -1418,10 +1438,10 @@ class MMB_Backup extends MMB_Core {
|
|
1418 |
}
|
1419 |
}
|
1420 |
}
|
1421 |
-
|
1422 |
//Remove hit count
|
1423 |
$query = "DELETE FROM " . $new_table_prefix . "options WHERE option_name = 'user_hit_count'";
|
1424 |
-
|
1425 |
|
1426 |
//Restore previous backups
|
1427 |
|
@@ -1430,17 +1450,17 @@ class MMB_Backup extends MMB_Core {
|
|
1430 |
//Check for .htaccess permalinks update
|
1431 |
$this->replace_htaccess($home);
|
1432 |
} else {
|
1433 |
-
|
1434 |
if (is_array($restore_options) && !empty($restore_options)) {
|
1435 |
foreach ($restore_options as $key => $option) {
|
1436 |
$result = $wpdb->update( $wpdb->options, array( 'option_value' => maybe_serialize($option) ), array( 'option_name' => $key ) );
|
1437 |
}
|
1438 |
}
|
1439 |
}
|
1440 |
-
|
1441 |
return true;
|
1442 |
}
|
1443 |
-
|
1444 |
/**
|
1445 |
* This function dispathces database restoring between mysql system command and php functions.
|
1446 |
* If system command fails, it calls the php alternative.
|
@@ -1454,33 +1474,33 @@ class MMB_Backup extends MMB_Core {
|
|
1454 |
@chmod($file_path,0755);
|
1455 |
$file_name = glob($file_path . '/*.sql');
|
1456 |
$file_name = $file_name[0];
|
1457 |
-
|
1458 |
if(!$file_name){
|
1459 |
-
|
1460 |
}
|
1461 |
-
|
1462 |
$brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
|
1463 |
$command = $brace . $paths['mysql'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" --default-character-set="utf8" ' . DB_NAME . ' < ' . $brace . $file_name . $brace;
|
1464 |
-
|
1465 |
ob_start();
|
1466 |
$result = $this->mmb_exec($command);
|
1467 |
ob_get_clean();
|
1468 |
if (!$result) {
|
1469 |
-
|
1470 |
//try php
|
1471 |
$this->restore_db_php($file_name);
|
1472 |
}
|
1473 |
-
|
1474 |
@unlink($file_name);
|
1475 |
return true;
|
1476 |
}
|
1477 |
-
|
1478 |
/**
|
1479 |
* Restores database dump by php functions.
|
1480 |
-
*
|
1481 |
* @param string $file_name relative path to database dump, which should be restored
|
1482 |
* @return bool is successful or not
|
1483 |
-
*/
|
1484 |
function restore_db_php($file_name) {
|
1485 |
global $wpdb;
|
1486 |
$current_query = '';
|
@@ -1491,7 +1511,7 @@ class MMB_Backup extends MMB_Core {
|
|
1491 |
// Skip it if it's a comment
|
1492 |
if (substr($line, 0, 2) == '--' || $line == '')
|
1493 |
continue;
|
1494 |
-
|
1495 |
// Add this line to the current query
|
1496 |
$current_query .= $line;
|
1497 |
// If it has a semicolon at the end, it's the end of the query
|
@@ -1504,15 +1524,15 @@ class MMB_Backup extends MMB_Core {
|
|
1504 |
$current_query = '';
|
1505 |
}
|
1506 |
}
|
1507 |
-
|
1508 |
@unlink($file_name);
|
1509 |
return true;
|
1510 |
}
|
1511 |
-
|
1512 |
/**
|
1513 |
* Retruns table_prefix for this WordPress installation.
|
1514 |
* It is used by restore.
|
1515 |
-
*
|
1516 |
* @return string table prefix from wp-config.php file, (default: wp_)
|
1517 |
*/
|
1518 |
function get_table_prefix() {
|
@@ -1528,27 +1548,40 @@ class MMB_Backup extends MMB_Core {
|
|
1528 |
}
|
1529 |
return 'wp_'; //default
|
1530 |
}
|
1531 |
-
|
1532 |
/**
|
1533 |
* Change all tables to InnoDB engine, and executes mysql OPTIMIZE TABLE for each table.
|
1534 |
-
*
|
1535 |
* @return bool optimized successfully or not
|
1536 |
*/
|
1537 |
function optimize_tables() {
|
1538 |
-
$
|
1539 |
-
$
|
1540 |
-
|
1541 |
-
|
1542 |
-
|
1543 |
-
|
1544 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1545 |
}
|
1546 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1547 |
}
|
1548 |
-
|
1549 |
/**
|
1550 |
* Returns mysql and mysql dump command path on OS.
|
1551 |
-
*
|
1552 |
* @return array array with system mysql and mysqldump command, blank if does not exist
|
1553 |
*/
|
1554 |
function check_mysql_paths() {
|
@@ -1571,36 +1604,36 @@ class MMB_Backup extends MMB_Core {
|
|
1571 |
$paths['mysql'] = $this->mmb_exec('which mysql', true);
|
1572 |
if (empty($paths['mysql']))
|
1573 |
$paths['mysql'] = 'mysql'; // try anyway
|
1574 |
-
|
1575 |
$paths['mysqldump'] = $this->mmb_exec('which mysqldump', true);
|
1576 |
if (empty($paths['mysqldump']))
|
1577 |
$paths['mysqldump'] = 'mysqldump'; // try anyway
|
1578 |
}
|
1579 |
-
|
1580 |
return $paths;
|
1581 |
}
|
1582 |
-
|
1583 |
/**
|
1584 |
* Check if exec, system, passthru functions exist
|
1585 |
-
*
|
1586 |
* @return string|bool exec if exists, then system, then passthru, then false if no one exist
|
1587 |
*/
|
1588 |
function check_sys() {
|
1589 |
if ($this->mmb_function_exists('exec'))
|
1590 |
return 'exec';
|
1591 |
-
|
1592 |
if ($this->mmb_function_exists('system'))
|
1593 |
return 'system';
|
1594 |
-
|
1595 |
if ($this->mmb_function_exists('passhtru'))
|
1596 |
return 'passthru';
|
1597 |
-
|
1598 |
return false;
|
1599 |
}
|
1600 |
-
|
1601 |
/**
|
1602 |
* Executes an external system command.
|
1603 |
-
*
|
1604 |
* @param string $command external command to execute
|
1605 |
* @param bool[optional] $string return as a system output string (default: false)
|
1606 |
* @param bool[optional] $rawreturn return as a status of executed command
|
@@ -1609,50 +1642,50 @@ class MMB_Backup extends MMB_Core {
|
|
1609 |
function mmb_exec($command, $string = false, $rawreturn = false) {
|
1610 |
if ($command == '')
|
1611 |
return false;
|
1612 |
-
|
1613 |
if ($this->mmb_function_exists('exec')) {
|
1614 |
$log = @exec($command, $output, $return);
|
1615 |
-
|
1616 |
-
|
1617 |
-
|
1618 |
if ($string)
|
1619 |
return $log;
|
1620 |
if ($rawreturn)
|
1621 |
return $return;
|
1622 |
-
|
1623 |
return $return ? false : true;
|
1624 |
} elseif ($this->mmb_function_exists('system')) {
|
1625 |
$log = @system($command, $return);
|
1626 |
-
|
1627 |
-
|
1628 |
-
|
1629 |
if ($string)
|
1630 |
return $log;
|
1631 |
-
|
1632 |
if ($rawreturn)
|
1633 |
return $return;
|
1634 |
-
|
1635 |
return $return ? false : true;
|
1636 |
} elseif ($this->mmb_function_exists('passthru') && !$string) {
|
1637 |
$log = passthru($command, $return);
|
1638 |
$this->_log("Type: passthru");
|
1639 |
$this->_log("Command: ".$command);
|
1640 |
-
|
1641 |
if ($rawreturn)
|
1642 |
return $return;
|
1643 |
-
|
1644 |
return $return ? false : true;
|
1645 |
}
|
1646 |
-
|
1647 |
if ($rawreturn)
|
1648 |
-
|
1649 |
-
|
1650 |
return false;
|
1651 |
}
|
1652 |
-
|
1653 |
/**
|
1654 |
* Returns a path to system command for zip execution.
|
1655 |
-
*
|
1656 |
* @return string command for zip execution
|
1657 |
*/
|
1658 |
function get_zip() {
|
@@ -1661,7 +1694,7 @@ class MMB_Backup extends MMB_Core {
|
|
1661 |
$zip = "zip";
|
1662 |
return $zip;
|
1663 |
}
|
1664 |
-
|
1665 |
/**
|
1666 |
* Returns a path to system command for unzip execution.
|
1667 |
*
|
@@ -1673,14 +1706,14 @@ class MMB_Backup extends MMB_Core {
|
|
1673 |
$unzip = "unzip";
|
1674 |
return $unzip;
|
1675 |
}
|
1676 |
-
|
1677 |
/**
|
1678 |
* Returns all important information of worker's system status to master.
|
1679 |
-
*
|
1680 |
* @return mixed associative array with information of server OS, php version, is backup folder writable, execute function, zip and unzip command, execution time, memory limit and path to error log if exists
|
1681 |
*/
|
1682 |
function check_backup_compat() {
|
1683 |
-
|
1684 |
if (strpos($_SERVER['DOCUMENT_ROOT'], '/') === 0) {
|
1685 |
$reqs['Server OS']['status'] = 'Linux (or compatible)';
|
1686 |
$reqs['Server OS']['pass'] = true;
|
@@ -1696,7 +1729,7 @@ class MMB_Backup extends MMB_Core {
|
|
1696 |
$reqs['PHP Version']['pass'] = false;
|
1697 |
$pass = false;
|
1698 |
}
|
1699 |
-
|
1700 |
if (is_writable(WP_CONTENT_DIR)) {
|
1701 |
$reqs['Backup Folder']['status'] = "writable";
|
1702 |
$reqs['Backup Folder']['pass'] = true;
|
@@ -1704,10 +1737,10 @@ class MMB_Backup extends MMB_Core {
|
|
1704 |
$reqs['Backup Folder']['status'] = "not writable";
|
1705 |
$reqs['Backup Folder']['pass'] = false;
|
1706 |
}
|
1707 |
-
|
1708 |
$file_path = MWP_BACKUP_DIR;
|
1709 |
$reqs['Backup Folder']['status'] .= ' (' . $file_path . ')';
|
1710 |
-
|
1711 |
if ($func = $this->check_sys()) {
|
1712 |
$reqs['Execute Function']['status'] = $func;
|
1713 |
$reqs['Execute Function']['pass'] = true;
|
@@ -1716,14 +1749,14 @@ class MMB_Backup extends MMB_Core {
|
|
1716 |
$reqs['Execute Function']['info'] = "(will try PHP replacement)";
|
1717 |
$reqs['Execute Function']['pass'] = false;
|
1718 |
}
|
1719 |
-
|
1720 |
$reqs['Zip']['status'] = $this->get_zip();
|
1721 |
$reqs['Zip']['pass'] = true;
|
1722 |
$reqs['Unzip']['status'] = $this->get_unzip();
|
1723 |
$reqs['Unzip']['pass'] = true;
|
1724 |
-
|
1725 |
$paths = $this->check_mysql_paths();
|
1726 |
-
|
1727 |
if (!empty($paths['mysqldump'])) {
|
1728 |
$reqs['MySQL Dump']['status'] = $paths['mysqldump'];
|
1729 |
$reqs['MySQL Dump']['pass'] = true;
|
@@ -1732,44 +1765,44 @@ class MMB_Backup extends MMB_Core {
|
|
1732 |
$reqs['MySQL Dump']['info'] = "(will try PHP replacement)";
|
1733 |
$reqs['MySQL Dump']['pass'] = false;
|
1734 |
}
|
1735 |
-
|
1736 |
$exec_time = ini_get('max_execution_time');
|
1737 |
$reqs['Execution time']['status'] = $exec_time ? $exec_time . "s" : 'unknown';
|
1738 |
$reqs['Execution time']['pass'] = true;
|
1739 |
-
|
1740 |
$mem_limit = ini_get('memory_limit');
|
1741 |
$reqs['Memory limit']['status'] = $mem_limit ? $mem_limit : 'unknown';
|
1742 |
$reqs['Memory limit']['pass'] = true;
|
1743 |
-
|
1744 |
$changed = $this->set_memory();
|
1745 |
if($changed['execution_time']){
|
1746 |
-
|
1747 |
-
|
1748 |
}
|
1749 |
if($changed['memory_limit']){
|
1750 |
-
|
1751 |
-
|
1752 |
}
|
1753 |
-
|
1754 |
if(defined('MWP_SHOW_LOG') && MWP_SHOW_LOG == true){
|
1755 |
-
|
1756 |
-
|
1757 |
-
|
1758 |
-
|
1759 |
-
|
1760 |
-
|
1761 |
-
|
1762 |
-
|
1763 |
-
|
1764 |
-
}
|
1765 |
-
|
1766 |
return $reqs;
|
1767 |
}
|
1768 |
-
|
1769 |
/**
|
1770 |
* Uploads backup file from server to email.
|
1771 |
* A lot of email service have limitation to 10mb.
|
1772 |
-
*
|
1773 |
* @param array $args arguments passed to the function
|
1774 |
* [email] -> email address which backup should send to
|
1775 |
* [task_name] -> name of backup task
|
@@ -1778,7 +1811,7 @@ class MMB_Backup extends MMB_Core {
|
|
1778 |
*/
|
1779 |
function email_backup($args) {
|
1780 |
$email = $args['email'];
|
1781 |
-
|
1782 |
if (!is_email($email)) {
|
1783 |
return array(
|
1784 |
'error' => 'Your email (' . $email . ') is not correct'
|
@@ -1795,9 +1828,9 @@ class MMB_Backup extends MMB_Core {
|
|
1795 |
ob_start();
|
1796 |
$result = wp_mail($email, $subject, $subject, $headers, $attachments);
|
1797 |
ob_end_clean();
|
1798 |
-
|
1799 |
}
|
1800 |
-
|
1801 |
if (!$result) {
|
1802 |
return array(
|
1803 |
'error' => 'Email not sent. Maybe your backup is too big for email or email server is not available on your website.'
|
@@ -1805,7 +1838,72 @@ class MMB_Backup extends MMB_Core {
|
|
1805 |
}
|
1806 |
return true;
|
1807 |
}
|
1808 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1809 |
/**
|
1810 |
* Uploads backup file from server to remote ftp server.
|
1811 |
*
|
@@ -1823,16 +1921,16 @@ class MMB_Backup extends MMB_Core {
|
|
1823 |
*/
|
1824 |
function ftp_backup($args) {
|
1825 |
extract($args);
|
1826 |
-
|
1827 |
$port = $ftp_port ? $ftp_port : 21; //default port is 21
|
1828 |
if ($ftp_ssl) {
|
1829 |
if (function_exists('ftp_ssl_connect')) {
|
1830 |
$conn_id = ftp_ssl_connect($ftp_hostname,$port);
|
1831 |
if ($conn_id === false) {
|
1832 |
-
|
1833 |
-
|
1834 |
-
|
1835 |
-
|
1836 |
}
|
1837 |
} else {
|
1838 |
return array(
|
@@ -1863,34 +1961,34 @@ class MMB_Backup extends MMB_Core {
|
|
1863 |
'partial' => 1
|
1864 |
);
|
1865 |
}
|
1866 |
-
|
1867 |
if($ftp_passive){
|
1868 |
-
|
1869 |
-
|
1870 |
-
|
1871 |
@ftp_mkdir($conn_id, $ftp_remote_folder);
|
1872 |
if ($ftp_site_folder) {
|
1873 |
$ftp_remote_folder .= '/' . $this->site_name;
|
1874 |
}
|
1875 |
@ftp_mkdir($conn_id, $ftp_remote_folder);
|
1876 |
-
|
1877 |
$upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_BINARY);
|
1878 |
-
|
1879 |
if ($upload === false) { //Try ascii
|
1880 |
$upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_ASCII);
|
1881 |
}
|
1882 |
@ftp_close($conn_id);
|
1883 |
-
|
1884 |
if ($upload === false) {
|
1885 |
return array(
|
1886 |
'error' => 'Failed to upload file to FTP. Please check your specified path.',
|
1887 |
'partial' => 1
|
1888 |
);
|
1889 |
}
|
1890 |
-
|
1891 |
return true;
|
1892 |
}
|
1893 |
-
|
1894 |
/**
|
1895 |
* Deletes backup file from remote ftp server.
|
1896 |
*
|
@@ -1905,29 +2003,60 @@ class MMB_Backup extends MMB_Core {
|
|
1905 |
*/
|
1906 |
function remove_ftp_backup($args) {
|
1907 |
extract($args);
|
1908 |
-
|
1909 |
$port = $ftp_port ? $ftp_port : 21; //default port is 21
|
1910 |
if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
|
1911 |
$conn_id = ftp_ssl_connect($ftp_hostname,$port);
|
1912 |
} else if (function_exists('ftp_connect')) {
|
1913 |
$conn_id = ftp_connect($ftp_hostname,$port);
|
1914 |
}
|
1915 |
-
|
1916 |
if ($conn_id) {
|
1917 |
$login = @ftp_login($conn_id, $ftp_username, $ftp_password);
|
1918 |
if ($ftp_site_folder)
|
1919 |
$ftp_remote_folder .= '/' . $this->site_name;
|
1920 |
-
|
1921 |
if($ftp_passive){
|
1922 |
-
|
1923 |
-
|
1924 |
-
|
1925 |
$delete = ftp_delete($conn_id, $ftp_remote_folder . '/' . $backup_file);
|
1926 |
-
|
1927 |
ftp_close($conn_id);
|
1928 |
}
|
1929 |
}
|
1930 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1931 |
/**
|
1932 |
* Downloads backup file from server from remote ftp server to root folder on local server.
|
1933 |
*
|
@@ -1942,80 +2071,125 @@ class MMB_Backup extends MMB_Core {
|
|
1942 |
*/
|
1943 |
function get_ftp_backup($args) {
|
1944 |
extract($args);
|
1945 |
-
|
1946 |
$port = $ftp_port ? $ftp_port : 21; //default port is 21
|
1947 |
if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
|
1948 |
$conn_id = ftp_ssl_connect($ftp_hostname,$port);
|
1949 |
-
|
1950 |
} else if (function_exists('ftp_connect')) {
|
1951 |
$conn_id = ftp_connect($ftp_hostname,$port);
|
1952 |
if ($conn_id === false) {
|
1953 |
return false;
|
1954 |
}
|
1955 |
-
}
|
1956 |
$login = @ftp_login($conn_id, $ftp_username, $ftp_password);
|
1957 |
if ($login === false) {
|
1958 |
return false;
|
1959 |
}
|
1960 |
-
|
1961 |
if ($ftp_site_folder)
|
1962 |
$ftp_remote_folder .= '/' . $this->site_name;
|
1963 |
-
|
1964 |
if($ftp_passive){
|
1965 |
-
|
1966 |
-
|
1967 |
-
|
1968 |
$temp = ABSPATH . 'mwp_temp_backup.zip';
|
1969 |
$get = ftp_get($conn_id, $temp, $ftp_remote_folder . '/' . $backup_file, FTP_BINARY);
|
1970 |
if ($get === false) {
|
1971 |
return false;
|
1972 |
}
|
1973 |
-
|
1974 |
ftp_close($conn_id);
|
1975 |
-
|
1976 |
return $temp;
|
1977 |
}
|
1978 |
-
|
|
|
|
|
1979 |
/**
|
1980 |
-
*
|
1981 |
*
|
1982 |
* @param array $args arguments passed to the function
|
1983 |
-
* [
|
1984 |
-
* [
|
1985 |
-
* [
|
1986 |
-
* [
|
1987 |
-
* [
|
1988 |
-
* [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be upload to
|
1989 |
* [backup_file] -> absolute path of backup file on local server
|
1990 |
-
* @return
|
1991 |
*/
|
1992 |
-
function
|
1993 |
extract($args);
|
1994 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1995 |
global $mmb_plugin_dir;
|
1996 |
require_once $mmb_plugin_dir . '/lib/dropbox.php';
|
1997 |
-
|
1998 |
$dropbox = new Dropbox($consumer_key, $consumer_secret);
|
1999 |
$dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
|
2000 |
-
|
2001 |
if ($dropbox_site_folder == true)
|
2002 |
-
|
2003 |
else
|
2004 |
-
|
2005 |
-
|
2006 |
try {
|
2007 |
-
|
2008 |
} catch (Exception $e) {
|
2009 |
-
|
2010 |
-
|
2011 |
-
|
2012 |
-
|
2013 |
-
|
2014 |
}
|
2015 |
-
|
2016 |
return true;
|
2017 |
}
|
2018 |
-
|
2019 |
/**
|
2020 |
* Deletes backup file from Dropbox to root folder on local server.
|
2021 |
*
|
@@ -2030,121 +2204,121 @@ class MMB_Backup extends MMB_Core {
|
|
2030 |
* @return void
|
2031 |
*/
|
2032 |
function remove_dropbox_backup($args) {
|
2033 |
-
|
2034 |
-
|
2035 |
global $mmb_plugin_dir;
|
2036 |
require_once $mmb_plugin_dir . '/lib/dropbox.php';
|
2037 |
-
|
2038 |
$dropbox = new Dropbox($consumer_key, $consumer_secret);
|
2039 |
$dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
|
2040 |
-
|
2041 |
if ($dropbox_site_folder == true)
|
2042 |
-
|
2043 |
-
|
2044 |
-
|
2045 |
-
|
2046 |
-
|
2047 |
-
|
2048 |
-
|
2049 |
-
|
2050 |
-
|
2051 |
-
|
2052 |
-
|
2053 |
-
|
2054 |
-
|
2055 |
-
|
2056 |
-
|
2057 |
-
|
2058 |
-
|
2059 |
-
|
2060 |
-
|
2061 |
-
|
2062 |
-
|
2063 |
-
|
2064 |
-
|
2065 |
-
|
2066 |
-
|
2067 |
-
|
2068 |
-
|
2069 |
-
|
2070 |
-
|
2071 |
-
|
2072 |
-
|
2073 |
-
|
2074 |
-
|
2075 |
-
|
2076 |
-
|
2077 |
$dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
|
2078 |
-
|
2079 |
if ($dropbox_site_folder == true)
|
2080 |
-
|
2081 |
-
|
2082 |
-
|
2083 |
-
|
2084 |
-
|
2085 |
-
|
2086 |
-
|
2087 |
-
|
2088 |
-
|
2089 |
-
|
2090 |
-
|
2091 |
-
|
2092 |
-
|
2093 |
-
|
2094 |
-
|
2095 |
-
|
2096 |
-
|
2097 |
-
|
2098 |
-
|
2099 |
-
|
2100 |
-
|
2101 |
-
|
2102 |
-
|
2103 |
-
|
2104 |
-
|
2105 |
-
|
2106 |
-
|
2107 |
-
|
2108 |
-
|
2109 |
-
|
2110 |
-
|
2111 |
-
|
2112 |
-
|
2113 |
-
|
2114 |
-
|
2115 |
-
|
2116 |
function amazons3_backup($args) {
|
2117 |
if ($this->mmb_function_exists('curl_init')) {
|
2118 |
require_once('lib/s3.php');
|
2119 |
extract($args);
|
2120 |
-
|
2121 |
if ($as3_site_folder == true)
|
2122 |
$as3_directory .= '/' . $this->site_name;
|
2123 |
-
|
2124 |
$endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
|
2125 |
try{
|
2126 |
-
|
2127 |
-
|
2128 |
-
|
2129 |
-
|
2130 |
-
|
2131 |
-
|
2132 |
-
|
2133 |
-
|
2134 |
-
|
2135 |
-
|
2136 |
-
|
2137 |
-
|
2138 |
-
|
2139 |
-
|
2140 |
-
|
2141 |
-
|
2142 |
-
|
2143 |
-
|
2144 |
-
|
2145 |
-
|
2146 |
-
|
2147 |
-
|
2148 |
} else {
|
2149 |
return array(
|
2150 |
'error' => 'You cannot use Amazon S3 on your server. Please enable curl extension first.',
|
@@ -2169,21 +2343,21 @@ class MMB_Backup extends MMB_Core {
|
|
2169 |
* @return void
|
2170 |
*/
|
2171 |
function remove_amazons3_backup($args) {
|
2172 |
-
|
2173 |
-
|
2174 |
-
|
2175 |
-
|
2176 |
-
|
2177 |
-
|
2178 |
-
|
2179 |
-
|
2180 |
-
|
2181 |
-
|
2182 |
-
|
2183 |
-
|
2184 |
-
|
2185 |
}
|
2186 |
-
|
2187 |
/**
|
2188 |
* Downloads backup file from Amazon S3 to root folder on local server.
|
2189 |
*
|
@@ -2203,18 +2377,18 @@ class MMB_Backup extends MMB_Core {
|
|
2203 |
$endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
|
2204 |
$temp = '';
|
2205 |
try {
|
2206 |
-
|
2207 |
-
|
2208 |
-
|
2209 |
-
|
2210 |
-
|
2211 |
-
|
2212 |
-
|
2213 |
-
|
2214 |
-
|
2215 |
-
|
2216 |
}
|
2217 |
-
|
2218 |
/**
|
2219 |
* Uploads backup file from server to Google Drive.
|
2220 |
*
|
@@ -2226,128 +2400,128 @@ class MMB_Backup extends MMB_Core {
|
|
2226 |
* @return bool|array true is successful, array with error message if not
|
2227 |
*/
|
2228 |
function google_drive_backup($args) {
|
2229 |
-
|
2230 |
-
|
2231 |
-
|
2232 |
-
|
2233 |
-
|
2234 |
-
|
2235 |
-
|
2236 |
-
|
2237 |
-
|
2238 |
-
|
2239 |
-
|
2240 |
-
|
2241 |
-
|
2242 |
-
|
2243 |
-
|
2244 |
-
|
2245 |
-
|
2246 |
-
|
2247 |
-
|
2248 |
-
|
2249 |
-
|
2250 |
-
|
2251 |
-
|
2252 |
-
|
2253 |
-
|
2254 |
-
|
2255 |
-
|
2256 |
-
|
2257 |
-
|
2258 |
-
|
2259 |
-
|
2260 |
-
|
2261 |
-
|
2262 |
-
|
2263 |
-
|
2264 |
-
|
2265 |
-
|
2266 |
-
|
2267 |
-
|
2268 |
-
|
2269 |
-
|
2270 |
-
|
2271 |
-
|
2272 |
-
|
2273 |
-
|
2274 |
-
|
2275 |
-
|
2276 |
-
|
2277 |
-
|
2278 |
-
|
2279 |
-
|
2280 |
-
|
2281 |
-
|
2282 |
-
|
2283 |
-
|
2284 |
-
|
2285 |
-
|
2286 |
-
|
2287 |
-
|
2288 |
-
|
2289 |
-
|
2290 |
-
|
2291 |
-
|
2292 |
-
|
2293 |
-
|
2294 |
-
|
2295 |
-
|
2296 |
-
|
2297 |
-
|
2298 |
-
|
2299 |
-
|
2300 |
-
|
2301 |
-
|
2302 |
-
|
2303 |
-
|
2304 |
-
|
2305 |
-
|
2306 |
-
|
2307 |
-
|
2308 |
-
|
2309 |
-
|
2310 |
-
|
2311 |
-
|
2312 |
-
|
2313 |
-
|
2314 |
-
|
2315 |
-
|
2316 |
-
|
2317 |
-
|
2318 |
-
|
2319 |
-
|
2320 |
-
|
2321 |
-
|
2322 |
-
|
2323 |
-
|
2324 |
-
|
2325 |
-
|
2326 |
-
|
2327 |
-
|
2328 |
-
|
2329 |
-
|
2330 |
-
|
2331 |
-
|
2332 |
-
|
2333 |
-
|
2334 |
-
|
2335 |
-
|
2336 |
-
|
2337 |
-
|
2338 |
-
|
2339 |
-
|
2340 |
-
|
2341 |
-
|
2342 |
-
|
2343 |
-
|
2344 |
-
|
2345 |
-
|
2346 |
-
|
2347 |
-
|
2348 |
-
|
2349 |
}
|
2350 |
-
|
2351 |
/**
|
2352 |
* Deletes backup file from Google Drive.
|
2353 |
*
|
@@ -2359,108 +2533,108 @@ class MMB_Backup extends MMB_Core {
|
|
2359 |
* @return void
|
2360 |
*/
|
2361 |
function remove_google_drive_backup($args) {
|
2362 |
-
|
2363 |
-
|
2364 |
-
|
2365 |
-
|
2366 |
-
|
2367 |
-
|
2368 |
-
|
2369 |
-
|
2370 |
-
|
2371 |
-
|
2372 |
-
|
2373 |
-
|
2374 |
-
|
2375 |
-
|
2376 |
-
|
2377 |
-
|
2378 |
-
|
2379 |
-
|
2380 |
-
|
2381 |
-
|
2382 |
-
|
2383 |
-
|
2384 |
-
|
2385 |
-
|
2386 |
-
|
2387 |
-
|
2388 |
-
|
2389 |
-
|
2390 |
-
|
2391 |
-
|
2392 |
-
|
2393 |
-
|
2394 |
-
|
2395 |
-
|
2396 |
-
|
2397 |
-
|
2398 |
-
|
2399 |
-
|
2400 |
-
|
2401 |
-
|
2402 |
-
|
2403 |
-
|
2404 |
-
|
2405 |
-
|
2406 |
-
|
2407 |
-
|
2408 |
-
|
2409 |
-
|
2410 |
-
|
2411 |
-
|
2412 |
-
|
2413 |
-
|
2414 |
-
|
2415 |
-
|
2416 |
-
|
2417 |
-
|
2418 |
-
|
2419 |
-
|
2420 |
-
|
2421 |
-
|
2422 |
-
|
2423 |
-
|
2424 |
-
|
2425 |
-
|
2426 |
-
|
2427 |
-
|
2428 |
-
|
2429 |
-
|
2430 |
-
|
2431 |
-
|
2432 |
-
|
2433 |
-
|
2434 |
-
|
2435 |
-
|
2436 |
-
|
2437 |
-
|
2438 |
-
|
2439 |
-
|
2440 |
-
|
2441 |
-
|
2442 |
-
|
2443 |
-
|
2444 |
-
|
2445 |
-
|
2446 |
-
|
2447 |
-
|
2448 |
-
|
2449 |
-
|
2450 |
-
|
2451 |
-
|
2452 |
-
|
2453 |
-
|
2454 |
-
|
2455 |
-
|
2456 |
-
|
2457 |
-
|
2458 |
-
|
2459 |
-
|
2460 |
-
|
2461 |
-
|
2462 |
}
|
2463 |
-
|
2464 |
/**
|
2465 |
* Downloads backup file from Google Drive to root folder on local server.
|
2466 |
*
|
@@ -2472,142 +2646,142 @@ class MMB_Backup extends MMB_Core {
|
|
2472 |
* @return bool|array absolute path to downloaded file is successful, array with error message if not
|
2473 |
*/
|
2474 |
function get_google_drive_backup($args) {
|
2475 |
-
|
2476 |
-
|
2477 |
-
|
2478 |
-
|
2479 |
-
|
2480 |
-
|
2481 |
-
|
2482 |
-
|
2483 |
-
|
2484 |
-
|
2485 |
-
|
2486 |
-
|
2487 |
-
|
2488 |
-
|
2489 |
-
|
2490 |
-
|
2491 |
-
|
2492 |
-
|
2493 |
-
|
2494 |
-
|
2495 |
-
|
2496 |
-
|
2497 |
-
|
2498 |
-
|
2499 |
-
|
2500 |
-
|
2501 |
-
|
2502 |
-
|
2503 |
-
|
2504 |
-
|
2505 |
-
|
2506 |
-
|
2507 |
-
|
2508 |
-
|
2509 |
-
|
2510 |
-
|
2511 |
-
|
2512 |
-
|
2513 |
-
|
2514 |
-
|
2515 |
-
|
2516 |
-
|
2517 |
-
|
2518 |
-
|
2519 |
-
|
2520 |
-
|
2521 |
-
|
2522 |
-
|
2523 |
-
|
2524 |
-
|
2525 |
-
|
2526 |
-
|
2527 |
-
|
2528 |
-
|
2529 |
-
|
2530 |
-
|
2531 |
-
|
2532 |
-
|
2533 |
-
|
2534 |
-
|
2535 |
-
|
2536 |
-
|
2537 |
-
|
2538 |
-
|
2539 |
-
|
2540 |
-
|
2541 |
-
|
2542 |
-
|
2543 |
-
|
2544 |
-
|
2545 |
-
|
2546 |
-
|
2547 |
-
|
2548 |
-
|
2549 |
-
|
2550 |
-
|
2551 |
-
|
2552 |
-
|
2553 |
-
|
2554 |
-
|
2555 |
-
|
2556 |
-
|
2557 |
-
|
2558 |
-
|
2559 |
-
|
2560 |
-
|
2561 |
-
|
2562 |
-
|
2563 |
-
|
2564 |
-
|
2565 |
-
|
2566 |
-
|
2567 |
-
|
2568 |
-
|
2569 |
-
|
2570 |
-
|
2571 |
-
|
2572 |
-
|
2573 |
-
|
2574 |
-
|
2575 |
-
|
2576 |
-
|
2577 |
-
|
2578 |
-
|
2579 |
-
|
2580 |
-
|
2581 |
-
|
2582 |
-
|
2583 |
-
|
2584 |
-
|
2585 |
-
|
2586 |
-
|
2587 |
-
|
2588 |
-
|
2589 |
-
|
2590 |
-
|
2591 |
}
|
2592 |
-
|
2593 |
/**
|
2594 |
* Schedules the next execution of some backup task.
|
2595 |
-
*
|
2596 |
* @param string $type daily, weekly or monthly
|
2597 |
* @param string $schedule format: task_time (if daily), task_time|task_day (if weekly), task_time|task_date (if monthly)
|
2598 |
* @return bool|int timestamp if sucessful, false if not
|
2599 |
*/
|
2600 |
-
|
2601 |
$schedule = explode("|", $schedule);
|
2602 |
-
|
2603 |
-
|
2604 |
return false;
|
2605 |
switch ($type) {
|
2606 |
case 'daily':
|
2607 |
if (isset($schedule[1]) && $schedule[1]) {
|
2608 |
$delay_time = $schedule[1] * 60;
|
2609 |
}
|
2610 |
-
|
2611 |
$current_hour = date("H");
|
2612 |
$schedule_hour = $schedule[0];
|
2613 |
if ($current_hour >= $schedule_hour)
|
@@ -2615,7 +2789,7 @@ class MMB_Backup extends MMB_Core {
|
|
2615 |
else
|
2616 |
$time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
|
2617 |
break;
|
2618 |
-
|
2619 |
case 'weekly':
|
2620 |
if (isset($schedule[2]) && $schedule[2]) {
|
2621 |
$delay_time = $schedule[2] * 60;
|
@@ -2624,12 +2798,12 @@ class MMB_Backup extends MMB_Core {
|
|
2624 |
$schedule_weekday = $schedule[1];
|
2625 |
$current_hour = date("H");
|
2626 |
$schedule_hour = $schedule[0];
|
2627 |
-
|
2628 |
if ($current_weekday > $schedule_weekday)
|
2629 |
$weekday_offset = 7 - ($week_day - $task_schedule[1]);
|
2630 |
else
|
2631 |
$weekday_offset = $schedule_weekday - $current_weekday;
|
2632 |
-
|
2633 |
if (!$weekday_offset) { //today is scheduled weekday
|
2634 |
if ($current_hour >= $schedule_hour)
|
2635 |
$time = mktime($schedule_hour, 0, 0, date("m"), date("d") + 7, date("Y"));
|
@@ -2639,7 +2813,7 @@ class MMB_Backup extends MMB_Core {
|
|
2639 |
$time = mktime($schedule_hour, 0, 0, date("m"), date("d") + $weekday_offset, date("Y"));
|
2640 |
}
|
2641 |
break;
|
2642 |
-
|
2643 |
case 'monthly':
|
2644 |
if (isset($schedule[2]) && $schedule[2]) {
|
2645 |
$delay_time = $schedule[2] * 60;
|
@@ -2648,7 +2822,7 @@ class MMB_Backup extends MMB_Core {
|
|
2648 |
$schedule_monthday = $schedule[1];
|
2649 |
$current_hour = date("H");
|
2650 |
$schedule_hour = $schedule[0];
|
2651 |
-
|
2652 |
if ($current_monthday > $schedule_monthday) {
|
2653 |
$time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
|
2654 |
} else if ($current_monthday < $schedule_monthday) {
|
@@ -2660,23 +2834,23 @@ class MMB_Backup extends MMB_Core {
|
|
2660 |
$time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
|
2661 |
break;
|
2662 |
}
|
2663 |
-
|
2664 |
break;
|
2665 |
-
|
2666 |
default:
|
2667 |
break;
|
2668 |
}
|
2669 |
-
|
2670 |
if (isset($delay_time) && $delay_time) {
|
2671 |
$time += $delay_time;
|
2672 |
}
|
2673 |
-
|
2674 |
return $time;
|
2675 |
}
|
2676 |
-
|
2677 |
/**
|
2678 |
* Parse task arguments for info on master.
|
2679 |
-
*
|
2680 |
* @return mixed associative array with stats for every backup task or error if backup is manually deleted on server
|
2681 |
*/
|
2682 |
function get_backup_stats() {
|
@@ -2688,23 +2862,23 @@ class MMB_Backup extends MMB_Core {
|
|
2688 |
foreach ($info['task_results'] as $key => $result) {
|
2689 |
if (isset($result['server']) && !isset($result['error'])) {
|
2690 |
if (isset($result['server']['file_path']) && !$info['task_args']['del_host_file']) {
|
2691 |
-
|
2692 |
-
|
2693 |
-
|
2694 |
}
|
2695 |
}
|
2696 |
}
|
2697 |
}
|
2698 |
if (is_array($info['task_results']))
|
2699 |
-
|
2700 |
}
|
2701 |
}
|
2702 |
return $stats;
|
2703 |
}
|
2704 |
-
|
2705 |
/**
|
2706 |
* Returns all backup tasks with information when the next schedule will be.
|
2707 |
-
*
|
2708 |
* @return mixed associative array with timestamp with next schedule for every backup task
|
2709 |
*/
|
2710 |
function get_next_schedules() {
|
@@ -2717,18 +2891,18 @@ class MMB_Backup extends MMB_Core {
|
|
2717 |
}
|
2718 |
return $stats;
|
2719 |
}
|
2720 |
-
|
2721 |
/**
|
2722 |
* Deletes all old backups from local server.
|
2723 |
* It depends on configuration on master (Number of backups to keep).
|
2724 |
-
*
|
2725 |
* @param string $task_name name of backup task
|
2726 |
* @return bool|void true if there are backups for deletion, void if not
|
2727 |
*/
|
2728 |
function remove_old_backups($task_name) {
|
2729 |
//Check for previous failed backups first
|
2730 |
$this->cleanup();
|
2731 |
-
|
2732 |
//Remove by limit
|
2733 |
$backups = $this->tasks;
|
2734 |
if ($task_name == 'Backup Now') {
|
@@ -2736,7 +2910,7 @@ class MMB_Backup extends MMB_Core {
|
|
2736 |
} else {
|
2737 |
$num = 1;
|
2738 |
}
|
2739 |
-
|
2740 |
if ((count($backups[$task_name]['task_results']) - $num) >= $backups[$task_name]['task_args']['limit']) {
|
2741 |
//how many to remove ?
|
2742 |
$remove_num = (count($backups[$task_name]['task_results']) - $num - $backups[$task_name]['task_args']['limit']) + 1;
|
@@ -2745,7 +2919,7 @@ class MMB_Backup extends MMB_Core {
|
|
2745 |
if (isset($backups[$task_name]['task_results'][$i]['server'])) {
|
2746 |
@unlink($backups[$task_name]['task_results'][$i]['server']['file_path']);
|
2747 |
}
|
2748 |
-
|
2749 |
//Remove from ftp
|
2750 |
if (isset($backups[$task_name]['task_results'][$i]['ftp']) && isset($backups[$task_name]['task_args']['account_info']['mwp_ftp'])) {
|
2751 |
$ftp_file = $backups[$task_name]['task_results'][$i]['ftp'];
|
@@ -2753,47 +2927,53 @@ class MMB_Backup extends MMB_Core {
|
|
2753 |
$args['backup_file'] = $ftp_file;
|
2754 |
$this->remove_ftp_backup($args);
|
2755 |
}
|
2756 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2757 |
if (isset($backups[$task_name]['task_results'][$i]['amazons3']) && isset($backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
|
2758 |
$amazons3_file = $backups[$task_name]['task_results'][$i]['amazons3'];
|
2759 |
$args = $backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
|
2760 |
$args['backup_file'] = $amazons3_file;
|
2761 |
$this->remove_amazons3_backup($args);
|
2762 |
}
|
2763 |
-
|
2764 |
if (isset($backups[$task_name]['task_results'][$i]['dropbox']) && isset($backups[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
|
2765 |
//To do: dropbox remove
|
2766 |
$dropbox_file = $backups[$task_name]['task_results'][$i]['dropbox'];
|
2767 |
$args = $backups[$task_name]['task_args']['account_info']['mwp_dropbox'];
|
2768 |
$args['backup_file'] = $dropbox_file;
|
2769 |
-
|
2770 |
}
|
2771 |
-
|
2772 |
if (isset($backups[$task_name]['task_results'][$i]['google_drive']) && isset($backups[$task_name]['task_args']['account_info']['mwp_google_drive'])) {
|
2773 |
-
|
2774 |
-
|
2775 |
-
|
2776 |
-
|
2777 |
}
|
2778 |
-
|
2779 |
//Remove database backup info
|
2780 |
unset($backups[$task_name]['task_results'][$i]);
|
2781 |
} //end foreach
|
2782 |
-
|
2783 |
if (is_array($backups[$task_name]['task_results']))
|
2784 |
-
|
2785 |
else
|
2786 |
-
|
2787 |
-
|
2788 |
$this->update_tasks($backups);
|
2789 |
-
|
2790 |
return true;
|
2791 |
}
|
2792 |
}
|
2793 |
-
|
2794 |
/**
|
2795 |
* Deletes specified backup.
|
2796 |
-
*
|
2797 |
* @param array $args arguments passed to function
|
2798 |
* [task_name] -> name of backup task
|
2799 |
* [result_id] -> id of baskup task result, which should be restored
|
@@ -2805,18 +2985,18 @@ class MMB_Backup extends MMB_Core {
|
|
2805 |
return false;
|
2806 |
extract($args);
|
2807 |
if (isset($google_drive_token)) {
|
2808 |
-
|
2809 |
}
|
2810 |
-
|
2811 |
$tasks = $this->tasks;
|
2812 |
$task = $tasks[$task_name];
|
2813 |
$backups = $task['task_results'];
|
2814 |
$backup = $backups[$result_id];
|
2815 |
-
|
2816 |
if (isset($backup['server'])) {
|
2817 |
@unlink($backup['server']['file_path']);
|
2818 |
}
|
2819 |
-
|
2820 |
//Remove from ftp
|
2821 |
if (isset($backup['ftp'])) {
|
2822 |
$ftp_file = $backup['ftp'];
|
@@ -2824,44 +3004,50 @@ class MMB_Backup extends MMB_Core {
|
|
2824 |
$args['backup_file'] = $ftp_file;
|
2825 |
$this->remove_ftp_backup($args);
|
2826 |
}
|
2827 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2828 |
if (isset($backup['amazons3'])) {
|
2829 |
$amazons3_file = $backup['amazons3'];
|
2830 |
$args = $tasks[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
|
2831 |
$args['backup_file'] = $amazons3_file;
|
2832 |
$this->remove_amazons3_backup($args);
|
2833 |
}
|
2834 |
-
|
2835 |
if (isset($backup['dropbox'])) {
|
2836 |
-
|
2837 |
$args = $tasks[$task_name]['task_args']['account_info']['mwp_dropbox'];
|
2838 |
$args['backup_file'] = $dropbox_file;
|
2839 |
$this->remove_dropbox_backup($args);
|
2840 |
}
|
2841 |
-
|
2842 |
if (isset($backup['google_drive'])) {
|
2843 |
-
|
2844 |
-
|
2845 |
-
|
2846 |
-
|
2847 |
}
|
2848 |
-
|
2849 |
unset($backups[$result_id]);
|
2850 |
-
|
2851 |
if (count($backups)) {
|
2852 |
$tasks[$task_name]['task_results'] = $backups;
|
2853 |
} else {
|
2854 |
unset($tasks[$task_name]['task_results']);
|
2855 |
}
|
2856 |
-
|
2857 |
$this->update_tasks($tasks);
|
2858 |
//update_option('mwp_backup_tasks', $tasks);
|
2859 |
return true;
|
2860 |
}
|
2861 |
-
|
2862 |
/**
|
2863 |
* Deletes all unneeded files produced by backup process.
|
2864 |
-
*
|
2865 |
* @return array array of deleted files
|
2866 |
*/
|
2867 |
function cleanup() {
|
@@ -2870,7 +3056,7 @@ class MMB_Backup extends MMB_Core {
|
|
2870 |
$backup_folder_new = MWP_BACKUP_DIR . '/';
|
2871 |
$files = glob($backup_folder . "*");
|
2872 |
$new = glob($backup_folder_new . "*");
|
2873 |
-
|
2874 |
//Failed db files first
|
2875 |
$db_folder = MWP_DB_DIR . '/';
|
2876 |
$db_files = glob($db_folder . "*");
|
@@ -2878,28 +3064,28 @@ class MMB_Backup extends MMB_Core {
|
|
2878 |
foreach ($db_files as $file) {
|
2879 |
@unlink($file);
|
2880 |
}
|
2881 |
-
|
2882 |
@rmdir(MWP_DB_DIR);
|
2883 |
}
|
2884 |
-
|
2885 |
//clean_old folder?
|
2886 |
if ((isset($files[0]) && basename($files[0]) == 'index.php' && count($files) == 1) || (empty($files))) {
|
2887 |
if (!empty($files)) {
|
2888 |
-
|
2889 |
-
|
2890 |
-
|
2891 |
}
|
2892 |
@rmdir(WP_CONTENT_DIR . '/' . md5('mmb-worker') . '/mwp_backups');
|
2893 |
@rmdir(WP_CONTENT_DIR . '/' . md5('mmb-worker'));
|
2894 |
}
|
2895 |
-
|
2896 |
if (!empty($new)) {
|
2897 |
-
|
2898 |
-
|
2899 |
-
|
2900 |
}
|
2901 |
$deleted = array();
|
2902 |
-
|
2903 |
if (is_array($files) && count($files)) {
|
2904 |
$results = array();
|
2905 |
if (!empty($tasks)) {
|
@@ -2913,7 +3099,7 @@ class MMB_Backup extends MMB_Core {
|
|
2913 |
}
|
2914 |
}
|
2915 |
}
|
2916 |
-
|
2917 |
$num_deleted = 0;
|
2918 |
foreach ($files as $file) {
|
2919 |
if (!in_array($file, $results) && basename($file) != 'index.php') {
|
@@ -2923,98 +3109,110 @@ class MMB_Backup extends MMB_Core {
|
|
2923 |
}
|
2924 |
}
|
2925 |
}
|
2926 |
-
|
2927 |
return $deleted;
|
2928 |
}
|
2929 |
-
|
2930 |
/**
|
2931 |
* Uploads to remote destination in the second step, invoked from master.
|
2932 |
-
*
|
2933 |
* @param array $args arguments passed to function
|
2934 |
* [task_name] -> name of backup task
|
2935 |
* @return array|void void if success, array with error message if not
|
2936 |
*/
|
2937 |
function remote_backup_now($args) {
|
2938 |
-
|
2939 |
if (!empty($args))
|
2940 |
extract($args);
|
2941 |
-
|
2942 |
$tasks = $this->tasks;
|
2943 |
$task = $tasks[$task_name];
|
2944 |
-
|
2945 |
if (!empty($task)) {
|
2946 |
extract($task['task_args']);
|
2947 |
}
|
2948 |
-
|
2949 |
$results = $task['task_results'];
|
2950 |
-
|
2951 |
if (is_array($results) && count($results)) {
|
2952 |
$backup_file = $results[count($results) - 1]['server']['file_path'];
|
2953 |
}
|
2954 |
-
|
2955 |
if ($backup_file && file_exists($backup_file)) {
|
2956 |
//FTP, Amazon S3, Dropbox or Google Drive
|
2957 |
if (isset($account_info['mwp_ftp']) && !empty($account_info['mwp_ftp'])) {
|
2958 |
-
|
2959 |
-
|
2960 |
$return = $this->ftp_backup($account_info['mwp_ftp']);
|
2961 |
$this->wpdb_reconnect();
|
2962 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2963 |
if (!(is_array($return) && isset($return['error']))) {
|
2964 |
-
|
2965 |
-
|
2966 |
}
|
2967 |
}
|
2968 |
-
|
2969 |
if (isset($account_info['mwp_amazon_s3']) && !empty($account_info['mwp_amazon_s3'])) {
|
2970 |
-
|
2971 |
-
|
2972 |
$return = $this->amazons3_backup($account_info['mwp_amazon_s3']);
|
2973 |
$this->wpdb_reconnect();
|
2974 |
-
|
2975 |
if (!(is_array($return) && isset($return['error']))) {
|
2976 |
-
|
2977 |
-
|
2978 |
}
|
2979 |
}
|
2980 |
-
|
2981 |
if (isset($account_info['mwp_dropbox']) && !empty($account_info['mwp_dropbox'])) {
|
2982 |
-
|
2983 |
-
|
2984 |
$return = $this->dropbox_backup($account_info['mwp_dropbox']);
|
2985 |
$this->wpdb_reconnect();
|
2986 |
-
|
2987 |
if (!(is_array($return) && isset($return['error']))) {
|
2988 |
-
|
2989 |
-
|
2990 |
}
|
2991 |
}
|
2992 |
-
|
2993 |
if (isset($account_info['mwp_email']) && !empty($account_info['mwp_email'])) {
|
2994 |
-
|
2995 |
-
|
2996 |
-
|
2997 |
$return = $this->email_backup($account_info['mwp_email']);
|
2998 |
$this->wpdb_reconnect();
|
2999 |
-
|
3000 |
if (!(is_array($return) && isset($return['error']))) {
|
3001 |
-
|
3002 |
-
|
3003 |
}
|
3004 |
}
|
3005 |
-
|
3006 |
if (isset($account_info['mwp_google_drive']) && !empty($account_info['mwp_google_drive'])) {
|
3007 |
-
|
3008 |
-
|
3009 |
-
|
3010 |
-
|
3011 |
-
|
3012 |
-
|
3013 |
-
|
3014 |
-
|
3015 |
-
|
3016 |
-
}
|
3017 |
-
|
3018 |
$tasks = $this->tasks;
|
3019 |
@file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
|
3020 |
if ($return == true && $del_host_file) {
|
@@ -3022,19 +3220,18 @@ class MMB_Backup extends MMB_Core {
|
|
3022 |
unset($tasks[$task_name]['task_results'][count($tasks[$task_name]['task_results']) - 1]['server']);
|
3023 |
}
|
3024 |
$this->update_tasks($tasks);
|
3025 |
-
$return = $tasks[$task_name];
|
3026 |
} else {
|
3027 |
$return = array(
|
3028 |
'error' => 'Backup file not found on your server. Please try again.'
|
3029 |
);
|
3030 |
}
|
3031 |
-
|
3032 |
return $return;
|
3033 |
}
|
3034 |
-
|
3035 |
/**
|
3036 |
* Checks if scheduled backup tasks should be executed.
|
3037 |
-
*
|
3038 |
* @param array $args arguments passed to function
|
3039 |
* [task_name] -> name of backup task
|
3040 |
* [task_id] -> id of backup task
|
@@ -3042,55 +3239,55 @@ class MMB_Backup extends MMB_Core {
|
|
3042 |
* [worker_version] -> version of worker
|
3043 |
* [mwp_google_drive_refresh_token] -> should be Google Drive token be refreshed, true if it is remote destination of task
|
3044 |
* @param string $url url on master where worker validate task
|
3045 |
-
* @return string|array|boolean
|
3046 |
*/
|
3047 |
function validate_task($args, $url) {
|
3048 |
if (!class_exists('WP_Http')) {
|
3049 |
include_once(ABSPATH . WPINC . '/class-http.php');
|
3050 |
}
|
3051 |
-
|
3052 |
$worker_upto_3_9_22 = (MMB_WORKER_VERSION <= '3.9.22'); // worker version is less or equals to 3.9.22
|
3053 |
$params = array('timeout'=>100);
|
3054 |
$params['body'] = $args;
|
3055 |
$result = wp_remote_post($url, $params);
|
3056 |
-
|
3057 |
if ($worker_upto_3_9_22) {
|
3058 |
-
|
3059 |
-
|
3060 |
-
|
3061 |
unset($tasks[$args['task_name']]);
|
3062 |
-
|
3063 |
-
|
3064 |
-
|
3065 |
-
|
3066 |
-
|
3067 |
-
|
3068 |
-
|
3069 |
-
|
3070 |
} else {
|
3071 |
-
|
3072 |
-
|
3073 |
-
|
3074 |
-
|
3075 |
unset($tasks[$args['task_name']]);
|
3076 |
-
|
3077 |
-
|
3078 |
return 'deleted';
|
3079 |
-
|
3080 |
-
|
3081 |
-
|
3082 |
-
|
3083 |
-
|
3084 |
-
|
3085 |
-
}
|
3086 |
-
|
3087 |
-
|
3088 |
}
|
3089 |
-
|
3090 |
/**
|
3091 |
* Updates status of backup task.
|
3092 |
* Positive number if completed, negative if not.
|
3093 |
-
*
|
3094 |
* @param string $task_name name of backup task
|
3095 |
* @param int $status status which tasks should be updated to
|
3096 |
* (
|
@@ -3121,15 +3318,15 @@ class MMB_Backup extends MMB_Core {
|
|
3121 |
$status_index = count($tasks[$task_name]['task_results'][$index]['status']) - 1;
|
3122 |
$tasks[$task_name]['task_results'][$index]['status'][$status_index] = abs($tasks[$task_name]['task_results'][$index]['status'][$status_index]);
|
3123 |
}
|
3124 |
-
|
3125 |
$this->update_tasks($tasks);
|
3126 |
//update_option('mwp_backup_tasks',$tasks);
|
3127 |
}
|
3128 |
}
|
3129 |
-
|
3130 |
/**
|
3131 |
* Update $this->tasks attribute and save it to wp_options with key mwp_backup_tasks.
|
3132 |
-
*
|
3133 |
* @param mixed $tasks associative array with all tasks data
|
3134 |
* @return void
|
3135 |
*/
|
@@ -3137,106 +3334,106 @@ class MMB_Backup extends MMB_Core {
|
|
3137 |
$this->tasks = $tasks;
|
3138 |
update_option('mwp_backup_tasks', $tasks);
|
3139 |
}
|
3140 |
-
|
3141 |
/**
|
3142 |
* Reconnects to database to avoid timeout problem after ZIP files.
|
3143 |
-
*
|
3144 |
* @return void
|
3145 |
*/
|
3146 |
function wpdb_reconnect() {
|
3147 |
-
|
3148 |
-
|
3149 |
-
|
3150 |
-
|
3151 |
-
|
3152 |
-
|
3153 |
-
|
3154 |
}
|
3155 |
-
|
3156 |
/**
|
3157 |
* Replaces .htaccess file in process of restoring WordPress site.
|
3158 |
-
*
|
3159 |
* @param string $url url of current site
|
3160 |
* @return void
|
3161 |
*/
|
3162 |
-
|
3163 |
-
|
3164 |
-
|
3165 |
-
|
3166 |
-
|
3167 |
-
|
3168 |
-
|
3169 |
-
|
3170 |
-
|
3171 |
-
|
3172 |
-
|
3173 |
-
|
3174 |
-
|
3175 |
-
|
3176 |
-
|
3177 |
-
|
3178 |
-
|
3179 |
-
|
3180 |
-
|
3181 |
-
|
3182 |
-
|
3183 |
-
|
3184 |
-
|
3185 |
-
|
3186 |
-
|
3187 |
-
|
3188 |
-
|
3189 |
-
|
3190 |
-
|
3191 |
-
|
3192 |
-
|
3193 |
-
|
3194 |
-
|
3195 |
-
|
3196 |
-
|
3197 |
-
|
3198 |
-
|
3199 |
-
|
3200 |
-
|
3201 |
-
|
3202 |
-
|
3203 |
-
|
3204 |
-
|
3205 |
-
|
3206 |
-
|
3207 |
-
|
3208 |
-
|
3209 |
-
|
3210 |
-
|
3211 |
-
|
3212 |
-
|
3213 |
-
|
3214 |
-
|
3215 |
-
|
3216 |
-
|
3217 |
-
|
3218 |
-
|
3219 |
-
|
3220 |
-
|
3221 |
-
|
3222 |
-
|
3223 |
-
|
3224 |
-
|
3225 |
-
|
3226 |
-
|
3227 |
-
|
3228 |
-
|
3229 |
-
|
3230 |
-
|
3231 |
-
|
3232 |
-
|
3233 |
-
|
3234 |
-
|
3235 |
-
|
3236 |
-
|
3237 |
-
|
3238 |
-
|
3239 |
-
|
3240 |
}
|
3241 |
|
3242 |
/*if( function_exists('add_filter') ) {
|
@@ -3244,56 +3441,56 @@ class MMB_Backup extends MMB_Core {
|
|
3244 |
}*/
|
3245 |
|
3246 |
if(!function_exists('get_all_files_from_dir')) {
|
3247 |
-
|
3248 |
-
|
3249 |
-
|
3250 |
-
|
3251 |
-
|
3252 |
-
|
3253 |
-
|
3254 |
-
|
3255 |
-
|
3256 |
-
|
3257 |
-
|
3258 |
-
|
3259 |
-
|
3260 |
-
|
3261 |
-
|
3262 |
-
|
3263 |
-
|
3264 |
-
|
3265 |
-
|
3266 |
-
|
3267 |
}
|
3268 |
|
3269 |
if (!function_exists('get_all_files_from_dir_recursive')) {
|
3270 |
-
|
3271 |
-
|
3272 |
-
|
3273 |
-
|
3274 |
-
|
3275 |
-
|
3276 |
-
|
3277 |
-
|
3278 |
-
|
3279 |
-
|
3280 |
-
|
3281 |
-
|
3282 |
-
|
3283 |
-
|
3284 |
-
|
3285 |
-
|
3286 |
-
|
3287 |
-
|
3288 |
-
|
3289 |
-
|
3290 |
-
|
3291 |
-
|
3292 |
-
|
3293 |
-
|
3294 |
-
|
3295 |
-
|
3296 |
-
|
3297 |
}
|
3298 |
|
3299 |
?>
|
1 |
<?php
|
2 |
/*************************************************************
|
3 |
+
*
|
4 |
* backup.class.php
|
5 |
+
*
|
6 |
* Manage Backups
|
7 |
+
*
|
8 |
+
*
|
9 |
* Copyright (c) 2011 Prelovac Media
|
10 |
* www.prelovac.com
|
11 |
**************************************************************/
|
16 |
define('MWP_BACKUP_DIR', WP_CONTENT_DIR . '/managewp/backups');
|
17 |
define('MWP_DB_DIR', MWP_BACKUP_DIR . '/mwp_db');
|
18 |
|
19 |
+
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__).'/lib/PHPSecLib');
|
20 |
+
require_once ('Net/SFTP.php');
|
21 |
+
|
22 |
$zip_errors = array(
|
23 |
'No error',
|
24 |
'No error',
|
62 |
|
63 |
/**
|
64 |
* The main class for processing database and full backups on ManageWP worker.
|
65 |
+
*
|
66 |
* @copyright 2011-2012 Prelovac Media
|
67 |
* @version 3.9.24
|
68 |
* @package ManageWP
|
77 |
var $ftp;
|
78 |
var $dropbox;
|
79 |
var $google_drive;
|
80 |
+
|
81 |
/**
|
82 |
* Initializes site_name, statuses, and tasks attributes.
|
83 |
+
*
|
84 |
* @return void
|
85 |
*/
|
86 |
function __construct() {
|
87 |
parent::__construct();
|
88 |
+
$this->site_name = str_replace(array(
|
89 |
"_",
|
90 |
"/",
|
91 |
+
"~"
|
92 |
), array(
|
93 |
"",
|
94 |
"-",
|
95 |
+
"-"
|
96 |
), rtrim($this->remove_http(get_bloginfo('url')), "/"));
|
97 |
$this->statuses = array(
|
98 |
'db_dump' => 1,
|
102 |
'dropbox' => 5,
|
103 |
'ftp' => 6,
|
104 |
'email' => 7,
|
105 |
+
'google_drive' => 8,
|
106 |
'finished' => 100
|
107 |
);
|
108 |
$this->tasks = get_option('mwp_backup_tasks');
|
109 |
}
|
110 |
+
|
111 |
/**
|
112 |
* Tries to increase memory limit to 384M and execution time to 600s.
|
113 |
+
*
|
114 |
* @return array an array with two keys for execution time and memory limit (0 - if not changed, 1 - if succesfully)
|
115 |
*/
|
116 |
+
function set_memory() {
|
117 |
+
$changed = array('execution_time' => 0, 'memory_limit' => 0);
|
118 |
+
|
119 |
+
$memory_limit = trim(ini_get('memory_limit'));
|
120 |
+
$last = strtolower(substr($memory_limit, -1));
|
121 |
+
|
122 |
+
if($last == 'g')
|
123 |
+
$memory_limit = ((int) $memory_limit)*1024;
|
124 |
+
else if($last == 'm')
|
125 |
+
$memory_limit = (int) $memory_limit;
|
126 |
+
if($last == 'k')
|
127 |
+
$memory_limit = ((int) $memory_limit)/1024;
|
128 |
+
|
129 |
+
if ( $memory_limit < 384 ) {
|
130 |
+
@ini_set('memory_limit', '384M');
|
131 |
+
$changed['memory_limit'] = 1;
|
132 |
+
}
|
133 |
+
|
134 |
+
if ( (int) @ini_get('max_execution_time') < 600 ) {
|
135 |
+
@set_time_limit(600); //ten minutes
|
136 |
+
$changed['execution_time'] = 1;
|
137 |
+
}
|
138 |
+
|
139 |
+
return $changed;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Returns backup settings from local database for all tasks
|
144 |
+
*
|
145 |
+
* @return mixed|boolean
|
146 |
+
*/
|
147 |
function get_backup_settings() {
|
148 |
$backup_settings = get_option('mwp_backup_tasks');
|
149 |
+
|
150 |
if (!empty($backup_settings))
|
151 |
return $backup_settings;
|
152 |
else
|
153 |
return false;
|
154 |
}
|
155 |
+
|
156 |
/**
|
157 |
* Sets backup task defined from master, if task name is "Backup Now" this function fires processing backup.
|
158 |
+
*
|
159 |
* @param mixed $params parameters sent from master
|
160 |
* @return mixed|boolean $this->tasks variable if success, array with error message if error has ocurred, false if $params are empty
|
161 |
*/
|
162 |
function set_backup_task($params) {
|
163 |
//$params => [$task_name, $args, $error]
|
164 |
if (!empty($params)) {
|
165 |
+
|
166 |
+
//Make sure backup cron job is set
|
167 |
+
if (!wp_next_scheduled('mwp_backup_tasks')) {
|
168 |
+
wp_schedule_event( time(), 'tenminutes', 'mwp_backup_tasks' );
|
169 |
+
}
|
170 |
+
|
171 |
extract($params);
|
172 |
+
|
173 |
//$before = $this->get_backup_settings();
|
174 |
$before = $this->tasks;
|
175 |
if (!$before || empty($before))
|
176 |
$before = array();
|
177 |
+
|
178 |
if (isset($args['remove'])) {
|
179 |
unset($before[$task_name]);
|
180 |
$return = array(
|
184 |
if (isset($params['account_info']) && is_array($params['account_info'])) { //only if sends from master first time(secure data)
|
185 |
$args['account_info'] = $account_info;
|
186 |
}
|
187 |
+
|
188 |
$before[$task_name]['task_args'] = $args;
|
189 |
if (strlen($args['schedule']))
|
190 |
$before[$task_name]['task_args']['next'] = $this->schedule_next($args['type'], $args['schedule']);
|
191 |
+
|
192 |
$return = $before[$task_name];
|
193 |
}
|
194 |
+
|
195 |
//Update with error
|
196 |
if (isset($error)) {
|
197 |
if (is_array($error)) {
|
200 |
$before[$task_name]['task_results'][count($before[$task_name]['task_results'])]['error'] = $error;
|
201 |
}
|
202 |
}
|
203 |
+
|
204 |
if (isset($time) && $time) { //set next result time before backup
|
205 |
if (is_array($before[$task_name]['task_results'])) {
|
206 |
$before[$task_name]['task_results'] = array_values($before[$task_name]['task_results']);
|
207 |
}
|
208 |
$before[$task_name]['task_results'][count($before[$task_name]['task_results'])]['time'] = $time;
|
209 |
}
|
210 |
+
|
211 |
$this->update_tasks($before);
|
212 |
//update_option('mwp_backup_tasks', $before);
|
213 |
+
|
214 |
if ($task_name == 'Backup Now') {
|
215 |
+
$result = $this->backup($args, $task_name);
|
216 |
$backup_settings = $this->tasks;
|
217 |
+
|
218 |
if (is_array($result) && array_key_exists('error', $result)) {
|
219 |
+
$return = $result;
|
220 |
} else {
|
221 |
$return = $backup_settings[$task_name];
|
222 |
}
|
223 |
}
|
224 |
return $return;
|
225 |
}
|
226 |
+
|
227 |
return false;
|
228 |
}
|
229 |
+
|
230 |
/**
|
231 |
* Checks if scheduled task is ready for execution,
|
232 |
* if it is ready master sends google_drive_token, failed_emails, success_emails if are needed.
|
233 |
+
*
|
234 |
* @return void
|
235 |
*/
|
236 |
function check_backup_tasks() {
|
237 |
+
$this->check_cron_remove();
|
238 |
+
|
239 |
+
$failed_emails = array();
|
240 |
$settings = $this->tasks;
|
241 |
if (is_array($settings) && !empty($settings)) {
|
242 |
foreach ($settings as $task_name => $setting) {
|
248 |
'task_name' => $task_name,
|
249 |
'task_id' => $setting['task_args']['task_id'],
|
250 |
'site_key' => $setting['task_args']['site_key'],
|
251 |
+
'worker_version' => MMB_WORKER_VERSION
|
252 |
);
|
253 |
+
|
254 |
if (isset($setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'])) {
|
255 |
+
$check_data['mwp_google_drive_refresh_token'] = true;
|
256 |
}
|
257 |
+
|
258 |
$check = $this->validate_task($check_data, $setting['task_args']['url']);
|
259 |
if($check == 'paused' || $check == 'deleted'){
|
260 |
continue;
|
261 |
}
|
262 |
$worker_upto_3_9_22 = (MMB_WORKER_VERSION <= '3.9.22'); // worker version is less or equals to 3.9.22
|
263 |
+
|
264 |
// This is the patch done in worker 3.9.22 because old worked provided message in the following format:
|
265 |
// token - not found or token - {...json...}
|
266 |
// The new message is a serialized string with google_drive_token or message.
|
267 |
if ($worker_upto_3_9_22) {
|
268 |
+
$potential_token = substr($check, 8);
|
269 |
+
if (substr($check, 0, 8) == 'token - ' && $potential_token != 'not found') {
|
270 |
+
$this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
|
271 |
+
$settings[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
|
272 |
+
$setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
|
273 |
+
}
|
274 |
} else {
|
275 |
+
$potential_token = isset($check['google_drive_token']) ? $check['google_drive_token'] : false;
|
276 |
+
if ($potential_token) {
|
277 |
+
$this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
|
278 |
+
$settings[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
|
279 |
+
$setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
|
280 |
+
}
|
281 |
}
|
282 |
+
|
283 |
}
|
284 |
+
|
285 |
$update = array(
|
286 |
'task_name' => $task_name,
|
287 |
+
'args' => $settings[$task_name]['task_args']
|
288 |
);
|
289 |
+
|
290 |
if ($check != 'paused') {
|
291 |
+
$update['time'] = time();
|
292 |
}
|
293 |
+
|
294 |
//Update task with next schedule
|
295 |
$this->set_backup_task($update);
|
296 |
+
|
297 |
+
$result = $this->backup($setting['task_args'], $task_name);
|
298 |
$error = '';
|
299 |
+
|
300 |
if (is_array($result) && array_key_exists('error', $result)) {
|
301 |
+
$error = $result;
|
302 |
+
$this->set_backup_task(array(
|
303 |
+
'task_name' => $task_name,
|
304 |
+
'args' => $settings[$task_name]['task_args'],
|
305 |
+
'error' => $error
|
306 |
+
));
|
307 |
} else {
|
308 |
+
if (@count($setting['task_args']['account_info'])) {
|
309 |
+
// Old way through sheduling.
|
310 |
+
// wp_schedule_single_event(time(), 'mmb_scheduled_remote_upload', array('args' => array('task_name' => $task_name)));
|
311 |
+
$nonce = substr(wp_hash(wp_nonce_tick() . 'mmb-backup-nonce' . 0, 'nonce'), -12, 10);
|
312 |
+
$cron_url = site_url('index.php');
|
313 |
+
$backup_file = $this->tasks[$task_name]['task_results'][count($this->tasks[$task_name]['task_results']) - 1]['server']['file_url'];
|
314 |
+
$del_host_file = $this->tasks[$task_name]['task_args']['del_host_file'];
|
315 |
+
$public_key = get_option('_worker_public_key');
|
316 |
+
$args = array(
|
317 |
+
'body' => array(
|
318 |
+
'backup_cron_action' => 'mmb_remote_upload',
|
319 |
+
'args' => json_encode(array('task_name' => $task_name, 'backup_file' => $backup_file, 'del_host_file' => $del_host_file)),
|
320 |
+
'mmb_backup_nonce' => $nonce,
|
321 |
+
'public_key' => $public_key,
|
322 |
+
),
|
323 |
+
'timeout' => 0.01,
|
324 |
+
'blocking' => false,
|
325 |
+
'sslverify' => apply_filters('https_local_ssl_verify', true)
|
326 |
+
);
|
327 |
+
wp_remote_post($cron_url, $args);
|
328 |
+
}
|
329 |
}
|
330 |
+
|
331 |
break; //Only one backup per cron
|
332 |
}
|
333 |
}
|
334 |
}
|
335 |
+
|
336 |
}
|
337 |
+
|
338 |
/**
|
339 |
* Runs backup task invoked from ManageWP master.
|
340 |
+
*
|
341 |
* @param string $task_name name of backup task
|
342 |
* @param string|bool[optional] $google_drive_token false if backup destination is not Google Drive, json of Google Drive token if it is remote destination (default: false)
|
343 |
* @return mixed array with backup statistics if successful, array with error message if not
|
344 |
*/
|
345 |
function task_now($task_name, $google_drive_token = false) {
|
346 |
+
if ($google_drive_token) {
|
347 |
+
$this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
|
348 |
+
}
|
349 |
+
|
350 |
+
$settings = $this->tasks;
|
351 |
+
if(!array_key_exists($task_name,$settings)){
|
352 |
+
return array('error' => $task_name." does not exist.");
|
353 |
+
} else {
|
354 |
+
$setting = $settings[$task_name];
|
355 |
+
}
|
356 |
+
|
357 |
+
$this->set_backup_task(array(
|
358 |
+
'task_name' => $task_name,
|
359 |
+
'args' => $settings[$task_name]['task_args'],
|
360 |
+
'time' => time()
|
361 |
+
));
|
362 |
+
|
363 |
+
//Run backup
|
364 |
+
$result = $this->backup($setting['task_args'], $task_name);
|
365 |
+
|
366 |
+
//Check for error
|
367 |
+
if (is_array($result) && array_key_exists('error', $result)) {
|
368 |
+
$this->set_backup_task(array(
|
369 |
+
'task_name' => $task_name,
|
370 |
+
'args' => $settings[$task_name]['task_args'],
|
371 |
+
'error' => $result
|
372 |
+
));
|
373 |
+
return $result;
|
374 |
+
} else {
|
375 |
+
return $this->get_backup_stats();
|
376 |
+
}
|
377 |
}
|
378 |
+
|
379 |
/**
|
380 |
* Backup a full wordpress instance, including a database dump, which is placed in mwp_db dir in root folder.
|
381 |
* All backups are compressed by zip and placed in wp-content/managewp/backups folder.
|
382 |
*
|
383 |
+
* @param string $args arguments passed from master
|
384 |
* [type] -> db, full
|
385 |
* [what] -> daily, weekly, monthly
|
386 |
* [account_info] -> remote destinations ftp, amazons3, dropbox, google_drive, email with their parameters
|
392 |
function backup($args, $task_name = false) {
|
393 |
if (!$args || empty($args))
|
394 |
return false;
|
395 |
+
|
396 |
extract($args); //extract settings
|
397 |
+
|
398 |
+
if (!empty($account_info)) {
|
399 |
+
$found = false;
|
400 |
+
$destinations = array('mwp_ftp','mwp_sftp', 'mwp_amazon_s3', 'mwp_dropbox', 'mwp_google_drive', 'mwp_email');
|
401 |
+
foreach($destinations as $dest) {
|
402 |
+
$found = $found || (isset($account_info[$dest]));
|
403 |
+
}
|
404 |
+
if (!$found) {
|
405 |
+
$error_message = 'Remote destination is not supported, please update your client plugin.';
|
406 |
+
return array(
|
407 |
+
'error' => $error_message
|
408 |
+
);
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
//Try increase memory limit and execution time
|
413 |
+
$this->set_memory();
|
414 |
+
|
415 |
//Remove old backup(s)
|
416 |
$removed = $this->remove_old_backups($task_name);
|
417 |
if (is_array($removed) && isset($removed['error'])) {
|
418 |
+
$error_message = $removed['error'];
|
419 |
+
return $removed;
|
420 |
}
|
421 |
+
|
422 |
$new_file_path = MWP_BACKUP_DIR;
|
423 |
+
|
424 |
if (!file_exists($new_file_path)) {
|
425 |
if (!mkdir($new_file_path, 0755, true))
|
426 |
+
$error_message = 'Permission denied, make sure you have write permission to wp-content folder.';
|
427 |
return array(
|
428 |
+
'error' => $error_message
|
429 |
);
|
430 |
}
|
431 |
+
|
432 |
@file_put_contents($new_file_path . '/index.php', ''); //safe
|
433 |
+
|
434 |
//Prepare .zip file name
|
435 |
$hash = md5(time());
|
436 |
$label = $type ? $type : 'manual';
|
437 |
$backup_file = $new_file_path . '/' . $this->site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') . '_' . $hash . '.zip';
|
438 |
$backup_url = WP_CONTENT_URL . '/managewp/backups/' . $this->site_name . '_' . $label . '_' . $what . '_' . date('Y-m-d') . '_' . $hash . '.zip';
|
439 |
+
|
440 |
$begin_compress = microtime(true);
|
441 |
+
|
442 |
//Optimize tables?
|
443 |
if (isset($optimize_tables) && !empty($optimize_tables)) {
|
444 |
$this->optimize_tables();
|
445 |
}
|
446 |
+
|
447 |
//What to backup - db or full?
|
448 |
if (trim($what) == 'db') {
|
449 |
$db_backup = $this->backup_db_compress($task_name, $backup_file);
|
450 |
if (is_array($db_backup) && array_key_exists('error', $db_backup)) {
|
451 |
+
$error_message = $db_backup['error'];
|
452 |
+
return array(
|
453 |
+
'error' => $error_message
|
454 |
+
);
|
455 |
}
|
456 |
} elseif (trim($what) == 'full') {
|
457 |
if (!$exclude) {
|
458 |
+
$exclude = array();
|
459 |
}
|
460 |
if (!$include) {
|
461 |
+
$include = array();
|
462 |
}
|
463 |
+
$content_backup = $this->backup_full($task_name, $backup_file, $exclude, $include);
|
464 |
if (is_array($content_backup) && array_key_exists('error', $content_backup)) {
|
465 |
+
$error_message = $content_backup['error'];
|
466 |
+
return array(
|
467 |
'error' => $error_message
|
468 |
);
|
469 |
}
|
470 |
}
|
471 |
+
|
472 |
$end_compress = microtime(true);
|
473 |
+
|
474 |
//Update backup info
|
475 |
if ($task_name) {
|
476 |
//backup task (scheduled)
|
478 |
$paths = array();
|
479 |
$size = ceil(filesize($backup_file) / 1024);
|
480 |
$duration = round($end_compress - $begin_compress, 2);
|
481 |
+
|
482 |
if ($size > 1000) {
|
483 |
$paths['size'] = ceil($size / 1024) . "mb";
|
484 |
} else {
|
485 |
$paths['size'] = $size . 'kb';
|
486 |
}
|
487 |
+
|
488 |
$paths['duration'] = $duration . 's';
|
489 |
+
|
490 |
if ($task_name != 'Backup Now') {
|
491 |
$paths['server'] = array(
|
492 |
'file_path' => $backup_file,
|
498 |
'file_url' => $backup_url
|
499 |
);
|
500 |
}
|
501 |
+
|
502 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_ftp'])) {
|
503 |
$paths['ftp'] = basename($backup_url);
|
504 |
}
|
505 |
+
|
506 |
+
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_sftp'])) {
|
507 |
+
$paths['sftp'] = basename($backup_url);
|
508 |
+
}
|
509 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
|
510 |
$paths['amazons3'] = basename($backup_url);
|
511 |
}
|
512 |
+
|
513 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
|
514 |
$paths['dropbox'] = basename($backup_url);
|
515 |
}
|
516 |
+
|
517 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_email'])) {
|
518 |
$paths['email'] = basename($backup_url);
|
519 |
}
|
520 |
+
|
521 |
if (isset($backup_settings[$task_name]['task_args']['account_info']['mwp_google_drive'])) {
|
522 |
+
$paths['google_drive'] = basename($backup_url);
|
523 |
}
|
524 |
+
|
525 |
$temp = $backup_settings[$task_name]['task_results'];
|
526 |
$temp = array_values($temp);
|
527 |
$paths['time'] = time();
|
528 |
+
|
529 |
if ($task_name != 'Backup Now') {
|
530 |
$paths['status'] = $temp[count($temp) - 1]['status'];
|
531 |
$temp[count($temp) - 1] = $paths;
|
532 |
+
|
533 |
} else {
|
534 |
$temp[count($temp)] = $paths;
|
535 |
}
|
536 |
+
|
537 |
$backup_settings[$task_name]['task_results'] = $temp;
|
538 |
$this->update_tasks($backup_settings);
|
539 |
//update_option('mwp_backup_tasks', $backup_settings);
|
540 |
}
|
541 |
+
|
542 |
// If there are not remote destination, set up task status to finished
|
543 |
if (@count($backup_settings[$task_name]['task_args']['account_info']) == 0) {
|
544 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
545 |
}
|
546 |
+
|
547 |
return true;
|
548 |
}
|
549 |
+
|
550 |
/**
|
551 |
* Backup a full wordpress instance, including a database dump, which is placed in mwp_db dir in root folder.
|
552 |
* All backups are compressed by zip and placed in wp-content/managewp/backups folder.
|
553 |
+
*
|
554 |
* @param string $task_name the name of backup task, which backup is done
|
555 |
* @param string $backup_file relative path to file which backup is stored
|
556 |
* @param array[optional] $exclude the list of files and folders, which are excluded from backup (default: array())
|
558 |
* @return bool|array true if backup is successful, or an array with error message if is failed
|
559 |
*/
|
560 |
function backup_full($task_name, $backup_file, $exclude = array(), $include = array()) {
|
561 |
+
$this->update_status($task_name, $this->statuses['db_dump']);
|
562 |
$db_result = $this->backup_db();
|
563 |
+
|
564 |
if ($db_result == false) {
|
565 |
return array(
|
566 |
'error' => 'Failed to backup database.'
|
570 |
'error' => $db_result['error']
|
571 |
);
|
572 |
}
|
573 |
+
|
574 |
$this->update_status($task_name, $this->statuses['db_dump'], true);
|
575 |
$this->update_status($task_name, $this->statuses['db_zip']);
|
576 |
+
|
577 |
@file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
|
578 |
$zip_db_result = $this->zip_backup_db($task_name, $backup_file);
|
579 |
+
|
580 |
if (!$zip_db_result) {
|
581 |
+
$zip_archive_db_result = false;
|
582 |
+
if (class_exists("ZipArchive")) {
|
583 |
+
$this->_log("DB zip, fallback to ZipArchive");
|
584 |
+
$zip_archive_db_result = $this->zip_archive_backup_db($task_name, $db_result, $backup_file);
|
585 |
+
}
|
586 |
+
|
587 |
+
if (!$zip_archive_db_result) {
|
588 |
+
$this->_log("DB zip, fallback to PclZip");
|
589 |
+
$pclzip_db_result = $this->pclzip_backup_db($task_name, $backup_file);
|
590 |
+
if (!$pclzip_db_result) {
|
591 |
+
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
592 |
+
@unlink($db_result);
|
593 |
+
@rmdir(MWP_DB_DIR);
|
594 |
|
595 |
if($archive->error_code!=''){
|
596 |
$archive->error_code = 'pclZip error ('.$archive->error_code . '): .';
|
597 |
}
|
598 |
+
return array(
|
599 |
+
'error' => 'Failed to zip database. ' . $archive->error_code . $archive->error_string
|
600 |
+
);
|
601 |
+
}
|
602 |
+
}
|
603 |
}
|
604 |
+
|
605 |
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
606 |
@unlink($db_result);
|
607 |
@rmdir(MWP_DB_DIR);
|
608 |
+
|
609 |
$remove = array(
|
610 |
+
trim(basename(WP_CONTENT_DIR)) . "/managewp/backups",
|
611 |
+
trim(basename(WP_CONTENT_DIR)) . "/" . md5('mmb-worker') . "/mwp_backups"
|
612 |
);
|
613 |
$exclude = array_merge($exclude, $remove);
|
614 |
+
|
615 |
$this->update_status($task_name, $this->statuses['db_zip'], true);
|
616 |
$this->update_status($task_name, $this->statuses['files_zip']);
|
617 |
+
|
618 |
$zip_result = $this->zip_backup($task_name, $backup_file, $exclude, $include);
|
619 |
+
|
620 |
if (isset($zip_result['error'])) {
|
621 |
+
return $zip_result;
|
622 |
}
|
623 |
+
|
624 |
if (!$zip_result) {
|
625 |
+
$zip_archive_result = false;
|
626 |
+
if (class_exists("ZipArchive")) {
|
627 |
+
$this->_log("Files zip fallback to ZipArchive");
|
628 |
+
$zip_archive_result = $this->zip_archive_backup($task_name, $backup_file, $exclude, $include);
|
629 |
+
}
|
630 |
+
|
631 |
+
if (!$zip_archive_result) {
|
632 |
+
$this->_log("Files zip fallback to PclZip");
|
633 |
+
$pclzip_result = $this->pclzip_backup($task_name, $backup_file, $exclude, $include);
|
634 |
+
if (!$pclzip_result) {
|
635 |
+
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
636 |
+
@unlink($db_result);
|
637 |
+
@rmdir(MWP_DB_DIR);
|
638 |
+
|
639 |
+
if (!$pclzip_result) {
|
640 |
+
@unlink($backup_file);
|
641 |
+
return array(
|
642 |
+
'error' => 'Failed to zip files. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
|
643 |
+
);
|
644 |
+
}
|
645 |
+
}
|
646 |
+
}
|
647 |
+
}
|
648 |
+
|
649 |
//Reconnect
|
650 |
$this->wpdb_reconnect();
|
651 |
+
|
652 |
$this->update_status($task_name, $this->statuses['files_zip'], true);
|
653 |
return true;
|
654 |
}
|
655 |
+
|
656 |
/**
|
657 |
* Zipping database dump and index.php in folder mwp_db by system zip command, requires zip installed on OS.
|
658 |
+
*
|
659 |
* @param string $task_name the name of backup task
|
660 |
* @param string $backup_file absolute path to zip file
|
661 |
* @return bool is compress successful or not
|
662 |
*/
|
663 |
function zip_backup_db($task_name, $backup_file) {
|
664 |
+
$disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
|
665 |
+
$comp_level = $disable_comp ? '-0' : '-1';
|
666 |
+
$zip = $this->get_zip();
|
667 |
+
//Add database file
|
668 |
+
chdir(MWP_BACKUP_DIR);
|
669 |
+
$command = "$zip -q -r $comp_level $backup_file 'mwp_db'";
|
670 |
+
|
671 |
+
ob_start();
|
672 |
+
$this->_log("Executing $command");
|
673 |
+
$result = $this->mmb_exec($command);
|
674 |
+
ob_get_clean();
|
675 |
+
|
676 |
+
return $result;
|
677 |
}
|
678 |
+
|
679 |
/**
|
680 |
* Zipping database dump and index.php in folder mwp_db by ZipArchive class, requires php zip extension.
|
681 |
*
|
685 |
* @return bool is compress successful or not
|
686 |
*/
|
687 |
function zip_archive_backup_db($task_name, $db_result, $backup_file) {
|
688 |
+
$disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
|
689 |
+
if (!$disable_comp) {
|
690 |
+
$this->_log("Compression is not supported by ZipArchive");
|
691 |
+
}
|
692 |
+
$zip = new ZipArchive();
|
693 |
+
$result = $zip->open($backup_file, ZIPARCHIVE::OVERWRITE); // Tries to open $backup_file for acrhiving
|
694 |
+
if ($result === true) {
|
695 |
+
$result = $result && $zip->addFile(MWP_BACKUP_DIR.'/mwp_db/index.php', "mwp_db/index.php"); // Tries to add mwp_db/index.php to $backup_file
|
696 |
+
$result = $result && $zip->addFile($db_result, "mwp_db/" . basename($db_result)); // Tries to add db dump form mwp_db dir to $backup_file
|
697 |
+
$result = $result && $zip->close(); // Tries to close $backup_file
|
698 |
+
} else {
|
699 |
+
$result = false;
|
700 |
+
}
|
701 |
+
|
702 |
+
return $result; // true if $backup_file iz zipped successfully, false if error is occured in zip process
|
703 |
}
|
704 |
+
|
705 |
/**
|
706 |
* Zipping database dump and index.php in folder mwp_db by PclZip library.
|
707 |
*
|
710 |
* @return bool is compress successful or not
|
711 |
*/
|
712 |
function pclzip_backup_db($task_name, $backup_file) {
|
713 |
+
$disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
|
714 |
+
define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
|
715 |
+
require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
|
716 |
+
$zip = new PclZip($backup_file);
|
717 |
+
|
718 |
+
if ($disable_comp) {
|
719 |
+
$result = $zip->add(MWP_BACKUP_DIR, PCLZIP_OPT_REMOVE_PATH, MWP_BACKUP_DIR, PCLZIP_OPT_NO_COMPRESSION) !== 0;
|
720 |
+
} else {
|
721 |
+
$result = $zip->add(MWP_BACKUP_DIR, PCLZIP_OPT_REMOVE_PATH, MWP_BACKUP_DIR) !== 0;
|
722 |
+
}
|
723 |
+
|
724 |
+
return $result;
|
725 |
}
|
726 |
+
|
727 |
/**
|
728 |
* Zipping whole site root folder and append to backup file with database dump
|
729 |
* by system zip command, requires zip installed on OS.
|
835 |
|
836 |
return true;
|
837 |
}
|
838 |
+
|
839 |
/**
|
840 |
* Zipping whole site root folder and append to backup file with database dump
|
841 |
* by ZipArchive class, requires php zip extension.
|
847 |
* @return array|bool true if successful or an array with error message if not
|
848 |
*/
|
849 |
function zip_archive_backup($task_name, $backup_file, $exclude, $include, $overwrite = false) {
|
850 |
+
$filelist = $this->get_backup_files($exclude, $include);
|
851 |
+
$disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
|
852 |
+
if (!$disable_comp) {
|
853 |
+
$this->_log("Compression is not supported by ZipArchive");
|
854 |
+
}
|
855 |
+
|
856 |
+
$zip = new ZipArchive();
|
857 |
+
if ($overwrite) {
|
858 |
+
$result = $zip->open($backup_file, ZipArchive::OVERWRITE); // Tries to open $backup_file for acrhiving
|
859 |
+
} else {
|
860 |
+
$result = $zip->open($backup_file); // Tries to open $backup_file for acrhiving
|
861 |
+
}
|
862 |
+
if ($result === true) {
|
863 |
+
foreach ($filelist as $file) {
|
864 |
+
$result = $result && $zip->addFile($file, sprintf("%s", str_replace(ABSPATH, '', $file))); // Tries to add a new file to $backup_file
|
865 |
+
}
|
866 |
+
$result = $result && $zip->close(); // Tries to close $backup_file
|
867 |
+
} else {
|
868 |
+
$result = false;
|
869 |
+
}
|
870 |
+
|
871 |
+
return $result; // true if $backup_file iz zipped successfully, false if error is occured in zip process
|
872 |
}
|
873 |
+
|
874 |
/**
|
875 |
* Zipping whole site root folder and append to backup file with database dump
|
876 |
* by PclZip library.
|
882 |
* @return array|bool true if successful or an array with error message if not
|
883 |
*/
|
884 |
function pclzip_backup($task_name, $backup_file, $exclude, $include) {
|
885 |
+
define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
|
886 |
+
require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
|
887 |
+
$zip = new PclZip($backup_file);
|
888 |
+
$add = array(
|
889 |
+
trim(WPINC),
|
890 |
+
trim(basename(WP_CONTENT_DIR)),
|
891 |
+
"wp-admin"
|
892 |
+
);
|
893 |
+
|
894 |
+
$include_data = array();
|
895 |
+
if (!empty($include)) {
|
896 |
+
foreach ($include as $data) {
|
897 |
+
if ($data && file_exists(ABSPATH . $data))
|
898 |
+
$include_data[] = ABSPATH . $data . '/';
|
899 |
+
}
|
900 |
+
}
|
901 |
+
$include_data = array_merge($add, $include_data);
|
902 |
+
|
903 |
+
if ($handle = opendir(ABSPATH)) {
|
904 |
+
while (false !== ($file = readdir($handle))) {
|
905 |
+
if ($file != "." && $file != ".." && !is_dir($file) && file_exists(ABSPATH . $file)) {
|
906 |
+
$include_data[] = ABSPATH . $file;
|
907 |
+
}
|
908 |
+
}
|
909 |
+
closedir($handle);
|
910 |
+
}
|
911 |
+
|
912 |
+
$disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
|
913 |
+
|
914 |
+
if ($disable_comp) {
|
915 |
+
$result = $zip->add($include_data, PCLZIP_OPT_REMOVE_PATH, ABSPATH, PCLZIP_OPT_NO_COMPRESSION) !== 0;
|
916 |
+
} else {
|
917 |
+
$result = $zip->add($include_data, PCLZIP_OPT_REMOVE_PATH, ABSPATH) !== 0;
|
918 |
+
}
|
919 |
+
|
920 |
+
$exclude_data = array();
|
921 |
+
if (!empty($exclude)) {
|
922 |
+
foreach ($exclude as $data) {
|
923 |
+
if (file_exists(ABSPATH . $data)) {
|
924 |
+
if (is_dir(ABSPATH . $data))
|
925 |
+
$exclude_data[] = $data . '/';
|
926 |
+
else
|
927 |
+
$exclude_data[] = $data;
|
928 |
+
}
|
929 |
+
}
|
930 |
+
}
|
931 |
+
$result = $result && $zip->delete(PCLZIP_OPT_BY_NAME, $exclude_data);
|
932 |
+
|
933 |
+
return $result;
|
934 |
}
|
935 |
+
|
936 |
/**
|
937 |
* Gets an array of relative paths of all files in site root recursively.
|
938 |
* By default, there are all files from root folder, all files from folders wp-admin, wp-content, wp-includes recursively.
|
939 |
* Parameter $include adds other folders from site root, and excludes any file or folder by relative path to site's root.
|
940 |
+
*
|
941 |
* @param array $exclude array of files of folders to exclude, relative to site's root
|
942 |
* @param array $include array of folders from site root which are included to backup (wp-admin, wp-content, wp-includes are default)
|
943 |
* @return array array with all files in site root dir
|
944 |
*/
|
945 |
function get_backup_files($exclude, $include) {
|
946 |
+
$add = array(
|
947 |
+
trim(WPINC),
|
948 |
+
trim(basename(WP_CONTENT_DIR)),
|
949 |
+
"wp-admin"
|
950 |
+
);
|
951 |
+
|
952 |
+
$include = array_merge($add, $include);
|
953 |
+
|
954 |
+
$filelist = array();
|
955 |
+
if ($handle = opendir(ABSPATH)) {
|
956 |
+
while (false !== ($file = readdir($handle))) {
|
957 |
+
if (is_dir($file) && file_exists(ABSPATH . $file) && !(in_array($file, $include))) {
|
958 |
+
$exclude[] = $file;
|
959 |
+
}
|
960 |
+
}
|
961 |
+
closedir($handle);
|
962 |
+
}
|
963 |
+
|
964 |
+
$filelist = get_all_files_from_dir(ABSPATH, $exclude);
|
965 |
+
|
966 |
+
return $filelist;
|
967 |
}
|
968 |
+
|
969 |
/**
|
970 |
* Backup a database dump of WordPress site.
|
971 |
* All backups are compressed by zip and placed in wp-content/managewp/backups folder.
|
975 |
* @return bool|array true if backup is successful, or an array with error message if is failed
|
976 |
*/
|
977 |
function backup_db_compress($task_name, $backup_file) {
|
978 |
+
$this->update_status($task_name, $this->statuses['db_dump']);
|
979 |
+
$db_result = $this->backup_db();
|
980 |
+
|
981 |
+
if ($db_result == false) {
|
982 |
+
return array(
|
983 |
+
'error' => 'Failed to backup database.'
|
984 |
+
);
|
985 |
+
} else if (is_array($db_result) && isset($db_result['error'])) {
|
986 |
+
return array(
|
987 |
+
'error' => $db_result['error']
|
988 |
+
);
|
989 |
+
}
|
990 |
+
|
991 |
+
$this->update_status($task_name, $this->statuses['db_dump'], true);
|
992 |
+
$this->update_status($task_name, $this->statuses['db_zip']);
|
993 |
+
@file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
|
994 |
+
$zip_db_result = $this->zip_backup_db($task_name, $backup_file);
|
995 |
+
|
996 |
+
if (!$zip_db_result) {
|
997 |
+
$zip_archive_db_result = false;
|
998 |
+
if (class_exists("ZipArchive")) {
|
999 |
+
$this->_log("DB zip, fallback to ZipArchive");
|
1000 |
+
$zip_archive_db_result = $this->zip_archive_backup_db($task_name, $db_result, $backup_file);
|
1001 |
+
}
|
1002 |
+
|
1003 |
+
if (!$zip_archive_db_result) {
|
1004 |
+
$this->_log("DB zip, fallback to PclZip");
|
1005 |
+
$pclzip_db_result = $this->pclzip_backup_db($task_name, $backup_file);
|
1006 |
+
if (!$pclzip_db_result) {
|
1007 |
+
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
1008 |
+
@unlink($db_result);
|
1009 |
+
@rmdir(MWP_DB_DIR);
|
1010 |
+
|
1011 |
+
return array(
|
1012 |
+
'error' => 'Failed to zip database. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
|
1013 |
+
);
|
1014 |
+
}
|
1015 |
+
}
|
1016 |
+
}
|
1017 |
+
|
1018 |
+
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
1019 |
+
@unlink($db_result);
|
1020 |
+
@rmdir(MWP_DB_DIR);
|
1021 |
+
|
1022 |
+
$this->update_status($task_name, $this->statuses['db_zip'], true);
|
1023 |
+
|
1024 |
+
return true;
|
1025 |
}
|
1026 |
+
|
1027 |
/**
|
1028 |
* Creates database dump and places it in mwp_db folder in site's root.
|
1029 |
* This function dispatches if OS mysql command does not work calls a php alternative.
|
1038 |
'error' => 'Error creating database backup folder (' . $db_folder . '). Make sure you have corrrect write permissions.'
|
1039 |
);
|
1040 |
}
|
1041 |
+
|
1042 |
$file = $db_folder . DB_NAME . '.sql';
|
1043 |
$result = $this->backup_db_dump($file); // try mysqldump always then fallback to php dump
|
1044 |
return $result;
|
1045 |
}
|
1046 |
+
|
1047 |
/**
|
1048 |
* Creates database dump by system mysql command.
|
1049 |
+
*
|
1050 |
* @param string $file absolute path to file in which dump should be placed
|
1051 |
* @return string|array path to dump file if successful, or an array with error message if is failed
|
1052 |
*/
|
1089 |
ob_start();
|
1090 |
$result = $this->mmb_exec($command);
|
1091 |
ob_get_clean();
|
1092 |
+
|
1093 |
if (!$result) { // Fallback to php
|
1094 |
+
$this->_log("DB dump fallback to php");
|
1095 |
$result = $this->backup_db_php($file);
|
1096 |
return $result;
|
1097 |
}
|
1098 |
+
|
1099 |
if (filesize($file) == 0 || !is_file($file) || !$result) {
|
1100 |
@unlink($file);
|
1101 |
return false;
|
1103 |
return $file;
|
1104 |
}
|
1105 |
}
|
1106 |
+
|
1107 |
/**
|
1108 |
* Creates database dump by php functions.
|
1109 |
*
|
1110 |
* @param string $file absolute path to file in which dump should be placed
|
1111 |
* @return string|array path to dump file if successful, or an array with error message if is failed
|
1112 |
*/
|
1113 |
+
function backup_db_php($file) {
|
1114 |
global $wpdb;
|
1115 |
$tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
|
1116 |
foreach ($tables as $table) {
|
1121 |
$create_table = $wpdb->get_row("SHOW CREATE TABLE $table[0]", ARRAY_N);
|
1122 |
$dump_data = "\n\n" . $create_table[1] . ";\n\n";
|
1123 |
file_put_contents($file, $dump_data, FILE_APPEND);
|
1124 |
+
|
1125 |
$count = $wpdb->get_var("SELECT count(*) FROM $table[0]");
|
1126 |
if ($count > 100)
|
1127 |
$count = ceil($count / 100);
|
1128 |
+
else if ($count > 0)
|
1129 |
+
$count = 1;
|
1130 |
+
|
1131 |
for ($i = 0; $i < $count; $i++) {
|
1132 |
$low_limit = $i * 100;
|
1133 |
$qry = "SELECT * FROM $table[0] LIMIT $low_limit, 100";
|
1152 |
}
|
1153 |
$dump_data = "\n\n\n";
|
1154 |
file_put_contents($file, $dump_data, FILE_APPEND);
|
1155 |
+
|
1156 |
unset($rows);
|
1157 |
unset($dump_data);
|
1158 |
}
|
1159 |
+
|
1160 |
if (filesize($file) == 0 || !is_file($file)) {
|
1161 |
@unlink($file);
|
1162 |
return array(
|
1163 |
'error' => 'Database backup failed. Try to enable MySQL dump on your server.'
|
1164 |
);
|
1165 |
}
|
1166 |
+
|
1167 |
return $file;
|
1168 |
}
|
1169 |
+
|
1170 |
/**
|
1171 |
* Restores full WordPress site or database only form backup zip file.
|
1172 |
+
*
|
1173 |
* @param array array of arguments passed to backup restore
|
1174 |
* [task_name] -> name of backup task
|
1175 |
* [result_id] -> id of baskup task result, which should be restored
|
1183 |
}
|
1184 |
extract($args);
|
1185 |
if (isset($google_drive_token)) {
|
1186 |
+
$this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
|
1187 |
}
|
1188 |
$this->set_memory();
|
1189 |
+
|
1190 |
$unlink_file = true; //Delete file after restore
|
1191 |
+
|
1192 |
//Detect source
|
1193 |
if ($backup_url) {
|
1194 |
//This is for clone (overwrite)
|
1211 |
$args = $task['task_args']['account_info']['mwp_ftp'];
|
1212 |
$args['backup_file'] = $ftp_file;
|
1213 |
$backup_file = $this->get_ftp_backup($args);
|
1214 |
+
|
1215 |
if ($backup_file == false) {
|
1216 |
return array(
|
1217 |
'error' => 'Failed to download file from FTP.'
|
1218 |
);
|
1219 |
}
|
1220 |
+
}elseif (isset($task['task_results'][$result_id]['sftp'])) {
|
1221 |
+
$ftp_file = $task['task_results'][$result_id]['sftp'];
|
1222 |
+
$args = $task['task_args']['account_info']['mwp_sftp'];
|
1223 |
+
$args['backup_file'] = $ftp_file;
|
1224 |
+
$backup_file = $this->get_sftp_backup($args);
|
1225 |
+
|
1226 |
+
if ($backup_file == false) {
|
1227 |
+
return array(
|
1228 |
+
'error' => 'Failed to download file from SFTP.'
|
1229 |
+
);
|
1230 |
+
}
|
1231 |
+
}
|
1232 |
+
|
1233 |
+
elseif (isset($task['task_results'][$result_id]['amazons3'])) {
|
1234 |
$amazons3_file = $task['task_results'][$result_id]['amazons3'];
|
1235 |
$args = $task['task_args']['account_info']['mwp_amazon_s3'];
|
1236 |
$args['backup_file'] = $amazons3_file;
|
1237 |
$backup_file = $this->get_amazons3_backup($args);
|
1238 |
+
|
1239 |
if ($backup_file == false) {
|
1240 |
return array(
|
1241 |
'error' => 'Failed to download file from Amazon S3.'
|
1242 |
);
|
1243 |
}
|
1244 |
} elseif(isset($task['task_results'][$result_id]['dropbox'])){
|
1245 |
+
$dropbox_file = $task['task_results'][$result_id]['dropbox'];
|
1246 |
$args = $task['task_args']['account_info']['mwp_dropbox'];
|
1247 |
$args['backup_file'] = $dropbox_file;
|
1248 |
$backup_file = $this->get_dropbox_backup($args);
|
1249 |
+
|
1250 |
if ($backup_file == false) {
|
1251 |
return array(
|
1252 |
'error' => 'Failed to download file from Dropbox.'
|
1257 |
$args = $task['task_args']['account_info']['mwp_google_drive'];
|
1258 |
$args['backup_file'] = $google_drive_file;
|
1259 |
$backup_file = $this->get_google_drive_backup($args);
|
1260 |
+
|
1261 |
if (is_array($backup_file) && isset($backup_file['error'])) {
|
1262 |
+
return array(
|
1263 |
+
'error' => 'Failed to download file from Google Drive, reason: ' . $backup_file['error']
|
1264 |
+
);
|
1265 |
} elseif ($backup_file == false) {
|
1266 |
return array(
|
1267 |
'error' => 'Failed to download file from Google Drive.'
|
1268 |
);
|
1269 |
}
|
1270 |
}
|
1271 |
+
|
1272 |
$what = $tasks[$task_name]['task_args']['what'];
|
1273 |
}
|
1274 |
+
|
1275 |
$this->wpdb_reconnect();
|
1276 |
+
|
1277 |
if ($backup_file && file_exists($backup_file)) {
|
1278 |
if ($overwrite) {
|
1279 |
//Keep old db credentials before overwrite
|
1286 |
If you are unsure on how to do this yourself, you can ask your hosting provider for help.'
|
1287 |
);
|
1288 |
}
|
1289 |
+
|
1290 |
$db_host = DB_HOST;
|
1291 |
$db_user = DB_USER;
|
1292 |
$db_password = DB_PASSWORD;
|
1293 |
$home = rtrim(get_option('home'), "/");
|
1294 |
$site_url = get_option('site_url');
|
1295 |
+
|
1296 |
$clone_options = array();
|
1297 |
if (trim($clone_from_url) || trim($mwp_clone)) {
|
1298 |
$clone_options['_worker_nossl_key'] = get_option('_worker_nossl_key');
|
1301 |
}
|
1302 |
$clone_options['upload_path'] = get_option('upload_path');
|
1303 |
$clone_options['upload_url_path'] = get_option('upload_url_path');
|
1304 |
+
|
1305 |
|
1306 |
$clone_options['mwp_backup_tasks'] = maybe_serialize(get_option('mwp_backup_tasks'));
|
1307 |
$clone_options['mwp_notifications'] = maybe_serialize(get_option('mwp_notifications'));
|
1308 |
$clone_options['mwp_pageview_alerts'] = maybe_serialize(get_option('mwp_pageview_alerts'));
|
1309 |
} else {
|
1310 |
+
$restore_options = array();
|
1311 |
+
$restore_options['mwp_notifications'] = get_option('mwp_notifications');
|
1312 |
+
$restore_options['mwp_pageview_alerts'] = get_option('mwp_pageview_alerts');
|
1313 |
+
$restore_options['user_hit_count'] = get_option('user_hit_count');
|
1314 |
$restore_options['mwp_backup_tasks'] = get_option('mwp_backup_tasks');
|
1315 |
}
|
1316 |
+
|
1317 |
chdir(ABSPATH);
|
1318 |
$unzip = $this->get_unzip();
|
1319 |
$command = "$unzip -o $backup_file";
|
1320 |
ob_start();
|
1321 |
$result = $this->mmb_exec($command);
|
1322 |
ob_get_clean();
|
1323 |
+
|
1324 |
if (!$result) { //fallback to pclzip
|
1325 |
+
$this->_log("Files uznip fallback to pclZip");
|
1326 |
define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
|
1327 |
require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
|
1328 |
$archive = new PclZip($backup_file);
|
1329 |
$result = $archive->extract(PCLZIP_OPT_PATH, ABSPATH, PCLZIP_OPT_REPLACE_NEWER);
|
1330 |
}
|
1331 |
+
|
1332 |
if ($unlink_file) {
|
1333 |
@unlink($backup_file);
|
1334 |
}
|
1335 |
+
|
1336 |
if (!$result) {
|
1337 |
return array(
|
1338 |
'error' => 'Failed to unzip files. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
|
1339 |
);
|
1340 |
}
|
1341 |
+
|
1342 |
+
$db_result = $this->restore_db();
|
1343 |
+
|
1344 |
if (!$db_result) {
|
1345 |
return array(
|
1346 |
'error' => 'Error restoring database.'
|
1347 |
);
|
1348 |
} else if(is_array($db_result) && isset($db_result['error'])){
|
1349 |
+
return array(
|
1350 |
'error' => $db_result['error']
|
1351 |
);
|
1352 |
}
|
1353 |
+
|
1354 |
} else {
|
1355 |
return array(
|
1356 |
'error' => 'Error restoring. Cannot find backup file.'
|
1357 |
);
|
1358 |
}
|
1359 |
+
|
1360 |
$this->wpdb_reconnect();
|
1361 |
+
|
1362 |
//Replace options and content urls
|
1363 |
if ($overwrite) {
|
1364 |
//Get New Table prefix
|
1367 |
@unlink(ABSPATH . 'wp-config.php');
|
1368 |
//Replace table prefix
|
1369 |
$lines = file(ABSPATH . 'mwp-temp-wp-config.php');
|
1370 |
+
|
1371 |
foreach ($lines as $line) {
|
1372 |
if (strstr($line, '$table_prefix')) {
|
1373 |
$line = '$table_prefix = "' . $new_table_prefix . '";' . PHP_EOL;
|
1374 |
}
|
1375 |
file_put_contents(ABSPATH . 'wp-config.php', $line, FILE_APPEND);
|
1376 |
}
|
1377 |
+
|
1378 |
@unlink(ABSPATH . 'mwp-temp-wp-config.php');
|
1379 |
+
|
1380 |
//Replace options
|
1381 |
$query = "SELECT option_value FROM " . $new_table_prefix . "options WHERE option_name = 'home'";
|
1382 |
$old = $wpdb->get_var($query);
|
1390 |
$regexp2 = 'href="(.*)$old(.*)"';
|
1391 |
$query = "UPDATE " . $new_table_prefix . "posts SET post_content = REPLACE (post_content, %s,%s) WHERE post_content REGEXP %s OR post_content REGEXP %s";
|
1392 |
$wpdb->query($wpdb->prepare($query, array($old, $home, $regexp1, $regexp2)));
|
1393 |
+
|
1394 |
if (trim($new_password)) {
|
1395 |
$new_password = wp_hash_password($new_password);
|
1396 |
}
|
1406 |
$wpdb->query($wpdb->prepare($query, $new_password, $new_user));
|
1407 |
}
|
1408 |
}
|
1409 |
+
|
1410 |
if ($mwp_clone) {
|
1411 |
if ($admin_email) {
|
1412 |
//Clean Install
|
1418 |
$query = "UPDATE " . $new_table_prefix . "users SET user_email=%s, user_login = %s, user_pass = %s WHERE user_login = %s";
|
1419 |
$wpdb->query($wpdb->prepare($query, $admin_email, $new_user, $new_password, $temp_user->user_login));
|
1420 |
}
|
1421 |
+
|
1422 |
}
|
1423 |
}
|
1424 |
}
|
1425 |
+
|
1426 |
if (is_array($clone_options) && !empty($clone_options)) {
|
1427 |
foreach ($clone_options as $key => $option) {
|
1428 |
if (!empty($key)) {
|
1438 |
}
|
1439 |
}
|
1440 |
}
|
1441 |
+
|
1442 |
//Remove hit count
|
1443 |
$query = "DELETE FROM " . $new_table_prefix . "options WHERE option_name = 'user_hit_count'";
|
1444 |
+
$wpdb->query($query);
|
1445 |
|
1446 |
//Restore previous backups
|
1447 |
|
1450 |
//Check for .htaccess permalinks update
|
1451 |
$this->replace_htaccess($home);
|
1452 |
} else {
|
1453 |
+
//restore worker options
|
1454 |
if (is_array($restore_options) && !empty($restore_options)) {
|
1455 |
foreach ($restore_options as $key => $option) {
|
1456 |
$result = $wpdb->update( $wpdb->options, array( 'option_value' => maybe_serialize($option) ), array( 'option_name' => $key ) );
|
1457 |
}
|
1458 |
}
|
1459 |
}
|
1460 |
+
|
1461 |
return true;
|
1462 |
}
|
1463 |
+
|
1464 |
/**
|
1465 |
* This function dispathces database restoring between mysql system command and php functions.
|
1466 |
* If system command fails, it calls the php alternative.
|
1474 |
@chmod($file_path,0755);
|
1475 |
$file_name = glob($file_path . '/*.sql');
|
1476 |
$file_name = $file_name[0];
|
1477 |
+
|
1478 |
if(!$file_name){
|
1479 |
+
return array('error' => 'Cannot access database file.');
|
1480 |
}
|
1481 |
+
|
1482 |
$brace = (substr(PHP_OS, 0, 3) == 'WIN') ? '"' : '';
|
1483 |
$command = $brace . $paths['mysql'] . $brace . ' --host="' . DB_HOST . '" --user="' . DB_USER . '" --password="' . DB_PASSWORD . '" --default-character-set="utf8" ' . DB_NAME . ' < ' . $brace . $file_name . $brace;
|
1484 |
+
|
1485 |
ob_start();
|
1486 |
$result = $this->mmb_exec($command);
|
1487 |
ob_get_clean();
|
1488 |
if (!$result) {
|
1489 |
+
$this->_log('DB restore fallback to PHP');
|
1490 |
//try php
|
1491 |
$this->restore_db_php($file_name);
|
1492 |
}
|
1493 |
+
|
1494 |
@unlink($file_name);
|
1495 |
return true;
|
1496 |
}
|
1497 |
+
|
1498 |
/**
|
1499 |
* Restores database dump by php functions.
|
1500 |
+
*
|
1501 |
* @param string $file_name relative path to database dump, which should be restored
|
1502 |
* @return bool is successful or not
|
1503 |
+
*/
|
1504 |
function restore_db_php($file_name) {
|
1505 |
global $wpdb;
|
1506 |
$current_query = '';
|
1511 |
// Skip it if it's a comment
|
1512 |
if (substr($line, 0, 2) == '--' || $line == '')
|
1513 |
continue;
|
1514 |
+
|
1515 |
// Add this line to the current query
|
1516 |
$current_query .= $line;
|
1517 |
// If it has a semicolon at the end, it's the end of the query
|
1524 |
$current_query = '';
|
1525 |
}
|
1526 |
}
|
1527 |
+
|
1528 |
@unlink($file_name);
|
1529 |
return true;
|
1530 |
}
|
1531 |
+
|
1532 |
/**
|
1533 |
* Retruns table_prefix for this WordPress installation.
|
1534 |
* It is used by restore.
|
1535 |
+
*
|
1536 |
* @return string table prefix from wp-config.php file, (default: wp_)
|
1537 |
*/
|
1538 |
function get_table_prefix() {
|
1548 |
}
|
1549 |
return 'wp_'; //default
|
1550 |
}
|
1551 |
+
|
1552 |
/**
|
1553 |
* Change all tables to InnoDB engine, and executes mysql OPTIMIZE TABLE for each table.
|
1554 |
+
*
|
1555 |
* @return bool optimized successfully or not
|
1556 |
*/
|
1557 |
function optimize_tables() {
|
1558 |
+
global $wpdb;
|
1559 |
+
$query = 'SHOW TABLES';
|
1560 |
+
$tables = $wpdb->get_results($query, ARRAY_A);
|
1561 |
+
foreach ($tables as $table) {
|
1562 |
+
if (in_array($table['Engine'], array(
|
1563 |
+
'MyISAM',
|
1564 |
+
'ISAM',
|
1565 |
+
'HEAP',
|
1566 |
+
'MEMORY',
|
1567 |
+
'ARCHIVE'
|
1568 |
+
)))
|
1569 |
+
$table_string .= $table['Name'] . ",";
|
1570 |
+
elseif ($table['Engine'] == 'InnoDB') {
|
1571 |
+
$optimize = $wpdb->query("ALTER TABLE {$table['Name']} ENGINE=InnoDB");
|
1572 |
}
|
1573 |
}
|
1574 |
+
|
1575 |
+
$table_string = rtrim($table_string);
|
1576 |
+
$optimize = $wpdb->query("OPTIMIZE TABLE $table_string");
|
1577 |
+
|
1578 |
+
return $optimize ? true : false;
|
1579 |
+
|
1580 |
}
|
1581 |
+
|
1582 |
/**
|
1583 |
* Returns mysql and mysql dump command path on OS.
|
1584 |
+
*
|
1585 |
* @return array array with system mysql and mysqldump command, blank if does not exist
|
1586 |
*/
|
1587 |
function check_mysql_paths() {
|
1604 |
$paths['mysql'] = $this->mmb_exec('which mysql', true);
|
1605 |
if (empty($paths['mysql']))
|
1606 |
$paths['mysql'] = 'mysql'; // try anyway
|
1607 |
+
|
1608 |
$paths['mysqldump'] = $this->mmb_exec('which mysqldump', true);
|
1609 |
if (empty($paths['mysqldump']))
|
1610 |
$paths['mysqldump'] = 'mysqldump'; // try anyway
|
1611 |
}
|
1612 |
+
|
1613 |
return $paths;
|
1614 |
}
|
1615 |
+
|
1616 |
/**
|
1617 |
* Check if exec, system, passthru functions exist
|
1618 |
+
*
|
1619 |
* @return string|bool exec if exists, then system, then passthru, then false if no one exist
|
1620 |
*/
|
1621 |
function check_sys() {
|
1622 |
if ($this->mmb_function_exists('exec'))
|
1623 |
return 'exec';
|
1624 |
+
|
1625 |
if ($this->mmb_function_exists('system'))
|
1626 |
return 'system';
|
1627 |
+
|
1628 |
if ($this->mmb_function_exists('passhtru'))
|
1629 |
return 'passthru';
|
1630 |
+
|
1631 |
return false;
|
1632 |
}
|
1633 |
+
|
1634 |
/**
|
1635 |
* Executes an external system command.
|
1636 |
+
*
|
1637 |
* @param string $command external command to execute
|
1638 |
* @param bool[optional] $string return as a system output string (default: false)
|
1639 |
* @param bool[optional] $rawreturn return as a status of executed command
|
1642 |
function mmb_exec($command, $string = false, $rawreturn = false) {
|
1643 |
if ($command == '')
|
1644 |
return false;
|
1645 |
+
|
1646 |
if ($this->mmb_function_exists('exec')) {
|
1647 |
$log = @exec($command, $output, $return);
|
1648 |
+
$this->_log("Type: exec");
|
1649 |
+
$this->_log("Command: ".$command);
|
1650 |
+
$this->_log("Return: ".$return);
|
1651 |
if ($string)
|
1652 |
return $log;
|
1653 |
if ($rawreturn)
|
1654 |
return $return;
|
1655 |
+
|
1656 |
return $return ? false : true;
|
1657 |
} elseif ($this->mmb_function_exists('system')) {
|
1658 |
$log = @system($command, $return);
|
1659 |
+
$this->_log("Type: system");
|
1660 |
+
$this->_log("Command: ".$command);
|
1661 |
+
$this->_log("Return: ".$return);
|
1662 |
if ($string)
|
1663 |
return $log;
|
1664 |
+
|
1665 |
if ($rawreturn)
|
1666 |
return $return;
|
1667 |
+
|
1668 |
return $return ? false : true;
|
1669 |
} elseif ($this->mmb_function_exists('passthru') && !$string) {
|
1670 |
$log = passthru($command, $return);
|
1671 |
$this->_log("Type: passthru");
|
1672 |
$this->_log("Command: ".$command);
|
1673 |
+
$this->_log("Return: ".$return);
|
1674 |
if ($rawreturn)
|
1675 |
return $return;
|
1676 |
+
|
1677 |
return $return ? false : true;
|
1678 |
}
|
1679 |
+
|
1680 |
if ($rawreturn)
|
1681 |
+
return -1;
|
1682 |
+
|
1683 |
return false;
|
1684 |
}
|
1685 |
+
|
1686 |
/**
|
1687 |
* Returns a path to system command for zip execution.
|
1688 |
+
*
|
1689 |
* @return string command for zip execution
|
1690 |
*/
|
1691 |
function get_zip() {
|
1694 |
$zip = "zip";
|
1695 |
return $zip;
|
1696 |
}
|
1697 |
+
|
1698 |
/**
|
1699 |
* Returns a path to system command for unzip execution.
|
1700 |
*
|
1706 |
$unzip = "unzip";
|
1707 |
return $unzip;
|
1708 |
}
|
1709 |
+
|
1710 |
/**
|
1711 |
* Returns all important information of worker's system status to master.
|
1712 |
+
*
|
1713 |
* @return mixed associative array with information of server OS, php version, is backup folder writable, execute function, zip and unzip command, execution time, memory limit and path to error log if exists
|
1714 |
*/
|
1715 |
function check_backup_compat() {
|
1716 |
+
$reqs = array();
|
1717 |
if (strpos($_SERVER['DOCUMENT_ROOT'], '/') === 0) {
|
1718 |
$reqs['Server OS']['status'] = 'Linux (or compatible)';
|
1719 |
$reqs['Server OS']['pass'] = true;
|
1729 |
$reqs['PHP Version']['pass'] = false;
|
1730 |
$pass = false;
|
1731 |
}
|
1732 |
+
|
1733 |
if (is_writable(WP_CONTENT_DIR)) {
|
1734 |
$reqs['Backup Folder']['status'] = "writable";
|
1735 |
$reqs['Backup Folder']['pass'] = true;
|
1737 |
$reqs['Backup Folder']['status'] = "not writable";
|
1738 |
$reqs['Backup Folder']['pass'] = false;
|
1739 |
}
|
1740 |
+
|
1741 |
$file_path = MWP_BACKUP_DIR;
|
1742 |
$reqs['Backup Folder']['status'] .= ' (' . $file_path . ')';
|
1743 |
+
|
1744 |
if ($func = $this->check_sys()) {
|
1745 |
$reqs['Execute Function']['status'] = $func;
|
1746 |
$reqs['Execute Function']['pass'] = true;
|
1749 |
$reqs['Execute Function']['info'] = "(will try PHP replacement)";
|
1750 |
$reqs['Execute Function']['pass'] = false;
|
1751 |
}
|
1752 |
+
|
1753 |
$reqs['Zip']['status'] = $this->get_zip();
|
1754 |
$reqs['Zip']['pass'] = true;
|
1755 |
$reqs['Unzip']['status'] = $this->get_unzip();
|
1756 |
$reqs['Unzip']['pass'] = true;
|
1757 |
+
|
1758 |
$paths = $this->check_mysql_paths();
|
1759 |
+
|
1760 |
if (!empty($paths['mysqldump'])) {
|
1761 |
$reqs['MySQL Dump']['status'] = $paths['mysqldump'];
|
1762 |
$reqs['MySQL Dump']['pass'] = true;
|
1765 |
$reqs['MySQL Dump']['info'] = "(will try PHP replacement)";
|
1766 |
$reqs['MySQL Dump']['pass'] = false;
|
1767 |
}
|
1768 |
+
|
1769 |
$exec_time = ini_get('max_execution_time');
|
1770 |
$reqs['Execution time']['status'] = $exec_time ? $exec_time . "s" : 'unknown';
|
1771 |
$reqs['Execution time']['pass'] = true;
|
1772 |
+
|
1773 |
$mem_limit = ini_get('memory_limit');
|
1774 |
$reqs['Memory limit']['status'] = $mem_limit ? $mem_limit : 'unknown';
|
1775 |
$reqs['Memory limit']['pass'] = true;
|
1776 |
+
|
1777 |
$changed = $this->set_memory();
|
1778 |
if($changed['execution_time']){
|
1779 |
+
$exec_time = ini_get('max_execution_time');
|
1780 |
+
$reqs['Execution time']['status'] .= $exec_time ? ' (will try '.$exec_time . 's)' : ' (unknown)';
|
1781 |
}
|
1782 |
if($changed['memory_limit']){
|
1783 |
+
$mem_limit = ini_get('memory_limit');
|
1784 |
+
$reqs['Memory limit']['status'] .= $mem_limit ? ' (will try '.$mem_limit.')' : ' (unknown)';
|
1785 |
}
|
1786 |
+
|
1787 |
if(defined('MWP_SHOW_LOG') && MWP_SHOW_LOG == true){
|
1788 |
+
$md5 = get_option('mwp_log_md5');
|
1789 |
+
if ($md5 !== false) {
|
1790 |
+
global $mmb_plugin_url;
|
1791 |
+
$md5 = "<a href='$mmb_plugin_url/log_$md5' target='_blank'>$md5</a>";
|
1792 |
+
} else {
|
1793 |
+
$md5 = "not created";
|
1794 |
+
}
|
1795 |
+
$reqs['Backup Log']['status'] = $md5;
|
1796 |
+
$reqs['Backup Log']['pass'] = true;
|
1797 |
+
}
|
1798 |
+
|
1799 |
return $reqs;
|
1800 |
}
|
1801 |
+
|
1802 |
/**
|
1803 |
* Uploads backup file from server to email.
|
1804 |
* A lot of email service have limitation to 10mb.
|
1805 |
+
*
|
1806 |
* @param array $args arguments passed to the function
|
1807 |
* [email] -> email address which backup should send to
|
1808 |
* [task_name] -> name of backup task
|
1811 |
*/
|
1812 |
function email_backup($args) {
|
1813 |
$email = $args['email'];
|
1814 |
+
|
1815 |
if (!is_email($email)) {
|
1816 |
return array(
|
1817 |
'error' => 'Your email (' . $email . ') is not correct'
|
1828 |
ob_start();
|
1829 |
$result = wp_mail($email, $subject, $subject, $headers, $attachments);
|
1830 |
ob_end_clean();
|
1831 |
+
|
1832 |
}
|
1833 |
+
|
1834 |
if (!$result) {
|
1835 |
return array(
|
1836 |
'error' => 'Email not sent. Maybe your backup is too big for email or email server is not available on your website.'
|
1838 |
}
|
1839 |
return true;
|
1840 |
}
|
1841 |
+
|
1842 |
+
/**
|
1843 |
+
* Uploads backup file from server to remote sftp server.
|
1844 |
+
*
|
1845 |
+
* @param array $args arguments passed to the function
|
1846 |
+
* [sftp_username] -> sftp username on remote server
|
1847 |
+
* [sftp_password] -> sftp password on remote server
|
1848 |
+
* [sftp_hostname] -> sftp hostname of remote host
|
1849 |
+
* [sftp_remote_folder] -> folder on remote site which backup file should be upload to
|
1850 |
+
* [sftp_site_folder] -> subfolder with site name in ftp_remote_folder which backup file should be upload to
|
1851 |
+
* [sftp_passive] -> passive mode or not
|
1852 |
+
* [sftp_ssl] -> ssl or not
|
1853 |
+
* [sftp_port] -> number of port for ssl protocol
|
1854 |
+
* [backup_file] -> absolute path of backup file on local server
|
1855 |
+
* @return bool|array true is successful, array with error message if not
|
1856 |
+
*/
|
1857 |
+
function sftp_backup($args) {
|
1858 |
+
extract($args);
|
1859 |
+
// file_put_contents("sftp_log.txt","sftp_backup",FILE_APPEND);
|
1860 |
+
$port = $sftp_port ? $sftp_port : 22; //default port is 22
|
1861 |
+
// file_put_contents("sftp_log.txt","sftp port:".$sftp_port,FILE_APPEND);
|
1862 |
+
$sftp_hostname = $sftp_hostname?$sftp_hostname:"";
|
1863 |
+
// file_put_contents("sftp_log.txt","sftp host:".$sftp_hostname,FILE_APPEND);
|
1864 |
+
$sftp_username = $sftp_username?$sftp_username:"";
|
1865 |
+
// file_put_contents("sftp_log.txt","sftp user:".$sftp_username,FILE_APPEND);
|
1866 |
+
$sftp_password = $sftp_password?$sftp_password:"";
|
1867 |
+
// file_put_contents("sftp_log.txt","sftp pass:".$sftp_password,FILE_APPEND);
|
1868 |
+
// file_put_contents("sftp_log.txt","Creating NetSFTP",FILE_APPEND);
|
1869 |
+
$sftp = new Net_SFTP($sftp_hostname);
|
1870 |
+
// file_put_contents("sftp_log.txt","Created NetSFTP",FILE_APPEND);
|
1871 |
+
$remote = $sftp_remote_folder ? trim($sftp_remote_folder,"/")."/" : '';
|
1872 |
+
if (!$sftp->login($sftp_username, $sftp_password)) {
|
1873 |
+
file_put_contents("sftp_log.txt","sftp login failed in sftp_backup",FILE_APPEND);
|
1874 |
+
return array(
|
1875 |
+
'error' => 'SFTP login failed for ' . $sftp_username . ', ' . $sftp_password,
|
1876 |
+
'partial' => 1
|
1877 |
+
);
|
1878 |
+
}
|
1879 |
+
file_put_contents("sftp_log.txt","making remote dir",FILE_APPEND);
|
1880 |
+
$sftp->mkdir($remote);
|
1881 |
+
file_put_contents("sftp_log.txt","made remote dir",FILE_APPEND);
|
1882 |
+
if ($sftp_site_folder) {
|
1883 |
+
$remote .= '/' . $this->site_name;
|
1884 |
+
}
|
1885 |
+
$sftp->mkdir($remote);
|
1886 |
+
file_put_contents("sftp_log.txt","making {$sftp_remote_folder} dir",FILE_APPEND);
|
1887 |
+
$sftp->mkdir($sftp_remote_folder);
|
1888 |
+
file_put_contents("sftp_log.txt","made {$sftp_remote_folder} dir",FILE_APPEND);
|
1889 |
+
file_put_contents("sftp_log.txt","starting upload",FILE_APPEND);
|
1890 |
+
$upload = $sftp->put( $remote.'/' . basename($backup_file),$backup_file, NET_SFTP_LOCAL_FILE);
|
1891 |
+
file_put_contents("sftp_log.txt","finish upload",FILE_APPEND);
|
1892 |
+
$sftp->disconnect();
|
1893 |
+
|
1894 |
+
if ($upload === false) {
|
1895 |
+
file_put_contents("sftp_log.txt","sftp upload failed",FILE_APPEND);
|
1896 |
+
return array(
|
1897 |
+
'error' => 'Failed to upload file to SFTP. Please check your specified path.',
|
1898 |
+
'partial' => 1
|
1899 |
+
);
|
1900 |
+
}
|
1901 |
+
|
1902 |
+
return true;
|
1903 |
+
}
|
1904 |
+
|
1905 |
+
|
1906 |
+
|
1907 |
/**
|
1908 |
* Uploads backup file from server to remote ftp server.
|
1909 |
*
|
1921 |
*/
|
1922 |
function ftp_backup($args) {
|
1923 |
extract($args);
|
1924 |
+
|
1925 |
$port = $ftp_port ? $ftp_port : 21; //default port is 21
|
1926 |
if ($ftp_ssl) {
|
1927 |
if (function_exists('ftp_ssl_connect')) {
|
1928 |
$conn_id = ftp_ssl_connect($ftp_hostname,$port);
|
1929 |
if ($conn_id === false) {
|
1930 |
+
return array(
|
1931 |
+
'error' => 'Failed to connect to ' . $ftp_hostname,
|
1932 |
+
'partial' => 1
|
1933 |
+
);
|
1934 |
}
|
1935 |
} else {
|
1936 |
return array(
|
1961 |
'partial' => 1
|
1962 |
);
|
1963 |
}
|
1964 |
+
|
1965 |
if($ftp_passive){
|
1966 |
+
@ftp_pasv($conn_id,true);
|
1967 |
+
}
|
1968 |
+
|
1969 |
@ftp_mkdir($conn_id, $ftp_remote_folder);
|
1970 |
if ($ftp_site_folder) {
|
1971 |
$ftp_remote_folder .= '/' . $this->site_name;
|
1972 |
}
|
1973 |
@ftp_mkdir($conn_id, $ftp_remote_folder);
|
1974 |
+
|
1975 |
$upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_BINARY);
|
1976 |
+
|
1977 |
if ($upload === false) { //Try ascii
|
1978 |
$upload = @ftp_put($conn_id, $ftp_remote_folder . '/' . basename($backup_file), $backup_file, FTP_ASCII);
|
1979 |
}
|
1980 |
@ftp_close($conn_id);
|
1981 |
+
|
1982 |
if ($upload === false) {
|
1983 |
return array(
|
1984 |
'error' => 'Failed to upload file to FTP. Please check your specified path.',
|
1985 |
'partial' => 1
|
1986 |
);
|
1987 |
}
|
1988 |
+
|
1989 |
return true;
|
1990 |
}
|
1991 |
+
|
1992 |
/**
|
1993 |
* Deletes backup file from remote ftp server.
|
1994 |
*
|
2003 |
*/
|
2004 |
function remove_ftp_backup($args) {
|
2005 |
extract($args);
|
2006 |
+
|
2007 |
$port = $ftp_port ? $ftp_port : 21; //default port is 21
|
2008 |
if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
|
2009 |
$conn_id = ftp_ssl_connect($ftp_hostname,$port);
|
2010 |
} else if (function_exists('ftp_connect')) {
|
2011 |
$conn_id = ftp_connect($ftp_hostname,$port);
|
2012 |
}
|
2013 |
+
|
2014 |
if ($conn_id) {
|
2015 |
$login = @ftp_login($conn_id, $ftp_username, $ftp_password);
|
2016 |
if ($ftp_site_folder)
|
2017 |
$ftp_remote_folder .= '/' . $this->site_name;
|
2018 |
+
|
2019 |
if($ftp_passive){
|
2020 |
+
@ftp_pasv($conn_id,true);
|
2021 |
+
}
|
2022 |
+
|
2023 |
$delete = ftp_delete($conn_id, $ftp_remote_folder . '/' . $backup_file);
|
2024 |
+
|
2025 |
ftp_close($conn_id);
|
2026 |
}
|
2027 |
}
|
2028 |
+
/**
|
2029 |
+
* Deletes backup file from remote sftp server.
|
2030 |
+
*
|
2031 |
+
* @param array $args arguments passed to the function
|
2032 |
+
* [sftp_username] -> sftp username on remote server
|
2033 |
+
* [sftp_password] -> sftp password on remote server
|
2034 |
+
* [sftp_hostname] -> sftp hostname of remote host
|
2035 |
+
* [sftp_remote_folder] -> folder on remote site which backup file should be deleted from
|
2036 |
+
* [sftp_site_folder] -> subfolder with site name in ftp_remote_folder which backup file should be deleted from
|
2037 |
+
* [backup_file] -> absolute path of backup file on local server
|
2038 |
+
* @return void
|
2039 |
+
*/
|
2040 |
+
function remove_sftp_backup($args) {
|
2041 |
+
extract($args);
|
2042 |
+
file_put_contents("sftp_log.txt","sftp remove_sftp_backup",FILE_APPEND);
|
2043 |
+
$port = $sftp_port ? $sftp_port : 22; //default port is 21
|
2044 |
+
$sftp_hostname = $sftp_hostname?$sftp_hostname:"";
|
2045 |
+
$sftp_username = $sftp_username?$sftp_username:"";
|
2046 |
+
$sftp_password = $sftp_password?$sftp_password:"";
|
2047 |
+
$sftp = new Net_SFTP($sftp_hostname);
|
2048 |
+
if (!$sftp->login($sftp_username, $sftp_password)) {
|
2049 |
+
file_put_contents("sftp_log.txt","sftp login failed in remove_sftp_backup",FILE_APPEND);
|
2050 |
+
return false;
|
2051 |
+
}
|
2052 |
+
$remote = $sftp_remote_folder ? trim($sftp_remote_folder,"/")."/" :'';
|
2053 |
+
// copies filename.local to filename.remote on the SFTP server
|
2054 |
+
if(isset($backup_file) && isset($remote) && $backup_file!=="")
|
2055 |
+
$upload = $sftp->delete( $remote . '/' . $backup_file);
|
2056 |
+
$sftp->disconnect();
|
2057 |
+
}
|
2058 |
+
|
2059 |
+
|
2060 |
/**
|
2061 |
* Downloads backup file from server from remote ftp server to root folder on local server.
|
2062 |
*
|
2071 |
*/
|
2072 |
function get_ftp_backup($args) {
|
2073 |
extract($args);
|
2074 |
+
|
2075 |
$port = $ftp_port ? $ftp_port : 21; //default port is 21
|
2076 |
if ($ftp_ssl && function_exists('ftp_ssl_connect')) {
|
2077 |
$conn_id = ftp_ssl_connect($ftp_hostname,$port);
|
2078 |
+
|
2079 |
} else if (function_exists('ftp_connect')) {
|
2080 |
$conn_id = ftp_connect($ftp_hostname,$port);
|
2081 |
if ($conn_id === false) {
|
2082 |
return false;
|
2083 |
}
|
2084 |
+
}
|
2085 |
$login = @ftp_login($conn_id, $ftp_username, $ftp_password);
|
2086 |
if ($login === false) {
|
2087 |
return false;
|
2088 |
}
|
2089 |
+
|
2090 |
if ($ftp_site_folder)
|
2091 |
$ftp_remote_folder .= '/' . $this->site_name;
|
2092 |
+
|
2093 |
if($ftp_passive){
|
2094 |
+
@ftp_pasv($conn_id,true);
|
2095 |
+
}
|
2096 |
+
|
2097 |
$temp = ABSPATH . 'mwp_temp_backup.zip';
|
2098 |
$get = ftp_get($conn_id, $temp, $ftp_remote_folder . '/' . $backup_file, FTP_BINARY);
|
2099 |
if ($get === false) {
|
2100 |
return false;
|
2101 |
}
|
2102 |
+
|
2103 |
ftp_close($conn_id);
|
2104 |
+
|
2105 |
return $temp;
|
2106 |
}
|
2107 |
+
|
2108 |
+
|
2109 |
+
|
2110 |
/**
|
2111 |
+
* Downloads backup file from server from remote ftp server to root folder on local server.
|
2112 |
*
|
2113 |
* @param array $args arguments passed to the function
|
2114 |
+
* [ftp_username] -> ftp username on remote server
|
2115 |
+
* [ftp_password] -> ftp password on remote server
|
2116 |
+
* [ftp_hostname] -> ftp hostname of remote host
|
2117 |
+
* [ftp_remote_folder] -> folder on remote site which backup file should be downloaded from
|
2118 |
+
* [ftp_site_folder] -> subfolder with site name in ftp_remote_folder which backup file should be downloaded from
|
|
|
2119 |
* [backup_file] -> absolute path of backup file on local server
|
2120 |
+
* @return string|array absolute path to downloaded file is successful, array with error message if not
|
2121 |
*/
|
2122 |
+
function get_sftp_backup($args) {
|
2123 |
extract($args);
|
2124 |
+
file_put_contents("sftp_log.txt","get_sftp_backup",FILE_APPEND);
|
2125 |
+
|
2126 |
+
$port = $sftp_port ? $sftp_port : 22; //default port is 21 $sftp_hostname = $sftp_hostname?$sftp_hostname:"";
|
2127 |
+
file_put_contents("sftp_log.txt","sftp port:".$sftp_port,FILE_APPEND);
|
2128 |
+
$sftp_username = $sftp_username?$sftp_username:"";
|
2129 |
+
$sftp_password = $sftp_password?$sftp_password:"";
|
2130 |
+
file_put_contents("sftp_log.txt","sftp host:".$sftp_hostname.";username:".$sftp_username.";password:".$sftp_password,FILE_APPEND);
|
2131 |
+
$sftp = new Net_SFTP($sftp_hostname);
|
2132 |
+
if (!$sftp->login($sftp_username, $sftp_password)) {
|
2133 |
+
file_put_contents("sftp_log.txt","sftp login failed in get_sftp_backup",FILE_APPEND);
|
2134 |
+
return false;
|
2135 |
+
}
|
2136 |
+
$remote = $sftp_remote_folder ? trim($sftp_remote_folder,"/")."/" : '';
|
2137 |
+
|
2138 |
+
|
2139 |
+
if ($ftp_site_folder)
|
2140 |
+
$remote .= '/' . $this->site_name;
|
2141 |
+
|
2142 |
+
$temp = ABSPATH . 'mwp_temp_backup.zip';
|
2143 |
+
$get = $sftp->get($remote . '/' . $backup_file,$temp);
|
2144 |
+
$sftp->disconnect();
|
2145 |
+
if ($get === false) {
|
2146 |
+
file_put_contents("sftp_log.txt","sftp get failed in get_sftp_backup",FILE_APPEND);
|
2147 |
+
return false;
|
2148 |
+
}
|
2149 |
+
|
2150 |
+
return $temp;
|
2151 |
+
}
|
2152 |
+
|
2153 |
+
/**
|
2154 |
+
* Uploads backup file from server to Dropbox.
|
2155 |
+
*
|
2156 |
+
* @param array $args arguments passed to the function
|
2157 |
+
* [consumer_key] -> consumer key of ManageWP Dropbox application
|
2158 |
+
* [consumer_secret] -> consumer secret of ManageWP Dropbox application
|
2159 |
+
* [oauth_token] -> oauth token of user on ManageWP Dropbox application
|
2160 |
+
* [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
|
2161 |
+
* [dropbox_destination] -> folder on user's Dropbox account which backup file should be upload to
|
2162 |
+
* [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be upload to
|
2163 |
+
* [backup_file] -> absolute path of backup file on local server
|
2164 |
+
* @return bool|array true is successful, array with error message if not
|
2165 |
+
*/
|
2166 |
+
function dropbox_backup($args) {
|
2167 |
+
extract($args);
|
2168 |
+
|
2169 |
global $mmb_plugin_dir;
|
2170 |
require_once $mmb_plugin_dir . '/lib/dropbox.php';
|
2171 |
+
|
2172 |
$dropbox = new Dropbox($consumer_key, $consumer_secret);
|
2173 |
$dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
|
2174 |
+
|
2175 |
if ($dropbox_site_folder == true)
|
2176 |
+
$dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
|
2177 |
else
|
2178 |
+
$dropbox_destination .= '/' . basename($backup_file);
|
2179 |
+
|
2180 |
try {
|
2181 |
+
$dropbox->upload($backup_file, $dropbox_destination, true);
|
2182 |
} catch (Exception $e) {
|
2183 |
+
$this->_log($e->getMessage());
|
2184 |
+
return array(
|
2185 |
+
'error' => $e->getMessage(),
|
2186 |
+
'partial' => 1
|
2187 |
+
);
|
2188 |
}
|
2189 |
+
|
2190 |
return true;
|
2191 |
}
|
2192 |
+
|
2193 |
/**
|
2194 |
* Deletes backup file from Dropbox to root folder on local server.
|
2195 |
*
|
2204 |
* @return void
|
2205 |
*/
|
2206 |
function remove_dropbox_backup($args) {
|
2207 |
+
extract($args);
|
2208 |
+
|
2209 |
global $mmb_plugin_dir;
|
2210 |
require_once $mmb_plugin_dir . '/lib/dropbox.php';
|
2211 |
+
|
2212 |
$dropbox = new Dropbox($consumer_key, $consumer_secret);
|
2213 |
$dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
|
2214 |
+
|
2215 |
if ($dropbox_site_folder == true)
|
2216 |
+
$dropbox_destination .= '/' . $this->site_name;
|
2217 |
+
|
2218 |
+
try {
|
2219 |
+
$dropbox->fileopsDelete($dropbox_destination . '/' . $backup_file);
|
2220 |
+
} catch (Exception $e) {
|
2221 |
+
$this->_log($e->getMessage());
|
2222 |
+
/*return array(
|
2223 |
+
'error' => $e->getMessage(),
|
2224 |
+
'partial' => 1
|
2225 |
+
);*/
|
2226 |
+
}
|
2227 |
+
|
2228 |
+
//return true;
|
2229 |
+
}
|
2230 |
+
|
2231 |
+
/**
|
2232 |
+
* Downloads backup file from Dropbox to root folder on local server.
|
2233 |
+
*
|
2234 |
+
* @param array $args arguments passed to the function
|
2235 |
+
* [consumer_key] -> consumer key of ManageWP Dropbox application
|
2236 |
+
* [consumer_secret] -> consumer secret of ManageWP Dropbox application
|
2237 |
+
* [oauth_token] -> oauth token of user on ManageWP Dropbox application
|
2238 |
+
* [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
|
2239 |
+
* [dropbox_destination] -> folder on user's Dropbox account which backup file should be deleted from
|
2240 |
+
* [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be deleted from
|
2241 |
+
* [backup_file] -> absolute path of backup file on local server
|
2242 |
+
* @return bool|array absolute path to downloaded file is successful, array with error message if not
|
2243 |
+
*/
|
2244 |
+
function get_dropbox_backup($args) {
|
2245 |
+
extract($args);
|
2246 |
+
|
2247 |
+
global $mmb_plugin_dir;
|
2248 |
+
require_once $mmb_plugin_dir . '/lib/dropbox.php';
|
2249 |
+
|
2250 |
+
$dropbox = new Dropbox($consumer_key, $consumer_secret);
|
2251 |
$dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
|
2252 |
+
|
2253 |
if ($dropbox_site_folder == true)
|
2254 |
+
$dropbox_destination .= '/' . $this->site_name;
|
2255 |
+
|
2256 |
+
$temp = ABSPATH . 'mwp_temp_backup.zip';
|
2257 |
+
|
2258 |
+
try {
|
2259 |
+
$file = $dropbox->download($dropbox_destination.'/'.$backup_file);
|
2260 |
+
$handle = @fopen($temp, 'w');
|
2261 |
+
$result = fwrite($handle,$file);
|
2262 |
+
fclose($handle);
|
2263 |
+
|
2264 |
+
if($result)
|
2265 |
+
return $temp;
|
2266 |
+
else
|
2267 |
+
return false;
|
2268 |
+
} catch (Exception $e) {
|
2269 |
+
$this->_log($e->getMessage());
|
2270 |
+
return array(
|
2271 |
+
'error' => $e->getMessage(),
|
2272 |
+
'partial' => 1
|
2273 |
+
);
|
2274 |
+
}
|
2275 |
+
}
|
2276 |
+
|
2277 |
+
/**
|
2278 |
+
* Uploads backup file from server to Amazon S3.
|
2279 |
+
*
|
2280 |
+
* @param array $args arguments passed to the function
|
2281 |
+
* [as3_bucket_region] -> Amazon S3 bucket region
|
2282 |
+
* [as3_bucket] -> Amazon S3 bucket
|
2283 |
+
* [as3_access_key] -> Amazon S3 access key
|
2284 |
+
* [as3_secure_key] -> Amazon S3 secure key
|
2285 |
+
* [as3_directory] -> folder on user's Amazon S3 account which backup file should be upload to
|
2286 |
+
* [as3_site_folder] -> subfolder with site name in as3_directory which backup file should be upload to
|
2287 |
+
* [backup_file] -> absolute path of backup file on local server
|
2288 |
+
* @return bool|array true is successful, array with error message if not
|
2289 |
+
*/
|
2290 |
function amazons3_backup($args) {
|
2291 |
if ($this->mmb_function_exists('curl_init')) {
|
2292 |
require_once('lib/s3.php');
|
2293 |
extract($args);
|
2294 |
+
|
2295 |
if ($as3_site_folder == true)
|
2296 |
$as3_directory .= '/' . $this->site_name;
|
2297 |
+
|
2298 |
$endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
|
2299 |
try{
|
2300 |
+
$s3 = new mwpS3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
|
2301 |
+
if ($s3->putObjectFile($backup_file, $as3_bucket, $as3_directory . '/' . basename($backup_file), mwpS3::ACL_PRIVATE)) {
|
2302 |
+
return true;
|
2303 |
+
} else {
|
2304 |
+
return array(
|
2305 |
+
'error' => 'Failed to upload to Amazon S3. Please check your details and set upload/delete permissions on your bucket.',
|
2306 |
+
'partial' => 1
|
2307 |
+
);
|
2308 |
+
}
|
2309 |
+
} catch (Exception $e) {
|
2310 |
+
$err = $e->getMessage();
|
2311 |
+
if($err){
|
2312 |
+
return array(
|
2313 |
+
'error' => 'Failed to upload to AmazonS3 ('.$err.').'
|
2314 |
+
);
|
2315 |
+
} else {
|
2316 |
+
return array(
|
2317 |
+
'error' => 'Failed to upload to Amazon S3.'
|
2318 |
+
);
|
2319 |
+
}
|
2320 |
+
}
|
2321 |
+
|
2322 |
} else {
|
2323 |
return array(
|
2324 |
'error' => 'You cannot use Amazon S3 on your server. Please enable curl extension first.',
|
2343 |
* @return void
|
2344 |
*/
|
2345 |
function remove_amazons3_backup($args) {
|
2346 |
+
if ($this->mmb_function_exists('curl_init')) {
|
2347 |
+
require_once('lib/s3.php');
|
2348 |
+
extract($args);
|
2349 |
+
if ($as3_site_folder == true)
|
2350 |
+
$as3_directory .= '/' . $this->site_name;
|
2351 |
+
$endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
|
2352 |
+
try {
|
2353 |
+
$s3 = new mwpS3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
|
2354 |
+
$s3->deleteObject($as3_bucket, $as3_directory . '/' . $backup_file);
|
2355 |
+
} catch (Exception $e){
|
2356 |
+
|
2357 |
+
}
|
2358 |
+
}
|
2359 |
}
|
2360 |
+
|
2361 |
/**
|
2362 |
* Downloads backup file from Amazon S3 to root folder on local server.
|
2363 |
*
|
2377 |
$endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
|
2378 |
$temp = '';
|
2379 |
try {
|
2380 |
+
$s3 = new mwpS3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
|
2381 |
+
if ($as3_site_folder == true)
|
2382 |
+
$as3_directory .= '/' . $this->site_name;
|
2383 |
+
|
2384 |
+
$temp = ABSPATH . 'mwp_temp_backup.zip';
|
2385 |
+
$s3->getObject($as3_bucket, $as3_directory . '/' . $backup_file, $temp);
|
2386 |
+
} catch (Exception $e) {
|
2387 |
+
return $temp;
|
2388 |
+
}
|
2389 |
+
return $temp;
|
2390 |
}
|
2391 |
+
|
2392 |
/**
|
2393 |
* Uploads backup file from server to Google Drive.
|
2394 |
*
|
2400 |
* @return bool|array true is successful, array with error message if not
|
2401 |
*/
|
2402 |
function google_drive_backup($args) {
|
2403 |
+
extract($args);
|
2404 |
+
|
2405 |
+
global $mmb_plugin_dir;
|
2406 |
+
require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
|
2407 |
+
require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
|
2408 |
+
|
2409 |
+
$gdrive_client = new Google_Client();
|
2410 |
+
$gdrive_client->setUseObjects(true);
|
2411 |
+
$gdrive_client->setAccessToken($google_drive_token);
|
2412 |
+
|
2413 |
+
$gdrive_service = new Google_DriveService($gdrive_client);
|
2414 |
+
|
2415 |
+
try {
|
2416 |
+
$about = $gdrive_service->about->get();
|
2417 |
+
$root_folder_id = $about->getRootFolderId();
|
2418 |
+
} catch (Exception $e) {
|
2419 |
+
return array(
|
2420 |
+
'error' => $e->getMessage(),
|
2421 |
+
);
|
2422 |
+
}
|
2423 |
+
|
2424 |
+
try {
|
2425 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
|
2426 |
+
$files = $list_files->getItems();
|
2427 |
+
} catch (Exception $e) {
|
2428 |
+
return array(
|
2429 |
+
'error' => $e->getMessage(),
|
2430 |
+
);
|
2431 |
+
}
|
2432 |
+
if (isset($files[0])) {
|
2433 |
+
$managewp_folder = $files[0];
|
2434 |
+
}
|
2435 |
+
|
2436 |
+
if (!isset($managewp_folder)) {
|
2437 |
+
try {
|
2438 |
+
$_managewp_folder = new Google_DriveFile();
|
2439 |
+
$_managewp_folder->setTitle($google_drive_directory);
|
2440 |
+
$_managewp_folder->setMimeType('application/vnd.google-apps.folder');
|
2441 |
+
|
2442 |
+
if ($root_folder_id != null) {
|
2443 |
+
$parent = new Google_ParentReference();
|
2444 |
+
$parent->setId($root_folder_id);
|
2445 |
+
$_managewp_folder->setParents(array($parent));
|
2446 |
+
}
|
2447 |
+
|
2448 |
+
$managewp_folder = $gdrive_service->files->insert($_managewp_folder, array());
|
2449 |
+
} catch (Exception $e) {
|
2450 |
+
return array(
|
2451 |
+
'error' => $e->getMessage(),
|
2452 |
+
);
|
2453 |
+
}
|
2454 |
+
}
|
2455 |
+
|
2456 |
+
if ($google_drive_site_folder) {
|
2457 |
+
try {
|
2458 |
+
$subfolder_title = $this->site_name;
|
2459 |
+
$managewp_folder_id = $managewp_folder->getId();
|
2460 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
|
2461 |
+
$files = $list_files->getItems();
|
2462 |
+
} catch (Exception $e) {
|
2463 |
+
return array(
|
2464 |
+
'error' => $e->getMessage(),
|
2465 |
+
);
|
2466 |
+
}
|
2467 |
+
if (isset($files[0])) {
|
2468 |
+
$backup_folder = $files[0];
|
2469 |
+
} else {
|
2470 |
+
try {
|
2471 |
+
$_backup_folder = new Google_DriveFile();
|
2472 |
+
$_backup_folder->setTitle($subfolder_title);
|
2473 |
+
$_backup_folder->setMimeType('application/vnd.google-apps.folder');
|
2474 |
+
|
2475 |
+
if (isset($managewp_folder)) {
|
2476 |
+
$_backup_folder->setParents(array($managewp_folder));
|
2477 |
+
}
|
2478 |
+
|
2479 |
+
$backup_folder = $gdrive_service->files->insert($_backup_folder, array());
|
2480 |
+
} catch (Exception $e) {
|
2481 |
+
return array(
|
2482 |
+
'error' => $e->getMessage(),
|
2483 |
+
);
|
2484 |
+
}
|
2485 |
+
}
|
2486 |
+
} else {
|
2487 |
+
$backup_folder = $managewp_folder;
|
2488 |
+
}
|
2489 |
+
|
2490 |
+
$file_path = explode('/', $backup_file);
|
2491 |
+
$new_file = new Google_DriveFile();
|
2492 |
+
$new_file->setTitle(end($file_path));
|
2493 |
+
$new_file->setDescription('Backup file of site: ' . $this->site_name . '.');
|
2494 |
+
|
2495 |
+
if ($backup_folder != null) {
|
2496 |
+
$new_file->setParents(array($backup_folder));
|
2497 |
+
}
|
2498 |
+
|
2499 |
+
$tries = 1;
|
2500 |
+
|
2501 |
+
while($tries <= 2) {
|
2502 |
+
try {
|
2503 |
+
$data = file_get_contents($backup_file);
|
2504 |
+
|
2505 |
+
$createdFile = $gdrive_service->files->insert($new_file, array(
|
2506 |
+
'data' => $data,
|
2507 |
+
));
|
2508 |
+
|
2509 |
+
break;
|
2510 |
+
} catch (Exception $e) {
|
2511 |
+
if ($e->getCode() >= 500 && $e->getCode() <= 504 && $mmb_gdrive_upload_tries <= 2) {
|
2512 |
+
sleep(2);
|
2513 |
+
$tries++;
|
2514 |
+
} else {
|
2515 |
+
return array(
|
2516 |
+
'error' => $e->getMessage(),
|
2517 |
+
);
|
2518 |
+
}
|
2519 |
+
}
|
2520 |
+
}
|
2521 |
+
|
2522 |
+
return true;
|
2523 |
}
|
2524 |
+
|
2525 |
/**
|
2526 |
* Deletes backup file from Google Drive.
|
2527 |
*
|
2533 |
* @return void
|
2534 |
*/
|
2535 |
function remove_google_drive_backup($args) {
|
2536 |
+
extract($args);
|
2537 |
+
|
2538 |
+
global $mmb_plugin_dir;
|
2539 |
+
require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
|
2540 |
+
require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
|
2541 |
+
|
2542 |
+
try {
|
2543 |
+
$gdrive_client = new Google_Client();
|
2544 |
+
$gdrive_client->setUseObjects(true);
|
2545 |
+
$gdrive_client->setAccessToken($google_drive_token);
|
2546 |
+
} catch (Exception $e) {
|
2547 |
+
$this->_log($e->getMessage());
|
2548 |
+
/*eturn array(
|
2549 |
+
'error' => $e->getMessage(),
|
2550 |
+
);*/
|
2551 |
+
}
|
2552 |
+
|
2553 |
+
$gdrive_service = new Google_DriveService($gdrive_client);
|
2554 |
+
|
2555 |
+
try {
|
2556 |
+
$about = $gdrive_service->about->get();
|
2557 |
+
$root_folder_id = $about->getRootFolderId();
|
2558 |
+
} catch (Exception $e) {
|
2559 |
+
$this->_log($e->getMessage());
|
2560 |
+
/*return array(
|
2561 |
+
'error' => $e->getMessage(),
|
2562 |
+
);*/
|
2563 |
+
}
|
2564 |
+
|
2565 |
+
try {
|
2566 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
|
2567 |
+
$files = $list_files->getItems();
|
2568 |
+
} catch (Exception $e) {
|
2569 |
+
$this->_log($e->getMessage());
|
2570 |
+
/*return array(
|
2571 |
+
'error' => $e->getMessage(),
|
2572 |
+
);*/
|
2573 |
+
}
|
2574 |
+
if (isset($files[0])) {
|
2575 |
+
$managewp_folder = $files[0];
|
2576 |
+
} else {
|
2577 |
+
$this->_log("This file does not exist.");
|
2578 |
+
/*return array(
|
2579 |
+
'error' => "This file does not exist.",
|
2580 |
+
);*/
|
2581 |
+
}
|
2582 |
+
|
2583 |
+
if ($google_drive_site_folder) {
|
2584 |
+
try {
|
2585 |
+
$subfolder_title = $this->site_name;
|
2586 |
+
$managewp_folder_id = $managewp_folder->getId();
|
2587 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
|
2588 |
+
$files = $list_files->getItems();
|
2589 |
+
} catch (Exception $e) {
|
2590 |
+
$this->_log($e->getMessage());
|
2591 |
+
/*return array(
|
2592 |
+
'error' => $e->getMessage(),
|
2593 |
+
);*/
|
2594 |
+
}
|
2595 |
+
if (isset($files[0])) {
|
2596 |
+
$backup_folder = $files[0];
|
2597 |
+
}
|
2598 |
+
} else {
|
2599 |
+
$backup_folder = $managewp_folder;
|
2600 |
+
}
|
2601 |
+
|
2602 |
+
if (isset($backup_folder)) {
|
2603 |
+
try {
|
2604 |
+
$backup_folder_id = $backup_folder->getId();
|
2605 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$backup_file' and '$backup_folder_id' in parents and trashed = false"));
|
2606 |
+
$files = $list_files->getItems();;
|
2607 |
+
} catch (Exception $e) {
|
2608 |
+
$this->_log($e->getMessage());
|
2609 |
+
/*return array(
|
2610 |
+
'error' => $e->getMessage(),
|
2611 |
+
);*/
|
2612 |
+
}
|
2613 |
+
if (isset($files[0])) {
|
2614 |
+
try {
|
2615 |
+
$gdrive_service->files->delete($files[0]->getId());
|
2616 |
+
} catch (Exception $e) {
|
2617 |
+
$this->_log($e->getMessage());
|
2618 |
+
/*return array(
|
2619 |
+
'error' => $e->getMessage(),
|
2620 |
+
);*/
|
2621 |
+
}
|
2622 |
+
} else {
|
2623 |
+
$this->_log("This file does not exist.");
|
2624 |
+
/*return array(
|
2625 |
+
'error' => "This file does not exist.",
|
2626 |
+
);*/
|
2627 |
+
}
|
2628 |
+
} else {
|
2629 |
+
$this->_log("This file does not exist.");
|
2630 |
+
/*return array(
|
2631 |
+
'error' => "This file does not exist.",
|
2632 |
+
);*/
|
2633 |
+
}
|
2634 |
+
|
2635 |
+
//return true;
|
2636 |
}
|
2637 |
+
|
2638 |
/**
|
2639 |
* Downloads backup file from Google Drive to root folder on local server.
|
2640 |
*
|
2646 |
* @return bool|array absolute path to downloaded file is successful, array with error message if not
|
2647 |
*/
|
2648 |
function get_google_drive_backup($args) {
|
2649 |
+
extract($args);
|
2650 |
+
|
2651 |
+
global $mmb_plugin_dir;
|
2652 |
+
require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
|
2653 |
+
require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
|
2654 |
+
|
2655 |
+
try {
|
2656 |
+
$gdrive_client = new Google_Client();
|
2657 |
+
$gdrive_client->setUseObjects(true);
|
2658 |
+
$gdrive_client->setAccessToken($google_drive_token);
|
2659 |
+
} catch (Exception $e) {
|
2660 |
+
return array(
|
2661 |
+
'error' => $e->getMessage(),
|
2662 |
+
);
|
2663 |
+
}
|
2664 |
+
|
2665 |
+
$gdrive_service = new Google_DriveService($gdrive_client);
|
2666 |
+
|
2667 |
+
try {
|
2668 |
+
$about = $gdrive_service->about->get();
|
2669 |
+
$root_folder_id = $about->getRootFolderId();
|
2670 |
+
} catch (Exception $e) {
|
2671 |
+
return array(
|
2672 |
+
'error' => $e->getMessage(),
|
2673 |
+
);
|
2674 |
+
}
|
2675 |
+
|
2676 |
+
try {
|
2677 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
|
2678 |
+
$files = $list_files->getItems();
|
2679 |
+
} catch (Exception $e) {
|
2680 |
+
return array(
|
2681 |
+
'error' => $e->getMessage(),
|
2682 |
+
);
|
2683 |
+
}
|
2684 |
+
if (isset($files[0])) {
|
2685 |
+
$managewp_folder = $files[0];
|
2686 |
+
} else {
|
2687 |
+
return array(
|
2688 |
+
'error' => "This file does not exist.",
|
2689 |
+
);
|
2690 |
+
}
|
2691 |
+
|
2692 |
+
if ($google_drive_site_folder) {
|
2693 |
+
try {
|
2694 |
+
$subfolder_title = $this->site_name;
|
2695 |
+
$managewp_folder_id = $managewp_folder->getId();
|
2696 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
|
2697 |
+
$files = $list_files->getItems();
|
2698 |
+
} catch (Exception $e) {
|
2699 |
+
return array(
|
2700 |
+
'error' => $e->getMessage(),
|
2701 |
+
);
|
2702 |
+
}
|
2703 |
+
if (isset($files[0])) {
|
2704 |
+
$backup_folder = $files[0];
|
2705 |
+
}
|
2706 |
+
} else {
|
2707 |
+
$backup_folder = $managewp_folder;
|
2708 |
+
}
|
2709 |
+
|
2710 |
+
if (isset($backup_folder)) {
|
2711 |
+
try {
|
2712 |
+
$backup_folder_id = $backup_folder->getId();
|
2713 |
+
$list_files = $gdrive_service->files->listFiles(array("q"=>"title='$backup_file' and '$backup_folder_id' in parents and trashed = false"));
|
2714 |
+
$files = $list_files->getItems();
|
2715 |
+
} catch (Exception $e) {
|
2716 |
+
return array(
|
2717 |
+
'error' => $e->getMessage(),
|
2718 |
+
);
|
2719 |
+
}
|
2720 |
+
if (isset($files[0])) {
|
2721 |
+
try {
|
2722 |
+
$download_url = $files[0]->getDownloadUrl();
|
2723 |
+
if ($download_url) {
|
2724 |
+
$request = new Google_HttpRequest($download_url, 'GET', null, null);
|
2725 |
+
$http_request = Google_Client::$io->authenticatedRequest($request);
|
2726 |
+
if ($http_request->getResponseHttpCode() == 200) {
|
2727 |
+
$stream = $http_request->getResponseBody();
|
2728 |
+
$local_destination = ABSPATH . 'mwp_temp_backup.zip';
|
2729 |
+
$handle = @fopen($local_destination, 'w+');
|
2730 |
+
$result = fwrite($handle, $stream);
|
2731 |
+
fclose($handle);
|
2732 |
+
if($result)
|
2733 |
+
return $local_destination;
|
2734 |
+
else
|
2735 |
+
return array(
|
2736 |
+
'error' => "Write permission error.",
|
2737 |
+
);
|
2738 |
+
} else {
|
2739 |
+
return array(
|
2740 |
+
'error' => "This file does not exist.",
|
2741 |
+
);
|
2742 |
+
}
|
2743 |
+
} else {
|
2744 |
+
return array(
|
2745 |
+
'error' => "This file does not exist.",
|
2746 |
+
);
|
2747 |
+
}
|
2748 |
+
} catch (Exception $e) {
|
2749 |
+
return array(
|
2750 |
+
'error' => $e->getMessage(),
|
2751 |
+
);
|
2752 |
+
}
|
2753 |
+
} else {
|
2754 |
+
return array(
|
2755 |
+
'error' => "This file does not exist.",
|
2756 |
+
);
|
2757 |
+
}
|
2758 |
+
} else {
|
2759 |
+
return array(
|
2760 |
+
'error' => "This file does not exist.",
|
2761 |
+
);
|
2762 |
+
}
|
2763 |
+
|
2764 |
+
return false;
|
2765 |
}
|
2766 |
+
|
2767 |
/**
|
2768 |
* Schedules the next execution of some backup task.
|
2769 |
+
*
|
2770 |
* @param string $type daily, weekly or monthly
|
2771 |
* @param string $schedule format: task_time (if daily), task_time|task_day (if weekly), task_time|task_date (if monthly)
|
2772 |
* @return bool|int timestamp if sucessful, false if not
|
2773 |
*/
|
2774 |
+
function schedule_next($type, $schedule) {
|
2775 |
$schedule = explode("|", $schedule);
|
2776 |
+
|
2777 |
+
if (empty($schedule))
|
2778 |
return false;
|
2779 |
switch ($type) {
|
2780 |
case 'daily':
|
2781 |
if (isset($schedule[1]) && $schedule[1]) {
|
2782 |
$delay_time = $schedule[1] * 60;
|
2783 |
}
|
2784 |
+
|
2785 |
$current_hour = date("H");
|
2786 |
$schedule_hour = $schedule[0];
|
2787 |
if ($current_hour >= $schedule_hour)
|
2789 |
else
|
2790 |
$time = mktime($schedule_hour, 0, 0, date("m"), date("d"), date("Y"));
|
2791 |
break;
|
2792 |
+
|
2793 |
case 'weekly':
|
2794 |
if (isset($schedule[2]) && $schedule[2]) {
|
2795 |
$delay_time = $schedule[2] * 60;
|
2798 |
$schedule_weekday = $schedule[1];
|
2799 |
$current_hour = date("H");
|
2800 |
$schedule_hour = $schedule[0];
|
2801 |
+
|
2802 |
if ($current_weekday > $schedule_weekday)
|
2803 |
$weekday_offset = 7 - ($week_day - $task_schedule[1]);
|
2804 |
else
|
2805 |
$weekday_offset = $schedule_weekday - $current_weekday;
|
2806 |
+
|
2807 |
if (!$weekday_offset) { //today is scheduled weekday
|
2808 |
if ($current_hour >= $schedule_hour)
|
2809 |
$time = mktime($schedule_hour, 0, 0, date("m"), date("d") + 7, date("Y"));
|
2813 |
$time = mktime($schedule_hour, 0, 0, date("m"), date("d") + $weekday_offset, date("Y"));
|
2814 |
}
|
2815 |
break;
|
2816 |
+
|
2817 |
case 'monthly':
|
2818 |
if (isset($schedule[2]) && $schedule[2]) {
|
2819 |
$delay_time = $schedule[2] * 60;
|
2822 |
$schedule_monthday = $schedule[1];
|
2823 |
$current_hour = date("H");
|
2824 |
$schedule_hour = $schedule[0];
|
2825 |
+
|
2826 |
if ($current_monthday > $schedule_monthday) {
|
2827 |
$time = mktime($schedule_hour, 0, 0, date("m") + 1, $schedule_monthday, date("Y"));
|
2828 |
} else if ($current_monthday < $schedule_monthday) {
|
2834 |
$time = mktime($schedule_hour, 0, 0, date("m"), $schedule_monthday, date("Y"));
|
2835 |
break;
|
2836 |
}
|
2837 |
+
|
2838 |
break;
|
2839 |
+
|
2840 |
default:
|
2841 |
break;
|
2842 |
}
|
2843 |
+
|
2844 |
if (isset($delay_time) && $delay_time) {
|
2845 |
$time += $delay_time;
|
2846 |
}
|
2847 |
+
|
2848 |
return $time;
|
2849 |
}
|
2850 |
+
|
2851 |
/**
|
2852 |
* Parse task arguments for info on master.
|
2853 |
+
*
|
2854 |
* @return mixed associative array with stats for every backup task or error if backup is manually deleted on server
|
2855 |
*/
|
2856 |
function get_backup_stats() {
|
2862 |
foreach ($info['task_results'] as $key => $result) {
|
2863 |
if (isset($result['server']) && !isset($result['error'])) {
|
2864 |
if (isset($result['server']['file_path']) && !$info['task_args']['del_host_file']) {
|
2865 |
+
if (!file_exists($result['server']['file_path'])) {
|
2866 |
+
$info['task_results'][$key]['error'] = 'Backup created but manually removed from server.';
|
2867 |
+
}
|
2868 |
}
|
2869 |
}
|
2870 |
}
|
2871 |
}
|
2872 |
if (is_array($info['task_results']))
|
2873 |
+
$stats[$task_name] = array_values($info['task_results']);
|
2874 |
}
|
2875 |
}
|
2876 |
return $stats;
|
2877 |
}
|
2878 |
+
|
2879 |
/**
|
2880 |
* Returns all backup tasks with information when the next schedule will be.
|
2881 |
+
*
|
2882 |
* @return mixed associative array with timestamp with next schedule for every backup task
|
2883 |
*/
|
2884 |
function get_next_schedules() {
|
2891 |
}
|
2892 |
return $stats;
|
2893 |
}
|
2894 |
+
|
2895 |
/**
|
2896 |
* Deletes all old backups from local server.
|
2897 |
* It depends on configuration on master (Number of backups to keep).
|
2898 |
+
*
|
2899 |
* @param string $task_name name of backup task
|
2900 |
* @return bool|void true if there are backups for deletion, void if not
|
2901 |
*/
|
2902 |
function remove_old_backups($task_name) {
|
2903 |
//Check for previous failed backups first
|
2904 |
$this->cleanup();
|
2905 |
+
|
2906 |
//Remove by limit
|
2907 |
$backups = $this->tasks;
|
2908 |
if ($task_name == 'Backup Now') {
|
2910 |
} else {
|
2911 |
$num = 1;
|
2912 |
}
|
2913 |
+
|
2914 |
if ((count($backups[$task_name]['task_results']) - $num) >= $backups[$task_name]['task_args']['limit']) {
|
2915 |
//how many to remove ?
|
2916 |
$remove_num = (count($backups[$task_name]['task_results']) - $num - $backups[$task_name]['task_args']['limit']) + 1;
|
2919 |
if (isset($backups[$task_name]['task_results'][$i]['server'])) {
|
2920 |
@unlink($backups[$task_name]['task_results'][$i]['server']['file_path']);
|
2921 |
}
|
2922 |
+
|
2923 |
//Remove from ftp
|
2924 |
if (isset($backups[$task_name]['task_results'][$i]['ftp']) && isset($backups[$task_name]['task_args']['account_info']['mwp_ftp'])) {
|
2925 |
$ftp_file = $backups[$task_name]['task_results'][$i]['ftp'];
|
2927 |
$args['backup_file'] = $ftp_file;
|
2928 |
$this->remove_ftp_backup($args);
|
2929 |
}
|
2930 |
+
if (isset($backups[$task_name]['task_results'][$i]['sftp']) && isset($backups[$task_name]['task_args']['account_info']['mwp_sftp'])) {
|
2931 |
+
$ftp_file = $backups[$task_name]['task_results'][$i]['fstp'];
|
2932 |
+
$args = $backups[$task_name]['task_args']['account_info']['mwp_sftp'];
|
2933 |
+
$args['backup_file'] = $sftp_file;
|
2934 |
+
$this->remove_sftp_backup($args);
|
2935 |
+
}
|
2936 |
+
|
2937 |
if (isset($backups[$task_name]['task_results'][$i]['amazons3']) && isset($backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'])) {
|
2938 |
$amazons3_file = $backups[$task_name]['task_results'][$i]['amazons3'];
|
2939 |
$args = $backups[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
|
2940 |
$args['backup_file'] = $amazons3_file;
|
2941 |
$this->remove_amazons3_backup($args);
|
2942 |
}
|
2943 |
+
|
2944 |
if (isset($backups[$task_name]['task_results'][$i]['dropbox']) && isset($backups[$task_name]['task_args']['account_info']['mwp_dropbox'])) {
|
2945 |
//To do: dropbox remove
|
2946 |
$dropbox_file = $backups[$task_name]['task_results'][$i]['dropbox'];
|
2947 |
$args = $backups[$task_name]['task_args']['account_info']['mwp_dropbox'];
|
2948 |
$args['backup_file'] = $dropbox_file;
|
2949 |
+
$this->remove_dropbox_backup($args);
|
2950 |
}
|
2951 |
+
|
2952 |
if (isset($backups[$task_name]['task_results'][$i]['google_drive']) && isset($backups[$task_name]['task_args']['account_info']['mwp_google_drive'])) {
|
2953 |
+
$google_drive_file = $backups[$task_name]['task_results'][$i]['google_drive'];
|
2954 |
+
$args = $backups[$task_name]['task_args']['account_info']['mwp_google_drive'];
|
2955 |
+
$args['backup_file'] = $google_drive_file;
|
2956 |
+
$this->remove_google_drive_backup($args);
|
2957 |
}
|
2958 |
+
|
2959 |
//Remove database backup info
|
2960 |
unset($backups[$task_name]['task_results'][$i]);
|
2961 |
} //end foreach
|
2962 |
+
|
2963 |
if (is_array($backups[$task_name]['task_results']))
|
2964 |
+
$backups[$task_name]['task_results'] = array_values($backups[$task_name]['task_results']);
|
2965 |
else
|
2966 |
+
$backups[$task_name]['task_results']=array();
|
2967 |
+
|
2968 |
$this->update_tasks($backups);
|
2969 |
+
|
2970 |
return true;
|
2971 |
}
|
2972 |
}
|
2973 |
+
|
2974 |
/**
|
2975 |
* Deletes specified backup.
|
2976 |
+
*
|
2977 |
* @param array $args arguments passed to function
|
2978 |
* [task_name] -> name of backup task
|
2979 |
* [result_id] -> id of baskup task result, which should be restored
|
2985 |
return false;
|
2986 |
extract($args);
|
2987 |
if (isset($google_drive_token)) {
|
2988 |
+
$this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
|
2989 |
}
|
2990 |
+
|
2991 |
$tasks = $this->tasks;
|
2992 |
$task = $tasks[$task_name];
|
2993 |
$backups = $task['task_results'];
|
2994 |
$backup = $backups[$result_id];
|
2995 |
+
|
2996 |
if (isset($backup['server'])) {
|
2997 |
@unlink($backup['server']['file_path']);
|
2998 |
}
|
2999 |
+
|
3000 |
//Remove from ftp
|
3001 |
if (isset($backup['ftp'])) {
|
3002 |
$ftp_file = $backup['ftp'];
|
3004 |
$args['backup_file'] = $ftp_file;
|
3005 |
$this->remove_ftp_backup($args);
|
3006 |
}
|
3007 |
+
if (isset($backup['sftp'])) {
|
3008 |
+
$ftp_file = $backup['ftp'];
|
3009 |
+
$args = $tasks[$task_name]['task_args']['account_info']['mwp_sftp'];
|
3010 |
+
$args['backup_file'] = $ftp_file;
|
3011 |
+
$this->remove_sftp_backup($args);
|
3012 |
+
}
|
3013 |
+
|
3014 |
if (isset($backup['amazons3'])) {
|
3015 |
$amazons3_file = $backup['amazons3'];
|
3016 |
$args = $tasks[$task_name]['task_args']['account_info']['mwp_amazon_s3'];
|
3017 |
$args['backup_file'] = $amazons3_file;
|
3018 |
$this->remove_amazons3_backup($args);
|
3019 |
}
|
3020 |
+
|
3021 |
if (isset($backup['dropbox'])) {
|
3022 |
+
$dropbox_file = $backup['dropbox'];
|
3023 |
$args = $tasks[$task_name]['task_args']['account_info']['mwp_dropbox'];
|
3024 |
$args['backup_file'] = $dropbox_file;
|
3025 |
$this->remove_dropbox_backup($args);
|
3026 |
}
|
3027 |
+
|
3028 |
if (isset($backup['google_drive'])) {
|
3029 |
+
$google_drive_file = $backup['google_drive'];
|
3030 |
+
$args = $tasks[$task_name]['task_args']['account_info']['mwp_google_drive'];
|
3031 |
+
$args['backup_file'] = $google_drive_file;
|
3032 |
+
$this->remove_google_drive_backup($args);
|
3033 |
}
|
3034 |
+
|
3035 |
unset($backups[$result_id]);
|
3036 |
+
|
3037 |
if (count($backups)) {
|
3038 |
$tasks[$task_name]['task_results'] = $backups;
|
3039 |
} else {
|
3040 |
unset($tasks[$task_name]['task_results']);
|
3041 |
}
|
3042 |
+
|
3043 |
$this->update_tasks($tasks);
|
3044 |
//update_option('mwp_backup_tasks', $tasks);
|
3045 |
return true;
|
3046 |
}
|
3047 |
+
|
3048 |
/**
|
3049 |
* Deletes all unneeded files produced by backup process.
|
3050 |
+
*
|
3051 |
* @return array array of deleted files
|
3052 |
*/
|
3053 |
function cleanup() {
|
3056 |
$backup_folder_new = MWP_BACKUP_DIR . '/';
|
3057 |
$files = glob($backup_folder . "*");
|
3058 |
$new = glob($backup_folder_new . "*");
|
3059 |
+
|
3060 |
//Failed db files first
|
3061 |
$db_folder = MWP_DB_DIR . '/';
|
3062 |
$db_files = glob($db_folder . "*");
|
3064 |
foreach ($db_files as $file) {
|
3065 |
@unlink($file);
|
3066 |
}
|
3067 |
+
@unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
|
3068 |
@rmdir(MWP_DB_DIR);
|
3069 |
}
|
3070 |
+
|
3071 |
//clean_old folder?
|
3072 |
if ((isset($files[0]) && basename($files[0]) == 'index.php' && count($files) == 1) || (empty($files))) {
|
3073 |
if (!empty($files)) {
|
3074 |
+
foreach ($files as $file) {
|
3075 |
+
@unlink($file);
|
3076 |
+
}
|
3077 |
}
|
3078 |
@rmdir(WP_CONTENT_DIR . '/' . md5('mmb-worker') . '/mwp_backups');
|
3079 |
@rmdir(WP_CONTENT_DIR . '/' . md5('mmb-worker'));
|
3080 |
}
|
3081 |
+
|
3082 |
if (!empty($new)) {
|
3083 |
+
foreach ($new as $b) {
|
3084 |
+
$files[] = $b;
|
3085 |
+
}
|
3086 |
}
|
3087 |
$deleted = array();
|
3088 |
+
|
3089 |
if (is_array($files) && count($files)) {
|
3090 |
$results = array();
|
3091 |
if (!empty($tasks)) {
|
3099 |
}
|
3100 |
}
|
3101 |
}
|
3102 |
+
|
3103 |
$num_deleted = 0;
|
3104 |
foreach ($files as $file) {
|
3105 |
if (!in_array($file, $results) && basename($file) != 'index.php') {
|
3109 |
}
|
3110 |
}
|
3111 |
}
|
3112 |
+
|
3113 |
return $deleted;
|
3114 |
}
|
3115 |
+
|
3116 |
/**
|
3117 |
* Uploads to remote destination in the second step, invoked from master.
|
3118 |
+
*
|
3119 |
* @param array $args arguments passed to function
|
3120 |
* [task_name] -> name of backup task
|
3121 |
* @return array|void void if success, array with error message if not
|
3122 |
*/
|
3123 |
function remote_backup_now($args) {
|
3124 |
+
$this->set_memory();
|
3125 |
if (!empty($args))
|
3126 |
extract($args);
|
3127 |
+
|
3128 |
$tasks = $this->tasks;
|
3129 |
$task = $tasks[$task_name];
|
3130 |
+
|
3131 |
if (!empty($task)) {
|
3132 |
extract($task['task_args']);
|
3133 |
}
|
3134 |
+
|
3135 |
$results = $task['task_results'];
|
3136 |
+
|
3137 |
if (is_array($results) && count($results)) {
|
3138 |
$backup_file = $results[count($results) - 1]['server']['file_path'];
|
3139 |
}
|
3140 |
+
|
3141 |
if ($backup_file && file_exists($backup_file)) {
|
3142 |
//FTP, Amazon S3, Dropbox or Google Drive
|
3143 |
if (isset($account_info['mwp_ftp']) && !empty($account_info['mwp_ftp'])) {
|
3144 |
+
$this->update_status($task_name, $this->statuses['ftp']);
|
3145 |
+
$account_info['mwp_ftp']['backup_file'] = $backup_file;
|
3146 |
$return = $this->ftp_backup($account_info['mwp_ftp']);
|
3147 |
$this->wpdb_reconnect();
|
3148 |
+
|
3149 |
+
if (!(is_array($return) && isset($return['error']))) {
|
3150 |
+
$this->update_status($task_name, $this->statuses['ftp'], true);
|
3151 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
3152 |
+
}
|
3153 |
+
}
|
3154 |
+
|
3155 |
+
if (isset($account_info['mwp_sftp']) && !empty($account_info['mwp_sftp'])) {
|
3156 |
+
$this->update_status($task_name, $this->statuses['sftp']);
|
3157 |
+
$account_info['mwp_sftp']['backup_file'] = $backup_file;
|
3158 |
+
$return = $this->sftp_backup($account_info['mwp_sftp']);
|
3159 |
+
$this->wpdb_reconnect();
|
3160 |
+
|
3161 |
if (!(is_array($return) && isset($return['error']))) {
|
3162 |
+
$this->update_status($task_name, $this->statuses['sftp'], true);
|
3163 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
3164 |
}
|
3165 |
}
|
3166 |
+
|
3167 |
if (isset($account_info['mwp_amazon_s3']) && !empty($account_info['mwp_amazon_s3'])) {
|
3168 |
+
$this->update_status($task_name, $this->statuses['s3']);
|
3169 |
+
$account_info['mwp_amazon_s3']['backup_file'] = $backup_file;
|
3170 |
$return = $this->amazons3_backup($account_info['mwp_amazon_s3']);
|
3171 |
$this->wpdb_reconnect();
|
3172 |
+
|
3173 |
if (!(is_array($return) && isset($return['error']))) {
|
3174 |
+
$this->update_status($task_name, $this->statuses['s3'], true);
|
3175 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
3176 |
}
|
3177 |
}
|
3178 |
+
|
3179 |
if (isset($account_info['mwp_dropbox']) && !empty($account_info['mwp_dropbox'])) {
|
3180 |
+
$this->update_status($task_name, $this->statuses['dropbox']);
|
3181 |
+
$account_info['mwp_dropbox']['backup_file'] = $backup_file;
|
3182 |
$return = $this->dropbox_backup($account_info['mwp_dropbox']);
|
3183 |
$this->wpdb_reconnect();
|
3184 |
+
|
3185 |
if (!(is_array($return) && isset($return['error']))) {
|
3186 |
+
$this->update_status($task_name, $this->statuses['dropbox'], true);
|
3187 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
3188 |
}
|
3189 |
}
|
3190 |
+
|
3191 |
if (isset($account_info['mwp_email']) && !empty($account_info['mwp_email'])) {
|
3192 |
+
$this->update_status($task_name, $this->statuses['email']);
|
3193 |
+
$account_info['mwp_email']['task_name'] = $task_name;
|
3194 |
+
$account_info['mwp_email']['file_path'] = $backup_file;
|
3195 |
$return = $this->email_backup($account_info['mwp_email']);
|
3196 |
$this->wpdb_reconnect();
|
3197 |
+
|
3198 |
if (!(is_array($return) && isset($return['error']))) {
|
3199 |
+
$this->update_status($task_name, $this->statuses['email'], true);
|
3200 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
3201 |
}
|
3202 |
}
|
3203 |
+
|
3204 |
if (isset($account_info['mwp_google_drive']) && !empty($account_info['mwp_google_drive'])) {
|
3205 |
+
$this->update_status($task_name, $this->statuses['google_drive']);
|
3206 |
+
$account_info['mwp_google_drive']['backup_file'] = $backup_file;
|
3207 |
+
$return = $this->google_drive_backup($account_info['mwp_google_drive']);
|
3208 |
+
$this->wpdb_reconnect();
|
3209 |
+
|
3210 |
+
if (!(is_array($return) && isset($return['error']))) {
|
3211 |
+
$this->update_status($task_name, $this->statuses['google_drive'], true);
|
3212 |
+
$this->update_status($task_name, $this->statuses['finished'], true);
|
3213 |
+
}
|
3214 |
+
}
|
3215 |
+
|
3216 |
$tasks = $this->tasks;
|
3217 |
@file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
|
3218 |
if ($return == true && $del_host_file) {
|
3220 |
unset($tasks[$task_name]['task_results'][count($tasks[$task_name]['task_results']) - 1]['server']);
|
3221 |
}
|
3222 |
$this->update_tasks($tasks);
|
|
|
3223 |
} else {
|
3224 |
$return = array(
|
3225 |
'error' => 'Backup file not found on your server. Please try again.'
|
3226 |
);
|
3227 |
}
|
3228 |
+
|
3229 |
return $return;
|
3230 |
}
|
3231 |
+
|
3232 |
/**
|
3233 |
* Checks if scheduled backup tasks should be executed.
|
3234 |
+
*
|
3235 |
* @param array $args arguments passed to function
|
3236 |
* [task_name] -> name of backup task
|
3237 |
* [task_id] -> id of backup task
|
3239 |
* [worker_version] -> version of worker
|
3240 |
* [mwp_google_drive_refresh_token] -> should be Google Drive token be refreshed, true if it is remote destination of task
|
3241 |
* @param string $url url on master where worker validate task
|
3242 |
+
* @return string|array|boolean
|
3243 |
*/
|
3244 |
function validate_task($args, $url) {
|
3245 |
if (!class_exists('WP_Http')) {
|
3246 |
include_once(ABSPATH . WPINC . '/class-http.php');
|
3247 |
}
|
3248 |
+
|
3249 |
$worker_upto_3_9_22 = (MMB_WORKER_VERSION <= '3.9.22'); // worker version is less or equals to 3.9.22
|
3250 |
$params = array('timeout'=>100);
|
3251 |
$params['body'] = $args;
|
3252 |
$result = wp_remote_post($url, $params);
|
3253 |
+
|
3254 |
if ($worker_upto_3_9_22) {
|
3255 |
+
if (is_array($result) && $result['body'] == 'mwp_delete_task') {
|
3256 |
+
//$tasks = $this->get_backup_settings();
|
3257 |
+
$tasks = $this->tasks;
|
3258 |
unset($tasks[$args['task_name']]);
|
3259 |
+
$this->update_tasks($tasks);
|
3260 |
+
$this->cleanup();
|
3261 |
+
return 'deleted';
|
3262 |
+
} elseif(is_array($result) && $result['body'] == 'mwp_pause_task'){
|
3263 |
+
return 'paused';
|
3264 |
+
} elseif(is_array($result) && substr($result['body'], 0, 8) == 'token - '){
|
3265 |
+
return $result['body'];
|
3266 |
+
}
|
3267 |
} else {
|
3268 |
+
if (is_array($result) && $result['body']) {
|
3269 |
+
$response = unserialize($result['body']);
|
3270 |
+
if ($response['message'] == 'mwp_delete_task') {
|
3271 |
+
$tasks = $this->tasks;
|
3272 |
unset($tasks[$args['task_name']]);
|
3273 |
+
$this->update_tasks($tasks);
|
3274 |
+
$this->cleanup();
|
3275 |
return 'deleted';
|
3276 |
+
} elseif ($response['message'] == 'mwp_pause_task') {
|
3277 |
+
return 'paused';
|
3278 |
+
} elseif ($response['message'] == 'mwp_do_task') {
|
3279 |
+
return $response;
|
3280 |
+
}
|
3281 |
+
}
|
3282 |
+
}
|
3283 |
+
|
3284 |
+
return false;
|
3285 |
}
|
3286 |
+
|
3287 |
/**
|
3288 |
* Updates status of backup task.
|
3289 |
* Positive number if completed, negative if not.
|
3290 |
+
*
|
3291 |
* @param string $task_name name of backup task
|
3292 |
* @param int $status status which tasks should be updated to
|
3293 |
* (
|
3318 |
$status_index = count($tasks[$task_name]['task_results'][$index]['status']) - 1;
|
3319 |
$tasks[$task_name]['task_results'][$index]['status'][$status_index] = abs($tasks[$task_name]['task_results'][$index]['status'][$status_index]);
|
3320 |
}
|
3321 |
+
|
3322 |
$this->update_tasks($tasks);
|
3323 |
//update_option('mwp_backup_tasks',$tasks);
|
3324 |
}
|
3325 |
}
|
3326 |
+
|
3327 |
/**
|
3328 |
* Update $this->tasks attribute and save it to wp_options with key mwp_backup_tasks.
|
3329 |
+
*
|
3330 |
* @param mixed $tasks associative array with all tasks data
|
3331 |
* @return void
|
3332 |
*/
|
3334 |
$this->tasks = $tasks;
|
3335 |
update_option('mwp_backup_tasks', $tasks);
|
3336 |
}
|
3337 |
+
|
3338 |
/**
|
3339 |
* Reconnects to database to avoid timeout problem after ZIP files.
|
3340 |
+
*
|
3341 |
* @return void
|
3342 |
*/
|
3343 |
function wpdb_reconnect() {
|
3344 |
+
global $wpdb;
|
3345 |
+
|
3346 |
+
if(class_exists('wpdb') && function_exists('wp_set_wpdb_vars')){
|
3347 |
+
@mysql_close($wpdb->dbh);
|
3348 |
+
$wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
|
3349 |
+
wp_set_wpdb_vars();
|
3350 |
+
}
|
3351 |
}
|
3352 |
+
|
3353 |
/**
|
3354 |
* Replaces .htaccess file in process of restoring WordPress site.
|
3355 |
+
*
|
3356 |
* @param string $url url of current site
|
3357 |
* @return void
|
3358 |
*/
|
3359 |
+
function replace_htaccess($url) {
|
3360 |
+
$file = @file_get_contents(ABSPATH.'.htaccess');
|
3361 |
+
if ($file && strlen($file)) {
|
3362 |
+
$args = parse_url($url);
|
3363 |
+
$string = rtrim($args['path'], "/");
|
3364 |
+
$regex = "/BEGIN WordPress(.*?)RewriteBase(.*?)\n(.*?)RewriteRule \.(.*?)index\.php(.*?)END WordPress/sm";
|
3365 |
+
$replace = "BEGIN WordPress$1RewriteBase " . $string . "/ \n$3RewriteRule . " . $string . "/index.php$5END WordPress";
|
3366 |
+
$file = preg_replace($regex, $replace, $file);
|
3367 |
+
@file_put_contents(ABSPATH.'.htaccess', $file);
|
3368 |
+
}
|
3369 |
+
}
|
3370 |
+
|
3371 |
+
/**
|
3372 |
+
* Removes cron for checking scheduled tasks, if there are not any scheduled task.
|
3373 |
+
*
|
3374 |
+
* @return void
|
3375 |
+
*/
|
3376 |
+
function check_cron_remove() {
|
3377 |
+
if(empty($this->tasks) || (count($this->tasks) == 1 && isset($this->tasks['Backup Now'])) ){
|
3378 |
+
wp_clear_scheduled_hook('mwp_backup_tasks');
|
3379 |
+
exit;
|
3380 |
+
}
|
3381 |
+
}
|
3382 |
+
|
3383 |
+
/**
|
3384 |
+
* Re-add tasks on website re-add.
|
3385 |
+
*
|
3386 |
+
* @param array $params arguments passed to function
|
3387 |
+
* @return array $params without backups
|
3388 |
+
*/
|
3389 |
+
public function readd_tasks($params = array()) {
|
3390 |
+
global $mmb_core;
|
3391 |
+
|
3392 |
+
if( empty($params) || !isset($params['backups']) )
|
3393 |
+
return $params;
|
3394 |
+
|
3395 |
+
$before = array();
|
3396 |
+
$tasks = $params['backups'];
|
3397 |
+
if( !empty($tasks) ){
|
3398 |
+
$mmb_backup = new MMB_Backup();
|
3399 |
+
|
3400 |
+
if( function_exists( 'wp_next_scheduled' ) ){
|
3401 |
+
if ( !wp_next_scheduled('mwp_backup_tasks') ) {
|
3402 |
+
wp_schedule_event( time(), 'tenminutes', 'mwp_backup_tasks' );
|
3403 |
+
}
|
3404 |
+
}
|
3405 |
+
|
3406 |
+
foreach( $tasks as $task ){
|
3407 |
+
$before[$task['task_name']] = array();
|
3408 |
+
|
3409 |
+
if(isset($task['secure'])){
|
3410 |
+
if($decrypted = $mmb_core->_secure_data($task['secure'])){
|
3411 |
+
$decrypted = maybe_unserialize($decrypted);
|
3412 |
+
if(is_array($decrypted)){
|
3413 |
+
foreach($decrypted as $key => $val){
|
3414 |
+
if(!is_numeric($key))
|
3415 |
+
$task[$key] = $val;
|
3416 |
+
}
|
3417 |
+
unset($task['secure']);
|
3418 |
+
} else
|
3419 |
+
$task['secure'] = $decrypted;
|
3420 |
+
}
|
3421 |
+
|
3422 |
+
}
|
3423 |
+
if (isset($task['account_info']) && is_array($task['account_info'])) { //only if sends from master first time(secure data)
|
3424 |
+
$task['args']['account_info'] = $task['account_info'];
|
3425 |
+
}
|
3426 |
+
|
3427 |
+
$before[$task['task_name']]['task_args'] = $task['args'];
|
3428 |
+
$before[$task['task_name']]['task_args']['next'] = $mmb_backup->schedule_next($task['args']['type'], $task['args']['schedule']);
|
3429 |
+
}
|
3430 |
+
}
|
3431 |
+
update_option('mwp_backup_tasks', $before);
|
3432 |
+
|
3433 |
+
unset($params['backups']);
|
3434 |
+
return $params;
|
3435 |
+
}
|
3436 |
+
|
3437 |
}
|
3438 |
|
3439 |
/*if( function_exists('add_filter') ) {
|
3441 |
}*/
|
3442 |
|
3443 |
if(!function_exists('get_all_files_from_dir')) {
|
3444 |
+
/**
|
3445 |
+
* Get all files in directory
|
3446 |
+
*
|
3447 |
+
* @param string $path Relative or absolute path to folder
|
3448 |
+
* @param array $exclude List of excluded files or folders, relative to $path
|
3449 |
+
* @return array List of all files in folder $path, exclude all files in $exclude array
|
3450 |
+
*/
|
3451 |
+
function get_all_files_from_dir($path, $exclude = array()) {
|
3452 |
+
if ($path[strlen($path) - 1] === "/") $path = substr($path, 0, -1);
|
3453 |
+
global $directory_tree, $ignore_array;
|
3454 |
+
$directory_tree = array();
|
3455 |
+
foreach ($exclude as $file) {
|
3456 |
+
if (!in_array($file, array('.', '..'))) {
|
3457 |
+
if ($file[0] === "/") $path = substr($file, 1);
|
3458 |
+
$ignore_array[] = "$path/$file";
|
3459 |
+
}
|
3460 |
+
}
|
3461 |
+
get_all_files_from_dir_recursive($path);
|
3462 |
+
return $directory_tree;
|
3463 |
+
}
|
3464 |
}
|
3465 |
|
3466 |
if (!function_exists('get_all_files_from_dir_recursive')) {
|
3467 |
+
/**
|
3468 |
+
* Get all files in directory,
|
3469 |
+
* wrapped function which writes in global variable
|
3470 |
+
* and exclued files or folders are read from global variable
|
3471 |
+
*
|
3472 |
+
* @param string $path Relative or absolute path to folder
|
3473 |
+
* @return void
|
3474 |
+
*/
|
3475 |
+
function get_all_files_from_dir_recursive($path) {
|
3476 |
+
if ($path[strlen($path) - 1] === "/") $path = substr($path, 0, -1);
|
3477 |
+
global $directory_tree, $ignore_array;
|
3478 |
+
$directory_tree_temp = array();
|
3479 |
+
$dh = @opendir($path);
|
3480 |
+
|
3481 |
+
while (false !== ($file = @readdir($dh))) {
|
3482 |
+
if (!in_array($file, array('.', '..'))) {
|
3483 |
+
if (!in_array("$path/$file", $ignore_array)) {
|
3484 |
+
if (!is_dir("$path/$file")) {
|
3485 |
+
$directory_tree[] = "$path/$file";
|
3486 |
+
} else {
|
3487 |
+
get_all_files_from_dir_recursive("$path/$file");
|
3488 |
+
}
|
3489 |
+
}
|
3490 |
+
}
|
3491 |
+
}
|
3492 |
+
@closedir($dh);
|
3493 |
+
}
|
3494 |
}
|
3495 |
|
3496 |
?>
|
init.php
CHANGED
@@ -4,7 +4,7 @@ Plugin Name: ManageWP - Worker
|
|
4 |
Plugin URI: http://managewp.com/
|
5 |
Description: Manage Multiple WordPress sites from one dashboard. Visit <a href="https://managewp.com">ManageWP.com</a> to sign up.
|
6 |
Author: ManageWP
|
7 |
-
Version: 3.9.
|
8 |
Author URI: http://managewp.com
|
9 |
*/
|
10 |
|
@@ -22,7 +22,7 @@ if(basename($_SERVER['SCRIPT_FILENAME']) == "init.php"):
|
|
22 |
exit;
|
23 |
endif;
|
24 |
if(!defined('MMB_WORKER_VERSION'))
|
25 |
-
define('MMB_WORKER_VERSION', '3.9.
|
26 |
|
27 |
if ( !defined('MMB_XFRAME_COOKIE')){
|
28 |
$siteurl = function_exists( 'get_site_option' ) ? get_site_option( 'siteurl' ) : get_option( 'siteurl' );
|
4 |
Plugin URI: http://managewp.com/
|
5 |
Description: Manage Multiple WordPress sites from one dashboard. Visit <a href="https://managewp.com">ManageWP.com</a> to sign up.
|
6 |
Author: ManageWP
|
7 |
+
Version: 3.9.27
|
8 |
Author URI: http://managewp.com
|
9 |
*/
|
10 |
|
22 |
exit;
|
23 |
endif;
|
24 |
if(!defined('MMB_WORKER_VERSION'))
|
25 |
+
define('MMB_WORKER_VERSION', '3.9.27');
|
26 |
|
27 |
if ( !defined('MMB_XFRAME_COOKIE')){
|
28 |
$siteurl = function_exists( 'get_site_option' ) ? get_site_option( 'siteurl' ) : get_option( 'siteurl' );
|
installer.class.php
CHANGED
@@ -212,7 +212,7 @@ class MMB_Installer extends MMB_Core
|
|
212 |
function upgrade_core($current)
|
213 |
{
|
214 |
ob_start();
|
215 |
-
|
216 |
include_once(ABSPATH . '/wp-admin/includes/update.php');
|
217 |
|
218 |
@wp_version_check();
|
212 |
function upgrade_core($current)
|
213 |
{
|
214 |
ob_start();
|
215 |
+
if (!function_exists('wp_version_check') || !function_exists('get_core_checksums'))
|
216 |
include_once(ABSPATH . '/wp-admin/includes/update.php');
|
217 |
|
218 |
@wp_version_check();
|
lib/PHPSecLib/Crypt/AES.php
ADDED
@@ -0,0 +1,540 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of AES.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
12 |
+
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
|
13 |
+
* it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
|
14 |
+
* is called, again, at which point, it'll be recalculated.
|
15 |
+
*
|
16 |
+
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
|
17 |
+
* make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
|
18 |
+
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
|
19 |
+
*
|
20 |
+
* Here's a short example of how to use this library:
|
21 |
+
* <code>
|
22 |
+
* <?php
|
23 |
+
* include('Crypt/AES.php');
|
24 |
+
*
|
25 |
+
* $aes = new Crypt_AES();
|
26 |
+
*
|
27 |
+
* $aes->setKey('abcdefghijklmnop');
|
28 |
+
*
|
29 |
+
* $size = 10 * 1024;
|
30 |
+
* $plaintext = '';
|
31 |
+
* for ($i = 0; $i < $size; $i++) {
|
32 |
+
* $plaintext.= 'a';
|
33 |
+
* }
|
34 |
+
*
|
35 |
+
* echo $aes->decrypt($aes->encrypt($plaintext));
|
36 |
+
* ?>
|
37 |
+
* </code>
|
38 |
+
*
|
39 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
40 |
+
* of this software and associated documentation files (the "Software"), to deal
|
41 |
+
* in the Software without restriction, including without limitation the rights
|
42 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
43 |
+
* copies of the Software, and to permit persons to whom the Software is
|
44 |
+
* furnished to do so, subject to the following conditions:
|
45 |
+
*
|
46 |
+
* The above copyright notice and this permission notice shall be included in
|
47 |
+
* all copies or substantial portions of the Software.
|
48 |
+
*
|
49 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
50 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
51 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
52 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
53 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
54 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
55 |
+
* THE SOFTWARE.
|
56 |
+
*
|
57 |
+
* @category Crypt
|
58 |
+
* @package Crypt_AES
|
59 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
60 |
+
* @copyright MMVIII Jim Wigginton
|
61 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
62 |
+
* @link http://phpseclib.sourceforge.net
|
63 |
+
*/
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Include Crypt_Rijndael
|
67 |
+
*/
|
68 |
+
if (!class_exists('Crypt_Rijndael')) {
|
69 |
+
require_once 'Rijndael.php';
|
70 |
+
}
|
71 |
+
|
72 |
+
/**#@+
|
73 |
+
* @access public
|
74 |
+
* @see Crypt_AES::encrypt()
|
75 |
+
* @see Crypt_AES::decrypt()
|
76 |
+
*/
|
77 |
+
/**
|
78 |
+
* Encrypt / decrypt using the Counter mode.
|
79 |
+
*
|
80 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
81 |
+
*
|
82 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
83 |
+
*/
|
84 |
+
define('CRYPT_AES_MODE_CTR', -1);
|
85 |
+
/**
|
86 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
87 |
+
*
|
88 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
89 |
+
*/
|
90 |
+
define('CRYPT_AES_MODE_ECB', 1);
|
91 |
+
/**
|
92 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
93 |
+
*
|
94 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
95 |
+
*/
|
96 |
+
define('CRYPT_AES_MODE_CBC', 2);
|
97 |
+
/**
|
98 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
99 |
+
*
|
100 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
101 |
+
*/
|
102 |
+
define('CRYPT_AES_MODE_CFB', 3);
|
103 |
+
/**
|
104 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
105 |
+
*
|
106 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
107 |
+
*/
|
108 |
+
define('CRYPT_AES_MODE_OFB', 4);
|
109 |
+
/**#@-*/
|
110 |
+
|
111 |
+
/**#@+
|
112 |
+
* @access private
|
113 |
+
* @see Crypt_AES::Crypt_AES()
|
114 |
+
*/
|
115 |
+
/**
|
116 |
+
* Toggles the internal implementation
|
117 |
+
*/
|
118 |
+
define('CRYPT_AES_MODE_INTERNAL', 1);
|
119 |
+
/**
|
120 |
+
* Toggles the mcrypt implementation
|
121 |
+
*/
|
122 |
+
define('CRYPT_AES_MODE_MCRYPT', 2);
|
123 |
+
/**#@-*/
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Pure-PHP implementation of AES.
|
127 |
+
*
|
128 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
129 |
+
* @version 0.1.0
|
130 |
+
* @access public
|
131 |
+
* @package Crypt_AES
|
132 |
+
*/
|
133 |
+
class Crypt_AES extends Crypt_Rijndael {
|
134 |
+
/**
|
135 |
+
* mcrypt resource for encryption
|
136 |
+
*
|
137 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
138 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
139 |
+
*
|
140 |
+
* @see Crypt_AES::encrypt()
|
141 |
+
* @var String
|
142 |
+
* @access private
|
143 |
+
*/
|
144 |
+
var $enmcrypt;
|
145 |
+
|
146 |
+
/**
|
147 |
+
* mcrypt resource for decryption
|
148 |
+
*
|
149 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
150 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
151 |
+
*
|
152 |
+
* @see Crypt_AES::decrypt()
|
153 |
+
* @var String
|
154 |
+
* @access private
|
155 |
+
*/
|
156 |
+
var $demcrypt;
|
157 |
+
|
158 |
+
/**
|
159 |
+
* mcrypt resource for CFB mode
|
160 |
+
*
|
161 |
+
* @see Crypt_AES::encrypt()
|
162 |
+
* @see Crypt_AES::decrypt()
|
163 |
+
* @var String
|
164 |
+
* @access private
|
165 |
+
*/
|
166 |
+
var $ecb;
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Default Constructor.
|
170 |
+
*
|
171 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
172 |
+
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
|
173 |
+
*
|
174 |
+
* @param optional Integer $mode
|
175 |
+
* @return Crypt_AES
|
176 |
+
* @access public
|
177 |
+
*/
|
178 |
+
function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
|
179 |
+
{
|
180 |
+
if ( !defined('CRYPT_AES_MODE') ) {
|
181 |
+
switch (true) {
|
182 |
+
case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()):
|
183 |
+
define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
|
184 |
+
break;
|
185 |
+
default:
|
186 |
+
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
switch ( CRYPT_AES_MODE ) {
|
191 |
+
case CRYPT_AES_MODE_MCRYPT:
|
192 |
+
switch ($mode) {
|
193 |
+
case CRYPT_AES_MODE_ECB:
|
194 |
+
$this->paddable = true;
|
195 |
+
$this->mode = MCRYPT_MODE_ECB;
|
196 |
+
break;
|
197 |
+
case CRYPT_AES_MODE_CTR:
|
198 |
+
// ctr doesn't have a constant associated with it even though it appears to be fairly widely
|
199 |
+
// supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
|
200 |
+
// include a compatibility layer. the layer has been implemented but, for now, is commented out.
|
201 |
+
$this->mode = 'ctr';
|
202 |
+
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
|
203 |
+
break;
|
204 |
+
case CRYPT_AES_MODE_CFB:
|
205 |
+
$this->mode = 'ncfb';
|
206 |
+
break;
|
207 |
+
case CRYPT_AES_MODE_OFB:
|
208 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
209 |
+
break;
|
210 |
+
case CRYPT_AES_MODE_CBC:
|
211 |
+
default:
|
212 |
+
$this->paddable = true;
|
213 |
+
$this->mode = MCRYPT_MODE_CBC;
|
214 |
+
}
|
215 |
+
|
216 |
+
break;
|
217 |
+
default:
|
218 |
+
switch ($mode) {
|
219 |
+
case CRYPT_AES_MODE_ECB:
|
220 |
+
$this->paddable = true;
|
221 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_ECB;
|
222 |
+
break;
|
223 |
+
case CRYPT_AES_MODE_CTR:
|
224 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CTR;
|
225 |
+
break;
|
226 |
+
case CRYPT_AES_MODE_CFB:
|
227 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CFB;
|
228 |
+
break;
|
229 |
+
case CRYPT_AES_MODE_OFB:
|
230 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_OFB;
|
231 |
+
break;
|
232 |
+
case CRYPT_AES_MODE_CBC:
|
233 |
+
default:
|
234 |
+
$this->paddable = true;
|
235 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
|
240 |
+
parent::Crypt_Rijndael($this->mode);
|
241 |
+
}
|
242 |
+
|
243 |
+
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Dummy function
|
247 |
+
*
|
248 |
+
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
|
249 |
+
*
|
250 |
+
* @access public
|
251 |
+
* @param Integer $length
|
252 |
+
*/
|
253 |
+
function setBlockLength($length)
|
254 |
+
{
|
255 |
+
return;
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Sets the initialization vector. (optional)
|
260 |
+
*
|
261 |
+
* SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
|
262 |
+
* to be all zero's.
|
263 |
+
*
|
264 |
+
* @access public
|
265 |
+
* @param String $iv
|
266 |
+
*/
|
267 |
+
function setIV($iv)
|
268 |
+
{
|
269 |
+
parent::setIV($iv);
|
270 |
+
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
271 |
+
$this->changed = true;
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Encrypts a message.
|
277 |
+
*
|
278 |
+
* $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
|
279 |
+
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
280 |
+
* URL:
|
281 |
+
*
|
282 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
283 |
+
*
|
284 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
285 |
+
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
|
286 |
+
* length.
|
287 |
+
*
|
288 |
+
* @see Crypt_AES::decrypt()
|
289 |
+
* @access public
|
290 |
+
* @param String $plaintext
|
291 |
+
*/
|
292 |
+
function encrypt($plaintext)
|
293 |
+
{
|
294 |
+
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
295 |
+
$this->_mcryptSetup();
|
296 |
+
|
297 |
+
// re: http://phpseclib.sourceforge.net/cfb-demo.phps
|
298 |
+
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
|
299 |
+
// rewritten CFB implementation the above outputs the same thing twice.
|
300 |
+
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
301 |
+
$iv = &$this->encryptIV;
|
302 |
+
$pos = &$this->enbuffer['pos'];
|
303 |
+
$len = strlen($plaintext);
|
304 |
+
$ciphertext = '';
|
305 |
+
$i = 0;
|
306 |
+
if ($pos) {
|
307 |
+
$orig_pos = $pos;
|
308 |
+
$max = 16 - $pos;
|
309 |
+
if ($len >= $max) {
|
310 |
+
$i = $max;
|
311 |
+
$len-= $max;
|
312 |
+
$pos = 0;
|
313 |
+
} else {
|
314 |
+
$i = $len;
|
315 |
+
$pos+= $len;
|
316 |
+
$len = 0;
|
317 |
+
}
|
318 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
319 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
320 |
+
$this->enbuffer['enmcrypt_init'] = true;
|
321 |
+
}
|
322 |
+
if ($len >= 16) {
|
323 |
+
if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) {
|
324 |
+
if ($this->enbuffer['enmcrypt_init'] === true) {
|
325 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
326 |
+
$this->enbuffer['enmcrypt_init'] = false;
|
327 |
+
}
|
328 |
+
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
|
329 |
+
$iv = substr($ciphertext, -16);
|
330 |
+
$len%= 16;
|
331 |
+
} else {
|
332 |
+
while ($len >= 16) {
|
333 |
+
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16);
|
334 |
+
$ciphertext.= $iv;
|
335 |
+
$len-= 16;
|
336 |
+
$i+= 16;
|
337 |
+
}
|
338 |
+
}
|
339 |
+
}
|
340 |
+
|
341 |
+
if ($len) {
|
342 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
343 |
+
$block = $iv ^ substr($plaintext, -$len);
|
344 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
345 |
+
$ciphertext.= $block;
|
346 |
+
$pos = $len;
|
347 |
+
}
|
348 |
+
|
349 |
+
return $ciphertext;
|
350 |
+
}
|
351 |
+
|
352 |
+
if ($this->paddable) {
|
353 |
+
$plaintext = $this->_pad($plaintext);
|
354 |
+
}
|
355 |
+
|
356 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
357 |
+
|
358 |
+
if (!$this->continuousBuffer) {
|
359 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
360 |
+
}
|
361 |
+
|
362 |
+
return $ciphertext;
|
363 |
+
}
|
364 |
+
|
365 |
+
return parent::encrypt($plaintext);
|
366 |
+
}
|
367 |
+
|
368 |
+
/**
|
369 |
+
* Decrypts a message.
|
370 |
+
*
|
371 |
+
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
|
372 |
+
*
|
373 |
+
* @see Crypt_AES::encrypt()
|
374 |
+
* @access public
|
375 |
+
* @param String $ciphertext
|
376 |
+
*/
|
377 |
+
function decrypt($ciphertext)
|
378 |
+
{
|
379 |
+
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
380 |
+
$this->_mcryptSetup();
|
381 |
+
|
382 |
+
if ($this->mode == 'ncfb' && $this->continuousBuffer) {
|
383 |
+
$iv = &$this->decryptIV;
|
384 |
+
$pos = &$this->debuffer['pos'];
|
385 |
+
$len = strlen($ciphertext);
|
386 |
+
$plaintext = '';
|
387 |
+
$i = 0;
|
388 |
+
if ($pos) {
|
389 |
+
$orig_pos = $pos;
|
390 |
+
$max = 16 - $pos;
|
391 |
+
if ($len >= $max) {
|
392 |
+
$i = $max;
|
393 |
+
$len-= $max;
|
394 |
+
$pos = 0;
|
395 |
+
} else {
|
396 |
+
$i = $len;
|
397 |
+
$pos+= $len;
|
398 |
+
$len = 0;
|
399 |
+
}
|
400 |
+
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
|
401 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
402 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
403 |
+
}
|
404 |
+
if ($len >= 16) {
|
405 |
+
$cb = substr($ciphertext, $i, $len - $len % 16);
|
406 |
+
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
407 |
+
$iv = substr($cb, -16);
|
408 |
+
$len%= 16;
|
409 |
+
}
|
410 |
+
if ($len) {
|
411 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
412 |
+
$plaintext.= $iv ^ substr($ciphertext, -$len);
|
413 |
+
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
|
414 |
+
$pos = $len;
|
415 |
+
}
|
416 |
+
|
417 |
+
return $plaintext;
|
418 |
+
}
|
419 |
+
|
420 |
+
if ($this->paddable) {
|
421 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
422 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
423 |
+
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
|
424 |
+
}
|
425 |
+
|
426 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
427 |
+
|
428 |
+
if (!$this->continuousBuffer) {
|
429 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
430 |
+
}
|
431 |
+
|
432 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
433 |
+
}
|
434 |
+
|
435 |
+
return parent::decrypt($ciphertext);
|
436 |
+
}
|
437 |
+
|
438 |
+
/**
|
439 |
+
* Setup mcrypt
|
440 |
+
*
|
441 |
+
* Validates all the variables.
|
442 |
+
*
|
443 |
+
* @access private
|
444 |
+
*/
|
445 |
+
function _mcryptSetup()
|
446 |
+
{
|
447 |
+
if (!$this->changed) {
|
448 |
+
return;
|
449 |
+
}
|
450 |
+
|
451 |
+
if (!$this->explicit_key_length) {
|
452 |
+
// this just copied from Crypt_Rijndael::_setup()
|
453 |
+
$length = strlen($this->key) >> 2;
|
454 |
+
if ($length > 8) {
|
455 |
+
$length = 8;
|
456 |
+
} else if ($length < 4) {
|
457 |
+
$length = 4;
|
458 |
+
}
|
459 |
+
$this->Nk = $length;
|
460 |
+
$this->key_size = $length << 2;
|
461 |
+
}
|
462 |
+
|
463 |
+
switch ($this->Nk) {
|
464 |
+
case 4: // 128
|
465 |
+
$this->key_size = 16;
|
466 |
+
break;
|
467 |
+
case 5: // 160
|
468 |
+
case 6: // 192
|
469 |
+
$this->key_size = 24;
|
470 |
+
break;
|
471 |
+
case 7: // 224
|
472 |
+
case 8: // 256
|
473 |
+
$this->key_size = 32;
|
474 |
+
}
|
475 |
+
|
476 |
+
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
|
477 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
|
478 |
+
|
479 |
+
if (!isset($this->enmcrypt)) {
|
480 |
+
$mode = $this->mode;
|
481 |
+
//$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
|
482 |
+
|
483 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
484 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
485 |
+
|
486 |
+
if ($mode == 'ncfb') {
|
487 |
+
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
488 |
+
}
|
489 |
+
|
490 |
+
} // else should mcrypt_generic_deinit be called?
|
491 |
+
|
492 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
493 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
494 |
+
|
495 |
+
if ($this->mode == 'ncfb') {
|
496 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
497 |
+
}
|
498 |
+
|
499 |
+
$this->changed = false;
|
500 |
+
}
|
501 |
+
|
502 |
+
/**
|
503 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
504 |
+
*
|
505 |
+
* The default behavior.
|
506 |
+
*
|
507 |
+
* @see Crypt_Rijndael::disableContinuousBuffer()
|
508 |
+
* @access public
|
509 |
+
*/
|
510 |
+
function enableContinuousBuffer()
|
511 |
+
{
|
512 |
+
parent::enableContinuousBuffer();
|
513 |
+
|
514 |
+
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
|
515 |
+
$this->enbuffer['enmcrypt_init'] = true;
|
516 |
+
$this->debuffer['demcrypt_init'] = true;
|
517 |
+
}
|
518 |
+
}
|
519 |
+
|
520 |
+
/**
|
521 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
522 |
+
*
|
523 |
+
* The default behavior.
|
524 |
+
*
|
525 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
526 |
+
* @access public
|
527 |
+
*/
|
528 |
+
function disableContinuousBuffer()
|
529 |
+
{
|
530 |
+
parent::disableContinuousBuffer();
|
531 |
+
|
532 |
+
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
|
533 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
534 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
535 |
+
}
|
536 |
+
}
|
537 |
+
}
|
538 |
+
|
539 |
+
// vim: ts=4:sw=4:et:
|
540 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/Crypt/Blowfish.php
ADDED
@@ -0,0 +1,1468 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of Blowfish.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Useful resources are as follows:
|
12 |
+
*
|
13 |
+
* - {@link http://en.wikipedia.org/wiki/Blowfish Wikipedia description of Blowfish}
|
14 |
+
*
|
15 |
+
* Here's a short example of how to use this library:
|
16 |
+
* <code>
|
17 |
+
* <?php
|
18 |
+
* include('Crypt/Blowfish.php');
|
19 |
+
*
|
20 |
+
* $blowfish = new Crypt_Blowfish();
|
21 |
+
*
|
22 |
+
* $blowfish->setKey('12345678901234567890123456789012');
|
23 |
+
*
|
24 |
+
* $plaintext = str_repeat('a', 1024);
|
25 |
+
*
|
26 |
+
* echo $blowfish->decrypt($blowfish->encrypt($plaintext));
|
27 |
+
* ?>
|
28 |
+
* </code>
|
29 |
+
*
|
30 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
31 |
+
* of this software and associated documentation files (the "Software"), to deal
|
32 |
+
* in the Software without restriction, including without limitation the rights
|
33 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
34 |
+
* copies of the Software, and to permit persons to whom the Software is
|
35 |
+
* furnished to do so, subject to the following conditions:
|
36 |
+
*
|
37 |
+
* The above copyright notice and this permission notice shall be included in
|
38 |
+
* all copies or substantial portions of the Software.
|
39 |
+
*
|
40 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
41 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
42 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
43 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
44 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
45 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
46 |
+
* THE SOFTWARE.
|
47 |
+
*
|
48 |
+
* @category Crypt
|
49 |
+
* @package Crypt_Blowfish
|
50 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
51 |
+
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
|
52 |
+
* @copyright MMVII Jim Wigginton
|
53 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
54 |
+
* @version 1.0
|
55 |
+
* @link http://phpseclib.sourceforge.net
|
56 |
+
*/
|
57 |
+
|
58 |
+
/**#@+
|
59 |
+
* @access public
|
60 |
+
* @see Crypt_Blowfish::encrypt()
|
61 |
+
* @see Crypt_Blowfish::decrypt()
|
62 |
+
*/
|
63 |
+
/**
|
64 |
+
* Encrypt / decrypt using the Counter mode.
|
65 |
+
*
|
66 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
67 |
+
*
|
68 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
69 |
+
*/
|
70 |
+
define('CRYPT_BLOWFISH_MODE_CTR', -1);
|
71 |
+
/**
|
72 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
73 |
+
*
|
74 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
75 |
+
*/
|
76 |
+
define('CRYPT_BLOWFISH_MODE_ECB', 1);
|
77 |
+
/**
|
78 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
79 |
+
*
|
80 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
81 |
+
*/
|
82 |
+
define('CRYPT_BLOWFISH_MODE_CBC', 2);
|
83 |
+
/**
|
84 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
85 |
+
*
|
86 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
87 |
+
*/
|
88 |
+
define('CRYPT_BLOWFISH_MODE_CFB', 3);
|
89 |
+
/**
|
90 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
91 |
+
*
|
92 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
93 |
+
*/
|
94 |
+
define('CRYPT_BLOWFISH_MODE_OFB', 4);
|
95 |
+
/**#@-*/
|
96 |
+
|
97 |
+
/**#@+
|
98 |
+
* @access private
|
99 |
+
* @see Crypt_Blowfish::Crypt_Blowfish()
|
100 |
+
*/
|
101 |
+
/**
|
102 |
+
* Toggles the internal implementation
|
103 |
+
*/
|
104 |
+
define('CRYPT_BLOWFISH_MODE_INTERNAL', 1);
|
105 |
+
/**
|
106 |
+
* Toggles the mcrypt implementation
|
107 |
+
*/
|
108 |
+
define('CRYPT_BLOWFISH_MODE_MCRYPT', 2);
|
109 |
+
/**#@-*/
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Pure-PHP implementation of Blowfish.
|
113 |
+
*
|
114 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
115 |
+
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
|
116 |
+
* @version 1.0
|
117 |
+
* @access public
|
118 |
+
* @package Crypt_Blowfish
|
119 |
+
*/
|
120 |
+
class Crypt_Blowfish {
|
121 |
+
/**
|
122 |
+
* The Key as String
|
123 |
+
*
|
124 |
+
* @see Crypt_Blowfish::setKey()
|
125 |
+
* @var Array
|
126 |
+
* @access private
|
127 |
+
*/
|
128 |
+
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
129 |
+
|
130 |
+
/**
|
131 |
+
* The Encryption Mode
|
132 |
+
*
|
133 |
+
* @see Crypt_Blowfish::Crypt_Blowfish()
|
134 |
+
* @var Integer
|
135 |
+
* @access private
|
136 |
+
*/
|
137 |
+
var $mode;
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Continuous Buffer status
|
141 |
+
*
|
142 |
+
* @see Crypt_Blowfish::enableContinuousBuffer()
|
143 |
+
* @var Boolean
|
144 |
+
* @access private
|
145 |
+
*/
|
146 |
+
var $continuousBuffer = false;
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Padding status
|
150 |
+
*
|
151 |
+
* @see Crypt_Blowfish::enablePadding()
|
152 |
+
* @var Boolean
|
153 |
+
* @access private
|
154 |
+
*/
|
155 |
+
var $padding = true;
|
156 |
+
|
157 |
+
/**
|
158 |
+
* The Initialization Vector
|
159 |
+
*
|
160 |
+
* @see Crypt_Blowfish::setIV()
|
161 |
+
* @var String
|
162 |
+
* @access private
|
163 |
+
*/
|
164 |
+
var $iv = "\0\0\0\0\0\0\0\0";
|
165 |
+
|
166 |
+
/**
|
167 |
+
* A "sliding" Initialization Vector
|
168 |
+
*
|
169 |
+
* @see Crypt_Blowfish::enableContinuousBuffer()
|
170 |
+
* @var String
|
171 |
+
* @access private
|
172 |
+
*/
|
173 |
+
var $encryptIV = "\0\0\0\0\0\0\0\0";
|
174 |
+
|
175 |
+
/**
|
176 |
+
* A "sliding" Initialization Vector
|
177 |
+
*
|
178 |
+
* @see Crypt_Blowfish::enableContinuousBuffer()
|
179 |
+
* @var String
|
180 |
+
* @access private
|
181 |
+
*/
|
182 |
+
var $decryptIV = "\0\0\0\0\0\0\0\0";
|
183 |
+
|
184 |
+
/**
|
185 |
+
* mcrypt resource for encryption
|
186 |
+
*
|
187 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
188 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
189 |
+
*
|
190 |
+
* @see Crypt_Blowfish::encrypt()
|
191 |
+
* @var String
|
192 |
+
* @access private
|
193 |
+
*/
|
194 |
+
var $enmcrypt;
|
195 |
+
|
196 |
+
/**
|
197 |
+
* mcrypt resource for decryption
|
198 |
+
*
|
199 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
200 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
201 |
+
*
|
202 |
+
* @see Crypt_Blowfish::decrypt()
|
203 |
+
* @var String
|
204 |
+
* @access private
|
205 |
+
*/
|
206 |
+
var $demcrypt;
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Does the enmcrypt resource need to be (re)initialized?
|
210 |
+
*
|
211 |
+
* @see Crypt_Blowfish::setKey()
|
212 |
+
* @see Crypt_Blowfish::setIV()
|
213 |
+
* @var Boolean
|
214 |
+
* @access private
|
215 |
+
*/
|
216 |
+
var $enchanged = true;
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Does the demcrypt resource need to be (re)initialized?
|
220 |
+
*
|
221 |
+
* @see Crypt_Blowfish::setKey()
|
222 |
+
* @see Crypt_Blowfish::setIV()
|
223 |
+
* @var Boolean
|
224 |
+
* @access private
|
225 |
+
*/
|
226 |
+
var $dechanged = true;
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Is the mode one that is paddable?
|
230 |
+
*
|
231 |
+
* @see Crypt_Blowfish::Crypt_Blowfish()
|
232 |
+
* @var Boolean
|
233 |
+
* @access private
|
234 |
+
*/
|
235 |
+
var $paddable = false;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
239 |
+
*
|
240 |
+
* @see Crypt_Blowfish::encrypt()
|
241 |
+
* @var Array
|
242 |
+
* @access private
|
243 |
+
*/
|
244 |
+
var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
248 |
+
*
|
249 |
+
* @see Crypt_Blowfish::decrypt()
|
250 |
+
* @var Array
|
251 |
+
* @access private
|
252 |
+
*/
|
253 |
+
var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
254 |
+
|
255 |
+
/**
|
256 |
+
* mcrypt resource for CFB mode
|
257 |
+
*
|
258 |
+
* @see Crypt_Blowfish::encrypt()
|
259 |
+
* @see Crypt_Blowfish::decrypt()
|
260 |
+
* @var String
|
261 |
+
* @access private
|
262 |
+
*/
|
263 |
+
var $ecb;
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Performance-optimized callback function for en/decrypt()
|
267 |
+
*
|
268 |
+
* @var Callback
|
269 |
+
* @access private
|
270 |
+
*/
|
271 |
+
var $inline_crypt;
|
272 |
+
|
273 |
+
/**
|
274 |
+
* The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
|
275 |
+
*
|
276 |
+
* S-Box 1
|
277 |
+
*
|
278 |
+
* @access private
|
279 |
+
* @var array
|
280 |
+
*/
|
281 |
+
var $sbox0 = array (
|
282 |
+
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
283 |
+
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
284 |
+
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
285 |
+
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
286 |
+
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
287 |
+
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
288 |
+
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
289 |
+
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
290 |
+
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
291 |
+
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
292 |
+
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
293 |
+
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
294 |
+
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
295 |
+
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
296 |
+
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
297 |
+
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
298 |
+
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
299 |
+
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
300 |
+
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
301 |
+
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
302 |
+
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
303 |
+
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
304 |
+
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
305 |
+
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
306 |
+
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
307 |
+
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
308 |
+
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
309 |
+
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
310 |
+
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
311 |
+
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
312 |
+
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
313 |
+
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
314 |
+
);
|
315 |
+
|
316 |
+
/**
|
317 |
+
* S-Box 1
|
318 |
+
*
|
319 |
+
* @access private
|
320 |
+
* @var array
|
321 |
+
*/
|
322 |
+
var $sbox1 = array(
|
323 |
+
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
324 |
+
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
325 |
+
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
326 |
+
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
327 |
+
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
328 |
+
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
329 |
+
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
330 |
+
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
331 |
+
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
332 |
+
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
333 |
+
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
334 |
+
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
335 |
+
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
336 |
+
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
337 |
+
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
338 |
+
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
339 |
+
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
340 |
+
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
341 |
+
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
342 |
+
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
343 |
+
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
344 |
+
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
345 |
+
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
346 |
+
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
347 |
+
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
348 |
+
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
349 |
+
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
350 |
+
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
351 |
+
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
352 |
+
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
353 |
+
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
354 |
+
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
355 |
+
);
|
356 |
+
|
357 |
+
/**
|
358 |
+
* S-Box 2
|
359 |
+
*
|
360 |
+
* @access private
|
361 |
+
* @var array
|
362 |
+
*/
|
363 |
+
var $sbox2 = array(
|
364 |
+
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
365 |
+
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
366 |
+
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
367 |
+
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
368 |
+
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
369 |
+
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
370 |
+
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
371 |
+
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
372 |
+
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
373 |
+
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
374 |
+
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
375 |
+
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
376 |
+
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
377 |
+
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
378 |
+
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
379 |
+
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
380 |
+
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
381 |
+
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
382 |
+
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
383 |
+
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
384 |
+
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
385 |
+
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
386 |
+
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
387 |
+
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
388 |
+
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
389 |
+
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
390 |
+
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
391 |
+
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
392 |
+
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
393 |
+
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
394 |
+
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
395 |
+
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
396 |
+
);
|
397 |
+
|
398 |
+
/**
|
399 |
+
* S-Box 3
|
400 |
+
*
|
401 |
+
* @access private
|
402 |
+
* @var array
|
403 |
+
*/
|
404 |
+
var $sbox3 = array(
|
405 |
+
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
406 |
+
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
407 |
+
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
408 |
+
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
409 |
+
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
410 |
+
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
411 |
+
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
412 |
+
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
413 |
+
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
414 |
+
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
415 |
+
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
416 |
+
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
417 |
+
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
418 |
+
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
419 |
+
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
420 |
+
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
421 |
+
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
422 |
+
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
423 |
+
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
424 |
+
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
425 |
+
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
426 |
+
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
427 |
+
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
428 |
+
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
429 |
+
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
430 |
+
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
431 |
+
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
432 |
+
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
433 |
+
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
434 |
+
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
435 |
+
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
436 |
+
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
437 |
+
);
|
438 |
+
|
439 |
+
/**
|
440 |
+
* P-Array consists of 18 32-bit subkeys
|
441 |
+
*
|
442 |
+
* @var array $parray
|
443 |
+
* @access private
|
444 |
+
*/
|
445 |
+
var $parray = array(
|
446 |
+
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
|
447 |
+
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
448 |
+
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
|
449 |
+
);
|
450 |
+
|
451 |
+
/**
|
452 |
+
* The BCTX-working Array
|
453 |
+
*
|
454 |
+
* Holds the expanded key [p] and the key-depended s-boxes [sb]
|
455 |
+
*
|
456 |
+
* @var array $bctx
|
457 |
+
* @access private
|
458 |
+
*/
|
459 |
+
var $bctx = array();
|
460 |
+
|
461 |
+
/**
|
462 |
+
* Default Constructor.
|
463 |
+
*
|
464 |
+
* Determines whether or not the mcrypt extension should be used.
|
465 |
+
* If not explictly set, CRYPT_BLOWFISH_MODE_CBC will be used.
|
466 |
+
*
|
467 |
+
* @param optional Integer $mode
|
468 |
+
* @access public
|
469 |
+
*/
|
470 |
+
function Crypt_Blowfish($mode = CRYPT_BLOWFISH_MODE_CBC)
|
471 |
+
{
|
472 |
+
if ( !defined('CRYPT_BLOWFISH_MODE') ) {
|
473 |
+
switch (true) {
|
474 |
+
case extension_loaded('mcrypt') && in_array('blowfish', mcrypt_list_algorithms()):
|
475 |
+
define('CRYPT_BLOWFISH_MODE', CRYPT_BLOWFISH_MODE_MCRYPT);
|
476 |
+
break;
|
477 |
+
default:
|
478 |
+
define('CRYPT_BLOWFISH_MODE', CRYPT_BLOWFISH_MODE_INTERNAL);
|
479 |
+
}
|
480 |
+
}
|
481 |
+
|
482 |
+
switch ( CRYPT_BLOWFISH_MODE ) {
|
483 |
+
case CRYPT_BLOWFISH_MODE_MCRYPT:
|
484 |
+
switch ($mode) {
|
485 |
+
case CRYPT_BLOWFISH_MODE_ECB:
|
486 |
+
$this->paddable = true;
|
487 |
+
$this->mode = MCRYPT_MODE_ECB;
|
488 |
+
break;
|
489 |
+
case CRYPT_BLOWFISH_MODE_CTR:
|
490 |
+
$this->mode = 'ctr';
|
491 |
+
break;
|
492 |
+
case CRYPT_BLOWFISH_MODE_CFB:
|
493 |
+
$this->mode = 'ncfb';
|
494 |
+
$this->ecb = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, '');
|
495 |
+
break;
|
496 |
+
case CRYPT_BLOWFISH_MODE_OFB:
|
497 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
498 |
+
break;
|
499 |
+
case CRYPT_BLOWFISH_MODE_CBC:
|
500 |
+
default:
|
501 |
+
$this->paddable = true;
|
502 |
+
$this->mode = MCRYPT_MODE_CBC;
|
503 |
+
}
|
504 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $this->mode, '');
|
505 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $this->mode, '');
|
506 |
+
|
507 |
+
break;
|
508 |
+
default:
|
509 |
+
switch ($mode) {
|
510 |
+
case CRYPT_BLOWFISH_MODE_ECB:
|
511 |
+
case CRYPT_BLOWFISH_MODE_CBC:
|
512 |
+
$this->paddable = true;
|
513 |
+
$this->mode = $mode;
|
514 |
+
break;
|
515 |
+
case CRYPT_BLOWFISH_MODE_CTR:
|
516 |
+
case CRYPT_BLOWFISH_MODE_CFB:
|
517 |
+
case CRYPT_BLOWFISH_MODE_OFB:
|
518 |
+
$this->mode = $mode;
|
519 |
+
break;
|
520 |
+
default:
|
521 |
+
$this->paddable = true;
|
522 |
+
$this->mode = CRYPT_BLOWFISH_MODE_CBC;
|
523 |
+
}
|
524 |
+
$this->inline_crypt_setup();
|
525 |
+
}
|
526 |
+
}
|
527 |
+
|
528 |
+
/**
|
529 |
+
* Sets the key.
|
530 |
+
*
|
531 |
+
* Keys can be of any length. Blowfish, itself, requires the use of a key between 32 and max. 448-bits long.
|
532 |
+
* If the key is less than 32-bits we NOT fill the key to 32bit but let the key as it is to be compatible
|
533 |
+
* with mcrypt because mcrypt act this way with blowfish key's < 32 bits.
|
534 |
+
*
|
535 |
+
* If the key is more than 448-bits, we trim the excess bits.
|
536 |
+
*
|
537 |
+
* If the key is not explicitly set, or empty, it'll be assumed a 128 bits key to be all null bytes.
|
538 |
+
*
|
539 |
+
* @access public
|
540 |
+
* @param String $key
|
541 |
+
*/
|
542 |
+
function setKey($key)
|
543 |
+
{
|
544 |
+
$keylength = strlen($key);
|
545 |
+
|
546 |
+
if (!$keylength) {
|
547 |
+
$key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
548 |
+
}
|
549 |
+
elseif ($keylength > 56) {
|
550 |
+
$key = substr($key, 0, 56);
|
551 |
+
}
|
552 |
+
|
553 |
+
$this->key = $key;
|
554 |
+
|
555 |
+
$this->enchanged = true;
|
556 |
+
$this->dechanged = true;
|
557 |
+
|
558 |
+
if (CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT) {
|
559 |
+
return;
|
560 |
+
}
|
561 |
+
|
562 |
+
/* key-expanding p[] and S-Box building sb[] */
|
563 |
+
$this->bctx = array(
|
564 |
+
'p' => array(),
|
565 |
+
'sb' => array(
|
566 |
+
$this->sbox0,
|
567 |
+
$this->sbox1,
|
568 |
+
$this->sbox2,
|
569 |
+
$this->sbox3
|
570 |
+
)
|
571 |
+
);
|
572 |
+
|
573 |
+
// unpack binary string in unsigned chars
|
574 |
+
$key = array_values(unpack('C*', $key));
|
575 |
+
$keyl = count($key);
|
576 |
+
for ($j = 0, $i = 0; $i < 18; ++$i) {
|
577 |
+
// xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
|
578 |
+
for ($data = 0, $k = 0; $k < 4; ++$k) {
|
579 |
+
$data = ($data << 8) | $key[$j];
|
580 |
+
if (++$j >= $keyl) {
|
581 |
+
$j = 0;
|
582 |
+
}
|
583 |
+
}
|
584 |
+
$this->bctx['p'][] = $this->parray[$i] ^ $data;
|
585 |
+
}
|
586 |
+
|
587 |
+
// encrypt the zero-string, replace P1 and P2 with the encrypted data,
|
588 |
+
// encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
|
589 |
+
$datal = 0;
|
590 |
+
$datar = 0;
|
591 |
+
for ($i = 0; $i < 18; $i += 2) {
|
592 |
+
$this->_encryptBlock($datal, $datar);
|
593 |
+
$this->bctx['p'][$i ] = $datal;
|
594 |
+
$this->bctx['p'][$i + 1] = $datar;
|
595 |
+
}
|
596 |
+
for ($i = 0; $i < 4; ++$i) {
|
597 |
+
for ($j = 0; $j < 256; $j += 2) {
|
598 |
+
$this->_encryptBlock($datal, $datar);
|
599 |
+
$this->bctx['sb'][$i][$j ] = $datal;
|
600 |
+
$this->bctx['sb'][$i][$j + 1] = $datar;
|
601 |
+
}
|
602 |
+
}
|
603 |
+
}
|
604 |
+
|
605 |
+
/**
|
606 |
+
* Encrypt the block.
|
607 |
+
*
|
608 |
+
* @access private
|
609 |
+
* @param int $Xl left uInt32 part of the block
|
610 |
+
* @param int $Xr right uInt32 part of the block
|
611 |
+
* @return void
|
612 |
+
*/
|
613 |
+
function _encryptBlock(&$Xl, &$Xr)
|
614 |
+
{
|
615 |
+
$p = $this->bctx['p'];
|
616 |
+
$sb_0 = $this->bctx['sb'][0];
|
617 |
+
$sb_1 = $this->bctx['sb'][1];
|
618 |
+
$sb_2 = $this->bctx['sb'][2];
|
619 |
+
$sb_3 = $this->bctx['sb'][3];
|
620 |
+
$l = $Xl;
|
621 |
+
$r = $Xr;
|
622 |
+
|
623 |
+
$i = -1;
|
624 |
+
while ($i < 15) {
|
625 |
+
$l^= $p[++$i];
|
626 |
+
$r^= ($sb_0[$l >> 24 & 0xff] +
|
627 |
+
$sb_1[$l >> 16 & 0xff] ^
|
628 |
+
$sb_2[$l >> 8 & 0xff]) +
|
629 |
+
$sb_3[$l & 0xff];
|
630 |
+
|
631 |
+
$r^= $p[++$i];
|
632 |
+
$l^= ($sb_0[$r >> 24 & 0xff] +
|
633 |
+
$sb_1[$r >> 16 & 0xff] ^
|
634 |
+
$sb_2[$r >> 8 & 0xff]) +
|
635 |
+
$sb_3[$r & 0xff];
|
636 |
+
|
637 |
+
}
|
638 |
+
$Xr = $l ^ $p[16];
|
639 |
+
$Xl = $r ^ $p[17];
|
640 |
+
}
|
641 |
+
|
642 |
+
/**
|
643 |
+
* Sets the password.
|
644 |
+
*
|
645 |
+
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
|
646 |
+
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
|
647 |
+
* $hash, $salt, $count
|
648 |
+
*
|
649 |
+
* @param String $password
|
650 |
+
* @param optional String $method
|
651 |
+
* @access public
|
652 |
+
*/
|
653 |
+
function setPassword($password, $method = 'pbkdf2')
|
654 |
+
{
|
655 |
+
$key = '';
|
656 |
+
|
657 |
+
switch ($method) {
|
658 |
+
default: // 'pbkdf2'
|
659 |
+
list(, , $hash, $salt, $count) = func_get_args();
|
660 |
+
if (!isset($hash)) {
|
661 |
+
$hash = 'sha1';
|
662 |
+
}
|
663 |
+
// WPA and WPA2 use the SSID as the salt
|
664 |
+
if (!isset($salt)) {
|
665 |
+
$salt = 'phpseclib/salt';
|
666 |
+
}
|
667 |
+
// RFC2898#section-4.2 uses 1,000 iterations by default
|
668 |
+
// WPA and WPA2 use 4,096.
|
669 |
+
if (!isset($count)) {
|
670 |
+
$count = 1000;
|
671 |
+
}
|
672 |
+
|
673 |
+
if (!class_exists('Crypt_Hash')) {
|
674 |
+
require_once('Crypt/Hash.php');
|
675 |
+
}
|
676 |
+
|
677 |
+
$i = 1;
|
678 |
+
while (strlen($key) < 56) {
|
679 |
+
//$dk.= $this->_pbkdf($password, $salt, $count, $i++);
|
680 |
+
$hmac = new Crypt_Hash();
|
681 |
+
$hmac->setHash($hash);
|
682 |
+
$hmac->setKey($password);
|
683 |
+
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
684 |
+
for ($j = 2; $j <= $count; $j++) {
|
685 |
+
$u = $hmac->hash($u);
|
686 |
+
$f^= $u;
|
687 |
+
}
|
688 |
+
$key.= $f;
|
689 |
+
}
|
690 |
+
}
|
691 |
+
|
692 |
+
$this->setKey($key);
|
693 |
+
}
|
694 |
+
|
695 |
+
/**
|
696 |
+
* Sets the initialization vector. (optional)
|
697 |
+
*
|
698 |
+
* SetIV is not required when CRYPT_BLOWFISH_MODE_ECB is being used. If not explictly set, it'll be assumed
|
699 |
+
* to be all null bytes.
|
700 |
+
*
|
701 |
+
* @access public
|
702 |
+
* @param String $iv
|
703 |
+
*/
|
704 |
+
function setIV($iv)
|
705 |
+
{
|
706 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
|
707 |
+
$this->enchanged = true;
|
708 |
+
$this->dechanged = true;
|
709 |
+
}
|
710 |
+
|
711 |
+
/**
|
712 |
+
* Encrypts a message.
|
713 |
+
*
|
714 |
+
* $plaintext will be padded with up to 8 additional bytes. Other Blowfish implementations may or may not pad in the
|
715 |
+
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
716 |
+
* URL:
|
717 |
+
*
|
718 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
719 |
+
*
|
720 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
721 |
+
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
|
722 |
+
* length.
|
723 |
+
*
|
724 |
+
* @see Crypt_Blowfish::decrypt()
|
725 |
+
* @access public
|
726 |
+
* @param String $plaintext
|
727 |
+
*/
|
728 |
+
function encrypt($plaintext)
|
729 |
+
{
|
730 |
+
if ( CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT ) {
|
731 |
+
if ($this->paddable) {
|
732 |
+
$plaintext = $this->_pad($plaintext);
|
733 |
+
}
|
734 |
+
|
735 |
+
if ($this->enchanged) {
|
736 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
737 |
+
if ($this->mode == 'ncfb') {
|
738 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
739 |
+
}
|
740 |
+
$this->enchanged = false;
|
741 |
+
}
|
742 |
+
|
743 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
744 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
745 |
+
} else {
|
746 |
+
$iv = &$this->encryptIV;
|
747 |
+
$pos = &$this->enbuffer['pos'];
|
748 |
+
$len = strlen($plaintext);
|
749 |
+
$ciphertext = '';
|
750 |
+
$i = 0;
|
751 |
+
if ($pos) {
|
752 |
+
$orig_pos = $pos;
|
753 |
+
$max = 8 - $pos;
|
754 |
+
if ($len >= $max) {
|
755 |
+
$i = $max;
|
756 |
+
$len-= $max;
|
757 |
+
$pos = 0;
|
758 |
+
} else {
|
759 |
+
$i = $len;
|
760 |
+
$pos+= $len;
|
761 |
+
$len = 0;
|
762 |
+
}
|
763 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
764 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
765 |
+
$this->enbuffer['enmcrypt_init'] = true;
|
766 |
+
}
|
767 |
+
if ($len >= 8) {
|
768 |
+
if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
|
769 |
+
if ($this->enbuffer['enmcrypt_init'] === true) {
|
770 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
771 |
+
$this->enbuffer['enmcrypt_init'] = false;
|
772 |
+
}
|
773 |
+
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
|
774 |
+
$iv = substr($ciphertext, -8);
|
775 |
+
$len%= 8;
|
776 |
+
} else {
|
777 |
+
while ($len >= 8) {
|
778 |
+
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
|
779 |
+
$ciphertext.= $iv;
|
780 |
+
$len-= 8;
|
781 |
+
$i+= 8;
|
782 |
+
}
|
783 |
+
}
|
784 |
+
}
|
785 |
+
if ($len) {
|
786 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
787 |
+
$block = $iv ^ substr($plaintext, -$len);
|
788 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
789 |
+
$ciphertext.= $block;
|
790 |
+
$pos = $len;
|
791 |
+
}
|
792 |
+
return $ciphertext;
|
793 |
+
}
|
794 |
+
|
795 |
+
if (!$this->continuousBuffer) {
|
796 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
797 |
+
}
|
798 |
+
|
799 |
+
return $ciphertext;
|
800 |
+
}
|
801 |
+
|
802 |
+
if (empty($this->bctx)) {
|
803 |
+
$this->setKey($this->key);
|
804 |
+
}
|
805 |
+
|
806 |
+
$inline = $this->inline_crypt;
|
807 |
+
return $inline('encrypt', $this, $plaintext);
|
808 |
+
}
|
809 |
+
|
810 |
+
/**
|
811 |
+
* Decrypts a message.
|
812 |
+
*
|
813 |
+
* If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
|
814 |
+
*
|
815 |
+
* @see Crypt_Blowfish::encrypt()
|
816 |
+
* @access public
|
817 |
+
* @param String $ciphertext
|
818 |
+
*/
|
819 |
+
function decrypt($ciphertext)
|
820 |
+
{
|
821 |
+
if ( CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT ) {
|
822 |
+
if ($this->paddable) {
|
823 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
824 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
825 |
+
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + (8 - strlen($ciphertext) % 8) % 8, chr(0));
|
826 |
+
}
|
827 |
+
|
828 |
+
if ($this->dechanged) {
|
829 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
830 |
+
if ($this->mode == 'ncfb') {
|
831 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
832 |
+
}
|
833 |
+
$this->dechanged = false;
|
834 |
+
}
|
835 |
+
|
836 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
837 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
838 |
+
} else {
|
839 |
+
$iv = &$this->decryptIV;
|
840 |
+
$pos = &$this->debuffer['pos'];
|
841 |
+
$len = strlen($ciphertext);
|
842 |
+
$plaintext = '';
|
843 |
+
$i = 0;
|
844 |
+
if ($pos) {
|
845 |
+
$orig_pos = $pos;
|
846 |
+
$max = 8 - $pos;
|
847 |
+
if ($len >= $max) {
|
848 |
+
$i = $max;
|
849 |
+
$len-= $max;
|
850 |
+
$pos = 0;
|
851 |
+
} else {
|
852 |
+
$i = $len;
|
853 |
+
$pos+= $len;
|
854 |
+
$len = 0;
|
855 |
+
}
|
856 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
857 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
858 |
+
}
|
859 |
+
if ($len >= 8) {
|
860 |
+
$cb = substr($ciphertext, $i, $len - $len % 8);
|
861 |
+
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
862 |
+
$iv = substr($cb, -8);
|
863 |
+
$len%= 8;
|
864 |
+
}
|
865 |
+
if ($len) {
|
866 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
867 |
+
$plaintext.= $iv ^ substr($ciphertext, -$len);
|
868 |
+
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
|
869 |
+
$pos = $len;
|
870 |
+
}
|
871 |
+
return $plaintext;
|
872 |
+
}
|
873 |
+
|
874 |
+
if (!$this->continuousBuffer) {
|
875 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
876 |
+
}
|
877 |
+
|
878 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
879 |
+
}
|
880 |
+
|
881 |
+
if (empty($this->bctx)) {
|
882 |
+
$this->setKey($this->key);
|
883 |
+
}
|
884 |
+
|
885 |
+
$inline = $this->inline_crypt;
|
886 |
+
return $inline('decrypt', $this, $ciphertext);
|
887 |
+
}
|
888 |
+
|
889 |
+
/**
|
890 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
891 |
+
*
|
892 |
+
* @see Crypt_Blowfish::disableContinuousBuffer()
|
893 |
+
* @access public
|
894 |
+
*/
|
895 |
+
function enableContinuousBuffer()
|
896 |
+
{
|
897 |
+
$this->continuousBuffer = true;
|
898 |
+
}
|
899 |
+
|
900 |
+
/**
|
901 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
902 |
+
*
|
903 |
+
* The default behavior.
|
904 |
+
*
|
905 |
+
* @see Crypt_Blowfish::enableContinuousBuffer()
|
906 |
+
* @access public
|
907 |
+
*/
|
908 |
+
function disableContinuousBuffer()
|
909 |
+
{
|
910 |
+
$this->continuousBuffer = false;
|
911 |
+
$this->encryptIV = $this->iv;
|
912 |
+
$this->decryptIV = $this->iv;
|
913 |
+
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
914 |
+
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
915 |
+
|
916 |
+
if (CRYPT_BLOWFISH_MODE == CRYPT_BLOWFISH_MODE_MCRYPT) {
|
917 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
918 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
919 |
+
}
|
920 |
+
}
|
921 |
+
|
922 |
+
/**
|
923 |
+
* Pad "packets".
|
924 |
+
*
|
925 |
+
* Blowfish works by encrypting 8 bytes at a time. If you ever need to encrypt or decrypt something that's not
|
926 |
+
* a multiple of 8, it becomes necessary to pad the input so that it's length is a multiple of eight.
|
927 |
+
*
|
928 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
|
929 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
930 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
931 |
+
* transmitted separately)
|
932 |
+
*
|
933 |
+
* @see Crypt_Blowfish::disablePadding()
|
934 |
+
* @access public
|
935 |
+
*/
|
936 |
+
function enablePadding()
|
937 |
+
{
|
938 |
+
$this->padding = true;
|
939 |
+
}
|
940 |
+
|
941 |
+
/**
|
942 |
+
* Do not pad packets.
|
943 |
+
*
|
944 |
+
* @see Crypt_Blowfish::enablePadding()
|
945 |
+
* @access public
|
946 |
+
*/
|
947 |
+
function disablePadding()
|
948 |
+
{
|
949 |
+
$this->padding = false;
|
950 |
+
}
|
951 |
+
|
952 |
+
/**
|
953 |
+
* Pads a string
|
954 |
+
*
|
955 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
|
956 |
+
*
|
957 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
958 |
+
* and padding will, hence forth, be enabled.
|
959 |
+
*
|
960 |
+
* @see Crypt_Blowfish::_unpad()
|
961 |
+
* @access private
|
962 |
+
*/
|
963 |
+
function _pad($text)
|
964 |
+
{
|
965 |
+
$length = strlen($text);
|
966 |
+
|
967 |
+
if (!$this->padding) {
|
968 |
+
if ($length % 8 == 0) {
|
969 |
+
return $text;
|
970 |
+
} else {
|
971 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
|
972 |
+
$this->padding = true;
|
973 |
+
}
|
974 |
+
}
|
975 |
+
|
976 |
+
$pad = 8 - ($length % 8);
|
977 |
+
|
978 |
+
return str_pad($text, $length + $pad, chr($pad));
|
979 |
+
}
|
980 |
+
|
981 |
+
/**
|
982 |
+
* Unpads a string
|
983 |
+
*
|
984 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
985 |
+
* and false will be returned.
|
986 |
+
*
|
987 |
+
* @see Crypt_Blowfish::_pad()
|
988 |
+
* @access private
|
989 |
+
*/
|
990 |
+
function _unpad($text)
|
991 |
+
{
|
992 |
+
if (!$this->padding) {
|
993 |
+
return $text;
|
994 |
+
}
|
995 |
+
|
996 |
+
$length = ord($text[strlen($text) - 1]);
|
997 |
+
|
998 |
+
if (!$length || $length > 8) {
|
999 |
+
return false;
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
return substr($text, 0, -$length);
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
/**
|
1006 |
+
* String Shift
|
1007 |
+
*
|
1008 |
+
* Inspired by array_shift
|
1009 |
+
*
|
1010 |
+
* @param String $string
|
1011 |
+
* @return String
|
1012 |
+
* @access private
|
1013 |
+
*/
|
1014 |
+
function _string_shift(&$string)
|
1015 |
+
{
|
1016 |
+
$substr = substr($string, 0, 8);
|
1017 |
+
$string = substr($string, 8);
|
1018 |
+
return $substr;
|
1019 |
+
}
|
1020 |
+
|
1021 |
+
/**
|
1022 |
+
* Generate CTR XOR encryption key
|
1023 |
+
*
|
1024 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
1025 |
+
* plaintext / ciphertext in CTR mode.
|
1026 |
+
*
|
1027 |
+
* @see Crypt_Blowfish::decrypt()
|
1028 |
+
* @see Crypt_Blowfish::encrypt()
|
1029 |
+
* @access public
|
1030 |
+
* @param String $iv
|
1031 |
+
*/
|
1032 |
+
function _generate_xor(&$iv)
|
1033 |
+
{
|
1034 |
+
$xor = $iv;
|
1035 |
+
for ($j = 4; $j <= 8; $j+=4) {
|
1036 |
+
$temp = substr($iv, -$j, 4);
|
1037 |
+
switch ($temp) {
|
1038 |
+
case "\xFF\xFF\xFF\xFF":
|
1039 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
1040 |
+
break;
|
1041 |
+
case "\x7F\xFF\xFF\xFF":
|
1042 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
1043 |
+
break 2;
|
1044 |
+
default:
|
1045 |
+
extract(unpack('Ncount', $temp));
|
1046 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
1047 |
+
break 2;
|
1048 |
+
}
|
1049 |
+
}
|
1050 |
+
|
1051 |
+
return $xor;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
/**
|
1055 |
+
* Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
|
1056 |
+
*
|
1057 |
+
* @access private
|
1058 |
+
*/
|
1059 |
+
function inline_crypt_setup()
|
1060 |
+
{/*{{{*/
|
1061 |
+
$lambda_functions =& Crypt_Blowfish::get_lambda_functions();
|
1062 |
+
$block_size = 8;
|
1063 |
+
$mode = $this->mode;
|
1064 |
+
$code_hash = "$mode";
|
1065 |
+
|
1066 |
+
if (!isset($lambda_functions[$code_hash])) {
|
1067 |
+
$init_cryptBlock = '
|
1068 |
+
extract($self->bctx["p"], EXTR_PREFIX_ALL, "p");
|
1069 |
+
extract($self->bctx["sb"], EXTR_PREFIX_ALL, "sb");
|
1070 |
+
';
|
1071 |
+
|
1072 |
+
// Generating encrypt code:
|
1073 |
+
$_encryptBlock = '
|
1074 |
+
$in = unpack("N*", $in);
|
1075 |
+
$l = $in[1];
|
1076 |
+
$r = $in[2];
|
1077 |
+
';
|
1078 |
+
for ($i = 0; $i < 16; $i+= 2) {
|
1079 |
+
$_encryptBlock.= '
|
1080 |
+
$l^= $p_'.($i).';
|
1081 |
+
$r^= ($sb_0[$l >> 24 & 0xff] +
|
1082 |
+
$sb_1[$l >> 16 & 0xff] ^
|
1083 |
+
$sb_2[$l >> 8 & 0xff]) +
|
1084 |
+
$sb_3[$l & 0xff];
|
1085 |
+
|
1086 |
+
$r^= $p_'.($i + 1).';
|
1087 |
+
$l^= ($sb_0[$r >> 24 & 0xff] +
|
1088 |
+
$sb_1[$r >> 16 & 0xff] ^
|
1089 |
+
$sb_2[$r >> 8 & 0xff]) +
|
1090 |
+
$sb_3[$r & 0xff];
|
1091 |
+
';
|
1092 |
+
}
|
1093 |
+
$_encryptBlock.= '
|
1094 |
+
$in = pack("N*", $r ^ $p_17, $l ^ $p_16);
|
1095 |
+
';
|
1096 |
+
|
1097 |
+
// Generating decrypt code:
|
1098 |
+
$_decryptBlock = '
|
1099 |
+
$in = unpack("N*", $in);
|
1100 |
+
$l = $in[1];
|
1101 |
+
$r = $in[2];
|
1102 |
+
';
|
1103 |
+
|
1104 |
+
for ($i = 17; $i > 2; $i-= 2) {
|
1105 |
+
$_decryptBlock.= '
|
1106 |
+
$l^= $p_'.($i).';
|
1107 |
+
$r^= ($sb_0[$l >> 24 & 0xff] +
|
1108 |
+
$sb_1[$l >> 16 & 0xff] ^
|
1109 |
+
$sb_2[$l >> 8 & 0xff]) +
|
1110 |
+
$sb_3[$l & 0xff];
|
1111 |
+
|
1112 |
+
$r^= $p_'.($i - 1).';
|
1113 |
+
$l^= ($sb_0[$r >> 24 & 0xff] +
|
1114 |
+
$sb_1[$r >> 16 & 0xff] ^
|
1115 |
+
$sb_2[$r >> 8 & 0xff]) +
|
1116 |
+
$sb_3[$r & 0xff];
|
1117 |
+
';
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
$_decryptBlock.= '
|
1121 |
+
$in = pack("N*", $r ^ $p_0, $l ^ $p_1);
|
1122 |
+
';
|
1123 |
+
|
1124 |
+
// Generating mode of operation code:
|
1125 |
+
switch ($mode) {
|
1126 |
+
case CRYPT_BLOWFISH_MODE_ECB:
|
1127 |
+
$encrypt = '
|
1128 |
+
$ciphertext = "";
|
1129 |
+
$text = $self->_pad($text);
|
1130 |
+
$plaintext_len = strlen($text);
|
1131 |
+
|
1132 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1133 |
+
$in = substr($text, $i, '.$block_size.');
|
1134 |
+
'.$_encryptBlock.'
|
1135 |
+
$ciphertext.= $in;
|
1136 |
+
}
|
1137 |
+
return $ciphertext;
|
1138 |
+
';
|
1139 |
+
|
1140 |
+
$decrypt = '
|
1141 |
+
$plaintext = "";
|
1142 |
+
$text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
|
1143 |
+
$ciphertext_len = strlen($text);
|
1144 |
+
|
1145 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1146 |
+
$in = substr($text, $i, '.$block_size.');
|
1147 |
+
'.$_decryptBlock.'
|
1148 |
+
$plaintext.= $in;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
return $self->_unpad($plaintext);
|
1152 |
+
';
|
1153 |
+
break;
|
1154 |
+
case CRYPT_BLOWFISH_MODE_CBC:
|
1155 |
+
$encrypt = '
|
1156 |
+
$ciphertext = "";
|
1157 |
+
$text = $self->_pad($text);
|
1158 |
+
$plaintext_len = strlen($text);
|
1159 |
+
|
1160 |
+
$in = $self->encryptIV;
|
1161 |
+
|
1162 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1163 |
+
$in = substr($text, $i, '.$block_size.') ^ $in;
|
1164 |
+
'.$_encryptBlock.'
|
1165 |
+
$ciphertext.= $in;
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
if ($self->continuousBuffer) {
|
1169 |
+
$self->encryptIV = $in;
|
1170 |
+
}
|
1171 |
+
|
1172 |
+
return $ciphertext;
|
1173 |
+
';
|
1174 |
+
|
1175 |
+
$decrypt = '
|
1176 |
+
$plaintext = "";
|
1177 |
+
$text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
|
1178 |
+
$ciphertext_len = strlen($text);
|
1179 |
+
|
1180 |
+
$iv = $self->decryptIV;
|
1181 |
+
|
1182 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1183 |
+
$in = $block = substr($text, $i, '.$block_size.');
|
1184 |
+
'.$_decryptBlock.'
|
1185 |
+
$plaintext.= $in ^ $iv;
|
1186 |
+
$iv = $block;
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
if ($self->continuousBuffer) {
|
1190 |
+
$self->decryptIV = $iv;
|
1191 |
+
}
|
1192 |
+
|
1193 |
+
return $self->_unpad($plaintext);
|
1194 |
+
';
|
1195 |
+
break;
|
1196 |
+
case CRYPT_BLOWFISH_MODE_CTR:
|
1197 |
+
$encrypt = '
|
1198 |
+
$ciphertext = "";
|
1199 |
+
$plaintext_len = strlen($text);
|
1200 |
+
$xor = $self->encryptIV;
|
1201 |
+
$buffer = &$self->enbuffer;
|
1202 |
+
|
1203 |
+
if (strlen($buffer["encrypted"])) {
|
1204 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1205 |
+
$block = substr($text, $i, '.$block_size.');
|
1206 |
+
if (strlen($block) > strlen($buffer["encrypted"])) {
|
1207 |
+
$in = $self->_generate_xor($xor);
|
1208 |
+
'.$_encryptBlock.'
|
1209 |
+
$buffer["encrypted"].= $in;
|
1210 |
+
}
|
1211 |
+
$key = $self->_string_shift($buffer["encrypted"]);
|
1212 |
+
$ciphertext.= $block ^ $key;
|
1213 |
+
}
|
1214 |
+
} else {
|
1215 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1216 |
+
$block = substr($text, $i, '.$block_size.');
|
1217 |
+
$in = $self->_generate_xor($xor);
|
1218 |
+
'.$_encryptBlock.'
|
1219 |
+
$key = $in;
|
1220 |
+
$ciphertext.= $block ^ $key;
|
1221 |
+
}
|
1222 |
+
}
|
1223 |
+
if ($self->continuousBuffer) {
|
1224 |
+
$self->encryptIV = $xor;
|
1225 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
1226 |
+
$buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
|
1227 |
+
}
|
1228 |
+
}
|
1229 |
+
|
1230 |
+
return $ciphertext;
|
1231 |
+
';
|
1232 |
+
|
1233 |
+
$decrypt = '
|
1234 |
+
$plaintext = "";
|
1235 |
+
$ciphertext_len = strlen($text);
|
1236 |
+
$xor = $self->decryptIV;
|
1237 |
+
$buffer = &$self->debuffer;
|
1238 |
+
|
1239 |
+
if (strlen($buffer["ciphertext"])) {
|
1240 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1241 |
+
$block = substr($text, $i, '.$block_size.');
|
1242 |
+
if (strlen($block) > strlen($buffer["ciphertext"])) {
|
1243 |
+
$in = $self->_generate_xor($xor);
|
1244 |
+
'.$_encryptBlock.'
|
1245 |
+
$buffer["ciphertext"].= $in;
|
1246 |
+
}
|
1247 |
+
$key = $self->_string_shift($buffer["ciphertext"]);
|
1248 |
+
$plaintext.= $block ^ $key;
|
1249 |
+
}
|
1250 |
+
} else {
|
1251 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1252 |
+
$block = substr($text, $i, '.$block_size.');
|
1253 |
+
$in = $self->_generate_xor($xor);
|
1254 |
+
'.$_encryptBlock.'
|
1255 |
+
$key = $in;
|
1256 |
+
$plaintext.= $block ^ $key;
|
1257 |
+
}
|
1258 |
+
}
|
1259 |
+
if ($self->continuousBuffer) {
|
1260 |
+
$self->decryptIV = $xor;
|
1261 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
1262 |
+
$buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
|
1263 |
+
}
|
1264 |
+
}
|
1265 |
+
return $plaintext;
|
1266 |
+
';
|
1267 |
+
break;
|
1268 |
+
case CRYPT_BLOWFISH_MODE_CFB:
|
1269 |
+
$encrypt = '
|
1270 |
+
$ciphertext = "";
|
1271 |
+
$buffer = &$self->enbuffer;
|
1272 |
+
|
1273 |
+
if ($self->continuousBuffer) {
|
1274 |
+
$iv = &$self->encryptIV;
|
1275 |
+
$pos = &$buffer["pos"];
|
1276 |
+
} else {
|
1277 |
+
$iv = $self->encryptIV;
|
1278 |
+
$pos = 0;
|
1279 |
+
}
|
1280 |
+
$len = strlen($text);
|
1281 |
+
$i = 0;
|
1282 |
+
if ($pos) {
|
1283 |
+
$orig_pos = $pos;
|
1284 |
+
$max = '.$block_size.' - $pos;
|
1285 |
+
if ($len >= $max) {
|
1286 |
+
$i = $max;
|
1287 |
+
$len-= $max;
|
1288 |
+
$pos = 0;
|
1289 |
+
} else {
|
1290 |
+
$i = $len;
|
1291 |
+
$pos+= $len;
|
1292 |
+
$len = 0;
|
1293 |
+
}
|
1294 |
+
$ciphertext = substr($iv, $orig_pos) ^ $text;
|
1295 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
1296 |
+
}
|
1297 |
+
while ($len >= '.$block_size.') {
|
1298 |
+
$in = $iv;
|
1299 |
+
'.$_encryptBlock.';
|
1300 |
+
$iv = $in ^ substr($text, $i, '.$block_size.');
|
1301 |
+
$ciphertext.= $iv;
|
1302 |
+
$len-= '.$block_size.';
|
1303 |
+
$i+= '.$block_size.';
|
1304 |
+
}
|
1305 |
+
if ($len) {
|
1306 |
+
$in = $iv;
|
1307 |
+
'.$_encryptBlock.'
|
1308 |
+
$iv = $in;
|
1309 |
+
$block = $iv ^ substr($text, $i);
|
1310 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
1311 |
+
$ciphertext.= $block;
|
1312 |
+
$pos = $len;
|
1313 |
+
}
|
1314 |
+
return $ciphertext;
|
1315 |
+
';
|
1316 |
+
|
1317 |
+
$decrypt = '
|
1318 |
+
$plaintext = "";
|
1319 |
+
$buffer = &$self->debuffer;
|
1320 |
+
|
1321 |
+
if ($self->continuousBuffer) {
|
1322 |
+
$iv = &$self->decryptIV;
|
1323 |
+
$pos = &$buffer["pos"];
|
1324 |
+
} else {
|
1325 |
+
$iv = $self->decryptIV;
|
1326 |
+
$pos = 0;
|
1327 |
+
}
|
1328 |
+
$len = strlen($text);
|
1329 |
+
$i = 0;
|
1330 |
+
if ($pos) {
|
1331 |
+
$orig_pos = $pos;
|
1332 |
+
$max = '.$block_size.' - $pos;
|
1333 |
+
if ($len >= $max) {
|
1334 |
+
$i = $max;
|
1335 |
+
$len-= $max;
|
1336 |
+
$pos = 0;
|
1337 |
+
} else {
|
1338 |
+
$i = $len;
|
1339 |
+
$pos+= $len;
|
1340 |
+
$len = 0;
|
1341 |
+
}
|
1342 |
+
$plaintext = substr($iv, $orig_pos) ^ $text;
|
1343 |
+
$iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
|
1344 |
+
}
|
1345 |
+
while ($len >= '.$block_size.') {
|
1346 |
+
$in = $iv;
|
1347 |
+
'.$_encryptBlock.'
|
1348 |
+
$iv = $in;
|
1349 |
+
$cb = substr($text, $i, '.$block_size.');
|
1350 |
+
$plaintext.= $iv ^ $cb;
|
1351 |
+
$iv = $cb;
|
1352 |
+
$len-= '.$block_size.';
|
1353 |
+
$i+= '.$block_size.';
|
1354 |
+
}
|
1355 |
+
if ($len) {
|
1356 |
+
$in = $iv;
|
1357 |
+
'.$_encryptBlock.'
|
1358 |
+
$iv = $in;
|
1359 |
+
$plaintext.= $iv ^ substr($text, $i);
|
1360 |
+
$iv = substr_replace($iv, substr($text, $i), 0, $len);
|
1361 |
+
$pos = $len;
|
1362 |
+
}
|
1363 |
+
|
1364 |
+
return $plaintext;
|
1365 |
+
';
|
1366 |
+
break;
|
1367 |
+
case CRYPT_BLOWFISH_MODE_OFB:
|
1368 |
+
$encrypt = '
|
1369 |
+
$ciphertext = "";
|
1370 |
+
$plaintext_len = strlen($text);
|
1371 |
+
$xor = $self->encryptIV;
|
1372 |
+
$buffer = &$self->enbuffer;
|
1373 |
+
|
1374 |
+
if (strlen($buffer["xor"])) {
|
1375 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1376 |
+
$block = substr($text, $i, '.$block_size.');
|
1377 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
1378 |
+
$in = $xor;
|
1379 |
+
'.$_encryptBlock.'
|
1380 |
+
$xor = $in;
|
1381 |
+
$buffer["xor"].= $xor;
|
1382 |
+
}
|
1383 |
+
$key = $self->_string_shift($buffer["xor"]);
|
1384 |
+
$ciphertext.= $block ^ $key;
|
1385 |
+
}
|
1386 |
+
} else {
|
1387 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1388 |
+
$in = $xor;
|
1389 |
+
'.$_encryptBlock.'
|
1390 |
+
$xor = $in;
|
1391 |
+
$ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
|
1392 |
+
}
|
1393 |
+
$key = $xor;
|
1394 |
+
}
|
1395 |
+
if ($self->continuousBuffer) {
|
1396 |
+
$self->encryptIV = $xor;
|
1397 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
1398 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
1399 |
+
}
|
1400 |
+
}
|
1401 |
+
return $ciphertext;
|
1402 |
+
';
|
1403 |
+
|
1404 |
+
$decrypt = '
|
1405 |
+
$plaintext = "";
|
1406 |
+
$ciphertext_len = strlen($text);
|
1407 |
+
$xor = $self->decryptIV;
|
1408 |
+
$buffer = &$self->debuffer;
|
1409 |
+
|
1410 |
+
if (strlen($buffer["xor"])) {
|
1411 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1412 |
+
$block = substr($text, $i, '.$block_size.');
|
1413 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
1414 |
+
$in = $xor;
|
1415 |
+
'.$_encryptBlock.'
|
1416 |
+
$xor = $in;
|
1417 |
+
$buffer["xor"].= $xor;
|
1418 |
+
}
|
1419 |
+
$key = $self->_string_shift($buffer["xor"]);
|
1420 |
+
$plaintext.= $block ^ $key;
|
1421 |
+
}
|
1422 |
+
} else {
|
1423 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1424 |
+
$in = $xor;
|
1425 |
+
'.$_encryptBlock.'
|
1426 |
+
$xor = $in;
|
1427 |
+
$plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
|
1428 |
+
}
|
1429 |
+
$key = $xor;
|
1430 |
+
}
|
1431 |
+
if ($self->continuousBuffer) {
|
1432 |
+
$self->decryptIV = $xor;
|
1433 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
1434 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
1435 |
+
}
|
1436 |
+
}
|
1437 |
+
return $plaintext;
|
1438 |
+
';
|
1439 |
+
break;
|
1440 |
+
}
|
1441 |
+
$fnc_head = '$action, &$self, $text';
|
1442 |
+
$fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }';
|
1443 |
+
|
1444 |
+
if (function_exists('create_function') && is_callable('create_function')) {
|
1445 |
+
$lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body);
|
1446 |
+
} else {
|
1447 |
+
eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }');
|
1448 |
+
}
|
1449 |
+
}
|
1450 |
+
$this->inline_crypt = $lambda_functions[$code_hash];
|
1451 |
+
}/*}}}*/
|
1452 |
+
|
1453 |
+
/**
|
1454 |
+
* Holds the lambda_functions table (classwide)
|
1455 |
+
*
|
1456 |
+
* @see inline_crypt_setup()
|
1457 |
+
* @return Array
|
1458 |
+
* @access private
|
1459 |
+
*/
|
1460 |
+
function &get_lambda_functions()
|
1461 |
+
{
|
1462 |
+
static $functions = array();
|
1463 |
+
return $functions;
|
1464 |
+
}
|
1465 |
+
}
|
1466 |
+
|
1467 |
+
// vim: ts=4:sw=4:et:
|
1468 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/Crypt/DES.php
ADDED
@@ -0,0 +1,2536 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of DES.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Useful resources are as follows:
|
12 |
+
*
|
13 |
+
* - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
|
14 |
+
* - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
|
15 |
+
* - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
|
16 |
+
*
|
17 |
+
* Here's a short example of how to use this library:
|
18 |
+
* <code>
|
19 |
+
* <?php
|
20 |
+
* include('Crypt/DES.php');
|
21 |
+
*
|
22 |
+
* $des = new Crypt_DES();
|
23 |
+
*
|
24 |
+
* $des->setKey('abcdefgh');
|
25 |
+
*
|
26 |
+
* $size = 10 * 1024;
|
27 |
+
* $plaintext = '';
|
28 |
+
* for ($i = 0; $i < $size; $i++) {
|
29 |
+
* $plaintext.= 'a';
|
30 |
+
* }
|
31 |
+
*
|
32 |
+
* echo $des->decrypt($des->encrypt($plaintext));
|
33 |
+
* ?>
|
34 |
+
* </code>
|
35 |
+
*
|
36 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
37 |
+
* of this software and associated documentation files (the "Software"), to deal
|
38 |
+
* in the Software without restriction, including without limitation the rights
|
39 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
40 |
+
* copies of the Software, and to permit persons to whom the Software is
|
41 |
+
* furnished to do so, subject to the following conditions:
|
42 |
+
*
|
43 |
+
* The above copyright notice and this permission notice shall be included in
|
44 |
+
* all copies or substantial portions of the Software.
|
45 |
+
*
|
46 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
47 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
48 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
49 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
50 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
51 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
52 |
+
* THE SOFTWARE.
|
53 |
+
*
|
54 |
+
* @category Crypt
|
55 |
+
* @package Crypt_DES
|
56 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
57 |
+
* @copyright MMVII Jim Wigginton
|
58 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
59 |
+
* @link http://phpseclib.sourceforge.net
|
60 |
+
*/
|
61 |
+
|
62 |
+
/**#@+
|
63 |
+
* @access private
|
64 |
+
* @see Crypt_DES::_prepareKey()
|
65 |
+
* @see Crypt_DES::_processBlock()
|
66 |
+
*/
|
67 |
+
/**
|
68 |
+
* Contains array_reverse($keys[CRYPT_DES_DECRYPT])
|
69 |
+
*/
|
70 |
+
define('CRYPT_DES_ENCRYPT', 0);
|
71 |
+
/**
|
72 |
+
* Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
|
73 |
+
*/
|
74 |
+
define('CRYPT_DES_DECRYPT', 1);
|
75 |
+
/**
|
76 |
+
* Contains $keys[CRYPT_DES_ENCRYPT] as 1-dim array
|
77 |
+
*/
|
78 |
+
define('CRYPT_DES_ENCRYPT_1DIM', 2);
|
79 |
+
/**
|
80 |
+
* Contains $keys[CRYPT_DES_DECRYPT] as 1-dim array
|
81 |
+
*/
|
82 |
+
define('CRYPT_DES_DECRYPT_1DIM', 3);
|
83 |
+
/**#@-*/
|
84 |
+
|
85 |
+
/**#@+
|
86 |
+
* @access public
|
87 |
+
* @see Crypt_DES::encrypt()
|
88 |
+
* @see Crypt_DES::decrypt()
|
89 |
+
*/
|
90 |
+
/**
|
91 |
+
* Encrypt / decrypt using the Counter mode.
|
92 |
+
*
|
93 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
94 |
+
*
|
95 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
96 |
+
*/
|
97 |
+
define('CRYPT_DES_MODE_CTR', -1);
|
98 |
+
/**
|
99 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
100 |
+
*
|
101 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
102 |
+
*/
|
103 |
+
define('CRYPT_DES_MODE_ECB', 1);
|
104 |
+
/**
|
105 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
106 |
+
*
|
107 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
108 |
+
*/
|
109 |
+
define('CRYPT_DES_MODE_CBC', 2);
|
110 |
+
/**
|
111 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
112 |
+
*
|
113 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
114 |
+
*/
|
115 |
+
define('CRYPT_DES_MODE_CFB', 3);
|
116 |
+
/**
|
117 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
118 |
+
*
|
119 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
120 |
+
*/
|
121 |
+
define('CRYPT_DES_MODE_OFB', 4);
|
122 |
+
/**#@-*/
|
123 |
+
|
124 |
+
/**#@+
|
125 |
+
* @access private
|
126 |
+
* @see Crypt_DES::Crypt_DES()
|
127 |
+
*/
|
128 |
+
/**
|
129 |
+
* Toggles the internal implementation
|
130 |
+
*/
|
131 |
+
define('CRYPT_DES_MODE_INTERNAL', 1);
|
132 |
+
/**
|
133 |
+
* Toggles the mcrypt implementation
|
134 |
+
*/
|
135 |
+
define('CRYPT_DES_MODE_MCRYPT', 2);
|
136 |
+
/**#@-*/
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Pure-PHP implementation of DES.
|
140 |
+
*
|
141 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
142 |
+
* @version 0.1.0
|
143 |
+
* @access public
|
144 |
+
* @package Crypt_DES
|
145 |
+
*/
|
146 |
+
class Crypt_DES {
|
147 |
+
/**
|
148 |
+
* The Key Schedule
|
149 |
+
*
|
150 |
+
* @see Crypt_DES::setKey()
|
151 |
+
* @var Array
|
152 |
+
* @access private
|
153 |
+
*/
|
154 |
+
var $keys = "\0\0\0\0\0\0\0\0";
|
155 |
+
|
156 |
+
/**
|
157 |
+
* The Encryption Mode
|
158 |
+
*
|
159 |
+
* @see Crypt_DES::Crypt_DES()
|
160 |
+
* @var Integer
|
161 |
+
* @access private
|
162 |
+
*/
|
163 |
+
var $mode;
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Continuous Buffer status
|
167 |
+
*
|
168 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
169 |
+
* @var Boolean
|
170 |
+
* @access private
|
171 |
+
*/
|
172 |
+
var $continuousBuffer = false;
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Padding status
|
176 |
+
*
|
177 |
+
* @see Crypt_DES::enablePadding()
|
178 |
+
* @var Boolean
|
179 |
+
* @access private
|
180 |
+
*/
|
181 |
+
var $padding = true;
|
182 |
+
|
183 |
+
/**
|
184 |
+
* The Initialization Vector
|
185 |
+
*
|
186 |
+
* @see Crypt_DES::setIV()
|
187 |
+
* @var String
|
188 |
+
* @access private
|
189 |
+
*/
|
190 |
+
var $iv = "\0\0\0\0\0\0\0\0";
|
191 |
+
|
192 |
+
/**
|
193 |
+
* A "sliding" Initialization Vector
|
194 |
+
*
|
195 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
196 |
+
* @var String
|
197 |
+
* @access private
|
198 |
+
*/
|
199 |
+
var $encryptIV = "\0\0\0\0\0\0\0\0";
|
200 |
+
|
201 |
+
/**
|
202 |
+
* A "sliding" Initialization Vector
|
203 |
+
*
|
204 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
205 |
+
* @var String
|
206 |
+
* @access private
|
207 |
+
*/
|
208 |
+
var $decryptIV = "\0\0\0\0\0\0\0\0";
|
209 |
+
|
210 |
+
/**
|
211 |
+
* mcrypt resource for encryption
|
212 |
+
*
|
213 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
214 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
215 |
+
*
|
216 |
+
* @see Crypt_DES::encrypt()
|
217 |
+
* @var String
|
218 |
+
* @access private
|
219 |
+
*/
|
220 |
+
var $enmcrypt;
|
221 |
+
|
222 |
+
/**
|
223 |
+
* mcrypt resource for decryption
|
224 |
+
*
|
225 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
226 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
227 |
+
*
|
228 |
+
* @see Crypt_DES::decrypt()
|
229 |
+
* @var String
|
230 |
+
* @access private
|
231 |
+
*/
|
232 |
+
var $demcrypt;
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Does the enmcrypt resource need to be (re)initialized?
|
236 |
+
*
|
237 |
+
* @see Crypt_DES::setKey()
|
238 |
+
* @see Crypt_DES::setIV()
|
239 |
+
* @var Boolean
|
240 |
+
* @access private
|
241 |
+
*/
|
242 |
+
var $enchanged = true;
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Does the demcrypt resource need to be (re)initialized?
|
246 |
+
*
|
247 |
+
* @see Crypt_DES::setKey()
|
248 |
+
* @see Crypt_DES::setIV()
|
249 |
+
* @var Boolean
|
250 |
+
* @access private
|
251 |
+
*/
|
252 |
+
var $dechanged = true;
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Is the mode one that is paddable?
|
256 |
+
*
|
257 |
+
* @see Crypt_DES::Crypt_DES()
|
258 |
+
* @var Boolean
|
259 |
+
* @access private
|
260 |
+
*/
|
261 |
+
var $paddable = false;
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
265 |
+
*
|
266 |
+
* @see Crypt_DES::encrypt()
|
267 |
+
* @var Array
|
268 |
+
* @access private
|
269 |
+
*/
|
270 |
+
var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
274 |
+
*
|
275 |
+
* @see Crypt_DES::decrypt()
|
276 |
+
* @var Array
|
277 |
+
* @access private
|
278 |
+
*/
|
279 |
+
var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
280 |
+
|
281 |
+
/**
|
282 |
+
* mcrypt resource for CFB mode
|
283 |
+
*
|
284 |
+
* @see Crypt_DES::encrypt()
|
285 |
+
* @see Crypt_DES::decrypt()
|
286 |
+
* @var String
|
287 |
+
* @access private
|
288 |
+
*/
|
289 |
+
var $ecb;
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Performance-optimized callback function for en/decrypt()
|
293 |
+
*
|
294 |
+
* @var Callback
|
295 |
+
* @access private
|
296 |
+
*/
|
297 |
+
var $inline_crypt;
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Holds whether performance-optimized $inline_crypt should be used or not.
|
301 |
+
*
|
302 |
+
* @var Boolean
|
303 |
+
* @access private
|
304 |
+
*/
|
305 |
+
var $use_inline_crypt = false;
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Shuffle table.
|
309 |
+
*
|
310 |
+
* For each byte value index, the entry holds an 8-byte string
|
311 |
+
* with each byte containing all bits in the same state as the
|
312 |
+
* corresponding bit in the index value.
|
313 |
+
*
|
314 |
+
* @see Crypt_DES::_processBlock()
|
315 |
+
* @see Crypt_DES::_prepareKey()
|
316 |
+
* @var Array
|
317 |
+
* @access private
|
318 |
+
*/
|
319 |
+
var $shuffle = array(
|
320 |
+
"\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
|
321 |
+
"\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
|
322 |
+
"\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
|
323 |
+
"\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
|
324 |
+
"\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
|
325 |
+
"\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
|
326 |
+
"\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
|
327 |
+
"\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
|
328 |
+
"\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
|
329 |
+
"\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
|
330 |
+
"\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
|
331 |
+
"\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
|
332 |
+
"\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
|
333 |
+
"\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
|
334 |
+
"\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
|
335 |
+
"\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
|
336 |
+
"\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
|
337 |
+
"\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
|
338 |
+
"\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
|
339 |
+
"\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
|
340 |
+
"\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
|
341 |
+
"\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
|
342 |
+
"\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
|
343 |
+
"\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
|
344 |
+
"\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
|
345 |
+
"\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
|
346 |
+
"\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
|
347 |
+
"\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
|
348 |
+
"\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
|
349 |
+
"\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
|
350 |
+
"\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
|
351 |
+
"\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
|
352 |
+
"\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
|
353 |
+
"\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
|
354 |
+
"\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
|
355 |
+
"\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
|
356 |
+
"\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
|
357 |
+
"\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
|
358 |
+
"\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
|
359 |
+
"\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
|
360 |
+
"\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
|
361 |
+
"\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
|
362 |
+
"\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
|
363 |
+
"\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
|
364 |
+
"\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
|
365 |
+
"\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
|
366 |
+
"\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
|
367 |
+
"\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
|
368 |
+
"\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
|
369 |
+
"\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
|
370 |
+
"\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
|
371 |
+
"\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
|
372 |
+
"\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
|
373 |
+
"\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
|
374 |
+
"\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
|
375 |
+
"\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
|
376 |
+
"\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
|
377 |
+
"\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
|
378 |
+
"\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
|
379 |
+
"\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
|
380 |
+
"\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
|
381 |
+
"\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
|
382 |
+
"\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
|
383 |
+
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
|
384 |
+
"\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
|
385 |
+
"\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
|
386 |
+
"\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
|
387 |
+
"\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
|
388 |
+
"\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
|
389 |
+
"\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
|
390 |
+
"\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
|
391 |
+
"\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
|
392 |
+
"\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
|
393 |
+
"\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
|
394 |
+
"\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
|
395 |
+
"\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
|
396 |
+
"\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
|
397 |
+
"\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
|
398 |
+
"\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
|
399 |
+
"\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
|
400 |
+
"\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
|
401 |
+
"\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
|
402 |
+
"\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
|
403 |
+
"\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
|
404 |
+
"\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
|
405 |
+
"\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
|
406 |
+
"\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
|
407 |
+
"\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
|
408 |
+
"\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
|
409 |
+
"\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
|
410 |
+
"\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
|
411 |
+
"\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
|
412 |
+
"\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
|
413 |
+
"\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
|
414 |
+
"\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
|
415 |
+
"\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
|
416 |
+
"\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
|
417 |
+
"\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
|
418 |
+
"\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
|
419 |
+
"\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
|
420 |
+
"\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
|
421 |
+
"\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
|
422 |
+
"\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
|
423 |
+
"\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
|
424 |
+
"\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
|
425 |
+
"\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
|
426 |
+
"\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
|
427 |
+
"\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
|
428 |
+
"\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
|
429 |
+
"\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
|
430 |
+
"\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
|
431 |
+
"\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
|
432 |
+
"\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
|
433 |
+
"\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
|
434 |
+
"\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
|
435 |
+
"\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
|
436 |
+
"\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
|
437 |
+
"\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
|
438 |
+
"\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
|
439 |
+
"\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
|
440 |
+
"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
|
441 |
+
"\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
|
442 |
+
"\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
|
443 |
+
"\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
|
444 |
+
"\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
|
445 |
+
"\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
|
446 |
+
"\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
|
447 |
+
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
|
448 |
+
);
|
449 |
+
|
450 |
+
/**
|
451 |
+
* IP mapping helper table.
|
452 |
+
*
|
453 |
+
* Indexing this table with each source byte performs the initial bit permutation.
|
454 |
+
*
|
455 |
+
* @var Array
|
456 |
+
* @access private
|
457 |
+
*/
|
458 |
+
var $ipmap = array(
|
459 |
+
0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
|
460 |
+
0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
|
461 |
+
0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
|
462 |
+
0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
|
463 |
+
0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
|
464 |
+
0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
|
465 |
+
0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
|
466 |
+
0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
|
467 |
+
0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
|
468 |
+
0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
|
469 |
+
0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
|
470 |
+
0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
|
471 |
+
0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
|
472 |
+
0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
|
473 |
+
0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
|
474 |
+
0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
|
475 |
+
0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
|
476 |
+
0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
|
477 |
+
0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
|
478 |
+
0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
|
479 |
+
0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
|
480 |
+
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
|
481 |
+
0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
|
482 |
+
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
|
483 |
+
0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
|
484 |
+
0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
|
485 |
+
0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
|
486 |
+
0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
|
487 |
+
0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
|
488 |
+
0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
|
489 |
+
0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
|
490 |
+
0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
|
491 |
+
);
|
492 |
+
|
493 |
+
/**
|
494 |
+
* Inverse IP mapping helper table.
|
495 |
+
* Indexing this table with a byte value reverses the bit order.
|
496 |
+
*
|
497 |
+
* @var Array
|
498 |
+
* @access private
|
499 |
+
*/
|
500 |
+
var $invipmap = array(
|
501 |
+
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
|
502 |
+
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
503 |
+
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
504 |
+
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
505 |
+
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
|
506 |
+
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
507 |
+
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
508 |
+
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
509 |
+
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
|
510 |
+
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
511 |
+
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
|
512 |
+
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
513 |
+
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
|
514 |
+
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
515 |
+
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
|
516 |
+
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
517 |
+
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
|
518 |
+
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
519 |
+
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
|
520 |
+
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
521 |
+
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
|
522 |
+
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
523 |
+
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
|
524 |
+
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
525 |
+
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
|
526 |
+
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
527 |
+
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
|
528 |
+
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
529 |
+
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
530 |
+
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
531 |
+
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
|
532 |
+
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
533 |
+
);
|
534 |
+
|
535 |
+
/**
|
536 |
+
* Pre-permuted S-box1
|
537 |
+
*
|
538 |
+
* Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
|
539 |
+
* P table: concatenation can then be replaced by exclusive ORs.
|
540 |
+
*
|
541 |
+
* @var Array
|
542 |
+
* @access private
|
543 |
+
*/
|
544 |
+
var $sbox1 = array(
|
545 |
+
0x00808200, 0x00000000, 0x00008000, 0x00808202,
|
546 |
+
0x00808002, 0x00008202, 0x00000002, 0x00008000,
|
547 |
+
0x00000200, 0x00808200, 0x00808202, 0x00000200,
|
548 |
+
0x00800202, 0x00808002, 0x00800000, 0x00000002,
|
549 |
+
0x00000202, 0x00800200, 0x00800200, 0x00008200,
|
550 |
+
0x00008200, 0x00808000, 0x00808000, 0x00800202,
|
551 |
+
0x00008002, 0x00800002, 0x00800002, 0x00008002,
|
552 |
+
0x00000000, 0x00000202, 0x00008202, 0x00800000,
|
553 |
+
0x00008000, 0x00808202, 0x00000002, 0x00808000,
|
554 |
+
0x00808200, 0x00800000, 0x00800000, 0x00000200,
|
555 |
+
0x00808002, 0x00008000, 0x00008200, 0x00800002,
|
556 |
+
0x00000200, 0x00000002, 0x00800202, 0x00008202,
|
557 |
+
0x00808202, 0x00008002, 0x00808000, 0x00800202,
|
558 |
+
0x00800002, 0x00000202, 0x00008202, 0x00808200,
|
559 |
+
0x00000202, 0x00800200, 0x00800200, 0x00000000,
|
560 |
+
0x00008002, 0x00008200, 0x00000000, 0x00808002
|
561 |
+
);
|
562 |
+
|
563 |
+
/**
|
564 |
+
* Pre-permuted S-box2
|
565 |
+
*
|
566 |
+
* @var Array
|
567 |
+
* @access private
|
568 |
+
*/
|
569 |
+
var $sbox2 = array(
|
570 |
+
0x40084010, 0x40004000, 0x00004000, 0x00084010,
|
571 |
+
0x00080000, 0x00000010, 0x40080010, 0x40004010,
|
572 |
+
0x40000010, 0x40084010, 0x40084000, 0x40000000,
|
573 |
+
0x40004000, 0x00080000, 0x00000010, 0x40080010,
|
574 |
+
0x00084000, 0x00080010, 0x40004010, 0x00000000,
|
575 |
+
0x40000000, 0x00004000, 0x00084010, 0x40080000,
|
576 |
+
0x00080010, 0x40000010, 0x00000000, 0x00084000,
|
577 |
+
0x00004010, 0x40084000, 0x40080000, 0x00004010,
|
578 |
+
0x00000000, 0x00084010, 0x40080010, 0x00080000,
|
579 |
+
0x40004010, 0x40080000, 0x40084000, 0x00004000,
|
580 |
+
0x40080000, 0x40004000, 0x00000010, 0x40084010,
|
581 |
+
0x00084010, 0x00000010, 0x00004000, 0x40000000,
|
582 |
+
0x00004010, 0x40084000, 0x00080000, 0x40000010,
|
583 |
+
0x00080010, 0x40004010, 0x40000010, 0x00080010,
|
584 |
+
0x00084000, 0x00000000, 0x40004000, 0x00004010,
|
585 |
+
0x40000000, 0x40080010, 0x40084010, 0x00084000
|
586 |
+
);
|
587 |
+
|
588 |
+
/**
|
589 |
+
* Pre-permuted S-box3
|
590 |
+
*
|
591 |
+
* @var Array
|
592 |
+
* @access private
|
593 |
+
*/
|
594 |
+
var $sbox3 = array(
|
595 |
+
0x00000104, 0x04010100, 0x00000000, 0x04010004,
|
596 |
+
0x04000100, 0x00000000, 0x00010104, 0x04000100,
|
597 |
+
0x00010004, 0x04000004, 0x04000004, 0x00010000,
|
598 |
+
0x04010104, 0x00010004, 0x04010000, 0x00000104,
|
599 |
+
0x04000000, 0x00000004, 0x04010100, 0x00000100,
|
600 |
+
0x00010100, 0x04010000, 0x04010004, 0x00010104,
|
601 |
+
0x04000104, 0x00010100, 0x00010000, 0x04000104,
|
602 |
+
0x00000004, 0x04010104, 0x00000100, 0x04000000,
|
603 |
+
0x04010100, 0x04000000, 0x00010004, 0x00000104,
|
604 |
+
0x00010000, 0x04010100, 0x04000100, 0x00000000,
|
605 |
+
0x00000100, 0x00010004, 0x04010104, 0x04000100,
|
606 |
+
0x04000004, 0x00000100, 0x00000000, 0x04010004,
|
607 |
+
0x04000104, 0x00010000, 0x04000000, 0x04010104,
|
608 |
+
0x00000004, 0x00010104, 0x00010100, 0x04000004,
|
609 |
+
0x04010000, 0x04000104, 0x00000104, 0x04010000,
|
610 |
+
0x00010104, 0x00000004, 0x04010004, 0x00010100
|
611 |
+
);
|
612 |
+
|
613 |
+
/**
|
614 |
+
* Pre-permuted S-box4
|
615 |
+
*
|
616 |
+
* @var Array
|
617 |
+
* @access private
|
618 |
+
*/
|
619 |
+
var $sbox4 = array(
|
620 |
+
0x80401000, 0x80001040, 0x80001040, 0x00000040,
|
621 |
+
0x00401040, 0x80400040, 0x80400000, 0x80001000,
|
622 |
+
0x00000000, 0x00401000, 0x00401000, 0x80401040,
|
623 |
+
0x80000040, 0x00000000, 0x00400040, 0x80400000,
|
624 |
+
0x80000000, 0x00001000, 0x00400000, 0x80401000,
|
625 |
+
0x00000040, 0x00400000, 0x80001000, 0x00001040,
|
626 |
+
0x80400040, 0x80000000, 0x00001040, 0x00400040,
|
627 |
+
0x00001000, 0x00401040, 0x80401040, 0x80000040,
|
628 |
+
0x00400040, 0x80400000, 0x00401000, 0x80401040,
|
629 |
+
0x80000040, 0x00000000, 0x00000000, 0x00401000,
|
630 |
+
0x00001040, 0x00400040, 0x80400040, 0x80000000,
|
631 |
+
0x80401000, 0x80001040, 0x80001040, 0x00000040,
|
632 |
+
0x80401040, 0x80000040, 0x80000000, 0x00001000,
|
633 |
+
0x80400000, 0x80001000, 0x00401040, 0x80400040,
|
634 |
+
0x80001000, 0x00001040, 0x00400000, 0x80401000,
|
635 |
+
0x00000040, 0x00400000, 0x00001000, 0x00401040
|
636 |
+
);
|
637 |
+
|
638 |
+
/**
|
639 |
+
* Pre-permuted S-box5
|
640 |
+
*
|
641 |
+
* @var Array
|
642 |
+
* @access private
|
643 |
+
*/
|
644 |
+
var $sbox5 = array(
|
645 |
+
0x00000080, 0x01040080, 0x01040000, 0x21000080,
|
646 |
+
0x00040000, 0x00000080, 0x20000000, 0x01040000,
|
647 |
+
0x20040080, 0x00040000, 0x01000080, 0x20040080,
|
648 |
+
0x21000080, 0x21040000, 0x00040080, 0x20000000,
|
649 |
+
0x01000000, 0x20040000, 0x20040000, 0x00000000,
|
650 |
+
0x20000080, 0x21040080, 0x21040080, 0x01000080,
|
651 |
+
0x21040000, 0x20000080, 0x00000000, 0x21000000,
|
652 |
+
0x01040080, 0x01000000, 0x21000000, 0x00040080,
|
653 |
+
0x00040000, 0x21000080, 0x00000080, 0x01000000,
|
654 |
+
0x20000000, 0x01040000, 0x21000080, 0x20040080,
|
655 |
+
0x01000080, 0x20000000, 0x21040000, 0x01040080,
|
656 |
+
0x20040080, 0x00000080, 0x01000000, 0x21040000,
|
657 |
+
0x21040080, 0x00040080, 0x21000000, 0x21040080,
|
658 |
+
0x01040000, 0x00000000, 0x20040000, 0x21000000,
|
659 |
+
0x00040080, 0x01000080, 0x20000080, 0x00040000,
|
660 |
+
0x00000000, 0x20040000, 0x01040080, 0x20000080
|
661 |
+
);
|
662 |
+
|
663 |
+
/**
|
664 |
+
* Pre-permuted S-box6
|
665 |
+
*
|
666 |
+
* @var Array
|
667 |
+
* @access private
|
668 |
+
*/
|
669 |
+
var $sbox6 = array(
|
670 |
+
0x10000008, 0x10200000, 0x00002000, 0x10202008,
|
671 |
+
0x10200000, 0x00000008, 0x10202008, 0x00200000,
|
672 |
+
0x10002000, 0x00202008, 0x00200000, 0x10000008,
|
673 |
+
0x00200008, 0x10002000, 0x10000000, 0x00002008,
|
674 |
+
0x00000000, 0x00200008, 0x10002008, 0x00002000,
|
675 |
+
0x00202000, 0x10002008, 0x00000008, 0x10200008,
|
676 |
+
0x10200008, 0x00000000, 0x00202008, 0x10202000,
|
677 |
+
0x00002008, 0x00202000, 0x10202000, 0x10000000,
|
678 |
+
0x10002000, 0x00000008, 0x10200008, 0x00202000,
|
679 |
+
0x10202008, 0x00200000, 0x00002008, 0x10000008,
|
680 |
+
0x00200000, 0x10002000, 0x10000000, 0x00002008,
|
681 |
+
0x10000008, 0x10202008, 0x00202000, 0x10200000,
|
682 |
+
0x00202008, 0x10202000, 0x00000000, 0x10200008,
|
683 |
+
0x00000008, 0x00002000, 0x10200000, 0x00202008,
|
684 |
+
0x00002000, 0x00200008, 0x10002008, 0x00000000,
|
685 |
+
0x10202000, 0x10000000, 0x00200008, 0x10002008
|
686 |
+
);
|
687 |
+
|
688 |
+
/**
|
689 |
+
* Pre-permuted S-box7
|
690 |
+
*
|
691 |
+
* @var Array
|
692 |
+
* @access private
|
693 |
+
*/
|
694 |
+
var $sbox7 = array(
|
695 |
+
0x00100000, 0x02100001, 0x02000401, 0x00000000,
|
696 |
+
0x00000400, 0x02000401, 0x00100401, 0x02100400,
|
697 |
+
0x02100401, 0x00100000, 0x00000000, 0x02000001,
|
698 |
+
0x00000001, 0x02000000, 0x02100001, 0x00000401,
|
699 |
+
0x02000400, 0x00100401, 0x00100001, 0x02000400,
|
700 |
+
0x02000001, 0x02100000, 0x02100400, 0x00100001,
|
701 |
+
0x02100000, 0x00000400, 0x00000401, 0x02100401,
|
702 |
+
0x00100400, 0x00000001, 0x02000000, 0x00100400,
|
703 |
+
0x02000000, 0x00100400, 0x00100000, 0x02000401,
|
704 |
+
0x02000401, 0x02100001, 0x02100001, 0x00000001,
|
705 |
+
0x00100001, 0x02000000, 0x02000400, 0x00100000,
|
706 |
+
0x02100400, 0x00000401, 0x00100401, 0x02100400,
|
707 |
+
0x00000401, 0x02000001, 0x02100401, 0x02100000,
|
708 |
+
0x00100400, 0x00000000, 0x00000001, 0x02100401,
|
709 |
+
0x00000000, 0x00100401, 0x02100000, 0x00000400,
|
710 |
+
0x02000001, 0x02000400, 0x00000400, 0x00100001
|
711 |
+
);
|
712 |
+
|
713 |
+
/**
|
714 |
+
* Pre-permuted S-box8
|
715 |
+
*
|
716 |
+
* @var Array
|
717 |
+
* @access private
|
718 |
+
*/
|
719 |
+
var $sbox8 = array(
|
720 |
+
0x08000820, 0x00000800, 0x00020000, 0x08020820,
|
721 |
+
0x08000000, 0x08000820, 0x00000020, 0x08000000,
|
722 |
+
0x00020020, 0x08020000, 0x08020820, 0x00020800,
|
723 |
+
0x08020800, 0x00020820, 0x00000800, 0x00000020,
|
724 |
+
0x08020000, 0x08000020, 0x08000800, 0x00000820,
|
725 |
+
0x00020800, 0x00020020, 0x08020020, 0x08020800,
|
726 |
+
0x00000820, 0x00000000, 0x00000000, 0x08020020,
|
727 |
+
0x08000020, 0x08000800, 0x00020820, 0x00020000,
|
728 |
+
0x00020820, 0x00020000, 0x08020800, 0x00000800,
|
729 |
+
0x00000020, 0x08020020, 0x00000800, 0x00020820,
|
730 |
+
0x08000800, 0x00000020, 0x08000020, 0x08020000,
|
731 |
+
0x08020020, 0x08000000, 0x00020000, 0x08000820,
|
732 |
+
0x00000000, 0x08020820, 0x00020020, 0x08000020,
|
733 |
+
0x08020000, 0x08000800, 0x08000820, 0x00000000,
|
734 |
+
0x08020820, 0x00020800, 0x00020800, 0x00000820,
|
735 |
+
0x00000820, 0x00020020, 0x08000000, 0x08020800
|
736 |
+
);
|
737 |
+
|
738 |
+
/**
|
739 |
+
* Default Constructor.
|
740 |
+
*
|
741 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
742 |
+
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
|
743 |
+
*
|
744 |
+
* @param optional Integer $mode
|
745 |
+
* @return Crypt_DES
|
746 |
+
* @access public
|
747 |
+
*/
|
748 |
+
function Crypt_DES($mode = CRYPT_DES_MODE_CBC)
|
749 |
+
{
|
750 |
+
if ( !defined('CRYPT_DES_MODE') ) {
|
751 |
+
switch (true) {
|
752 |
+
case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()):
|
753 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
|
754 |
+
break;
|
755 |
+
default:
|
756 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
|
757 |
+
}
|
758 |
+
}
|
759 |
+
|
760 |
+
switch ( CRYPT_DES_MODE ) {
|
761 |
+
case CRYPT_DES_MODE_MCRYPT:
|
762 |
+
switch ($mode) {
|
763 |
+
case CRYPT_DES_MODE_ECB:
|
764 |
+
$this->paddable = true;
|
765 |
+
$this->mode = MCRYPT_MODE_ECB;
|
766 |
+
break;
|
767 |
+
case CRYPT_DES_MODE_CTR:
|
768 |
+
$this->mode = 'ctr';
|
769 |
+
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
|
770 |
+
break;
|
771 |
+
case CRYPT_DES_MODE_CFB:
|
772 |
+
$this->mode = 'ncfb';
|
773 |
+
$this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
|
774 |
+
break;
|
775 |
+
case CRYPT_DES_MODE_OFB:
|
776 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
777 |
+
break;
|
778 |
+
case CRYPT_DES_MODE_CBC:
|
779 |
+
default:
|
780 |
+
$this->paddable = true;
|
781 |
+
$this->mode = MCRYPT_MODE_CBC;
|
782 |
+
}
|
783 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
|
784 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
|
785 |
+
|
786 |
+
break;
|
787 |
+
default:
|
788 |
+
switch ($mode) {
|
789 |
+
case CRYPT_DES_MODE_ECB:
|
790 |
+
case CRYPT_DES_MODE_CBC:
|
791 |
+
$this->paddable = true;
|
792 |
+
$this->mode = $mode;
|
793 |
+
break;
|
794 |
+
case CRYPT_DES_MODE_CTR:
|
795 |
+
case CRYPT_DES_MODE_CFB:
|
796 |
+
case CRYPT_DES_MODE_OFB:
|
797 |
+
$this->mode = $mode;
|
798 |
+
break;
|
799 |
+
default:
|
800 |
+
$this->paddable = true;
|
801 |
+
$this->mode = CRYPT_DES_MODE_CBC;
|
802 |
+
}
|
803 |
+
if (function_exists('create_function') && is_callable('create_function')) {
|
804 |
+
$this->inline_crypt_setup();
|
805 |
+
$this->use_inline_crypt = true;
|
806 |
+
}
|
807 |
+
}
|
808 |
+
}
|
809 |
+
|
810 |
+
/**
|
811 |
+
* Sets the key.
|
812 |
+
*
|
813 |
+
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
|
814 |
+
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
|
815 |
+
* null byte if it is less then eight characters long.
|
816 |
+
*
|
817 |
+
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
818 |
+
*
|
819 |
+
* If the key is not explicitly set, it'll be assumed to be all zero's.
|
820 |
+
*
|
821 |
+
* @access public
|
822 |
+
* @param String $key
|
823 |
+
*/
|
824 |
+
function setKey($key)
|
825 |
+
{
|
826 |
+
$this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key);
|
827 |
+
$this->enchanged = true;
|
828 |
+
$this->dechanged = true;
|
829 |
+
}
|
830 |
+
|
831 |
+
/**
|
832 |
+
* Sets the password.
|
833 |
+
*
|
834 |
+
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
|
835 |
+
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
|
836 |
+
* $hash, $salt, $count
|
837 |
+
*
|
838 |
+
* @param String $password
|
839 |
+
* @param optional String $method
|
840 |
+
* @access public
|
841 |
+
*/
|
842 |
+
function setPassword($password, $method = 'pbkdf2')
|
843 |
+
{
|
844 |
+
$key = '';
|
845 |
+
|
846 |
+
switch ($method) {
|
847 |
+
default: // 'pbkdf2'
|
848 |
+
list(, , $hash, $salt, $count) = func_get_args();
|
849 |
+
if (!isset($hash)) {
|
850 |
+
$hash = 'sha1';
|
851 |
+
}
|
852 |
+
// WPA and WPA2 use the SSID as the salt
|
853 |
+
if (!isset($salt)) {
|
854 |
+
$salt = 'phpseclib/salt';
|
855 |
+
}
|
856 |
+
// RFC2898#section-4.2 uses 1,000 iterations by default
|
857 |
+
// WPA and WPA2 use 4,096.
|
858 |
+
if (!isset($count)) {
|
859 |
+
$count = 1000;
|
860 |
+
}
|
861 |
+
|
862 |
+
if (!class_exists('Crypt_Hash')) {
|
863 |
+
require_once('Crypt/Hash.php');
|
864 |
+
}
|
865 |
+
|
866 |
+
$i = 1;
|
867 |
+
while (strlen($key) < 8) { // $dkLen == 8
|
868 |
+
//$dk.= $this->_pbkdf($password, $salt, $count, $i++);
|
869 |
+
$hmac = new Crypt_Hash();
|
870 |
+
$hmac->setHash($hash);
|
871 |
+
$hmac->setKey($password);
|
872 |
+
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
873 |
+
for ($j = 2; $j <= $count; $j++) {
|
874 |
+
$u = $hmac->hash($u);
|
875 |
+
$f^= $u;
|
876 |
+
}
|
877 |
+
$key.= $f;
|
878 |
+
}
|
879 |
+
}
|
880 |
+
|
881 |
+
$this->setKey($key);
|
882 |
+
}
|
883 |
+
|
884 |
+
/**
|
885 |
+
* Sets the initialization vector. (optional)
|
886 |
+
*
|
887 |
+
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
|
888 |
+
* to be all zero's.
|
889 |
+
*
|
890 |
+
* @access public
|
891 |
+
* @param String $iv
|
892 |
+
*/
|
893 |
+
function setIV($iv)
|
894 |
+
{
|
895 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
|
896 |
+
$this->enchanged = true;
|
897 |
+
$this->dechanged = true;
|
898 |
+
}
|
899 |
+
|
900 |
+
/**
|
901 |
+
* Generate CTR XOR encryption key
|
902 |
+
*
|
903 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
904 |
+
* plaintext / ciphertext in CTR mode.
|
905 |
+
*
|
906 |
+
* @see Crypt_DES::decrypt()
|
907 |
+
* @see Crypt_DES::encrypt()
|
908 |
+
* @access public
|
909 |
+
* @param String $iv
|
910 |
+
*/
|
911 |
+
function _generate_xor(&$iv)
|
912 |
+
{
|
913 |
+
$xor = $iv;
|
914 |
+
for ($j = 4; $j <= 8; $j+=4) {
|
915 |
+
$temp = substr($iv, -$j, 4);
|
916 |
+
switch ($temp) {
|
917 |
+
case "\xFF\xFF\xFF\xFF":
|
918 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
919 |
+
break;
|
920 |
+
case "\x7F\xFF\xFF\xFF":
|
921 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
922 |
+
break 2;
|
923 |
+
default:
|
924 |
+
extract(unpack('Ncount', $temp));
|
925 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
926 |
+
break 2;
|
927 |
+
}
|
928 |
+
}
|
929 |
+
|
930 |
+
return $xor;
|
931 |
+
}
|
932 |
+
|
933 |
+
/**
|
934 |
+
* Encrypts a message.
|
935 |
+
*
|
936 |
+
* $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the
|
937 |
+
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
938 |
+
* URL:
|
939 |
+
*
|
940 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
941 |
+
*
|
942 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
943 |
+
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
|
944 |
+
* length.
|
945 |
+
*
|
946 |
+
* @see Crypt_DES::decrypt()
|
947 |
+
* @access public
|
948 |
+
* @param String $plaintext
|
949 |
+
*/
|
950 |
+
function encrypt($plaintext)
|
951 |
+
{
|
952 |
+
if ($this->paddable) {
|
953 |
+
$plaintext = $this->_pad($plaintext);
|
954 |
+
}
|
955 |
+
|
956 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
957 |
+
if ($this->enchanged) {
|
958 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
|
959 |
+
if ($this->mode == 'ncfb') {
|
960 |
+
mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
|
961 |
+
}
|
962 |
+
$this->enchanged = false;
|
963 |
+
}
|
964 |
+
|
965 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
966 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
967 |
+
} else {
|
968 |
+
$iv = &$this->encryptIV;
|
969 |
+
$pos = &$this->enbuffer['pos'];
|
970 |
+
$len = strlen($plaintext);
|
971 |
+
$ciphertext = '';
|
972 |
+
$i = 0;
|
973 |
+
if ($pos) {
|
974 |
+
$orig_pos = $pos;
|
975 |
+
$max = 8 - $pos;
|
976 |
+
if ($len >= $max) {
|
977 |
+
$i = $max;
|
978 |
+
$len-= $max;
|
979 |
+
$pos = 0;
|
980 |
+
} else {
|
981 |
+
$i = $len;
|
982 |
+
$pos+= $len;
|
983 |
+
$len = 0;
|
984 |
+
}
|
985 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
986 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
987 |
+
$this->enbuffer['enmcrypt_init'] = true;
|
988 |
+
}
|
989 |
+
if ($len >= 8) {
|
990 |
+
if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
|
991 |
+
if ($this->enbuffer['enmcrypt_init'] === true) {
|
992 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $iv);
|
993 |
+
$this->enbuffer['enmcrypt_init'] = false;
|
994 |
+
}
|
995 |
+
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
|
996 |
+
$iv = substr($ciphertext, -8);
|
997 |
+
$len%= 8;
|
998 |
+
} else {
|
999 |
+
while ($len >= 8) {
|
1000 |
+
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
|
1001 |
+
$ciphertext.= $iv;
|
1002 |
+
$len-= 8;
|
1003 |
+
$i+= 8;
|
1004 |
+
}
|
1005 |
+
}
|
1006 |
+
}
|
1007 |
+
if ($len) {
|
1008 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
1009 |
+
$block = $iv ^ substr($plaintext, -$len);
|
1010 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
1011 |
+
$ciphertext.= $block;
|
1012 |
+
$pos = $len;
|
1013 |
+
}
|
1014 |
+
return $ciphertext;
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
if (!$this->continuousBuffer) {
|
1018 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
|
1019 |
+
}
|
1020 |
+
|
1021 |
+
return $ciphertext;
|
1022 |
+
}
|
1023 |
+
|
1024 |
+
if (!is_array($this->keys)) {
|
1025 |
+
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
if ($this->use_inline_crypt) {
|
1029 |
+
$inline = $this->inline_crypt;
|
1030 |
+
return $inline('encrypt', $this, $plaintext);
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
$buffer = &$this->enbuffer;
|
1034 |
+
$continuousBuffer = $this->continuousBuffer;
|
1035 |
+
$ciphertext = '';
|
1036 |
+
switch ($this->mode) {
|
1037 |
+
case CRYPT_DES_MODE_ECB:
|
1038 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
1039 |
+
$ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
|
1040 |
+
}
|
1041 |
+
break;
|
1042 |
+
case CRYPT_DES_MODE_CBC:
|
1043 |
+
$xor = $this->encryptIV;
|
1044 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
1045 |
+
$block = substr($plaintext, $i, 8);
|
1046 |
+
$block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
|
1047 |
+
$xor = $block;
|
1048 |
+
$ciphertext.= $block;
|
1049 |
+
}
|
1050 |
+
if ($this->continuousBuffer) {
|
1051 |
+
$this->encryptIV = $xor;
|
1052 |
+
}
|
1053 |
+
break;
|
1054 |
+
case CRYPT_DES_MODE_CTR:
|
1055 |
+
$xor = $this->encryptIV;
|
1056 |
+
if (strlen($buffer['encrypted'])) {
|
1057 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
1058 |
+
$block = substr($plaintext, $i, 8);
|
1059 |
+
if (strlen($block) > strlen($buffer['encrypted'])) {
|
1060 |
+
$buffer['encrypted'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
|
1061 |
+
}
|
1062 |
+
$key = $this->_string_shift($buffer['encrypted']);
|
1063 |
+
$ciphertext.= $block ^ $key;
|
1064 |
+
}
|
1065 |
+
} else {
|
1066 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
1067 |
+
$block = substr($plaintext, $i, 8);
|
1068 |
+
$key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
|
1069 |
+
$ciphertext.= $block ^ $key;
|
1070 |
+
}
|
1071 |
+
}
|
1072 |
+
if ($this->continuousBuffer) {
|
1073 |
+
$this->encryptIV = $xor;
|
1074 |
+
if ($start = strlen($plaintext) & 7) {
|
1075 |
+
$buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
|
1076 |
+
}
|
1077 |
+
}
|
1078 |
+
break;
|
1079 |
+
case CRYPT_DES_MODE_CFB:
|
1080 |
+
if ($this->continuousBuffer) {
|
1081 |
+
$iv = &$this->encryptIV;
|
1082 |
+
$pos = &$buffer['pos'];
|
1083 |
+
} else {
|
1084 |
+
$iv = $this->encryptIV;
|
1085 |
+
$pos = 0;
|
1086 |
+
}
|
1087 |
+
$len = strlen($plaintext);
|
1088 |
+
$i = 0;
|
1089 |
+
if ($pos) {
|
1090 |
+
$orig_pos = $pos;
|
1091 |
+
$max = 8 - $pos;
|
1092 |
+
if ($len >= $max) {
|
1093 |
+
$i = $max;
|
1094 |
+
$len-= $max;
|
1095 |
+
$pos = 0;
|
1096 |
+
} else {
|
1097 |
+
$i = $len;
|
1098 |
+
$pos+= $len;
|
1099 |
+
$len = 0;
|
1100 |
+
}
|
1101 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
1102 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
1103 |
+
}
|
1104 |
+
while ($len >= 8) {
|
1105 |
+
$iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT) ^ substr($plaintext, $i, 8);
|
1106 |
+
$ciphertext.= $iv;
|
1107 |
+
$len-= 8;
|
1108 |
+
$i+= 8;
|
1109 |
+
}
|
1110 |
+
if ($len) {
|
1111 |
+
$iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
1112 |
+
$block = $iv ^ substr($plaintext, $i);
|
1113 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
1114 |
+
$ciphertext.= $block;
|
1115 |
+
$pos = $len;
|
1116 |
+
}
|
1117 |
+
return $ciphertext;
|
1118 |
+
case CRYPT_DES_MODE_OFB:
|
1119 |
+
$xor = $this->encryptIV;
|
1120 |
+
if (strlen($buffer['xor'])) {
|
1121 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
1122 |
+
$block = substr($plaintext, $i, 8);
|
1123 |
+
if (strlen($block) > strlen($buffer['xor'])) {
|
1124 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
1125 |
+
$buffer['xor'].= $xor;
|
1126 |
+
}
|
1127 |
+
$key = $this->_string_shift($buffer['xor']);
|
1128 |
+
$ciphertext.= $block ^ $key;
|
1129 |
+
}
|
1130 |
+
} else {
|
1131 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
1132 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
1133 |
+
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
|
1134 |
+
}
|
1135 |
+
$key = $xor;
|
1136 |
+
}
|
1137 |
+
if ($this->continuousBuffer) {
|
1138 |
+
$this->encryptIV = $xor;
|
1139 |
+
if ($start = strlen($plaintext) & 7) {
|
1140 |
+
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
1141 |
+
}
|
1142 |
+
}
|
1143 |
+
}
|
1144 |
+
|
1145 |
+
return $ciphertext;
|
1146 |
+
}
|
1147 |
+
|
1148 |
+
/**
|
1149 |
+
* Decrypts a message.
|
1150 |
+
*
|
1151 |
+
* If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
|
1152 |
+
*
|
1153 |
+
* @see Crypt_DES::encrypt()
|
1154 |
+
* @access public
|
1155 |
+
* @param String $ciphertext
|
1156 |
+
*/
|
1157 |
+
function decrypt($ciphertext)
|
1158 |
+
{
|
1159 |
+
if ($this->paddable) {
|
1160 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
1161 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
1162 |
+
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
|
1163 |
+
}
|
1164 |
+
|
1165 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
1166 |
+
if ($this->dechanged) {
|
1167 |
+
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
|
1168 |
+
if ($this->mode == 'ncfb') {
|
1169 |
+
mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
|
1170 |
+
}
|
1171 |
+
$this->dechanged = false;
|
1172 |
+
}
|
1173 |
+
|
1174 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
1175 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
1176 |
+
} else {
|
1177 |
+
$iv = &$this->decryptIV;
|
1178 |
+
$pos = &$this->debuffer['pos'];
|
1179 |
+
$len = strlen($ciphertext);
|
1180 |
+
$plaintext = '';
|
1181 |
+
$i = 0;
|
1182 |
+
if ($pos) {
|
1183 |
+
$orig_pos = $pos;
|
1184 |
+
$max = 8 - $pos;
|
1185 |
+
if ($len >= $max) {
|
1186 |
+
$i = $max;
|
1187 |
+
$len-= $max;
|
1188 |
+
$pos = 0;
|
1189 |
+
} else {
|
1190 |
+
$i = $len;
|
1191 |
+
$pos+= $len;
|
1192 |
+
$len = 0;
|
1193 |
+
}
|
1194 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
1195 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
1196 |
+
}
|
1197 |
+
if ($len >= 8) {
|
1198 |
+
$cb = substr($ciphertext, $i, $len - $len % 8);
|
1199 |
+
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
1200 |
+
$iv = substr($cb, -8);
|
1201 |
+
$len%= 8;
|
1202 |
+
}
|
1203 |
+
if ($len) {
|
1204 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
1205 |
+
$plaintext.= $iv ^ substr($ciphertext, -$len);
|
1206 |
+
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
|
1207 |
+
$pos = $len;
|
1208 |
+
}
|
1209 |
+
return $plaintext;
|
1210 |
+
}
|
1211 |
+
|
1212 |
+
if (!$this->continuousBuffer) {
|
1213 |
+
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
|
1214 |
+
}
|
1215 |
+
|
1216 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
if (!is_array($this->keys)) {
|
1220 |
+
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
if ($this->use_inline_crypt) {
|
1224 |
+
$inline = $this->inline_crypt;
|
1225 |
+
return $inline('decrypt', $this, $ciphertext);
|
1226 |
+
}
|
1227 |
+
|
1228 |
+
$buffer = &$this->debuffer;
|
1229 |
+
$continuousBuffer = $this->continuousBuffer;
|
1230 |
+
$plaintext = '';
|
1231 |
+
switch ($this->mode) {
|
1232 |
+
case CRYPT_DES_MODE_ECB:
|
1233 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
1234 |
+
$plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
|
1235 |
+
}
|
1236 |
+
break;
|
1237 |
+
case CRYPT_DES_MODE_CBC:
|
1238 |
+
$xor = $this->decryptIV;
|
1239 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
1240 |
+
$block = substr($ciphertext, $i, 8);
|
1241 |
+
$plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
|
1242 |
+
$xor = $block;
|
1243 |
+
}
|
1244 |
+
if ($this->continuousBuffer) {
|
1245 |
+
$this->decryptIV = $xor;
|
1246 |
+
}
|
1247 |
+
break;
|
1248 |
+
case CRYPT_DES_MODE_CTR:
|
1249 |
+
$xor = $this->decryptIV;
|
1250 |
+
if (strlen($buffer['ciphertext'])) {
|
1251 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
1252 |
+
$block = substr($ciphertext, $i, 8);
|
1253 |
+
if (strlen($block) > strlen($buffer['ciphertext'])) {
|
1254 |
+
$buffer['ciphertext'].= $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
|
1255 |
+
}
|
1256 |
+
$key = $this->_string_shift($buffer['ciphertext']);
|
1257 |
+
$plaintext.= $block ^ $key;
|
1258 |
+
}
|
1259 |
+
} else {
|
1260 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
1261 |
+
$block = substr($ciphertext, $i, 8);
|
1262 |
+
$key = $this->_processBlock($this->_generate_xor($xor), CRYPT_DES_ENCRYPT);
|
1263 |
+
$plaintext.= $block ^ $key;
|
1264 |
+
}
|
1265 |
+
}
|
1266 |
+
if ($this->continuousBuffer) {
|
1267 |
+
$this->decryptIV = $xor;
|
1268 |
+
if ($start = strlen($ciphertext) % 8) {
|
1269 |
+
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
|
1270 |
+
}
|
1271 |
+
}
|
1272 |
+
break;
|
1273 |
+
case CRYPT_DES_MODE_CFB:
|
1274 |
+
if ($this->continuousBuffer) {
|
1275 |
+
$iv = &$this->decryptIV;
|
1276 |
+
$pos = &$buffer['pos'];
|
1277 |
+
} else {
|
1278 |
+
$iv = $this->decryptIV;
|
1279 |
+
$pos = 0;
|
1280 |
+
}
|
1281 |
+
$len = strlen($ciphertext);
|
1282 |
+
$i = 0;
|
1283 |
+
if ($pos) {
|
1284 |
+
$orig_pos = $pos;
|
1285 |
+
$max = 8 - $pos;
|
1286 |
+
if ($len >= $max) {
|
1287 |
+
$i = $max;
|
1288 |
+
$len-= $max;
|
1289 |
+
$pos = 0;
|
1290 |
+
} else {
|
1291 |
+
$i = $len;
|
1292 |
+
$pos+= $len;
|
1293 |
+
$len = 0;
|
1294 |
+
}
|
1295 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
1296 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
1297 |
+
}
|
1298 |
+
while ($len >= 8) {
|
1299 |
+
$iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
1300 |
+
$cb = substr($ciphertext, $i, 8);
|
1301 |
+
$plaintext.= $iv ^ $cb;
|
1302 |
+
$iv = $cb;
|
1303 |
+
$len-= 8;
|
1304 |
+
$i+= 8;
|
1305 |
+
}
|
1306 |
+
if ($len) {
|
1307 |
+
$iv = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
1308 |
+
$plaintext.= $iv ^ substr($ciphertext, $i);
|
1309 |
+
$iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
|
1310 |
+
$pos = $len;
|
1311 |
+
}
|
1312 |
+
return $plaintext;
|
1313 |
+
case CRYPT_DES_MODE_OFB:
|
1314 |
+
$xor = $this->decryptIV;
|
1315 |
+
if (strlen($buffer['xor'])) {
|
1316 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
1317 |
+
$block = substr($ciphertext, $i, 8);
|
1318 |
+
if (strlen($block) > strlen($buffer['xor'])) {
|
1319 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
1320 |
+
$buffer['xor'].= $xor;
|
1321 |
+
}
|
1322 |
+
$key = $this->_string_shift($buffer['xor']);
|
1323 |
+
$plaintext.= $block ^ $key;
|
1324 |
+
}
|
1325 |
+
} else {
|
1326 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
1327 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
1328 |
+
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
|
1329 |
+
}
|
1330 |
+
$key = $xor;
|
1331 |
+
}
|
1332 |
+
if ($this->continuousBuffer) {
|
1333 |
+
$this->decryptIV = $xor;
|
1334 |
+
if ($start = strlen($ciphertext) % 8) {
|
1335 |
+
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
1336 |
+
}
|
1337 |
+
}
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
1341 |
+
}
|
1342 |
+
|
1343 |
+
/**
|
1344 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
1345 |
+
*
|
1346 |
+
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
1347 |
+
* will yield different outputs:
|
1348 |
+
*
|
1349 |
+
* <code>
|
1350 |
+
* echo $des->encrypt(substr($plaintext, 0, 8));
|
1351 |
+
* echo $des->encrypt(substr($plaintext, 8, 8));
|
1352 |
+
* </code>
|
1353 |
+
* <code>
|
1354 |
+
* echo $des->encrypt($plaintext);
|
1355 |
+
* </code>
|
1356 |
+
*
|
1357 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
1358 |
+
* another, as demonstrated with the following:
|
1359 |
+
*
|
1360 |
+
* <code>
|
1361 |
+
* $des->encrypt(substr($plaintext, 0, 8));
|
1362 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
1363 |
+
* </code>
|
1364 |
+
* <code>
|
1365 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
1366 |
+
* </code>
|
1367 |
+
*
|
1368 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
1369 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
1370 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
1371 |
+
*
|
1372 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
1373 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
1374 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
1375 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
1376 |
+
*
|
1377 |
+
* @see Crypt_DES::disableContinuousBuffer()
|
1378 |
+
* @access public
|
1379 |
+
*/
|
1380 |
+
function enableContinuousBuffer()
|
1381 |
+
{
|
1382 |
+
$this->continuousBuffer = true;
|
1383 |
+
}
|
1384 |
+
|
1385 |
+
/**
|
1386 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
1387 |
+
*
|
1388 |
+
* The default behavior.
|
1389 |
+
*
|
1390 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
1391 |
+
* @access public
|
1392 |
+
*/
|
1393 |
+
function disableContinuousBuffer()
|
1394 |
+
{
|
1395 |
+
$this->continuousBuffer = false;
|
1396 |
+
$this->encryptIV = $this->iv;
|
1397 |
+
$this->decryptIV = $this->iv;
|
1398 |
+
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
1399 |
+
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
1400 |
+
|
1401 |
+
if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) {
|
1402 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->iv);
|
1403 |
+
mcrypt_generic_init($this->demcrypt, $this->keys, $this->iv);
|
1404 |
+
}
|
1405 |
+
}
|
1406 |
+
|
1407 |
+
/**
|
1408 |
+
* Pad "packets".
|
1409 |
+
*
|
1410 |
+
* DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
|
1411 |
+
* a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
|
1412 |
+
*
|
1413 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
|
1414 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
1415 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
1416 |
+
* transmitted separately)
|
1417 |
+
*
|
1418 |
+
* @see Crypt_DES::disablePadding()
|
1419 |
+
* @access public
|
1420 |
+
*/
|
1421 |
+
function enablePadding()
|
1422 |
+
{
|
1423 |
+
$this->padding = true;
|
1424 |
+
}
|
1425 |
+
|
1426 |
+
/**
|
1427 |
+
* Do not pad packets.
|
1428 |
+
*
|
1429 |
+
* @see Crypt_DES::enablePadding()
|
1430 |
+
* @access public
|
1431 |
+
*/
|
1432 |
+
function disablePadding()
|
1433 |
+
{
|
1434 |
+
$this->padding = false;
|
1435 |
+
}
|
1436 |
+
|
1437 |
+
/**
|
1438 |
+
* Pads a string
|
1439 |
+
*
|
1440 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
|
1441 |
+
* 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
|
1442 |
+
*
|
1443 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
1444 |
+
* and padding will, hence forth, be enabled.
|
1445 |
+
*
|
1446 |
+
* @see Crypt_DES::_unpad()
|
1447 |
+
* @access private
|
1448 |
+
*/
|
1449 |
+
function _pad($text)
|
1450 |
+
{
|
1451 |
+
$length = strlen($text);
|
1452 |
+
|
1453 |
+
if (!$this->padding) {
|
1454 |
+
if (($length & 7) == 0) {
|
1455 |
+
return $text;
|
1456 |
+
} else {
|
1457 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
|
1458 |
+
$this->padding = true;
|
1459 |
+
}
|
1460 |
+
}
|
1461 |
+
|
1462 |
+
$pad = 8 - ($length & 7);
|
1463 |
+
return str_pad($text, $length + $pad, chr($pad));
|
1464 |
+
}
|
1465 |
+
|
1466 |
+
/**
|
1467 |
+
* Unpads a string
|
1468 |
+
*
|
1469 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
1470 |
+
* and false will be returned.
|
1471 |
+
*
|
1472 |
+
* @see Crypt_DES::_pad()
|
1473 |
+
* @access private
|
1474 |
+
*/
|
1475 |
+
function _unpad($text)
|
1476 |
+
{
|
1477 |
+
if (!$this->padding) {
|
1478 |
+
return $text;
|
1479 |
+
}
|
1480 |
+
|
1481 |
+
$length = ord($text[strlen($text) - 1]);
|
1482 |
+
|
1483 |
+
if (!$length || $length > 8) {
|
1484 |
+
return false;
|
1485 |
+
}
|
1486 |
+
|
1487 |
+
return substr($text, 0, -$length);
|
1488 |
+
}
|
1489 |
+
|
1490 |
+
/**
|
1491 |
+
* Encrypts or decrypts a 64-bit block
|
1492 |
+
*
|
1493 |
+
* $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
|
1494 |
+
* {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
|
1495 |
+
* idea of what this function does.
|
1496 |
+
*
|
1497 |
+
* @access private
|
1498 |
+
* @param String $block
|
1499 |
+
* @param Integer $mode
|
1500 |
+
* @return String
|
1501 |
+
*/
|
1502 |
+
function _processBlock($block, $mode)
|
1503 |
+
{
|
1504 |
+
$shuffle = $this->shuffle;
|
1505 |
+
$invipmap = $this->invipmap;
|
1506 |
+
$ipmap = $this->ipmap;
|
1507 |
+
$sbox1 = $this->sbox1;
|
1508 |
+
$sbox2 = $this->sbox2;
|
1509 |
+
$sbox3 = $this->sbox3;
|
1510 |
+
$sbox4 = $this->sbox4;
|
1511 |
+
$sbox5 = $this->sbox5;
|
1512 |
+
$sbox6 = $this->sbox6;
|
1513 |
+
$sbox7 = $this->sbox7;
|
1514 |
+
$sbox8 = $this->sbox8;
|
1515 |
+
$keys = $this->keys[$mode];
|
1516 |
+
|
1517 |
+
// Do the initial IP permutation.
|
1518 |
+
$t = unpack('Nl/Nr', $block);
|
1519 |
+
list($l, $r) = array($t['l'], $t['r']);
|
1520 |
+
$block = ($shuffle[$ipmap[$r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
|
1521 |
+
($shuffle[$ipmap[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
|
1522 |
+
($shuffle[$ipmap[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
|
1523 |
+
($shuffle[$ipmap[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
|
1524 |
+
($shuffle[$ipmap[$l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
|
1525 |
+
($shuffle[$ipmap[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
|
1526 |
+
($shuffle[$ipmap[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
|
1527 |
+
($shuffle[$ipmap[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01");
|
1528 |
+
|
1529 |
+
// Extract L0 and R0.
|
1530 |
+
$t = unpack('Nl/Nr', $block);
|
1531 |
+
list($l, $r) = array($t['l'], $t['r']);
|
1532 |
+
|
1533 |
+
// Perform the 16 steps.
|
1534 |
+
for ($i = 0; $i < 16; $i++) {
|
1535 |
+
// start of "the Feistel (F) function" - see the following URL:
|
1536 |
+
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
|
1537 |
+
// Merge key schedule.
|
1538 |
+
$b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[$i][0];
|
1539 |
+
$b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[$i][1];
|
1540 |
+
|
1541 |
+
// S-box indexing.
|
1542 |
+
$t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
|
1543 |
+
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
|
1544 |
+
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
|
1545 |
+
$sbox7[$b1 & 0x3F] ^ $sbox8[$b2 & 0x3F] ^ $l;
|
1546 |
+
// end of "the Feistel (F) function"
|
1547 |
+
|
1548 |
+
$l = $r;
|
1549 |
+
$r = $t;
|
1550 |
+
}
|
1551 |
+
|
1552 |
+
// Perform the inverse IP permutation.
|
1553 |
+
return ($shuffle[$invipmap[($l >> 24) & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
|
1554 |
+
($shuffle[$invipmap[($r >> 24) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
|
1555 |
+
($shuffle[$invipmap[($l >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
|
1556 |
+
($shuffle[$invipmap[($r >> 16) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
|
1557 |
+
($shuffle[$invipmap[($l >> 8) & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
|
1558 |
+
($shuffle[$invipmap[($r >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
|
1559 |
+
($shuffle[$invipmap[$l & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
|
1560 |
+
($shuffle[$invipmap[$r & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01");
|
1561 |
+
}
|
1562 |
+
|
1563 |
+
/**
|
1564 |
+
* Creates the key schedule.
|
1565 |
+
*
|
1566 |
+
* @access private
|
1567 |
+
* @param String $key
|
1568 |
+
* @return Array
|
1569 |
+
*/
|
1570 |
+
function _prepareKey($key)
|
1571 |
+
{
|
1572 |
+
static $shifts = array( // number of key bits shifted per round
|
1573 |
+
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
|
1574 |
+
);
|
1575 |
+
|
1576 |
+
static $pc1map = array(
|
1577 |
+
0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
|
1578 |
+
0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
|
1579 |
+
0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
|
1580 |
+
0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
|
1581 |
+
0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
|
1582 |
+
0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
|
1583 |
+
0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
|
1584 |
+
0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
|
1585 |
+
0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
|
1586 |
+
0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
|
1587 |
+
0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
|
1588 |
+
0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
|
1589 |
+
0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
|
1590 |
+
0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
|
1591 |
+
0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
|
1592 |
+
0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
|
1593 |
+
0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
|
1594 |
+
0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
|
1595 |
+
0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
|
1596 |
+
0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
|
1597 |
+
0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
|
1598 |
+
0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
|
1599 |
+
0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
|
1600 |
+
0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
|
1601 |
+
0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
|
1602 |
+
0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
|
1603 |
+
0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
|
1604 |
+
0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
|
1605 |
+
0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
|
1606 |
+
0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
|
1607 |
+
0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
|
1608 |
+
0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
|
1609 |
+
);
|
1610 |
+
|
1611 |
+
// Mapping tables for the PC-2 transformation.
|
1612 |
+
static $pc2mapc1 = array(
|
1613 |
+
0x00000000, 0x00000400, 0x00200000, 0x00200400,
|
1614 |
+
0x00000001, 0x00000401, 0x00200001, 0x00200401,
|
1615 |
+
0x02000000, 0x02000400, 0x02200000, 0x02200400,
|
1616 |
+
0x02000001, 0x02000401, 0x02200001, 0x02200401
|
1617 |
+
);
|
1618 |
+
static $pc2mapc2 = array(
|
1619 |
+
0x00000000, 0x00000800, 0x08000000, 0x08000800,
|
1620 |
+
0x00010000, 0x00010800, 0x08010000, 0x08010800,
|
1621 |
+
0x00000000, 0x00000800, 0x08000000, 0x08000800,
|
1622 |
+
0x00010000, 0x00010800, 0x08010000, 0x08010800,
|
1623 |
+
0x00000100, 0x00000900, 0x08000100, 0x08000900,
|
1624 |
+
0x00010100, 0x00010900, 0x08010100, 0x08010900,
|
1625 |
+
0x00000100, 0x00000900, 0x08000100, 0x08000900,
|
1626 |
+
0x00010100, 0x00010900, 0x08010100, 0x08010900,
|
1627 |
+
0x00000010, 0x00000810, 0x08000010, 0x08000810,
|
1628 |
+
0x00010010, 0x00010810, 0x08010010, 0x08010810,
|
1629 |
+
0x00000010, 0x00000810, 0x08000010, 0x08000810,
|
1630 |
+
0x00010010, 0x00010810, 0x08010010, 0x08010810,
|
1631 |
+
0x00000110, 0x00000910, 0x08000110, 0x08000910,
|
1632 |
+
0x00010110, 0x00010910, 0x08010110, 0x08010910,
|
1633 |
+
0x00000110, 0x00000910, 0x08000110, 0x08000910,
|
1634 |
+
0x00010110, 0x00010910, 0x08010110, 0x08010910,
|
1635 |
+
0x00040000, 0x00040800, 0x08040000, 0x08040800,
|
1636 |
+
0x00050000, 0x00050800, 0x08050000, 0x08050800,
|
1637 |
+
0x00040000, 0x00040800, 0x08040000, 0x08040800,
|
1638 |
+
0x00050000, 0x00050800, 0x08050000, 0x08050800,
|
1639 |
+
0x00040100, 0x00040900, 0x08040100, 0x08040900,
|
1640 |
+
0x00050100, 0x00050900, 0x08050100, 0x08050900,
|
1641 |
+
0x00040100, 0x00040900, 0x08040100, 0x08040900,
|
1642 |
+
0x00050100, 0x00050900, 0x08050100, 0x08050900,
|
1643 |
+
0x00040010, 0x00040810, 0x08040010, 0x08040810,
|
1644 |
+
0x00050010, 0x00050810, 0x08050010, 0x08050810,
|
1645 |
+
0x00040010, 0x00040810, 0x08040010, 0x08040810,
|
1646 |
+
0x00050010, 0x00050810, 0x08050010, 0x08050810,
|
1647 |
+
0x00040110, 0x00040910, 0x08040110, 0x08040910,
|
1648 |
+
0x00050110, 0x00050910, 0x08050110, 0x08050910,
|
1649 |
+
0x00040110, 0x00040910, 0x08040110, 0x08040910,
|
1650 |
+
0x00050110, 0x00050910, 0x08050110, 0x08050910,
|
1651 |
+
0x01000000, 0x01000800, 0x09000000, 0x09000800,
|
1652 |
+
0x01010000, 0x01010800, 0x09010000, 0x09010800,
|
1653 |
+
0x01000000, 0x01000800, 0x09000000, 0x09000800,
|
1654 |
+
0x01010000, 0x01010800, 0x09010000, 0x09010800,
|
1655 |
+
0x01000100, 0x01000900, 0x09000100, 0x09000900,
|
1656 |
+
0x01010100, 0x01010900, 0x09010100, 0x09010900,
|
1657 |
+
0x01000100, 0x01000900, 0x09000100, 0x09000900,
|
1658 |
+
0x01010100, 0x01010900, 0x09010100, 0x09010900,
|
1659 |
+
0x01000010, 0x01000810, 0x09000010, 0x09000810,
|
1660 |
+
0x01010010, 0x01010810, 0x09010010, 0x09010810,
|
1661 |
+
0x01000010, 0x01000810, 0x09000010, 0x09000810,
|
1662 |
+
0x01010010, 0x01010810, 0x09010010, 0x09010810,
|
1663 |
+
0x01000110, 0x01000910, 0x09000110, 0x09000910,
|
1664 |
+
0x01010110, 0x01010910, 0x09010110, 0x09010910,
|
1665 |
+
0x01000110, 0x01000910, 0x09000110, 0x09000910,
|
1666 |
+
0x01010110, 0x01010910, 0x09010110, 0x09010910,
|
1667 |
+
0x01040000, 0x01040800, 0x09040000, 0x09040800,
|
1668 |
+
0x01050000, 0x01050800, 0x09050000, 0x09050800,
|
1669 |
+
0x01040000, 0x01040800, 0x09040000, 0x09040800,
|
1670 |
+
0x01050000, 0x01050800, 0x09050000, 0x09050800,
|
1671 |
+
0x01040100, 0x01040900, 0x09040100, 0x09040900,
|
1672 |
+
0x01050100, 0x01050900, 0x09050100, 0x09050900,
|
1673 |
+
0x01040100, 0x01040900, 0x09040100, 0x09040900,
|
1674 |
+
0x01050100, 0x01050900, 0x09050100, 0x09050900,
|
1675 |
+
0x01040010, 0x01040810, 0x09040010, 0x09040810,
|
1676 |
+
0x01050010, 0x01050810, 0x09050010, 0x09050810,
|
1677 |
+
0x01040010, 0x01040810, 0x09040010, 0x09040810,
|
1678 |
+
0x01050010, 0x01050810, 0x09050010, 0x09050810,
|
1679 |
+
0x01040110, 0x01040910, 0x09040110, 0x09040910,
|
1680 |
+
0x01050110, 0x01050910, 0x09050110, 0x09050910,
|
1681 |
+
0x01040110, 0x01040910, 0x09040110, 0x09040910,
|
1682 |
+
0x01050110, 0x01050910, 0x09050110, 0x09050910
|
1683 |
+
);
|
1684 |
+
static $pc2mapc3 = array(
|
1685 |
+
0x00000000, 0x00000004, 0x00001000, 0x00001004,
|
1686 |
+
0x00000000, 0x00000004, 0x00001000, 0x00001004,
|
1687 |
+
0x10000000, 0x10000004, 0x10001000, 0x10001004,
|
1688 |
+
0x10000000, 0x10000004, 0x10001000, 0x10001004,
|
1689 |
+
0x00000020, 0x00000024, 0x00001020, 0x00001024,
|
1690 |
+
0x00000020, 0x00000024, 0x00001020, 0x00001024,
|
1691 |
+
0x10000020, 0x10000024, 0x10001020, 0x10001024,
|
1692 |
+
0x10000020, 0x10000024, 0x10001020, 0x10001024,
|
1693 |
+
0x00080000, 0x00080004, 0x00081000, 0x00081004,
|
1694 |
+
0x00080000, 0x00080004, 0x00081000, 0x00081004,
|
1695 |
+
0x10080000, 0x10080004, 0x10081000, 0x10081004,
|
1696 |
+
0x10080000, 0x10080004, 0x10081000, 0x10081004,
|
1697 |
+
0x00080020, 0x00080024, 0x00081020, 0x00081024,
|
1698 |
+
0x00080020, 0x00080024, 0x00081020, 0x00081024,
|
1699 |
+
0x10080020, 0x10080024, 0x10081020, 0x10081024,
|
1700 |
+
0x10080020, 0x10080024, 0x10081020, 0x10081024,
|
1701 |
+
0x20000000, 0x20000004, 0x20001000, 0x20001004,
|
1702 |
+
0x20000000, 0x20000004, 0x20001000, 0x20001004,
|
1703 |
+
0x30000000, 0x30000004, 0x30001000, 0x30001004,
|
1704 |
+
0x30000000, 0x30000004, 0x30001000, 0x30001004,
|
1705 |
+
0x20000020, 0x20000024, 0x20001020, 0x20001024,
|
1706 |
+
0x20000020, 0x20000024, 0x20001020, 0x20001024,
|
1707 |
+
0x30000020, 0x30000024, 0x30001020, 0x30001024,
|
1708 |
+
0x30000020, 0x30000024, 0x30001020, 0x30001024,
|
1709 |
+
0x20080000, 0x20080004, 0x20081000, 0x20081004,
|
1710 |
+
0x20080000, 0x20080004, 0x20081000, 0x20081004,
|
1711 |
+
0x30080000, 0x30080004, 0x30081000, 0x30081004,
|
1712 |
+
0x30080000, 0x30080004, 0x30081000, 0x30081004,
|
1713 |
+
0x20080020, 0x20080024, 0x20081020, 0x20081024,
|
1714 |
+
0x20080020, 0x20080024, 0x20081020, 0x20081024,
|
1715 |
+
0x30080020, 0x30080024, 0x30081020, 0x30081024,
|
1716 |
+
0x30080020, 0x30080024, 0x30081020, 0x30081024,
|
1717 |
+
0x00000002, 0x00000006, 0x00001002, 0x00001006,
|
1718 |
+
0x00000002, 0x00000006, 0x00001002, 0x00001006,
|
1719 |
+
0x10000002, 0x10000006, 0x10001002, 0x10001006,
|
1720 |
+
0x10000002, 0x10000006, 0x10001002, 0x10001006,
|
1721 |
+
0x00000022, 0x00000026, 0x00001022, 0x00001026,
|
1722 |
+
0x00000022, 0x00000026, 0x00001022, 0x00001026,
|
1723 |
+
0x10000022, 0x10000026, 0x10001022, 0x10001026,
|
1724 |
+
0x10000022, 0x10000026, 0x10001022, 0x10001026,
|
1725 |
+
0x00080002, 0x00080006, 0x00081002, 0x00081006,
|
1726 |
+
0x00080002, 0x00080006, 0x00081002, 0x00081006,
|
1727 |
+
0x10080002, 0x10080006, 0x10081002, 0x10081006,
|
1728 |
+
0x10080002, 0x10080006, 0x10081002, 0x10081006,
|
1729 |
+
0x00080022, 0x00080026, 0x00081022, 0x00081026,
|
1730 |
+
0x00080022, 0x00080026, 0x00081022, 0x00081026,
|
1731 |
+
0x10080022, 0x10080026, 0x10081022, 0x10081026,
|
1732 |
+
0x10080022, 0x10080026, 0x10081022, 0x10081026,
|
1733 |
+
0x20000002, 0x20000006, 0x20001002, 0x20001006,
|
1734 |
+
0x20000002, 0x20000006, 0x20001002, 0x20001006,
|
1735 |
+
0x30000002, 0x30000006, 0x30001002, 0x30001006,
|
1736 |
+
0x30000002, 0x30000006, 0x30001002, 0x30001006,
|
1737 |
+
0x20000022, 0x20000026, 0x20001022, 0x20001026,
|
1738 |
+
0x20000022, 0x20000026, 0x20001022, 0x20001026,
|
1739 |
+
0x30000022, 0x30000026, 0x30001022, 0x30001026,
|
1740 |
+
0x30000022, 0x30000026, 0x30001022, 0x30001026,
|
1741 |
+
0x20080002, 0x20080006, 0x20081002, 0x20081006,
|
1742 |
+
0x20080002, 0x20080006, 0x20081002, 0x20081006,
|
1743 |
+
0x30080002, 0x30080006, 0x30081002, 0x30081006,
|
1744 |
+
0x30080002, 0x30080006, 0x30081002, 0x30081006,
|
1745 |
+
0x20080022, 0x20080026, 0x20081022, 0x20081026,
|
1746 |
+
0x20080022, 0x20080026, 0x20081022, 0x20081026,
|
1747 |
+
0x30080022, 0x30080026, 0x30081022, 0x30081026,
|
1748 |
+
0x30080022, 0x30080026, 0x30081022, 0x30081026
|
1749 |
+
);
|
1750 |
+
static $pc2mapc4 = array(
|
1751 |
+
0x00000000, 0x00100000, 0x00000008, 0x00100008,
|
1752 |
+
0x00000200, 0x00100200, 0x00000208, 0x00100208,
|
1753 |
+
0x00000000, 0x00100000, 0x00000008, 0x00100008,
|
1754 |
+
0x00000200, 0x00100200, 0x00000208, 0x00100208,
|
1755 |
+
0x04000000, 0x04100000, 0x04000008, 0x04100008,
|
1756 |
+
0x04000200, 0x04100200, 0x04000208, 0x04100208,
|
1757 |
+
0x04000000, 0x04100000, 0x04000008, 0x04100008,
|
1758 |
+
0x04000200, 0x04100200, 0x04000208, 0x04100208,
|
1759 |
+
0x00002000, 0x00102000, 0x00002008, 0x00102008,
|
1760 |
+
0x00002200, 0x00102200, 0x00002208, 0x00102208,
|
1761 |
+
0x00002000, 0x00102000, 0x00002008, 0x00102008,
|
1762 |
+
0x00002200, 0x00102200, 0x00002208, 0x00102208,
|
1763 |
+
0x04002000, 0x04102000, 0x04002008, 0x04102008,
|
1764 |
+
0x04002200, 0x04102200, 0x04002208, 0x04102208,
|
1765 |
+
0x04002000, 0x04102000, 0x04002008, 0x04102008,
|
1766 |
+
0x04002200, 0x04102200, 0x04002208, 0x04102208,
|
1767 |
+
0x00000000, 0x00100000, 0x00000008, 0x00100008,
|
1768 |
+
0x00000200, 0x00100200, 0x00000208, 0x00100208,
|
1769 |
+
0x00000000, 0x00100000, 0x00000008, 0x00100008,
|
1770 |
+
0x00000200, 0x00100200, 0x00000208, 0x00100208,
|
1771 |
+
0x04000000, 0x04100000, 0x04000008, 0x04100008,
|
1772 |
+
0x04000200, 0x04100200, 0x04000208, 0x04100208,
|
1773 |
+
0x04000000, 0x04100000, 0x04000008, 0x04100008,
|
1774 |
+
0x04000200, 0x04100200, 0x04000208, 0x04100208,
|
1775 |
+
0x00002000, 0x00102000, 0x00002008, 0x00102008,
|
1776 |
+
0x00002200, 0x00102200, 0x00002208, 0x00102208,
|
1777 |
+
0x00002000, 0x00102000, 0x00002008, 0x00102008,
|
1778 |
+
0x00002200, 0x00102200, 0x00002208, 0x00102208,
|
1779 |
+
0x04002000, 0x04102000, 0x04002008, 0x04102008,
|
1780 |
+
0x04002200, 0x04102200, 0x04002208, 0x04102208,
|
1781 |
+
0x04002000, 0x04102000, 0x04002008, 0x04102008,
|
1782 |
+
0x04002200, 0x04102200, 0x04002208, 0x04102208,
|
1783 |
+
0x00020000, 0x00120000, 0x00020008, 0x00120008,
|
1784 |
+
0x00020200, 0x00120200, 0x00020208, 0x00120208,
|
1785 |
+
0x00020000, 0x00120000, 0x00020008, 0x00120008,
|
1786 |
+
0x00020200, 0x00120200, 0x00020208, 0x00120208,
|
1787 |
+
0x04020000, 0x04120000, 0x04020008, 0x04120008,
|
1788 |
+
0x04020200, 0x04120200, 0x04020208, 0x04120208,
|
1789 |
+
0x04020000, 0x04120000, 0x04020008, 0x04120008,
|
1790 |
+
0x04020200, 0x04120200, 0x04020208, 0x04120208,
|
1791 |
+
0x00022000, 0x00122000, 0x00022008, 0x00122008,
|
1792 |
+
0x00022200, 0x00122200, 0x00022208, 0x00122208,
|
1793 |
+
0x00022000, 0x00122000, 0x00022008, 0x00122008,
|
1794 |
+
0x00022200, 0x00122200, 0x00022208, 0x00122208,
|
1795 |
+
0x04022000, 0x04122000, 0x04022008, 0x04122008,
|
1796 |
+
0x04022200, 0x04122200, 0x04022208, 0x04122208,
|
1797 |
+
0x04022000, 0x04122000, 0x04022008, 0x04122008,
|
1798 |
+
0x04022200, 0x04122200, 0x04022208, 0x04122208,
|
1799 |
+
0x00020000, 0x00120000, 0x00020008, 0x00120008,
|
1800 |
+
0x00020200, 0x00120200, 0x00020208, 0x00120208,
|
1801 |
+
0x00020000, 0x00120000, 0x00020008, 0x00120008,
|
1802 |
+
0x00020200, 0x00120200, 0x00020208, 0x00120208,
|
1803 |
+
0x04020000, 0x04120000, 0x04020008, 0x04120008,
|
1804 |
+
0x04020200, 0x04120200, 0x04020208, 0x04120208,
|
1805 |
+
0x04020000, 0x04120000, 0x04020008, 0x04120008,
|
1806 |
+
0x04020200, 0x04120200, 0x04020208, 0x04120208,
|
1807 |
+
0x00022000, 0x00122000, 0x00022008, 0x00122008,
|
1808 |
+
0x00022200, 0x00122200, 0x00022208, 0x00122208,
|
1809 |
+
0x00022000, 0x00122000, 0x00022008, 0x00122008,
|
1810 |
+
0x00022200, 0x00122200, 0x00022208, 0x00122208,
|
1811 |
+
0x04022000, 0x04122000, 0x04022008, 0x04122008,
|
1812 |
+
0x04022200, 0x04122200, 0x04022208, 0x04122208,
|
1813 |
+
0x04022000, 0x04122000, 0x04022008, 0x04122008,
|
1814 |
+
0x04022200, 0x04122200, 0x04022208, 0x04122208
|
1815 |
+
);
|
1816 |
+
static $pc2mapd1 = array(
|
1817 |
+
0x00000000, 0x00000001, 0x08000000, 0x08000001,
|
1818 |
+
0x00200000, 0x00200001, 0x08200000, 0x08200001,
|
1819 |
+
0x00000002, 0x00000003, 0x08000002, 0x08000003,
|
1820 |
+
0x00200002, 0x00200003, 0x08200002, 0x08200003
|
1821 |
+
);
|
1822 |
+
static $pc2mapd2 = array(
|
1823 |
+
0x00000000, 0x00100000, 0x00000800, 0x00100800,
|
1824 |
+
0x00000000, 0x00100000, 0x00000800, 0x00100800,
|
1825 |
+
0x04000000, 0x04100000, 0x04000800, 0x04100800,
|
1826 |
+
0x04000000, 0x04100000, 0x04000800, 0x04100800,
|
1827 |
+
0x00000004, 0x00100004, 0x00000804, 0x00100804,
|
1828 |
+
0x00000004, 0x00100004, 0x00000804, 0x00100804,
|
1829 |
+
0x04000004, 0x04100004, 0x04000804, 0x04100804,
|
1830 |
+
0x04000004, 0x04100004, 0x04000804, 0x04100804,
|
1831 |
+
0x00000000, 0x00100000, 0x00000800, 0x00100800,
|
1832 |
+
0x00000000, 0x00100000, 0x00000800, 0x00100800,
|
1833 |
+
0x04000000, 0x04100000, 0x04000800, 0x04100800,
|
1834 |
+
0x04000000, 0x04100000, 0x04000800, 0x04100800,
|
1835 |
+
0x00000004, 0x00100004, 0x00000804, 0x00100804,
|
1836 |
+
0x00000004, 0x00100004, 0x00000804, 0x00100804,
|
1837 |
+
0x04000004, 0x04100004, 0x04000804, 0x04100804,
|
1838 |
+
0x04000004, 0x04100004, 0x04000804, 0x04100804,
|
1839 |
+
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
|
1840 |
+
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
|
1841 |
+
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
|
1842 |
+
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
|
1843 |
+
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
|
1844 |
+
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
|
1845 |
+
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
|
1846 |
+
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
|
1847 |
+
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
|
1848 |
+
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
|
1849 |
+
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
|
1850 |
+
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
|
1851 |
+
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
|
1852 |
+
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
|
1853 |
+
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
|
1854 |
+
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
|
1855 |
+
0x00020000, 0x00120000, 0x00020800, 0x00120800,
|
1856 |
+
0x00020000, 0x00120000, 0x00020800, 0x00120800,
|
1857 |
+
0x04020000, 0x04120000, 0x04020800, 0x04120800,
|
1858 |
+
0x04020000, 0x04120000, 0x04020800, 0x04120800,
|
1859 |
+
0x00020004, 0x00120004, 0x00020804, 0x00120804,
|
1860 |
+
0x00020004, 0x00120004, 0x00020804, 0x00120804,
|
1861 |
+
0x04020004, 0x04120004, 0x04020804, 0x04120804,
|
1862 |
+
0x04020004, 0x04120004, 0x04020804, 0x04120804,
|
1863 |
+
0x00020000, 0x00120000, 0x00020800, 0x00120800,
|
1864 |
+
0x00020000, 0x00120000, 0x00020800, 0x00120800,
|
1865 |
+
0x04020000, 0x04120000, 0x04020800, 0x04120800,
|
1866 |
+
0x04020000, 0x04120000, 0x04020800, 0x04120800,
|
1867 |
+
0x00020004, 0x00120004, 0x00020804, 0x00120804,
|
1868 |
+
0x00020004, 0x00120004, 0x00020804, 0x00120804,
|
1869 |
+
0x04020004, 0x04120004, 0x04020804, 0x04120804,
|
1870 |
+
0x04020004, 0x04120004, 0x04020804, 0x04120804,
|
1871 |
+
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
|
1872 |
+
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
|
1873 |
+
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
|
1874 |
+
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
|
1875 |
+
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
|
1876 |
+
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
|
1877 |
+
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
|
1878 |
+
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
|
1879 |
+
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
|
1880 |
+
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
|
1881 |
+
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
|
1882 |
+
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
|
1883 |
+
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
|
1884 |
+
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
|
1885 |
+
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
|
1886 |
+
0x04020204, 0x04120204, 0x04020A04, 0x04120A04
|
1887 |
+
);
|
1888 |
+
static $pc2mapd3 = array(
|
1889 |
+
0x00000000, 0x00010000, 0x02000000, 0x02010000,
|
1890 |
+
0x00000020, 0x00010020, 0x02000020, 0x02010020,
|
1891 |
+
0x00040000, 0x00050000, 0x02040000, 0x02050000,
|
1892 |
+
0x00040020, 0x00050020, 0x02040020, 0x02050020,
|
1893 |
+
0x00002000, 0x00012000, 0x02002000, 0x02012000,
|
1894 |
+
0x00002020, 0x00012020, 0x02002020, 0x02012020,
|
1895 |
+
0x00042000, 0x00052000, 0x02042000, 0x02052000,
|
1896 |
+
0x00042020, 0x00052020, 0x02042020, 0x02052020,
|
1897 |
+
0x00000000, 0x00010000, 0x02000000, 0x02010000,
|
1898 |
+
0x00000020, 0x00010020, 0x02000020, 0x02010020,
|
1899 |
+
0x00040000, 0x00050000, 0x02040000, 0x02050000,
|
1900 |
+
0x00040020, 0x00050020, 0x02040020, 0x02050020,
|
1901 |
+
0x00002000, 0x00012000, 0x02002000, 0x02012000,
|
1902 |
+
0x00002020, 0x00012020, 0x02002020, 0x02012020,
|
1903 |
+
0x00042000, 0x00052000, 0x02042000, 0x02052000,
|
1904 |
+
0x00042020, 0x00052020, 0x02042020, 0x02052020,
|
1905 |
+
0x00000010, 0x00010010, 0x02000010, 0x02010010,
|
1906 |
+
0x00000030, 0x00010030, 0x02000030, 0x02010030,
|
1907 |
+
0x00040010, 0x00050010, 0x02040010, 0x02050010,
|
1908 |
+
0x00040030, 0x00050030, 0x02040030, 0x02050030,
|
1909 |
+
0x00002010, 0x00012010, 0x02002010, 0x02012010,
|
1910 |
+
0x00002030, 0x00012030, 0x02002030, 0x02012030,
|
1911 |
+
0x00042010, 0x00052010, 0x02042010, 0x02052010,
|
1912 |
+
0x00042030, 0x00052030, 0x02042030, 0x02052030,
|
1913 |
+
0x00000010, 0x00010010, 0x02000010, 0x02010010,
|
1914 |
+
0x00000030, 0x00010030, 0x02000030, 0x02010030,
|
1915 |
+
0x00040010, 0x00050010, 0x02040010, 0x02050010,
|
1916 |
+
0x00040030, 0x00050030, 0x02040030, 0x02050030,
|
1917 |
+
0x00002010, 0x00012010, 0x02002010, 0x02012010,
|
1918 |
+
0x00002030, 0x00012030, 0x02002030, 0x02012030,
|
1919 |
+
0x00042010, 0x00052010, 0x02042010, 0x02052010,
|
1920 |
+
0x00042030, 0x00052030, 0x02042030, 0x02052030,
|
1921 |
+
0x20000000, 0x20010000, 0x22000000, 0x22010000,
|
1922 |
+
0x20000020, 0x20010020, 0x22000020, 0x22010020,
|
1923 |
+
0x20040000, 0x20050000, 0x22040000, 0x22050000,
|
1924 |
+
0x20040020, 0x20050020, 0x22040020, 0x22050020,
|
1925 |
+
0x20002000, 0x20012000, 0x22002000, 0x22012000,
|
1926 |
+
0x20002020, 0x20012020, 0x22002020, 0x22012020,
|
1927 |
+
0x20042000, 0x20052000, 0x22042000, 0x22052000,
|
1928 |
+
0x20042020, 0x20052020, 0x22042020, 0x22052020,
|
1929 |
+
0x20000000, 0x20010000, 0x22000000, 0x22010000,
|
1930 |
+
0x20000020, 0x20010020, 0x22000020, 0x22010020,
|
1931 |
+
0x20040000, 0x20050000, 0x22040000, 0x22050000,
|
1932 |
+
0x20040020, 0x20050020, 0x22040020, 0x22050020,
|
1933 |
+
0x20002000, 0x20012000, 0x22002000, 0x22012000,
|
1934 |
+
0x20002020, 0x20012020, 0x22002020, 0x22012020,
|
1935 |
+
0x20042000, 0x20052000, 0x22042000, 0x22052000,
|
1936 |
+
0x20042020, 0x20052020, 0x22042020, 0x22052020,
|
1937 |
+
0x20000010, 0x20010010, 0x22000010, 0x22010010,
|
1938 |
+
0x20000030, 0x20010030, 0x22000030, 0x22010030,
|
1939 |
+
0x20040010, 0x20050010, 0x22040010, 0x22050010,
|
1940 |
+
0x20040030, 0x20050030, 0x22040030, 0x22050030,
|
1941 |
+
0x20002010, 0x20012010, 0x22002010, 0x22012010,
|
1942 |
+
0x20002030, 0x20012030, 0x22002030, 0x22012030,
|
1943 |
+
0x20042010, 0x20052010, 0x22042010, 0x22052010,
|
1944 |
+
0x20042030, 0x20052030, 0x22042030, 0x22052030,
|
1945 |
+
0x20000010, 0x20010010, 0x22000010, 0x22010010,
|
1946 |
+
0x20000030, 0x20010030, 0x22000030, 0x22010030,
|
1947 |
+
0x20040010, 0x20050010, 0x22040010, 0x22050010,
|
1948 |
+
0x20040030, 0x20050030, 0x22040030, 0x22050030,
|
1949 |
+
0x20002010, 0x20012010, 0x22002010, 0x22012010,
|
1950 |
+
0x20002030, 0x20012030, 0x22002030, 0x22012030,
|
1951 |
+
0x20042010, 0x20052010, 0x22042010, 0x22052010,
|
1952 |
+
0x20042030, 0x20052030, 0x22042030, 0x22052030
|
1953 |
+
);
|
1954 |
+
static $pc2mapd4 = array(
|
1955 |
+
0x00000000, 0x00000400, 0x01000000, 0x01000400,
|
1956 |
+
0x00000000, 0x00000400, 0x01000000, 0x01000400,
|
1957 |
+
0x00000100, 0x00000500, 0x01000100, 0x01000500,
|
1958 |
+
0x00000100, 0x00000500, 0x01000100, 0x01000500,
|
1959 |
+
0x10000000, 0x10000400, 0x11000000, 0x11000400,
|
1960 |
+
0x10000000, 0x10000400, 0x11000000, 0x11000400,
|
1961 |
+
0x10000100, 0x10000500, 0x11000100, 0x11000500,
|
1962 |
+
0x10000100, 0x10000500, 0x11000100, 0x11000500,
|
1963 |
+
0x00080000, 0x00080400, 0x01080000, 0x01080400,
|
1964 |
+
0x00080000, 0x00080400, 0x01080000, 0x01080400,
|
1965 |
+
0x00080100, 0x00080500, 0x01080100, 0x01080500,
|
1966 |
+
0x00080100, 0x00080500, 0x01080100, 0x01080500,
|
1967 |
+
0x10080000, 0x10080400, 0x11080000, 0x11080400,
|
1968 |
+
0x10080000, 0x10080400, 0x11080000, 0x11080400,
|
1969 |
+
0x10080100, 0x10080500, 0x11080100, 0x11080500,
|
1970 |
+
0x10080100, 0x10080500, 0x11080100, 0x11080500,
|
1971 |
+
0x00000008, 0x00000408, 0x01000008, 0x01000408,
|
1972 |
+
0x00000008, 0x00000408, 0x01000008, 0x01000408,
|
1973 |
+
0x00000108, 0x00000508, 0x01000108, 0x01000508,
|
1974 |
+
0x00000108, 0x00000508, 0x01000108, 0x01000508,
|
1975 |
+
0x10000008, 0x10000408, 0x11000008, 0x11000408,
|
1976 |
+
0x10000008, 0x10000408, 0x11000008, 0x11000408,
|
1977 |
+
0x10000108, 0x10000508, 0x11000108, 0x11000508,
|
1978 |
+
0x10000108, 0x10000508, 0x11000108, 0x11000508,
|
1979 |
+
0x00080008, 0x00080408, 0x01080008, 0x01080408,
|
1980 |
+
0x00080008, 0x00080408, 0x01080008, 0x01080408,
|
1981 |
+
0x00080108, 0x00080508, 0x01080108, 0x01080508,
|
1982 |
+
0x00080108, 0x00080508, 0x01080108, 0x01080508,
|
1983 |
+
0x10080008, 0x10080408, 0x11080008, 0x11080408,
|
1984 |
+
0x10080008, 0x10080408, 0x11080008, 0x11080408,
|
1985 |
+
0x10080108, 0x10080508, 0x11080108, 0x11080508,
|
1986 |
+
0x10080108, 0x10080508, 0x11080108, 0x11080508,
|
1987 |
+
0x00001000, 0x00001400, 0x01001000, 0x01001400,
|
1988 |
+
0x00001000, 0x00001400, 0x01001000, 0x01001400,
|
1989 |
+
0x00001100, 0x00001500, 0x01001100, 0x01001500,
|
1990 |
+
0x00001100, 0x00001500, 0x01001100, 0x01001500,
|
1991 |
+
0x10001000, 0x10001400, 0x11001000, 0x11001400,
|
1992 |
+
0x10001000, 0x10001400, 0x11001000, 0x11001400,
|
1993 |
+
0x10001100, 0x10001500, 0x11001100, 0x11001500,
|
1994 |
+
0x10001100, 0x10001500, 0x11001100, 0x11001500,
|
1995 |
+
0x00081000, 0x00081400, 0x01081000, 0x01081400,
|
1996 |
+
0x00081000, 0x00081400, 0x01081000, 0x01081400,
|
1997 |
+
0x00081100, 0x00081500, 0x01081100, 0x01081500,
|
1998 |
+
0x00081100, 0x00081500, 0x01081100, 0x01081500,
|
1999 |
+
0x10081000, 0x10081400, 0x11081000, 0x11081400,
|
2000 |
+
0x10081000, 0x10081400, 0x11081000, 0x11081400,
|
2001 |
+
0x10081100, 0x10081500, 0x11081100, 0x11081500,
|
2002 |
+
0x10081100, 0x10081500, 0x11081100, 0x11081500,
|
2003 |
+
0x00001008, 0x00001408, 0x01001008, 0x01001408,
|
2004 |
+
0x00001008, 0x00001408, 0x01001008, 0x01001408,
|
2005 |
+
0x00001108, 0x00001508, 0x01001108, 0x01001508,
|
2006 |
+
0x00001108, 0x00001508, 0x01001108, 0x01001508,
|
2007 |
+
0x10001008, 0x10001408, 0x11001008, 0x11001408,
|
2008 |
+
0x10001008, 0x10001408, 0x11001008, 0x11001408,
|
2009 |
+
0x10001108, 0x10001508, 0x11001108, 0x11001508,
|
2010 |
+
0x10001108, 0x10001508, 0x11001108, 0x11001508,
|
2011 |
+
0x00081008, 0x00081408, 0x01081008, 0x01081408,
|
2012 |
+
0x00081008, 0x00081408, 0x01081008, 0x01081408,
|
2013 |
+
0x00081108, 0x00081508, 0x01081108, 0x01081508,
|
2014 |
+
0x00081108, 0x00081508, 0x01081108, 0x01081508,
|
2015 |
+
0x10081008, 0x10081408, 0x11081008, 0x11081408,
|
2016 |
+
0x10081008, 0x10081408, 0x11081008, 0x11081408,
|
2017 |
+
0x10081108, 0x10081508, 0x11081108, 0x11081508,
|
2018 |
+
0x10081108, 0x10081508, 0x11081108, 0x11081508
|
2019 |
+
);
|
2020 |
+
|
2021 |
+
// pad the key and remove extra characters as appropriate.
|
2022 |
+
$key = str_pad(substr($key, 0, 8), 8, chr(0));
|
2023 |
+
|
2024 |
+
// Perform the PC/1 transformation and compute C and D.
|
2025 |
+
$t = unpack('Nl/Nr', $key);
|
2026 |
+
list($l, $r) = array($t['l'], $t['r']);
|
2027 |
+
$key = ($this->shuffle[$pc1map[$r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
|
2028 |
+
($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
|
2029 |
+
($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
|
2030 |
+
($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
|
2031 |
+
($this->shuffle[$pc1map[$l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
|
2032 |
+
($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
|
2033 |
+
($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
|
2034 |
+
($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
|
2035 |
+
$key = unpack('Nc/Nd', $key);
|
2036 |
+
$c = ($key['c'] >> 4) & 0x0FFFFFFF;
|
2037 |
+
$d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
|
2038 |
+
|
2039 |
+
$keys = array();
|
2040 |
+
for ($i = 0; $i < 16; $i++) {
|
2041 |
+
$c <<= $shifts[$i];
|
2042 |
+
$c = ($c | ($c >> 28)) & 0x0FFFFFFF;
|
2043 |
+
$d <<= $shifts[$i];
|
2044 |
+
$d = ($d | ($d >> 28)) & 0x0FFFFFFF;
|
2045 |
+
|
2046 |
+
// Perform the PC-2 transformation.
|
2047 |
+
$cp = $pc2mapc1[$c >> 24] | $pc2mapc2[($c >> 16) & 0xFF] |
|
2048 |
+
$pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[$c & 0xFF];
|
2049 |
+
$dp = $pc2mapd1[$d >> 24] | $pc2mapd2[($d >> 16) & 0xFF] |
|
2050 |
+
$pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[$d & 0xFF];
|
2051 |
+
|
2052 |
+
// Reorder: odd bytes/even bytes. Push the result in key schedule.
|
2053 |
+
$keys[] = array(
|
2054 |
+
($cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
|
2055 |
+
(($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF),
|
2056 |
+
(($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
|
2057 |
+
(($dp >> 8) & 0x0000FF00) | ($dp & 0x000000FF)
|
2058 |
+
);
|
2059 |
+
}
|
2060 |
+
|
2061 |
+
$keys = array(
|
2062 |
+
CRYPT_DES_ENCRYPT => $keys,
|
2063 |
+
CRYPT_DES_DECRYPT => array_reverse($keys),
|
2064 |
+
CRYPT_DES_ENCRYPT_1DIM => array(),
|
2065 |
+
CRYPT_DES_DECRYPT_1DIM => array()
|
2066 |
+
);
|
2067 |
+
|
2068 |
+
// Generate 1-dim arrays for inline en/decrypting
|
2069 |
+
for ($i = 0; $i < 16; ++$i) {
|
2070 |
+
$keys[CRYPT_DES_ENCRYPT_1DIM][] = $keys[CRYPT_DES_ENCRYPT][$i][0];
|
2071 |
+
$keys[CRYPT_DES_ENCRYPT_1DIM][] = $keys[CRYPT_DES_ENCRYPT][$i][1];
|
2072 |
+
$keys[CRYPT_DES_DECRYPT_1DIM][] = $keys[CRYPT_DES_DECRYPT][$i][0];
|
2073 |
+
$keys[CRYPT_DES_DECRYPT_1DIM][] = $keys[CRYPT_DES_DECRYPT][$i][1];
|
2074 |
+
}
|
2075 |
+
|
2076 |
+
return $keys;
|
2077 |
+
}
|
2078 |
+
|
2079 |
+
/**
|
2080 |
+
* String Shift
|
2081 |
+
*
|
2082 |
+
* Inspired by array_shift
|
2083 |
+
*
|
2084 |
+
* @param String $string
|
2085 |
+
* @return String
|
2086 |
+
* @access private
|
2087 |
+
*/
|
2088 |
+
function _string_shift(&$string)
|
2089 |
+
{
|
2090 |
+
$substr = substr($string, 0, 8);
|
2091 |
+
$string = substr($string, 8);
|
2092 |
+
return $substr;
|
2093 |
+
}
|
2094 |
+
|
2095 |
+
/**
|
2096 |
+
* Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
|
2097 |
+
*
|
2098 |
+
* @param optional Integer $des_rounds (1 = DES[default], 3 = TribleDES)
|
2099 |
+
* @access private
|
2100 |
+
*/
|
2101 |
+
function inline_crypt_setup($des_rounds = 1)
|
2102 |
+
{
|
2103 |
+
$lambda_functions =& Crypt_DES::get_lambda_functions();
|
2104 |
+
$block_size = 8;
|
2105 |
+
$mode = $this->mode;
|
2106 |
+
|
2107 |
+
$code_hash = "$mode,$des_rounds";
|
2108 |
+
|
2109 |
+
if (!isset($lambda_functions[$code_hash])) {
|
2110 |
+
// Generating encrypt code:
|
2111 |
+
$ki = -1;
|
2112 |
+
$init_cryptBlock = '
|
2113 |
+
$shuffle = $self->shuffle;
|
2114 |
+
$invipmap = $self->invipmap;
|
2115 |
+
$ipmap = $self->ipmap;
|
2116 |
+
$sbox1 = $self->sbox1;
|
2117 |
+
$sbox2 = $self->sbox2;
|
2118 |
+
$sbox3 = $self->sbox3;
|
2119 |
+
$sbox4 = $self->sbox4;
|
2120 |
+
$sbox5 = $self->sbox5;
|
2121 |
+
$sbox6 = $self->sbox6;
|
2122 |
+
$sbox7 = $self->sbox7;
|
2123 |
+
$sbox8 = $self->sbox8;
|
2124 |
+
';
|
2125 |
+
|
2126 |
+
$_cryptBlock = '$in = unpack("N*", $in);'."\n";
|
2127 |
+
// Do the initial IP permutation.
|
2128 |
+
$_cryptBlock .= '
|
2129 |
+
$l = $in[1];
|
2130 |
+
$r = $in[2];
|
2131 |
+
$in = unpack("N*",
|
2132 |
+
($shuffle[$ipmap[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
|
2133 |
+
($shuffle[$ipmap[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
|
2134 |
+
($shuffle[$ipmap[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
|
2135 |
+
($shuffle[$ipmap[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
|
2136 |
+
($shuffle[$ipmap[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
|
2137 |
+
($shuffle[$ipmap[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
|
2138 |
+
($shuffle[$ipmap[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
|
2139 |
+
($shuffle[$ipmap[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01")
|
2140 |
+
);
|
2141 |
+
|
2142 |
+
'.'' /* Extract L0 and R0 */ .'
|
2143 |
+
$l = $in[1];
|
2144 |
+
$r = $in[2];
|
2145 |
+
';
|
2146 |
+
|
2147 |
+
$l = 'l';
|
2148 |
+
$r = 'r';
|
2149 |
+
for ($des_round = 0; $des_round < $des_rounds; ++$des_round) {
|
2150 |
+
// Perform the 16 steps.
|
2151 |
+
// start of "the Feistel (F) function" - see the following URL:
|
2152 |
+
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
|
2153 |
+
// Merge key schedule.
|
2154 |
+
for ($i = 0; $i < 8; ++$i) {
|
2155 |
+
$_cryptBlock .= '
|
2156 |
+
$b1 = (($' . $r . ' >> 3) & 0x1FFFFFFF) ^ ($' . $r . ' << 29) ^ $k_'.(++$ki).';
|
2157 |
+
$b2 = (($' . $r . ' >> 31) & 0x00000001) ^ ($' . $r . ' << 1) ^ $k_'.(++$ki).';
|
2158 |
+
$' . $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
|
2159 |
+
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
|
2160 |
+
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
|
2161 |
+
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $' . $l . ';
|
2162 |
+
|
2163 |
+
$b1 = (($' . $l . ' >> 3) & 0x1FFFFFFF) ^ ($' . $l . ' << 29) ^ $k_'.(++$ki).';
|
2164 |
+
$b2 = (($' . $l . ' >> 31) & 0x00000001) ^ ($' . $l . ' << 1) ^ $k_'.(++$ki).';
|
2165 |
+
$' . $r . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
|
2166 |
+
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
|
2167 |
+
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
|
2168 |
+
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $' . $r . ';
|
2169 |
+
';
|
2170 |
+
}
|
2171 |
+
|
2172 |
+
// Last step should not permute L & R.
|
2173 |
+
$t = $l;
|
2174 |
+
$l = $r;
|
2175 |
+
$r = $t;
|
2176 |
+
}
|
2177 |
+
|
2178 |
+
// Perform the inverse IP permutation.
|
2179 |
+
$_cryptBlock .= '$in = (
|
2180 |
+
($shuffle[$invipmap[($' . $r . ' >> 24) & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
|
2181 |
+
($shuffle[$invipmap[($' . $l . ' >> 24) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
|
2182 |
+
($shuffle[$invipmap[($' . $r . ' >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
|
2183 |
+
($shuffle[$invipmap[($' . $l . ' >> 16) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
|
2184 |
+
($shuffle[$invipmap[($' . $r . ' >> 8) & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
|
2185 |
+
($shuffle[$invipmap[($' . $l . ' >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
|
2186 |
+
($shuffle[$invipmap[ $' . $r . ' & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
|
2187 |
+
($shuffle[$invipmap[ $' . $l . ' & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x01")
|
2188 |
+
);
|
2189 |
+
';
|
2190 |
+
|
2191 |
+
// Generating mode of operation code:
|
2192 |
+
switch ($mode) {
|
2193 |
+
case CRYPT_DES_MODE_ECB:
|
2194 |
+
$encrypt = $init_cryptBlock . '
|
2195 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2196 |
+
$ciphertext = "";
|
2197 |
+
$plaintext_len = strlen($text);
|
2198 |
+
|
2199 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
2200 |
+
$in = substr($text, $i, '.$block_size.');
|
2201 |
+
'.$_cryptBlock.'
|
2202 |
+
$ciphertext.= $in;
|
2203 |
+
}
|
2204 |
+
|
2205 |
+
return $ciphertext;
|
2206 |
+
';
|
2207 |
+
|
2208 |
+
$decrypt = $init_cryptBlock . '
|
2209 |
+
extract($self->keys[CRYPT_DES_DECRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2210 |
+
$plaintext = "";
|
2211 |
+
$ciphertext_len = strlen($text);
|
2212 |
+
|
2213 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2214 |
+
$in = substr($text, $i, '.$block_size.');
|
2215 |
+
'.$_cryptBlock.'
|
2216 |
+
$plaintext.= $in;
|
2217 |
+
}
|
2218 |
+
|
2219 |
+
return $self->_unpad($plaintext);
|
2220 |
+
';
|
2221 |
+
break;
|
2222 |
+
case CRYPT_DES_MODE_CBC:
|
2223 |
+
$encrypt = $init_cryptBlock . '
|
2224 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2225 |
+
$ciphertext = "";
|
2226 |
+
$plaintext_len = strlen($text);
|
2227 |
+
|
2228 |
+
$in = $self->encryptIV;
|
2229 |
+
|
2230 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
2231 |
+
$in = substr($text, $i, '.$block_size.') ^ $in;
|
2232 |
+
'.$_cryptBlock.'
|
2233 |
+
$ciphertext.= $in;
|
2234 |
+
}
|
2235 |
+
|
2236 |
+
if ($self->continuousBuffer) {
|
2237 |
+
$self->encryptIV = $in;
|
2238 |
+
}
|
2239 |
+
|
2240 |
+
return $ciphertext;
|
2241 |
+
';
|
2242 |
+
|
2243 |
+
$decrypt = $init_cryptBlock . '
|
2244 |
+
extract($self->keys[CRYPT_DES_DECRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2245 |
+
$plaintext = "";
|
2246 |
+
$ciphertext_len = strlen($text);
|
2247 |
+
|
2248 |
+
$iv = $self->decryptIV;
|
2249 |
+
|
2250 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2251 |
+
$in = $block = substr($text, $i, '.$block_size.');
|
2252 |
+
'.$_cryptBlock.'
|
2253 |
+
$plaintext.= $in ^ $iv;
|
2254 |
+
$iv = $block;
|
2255 |
+
}
|
2256 |
+
|
2257 |
+
if ($self->continuousBuffer) {
|
2258 |
+
$self->decryptIV = $iv;
|
2259 |
+
}
|
2260 |
+
|
2261 |
+
return $self->_unpad($plaintext);
|
2262 |
+
';
|
2263 |
+
break;
|
2264 |
+
case CRYPT_DES_MODE_CTR:
|
2265 |
+
$encrypt = $init_cryptBlock . '
|
2266 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2267 |
+
$ciphertext = "";
|
2268 |
+
$plaintext_len = strlen($text);
|
2269 |
+
$xor = $self->encryptIV;
|
2270 |
+
$buffer = &$self->enbuffer;
|
2271 |
+
|
2272 |
+
if (strlen($buffer["encrypted"])) {
|
2273 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
2274 |
+
$block = substr($text, $i, '.$block_size.');
|
2275 |
+
if (strlen($block) > strlen($buffer["encrypted"])) {
|
2276 |
+
$in = $self->_generate_xor($xor);
|
2277 |
+
'.$_cryptBlock.'
|
2278 |
+
$buffer["encrypted"].= $in;
|
2279 |
+
}
|
2280 |
+
$key = $self->_string_shift($buffer["encrypted"]);
|
2281 |
+
$ciphertext.= $block ^ $key;
|
2282 |
+
}
|
2283 |
+
} else {
|
2284 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
2285 |
+
$block = substr($text, $i, '.$block_size.');
|
2286 |
+
$in = $self->_generate_xor($xor);
|
2287 |
+
'.$_cryptBlock.'
|
2288 |
+
$key = $in;
|
2289 |
+
$ciphertext.= $block ^ $key;
|
2290 |
+
}
|
2291 |
+
}
|
2292 |
+
if ($self->continuousBuffer) {
|
2293 |
+
$self->encryptIV = $xor;
|
2294 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
2295 |
+
$buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
|
2296 |
+
}
|
2297 |
+
}
|
2298 |
+
|
2299 |
+
return $ciphertext;
|
2300 |
+
';
|
2301 |
+
|
2302 |
+
$decrypt = $init_cryptBlock . '
|
2303 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2304 |
+
$plaintext = "";
|
2305 |
+
$ciphertext_len = strlen($text);
|
2306 |
+
$xor = $self->decryptIV;
|
2307 |
+
$buffer = &$self->debuffer;
|
2308 |
+
|
2309 |
+
if (strlen($buffer["ciphertext"])) {
|
2310 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2311 |
+
$block = substr($text, $i, '.$block_size.');
|
2312 |
+
if (strlen($block) > strlen($buffer["ciphertext"])) {
|
2313 |
+
$in = $self->_generate_xor($xor);
|
2314 |
+
'.$_cryptBlock.'
|
2315 |
+
$buffer["ciphertext"].= $in;
|
2316 |
+
}
|
2317 |
+
$key = $self->_string_shift($buffer["ciphertext"]);
|
2318 |
+
$plaintext.= $block ^ $key;
|
2319 |
+
}
|
2320 |
+
} else {
|
2321 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2322 |
+
$block = substr($text, $i, '.$block_size.');
|
2323 |
+
$in = $self->_generate_xor($xor);
|
2324 |
+
'.$_cryptBlock.'
|
2325 |
+
$key = $in;
|
2326 |
+
$plaintext.= $block ^ $key;
|
2327 |
+
}
|
2328 |
+
}
|
2329 |
+
if ($self->continuousBuffer) {
|
2330 |
+
$self->decryptIV = $xor;
|
2331 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
2332 |
+
$buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
|
2333 |
+
}
|
2334 |
+
}
|
2335 |
+
|
2336 |
+
return $plaintext;
|
2337 |
+
';
|
2338 |
+
break;
|
2339 |
+
case CRYPT_DES_MODE_CFB:
|
2340 |
+
$encrypt = $init_cryptBlock . '
|
2341 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2342 |
+
$ciphertext = "";
|
2343 |
+
$buffer = &$self->enbuffer;
|
2344 |
+
|
2345 |
+
if ($self->continuousBuffer) {
|
2346 |
+
$iv = &$self->encryptIV;
|
2347 |
+
$pos = &$buffer["pos"];
|
2348 |
+
} else {
|
2349 |
+
$iv = $self->encryptIV;
|
2350 |
+
$pos = 0;
|
2351 |
+
}
|
2352 |
+
$len = strlen($text);
|
2353 |
+
$i = 0;
|
2354 |
+
if ($pos) {
|
2355 |
+
$orig_pos = $pos;
|
2356 |
+
$max = '.$block_size.' - $pos;
|
2357 |
+
if ($len >= $max) {
|
2358 |
+
$i = $max;
|
2359 |
+
$len-= $max;
|
2360 |
+
$pos = 0;
|
2361 |
+
} else {
|
2362 |
+
$i = $len;
|
2363 |
+
$pos+= $len;
|
2364 |
+
$len = 0;
|
2365 |
+
}
|
2366 |
+
$ciphertext = substr($iv, $orig_pos) ^ $text;
|
2367 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
2368 |
+
}
|
2369 |
+
while ($len >= '.$block_size.') {
|
2370 |
+
$in = $iv;
|
2371 |
+
'.$_cryptBlock.';
|
2372 |
+
$iv = $in ^ substr($text, $i, '.$block_size.');
|
2373 |
+
$ciphertext.= $iv;
|
2374 |
+
$len-= '.$block_size.';
|
2375 |
+
$i+= '.$block_size.';
|
2376 |
+
}
|
2377 |
+
if ($len) {
|
2378 |
+
$in = $iv;
|
2379 |
+
'.$_cryptBlock.'
|
2380 |
+
$iv = $in;
|
2381 |
+
$block = $iv ^ substr($text, $i);
|
2382 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
2383 |
+
$ciphertext.= $block;
|
2384 |
+
$pos = $len;
|
2385 |
+
}
|
2386 |
+
return $ciphertext;
|
2387 |
+
';
|
2388 |
+
|
2389 |
+
$decrypt = $init_cryptBlock . '
|
2390 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2391 |
+
$plaintext = "";
|
2392 |
+
$buffer = &$self->debuffer;
|
2393 |
+
|
2394 |
+
if ($self->continuousBuffer) {
|
2395 |
+
$iv = &$self->decryptIV;
|
2396 |
+
$pos = &$buffer["pos"];
|
2397 |
+
} else {
|
2398 |
+
$iv = $self->decryptIV;
|
2399 |
+
$pos = 0;
|
2400 |
+
}
|
2401 |
+
$len = strlen($text);
|
2402 |
+
$i = 0;
|
2403 |
+
if ($pos) {
|
2404 |
+
$orig_pos = $pos;
|
2405 |
+
$max = '.$block_size.' - $pos;
|
2406 |
+
if ($len >= $max) {
|
2407 |
+
$i = $max;
|
2408 |
+
$len-= $max;
|
2409 |
+
$pos = 0;
|
2410 |
+
} else {
|
2411 |
+
$i = $len;
|
2412 |
+
$pos+= $len;
|
2413 |
+
$len = 0;
|
2414 |
+
}
|
2415 |
+
$plaintext = substr($iv, $orig_pos) ^ $text;
|
2416 |
+
$iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
|
2417 |
+
}
|
2418 |
+
while ($len >= '.$block_size.') {
|
2419 |
+
$in = $iv;
|
2420 |
+
'.$_cryptBlock.'
|
2421 |
+
$iv = $in;
|
2422 |
+
$cb = substr($text, $i, '.$block_size.');
|
2423 |
+
$plaintext.= $iv ^ $cb;
|
2424 |
+
$iv = $cb;
|
2425 |
+
$len-= '.$block_size.';
|
2426 |
+
$i+= '.$block_size.';
|
2427 |
+
}
|
2428 |
+
if ($len) {
|
2429 |
+
$in = $iv;
|
2430 |
+
'.$_cryptBlock.'
|
2431 |
+
$iv = $in;
|
2432 |
+
$plaintext.= $iv ^ substr($text, $i);
|
2433 |
+
$iv = substr_replace($iv, substr($text, $i), 0, $len);
|
2434 |
+
$pos = $len;
|
2435 |
+
}
|
2436 |
+
|
2437 |
+
return $plaintext;
|
2438 |
+
';
|
2439 |
+
break;
|
2440 |
+
case CRYPT_DES_MODE_OFB:
|
2441 |
+
$encrypt = $init_cryptBlock . '
|
2442 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2443 |
+
$ciphertext = "";
|
2444 |
+
$plaintext_len = strlen($text);
|
2445 |
+
$xor = $self->encryptIV;
|
2446 |
+
$buffer = &$self->enbuffer;
|
2447 |
+
|
2448 |
+
if (strlen($buffer["xor"])) {
|
2449 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
2450 |
+
$block = substr($text, $i, '.$block_size.');
|
2451 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
2452 |
+
$in = $xor;
|
2453 |
+
'.$_cryptBlock.'
|
2454 |
+
$xor = $in;
|
2455 |
+
$buffer["xor"].= $xor;
|
2456 |
+
}
|
2457 |
+
$key = $self->_string_shift($buffer["xor"]);
|
2458 |
+
$ciphertext.= $block ^ $key;
|
2459 |
+
}
|
2460 |
+
} else {
|
2461 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
2462 |
+
$in = $xor;
|
2463 |
+
'.$_cryptBlock.'
|
2464 |
+
$xor = $in;
|
2465 |
+
$ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
|
2466 |
+
}
|
2467 |
+
$key = $xor;
|
2468 |
+
}
|
2469 |
+
if ($self->continuousBuffer) {
|
2470 |
+
$self->encryptIV = $xor;
|
2471 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
2472 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
2473 |
+
}
|
2474 |
+
}
|
2475 |
+
return $ciphertext;
|
2476 |
+
';
|
2477 |
+
|
2478 |
+
$decrypt = $init_cryptBlock . '
|
2479 |
+
extract($self->keys[CRYPT_DES_ENCRYPT_1DIM], EXTR_PREFIX_ALL, "k");
|
2480 |
+
$plaintext = "";
|
2481 |
+
$ciphertext_len = strlen($text);
|
2482 |
+
$xor = $self->decryptIV;
|
2483 |
+
$buffer = &$self->debuffer;
|
2484 |
+
|
2485 |
+
if (strlen($buffer["xor"])) {
|
2486 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2487 |
+
$block = substr($text, $i, '.$block_size.');
|
2488 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
2489 |
+
$in = $xor;
|
2490 |
+
'.$_cryptBlock.'
|
2491 |
+
$xor = $in;
|
2492 |
+
$buffer["xor"].= $xor;
|
2493 |
+
}
|
2494 |
+
$key = $self->_string_shift($buffer["xor"]);
|
2495 |
+
$plaintext.= $block ^ $key;
|
2496 |
+
}
|
2497 |
+
} else {
|
2498 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2499 |
+
$in = $xor;
|
2500 |
+
'.$_cryptBlock.'
|
2501 |
+
$xor = $in;
|
2502 |
+
$plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
|
2503 |
+
}
|
2504 |
+
$key = $xor;
|
2505 |
+
}
|
2506 |
+
if ($self->continuousBuffer) {
|
2507 |
+
$self->decryptIV = $xor;
|
2508 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
2509 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
2510 |
+
}
|
2511 |
+
}
|
2512 |
+
return $plaintext;
|
2513 |
+
';
|
2514 |
+
break;
|
2515 |
+
}
|
2516 |
+
$lambda_functions[$code_hash] = create_function('$action, &$self, $text', 'if ($action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }');
|
2517 |
+
}
|
2518 |
+
$this->inline_crypt = $lambda_functions[$code_hash];
|
2519 |
+
}
|
2520 |
+
|
2521 |
+
/**
|
2522 |
+
* Holds the lambda_functions table (classwide)
|
2523 |
+
*
|
2524 |
+
* @see inline_crypt_setup()
|
2525 |
+
* @return Array
|
2526 |
+
* @access private
|
2527 |
+
*/
|
2528 |
+
function &get_lambda_functions()
|
2529 |
+
{
|
2530 |
+
static $functions = array();
|
2531 |
+
return $functions;
|
2532 |
+
}
|
2533 |
+
}
|
2534 |
+
|
2535 |
+
// vim: ts=4:sw=4:et:
|
2536 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/Crypt/Hash.php
ADDED
@@ -0,0 +1,823 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
6 |
+
*
|
7 |
+
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
|
8 |
+
*
|
9 |
+
* md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512
|
10 |
+
*
|
11 |
+
* If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
|
12 |
+
* the hash. If no valid algorithm is provided, sha1 will be used.
|
13 |
+
*
|
14 |
+
* PHP versions 4 and 5
|
15 |
+
*
|
16 |
+
* {@internal The variable names are the same as those in
|
17 |
+
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
|
18 |
+
*
|
19 |
+
* Here's a short example of how to use this library:
|
20 |
+
* <code>
|
21 |
+
* <?php
|
22 |
+
* include('Crypt/Hash.php');
|
23 |
+
*
|
24 |
+
* $hash = new Crypt_Hash('sha1');
|
25 |
+
*
|
26 |
+
* $hash->setKey('abcdefg');
|
27 |
+
*
|
28 |
+
* echo base64_encode($hash->hash('abcdefg'));
|
29 |
+
* ?>
|
30 |
+
* </code>
|
31 |
+
*
|
32 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
33 |
+
* of this software and associated documentation files (the "Software"), to deal
|
34 |
+
* in the Software without restriction, including without limitation the rights
|
35 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
36 |
+
* copies of the Software, and to permit persons to whom the Software is
|
37 |
+
* furnished to do so, subject to the following conditions:
|
38 |
+
*
|
39 |
+
* The above copyright notice and this permission notice shall be included in
|
40 |
+
* all copies or substantial portions of the Software.
|
41 |
+
*
|
42 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
43 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
44 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
45 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
46 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
47 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
48 |
+
* THE SOFTWARE.
|
49 |
+
*
|
50 |
+
* @category Crypt
|
51 |
+
* @package Crypt_Hash
|
52 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
53 |
+
* @copyright MMVII Jim Wigginton
|
54 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
55 |
+
* @link http://phpseclib.sourceforge.net
|
56 |
+
*/
|
57 |
+
|
58 |
+
/**#@+
|
59 |
+
* @access private
|
60 |
+
* @see Crypt_Hash::Crypt_Hash()
|
61 |
+
*/
|
62 |
+
/**
|
63 |
+
* Toggles the internal implementation
|
64 |
+
*/
|
65 |
+
define('CRYPT_HASH_MODE_INTERNAL', 1);
|
66 |
+
/**
|
67 |
+
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
|
68 |
+
*/
|
69 |
+
define('CRYPT_HASH_MODE_MHASH', 2);
|
70 |
+
/**
|
71 |
+
* Toggles the hash() implementation, which works on PHP 5.1.2+.
|
72 |
+
*/
|
73 |
+
define('CRYPT_HASH_MODE_HASH', 3);
|
74 |
+
/**#@-*/
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
78 |
+
*
|
79 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
80 |
+
* @version 0.1.0
|
81 |
+
* @access public
|
82 |
+
* @package Crypt_Hash
|
83 |
+
*/
|
84 |
+
class Crypt_Hash {
|
85 |
+
/**
|
86 |
+
* Byte-length of compression blocks / key (Internal HMAC)
|
87 |
+
*
|
88 |
+
* @see Crypt_Hash::setAlgorithm()
|
89 |
+
* @var Integer
|
90 |
+
* @access private
|
91 |
+
*/
|
92 |
+
var $b;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Byte-length of hash output (Internal HMAC)
|
96 |
+
*
|
97 |
+
* @see Crypt_Hash::setHash()
|
98 |
+
* @var Integer
|
99 |
+
* @access private
|
100 |
+
*/
|
101 |
+
var $l = false;
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Hash Algorithm
|
105 |
+
*
|
106 |
+
* @see Crypt_Hash::setHash()
|
107 |
+
* @var String
|
108 |
+
* @access private
|
109 |
+
*/
|
110 |
+
var $hash;
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Key
|
114 |
+
*
|
115 |
+
* @see Crypt_Hash::setKey()
|
116 |
+
* @var String
|
117 |
+
* @access private
|
118 |
+
*/
|
119 |
+
var $key = false;
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Outer XOR (Internal HMAC)
|
123 |
+
*
|
124 |
+
* @see Crypt_Hash::setKey()
|
125 |
+
* @var String
|
126 |
+
* @access private
|
127 |
+
*/
|
128 |
+
var $opad;
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Inner XOR (Internal HMAC)
|
132 |
+
*
|
133 |
+
* @see Crypt_Hash::setKey()
|
134 |
+
* @var String
|
135 |
+
* @access private
|
136 |
+
*/
|
137 |
+
var $ipad;
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Default Constructor.
|
141 |
+
*
|
142 |
+
* @param optional String $hash
|
143 |
+
* @return Crypt_Hash
|
144 |
+
* @access public
|
145 |
+
*/
|
146 |
+
function Crypt_Hash($hash = 'sha1')
|
147 |
+
{
|
148 |
+
if ( !defined('CRYPT_HASH_MODE') ) {
|
149 |
+
switch (true) {
|
150 |
+
case extension_loaded('hash'):
|
151 |
+
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
|
152 |
+
break;
|
153 |
+
case extension_loaded('mhash'):
|
154 |
+
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
|
155 |
+
break;
|
156 |
+
default:
|
157 |
+
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
$this->setHash($hash);
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Sets the key for HMACs
|
166 |
+
*
|
167 |
+
* Keys can be of any length.
|
168 |
+
*
|
169 |
+
* @access public
|
170 |
+
* @param optional String $key
|
171 |
+
*/
|
172 |
+
function setKey($key = false)
|
173 |
+
{
|
174 |
+
$this->key = $key;
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Sets the hash function.
|
179 |
+
*
|
180 |
+
* @access public
|
181 |
+
* @param String $hash
|
182 |
+
*/
|
183 |
+
function setHash($hash)
|
184 |
+
{
|
185 |
+
$hash = strtolower($hash);
|
186 |
+
switch ($hash) {
|
187 |
+
case 'md5-96':
|
188 |
+
case 'sha1-96':
|
189 |
+
$this->l = 12; // 96 / 8 = 12
|
190 |
+
break;
|
191 |
+
case 'md2':
|
192 |
+
case 'md5':
|
193 |
+
$this->l = 16;
|
194 |
+
break;
|
195 |
+
case 'sha1':
|
196 |
+
$this->l = 20;
|
197 |
+
break;
|
198 |
+
case 'sha256':
|
199 |
+
$this->l = 32;
|
200 |
+
break;
|
201 |
+
case 'sha384':
|
202 |
+
$this->l = 48;
|
203 |
+
break;
|
204 |
+
case 'sha512':
|
205 |
+
$this->l = 64;
|
206 |
+
}
|
207 |
+
|
208 |
+
switch ($hash) {
|
209 |
+
case 'md2':
|
210 |
+
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
|
211 |
+
CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
|
212 |
+
break;
|
213 |
+
case 'sha384':
|
214 |
+
case 'sha512':
|
215 |
+
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
|
216 |
+
break;
|
217 |
+
default:
|
218 |
+
$mode = CRYPT_HASH_MODE;
|
219 |
+
}
|
220 |
+
|
221 |
+
switch ( $mode ) {
|
222 |
+
case CRYPT_HASH_MODE_MHASH:
|
223 |
+
switch ($hash) {
|
224 |
+
case 'md5':
|
225 |
+
case 'md5-96':
|
226 |
+
$this->hash = MHASH_MD5;
|
227 |
+
break;
|
228 |
+
case 'sha256':
|
229 |
+
$this->hash = MHASH_SHA256;
|
230 |
+
break;
|
231 |
+
case 'sha1':
|
232 |
+
case 'sha1-96':
|
233 |
+
default:
|
234 |
+
$this->hash = MHASH_SHA1;
|
235 |
+
}
|
236 |
+
return;
|
237 |
+
case CRYPT_HASH_MODE_HASH:
|
238 |
+
switch ($hash) {
|
239 |
+
case 'md5':
|
240 |
+
case 'md5-96':
|
241 |
+
$this->hash = 'md5';
|
242 |
+
return;
|
243 |
+
case 'md2':
|
244 |
+
case 'sha256':
|
245 |
+
case 'sha384':
|
246 |
+
case 'sha512':
|
247 |
+
$this->hash = $hash;
|
248 |
+
return;
|
249 |
+
case 'sha1':
|
250 |
+
case 'sha1-96':
|
251 |
+
default:
|
252 |
+
$this->hash = 'sha1';
|
253 |
+
}
|
254 |
+
return;
|
255 |
+
}
|
256 |
+
|
257 |
+
switch ($hash) {
|
258 |
+
case 'md2':
|
259 |
+
$this->b = 16;
|
260 |
+
$this->hash = array($this, '_md2');
|
261 |
+
break;
|
262 |
+
case 'md5':
|
263 |
+
case 'md5-96':
|
264 |
+
$this->b = 64;
|
265 |
+
$this->hash = array($this, '_md5');
|
266 |
+
break;
|
267 |
+
case 'sha256':
|
268 |
+
$this->b = 64;
|
269 |
+
$this->hash = array($this, '_sha256');
|
270 |
+
break;
|
271 |
+
case 'sha384':
|
272 |
+
case 'sha512':
|
273 |
+
$this->b = 128;
|
274 |
+
$this->hash = array($this, '_sha512');
|
275 |
+
break;
|
276 |
+
case 'sha1':
|
277 |
+
case 'sha1-96':
|
278 |
+
default:
|
279 |
+
$this->b = 64;
|
280 |
+
$this->hash = array($this, '_sha1');
|
281 |
+
}
|
282 |
+
|
283 |
+
$this->ipad = str_repeat(chr(0x36), $this->b);
|
284 |
+
$this->opad = str_repeat(chr(0x5C), $this->b);
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Compute the HMAC.
|
289 |
+
*
|
290 |
+
* @access public
|
291 |
+
* @param String $text
|
292 |
+
* @return String
|
293 |
+
*/
|
294 |
+
function hash($text)
|
295 |
+
{
|
296 |
+
$mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
|
297 |
+
|
298 |
+
if (!empty($this->key) || is_string($this->key)) {
|
299 |
+
switch ( $mode ) {
|
300 |
+
case CRYPT_HASH_MODE_MHASH:
|
301 |
+
$output = mhash($this->hash, $text, $this->key);
|
302 |
+
break;
|
303 |
+
case CRYPT_HASH_MODE_HASH:
|
304 |
+
$output = hash_hmac($this->hash, $text, $this->key, true);
|
305 |
+
break;
|
306 |
+
case CRYPT_HASH_MODE_INTERNAL:
|
307 |
+
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the
|
308 |
+
resultant L byte string as the actual key to HMAC."
|
309 |
+
|
310 |
+
-- http://tools.ietf.org/html/rfc2104#section-2 */
|
311 |
+
$key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
|
312 |
+
|
313 |
+
$key = str_pad($key, $this->b, chr(0)); // step 1
|
314 |
+
$temp = $this->ipad ^ $key; // step 2
|
315 |
+
$temp .= $text; // step 3
|
316 |
+
$temp = call_user_func($this->hash, $temp); // step 4
|
317 |
+
$output = $this->opad ^ $key; // step 5
|
318 |
+
$output.= $temp; // step 6
|
319 |
+
$output = call_user_func($this->hash, $output); // step 7
|
320 |
+
}
|
321 |
+
} else {
|
322 |
+
switch ( $mode ) {
|
323 |
+
case CRYPT_HASH_MODE_MHASH:
|
324 |
+
$output = mhash($this->hash, $text);
|
325 |
+
break;
|
326 |
+
case CRYPT_HASH_MODE_HASH:
|
327 |
+
$output = hash($this->hash, $text, true);
|
328 |
+
break;
|
329 |
+
case CRYPT_HASH_MODE_INTERNAL:
|
330 |
+
$output = call_user_func($this->hash, $text);
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
return substr($output, 0, $this->l);
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Returns the hash length (in bytes)
|
339 |
+
*
|
340 |
+
* @access public
|
341 |
+
* @return Integer
|
342 |
+
*/
|
343 |
+
function getLength()
|
344 |
+
{
|
345 |
+
return $this->l;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* Wrapper for MD5
|
350 |
+
*
|
351 |
+
* @access private
|
352 |
+
* @param String $m
|
353 |
+
*/
|
354 |
+
function _md5($m)
|
355 |
+
{
|
356 |
+
return pack('H*', md5($m));
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* Wrapper for SHA1
|
361 |
+
*
|
362 |
+
* @access private
|
363 |
+
* @param String $m
|
364 |
+
*/
|
365 |
+
function _sha1($m)
|
366 |
+
{
|
367 |
+
return pack('H*', sha1($m));
|
368 |
+
}
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Pure-PHP implementation of MD2
|
372 |
+
*
|
373 |
+
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
|
374 |
+
*
|
375 |
+
* @access private
|
376 |
+
* @param String $m
|
377 |
+
*/
|
378 |
+
function _md2($m)
|
379 |
+
{
|
380 |
+
static $s = array(
|
381 |
+
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
382 |
+
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
|
383 |
+
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
|
384 |
+
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
|
385 |
+
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
|
386 |
+
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
|
387 |
+
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
|
388 |
+
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
|
389 |
+
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
|
390 |
+
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
|
391 |
+
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
|
392 |
+
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
|
393 |
+
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
|
394 |
+
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
|
395 |
+
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
|
396 |
+
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
|
397 |
+
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
|
398 |
+
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
|
399 |
+
);
|
400 |
+
|
401 |
+
// Step 1. Append Padding Bytes
|
402 |
+
$pad = 16 - (strlen($m) & 0xF);
|
403 |
+
$m.= str_repeat(chr($pad), $pad);
|
404 |
+
|
405 |
+
$length = strlen($m);
|
406 |
+
|
407 |
+
// Step 2. Append Checksum
|
408 |
+
$c = str_repeat(chr(0), 16);
|
409 |
+
$l = chr(0);
|
410 |
+
for ($i = 0; $i < $length; $i+= 16) {
|
411 |
+
for ($j = 0; $j < 16; $j++) {
|
412 |
+
// RFC1319 incorrectly states that C[j] should be set to S[c xor L]
|
413 |
+
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
|
414 |
+
// per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
|
415 |
+
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
|
416 |
+
$l = $c[$j];
|
417 |
+
}
|
418 |
+
}
|
419 |
+
$m.= $c;
|
420 |
+
|
421 |
+
$length+= 16;
|
422 |
+
|
423 |
+
// Step 3. Initialize MD Buffer
|
424 |
+
$x = str_repeat(chr(0), 48);
|
425 |
+
|
426 |
+
// Step 4. Process Message in 16-Byte Blocks
|
427 |
+
for ($i = 0; $i < $length; $i+= 16) {
|
428 |
+
for ($j = 0; $j < 16; $j++) {
|
429 |
+
$x[$j + 16] = $m[$i + $j];
|
430 |
+
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
|
431 |
+
}
|
432 |
+
$t = chr(0);
|
433 |
+
for ($j = 0; $j < 18; $j++) {
|
434 |
+
for ($k = 0; $k < 48; $k++) {
|
435 |
+
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
|
436 |
+
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
|
437 |
+
}
|
438 |
+
$t = chr(ord($t) + $j);
|
439 |
+
}
|
440 |
+
}
|
441 |
+
|
442 |
+
// Step 5. Output
|
443 |
+
return substr($x, 0, 16);
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Pure-PHP implementation of SHA256
|
448 |
+
*
|
449 |
+
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
|
450 |
+
*
|
451 |
+
* @access private
|
452 |
+
* @param String $m
|
453 |
+
*/
|
454 |
+
function _sha256($m)
|
455 |
+
{
|
456 |
+
if (extension_loaded('suhosin')) {
|
457 |
+
return pack('H*', sha256($m));
|
458 |
+
}
|
459 |
+
|
460 |
+
// Initialize variables
|
461 |
+
$hash = array(
|
462 |
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
463 |
+
);
|
464 |
+
// Initialize table of round constants
|
465 |
+
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
|
466 |
+
static $k = array(
|
467 |
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
468 |
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
469 |
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
470 |
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
471 |
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
472 |
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
473 |
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
474 |
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
475 |
+
);
|
476 |
+
|
477 |
+
// Pre-processing
|
478 |
+
$length = strlen($m);
|
479 |
+
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
|
480 |
+
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
|
481 |
+
$m[$length] = chr(0x80);
|
482 |
+
// we don't support hashing strings 512MB long
|
483 |
+
$m.= pack('N2', 0, $length << 3);
|
484 |
+
|
485 |
+
// Process the message in successive 512-bit chunks
|
486 |
+
$chunks = str_split($m, 64);
|
487 |
+
foreach ($chunks as $chunk) {
|
488 |
+
$w = array();
|
489 |
+
for ($i = 0; $i < 16; $i++) {
|
490 |
+
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
|
491 |
+
$w[] = $temp;
|
492 |
+
}
|
493 |
+
|
494 |
+
// Extend the sixteen 32-bit words into sixty-four 32-bit words
|
495 |
+
for ($i = 16; $i < 64; $i++) {
|
496 |
+
$s0 = $this->_rightRotate($w[$i - 15], 7) ^
|
497 |
+
$this->_rightRotate($w[$i - 15], 18) ^
|
498 |
+
$this->_rightShift( $w[$i - 15], 3);
|
499 |
+
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
|
500 |
+
$this->_rightRotate($w[$i - 2], 19) ^
|
501 |
+
$this->_rightShift( $w[$i - 2], 10);
|
502 |
+
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
|
503 |
+
|
504 |
+
}
|
505 |
+
|
506 |
+
// Initialize hash value for this chunk
|
507 |
+
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
|
508 |
+
|
509 |
+
// Main loop
|
510 |
+
for ($i = 0; $i < 64; $i++) {
|
511 |
+
$s0 = $this->_rightRotate($a, 2) ^
|
512 |
+
$this->_rightRotate($a, 13) ^
|
513 |
+
$this->_rightRotate($a, 22);
|
514 |
+
$maj = ($a & $b) ^
|
515 |
+
($a & $c) ^
|
516 |
+
($b & $c);
|
517 |
+
$t2 = $this->_add($s0, $maj);
|
518 |
+
|
519 |
+
$s1 = $this->_rightRotate($e, 6) ^
|
520 |
+
$this->_rightRotate($e, 11) ^
|
521 |
+
$this->_rightRotate($e, 25);
|
522 |
+
$ch = ($e & $f) ^
|
523 |
+
($this->_not($e) & $g);
|
524 |
+
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
|
525 |
+
|
526 |
+
$h = $g;
|
527 |
+
$g = $f;
|
528 |
+
$f = $e;
|
529 |
+
$e = $this->_add($d, $t1);
|
530 |
+
$d = $c;
|
531 |
+
$c = $b;
|
532 |
+
$b = $a;
|
533 |
+
$a = $this->_add($t1, $t2);
|
534 |
+
}
|
535 |
+
|
536 |
+
// Add this chunk's hash to result so far
|
537 |
+
$hash = array(
|
538 |
+
$this->_add($hash[0], $a),
|
539 |
+
$this->_add($hash[1], $b),
|
540 |
+
$this->_add($hash[2], $c),
|
541 |
+
$this->_add($hash[3], $d),
|
542 |
+
$this->_add($hash[4], $e),
|
543 |
+
$this->_add($hash[5], $f),
|
544 |
+
$this->_add($hash[6], $g),
|
545 |
+
$this->_add($hash[7], $h)
|
546 |
+
);
|
547 |
+
}
|
548 |
+
|
549 |
+
// Produce the final hash value (big-endian)
|
550 |
+
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
|
551 |
+
}
|
552 |
+
|
553 |
+
/**
|
554 |
+
* Pure-PHP implementation of SHA384 and SHA512
|
555 |
+
*
|
556 |
+
* @access private
|
557 |
+
* @param String $m
|
558 |
+
*/
|
559 |
+
function _sha512($m)
|
560 |
+
{
|
561 |
+
if (!class_exists('Math_BigInteger')) {
|
562 |
+
require_once('Math/BigInteger.php');
|
563 |
+
}
|
564 |
+
|
565 |
+
static $init384, $init512, $k;
|
566 |
+
|
567 |
+
if (!isset($k)) {
|
568 |
+
// Initialize variables
|
569 |
+
$init384 = array( // initial values for SHA384
|
570 |
+
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
|
571 |
+
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
|
572 |
+
);
|
573 |
+
$init512 = array( // initial values for SHA512
|
574 |
+
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
|
575 |
+
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
|
576 |
+
);
|
577 |
+
|
578 |
+
for ($i = 0; $i < 8; $i++) {
|
579 |
+
$init384[$i] = new Math_BigInteger($init384[$i], 16);
|
580 |
+
$init384[$i]->setPrecision(64);
|
581 |
+
$init512[$i] = new Math_BigInteger($init512[$i], 16);
|
582 |
+
$init512[$i]->setPrecision(64);
|
583 |
+
}
|
584 |
+
|
585 |
+
// Initialize table of round constants
|
586 |
+
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
|
587 |
+
$k = array(
|
588 |
+
'428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
|
589 |
+
'3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
|
590 |
+
'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
|
591 |
+
'72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
|
592 |
+
'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
|
593 |
+
'2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
|
594 |
+
'983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
|
595 |
+
'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
|
596 |
+
'27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
|
597 |
+
'650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
|
598 |
+
'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
|
599 |
+
'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
|
600 |
+
'19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
|
601 |
+
'391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
|
602 |
+
'748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
|
603 |
+
'90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
|
604 |
+
'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
|
605 |
+
'06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
|
606 |
+
'28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
|
607 |
+
'4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
|
608 |
+
);
|
609 |
+
|
610 |
+
for ($i = 0; $i < 80; $i++) {
|
611 |
+
$k[$i] = new Math_BigInteger($k[$i], 16);
|
612 |
+
}
|
613 |
+
}
|
614 |
+
|
615 |
+
$hash = $this->l == 48 ? $init384 : $init512;
|
616 |
+
|
617 |
+
// Pre-processing
|
618 |
+
$length = strlen($m);
|
619 |
+
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
|
620 |
+
$m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
|
621 |
+
$m[$length] = chr(0x80);
|
622 |
+
// we don't support hashing strings 512MB long
|
623 |
+
$m.= pack('N4', 0, 0, 0, $length << 3);
|
624 |
+
|
625 |
+
// Process the message in successive 1024-bit chunks
|
626 |
+
$chunks = str_split($m, 128);
|
627 |
+
foreach ($chunks as $chunk) {
|
628 |
+
$w = array();
|
629 |
+
for ($i = 0; $i < 16; $i++) {
|
630 |
+
$temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
|
631 |
+
$temp->setPrecision(64);
|
632 |
+
$w[] = $temp;
|
633 |
+
}
|
634 |
+
|
635 |
+
// Extend the sixteen 32-bit words into eighty 32-bit words
|
636 |
+
for ($i = 16; $i < 80; $i++) {
|
637 |
+
$temp = array(
|
638 |
+
$w[$i - 15]->bitwise_rightRotate(1),
|
639 |
+
$w[$i - 15]->bitwise_rightRotate(8),
|
640 |
+
$w[$i - 15]->bitwise_rightShift(7)
|
641 |
+
);
|
642 |
+
$s0 = $temp[0]->bitwise_xor($temp[1]);
|
643 |
+
$s0 = $s0->bitwise_xor($temp[2]);
|
644 |
+
$temp = array(
|
645 |
+
$w[$i - 2]->bitwise_rightRotate(19),
|
646 |
+
$w[$i - 2]->bitwise_rightRotate(61),
|
647 |
+
$w[$i - 2]->bitwise_rightShift(6)
|
648 |
+
);
|
649 |
+
$s1 = $temp[0]->bitwise_xor($temp[1]);
|
650 |
+
$s1 = $s1->bitwise_xor($temp[2]);
|
651 |
+
$w[$i] = $w[$i - 16]->copy();
|
652 |
+
$w[$i] = $w[$i]->add($s0);
|
653 |
+
$w[$i] = $w[$i]->add($w[$i - 7]);
|
654 |
+
$w[$i] = $w[$i]->add($s1);
|
655 |
+
}
|
656 |
+
|
657 |
+
// Initialize hash value for this chunk
|
658 |
+
$a = $hash[0]->copy();
|
659 |
+
$b = $hash[1]->copy();
|
660 |
+
$c = $hash[2]->copy();
|
661 |
+
$d = $hash[3]->copy();
|
662 |
+
$e = $hash[4]->copy();
|
663 |
+
$f = $hash[5]->copy();
|
664 |
+
$g = $hash[6]->copy();
|
665 |
+
$h = $hash[7]->copy();
|
666 |
+
|
667 |
+
// Main loop
|
668 |
+
for ($i = 0; $i < 80; $i++) {
|
669 |
+
$temp = array(
|
670 |
+
$a->bitwise_rightRotate(28),
|
671 |
+
$a->bitwise_rightRotate(34),
|
672 |
+
$a->bitwise_rightRotate(39)
|
673 |
+
);
|
674 |
+
$s0 = $temp[0]->bitwise_xor($temp[1]);
|
675 |
+
$s0 = $s0->bitwise_xor($temp[2]);
|
676 |
+
$temp = array(
|
677 |
+
$a->bitwise_and($b),
|
678 |
+
$a->bitwise_and($c),
|
679 |
+
$b->bitwise_and($c)
|
680 |
+
);
|
681 |
+
$maj = $temp[0]->bitwise_xor($temp[1]);
|
682 |
+
$maj = $maj->bitwise_xor($temp[2]);
|
683 |
+
$t2 = $s0->add($maj);
|
684 |
+
|
685 |
+
$temp = array(
|
686 |
+
$e->bitwise_rightRotate(14),
|
687 |
+
$e->bitwise_rightRotate(18),
|
688 |
+
$e->bitwise_rightRotate(41)
|
689 |
+
);
|
690 |
+
$s1 = $temp[0]->bitwise_xor($temp[1]);
|
691 |
+
$s1 = $s1->bitwise_xor($temp[2]);
|
692 |
+
$temp = array(
|
693 |
+
$e->bitwise_and($f),
|
694 |
+
$g->bitwise_and($e->bitwise_not())
|
695 |
+
);
|
696 |
+
$ch = $temp[0]->bitwise_xor($temp[1]);
|
697 |
+
$t1 = $h->add($s1);
|
698 |
+
$t1 = $t1->add($ch);
|
699 |
+
$t1 = $t1->add($k[$i]);
|
700 |
+
$t1 = $t1->add($w[$i]);
|
701 |
+
|
702 |
+
$h = $g->copy();
|
703 |
+
$g = $f->copy();
|
704 |
+
$f = $e->copy();
|
705 |
+
$e = $d->add($t1);
|
706 |
+
$d = $c->copy();
|
707 |
+
$c = $b->copy();
|
708 |
+
$b = $a->copy();
|
709 |
+
$a = $t1->add($t2);
|
710 |
+
}
|
711 |
+
|
712 |
+
// Add this chunk's hash to result so far
|
713 |
+
$hash = array(
|
714 |
+
$hash[0]->add($a),
|
715 |
+
$hash[1]->add($b),
|
716 |
+
$hash[2]->add($c),
|
717 |
+
$hash[3]->add($d),
|
718 |
+
$hash[4]->add($e),
|
719 |
+
$hash[5]->add($f),
|
720 |
+
$hash[6]->add($g),
|
721 |
+
$hash[7]->add($h)
|
722 |
+
);
|
723 |
+
}
|
724 |
+
|
725 |
+
// Produce the final hash value (big-endian)
|
726 |
+
// (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
|
727 |
+
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
|
728 |
+
$hash[4]->toBytes() . $hash[5]->toBytes();
|
729 |
+
if ($this->l != 48) {
|
730 |
+
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
|
731 |
+
}
|
732 |
+
|
733 |
+
return $temp;
|
734 |
+
}
|
735 |
+
|
736 |
+
/**
|
737 |
+
* Right Rotate
|
738 |
+
*
|
739 |
+
* @access private
|
740 |
+
* @param Integer $int
|
741 |
+
* @param Integer $amt
|
742 |
+
* @see _sha256()
|
743 |
+
* @return Integer
|
744 |
+
*/
|
745 |
+
function _rightRotate($int, $amt)
|
746 |
+
{
|
747 |
+
$invamt = 32 - $amt;
|
748 |
+
$mask = (1 << $invamt) - 1;
|
749 |
+
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
|
750 |
+
}
|
751 |
+
|
752 |
+
/**
|
753 |
+
* Right Shift
|
754 |
+
*
|
755 |
+
* @access private
|
756 |
+
* @param Integer $int
|
757 |
+
* @param Integer $amt
|
758 |
+
* @see _sha256()
|
759 |
+
* @return Integer
|
760 |
+
*/
|
761 |
+
function _rightShift($int, $amt)
|
762 |
+
{
|
763 |
+
$mask = (1 << (32 - $amt)) - 1;
|
764 |
+
return ($int >> $amt) & $mask;
|
765 |
+
}
|
766 |
+
|
767 |
+
/**
|
768 |
+
* Not
|
769 |
+
*
|
770 |
+
* @access private
|
771 |
+
* @param Integer $int
|
772 |
+
* @see _sha256()
|
773 |
+
* @return Integer
|
774 |
+
*/
|
775 |
+
function _not($int)
|
776 |
+
{
|
777 |
+
return ~$int & 0xFFFFFFFF;
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* Add
|
782 |
+
*
|
783 |
+
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
|
784 |
+
* possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
|
785 |
+
*
|
786 |
+
* @param Integer $...
|
787 |
+
* @return Integer
|
788 |
+
* @see _sha256()
|
789 |
+
* @access private
|
790 |
+
*/
|
791 |
+
function _add()
|
792 |
+
{
|
793 |
+
static $mod;
|
794 |
+
if (!isset($mod)) {
|
795 |
+
$mod = pow(2, 32);
|
796 |
+
}
|
797 |
+
|
798 |
+
$result = 0;
|
799 |
+
$arguments = func_get_args();
|
800 |
+
foreach ($arguments as $argument) {
|
801 |
+
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
|
802 |
+
}
|
803 |
+
|
804 |
+
return fmod($result, $mod);
|
805 |
+
}
|
806 |
+
|
807 |
+
/**
|
808 |
+
* String Shift
|
809 |
+
*
|
810 |
+
* Inspired by array_shift
|
811 |
+
*
|
812 |
+
* @param String $string
|
813 |
+
* @param optional Integer $index
|
814 |
+
* @return String
|
815 |
+
* @access private
|
816 |
+
*/
|
817 |
+
function _string_shift(&$string, $index = 1)
|
818 |
+
{
|
819 |
+
$substr = substr($string, 0, $index);
|
820 |
+
$string = substr($string, $index);
|
821 |
+
return $substr;
|
822 |
+
}
|
823 |
+
}
|
lib/PHPSecLib/Crypt/RC4.php
ADDED
@@ -0,0 +1,492 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of RC4.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Useful resources are as follows:
|
12 |
+
*
|
13 |
+
* - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
|
14 |
+
* - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
|
15 |
+
*
|
16 |
+
* RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
|
17 |
+
* ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
|
18 |
+
*
|
19 |
+
* Here's a short example of how to use this library:
|
20 |
+
* <code>
|
21 |
+
* <?php
|
22 |
+
* include('Crypt/RC4.php');
|
23 |
+
*
|
24 |
+
* $rc4 = new Crypt_RC4();
|
25 |
+
*
|
26 |
+
* $rc4->setKey('abcdefgh');
|
27 |
+
*
|
28 |
+
* $size = 10 * 1024;
|
29 |
+
* $plaintext = '';
|
30 |
+
* for ($i = 0; $i < $size; $i++) {
|
31 |
+
* $plaintext.= 'a';
|
32 |
+
* }
|
33 |
+
*
|
34 |
+
* echo $rc4->decrypt($rc4->encrypt($plaintext));
|
35 |
+
* ?>
|
36 |
+
* </code>
|
37 |
+
*
|
38 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
39 |
+
* of this software and associated documentation files (the "Software"), to deal
|
40 |
+
* in the Software without restriction, including without limitation the rights
|
41 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
42 |
+
* copies of the Software, and to permit persons to whom the Software is
|
43 |
+
* furnished to do so, subject to the following conditions:
|
44 |
+
*
|
45 |
+
* The above copyright notice and this permission notice shall be included in
|
46 |
+
* all copies or substantial portions of the Software.
|
47 |
+
*
|
48 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
49 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
50 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
51 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
52 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
53 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
54 |
+
* THE SOFTWARE.
|
55 |
+
*
|
56 |
+
* @category Crypt
|
57 |
+
* @package Crypt_RC4
|
58 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
59 |
+
* @copyright MMVII Jim Wigginton
|
60 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
61 |
+
* @link http://phpseclib.sourceforge.net
|
62 |
+
*/
|
63 |
+
|
64 |
+
/**#@+
|
65 |
+
* @access private
|
66 |
+
* @see Crypt_RC4::Crypt_RC4()
|
67 |
+
*/
|
68 |
+
/**
|
69 |
+
* Toggles the internal implementation
|
70 |
+
*/
|
71 |
+
define('CRYPT_RC4_MODE_INTERNAL', 1);
|
72 |
+
/**
|
73 |
+
* Toggles the mcrypt implementation
|
74 |
+
*/
|
75 |
+
define('CRYPT_RC4_MODE_MCRYPT', 2);
|
76 |
+
/**#@-*/
|
77 |
+
|
78 |
+
/**#@+
|
79 |
+
* @access private
|
80 |
+
* @see Crypt_RC4::_crypt()
|
81 |
+
*/
|
82 |
+
define('CRYPT_RC4_ENCRYPT', 0);
|
83 |
+
define('CRYPT_RC4_DECRYPT', 1);
|
84 |
+
/**#@-*/
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Pure-PHP implementation of RC4.
|
88 |
+
*
|
89 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
90 |
+
* @version 0.1.0
|
91 |
+
* @access public
|
92 |
+
* @package Crypt_RC4
|
93 |
+
*/
|
94 |
+
class Crypt_RC4 {
|
95 |
+
/**
|
96 |
+
* The Key
|
97 |
+
*
|
98 |
+
* @see Crypt_RC4::setKey()
|
99 |
+
* @var String
|
100 |
+
* @access private
|
101 |
+
*/
|
102 |
+
var $key = "\0";
|
103 |
+
|
104 |
+
/**
|
105 |
+
* The Key Stream for encryption
|
106 |
+
*
|
107 |
+
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
|
108 |
+
*
|
109 |
+
* @see Crypt_RC4::setKey()
|
110 |
+
* @var Array
|
111 |
+
* @access private
|
112 |
+
*/
|
113 |
+
var $encryptStream = false;
|
114 |
+
|
115 |
+
/**
|
116 |
+
* The Key Stream for decryption
|
117 |
+
*
|
118 |
+
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
|
119 |
+
*
|
120 |
+
* @see Crypt_RC4::setKey()
|
121 |
+
* @var Array
|
122 |
+
* @access private
|
123 |
+
*/
|
124 |
+
var $decryptStream = false;
|
125 |
+
|
126 |
+
/**
|
127 |
+
* The $i and $j indexes for encryption
|
128 |
+
*
|
129 |
+
* @see Crypt_RC4::_crypt()
|
130 |
+
* @var Integer
|
131 |
+
* @access private
|
132 |
+
*/
|
133 |
+
var $encryptIndex = 0;
|
134 |
+
|
135 |
+
/**
|
136 |
+
* The $i and $j indexes for decryption
|
137 |
+
*
|
138 |
+
* @see Crypt_RC4::_crypt()
|
139 |
+
* @var Integer
|
140 |
+
* @access private
|
141 |
+
*/
|
142 |
+
var $decryptIndex = 0;
|
143 |
+
|
144 |
+
/**
|
145 |
+
* The Encryption Algorithm
|
146 |
+
*
|
147 |
+
* Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
|
148 |
+
*
|
149 |
+
* @see Crypt_RC4::Crypt_RC4()
|
150 |
+
* @var Integer
|
151 |
+
* @access private
|
152 |
+
*/
|
153 |
+
var $mode;
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Continuous Buffer status
|
157 |
+
*
|
158 |
+
* @see Crypt_RC4::enableContinuousBuffer()
|
159 |
+
* @var Boolean
|
160 |
+
* @access private
|
161 |
+
*/
|
162 |
+
var $continuousBuffer = false;
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Default Constructor.
|
166 |
+
*
|
167 |
+
* Determines whether or not the mcrypt extension should be used.
|
168 |
+
*
|
169 |
+
* @return Crypt_RC4
|
170 |
+
* @access public
|
171 |
+
*/
|
172 |
+
function Crypt_RC4()
|
173 |
+
{
|
174 |
+
if ( !defined('CRYPT_RC4_MODE') ) {
|
175 |
+
switch (true) {
|
176 |
+
case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
|
177 |
+
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
|
178 |
+
break;
|
179 |
+
default:
|
180 |
+
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
switch ( CRYPT_RC4_MODE ) {
|
185 |
+
case CRYPT_RC4_MODE_MCRYPT:
|
186 |
+
switch (true) {
|
187 |
+
case defined('MCRYPT_ARCFOUR'):
|
188 |
+
$this->mode = MCRYPT_ARCFOUR;
|
189 |
+
break;
|
190 |
+
case defined('MCRYPT_RC4');
|
191 |
+
$this->mode = MCRYPT_RC4;
|
192 |
+
}
|
193 |
+
$this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
|
194 |
+
$this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
|
195 |
+
|
196 |
+
}
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Sets the key.
|
201 |
+
*
|
202 |
+
* Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
|
203 |
+
* be used. If no key is explicitly set, it'll be assumed to be a single null byte.
|
204 |
+
*
|
205 |
+
* @access public
|
206 |
+
* @param String $key
|
207 |
+
*/
|
208 |
+
function setKey($key)
|
209 |
+
{
|
210 |
+
$this->key = $key;
|
211 |
+
|
212 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
213 |
+
mcrypt_generic_init($this->encryptStream, $this->key, '');
|
214 |
+
mcrypt_generic_init($this->decryptStream, $this->key, '');
|
215 |
+
return;
|
216 |
+
}
|
217 |
+
|
218 |
+
$keyLength = strlen($key);
|
219 |
+
$keyStream = array();
|
220 |
+
for ($i = 0; $i < 256; $i++) {
|
221 |
+
$keyStream[$i] = $i;
|
222 |
+
}
|
223 |
+
$j = 0;
|
224 |
+
for ($i = 0; $i < 256; $i++) {
|
225 |
+
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
|
226 |
+
$temp = $keyStream[$i];
|
227 |
+
$keyStream[$i] = $keyStream[$j];
|
228 |
+
$keyStream[$j] = $temp;
|
229 |
+
}
|
230 |
+
|
231 |
+
$this->encryptIndex = $this->decryptIndex = array(0, 0);
|
232 |
+
$this->encryptStream = $this->decryptStream = $keyStream;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Sets the password.
|
237 |
+
*
|
238 |
+
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
|
239 |
+
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
|
240 |
+
* $hash, $salt, $count, $dkLen
|
241 |
+
*
|
242 |
+
* @param String $password
|
243 |
+
* @param optional String $method
|
244 |
+
* @access public
|
245 |
+
*/
|
246 |
+
function setPassword($password, $method = 'pbkdf2')
|
247 |
+
{
|
248 |
+
$key = '';
|
249 |
+
|
250 |
+
switch ($method) {
|
251 |
+
default: // 'pbkdf2'
|
252 |
+
list(, , $hash, $salt, $count) = func_get_args();
|
253 |
+
if (!isset($hash)) {
|
254 |
+
$hash = 'sha1';
|
255 |
+
}
|
256 |
+
// WPA and WPA2 use the SSID as the salt
|
257 |
+
if (!isset($salt)) {
|
258 |
+
$salt = 'phpseclib/salt';
|
259 |
+
}
|
260 |
+
// RFC2898#section-4.2 uses 1,000 iterations by default
|
261 |
+
// WPA and WPA2 use 4,096.
|
262 |
+
if (!isset($count)) {
|
263 |
+
$count = 1000;
|
264 |
+
}
|
265 |
+
if (!isset($dkLen)) {
|
266 |
+
$dkLen = 128;
|
267 |
+
}
|
268 |
+
|
269 |
+
if (!class_exists('Crypt_Hash')) {
|
270 |
+
require_once('Crypt/Hash.php');
|
271 |
+
}
|
272 |
+
|
273 |
+
$i = 1;
|
274 |
+
while (strlen($key) < $dkLen) {
|
275 |
+
//$dk.= $this->_pbkdf($password, $salt, $count, $i++);
|
276 |
+
$hmac = new Crypt_Hash();
|
277 |
+
$hmac->setHash($hash);
|
278 |
+
$hmac->setKey($password);
|
279 |
+
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
280 |
+
for ($j = 2; $j <= $count; $j++) {
|
281 |
+
$u = $hmac->hash($u);
|
282 |
+
$f^= $u;
|
283 |
+
}
|
284 |
+
$key.= $f;
|
285 |
+
}
|
286 |
+
}
|
287 |
+
|
288 |
+
$this->setKey(substr($key, 0, $dkLen));
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* Dummy function.
|
293 |
+
*
|
294 |
+
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
|
295 |
+
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
|
296 |
+
* calling setKey().
|
297 |
+
*
|
298 |
+
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
|
299 |
+
* the IV's are relatively easy to predict, an attack described by
|
300 |
+
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
|
301 |
+
* can be used to quickly guess at the rest of the key. The following links elaborate:
|
302 |
+
*
|
303 |
+
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
|
304 |
+
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
|
305 |
+
*
|
306 |
+
* @param String $iv
|
307 |
+
* @see Crypt_RC4::setKey()
|
308 |
+
* @access public
|
309 |
+
*/
|
310 |
+
function setIV($iv)
|
311 |
+
{
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Encrypts a message.
|
316 |
+
*
|
317 |
+
* @see Crypt_RC4::_crypt()
|
318 |
+
* @access public
|
319 |
+
* @param String $plaintext
|
320 |
+
*/
|
321 |
+
function encrypt($plaintext)
|
322 |
+
{
|
323 |
+
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
|
324 |
+
}
|
325 |
+
|
326 |
+
/**
|
327 |
+
* Decrypts a message.
|
328 |
+
*
|
329 |
+
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
|
330 |
+
* Atleast if the continuous buffer is disabled.
|
331 |
+
*
|
332 |
+
* @see Crypt_RC4::_crypt()
|
333 |
+
* @access public
|
334 |
+
* @param String $ciphertext
|
335 |
+
*/
|
336 |
+
function decrypt($ciphertext)
|
337 |
+
{
|
338 |
+
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
|
339 |
+
}
|
340 |
+
|
341 |
+
/**
|
342 |
+
* Encrypts or decrypts a message.
|
343 |
+
*
|
344 |
+
* @see Crypt_RC4::encrypt()
|
345 |
+
* @see Crypt_RC4::decrypt()
|
346 |
+
* @access private
|
347 |
+
* @param String $text
|
348 |
+
* @param Integer $mode
|
349 |
+
*/
|
350 |
+
function _crypt($text, $mode)
|
351 |
+
{
|
352 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
353 |
+
$keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
|
354 |
+
|
355 |
+
if (!$this->continuousBuffer) {
|
356 |
+
mcrypt_generic_init($this->$keyStream, $this->key, '');
|
357 |
+
}
|
358 |
+
|
359 |
+
return mcrypt_generic($this->$keyStream, $text);
|
360 |
+
}
|
361 |
+
|
362 |
+
if ($this->encryptStream === false) {
|
363 |
+
$this->setKey($this->key);
|
364 |
+
}
|
365 |
+
|
366 |
+
switch ($mode) {
|
367 |
+
case CRYPT_RC4_ENCRYPT:
|
368 |
+
$keyStream = $this->encryptStream;
|
369 |
+
list($i, $j) = $this->encryptIndex;
|
370 |
+
break;
|
371 |
+
case CRYPT_RC4_DECRYPT:
|
372 |
+
$keyStream = $this->decryptStream;
|
373 |
+
list($i, $j) = $this->decryptIndex;
|
374 |
+
}
|
375 |
+
|
376 |
+
$newText = '';
|
377 |
+
for ($k = 0; $k < strlen($text); $k++) {
|
378 |
+
$i = ($i + 1) & 255;
|
379 |
+
$j = ($j + $keyStream[$i]) & 255;
|
380 |
+
$temp = $keyStream[$i];
|
381 |
+
$keyStream[$i] = $keyStream[$j];
|
382 |
+
$keyStream[$j] = $temp;
|
383 |
+
$temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
|
384 |
+
$newText.= chr(ord($text[$k]) ^ $temp);
|
385 |
+
}
|
386 |
+
|
387 |
+
if ($this->continuousBuffer) {
|
388 |
+
switch ($mode) {
|
389 |
+
case CRYPT_RC4_ENCRYPT:
|
390 |
+
$this->encryptStream = $keyStream;
|
391 |
+
$this->encryptIndex = array($i, $j);
|
392 |
+
break;
|
393 |
+
case CRYPT_RC4_DECRYPT:
|
394 |
+
$this->decryptStream = $keyStream;
|
395 |
+
$this->decryptIndex = array($i, $j);
|
396 |
+
}
|
397 |
+
}
|
398 |
+
|
399 |
+
return $newText;
|
400 |
+
}
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
404 |
+
*
|
405 |
+
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
406 |
+
* will yield different outputs:
|
407 |
+
*
|
408 |
+
* <code>
|
409 |
+
* echo $rc4->encrypt(substr($plaintext, 0, 8));
|
410 |
+
* echo $rc4->encrypt(substr($plaintext, 8, 8));
|
411 |
+
* </code>
|
412 |
+
* <code>
|
413 |
+
* echo $rc4->encrypt($plaintext);
|
414 |
+
* </code>
|
415 |
+
*
|
416 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
417 |
+
* another, as demonstrated with the following:
|
418 |
+
*
|
419 |
+
* <code>
|
420 |
+
* $rc4->encrypt(substr($plaintext, 0, 8));
|
421 |
+
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
422 |
+
* </code>
|
423 |
+
* <code>
|
424 |
+
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
425 |
+
* </code>
|
426 |
+
*
|
427 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
428 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
429 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
430 |
+
*
|
431 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
432 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
433 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
434 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
435 |
+
*
|
436 |
+
* @see Crypt_RC4::disableContinuousBuffer()
|
437 |
+
* @access public
|
438 |
+
*/
|
439 |
+
function enableContinuousBuffer()
|
440 |
+
{
|
441 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
442 |
+
mcrypt_generic_init($this->encryptStream, $this->key, '');
|
443 |
+
mcrypt_generic_init($this->decryptStream, $this->key, '');
|
444 |
+
}
|
445 |
+
|
446 |
+
$this->continuousBuffer = true;
|
447 |
+
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
451 |
+
*
|
452 |
+
* The default behavior.
|
453 |
+
*
|
454 |
+
* @see Crypt_RC4::enableContinuousBuffer()
|
455 |
+
* @access public
|
456 |
+
*/
|
457 |
+
function disableContinuousBuffer()
|
458 |
+
{
|
459 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
|
460 |
+
$this->encryptIndex = $this->decryptIndex = array(0, 0);
|
461 |
+
$this->encryptStream = $this->decryptStream = false;
|
462 |
+
}
|
463 |
+
|
464 |
+
$this->continuousBuffer = false;
|
465 |
+
}
|
466 |
+
|
467 |
+
/**
|
468 |
+
* Dummy function.
|
469 |
+
*
|
470 |
+
* Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
|
471 |
+
* included is so that you can switch between a block cipher and a stream cipher transparently.
|
472 |
+
*
|
473 |
+
* @see Crypt_RC4::disablePadding()
|
474 |
+
* @access public
|
475 |
+
*/
|
476 |
+
function enablePadding()
|
477 |
+
{
|
478 |
+
}
|
479 |
+
|
480 |
+
/**
|
481 |
+
* Dummy function.
|
482 |
+
*
|
483 |
+
* @see Crypt_RC4::enablePadding()
|
484 |
+
* @access public
|
485 |
+
*/
|
486 |
+
function disablePadding()
|
487 |
+
{
|
488 |
+
}
|
489 |
+
}
|
490 |
+
|
491 |
+
// vim: ts=4:sw=4:et:
|
492 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/Crypt/RSA.php
ADDED
@@ -0,0 +1,2693 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Here's an example of how to encrypt and decrypt text with this library:
|
10 |
+
* <code>
|
11 |
+
* <?php
|
12 |
+
* include('Crypt/RSA.php');
|
13 |
+
*
|
14 |
+
* $rsa = new Crypt_RSA();
|
15 |
+
* extract($rsa->createKey());
|
16 |
+
*
|
17 |
+
* $plaintext = 'terrafrost';
|
18 |
+
*
|
19 |
+
* $rsa->loadKey($privatekey);
|
20 |
+
* $ciphertext = $rsa->encrypt($plaintext);
|
21 |
+
*
|
22 |
+
* $rsa->loadKey($publickey);
|
23 |
+
* echo $rsa->decrypt($ciphertext);
|
24 |
+
* ?>
|
25 |
+
* </code>
|
26 |
+
*
|
27 |
+
* Here's an example of how to create signatures and verify signatures with this library:
|
28 |
+
* <code>
|
29 |
+
* <?php
|
30 |
+
* include('Crypt/RSA.php');
|
31 |
+
*
|
32 |
+
* $rsa = new Crypt_RSA();
|
33 |
+
* extract($rsa->createKey());
|
34 |
+
*
|
35 |
+
* $plaintext = 'terrafrost';
|
36 |
+
*
|
37 |
+
* $rsa->loadKey($privatekey);
|
38 |
+
* $signature = $rsa->sign($plaintext);
|
39 |
+
*
|
40 |
+
* $rsa->loadKey($publickey);
|
41 |
+
* echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
|
42 |
+
* ?>
|
43 |
+
* </code>
|
44 |
+
*
|
45 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
46 |
+
* of this software and associated documentation files (the "Software"), to deal
|
47 |
+
* in the Software without restriction, including without limitation the rights
|
48 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
49 |
+
* copies of the Software, and to permit persons to whom the Software is
|
50 |
+
* furnished to do so, subject to the following conditions:
|
51 |
+
*
|
52 |
+
* The above copyright notice and this permission notice shall be included in
|
53 |
+
* all copies or substantial portions of the Software.
|
54 |
+
*
|
55 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
56 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
57 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
58 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
59 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
60 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
61 |
+
* THE SOFTWARE.
|
62 |
+
*
|
63 |
+
* @category Crypt
|
64 |
+
* @package Crypt_RSA
|
65 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
66 |
+
* @copyright MMIX Jim Wigginton
|
67 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
68 |
+
* @link http://phpseclib.sourceforge.net
|
69 |
+
*/
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Include Crypt_Random
|
73 |
+
*/
|
74 |
+
// the class_exists() will only be called if the crypt_random_string function hasn't been defined and
|
75 |
+
// will trigger a call to __autoload() if you're wanting to auto-load classes
|
76 |
+
// call function_exists() a second time to stop the require_once from being called outside
|
77 |
+
// of the auto loader
|
78 |
+
if (!function_exists('crypt_random_string')) {
|
79 |
+
require_once('Random.php');
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Include Crypt_Hash
|
84 |
+
*/
|
85 |
+
if (!class_exists('Crypt_Hash')) {
|
86 |
+
require_once('Hash.php');
|
87 |
+
}
|
88 |
+
|
89 |
+
/**#@+
|
90 |
+
* @access public
|
91 |
+
* @see Crypt_RSA::encrypt()
|
92 |
+
* @see Crypt_RSA::decrypt()
|
93 |
+
*/
|
94 |
+
/**
|
95 |
+
* Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
|
96 |
+
* (OAEP) for encryption / decryption.
|
97 |
+
*
|
98 |
+
* Uses sha1 by default.
|
99 |
+
*
|
100 |
+
* @see Crypt_RSA::setHash()
|
101 |
+
* @see Crypt_RSA::setMGFHash()
|
102 |
+
*/
|
103 |
+
define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
|
104 |
+
/**
|
105 |
+
* Use PKCS#1 padding.
|
106 |
+
*
|
107 |
+
* Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
|
108 |
+
* compatability with protocols (like SSH-1) written before OAEP's introduction.
|
109 |
+
*/
|
110 |
+
define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
|
111 |
+
/**#@-*/
|
112 |
+
|
113 |
+
/**#@+
|
114 |
+
* @access public
|
115 |
+
* @see Crypt_RSA::sign()
|
116 |
+
* @see Crypt_RSA::verify()
|
117 |
+
* @see Crypt_RSA::setHash()
|
118 |
+
*/
|
119 |
+
/**
|
120 |
+
* Use the Probabilistic Signature Scheme for signing
|
121 |
+
*
|
122 |
+
* Uses sha1 by default.
|
123 |
+
*
|
124 |
+
* @see Crypt_RSA::setSaltLength()
|
125 |
+
* @see Crypt_RSA::setMGFHash()
|
126 |
+
*/
|
127 |
+
define('CRYPT_RSA_SIGNATURE_PSS', 1);
|
128 |
+
/**
|
129 |
+
* Use the PKCS#1 scheme by default.
|
130 |
+
*
|
131 |
+
* Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
|
132 |
+
* compatability with protocols (like SSH-2) written before PSS's introduction.
|
133 |
+
*/
|
134 |
+
define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
|
135 |
+
/**#@-*/
|
136 |
+
|
137 |
+
/**#@+
|
138 |
+
* @access private
|
139 |
+
* @see Crypt_RSA::createKey()
|
140 |
+
*/
|
141 |
+
/**
|
142 |
+
* ASN1 Integer
|
143 |
+
*/
|
144 |
+
define('CRYPT_RSA_ASN1_INTEGER', 2);
|
145 |
+
/**
|
146 |
+
* ASN1 Bit String
|
147 |
+
*/
|
148 |
+
define('CRYPT_RSA_ASN1_BITSTRING', 3);
|
149 |
+
/**
|
150 |
+
* ASN1 Sequence (with the constucted bit set)
|
151 |
+
*/
|
152 |
+
define('CRYPT_RSA_ASN1_SEQUENCE', 48);
|
153 |
+
/**#@-*/
|
154 |
+
|
155 |
+
/**#@+
|
156 |
+
* @access private
|
157 |
+
* @see Crypt_RSA::Crypt_RSA()
|
158 |
+
*/
|
159 |
+
/**
|
160 |
+
* To use the pure-PHP implementation
|
161 |
+
*/
|
162 |
+
define('CRYPT_RSA_MODE_INTERNAL', 1);
|
163 |
+
/**
|
164 |
+
* To use the OpenSSL library
|
165 |
+
*
|
166 |
+
* (if enabled; otherwise, the internal implementation will be used)
|
167 |
+
*/
|
168 |
+
define('CRYPT_RSA_MODE_OPENSSL', 2);
|
169 |
+
/**#@-*/
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Default openSSL configuration file.
|
173 |
+
*/
|
174 |
+
define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
|
175 |
+
|
176 |
+
|
177 |
+
/**#@+
|
178 |
+
* @access public
|
179 |
+
* @see Crypt_RSA::createKey()
|
180 |
+
* @see Crypt_RSA::setPrivateKeyFormat()
|
181 |
+
*/
|
182 |
+
/**
|
183 |
+
* PKCS#1 formatted private key
|
184 |
+
*
|
185 |
+
* Used by OpenSSH
|
186 |
+
*/
|
187 |
+
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
|
188 |
+
/**
|
189 |
+
* PuTTY formatted private key
|
190 |
+
*/
|
191 |
+
define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
|
192 |
+
/**
|
193 |
+
* XML formatted private key
|
194 |
+
*/
|
195 |
+
define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
|
196 |
+
/**#@-*/
|
197 |
+
|
198 |
+
/**#@+
|
199 |
+
* @access public
|
200 |
+
* @see Crypt_RSA::createKey()
|
201 |
+
* @see Crypt_RSA::setPublicKeyFormat()
|
202 |
+
*/
|
203 |
+
/**
|
204 |
+
* Raw public key
|
205 |
+
*
|
206 |
+
* An array containing two Math_BigInteger objects.
|
207 |
+
*
|
208 |
+
* The exponent can be indexed with any of the following:
|
209 |
+
*
|
210 |
+
* 0, e, exponent, publicExponent
|
211 |
+
*
|
212 |
+
* The modulus can be indexed with any of the following:
|
213 |
+
*
|
214 |
+
* 1, n, modulo, modulus
|
215 |
+
*/
|
216 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
|
217 |
+
/**
|
218 |
+
* PKCS#1 formatted public key (raw)
|
219 |
+
*
|
220 |
+
* Used by File/X509.php
|
221 |
+
*/
|
222 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
|
223 |
+
/**
|
224 |
+
* XML formatted public key
|
225 |
+
*/
|
226 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
|
227 |
+
/**
|
228 |
+
* OpenSSH formatted public key
|
229 |
+
*
|
230 |
+
* Place in $HOME/.ssh/authorized_keys
|
231 |
+
*/
|
232 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
|
233 |
+
/**
|
234 |
+
* PKCS#1 formatted public key (encapsulated)
|
235 |
+
*
|
236 |
+
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
|
237 |
+
*/
|
238 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
|
239 |
+
/**#@-*/
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Pure-PHP PKCS#1 compliant implementation of RSA.
|
243 |
+
*
|
244 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
245 |
+
* @version 0.1.0
|
246 |
+
* @access public
|
247 |
+
* @package Crypt_RSA
|
248 |
+
*/
|
249 |
+
class Crypt_RSA {
|
250 |
+
/**
|
251 |
+
* Precomputed Zero
|
252 |
+
*
|
253 |
+
* @var Array
|
254 |
+
* @access private
|
255 |
+
*/
|
256 |
+
var $zero;
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Precomputed One
|
260 |
+
*
|
261 |
+
* @var Array
|
262 |
+
* @access private
|
263 |
+
*/
|
264 |
+
var $one;
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Private Key Format
|
268 |
+
*
|
269 |
+
* @var Integer
|
270 |
+
* @access private
|
271 |
+
*/
|
272 |
+
var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Public Key Format
|
276 |
+
*
|
277 |
+
* @var Integer
|
278 |
+
* @access public
|
279 |
+
*/
|
280 |
+
var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Modulus (ie. n)
|
284 |
+
*
|
285 |
+
* @var Math_BigInteger
|
286 |
+
* @access private
|
287 |
+
*/
|
288 |
+
var $modulus;
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Modulus length
|
292 |
+
*
|
293 |
+
* @var Math_BigInteger
|
294 |
+
* @access private
|
295 |
+
*/
|
296 |
+
var $k;
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Exponent (ie. e or d)
|
300 |
+
*
|
301 |
+
* @var Math_BigInteger
|
302 |
+
* @access private
|
303 |
+
*/
|
304 |
+
var $exponent;
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Primes for Chinese Remainder Theorem (ie. p and q)
|
308 |
+
*
|
309 |
+
* @var Array
|
310 |
+
* @access private
|
311 |
+
*/
|
312 |
+
var $primes;
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Exponents for Chinese Remainder Theorem (ie. dP and dQ)
|
316 |
+
*
|
317 |
+
* @var Array
|
318 |
+
* @access private
|
319 |
+
*/
|
320 |
+
var $exponents;
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Coefficients for Chinese Remainder Theorem (ie. qInv)
|
324 |
+
*
|
325 |
+
* @var Array
|
326 |
+
* @access private
|
327 |
+
*/
|
328 |
+
var $coefficients;
|
329 |
+
|
330 |
+
/**
|
331 |
+
* Hash name
|
332 |
+
*
|
333 |
+
* @var String
|
334 |
+
* @access private
|
335 |
+
*/
|
336 |
+
var $hashName;
|
337 |
+
|
338 |
+
/**
|
339 |
+
* Hash function
|
340 |
+
*
|
341 |
+
* @var Crypt_Hash
|
342 |
+
* @access private
|
343 |
+
*/
|
344 |
+
var $hash;
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Length of hash function output
|
348 |
+
*
|
349 |
+
* @var Integer
|
350 |
+
* @access private
|
351 |
+
*/
|
352 |
+
var $hLen;
|
353 |
+
|
354 |
+
/**
|
355 |
+
* Length of salt
|
356 |
+
*
|
357 |
+
* @var Integer
|
358 |
+
* @access private
|
359 |
+
*/
|
360 |
+
var $sLen;
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Hash function for the Mask Generation Function
|
364 |
+
*
|
365 |
+
* @var Crypt_Hash
|
366 |
+
* @access private
|
367 |
+
*/
|
368 |
+
var $mgfHash;
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Length of MGF hash function output
|
372 |
+
*
|
373 |
+
* @var Integer
|
374 |
+
* @access private
|
375 |
+
*/
|
376 |
+
var $mgfHLen;
|
377 |
+
|
378 |
+
/**
|
379 |
+
* Encryption mode
|
380 |
+
*
|
381 |
+
* @var Integer
|
382 |
+
* @access private
|
383 |
+
*/
|
384 |
+
var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Signature mode
|
388 |
+
*
|
389 |
+
* @var Integer
|
390 |
+
* @access private
|
391 |
+
*/
|
392 |
+
var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Public Exponent
|
396 |
+
*
|
397 |
+
* @var Mixed
|
398 |
+
* @access private
|
399 |
+
*/
|
400 |
+
var $publicExponent = false;
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Password
|
404 |
+
*
|
405 |
+
* @var String
|
406 |
+
* @access private
|
407 |
+
*/
|
408 |
+
var $password = false;
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Components
|
412 |
+
*
|
413 |
+
* For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
|
414 |
+
* because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
|
415 |
+
*
|
416 |
+
* @see Crypt_RSA::_start_element_handler()
|
417 |
+
* @var Array
|
418 |
+
* @access private
|
419 |
+
*/
|
420 |
+
var $components = array();
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Current String
|
424 |
+
*
|
425 |
+
* For use with parsing XML formatted keys.
|
426 |
+
*
|
427 |
+
* @see Crypt_RSA::_character_handler()
|
428 |
+
* @see Crypt_RSA::_stop_element_handler()
|
429 |
+
* @var Mixed
|
430 |
+
* @access private
|
431 |
+
*/
|
432 |
+
var $current;
|
433 |
+
|
434 |
+
/**
|
435 |
+
* OpenSSL configuration file name.
|
436 |
+
*
|
437 |
+
* Set to NULL to use system configuration file.
|
438 |
+
* @see Crypt_RSA::createKey()
|
439 |
+
* @var Mixed
|
440 |
+
* @Access public
|
441 |
+
*/
|
442 |
+
var $configFile;
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Public key comment field.
|
446 |
+
*
|
447 |
+
* @var String
|
448 |
+
* @access private
|
449 |
+
*/
|
450 |
+
var $comment = 'phpseclib-generated-key';
|
451 |
+
|
452 |
+
/**
|
453 |
+
* The constructor
|
454 |
+
*
|
455 |
+
* If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
|
456 |
+
* Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
|
457 |
+
* openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
|
458 |
+
*
|
459 |
+
* @return Crypt_RSA
|
460 |
+
* @access public
|
461 |
+
*/
|
462 |
+
function Crypt_RSA()
|
463 |
+
{
|
464 |
+
if (!class_exists('Math_BigInteger')) {
|
465 |
+
require_once('Math/BigInteger.php');
|
466 |
+
}
|
467 |
+
|
468 |
+
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
|
469 |
+
|
470 |
+
if ( !defined('CRYPT_RSA_MODE') ) {
|
471 |
+
switch (true) {
|
472 |
+
case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
|
473 |
+
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
|
474 |
+
break;
|
475 |
+
default:
|
476 |
+
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
477 |
+
}
|
478 |
+
}
|
479 |
+
|
480 |
+
$this->zero = new Math_BigInteger();
|
481 |
+
$this->one = new Math_BigInteger(1);
|
482 |
+
|
483 |
+
$this->hash = new Crypt_Hash('sha1');
|
484 |
+
$this->hLen = $this->hash->getLength();
|
485 |
+
$this->hashName = 'sha1';
|
486 |
+
$this->mgfHash = new Crypt_Hash('sha1');
|
487 |
+
$this->mgfHLen = $this->mgfHash->getLength();
|
488 |
+
}
|
489 |
+
|
490 |
+
/**
|
491 |
+
* Create public / private key pair
|
492 |
+
*
|
493 |
+
* Returns an array with the following three elements:
|
494 |
+
* - 'privatekey': The private key.
|
495 |
+
* - 'publickey': The public key.
|
496 |
+
* - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
|
497 |
+
* Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
|
498 |
+
*
|
499 |
+
* @access public
|
500 |
+
* @param optional Integer $bits
|
501 |
+
* @param optional Integer $timeout
|
502 |
+
* @param optional Math_BigInteger $p
|
503 |
+
*/
|
504 |
+
function createKey($bits = 1024, $timeout = false, $partial = array())
|
505 |
+
{
|
506 |
+
if (!defined('CRYPT_RSA_EXPONENT')) {
|
507 |
+
// http://en.wikipedia.org/wiki/65537_%28number%29
|
508 |
+
define('CRYPT_RSA_EXPONENT', '65537');
|
509 |
+
}
|
510 |
+
// per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
|
511 |
+
// than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
|
512 |
+
// to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
|
513 |
+
// CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
|
514 |
+
// CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
|
515 |
+
// generation when there's a chance neither gmp nor OpenSSL are installed)
|
516 |
+
if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
|
517 |
+
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
|
518 |
+
}
|
519 |
+
|
520 |
+
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
|
521 |
+
if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
|
522 |
+
$config = array();
|
523 |
+
if (isset($this->configFile)) {
|
524 |
+
$config['config'] = $this->configFile;
|
525 |
+
}
|
526 |
+
$rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
|
527 |
+
openssl_pkey_export($rsa, $privatekey, NULL, $config);
|
528 |
+
$publickey = openssl_pkey_get_details($rsa);
|
529 |
+
$publickey = $publickey['key'];
|
530 |
+
|
531 |
+
$privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
|
532 |
+
$publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
|
533 |
+
|
534 |
+
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
|
535 |
+
while (openssl_error_string() !== false);
|
536 |
+
|
537 |
+
return array(
|
538 |
+
'privatekey' => $privatekey,
|
539 |
+
'publickey' => $publickey,
|
540 |
+
'partialkey' => false
|
541 |
+
);
|
542 |
+
}
|
543 |
+
|
544 |
+
static $e;
|
545 |
+
if (!isset($e)) {
|
546 |
+
$e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
|
547 |
+
}
|
548 |
+
|
549 |
+
extract($this->_generateMinMax($bits));
|
550 |
+
$absoluteMin = $min;
|
551 |
+
$temp = $bits >> 1; // divide by two to see how many bits P and Q would be
|
552 |
+
if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
|
553 |
+
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
|
554 |
+
$temp = CRYPT_RSA_SMALLEST_PRIME;
|
555 |
+
} else {
|
556 |
+
$num_primes = 2;
|
557 |
+
}
|
558 |
+
extract($this->_generateMinMax($temp + $bits % $temp));
|
559 |
+
$finalMax = $max;
|
560 |
+
extract($this->_generateMinMax($temp));
|
561 |
+
|
562 |
+
$generator = new Math_BigInteger();
|
563 |
+
|
564 |
+
$n = $this->one->copy();
|
565 |
+
if (!empty($partial)) {
|
566 |
+
extract(unserialize($partial));
|
567 |
+
} else {
|
568 |
+
$exponents = $coefficients = $primes = array();
|
569 |
+
$lcm = array(
|
570 |
+
'top' => $this->one->copy(),
|
571 |
+
'bottom' => false
|
572 |
+
);
|
573 |
+
}
|
574 |
+
|
575 |
+
$start = time();
|
576 |
+
$i0 = count($primes) + 1;
|
577 |
+
|
578 |
+
do {
|
579 |
+
for ($i = $i0; $i <= $num_primes; $i++) {
|
580 |
+
if ($timeout !== false) {
|
581 |
+
$timeout-= time() - $start;
|
582 |
+
$start = time();
|
583 |
+
if ($timeout <= 0) {
|
584 |
+
return array(
|
585 |
+
'privatekey' => '',
|
586 |
+
'publickey' => '',
|
587 |
+
'partialkey' => serialize(array(
|
588 |
+
'primes' => $primes,
|
589 |
+
'coefficients' => $coefficients,
|
590 |
+
'lcm' => $lcm,
|
591 |
+
'exponents' => $exponents
|
592 |
+
))
|
593 |
+
);
|
594 |
+
}
|
595 |
+
}
|
596 |
+
|
597 |
+
if ($i == $num_primes) {
|
598 |
+
list($min, $temp) = $absoluteMin->divide($n);
|
599 |
+
if (!$temp->equals($this->zero)) {
|
600 |
+
$min = $min->add($this->one); // ie. ceil()
|
601 |
+
}
|
602 |
+
$primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
|
603 |
+
} else {
|
604 |
+
$primes[$i] = $generator->randomPrime($min, $max, $timeout);
|
605 |
+
}
|
606 |
+
|
607 |
+
if ($primes[$i] === false) { // if we've reached the timeout
|
608 |
+
if (count($primes) > 1) {
|
609 |
+
$partialkey = '';
|
610 |
+
} else {
|
611 |
+
array_pop($primes);
|
612 |
+
$partialkey = serialize(array(
|
613 |
+
'primes' => $primes,
|
614 |
+
'coefficients' => $coefficients,
|
615 |
+
'lcm' => $lcm,
|
616 |
+
'exponents' => $exponents
|
617 |
+
));
|
618 |
+
}
|
619 |
+
|
620 |
+
return array(
|
621 |
+
'privatekey' => '',
|
622 |
+
'publickey' => '',
|
623 |
+
'partialkey' => $partialkey
|
624 |
+
);
|
625 |
+
}
|
626 |
+
|
627 |
+
// the first coefficient is calculated differently from the rest
|
628 |
+
// ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
|
629 |
+
if ($i > 2) {
|
630 |
+
$coefficients[$i] = $n->modInverse($primes[$i]);
|
631 |
+
}
|
632 |
+
|
633 |
+
$n = $n->multiply($primes[$i]);
|
634 |
+
|
635 |
+
$temp = $primes[$i]->subtract($this->one);
|
636 |
+
|
637 |
+
// textbook RSA implementations use Euler's totient function instead of the least common multiple.
|
638 |
+
// see http://en.wikipedia.org/wiki/Euler%27s_totient_function
|
639 |
+
$lcm['top'] = $lcm['top']->multiply($temp);
|
640 |
+
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
|
641 |
+
|
642 |
+
$exponents[$i] = $e->modInverse($temp);
|
643 |
+
}
|
644 |
+
|
645 |
+
list($lcm) = $lcm['top']->divide($lcm['bottom']);
|
646 |
+
$gcd = $lcm->gcd($e);
|
647 |
+
$i0 = 1;
|
648 |
+
} while (!$gcd->equals($this->one));
|
649 |
+
|
650 |
+
$d = $e->modInverse($lcm);
|
651 |
+
|
652 |
+
$coefficients[2] = $primes[2]->modInverse($primes[1]);
|
653 |
+
|
654 |
+
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
|
655 |
+
// RSAPrivateKey ::= SEQUENCE {
|
656 |
+
// version Version,
|
657 |
+
// modulus INTEGER, -- n
|
658 |
+
// publicExponent INTEGER, -- e
|
659 |
+
// privateExponent INTEGER, -- d
|
660 |
+
// prime1 INTEGER, -- p
|
661 |
+
// prime2 INTEGER, -- q
|
662 |
+
// exponent1 INTEGER, -- d mod (p-1)
|
663 |
+
// exponent2 INTEGER, -- d mod (q-1)
|
664 |
+
// coefficient INTEGER, -- (inverse of q) mod p
|
665 |
+
// otherPrimeInfos OtherPrimeInfos OPTIONAL
|
666 |
+
// }
|
667 |
+
|
668 |
+
return array(
|
669 |
+
'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
|
670 |
+
'publickey' => $this->_convertPublicKey($n, $e),
|
671 |
+
'partialkey' => false
|
672 |
+
);
|
673 |
+
}
|
674 |
+
|
675 |
+
/**
|
676 |
+
* Convert a private key to the appropriate format.
|
677 |
+
*
|
678 |
+
* @access private
|
679 |
+
* @see setPrivateKeyFormat()
|
680 |
+
* @param String $RSAPrivateKey
|
681 |
+
* @return String
|
682 |
+
*/
|
683 |
+
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
|
684 |
+
{
|
685 |
+
$num_primes = count($primes);
|
686 |
+
$raw = array(
|
687 |
+
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
688 |
+
'modulus' => $n->toBytes(true),
|
689 |
+
'publicExponent' => $e->toBytes(true),
|
690 |
+
'privateExponent' => $d->toBytes(true),
|
691 |
+
'prime1' => $primes[1]->toBytes(true),
|
692 |
+
'prime2' => $primes[2]->toBytes(true),
|
693 |
+
'exponent1' => $exponents[1]->toBytes(true),
|
694 |
+
'exponent2' => $exponents[2]->toBytes(true),
|
695 |
+
'coefficient' => $coefficients[2]->toBytes(true)
|
696 |
+
);
|
697 |
+
|
698 |
+
// if the format in question does not support multi-prime rsa and multi-prime rsa was used,
|
699 |
+
// call _convertPublicKey() instead.
|
700 |
+
switch ($this->privateKeyFormat) {
|
701 |
+
case CRYPT_RSA_PRIVATE_FORMAT_XML:
|
702 |
+
if ($num_primes != 2) {
|
703 |
+
return false;
|
704 |
+
}
|
705 |
+
return "<RSAKeyValue>\r\n" .
|
706 |
+
' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
|
707 |
+
' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
|
708 |
+
' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
|
709 |
+
' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
|
710 |
+
' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
|
711 |
+
' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
|
712 |
+
' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
|
713 |
+
' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
|
714 |
+
'</RSAKeyValue>';
|
715 |
+
break;
|
716 |
+
case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
|
717 |
+
if ($num_primes != 2) {
|
718 |
+
return false;
|
719 |
+
}
|
720 |
+
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
|
721 |
+
$encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
|
722 |
+
$key.= $encryption;
|
723 |
+
$key.= "\r\nComment: " . $this->comment . "\r\n";
|
724 |
+
$public = pack('Na*Na*Na*',
|
725 |
+
strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
|
726 |
+
);
|
727 |
+
$source = pack('Na*Na*Na*Na*',
|
728 |
+
strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
|
729 |
+
strlen($this->comment), $this->comment, strlen($public), $public
|
730 |
+
);
|
731 |
+
$public = base64_encode($public);
|
732 |
+
$key.= "Public-Lines: " . ((strlen($public) + 32) >> 6) . "\r\n";
|
733 |
+
$key.= chunk_split($public, 64);
|
734 |
+
$private = pack('Na*Na*Na*Na*',
|
735 |
+
strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
|
736 |
+
strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
|
737 |
+
);
|
738 |
+
if (empty($this->password) && !is_string($this->password)) {
|
739 |
+
$source.= pack('Na*', strlen($private), $private);
|
740 |
+
$hashkey = 'putty-private-key-file-mac-key';
|
741 |
+
} else {
|
742 |
+
$private.= crypt_random_string(16 - (strlen($private) & 15));
|
743 |
+
$source.= pack('Na*', strlen($private), $private);
|
744 |
+
if (!class_exists('Crypt_AES')) {
|
745 |
+
require_once('Crypt/AES.php');
|
746 |
+
}
|
747 |
+
$sequence = 0;
|
748 |
+
$symkey = '';
|
749 |
+
while (strlen($symkey) < 32) {
|
750 |
+
$temp = pack('Na*', $sequence++, $this->password);
|
751 |
+
$symkey.= pack('H*', sha1($temp));
|
752 |
+
}
|
753 |
+
$symkey = substr($symkey, 0, 32);
|
754 |
+
$crypto = new Crypt_AES();
|
755 |
+
|
756 |
+
$crypto->setKey($symkey);
|
757 |
+
$crypto->disablePadding();
|
758 |
+
$private = $crypto->encrypt($private);
|
759 |
+
$hashkey = 'putty-private-key-file-mac-key' . $this->password;
|
760 |
+
}
|
761 |
+
|
762 |
+
$private = base64_encode($private);
|
763 |
+
$key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n";
|
764 |
+
$key.= chunk_split($private, 64);
|
765 |
+
if (!class_exists('Crypt_Hash')) {
|
766 |
+
require_once('Crypt/Hash.php');
|
767 |
+
}
|
768 |
+
$hash = new Crypt_Hash('sha1');
|
769 |
+
$hash->setKey(pack('H*', sha1($hashkey)));
|
770 |
+
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
|
771 |
+
|
772 |
+
return $key;
|
773 |
+
default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
|
774 |
+
$components = array();
|
775 |
+
foreach ($raw as $name => $value) {
|
776 |
+
$components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
|
777 |
+
}
|
778 |
+
|
779 |
+
$RSAPrivateKey = implode('', $components);
|
780 |
+
|
781 |
+
if ($num_primes > 2) {
|
782 |
+
$OtherPrimeInfos = '';
|
783 |
+
for ($i = 3; $i <= $num_primes; $i++) {
|
784 |
+
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
785 |
+
//
|
786 |
+
// OtherPrimeInfo ::= SEQUENCE {
|
787 |
+
// prime INTEGER, -- ri
|
788 |
+
// exponent INTEGER, -- di
|
789 |
+
// coefficient INTEGER -- ti
|
790 |
+
// }
|
791 |
+
$OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
792 |
+
$OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
793 |
+
$OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
794 |
+
$OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
795 |
+
}
|
796 |
+
$RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
797 |
+
}
|
798 |
+
|
799 |
+
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
800 |
+
|
801 |
+
if (!empty($this->password) || is_string($this->password)) {
|
802 |
+
$iv = crypt_random_string(8);
|
803 |
+
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
|
804 |
+
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
|
805 |
+
if (!class_exists('Crypt_TripleDES')) {
|
806 |
+
require_once('Crypt/TripleDES.php');
|
807 |
+
}
|
808 |
+
$des = new Crypt_TripleDES();
|
809 |
+
$des->setKey($symkey);
|
810 |
+
$des->setIV($iv);
|
811 |
+
$iv = strtoupper(bin2hex($iv));
|
812 |
+
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
813 |
+
"Proc-Type: 4,ENCRYPTED\r\n" .
|
814 |
+
"DEK-Info: DES-EDE3-CBC,$iv\r\n" .
|
815 |
+
"\r\n" .
|
816 |
+
chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
|
817 |
+
'-----END RSA PRIVATE KEY-----';
|
818 |
+
} else {
|
819 |
+
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
820 |
+
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
821 |
+
'-----END RSA PRIVATE KEY-----';
|
822 |
+
}
|
823 |
+
|
824 |
+
return $RSAPrivateKey;
|
825 |
+
}
|
826 |
+
}
|
827 |
+
|
828 |
+
/**
|
829 |
+
* Convert a public key to the appropriate format
|
830 |
+
*
|
831 |
+
* @access private
|
832 |
+
* @see setPublicKeyFormat()
|
833 |
+
* @param String $RSAPrivateKey
|
834 |
+
* @return String
|
835 |
+
*/
|
836 |
+
function _convertPublicKey($n, $e)
|
837 |
+
{
|
838 |
+
$modulus = $n->toBytes(true);
|
839 |
+
$publicExponent = $e->toBytes(true);
|
840 |
+
|
841 |
+
switch ($this->publicKeyFormat) {
|
842 |
+
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
|
843 |
+
return array('e' => $e->copy(), 'n' => $n->copy());
|
844 |
+
case CRYPT_RSA_PUBLIC_FORMAT_XML:
|
845 |
+
return "<RSAKeyValue>\r\n" .
|
846 |
+
' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
|
847 |
+
' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
|
848 |
+
'</RSAKeyValue>';
|
849 |
+
break;
|
850 |
+
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
|
851 |
+
// from <http://tools.ietf.org/html/rfc4253#page-15>:
|
852 |
+
// string "ssh-rsa"
|
853 |
+
// mpint e
|
854 |
+
// mpint n
|
855 |
+
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
|
856 |
+
$RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
|
857 |
+
|
858 |
+
return $RSAPublicKey;
|
859 |
+
default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
|
860 |
+
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
861 |
+
// RSAPublicKey ::= SEQUENCE {
|
862 |
+
// modulus INTEGER, -- n
|
863 |
+
// publicExponent INTEGER -- e
|
864 |
+
// }
|
865 |
+
$components = array(
|
866 |
+
'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
|
867 |
+
'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
|
868 |
+
);
|
869 |
+
|
870 |
+
$RSAPublicKey = pack('Ca*a*a*',
|
871 |
+
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
872 |
+
$components['modulus'], $components['publicExponent']
|
873 |
+
);
|
874 |
+
|
875 |
+
if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) {
|
876 |
+
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
|
877 |
+
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
|
878 |
+
$RSAPublicKey = chr(0) . $RSAPublicKey;
|
879 |
+
$RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
|
880 |
+
|
881 |
+
$RSAPublicKey = pack('Ca*a*',
|
882 |
+
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
|
883 |
+
);
|
884 |
+
}
|
885 |
+
|
886 |
+
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
|
887 |
+
chunk_split(base64_encode($RSAPublicKey), 64) .
|
888 |
+
'-----END PUBLIC KEY-----';
|
889 |
+
|
890 |
+
return $RSAPublicKey;
|
891 |
+
}
|
892 |
+
}
|
893 |
+
|
894 |
+
/**
|
895 |
+
* Break a public or private key down into its constituant components
|
896 |
+
*
|
897 |
+
* @access private
|
898 |
+
* @see _convertPublicKey()
|
899 |
+
* @see _convertPrivateKey()
|
900 |
+
* @param String $key
|
901 |
+
* @param Integer $type
|
902 |
+
* @return Array
|
903 |
+
*/
|
904 |
+
function _parseKey($key, $type)
|
905 |
+
{
|
906 |
+
if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
|
907 |
+
return false;
|
908 |
+
}
|
909 |
+
|
910 |
+
switch ($type) {
|
911 |
+
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
|
912 |
+
if (!is_array($key)) {
|
913 |
+
return false;
|
914 |
+
}
|
915 |
+
$components = array();
|
916 |
+
switch (true) {
|
917 |
+
case isset($key['e']):
|
918 |
+
$components['publicExponent'] = $key['e']->copy();
|
919 |
+
break;
|
920 |
+
case isset($key['exponent']):
|
921 |
+
$components['publicExponent'] = $key['exponent']->copy();
|
922 |
+
break;
|
923 |
+
case isset($key['publicExponent']):
|
924 |
+
$components['publicExponent'] = $key['publicExponent']->copy();
|
925 |
+
break;
|
926 |
+
case isset($key[0]):
|
927 |
+
$components['publicExponent'] = $key[0]->copy();
|
928 |
+
}
|
929 |
+
switch (true) {
|
930 |
+
case isset($key['n']):
|
931 |
+
$components['modulus'] = $key['n']->copy();
|
932 |
+
break;
|
933 |
+
case isset($key['modulo']):
|
934 |
+
$components['modulus'] = $key['modulo']->copy();
|
935 |
+
break;
|
936 |
+
case isset($key['modulus']):
|
937 |
+
$components['modulus'] = $key['modulus']->copy();
|
938 |
+
break;
|
939 |
+
case isset($key[1]):
|
940 |
+
$components['modulus'] = $key[1]->copy();
|
941 |
+
}
|
942 |
+
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
|
943 |
+
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
|
944 |
+
case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
|
945 |
+
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
|
946 |
+
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
|
947 |
+
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
|
948 |
+
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
|
949 |
+
|
950 |
+
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
|
951 |
+
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
|
952 |
+
|
953 |
+
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
954 |
+
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
955 |
+
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
956 |
+
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
957 |
+
implementation are part of the standard, as well.
|
958 |
+
|
959 |
+
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
960 |
+
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
|
961 |
+
$iv = pack('H*', trim($matches[2]));
|
962 |
+
$symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
|
963 |
+
$symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
|
964 |
+
$ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
|
965 |
+
$ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
|
966 |
+
if ($ciphertext === false) {
|
967 |
+
$ciphertext = $key;
|
968 |
+
}
|
969 |
+
switch ($matches[1]) {
|
970 |
+
case 'AES-256-CBC':
|
971 |
+
if (!class_exists('Crypt_AES')) {
|
972 |
+
require_once('Crypt/AES.php');
|
973 |
+
}
|
974 |
+
$crypto = new Crypt_AES();
|
975 |
+
break;
|
976 |
+
case 'AES-128-CBC':
|
977 |
+
if (!class_exists('Crypt_AES')) {
|
978 |
+
require_once('Crypt/AES.php');
|
979 |
+
}
|
980 |
+
$symkey = substr($symkey, 0, 16);
|
981 |
+
$crypto = new Crypt_AES();
|
982 |
+
break;
|
983 |
+
case 'DES-EDE3-CFB':
|
984 |
+
if (!class_exists('Crypt_TripleDES')) {
|
985 |
+
require_once('Crypt/TripleDES.php');
|
986 |
+
}
|
987 |
+
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
|
988 |
+
break;
|
989 |
+
case 'DES-EDE3-CBC':
|
990 |
+
if (!class_exists('Crypt_TripleDES')) {
|
991 |
+
require_once('Crypt/TripleDES.php');
|
992 |
+
}
|
993 |
+
$symkey = substr($symkey, 0, 24);
|
994 |
+
$crypto = new Crypt_TripleDES();
|
995 |
+
break;
|
996 |
+
case 'DES-CBC':
|
997 |
+
if (!class_exists('Crypt_DES')) {
|
998 |
+
require_once('Crypt/DES.php');
|
999 |
+
}
|
1000 |
+
$crypto = new Crypt_DES();
|
1001 |
+
break;
|
1002 |
+
default:
|
1003 |
+
return false;
|
1004 |
+
}
|
1005 |
+
$crypto->setKey($symkey);
|
1006 |
+
$crypto->setIV($iv);
|
1007 |
+
$decoded = $crypto->decrypt($ciphertext);
|
1008 |
+
} else {
|
1009 |
+
$decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
|
1010 |
+
$decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
|
1011 |
+
}
|
1012 |
+
|
1013 |
+
if ($decoded !== false) {
|
1014 |
+
$key = $decoded;
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
$components = array();
|
1018 |
+
|
1019 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
1020 |
+
return false;
|
1021 |
+
}
|
1022 |
+
if ($this->_decodeLength($key) != strlen($key)) {
|
1023 |
+
return false;
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
$tag = ord($this->_string_shift($key));
|
1027 |
+
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
1028 |
+
|
1029 |
+
0:d=0 hl=4 l= 631 cons: SEQUENCE
|
1030 |
+
4:d=1 hl=2 l= 1 prim: INTEGER :00
|
1031 |
+
7:d=1 hl=2 l= 13 cons: SEQUENCE
|
1032 |
+
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
1033 |
+
20:d=2 hl=2 l= 0 prim: NULL
|
1034 |
+
22:d=1 hl=4 l= 609 prim: OCTET STRING */
|
1035 |
+
|
1036 |
+
if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
|
1037 |
+
$this->_string_shift($key, 3);
|
1038 |
+
$tag = CRYPT_RSA_ASN1_SEQUENCE;
|
1039 |
+
}
|
1040 |
+
|
1041 |
+
if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
|
1042 |
+
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
1043 |
+
|
1044 |
+
0:d=0 hl=4 l= 290 cons: SEQUENCE
|
1045 |
+
4:d=1 hl=2 l= 13 cons: SEQUENCE
|
1046 |
+
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
1047 |
+
17:d=2 hl=2 l= 0 prim: NULL
|
1048 |
+
19:d=1 hl=4 l= 271 prim: BIT STRING */
|
1049 |
+
$this->_string_shift($key, $this->_decodeLength($key));
|
1050 |
+
$tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
|
1051 |
+
$this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
|
1052 |
+
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
|
1053 |
+
// unused bits in the final subsequent octet. The number shall be in the range zero to seven."
|
1054 |
+
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
|
1055 |
+
if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
|
1056 |
+
$this->_string_shift($key);
|
1057 |
+
}
|
1058 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
1059 |
+
return false;
|
1060 |
+
}
|
1061 |
+
if ($this->_decodeLength($key) != strlen($key)) {
|
1062 |
+
return false;
|
1063 |
+
}
|
1064 |
+
$tag = ord($this->_string_shift($key));
|
1065 |
+
}
|
1066 |
+
if ($tag != CRYPT_RSA_ASN1_INTEGER) {
|
1067 |
+
return false;
|
1068 |
+
}
|
1069 |
+
|
1070 |
+
$length = $this->_decodeLength($key);
|
1071 |
+
$temp = $this->_string_shift($key, $length);
|
1072 |
+
if (strlen($temp) != 1 || ord($temp) > 2) {
|
1073 |
+
$components['modulus'] = new Math_BigInteger($temp, 256);
|
1074 |
+
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
|
1075 |
+
$length = $this->_decodeLength($key);
|
1076 |
+
$components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1077 |
+
|
1078 |
+
return $components;
|
1079 |
+
}
|
1080 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
|
1081 |
+
return false;
|
1082 |
+
}
|
1083 |
+
$length = $this->_decodeLength($key);
|
1084 |
+
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1085 |
+
$this->_string_shift($key);
|
1086 |
+
$length = $this->_decodeLength($key);
|
1087 |
+
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1088 |
+
$this->_string_shift($key);
|
1089 |
+
$length = $this->_decodeLength($key);
|
1090 |
+
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1091 |
+
$this->_string_shift($key);
|
1092 |
+
$length = $this->_decodeLength($key);
|
1093 |
+
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
|
1094 |
+
$this->_string_shift($key);
|
1095 |
+
$length = $this->_decodeLength($key);
|
1096 |
+
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1097 |
+
$this->_string_shift($key);
|
1098 |
+
$length = $this->_decodeLength($key);
|
1099 |
+
$components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
|
1100 |
+
$this->_string_shift($key);
|
1101 |
+
$length = $this->_decodeLength($key);
|
1102 |
+
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1103 |
+
$this->_string_shift($key);
|
1104 |
+
$length = $this->_decodeLength($key);
|
1105 |
+
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
|
1106 |
+
|
1107 |
+
if (!empty($key)) {
|
1108 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
1109 |
+
return false;
|
1110 |
+
}
|
1111 |
+
$this->_decodeLength($key);
|
1112 |
+
while (!empty($key)) {
|
1113 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
1114 |
+
return false;
|
1115 |
+
}
|
1116 |
+
$this->_decodeLength($key);
|
1117 |
+
$key = substr($key, 1);
|
1118 |
+
$length = $this->_decodeLength($key);
|
1119 |
+
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1120 |
+
$this->_string_shift($key);
|
1121 |
+
$length = $this->_decodeLength($key);
|
1122 |
+
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1123 |
+
$this->_string_shift($key);
|
1124 |
+
$length = $this->_decodeLength($key);
|
1125 |
+
$components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
|
1126 |
+
}
|
1127 |
+
}
|
1128 |
+
|
1129 |
+
return $components;
|
1130 |
+
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
|
1131 |
+
$parts = explode(' ', $key, 3);
|
1132 |
+
|
1133 |
+
$key = isset($parts[1]) ? base64_decode($parts[1]) : false;
|
1134 |
+
if ($key === false) {
|
1135 |
+
return false;
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
$comment = isset($parts[2]) ? $parts[2] : false;
|
1139 |
+
|
1140 |
+
$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
|
1141 |
+
|
1142 |
+
if (strlen($key) <= 4) {
|
1143 |
+
return false;
|
1144 |
+
}
|
1145 |
+
extract(unpack('Nlength', $this->_string_shift($key, 4)));
|
1146 |
+
$publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
1147 |
+
if (strlen($key) <= 4) {
|
1148 |
+
return false;
|
1149 |
+
}
|
1150 |
+
extract(unpack('Nlength', $this->_string_shift($key, 4)));
|
1151 |
+
$modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
1152 |
+
|
1153 |
+
if ($cleanup && strlen($key)) {
|
1154 |
+
if (strlen($key) <= 4) {
|
1155 |
+
return false;
|
1156 |
+
}
|
1157 |
+
extract(unpack('Nlength', $this->_string_shift($key, 4)));
|
1158 |
+
$realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
1159 |
+
return strlen($key) ? false : array(
|
1160 |
+
'modulus' => $realModulus,
|
1161 |
+
'publicExponent' => $modulus,
|
1162 |
+
'comment' => $comment
|
1163 |
+
);
|
1164 |
+
} else {
|
1165 |
+
return strlen($key) ? false : array(
|
1166 |
+
'modulus' => $modulus,
|
1167 |
+
'publicExponent' => $publicExponent,
|
1168 |
+
'comment' => $comment
|
1169 |
+
);
|
1170 |
+
}
|
1171 |
+
// http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
|
1172 |
+
// http://en.wikipedia.org/wiki/XML_Signature
|
1173 |
+
case CRYPT_RSA_PRIVATE_FORMAT_XML:
|
1174 |
+
case CRYPT_RSA_PUBLIC_FORMAT_XML:
|
1175 |
+
$this->components = array();
|
1176 |
+
|
1177 |
+
$xml = xml_parser_create('UTF-8');
|
1178 |
+
xml_set_object($xml, $this);
|
1179 |
+
xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
|
1180 |
+
xml_set_character_data_handler($xml, '_data_handler');
|
1181 |
+
// add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
|
1182 |
+
if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
|
1183 |
+
return false;
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
|
1187 |
+
// from PuTTY's SSHPUBK.C
|
1188 |
+
case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
|
1189 |
+
$components = array();
|
1190 |
+
$key = preg_split('#\r\n|\r|\n#', $key);
|
1191 |
+
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
|
1192 |
+
if ($type != 'ssh-rsa') {
|
1193 |
+
return false;
|
1194 |
+
}
|
1195 |
+
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
|
1196 |
+
$comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
|
1197 |
+
|
1198 |
+
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
|
1199 |
+
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
|
1200 |
+
$public = substr($public, 11);
|
1201 |
+
extract(unpack('Nlength', $this->_string_shift($public, 4)));
|
1202 |
+
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
|
1203 |
+
extract(unpack('Nlength', $this->_string_shift($public, 4)));
|
1204 |
+
$components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
|
1205 |
+
|
1206 |
+
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
|
1207 |
+
$private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
|
1208 |
+
|
1209 |
+
switch ($encryption) {
|
1210 |
+
case 'aes256-cbc':
|
1211 |
+
if (!class_exists('Crypt_AES')) {
|
1212 |
+
require_once('Crypt/AES.php');
|
1213 |
+
}
|
1214 |
+
$symkey = '';
|
1215 |
+
$sequence = 0;
|
1216 |
+
while (strlen($symkey) < 32) {
|
1217 |
+
$temp = pack('Na*', $sequence++, $this->password);
|
1218 |
+
$symkey.= pack('H*', sha1($temp));
|
1219 |
+
}
|
1220 |
+
$symkey = substr($symkey, 0, 32);
|
1221 |
+
$crypto = new Crypt_AES();
|
1222 |
+
}
|
1223 |
+
|
1224 |
+
if ($encryption != 'none') {
|
1225 |
+
$crypto->setKey($symkey);
|
1226 |
+
$crypto->disablePadding();
|
1227 |
+
$private = $crypto->decrypt($private);
|
1228 |
+
if ($private === false) {
|
1229 |
+
return false;
|
1230 |
+
}
|
1231 |
+
}
|
1232 |
+
|
1233 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1234 |
+
if (strlen($private) < $length) {
|
1235 |
+
return false;
|
1236 |
+
}
|
1237 |
+
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
|
1238 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1239 |
+
if (strlen($private) < $length) {
|
1240 |
+
return false;
|
1241 |
+
}
|
1242 |
+
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
|
1243 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1244 |
+
if (strlen($private) < $length) {
|
1245 |
+
return false;
|
1246 |
+
}
|
1247 |
+
$components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
|
1248 |
+
|
1249 |
+
$temp = $components['primes'][1]->subtract($this->one);
|
1250 |
+
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
|
1251 |
+
$temp = $components['primes'][2]->subtract($this->one);
|
1252 |
+
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
|
1253 |
+
|
1254 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1255 |
+
if (strlen($private) < $length) {
|
1256 |
+
return false;
|
1257 |
+
}
|
1258 |
+
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
|
1259 |
+
|
1260 |
+
return $components;
|
1261 |
+
}
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
/**
|
1265 |
+
* Returns the key size
|
1266 |
+
*
|
1267 |
+
* More specifically, this returns the size of the modulo in bits.
|
1268 |
+
*
|
1269 |
+
* @access public
|
1270 |
+
* @return Integer
|
1271 |
+
*/
|
1272 |
+
function getSize()
|
1273 |
+
{
|
1274 |
+
return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
|
1275 |
+
}
|
1276 |
+
|
1277 |
+
/**
|
1278 |
+
* Start Element Handler
|
1279 |
+
*
|
1280 |
+
* Called by xml_set_element_handler()
|
1281 |
+
*
|
1282 |
+
* @access private
|
1283 |
+
* @param Resource $parser
|
1284 |
+
* @param String $name
|
1285 |
+
* @param Array $attribs
|
1286 |
+
*/
|
1287 |
+
function _start_element_handler($parser, $name, $attribs)
|
1288 |
+
{
|
1289 |
+
//$name = strtoupper($name);
|
1290 |
+
switch ($name) {
|
1291 |
+
case 'MODULUS':
|
1292 |
+
$this->current = &$this->components['modulus'];
|
1293 |
+
break;
|
1294 |
+
case 'EXPONENT':
|
1295 |
+
$this->current = &$this->components['publicExponent'];
|
1296 |
+
break;
|
1297 |
+
case 'P':
|
1298 |
+
$this->current = &$this->components['primes'][1];
|
1299 |
+
break;
|
1300 |
+
case 'Q':
|
1301 |
+
$this->current = &$this->components['primes'][2];
|
1302 |
+
break;
|
1303 |
+
case 'DP':
|
1304 |
+
$this->current = &$this->components['exponents'][1];
|
1305 |
+
break;
|
1306 |
+
case 'DQ':
|
1307 |
+
$this->current = &$this->components['exponents'][2];
|
1308 |
+
break;
|
1309 |
+
case 'INVERSEQ':
|
1310 |
+
$this->current = &$this->components['coefficients'][2];
|
1311 |
+
break;
|
1312 |
+
case 'D':
|
1313 |
+
$this->current = &$this->components['privateExponent'];
|
1314 |
+
break;
|
1315 |
+
default:
|
1316 |
+
unset($this->current);
|
1317 |
+
}
|
1318 |
+
$this->current = '';
|
1319 |
+
}
|
1320 |
+
|
1321 |
+
/**
|
1322 |
+
* Stop Element Handler
|
1323 |
+
*
|
1324 |
+
* Called by xml_set_element_handler()
|
1325 |
+
*
|
1326 |
+
* @access private
|
1327 |
+
* @param Resource $parser
|
1328 |
+
* @param String $name
|
1329 |
+
*/
|
1330 |
+
function _stop_element_handler($parser, $name)
|
1331 |
+
{
|
1332 |
+
//$name = strtoupper($name);
|
1333 |
+
if ($name == 'RSAKEYVALUE') {
|
1334 |
+
return;
|
1335 |
+
}
|
1336 |
+
$this->current = new Math_BigInteger(base64_decode($this->current), 256);
|
1337 |
+
}
|
1338 |
+
|
1339 |
+
/**
|
1340 |
+
* Data Handler
|
1341 |
+
*
|
1342 |
+
* Called by xml_set_character_data_handler()
|
1343 |
+
*
|
1344 |
+
* @access private
|
1345 |
+
* @param Resource $parser
|
1346 |
+
* @param String $data
|
1347 |
+
*/
|
1348 |
+
function _data_handler($parser, $data)
|
1349 |
+
{
|
1350 |
+
if (!isset($this->current) || is_object($this->current)) {
|
1351 |
+
return;
|
1352 |
+
}
|
1353 |
+
$this->current.= trim($data);
|
1354 |
+
}
|
1355 |
+
|
1356 |
+
/**
|
1357 |
+
* Loads a public or private key
|
1358 |
+
*
|
1359 |
+
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
|
1360 |
+
*
|
1361 |
+
* @access public
|
1362 |
+
* @param String $key
|
1363 |
+
* @param Integer $type optional
|
1364 |
+
*/
|
1365 |
+
function loadKey($key, $type = false)
|
1366 |
+
{
|
1367 |
+
if ($type === false) {
|
1368 |
+
$types = array(
|
1369 |
+
CRYPT_RSA_PUBLIC_FORMAT_RAW,
|
1370 |
+
CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
|
1371 |
+
CRYPT_RSA_PRIVATE_FORMAT_XML,
|
1372 |
+
CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
|
1373 |
+
CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
|
1374 |
+
);
|
1375 |
+
foreach ($types as $type) {
|
1376 |
+
$components = $this->_parseKey($key, $type);
|
1377 |
+
if ($components !== false) {
|
1378 |
+
break;
|
1379 |
+
}
|
1380 |
+
}
|
1381 |
+
|
1382 |
+
} else {
|
1383 |
+
$components = $this->_parseKey($key, $type);
|
1384 |
+
}
|
1385 |
+
|
1386 |
+
if ($components === false) {
|
1387 |
+
return false;
|
1388 |
+
}
|
1389 |
+
|
1390 |
+
if (isset($components['comment']) && $components['comment'] !== false) {
|
1391 |
+
$this->comment = $components['comment'];
|
1392 |
+
}
|
1393 |
+
$this->modulus = $components['modulus'];
|
1394 |
+
$this->k = strlen($this->modulus->toBytes());
|
1395 |
+
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
|
1396 |
+
if (isset($components['primes'])) {
|
1397 |
+
$this->primes = $components['primes'];
|
1398 |
+
$this->exponents = $components['exponents'];
|
1399 |
+
$this->coefficients = $components['coefficients'];
|
1400 |
+
$this->publicExponent = $components['publicExponent'];
|
1401 |
+
} else {
|
1402 |
+
$this->primes = array();
|
1403 |
+
$this->exponents = array();
|
1404 |
+
$this->coefficients = array();
|
1405 |
+
$this->publicExponent = false;
|
1406 |
+
}
|
1407 |
+
|
1408 |
+
return true;
|
1409 |
+
}
|
1410 |
+
|
1411 |
+
/**
|
1412 |
+
* Sets the password
|
1413 |
+
*
|
1414 |
+
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
|
1415 |
+
* Or rather, pass in $password such that empty($password) && !is_string($password) is true.
|
1416 |
+
*
|
1417 |
+
* @see createKey()
|
1418 |
+
* @see loadKey()
|
1419 |
+
* @access public
|
1420 |
+
* @param String $password
|
1421 |
+
*/
|
1422 |
+
function setPassword($password = false)
|
1423 |
+
{
|
1424 |
+
$this->password = $password;
|
1425 |
+
}
|
1426 |
+
|
1427 |
+
/**
|
1428 |
+
* Defines the public key
|
1429 |
+
*
|
1430 |
+
* Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
|
1431 |
+
* used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
|
1432 |
+
* message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
|
1433 |
+
* and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
|
1434 |
+
* exponent this won't work unless you manually add the public exponent.
|
1435 |
+
*
|
1436 |
+
* Do note that when a new key is loaded the index will be cleared.
|
1437 |
+
*
|
1438 |
+
* Returns true on success, false on failure
|
1439 |
+
*
|
1440 |
+
* @see getPublicKey()
|
1441 |
+
* @access public
|
1442 |
+
* @param String $key optional
|
1443 |
+
* @param Integer $type optional
|
1444 |
+
* @return Boolean
|
1445 |
+
*/
|
1446 |
+
function setPublicKey($key = false, $type = false)
|
1447 |
+
{
|
1448 |
+
if ($key === false && !empty($this->modulus)) {
|
1449 |
+
$this->publicExponent = $this->exponent;
|
1450 |
+
return true;
|
1451 |
+
}
|
1452 |
+
|
1453 |
+
if ($type === false) {
|
1454 |
+
$types = array(
|
1455 |
+
CRYPT_RSA_PUBLIC_FORMAT_RAW,
|
1456 |
+
CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
|
1457 |
+
CRYPT_RSA_PUBLIC_FORMAT_XML,
|
1458 |
+
CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
|
1459 |
+
);
|
1460 |
+
foreach ($types as $type) {
|
1461 |
+
$components = $this->_parseKey($key, $type);
|
1462 |
+
if ($components !== false) {
|
1463 |
+
break;
|
1464 |
+
}
|
1465 |
+
}
|
1466 |
+
} else {
|
1467 |
+
$components = $this->_parseKey($key, $type);
|
1468 |
+
}
|
1469 |
+
|
1470 |
+
if ($components === false) {
|
1471 |
+
return false;
|
1472 |
+
}
|
1473 |
+
|
1474 |
+
if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
|
1475 |
+
$this->modulus = $components['modulus'];
|
1476 |
+
$this->exponent = $this->publicExponent = $components['publicExponent'];
|
1477 |
+
return true;
|
1478 |
+
}
|
1479 |
+
|
1480 |
+
$this->publicExponent = $components['publicExponent'];
|
1481 |
+
|
1482 |
+
return true;
|
1483 |
+
}
|
1484 |
+
|
1485 |
+
/**
|
1486 |
+
* Returns the public key
|
1487 |
+
*
|
1488 |
+
* The public key is only returned under two circumstances - if the private key had the public key embedded within it
|
1489 |
+
* or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
|
1490 |
+
* function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
|
1491 |
+
*
|
1492 |
+
* @see getPublicKey()
|
1493 |
+
* @access public
|
1494 |
+
* @param String $key
|
1495 |
+
* @param Integer $type optional
|
1496 |
+
*/
|
1497 |
+
function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
1498 |
+
{
|
1499 |
+
if (empty($this->modulus) || empty($this->publicExponent)) {
|
1500 |
+
return false;
|
1501 |
+
}
|
1502 |
+
|
1503 |
+
$oldFormat = $this->publicKeyFormat;
|
1504 |
+
$this->publicKeyFormat = $type;
|
1505 |
+
$temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
|
1506 |
+
$this->publicKeyFormat = $oldFormat;
|
1507 |
+
return $temp;
|
1508 |
+
}
|
1509 |
+
|
1510 |
+
/**
|
1511 |
+
* Returns the private key
|
1512 |
+
*
|
1513 |
+
* The private key is only returned if the currently loaded key contains the constituent prime numbers.
|
1514 |
+
*
|
1515 |
+
* @see getPublicKey()
|
1516 |
+
* @access public
|
1517 |
+
* @param String $key
|
1518 |
+
* @param Integer $type optional
|
1519 |
+
*/
|
1520 |
+
function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
1521 |
+
{
|
1522 |
+
if (empty($this->primes)) {
|
1523 |
+
return false;
|
1524 |
+
}
|
1525 |
+
|
1526 |
+
$oldFormat = $this->privateKeyFormat;
|
1527 |
+
$this->privateKeyFormat = $type;
|
1528 |
+
$temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
|
1529 |
+
$this->privateKeyFormat = $oldFormat;
|
1530 |
+
return $temp;
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
/**
|
1534 |
+
* Returns a minimalistic private key
|
1535 |
+
*
|
1536 |
+
* Returns the private key without the prime number constituants. Structurally identical to a public key that
|
1537 |
+
* hasn't been set as the public key
|
1538 |
+
*
|
1539 |
+
* @see getPrivateKey()
|
1540 |
+
* @access private
|
1541 |
+
* @param String $key
|
1542 |
+
* @param Integer $type optional
|
1543 |
+
*/
|
1544 |
+
function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
1545 |
+
{
|
1546 |
+
if (empty($this->modulus) || empty($this->exponent)) {
|
1547 |
+
return false;
|
1548 |
+
}
|
1549 |
+
|
1550 |
+
$oldFormat = $this->publicKeyFormat;
|
1551 |
+
$this->publicKeyFormat = $mode;
|
1552 |
+
$temp = $this->_convertPublicKey($this->modulus, $this->exponent);
|
1553 |
+
$this->publicKeyFormat = $oldFormat;
|
1554 |
+
return $temp;
|
1555 |
+
}
|
1556 |
+
|
1557 |
+
/**
|
1558 |
+
* __toString() magic method
|
1559 |
+
*
|
1560 |
+
* @access public
|
1561 |
+
*/
|
1562 |
+
function __toString()
|
1563 |
+
{
|
1564 |
+
$key = $this->getPrivateKey($this->privateKeyFormat);
|
1565 |
+
if ($key !== false) {
|
1566 |
+
return $key;
|
1567 |
+
}
|
1568 |
+
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
|
1569 |
+
return $key !== false ? $key : '';
|
1570 |
+
}
|
1571 |
+
|
1572 |
+
/**
|
1573 |
+
* Generates the smallest and largest numbers requiring $bits bits
|
1574 |
+
*
|
1575 |
+
* @access private
|
1576 |
+
* @param Integer $bits
|
1577 |
+
* @return Array
|
1578 |
+
*/
|
1579 |
+
function _generateMinMax($bits)
|
1580 |
+
{
|
1581 |
+
$bytes = $bits >> 3;
|
1582 |
+
$min = str_repeat(chr(0), $bytes);
|
1583 |
+
$max = str_repeat(chr(0xFF), $bytes);
|
1584 |
+
$msb = $bits & 7;
|
1585 |
+
if ($msb) {
|
1586 |
+
$min = chr(1 << ($msb - 1)) . $min;
|
1587 |
+
$max = chr((1 << $msb) - 1) . $max;
|
1588 |
+
} else {
|
1589 |
+
$min[0] = chr(0x80);
|
1590 |
+
}
|
1591 |
+
|
1592 |
+
return array(
|
1593 |
+
'min' => new Math_BigInteger($min, 256),
|
1594 |
+
'max' => new Math_BigInteger($max, 256)
|
1595 |
+
);
|
1596 |
+
}
|
1597 |
+
|
1598 |
+
/**
|
1599 |
+
* DER-decode the length
|
1600 |
+
*
|
1601 |
+
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
1602 |
+
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
1603 |
+
*
|
1604 |
+
* @access private
|
1605 |
+
* @param String $string
|
1606 |
+
* @return Integer
|
1607 |
+
*/
|
1608 |
+
function _decodeLength(&$string)
|
1609 |
+
{
|
1610 |
+
$length = ord($this->_string_shift($string));
|
1611 |
+
if ( $length & 0x80 ) { // definite length, long form
|
1612 |
+
$length&= 0x7F;
|
1613 |
+
$temp = $this->_string_shift($string, $length);
|
1614 |
+
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
|
1615 |
+
}
|
1616 |
+
return $length;
|
1617 |
+
}
|
1618 |
+
|
1619 |
+
/**
|
1620 |
+
* DER-encode the length
|
1621 |
+
*
|
1622 |
+
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
1623 |
+
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
1624 |
+
*
|
1625 |
+
* @access private
|
1626 |
+
* @param Integer $length
|
1627 |
+
* @return String
|
1628 |
+
*/
|
1629 |
+
function _encodeLength($length)
|
1630 |
+
{
|
1631 |
+
if ($length <= 0x7F) {
|
1632 |
+
return chr($length);
|
1633 |
+
}
|
1634 |
+
|
1635 |
+
$temp = ltrim(pack('N', $length), chr(0));
|
1636 |
+
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
1637 |
+
}
|
1638 |
+
|
1639 |
+
/**
|
1640 |
+
* String Shift
|
1641 |
+
*
|
1642 |
+
* Inspired by array_shift
|
1643 |
+
*
|
1644 |
+
* @param String $string
|
1645 |
+
* @param optional Integer $index
|
1646 |
+
* @return String
|
1647 |
+
* @access private
|
1648 |
+
*/
|
1649 |
+
function _string_shift(&$string, $index = 1)
|
1650 |
+
{
|
1651 |
+
$substr = substr($string, 0, $index);
|
1652 |
+
$string = substr($string, $index);
|
1653 |
+
return $substr;
|
1654 |
+
}
|
1655 |
+
|
1656 |
+
/**
|
1657 |
+
* Determines the private key format
|
1658 |
+
*
|
1659 |
+
* @see createKey()
|
1660 |
+
* @access public
|
1661 |
+
* @param Integer $format
|
1662 |
+
*/
|
1663 |
+
function setPrivateKeyFormat($format)
|
1664 |
+
{
|
1665 |
+
$this->privateKeyFormat = $format;
|
1666 |
+
}
|
1667 |
+
|
1668 |
+
/**
|
1669 |
+
* Determines the public key format
|
1670 |
+
*
|
1671 |
+
* @see createKey()
|
1672 |
+
* @access public
|
1673 |
+
* @param Integer $format
|
1674 |
+
*/
|
1675 |
+
function setPublicKeyFormat($format)
|
1676 |
+
{
|
1677 |
+
$this->publicKeyFormat = $format;
|
1678 |
+
}
|
1679 |
+
|
1680 |
+
/**
|
1681 |
+
* Determines which hashing function should be used
|
1682 |
+
*
|
1683 |
+
* Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
|
1684 |
+
* decryption. If $hash isn't supported, sha1 is used.
|
1685 |
+
*
|
1686 |
+
* @access public
|
1687 |
+
* @param String $hash
|
1688 |
+
*/
|
1689 |
+
function setHash($hash)
|
1690 |
+
{
|
1691 |
+
// Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
|
1692 |
+
switch ($hash) {
|
1693 |
+
case 'md2':
|
1694 |
+
case 'md5':
|
1695 |
+
case 'sha1':
|
1696 |
+
case 'sha256':
|
1697 |
+
case 'sha384':
|
1698 |
+
case 'sha512':
|
1699 |
+
$this->hash = new Crypt_Hash($hash);
|
1700 |
+
$this->hashName = $hash;
|
1701 |
+
break;
|
1702 |
+
default:
|
1703 |
+
$this->hash = new Crypt_Hash('sha1');
|
1704 |
+
$this->hashName = 'sha1';
|
1705 |
+
}
|
1706 |
+
$this->hLen = $this->hash->getLength();
|
1707 |
+
}
|
1708 |
+
|
1709 |
+
/**
|
1710 |
+
* Determines which hashing function should be used for the mask generation function
|
1711 |
+
*
|
1712 |
+
* The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
|
1713 |
+
* best if Hash and MGFHash are set to the same thing this is not a requirement.
|
1714 |
+
*
|
1715 |
+
* @access public
|
1716 |
+
* @param String $hash
|
1717 |
+
*/
|
1718 |
+
function setMGFHash($hash)
|
1719 |
+
{
|
1720 |
+
// Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
|
1721 |
+
switch ($hash) {
|
1722 |
+
case 'md2':
|
1723 |
+
case 'md5':
|
1724 |
+
case 'sha1':
|
1725 |
+
case 'sha256':
|
1726 |
+
case 'sha384':
|
1727 |
+
case 'sha512':
|
1728 |
+
$this->mgfHash = new Crypt_Hash($hash);
|
1729 |
+
break;
|
1730 |
+
default:
|
1731 |
+
$this->mgfHash = new Crypt_Hash('sha1');
|
1732 |
+
}
|
1733 |
+
$this->mgfHLen = $this->mgfHash->getLength();
|
1734 |
+
}
|
1735 |
+
|
1736 |
+
/**
|
1737 |
+
* Determines the salt length
|
1738 |
+
*
|
1739 |
+
* To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
|
1740 |
+
*
|
1741 |
+
* Typical salt lengths in octets are hLen (the length of the output
|
1742 |
+
* of the hash function Hash) and 0.
|
1743 |
+
*
|
1744 |
+
* @access public
|
1745 |
+
* @param Integer $format
|
1746 |
+
*/
|
1747 |
+
function setSaltLength($sLen)
|
1748 |
+
{
|
1749 |
+
$this->sLen = $sLen;
|
1750 |
+
}
|
1751 |
+
|
1752 |
+
/**
|
1753 |
+
* Integer-to-Octet-String primitive
|
1754 |
+
*
|
1755 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
|
1756 |
+
*
|
1757 |
+
* @access private
|
1758 |
+
* @param Math_BigInteger $x
|
1759 |
+
* @param Integer $xLen
|
1760 |
+
* @return String
|
1761 |
+
*/
|
1762 |
+
function _i2osp($x, $xLen)
|
1763 |
+
{
|
1764 |
+
$x = $x->toBytes();
|
1765 |
+
if (strlen($x) > $xLen) {
|
1766 |
+
user_error('Integer too large');
|
1767 |
+
return false;
|
1768 |
+
}
|
1769 |
+
return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
|
1770 |
+
}
|
1771 |
+
|
1772 |
+
/**
|
1773 |
+
* Octet-String-to-Integer primitive
|
1774 |
+
*
|
1775 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
|
1776 |
+
*
|
1777 |
+
* @access private
|
1778 |
+
* @param String $x
|
1779 |
+
* @return Math_BigInteger
|
1780 |
+
*/
|
1781 |
+
function _os2ip($x)
|
1782 |
+
{
|
1783 |
+
return new Math_BigInteger($x, 256);
|
1784 |
+
}
|
1785 |
+
|
1786 |
+
/**
|
1787 |
+
* Exponentiate with or without Chinese Remainder Theorem
|
1788 |
+
*
|
1789 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
|
1790 |
+
*
|
1791 |
+
* @access private
|
1792 |
+
* @param Math_BigInteger $x
|
1793 |
+
* @return Math_BigInteger
|
1794 |
+
*/
|
1795 |
+
function _exponentiate($x)
|
1796 |
+
{
|
1797 |
+
if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
|
1798 |
+
return $x->modPow($this->exponent, $this->modulus);
|
1799 |
+
}
|
1800 |
+
|
1801 |
+
$num_primes = count($this->primes);
|
1802 |
+
|
1803 |
+
if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
|
1804 |
+
$m_i = array(
|
1805 |
+
1 => $x->modPow($this->exponents[1], $this->primes[1]),
|
1806 |
+
2 => $x->modPow($this->exponents[2], $this->primes[2])
|
1807 |
+
);
|
1808 |
+
$h = $m_i[1]->subtract($m_i[2]);
|
1809 |
+
$h = $h->multiply($this->coefficients[2]);
|
1810 |
+
list(, $h) = $h->divide($this->primes[1]);
|
1811 |
+
$m = $m_i[2]->add($h->multiply($this->primes[2]));
|
1812 |
+
|
1813 |
+
$r = $this->primes[1];
|
1814 |
+
for ($i = 3; $i <= $num_primes; $i++) {
|
1815 |
+
$m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
|
1816 |
+
|
1817 |
+
$r = $r->multiply($this->primes[$i - 1]);
|
1818 |
+
|
1819 |
+
$h = $m_i->subtract($m);
|
1820 |
+
$h = $h->multiply($this->coefficients[$i]);
|
1821 |
+
list(, $h) = $h->divide($this->primes[$i]);
|
1822 |
+
|
1823 |
+
$m = $m->add($r->multiply($h));
|
1824 |
+
}
|
1825 |
+
} else {
|
1826 |
+
$smallest = $this->primes[1];
|
1827 |
+
for ($i = 2; $i <= $num_primes; $i++) {
|
1828 |
+
if ($smallest->compare($this->primes[$i]) > 0) {
|
1829 |
+
$smallest = $this->primes[$i];
|
1830 |
+
}
|
1831 |
+
}
|
1832 |
+
|
1833 |
+
$one = new Math_BigInteger(1);
|
1834 |
+
|
1835 |
+
$r = $one->random($one, $smallest->subtract($one));
|
1836 |
+
|
1837 |
+
$m_i = array(
|
1838 |
+
1 => $this->_blind($x, $r, 1),
|
1839 |
+
2 => $this->_blind($x, $r, 2)
|
1840 |
+
);
|
1841 |
+
$h = $m_i[1]->subtract($m_i[2]);
|
1842 |
+
$h = $h->multiply($this->coefficients[2]);
|
1843 |
+
list(, $h) = $h->divide($this->primes[1]);
|
1844 |
+
$m = $m_i[2]->add($h->multiply($this->primes[2]));
|
1845 |
+
|
1846 |
+
$r = $this->primes[1];
|
1847 |
+
for ($i = 3; $i <= $num_primes; $i++) {
|
1848 |
+
$m_i = $this->_blind($x, $r, $i);
|
1849 |
+
|
1850 |
+
$r = $r->multiply($this->primes[$i - 1]);
|
1851 |
+
|
1852 |
+
$h = $m_i->subtract($m);
|
1853 |
+
$h = $h->multiply($this->coefficients[$i]);
|
1854 |
+
list(, $h) = $h->divide($this->primes[$i]);
|
1855 |
+
|
1856 |
+
$m = $m->add($r->multiply($h));
|
1857 |
+
}
|
1858 |
+
}
|
1859 |
+
|
1860 |
+
return $m;
|
1861 |
+
}
|
1862 |
+
|
1863 |
+
/**
|
1864 |
+
* Performs RSA Blinding
|
1865 |
+
*
|
1866 |
+
* Protects against timing attacks by employing RSA Blinding.
|
1867 |
+
* Returns $x->modPow($this->exponents[$i], $this->primes[$i])
|
1868 |
+
*
|
1869 |
+
* @access private
|
1870 |
+
* @param Math_BigInteger $x
|
1871 |
+
* @param Math_BigInteger $r
|
1872 |
+
* @param Integer $i
|
1873 |
+
* @return Math_BigInteger
|
1874 |
+
*/
|
1875 |
+
function _blind($x, $r, $i)
|
1876 |
+
{
|
1877 |
+
$x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
|
1878 |
+
$x = $x->modPow($this->exponents[$i], $this->primes[$i]);
|
1879 |
+
|
1880 |
+
$r = $r->modInverse($this->primes[$i]);
|
1881 |
+
$x = $x->multiply($r);
|
1882 |
+
list(, $x) = $x->divide($this->primes[$i]);
|
1883 |
+
|
1884 |
+
return $x;
|
1885 |
+
}
|
1886 |
+
|
1887 |
+
/**
|
1888 |
+
* Performs blinded RSA equality testing
|
1889 |
+
*
|
1890 |
+
* Protects against a particular type of timing attack described.
|
1891 |
+
*
|
1892 |
+
* See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
|
1893 |
+
*
|
1894 |
+
* Thanks for the heads up singpolyma!
|
1895 |
+
*
|
1896 |
+
* @access private
|
1897 |
+
* @param String $x
|
1898 |
+
* @param String $y
|
1899 |
+
* @return Boolean
|
1900 |
+
*/
|
1901 |
+
function _equals($x, $y)
|
1902 |
+
{
|
1903 |
+
if (strlen($x) != strlen($y)) {
|
1904 |
+
return false;
|
1905 |
+
}
|
1906 |
+
|
1907 |
+
$result = 0;
|
1908 |
+
for ($i = 0; $i < strlen($x); $i++) {
|
1909 |
+
$result |= ord($x[$i]) ^ ord($y[$i]);
|
1910 |
+
}
|
1911 |
+
|
1912 |
+
return $result == 0;
|
1913 |
+
}
|
1914 |
+
|
1915 |
+
/**
|
1916 |
+
* RSAEP
|
1917 |
+
*
|
1918 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
|
1919 |
+
*
|
1920 |
+
* @access private
|
1921 |
+
* @param Math_BigInteger $m
|
1922 |
+
* @return Math_BigInteger
|
1923 |
+
*/
|
1924 |
+
function _rsaep($m)
|
1925 |
+
{
|
1926 |
+
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
|
1927 |
+
user_error('Message representative out of range');
|
1928 |
+
return false;
|
1929 |
+
}
|
1930 |
+
return $this->_exponentiate($m);
|
1931 |
+
}
|
1932 |
+
|
1933 |
+
/**
|
1934 |
+
* RSADP
|
1935 |
+
*
|
1936 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
|
1937 |
+
*
|
1938 |
+
* @access private
|
1939 |
+
* @param Math_BigInteger $c
|
1940 |
+
* @return Math_BigInteger
|
1941 |
+
*/
|
1942 |
+
function _rsadp($c)
|
1943 |
+
{
|
1944 |
+
if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
|
1945 |
+
user_error('Ciphertext representative out of range');
|
1946 |
+
return false;
|
1947 |
+
}
|
1948 |
+
return $this->_exponentiate($c);
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
/**
|
1952 |
+
* RSASP1
|
1953 |
+
*
|
1954 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
|
1955 |
+
*
|
1956 |
+
* @access private
|
1957 |
+
* @param Math_BigInteger $m
|
1958 |
+
* @return Math_BigInteger
|
1959 |
+
*/
|
1960 |
+
function _rsasp1($m)
|
1961 |
+
{
|
1962 |
+
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
|
1963 |
+
user_error('Message representative out of range');
|
1964 |
+
return false;
|
1965 |
+
}
|
1966 |
+
return $this->_exponentiate($m);
|
1967 |
+
}
|
1968 |
+
|
1969 |
+
/**
|
1970 |
+
* RSAVP1
|
1971 |
+
*
|
1972 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
|
1973 |
+
*
|
1974 |
+
* @access private
|
1975 |
+
* @param Math_BigInteger $s
|
1976 |
+
* @return Math_BigInteger
|
1977 |
+
*/
|
1978 |
+
function _rsavp1($s)
|
1979 |
+
{
|
1980 |
+
if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
|
1981 |
+
user_error('Signature representative out of range');
|
1982 |
+
return false;
|
1983 |
+
}
|
1984 |
+
return $this->_exponentiate($s);
|
1985 |
+
}
|
1986 |
+
|
1987 |
+
/**
|
1988 |
+
* MGF1
|
1989 |
+
*
|
1990 |
+
* See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
|
1991 |
+
*
|
1992 |
+
* @access private
|
1993 |
+
* @param String $mgfSeed
|
1994 |
+
* @param Integer $mgfLen
|
1995 |
+
* @return String
|
1996 |
+
*/
|
1997 |
+
function _mgf1($mgfSeed, $maskLen)
|
1998 |
+
{
|
1999 |
+
// if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
|
2000 |
+
|
2001 |
+
$t = '';
|
2002 |
+
$count = ceil($maskLen / $this->mgfHLen);
|
2003 |
+
for ($i = 0; $i < $count; $i++) {
|
2004 |
+
$c = pack('N', $i);
|
2005 |
+
$t.= $this->mgfHash->hash($mgfSeed . $c);
|
2006 |
+
}
|
2007 |
+
|
2008 |
+
return substr($t, 0, $maskLen);
|
2009 |
+
}
|
2010 |
+
|
2011 |
+
/**
|
2012 |
+
* RSAES-OAEP-ENCRYPT
|
2013 |
+
*
|
2014 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
|
2015 |
+
* {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
|
2016 |
+
*
|
2017 |
+
* @access private
|
2018 |
+
* @param String $m
|
2019 |
+
* @param String $l
|
2020 |
+
* @return String
|
2021 |
+
*/
|
2022 |
+
function _rsaes_oaep_encrypt($m, $l = '')
|
2023 |
+
{
|
2024 |
+
$mLen = strlen($m);
|
2025 |
+
|
2026 |
+
// Length checking
|
2027 |
+
|
2028 |
+
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
2029 |
+
// be output.
|
2030 |
+
|
2031 |
+
if ($mLen > $this->k - 2 * $this->hLen - 2) {
|
2032 |
+
user_error('Message too long');
|
2033 |
+
return false;
|
2034 |
+
}
|
2035 |
+
|
2036 |
+
// EME-OAEP encoding
|
2037 |
+
|
2038 |
+
$lHash = $this->hash->hash($l);
|
2039 |
+
$ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
|
2040 |
+
$db = $lHash . $ps . chr(1) . $m;
|
2041 |
+
$seed = crypt_random_string($this->hLen);
|
2042 |
+
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
|
2043 |
+
$maskedDB = $db ^ $dbMask;
|
2044 |
+
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
|
2045 |
+
$maskedSeed = $seed ^ $seedMask;
|
2046 |
+
$em = chr(0) . $maskedSeed . $maskedDB;
|
2047 |
+
|
2048 |
+
// RSA encryption
|
2049 |
+
|
2050 |
+
$m = $this->_os2ip($em);
|
2051 |
+
$c = $this->_rsaep($m);
|
2052 |
+
$c = $this->_i2osp($c, $this->k);
|
2053 |
+
|
2054 |
+
// Output the ciphertext C
|
2055 |
+
|
2056 |
+
return $c;
|
2057 |
+
}
|
2058 |
+
|
2059 |
+
/**
|
2060 |
+
* RSAES-OAEP-DECRYPT
|
2061 |
+
*
|
2062 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
|
2063 |
+
* messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
|
2064 |
+
*
|
2065 |
+
* Note. Care must be taken to ensure that an opponent cannot
|
2066 |
+
* distinguish the different error conditions in Step 3.g, whether by
|
2067 |
+
* error message or timing, or, more generally, learn partial
|
2068 |
+
* information about the encoded message EM. Otherwise an opponent may
|
2069 |
+
* be able to obtain useful information about the decryption of the
|
2070 |
+
* ciphertext C, leading to a chosen-ciphertext attack such as the one
|
2071 |
+
* observed by Manger [36].
|
2072 |
+
*
|
2073 |
+
* As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
|
2074 |
+
*
|
2075 |
+
* Both the encryption and the decryption operations of RSAES-OAEP take
|
2076 |
+
* the value of a label L as input. In this version of PKCS #1, L is
|
2077 |
+
* the empty string; other uses of the label are outside the scope of
|
2078 |
+
* this document.
|
2079 |
+
*
|
2080 |
+
* @access private
|
2081 |
+
* @param String $c
|
2082 |
+
* @param String $l
|
2083 |
+
* @return String
|
2084 |
+
*/
|
2085 |
+
function _rsaes_oaep_decrypt($c, $l = '')
|
2086 |
+
{
|
2087 |
+
// Length checking
|
2088 |
+
|
2089 |
+
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
2090 |
+
// be output.
|
2091 |
+
|
2092 |
+
if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
|
2093 |
+
user_error('Decryption error');
|
2094 |
+
return false;
|
2095 |
+
}
|
2096 |
+
|
2097 |
+
// RSA decryption
|
2098 |
+
|
2099 |
+
$c = $this->_os2ip($c);
|
2100 |
+
$m = $this->_rsadp($c);
|
2101 |
+
if ($m === false) {
|
2102 |
+
user_error('Decryption error');
|
2103 |
+
return false;
|
2104 |
+
}
|
2105 |
+
$em = $this->_i2osp($m, $this->k);
|
2106 |
+
|
2107 |
+
// EME-OAEP decoding
|
2108 |
+
|
2109 |
+
$lHash = $this->hash->hash($l);
|
2110 |
+
$y = ord($em[0]);
|
2111 |
+
$maskedSeed = substr($em, 1, $this->hLen);
|
2112 |
+
$maskedDB = substr($em, $this->hLen + 1);
|
2113 |
+
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
|
2114 |
+
$seed = $maskedSeed ^ $seedMask;
|
2115 |
+
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
|
2116 |
+
$db = $maskedDB ^ $dbMask;
|
2117 |
+
$lHash2 = substr($db, 0, $this->hLen);
|
2118 |
+
$m = substr($db, $this->hLen);
|
2119 |
+
if ($lHash != $lHash2) {
|
2120 |
+
user_error('Decryption error');
|
2121 |
+
return false;
|
2122 |
+
}
|
2123 |
+
$m = ltrim($m, chr(0));
|
2124 |
+
if (ord($m[0]) != 1) {
|
2125 |
+
user_error('Decryption error');
|
2126 |
+
return false;
|
2127 |
+
}
|
2128 |
+
|
2129 |
+
// Output the message M
|
2130 |
+
|
2131 |
+
return substr($m, 1);
|
2132 |
+
}
|
2133 |
+
|
2134 |
+
/**
|
2135 |
+
* RSAES-PKCS1-V1_5-ENCRYPT
|
2136 |
+
*
|
2137 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
|
2138 |
+
*
|
2139 |
+
* @access private
|
2140 |
+
* @param String $m
|
2141 |
+
* @return String
|
2142 |
+
*/
|
2143 |
+
function _rsaes_pkcs1_v1_5_encrypt($m)
|
2144 |
+
{
|
2145 |
+
$mLen = strlen($m);
|
2146 |
+
|
2147 |
+
// Length checking
|
2148 |
+
|
2149 |
+
if ($mLen > $this->k - 11) {
|
2150 |
+
user_error('Message too long');
|
2151 |
+
return false;
|
2152 |
+
}
|
2153 |
+
|
2154 |
+
// EME-PKCS1-v1_5 encoding
|
2155 |
+
|
2156 |
+
$psLen = $this->k - $mLen - 3;
|
2157 |
+
$ps = '';
|
2158 |
+
while (strlen($ps) != $psLen) {
|
2159 |
+
$temp = crypt_random_string($psLen - strlen($ps));
|
2160 |
+
$temp = str_replace("\x00", '', $temp);
|
2161 |
+
$ps.= $temp;
|
2162 |
+
}
|
2163 |
+
$type = 2;
|
2164 |
+
// see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
|
2165 |
+
if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
|
2166 |
+
$type = 1;
|
2167 |
+
// "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
|
2168 |
+
$ps = str_repeat("\xFF", $psLen);
|
2169 |
+
}
|
2170 |
+
$em = chr(0) . chr($type) . $ps . chr(0) . $m;
|
2171 |
+
|
2172 |
+
// RSA encryption
|
2173 |
+
$m = $this->_os2ip($em);
|
2174 |
+
$c = $this->_rsaep($m);
|
2175 |
+
$c = $this->_i2osp($c, $this->k);
|
2176 |
+
|
2177 |
+
// Output the ciphertext C
|
2178 |
+
|
2179 |
+
return $c;
|
2180 |
+
}
|
2181 |
+
|
2182 |
+
/**
|
2183 |
+
* RSAES-PKCS1-V1_5-DECRYPT
|
2184 |
+
*
|
2185 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
|
2186 |
+
*
|
2187 |
+
* For compatability purposes, this function departs slightly from the description given in RFC3447.
|
2188 |
+
* The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
|
2189 |
+
* private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
|
2190 |
+
* public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
|
2191 |
+
* to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the
|
2192 |
+
* second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
|
2193 |
+
*
|
2194 |
+
* As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
|
2195 |
+
* with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
|
2196 |
+
* not private key encrypted ciphertext's.
|
2197 |
+
*
|
2198 |
+
* @access private
|
2199 |
+
* @param String $c
|
2200 |
+
* @return String
|
2201 |
+
*/
|
2202 |
+
function _rsaes_pkcs1_v1_5_decrypt($c)
|
2203 |
+
{
|
2204 |
+
// Length checking
|
2205 |
+
|
2206 |
+
if (strlen($c) != $this->k) { // or if k < 11
|
2207 |
+
user_error('Decryption error');
|
2208 |
+
return false;
|
2209 |
+
}
|
2210 |
+
|
2211 |
+
// RSA decryption
|
2212 |
+
|
2213 |
+
$c = $this->_os2ip($c);
|
2214 |
+
$m = $this->_rsadp($c);
|
2215 |
+
|
2216 |
+
if ($m === false) {
|
2217 |
+
user_error('Decryption error');
|
2218 |
+
return false;
|
2219 |
+
}
|
2220 |
+
$em = $this->_i2osp($m, $this->k);
|
2221 |
+
|
2222 |
+
// EME-PKCS1-v1_5 decoding
|
2223 |
+
|
2224 |
+
if (ord($em[0]) != 0 || ord($em[1]) > 2) {
|
2225 |
+
user_error('Decryption error');
|
2226 |
+
return false;
|
2227 |
+
}
|
2228 |
+
|
2229 |
+
$ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
|
2230 |
+
$m = substr($em, strlen($ps) + 3);
|
2231 |
+
|
2232 |
+
if (strlen($ps) < 8) {
|
2233 |
+
user_error('Decryption error');
|
2234 |
+
return false;
|
2235 |
+
}
|
2236 |
+
|
2237 |
+
// Output M
|
2238 |
+
|
2239 |
+
return $m;
|
2240 |
+
}
|
2241 |
+
|
2242 |
+
/**
|
2243 |
+
* EMSA-PSS-ENCODE
|
2244 |
+
*
|
2245 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
|
2246 |
+
*
|
2247 |
+
* @access private
|
2248 |
+
* @param String $m
|
2249 |
+
* @param Integer $emBits
|
2250 |
+
*/
|
2251 |
+
function _emsa_pss_encode($m, $emBits)
|
2252 |
+
{
|
2253 |
+
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
2254 |
+
// be output.
|
2255 |
+
|
2256 |
+
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
|
2257 |
+
$sLen = $this->sLen == false ? $this->hLen : $this->sLen;
|
2258 |
+
|
2259 |
+
$mHash = $this->hash->hash($m);
|
2260 |
+
if ($emLen < $this->hLen + $sLen + 2) {
|
2261 |
+
user_error('Encoding error');
|
2262 |
+
return false;
|
2263 |
+
}
|
2264 |
+
|
2265 |
+
$salt = crypt_random_string($sLen);
|
2266 |
+
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
2267 |
+
$h = $this->hash->hash($m2);
|
2268 |
+
$ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
|
2269 |
+
$db = $ps . chr(1) . $salt;
|
2270 |
+
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
|
2271 |
+
$maskedDB = $db ^ $dbMask;
|
2272 |
+
$maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
|
2273 |
+
$em = $maskedDB . $h . chr(0xBC);
|
2274 |
+
|
2275 |
+
return $em;
|
2276 |
+
}
|
2277 |
+
|
2278 |
+
/**
|
2279 |
+
* EMSA-PSS-VERIFY
|
2280 |
+
*
|
2281 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
|
2282 |
+
*
|
2283 |
+
* @access private
|
2284 |
+
* @param String $m
|
2285 |
+
* @param String $em
|
2286 |
+
* @param Integer $emBits
|
2287 |
+
* @return String
|
2288 |
+
*/
|
2289 |
+
function _emsa_pss_verify($m, $em, $emBits)
|
2290 |
+
{
|
2291 |
+
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
2292 |
+
// be output.
|
2293 |
+
|
2294 |
+
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
|
2295 |
+
$sLen = $this->sLen == false ? $this->hLen : $this->sLen;
|
2296 |
+
|
2297 |
+
$mHash = $this->hash->hash($m);
|
2298 |
+
if ($emLen < $this->hLen + $sLen + 2) {
|
2299 |
+
return false;
|
2300 |
+
}
|
2301 |
+
|
2302 |
+
if ($em[strlen($em) - 1] != chr(0xBC)) {
|
2303 |
+
return false;
|
2304 |
+
}
|
2305 |
+
|
2306 |
+
$maskedDB = substr($em, 0, -$this->hLen - 1);
|
2307 |
+
$h = substr($em, -$this->hLen - 1, $this->hLen);
|
2308 |
+
$temp = chr(0xFF << ($emBits & 7));
|
2309 |
+
if ((~$maskedDB[0] & $temp) != $temp) {
|
2310 |
+
return false;
|
2311 |
+
}
|
2312 |
+
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
|
2313 |
+
$db = $maskedDB ^ $dbMask;
|
2314 |
+
$db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
|
2315 |
+
$temp = $emLen - $this->hLen - $sLen - 2;
|
2316 |
+
if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
|
2317 |
+
return false;
|
2318 |
+
}
|
2319 |
+
$salt = substr($db, $temp + 1); // should be $sLen long
|
2320 |
+
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
2321 |
+
$h2 = $this->hash->hash($m2);
|
2322 |
+
return $this->_equals($h, $h2);
|
2323 |
+
}
|
2324 |
+
|
2325 |
+
/**
|
2326 |
+
* RSASSA-PSS-SIGN
|
2327 |
+
*
|
2328 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
|
2329 |
+
*
|
2330 |
+
* @access private
|
2331 |
+
* @param String $m
|
2332 |
+
* @return String
|
2333 |
+
*/
|
2334 |
+
function _rsassa_pss_sign($m)
|
2335 |
+
{
|
2336 |
+
// EMSA-PSS encoding
|
2337 |
+
|
2338 |
+
$em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
|
2339 |
+
|
2340 |
+
// RSA signature
|
2341 |
+
|
2342 |
+
$m = $this->_os2ip($em);
|
2343 |
+
$s = $this->_rsasp1($m);
|
2344 |
+
$s = $this->_i2osp($s, $this->k);
|
2345 |
+
|
2346 |
+
// Output the signature S
|
2347 |
+
|
2348 |
+
return $s;
|
2349 |
+
}
|
2350 |
+
|
2351 |
+
/**
|
2352 |
+
* RSASSA-PSS-VERIFY
|
2353 |
+
*
|
2354 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
|
2355 |
+
*
|
2356 |
+
* @access private
|
2357 |
+
* @param String $m
|
2358 |
+
* @param String $s
|
2359 |
+
* @return String
|
2360 |
+
*/
|
2361 |
+
function _rsassa_pss_verify($m, $s)
|
2362 |
+
{
|
2363 |
+
// Length checking
|
2364 |
+
|
2365 |
+
if (strlen($s) != $this->k) {
|
2366 |
+
user_error('Invalid signature');
|
2367 |
+
return false;
|
2368 |
+
}
|
2369 |
+
|
2370 |
+
// RSA verification
|
2371 |
+
|
2372 |
+
$modBits = 8 * $this->k;
|
2373 |
+
|
2374 |
+
$s2 = $this->_os2ip($s);
|
2375 |
+
$m2 = $this->_rsavp1($s2);
|
2376 |
+
if ($m2 === false) {
|
2377 |
+
user_error('Invalid signature');
|
2378 |
+
return false;
|
2379 |
+
}
|
2380 |
+
$em = $this->_i2osp($m2, $modBits >> 3);
|
2381 |
+
if ($em === false) {
|
2382 |
+
user_error('Invalid signature');
|
2383 |
+
return false;
|
2384 |
+
}
|
2385 |
+
|
2386 |
+
// EMSA-PSS verification
|
2387 |
+
|
2388 |
+
return $this->_emsa_pss_verify($m, $em, $modBits - 1);
|
2389 |
+
}
|
2390 |
+
|
2391 |
+
/**
|
2392 |
+
* EMSA-PKCS1-V1_5-ENCODE
|
2393 |
+
*
|
2394 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
|
2395 |
+
*
|
2396 |
+
* @access private
|
2397 |
+
* @param String $m
|
2398 |
+
* @param Integer $emLen
|
2399 |
+
* @return String
|
2400 |
+
*/
|
2401 |
+
function _emsa_pkcs1_v1_5_encode($m, $emLen)
|
2402 |
+
{
|
2403 |
+
$h = $this->hash->hash($m);
|
2404 |
+
if ($h === false) {
|
2405 |
+
return false;
|
2406 |
+
}
|
2407 |
+
|
2408 |
+
// see http://tools.ietf.org/html/rfc3447#page-43
|
2409 |
+
switch ($this->hashName) {
|
2410 |
+
case 'md2':
|
2411 |
+
$t = pack('H*', '3020300c06082a864886f70d020205000410');
|
2412 |
+
break;
|
2413 |
+
case 'md5':
|
2414 |
+
$t = pack('H*', '3020300c06082a864886f70d020505000410');
|
2415 |
+
break;
|
2416 |
+
case 'sha1':
|
2417 |
+
$t = pack('H*', '3021300906052b0e03021a05000414');
|
2418 |
+
break;
|
2419 |
+
case 'sha256':
|
2420 |
+
$t = pack('H*', '3031300d060960864801650304020105000420');
|
2421 |
+
break;
|
2422 |
+
case 'sha384':
|
2423 |
+
$t = pack('H*', '3041300d060960864801650304020205000430');
|
2424 |
+
break;
|
2425 |
+
case 'sha512':
|
2426 |
+
$t = pack('H*', '3051300d060960864801650304020305000440');
|
2427 |
+
}
|
2428 |
+
$t.= $h;
|
2429 |
+
$tLen = strlen($t);
|
2430 |
+
|
2431 |
+
if ($emLen < $tLen + 11) {
|
2432 |
+
user_error('Intended encoded message length too short');
|
2433 |
+
return false;
|
2434 |
+
}
|
2435 |
+
|
2436 |
+
$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
|
2437 |
+
|
2438 |
+
$em = "\0\1$ps\0$t";
|
2439 |
+
|
2440 |
+
return $em;
|
2441 |
+
}
|
2442 |
+
|
2443 |
+
/**
|
2444 |
+
* RSASSA-PKCS1-V1_5-SIGN
|
2445 |
+
*
|
2446 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
|
2447 |
+
*
|
2448 |
+
* @access private
|
2449 |
+
* @param String $m
|
2450 |
+
* @return String
|
2451 |
+
*/
|
2452 |
+
function _rsassa_pkcs1_v1_5_sign($m)
|
2453 |
+
{
|
2454 |
+
// EMSA-PKCS1-v1_5 encoding
|
2455 |
+
|
2456 |
+
$em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
|
2457 |
+
if ($em === false) {
|
2458 |
+
user_error('RSA modulus too short');
|
2459 |
+
return false;
|
2460 |
+
}
|
2461 |
+
|
2462 |
+
// RSA signature
|
2463 |
+
|
2464 |
+
$m = $this->_os2ip($em);
|
2465 |
+
$s = $this->_rsasp1($m);
|
2466 |
+
$s = $this->_i2osp($s, $this->k);
|
2467 |
+
|
2468 |
+
// Output the signature S
|
2469 |
+
|
2470 |
+
return $s;
|
2471 |
+
}
|
2472 |
+
|
2473 |
+
/**
|
2474 |
+
* RSASSA-PKCS1-V1_5-VERIFY
|
2475 |
+
*
|
2476 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
|
2477 |
+
*
|
2478 |
+
* @access private
|
2479 |
+
* @param String $m
|
2480 |
+
* @return String
|
2481 |
+
*/
|
2482 |
+
function _rsassa_pkcs1_v1_5_verify($m, $s)
|
2483 |
+
{
|
2484 |
+
// Length checking
|
2485 |
+
|
2486 |
+
if (strlen($s) != $this->k) {
|
2487 |
+
user_error('Invalid signature');
|
2488 |
+
return false;
|
2489 |
+
}
|
2490 |
+
|
2491 |
+
// RSA verification
|
2492 |
+
|
2493 |
+
$s = $this->_os2ip($s);
|
2494 |
+
$m2 = $this->_rsavp1($s);
|
2495 |
+
if ($m2 === false) {
|
2496 |
+
user_error('Invalid signature');
|
2497 |
+
return false;
|
2498 |
+
}
|
2499 |
+
$em = $this->_i2osp($m2, $this->k);
|
2500 |
+
if ($em === false) {
|
2501 |
+
user_error('Invalid signature');
|
2502 |
+
return false;
|
2503 |
+
}
|
2504 |
+
|
2505 |
+
// EMSA-PKCS1-v1_5 encoding
|
2506 |
+
|
2507 |
+
$em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
|
2508 |
+
if ($em2 === false) {
|
2509 |
+
user_error('RSA modulus too short');
|
2510 |
+
return false;
|
2511 |
+
}
|
2512 |
+
|
2513 |
+
// Compare
|
2514 |
+
return $this->_equals($em, $em2);
|
2515 |
+
}
|
2516 |
+
|
2517 |
+
/**
|
2518 |
+
* Set Encryption Mode
|
2519 |
+
*
|
2520 |
+
* Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
|
2521 |
+
*
|
2522 |
+
* @access public
|
2523 |
+
* @param Integer $mode
|
2524 |
+
*/
|
2525 |
+
function setEncryptionMode($mode)
|
2526 |
+
{
|
2527 |
+
$this->encryptionMode = $mode;
|
2528 |
+
}
|
2529 |
+
|
2530 |
+
/**
|
2531 |
+
* Set Signature Mode
|
2532 |
+
*
|
2533 |
+
* Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
|
2534 |
+
*
|
2535 |
+
* @access public
|
2536 |
+
* @param Integer $mode
|
2537 |
+
*/
|
2538 |
+
function setSignatureMode($mode)
|
2539 |
+
{
|
2540 |
+
$this->signatureMode = $mode;
|
2541 |
+
}
|
2542 |
+
|
2543 |
+
/**
|
2544 |
+
* Set public key comment.
|
2545 |
+
*
|
2546 |
+
* @access public
|
2547 |
+
* @param String $comment
|
2548 |
+
*/
|
2549 |
+
function setComment($comment)
|
2550 |
+
{
|
2551 |
+
$this->comment = $comment;
|
2552 |
+
}
|
2553 |
+
|
2554 |
+
/**
|
2555 |
+
* Get public key comment.
|
2556 |
+
*
|
2557 |
+
* @access public
|
2558 |
+
* @return String
|
2559 |
+
*/
|
2560 |
+
function getComment()
|
2561 |
+
{
|
2562 |
+
return $this->comment;
|
2563 |
+
}
|
2564 |
+
|
2565 |
+
/**
|
2566 |
+
* Encryption
|
2567 |
+
*
|
2568 |
+
* Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
|
2569 |
+
* If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
|
2570 |
+
* be concatenated together.
|
2571 |
+
*
|
2572 |
+
* @see decrypt()
|
2573 |
+
* @access public
|
2574 |
+
* @param String $plaintext
|
2575 |
+
* @return String
|
2576 |
+
*/
|
2577 |
+
function encrypt($plaintext)
|
2578 |
+
{
|
2579 |
+
switch ($this->encryptionMode) {
|
2580 |
+
case CRYPT_RSA_ENCRYPTION_PKCS1:
|
2581 |
+
$length = $this->k - 11;
|
2582 |
+
if ($length <= 0) {
|
2583 |
+
return false;
|
2584 |
+
}
|
2585 |
+
|
2586 |
+
$plaintext = str_split($plaintext, $length);
|
2587 |
+
$ciphertext = '';
|
2588 |
+
foreach ($plaintext as $m) {
|
2589 |
+
$ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
|
2590 |
+
}
|
2591 |
+
return $ciphertext;
|
2592 |
+
//case CRYPT_RSA_ENCRYPTION_OAEP:
|
2593 |
+
default:
|
2594 |
+
$length = $this->k - 2 * $this->hLen - 2;
|
2595 |
+
if ($length <= 0) {
|
2596 |
+
return false;
|
2597 |
+
}
|
2598 |
+
|
2599 |
+
$plaintext = str_split($plaintext, $length);
|
2600 |
+
$ciphertext = '';
|
2601 |
+
foreach ($plaintext as $m) {
|
2602 |
+
$ciphertext.= $this->_rsaes_oaep_encrypt($m);
|
2603 |
+
}
|
2604 |
+
return $ciphertext;
|
2605 |
+
}
|
2606 |
+
}
|
2607 |
+
|
2608 |
+
/**
|
2609 |
+
* Decryption
|
2610 |
+
*
|
2611 |
+
* @see encrypt()
|
2612 |
+
* @access public
|
2613 |
+
* @param String $plaintext
|
2614 |
+
* @return String
|
2615 |
+
*/
|
2616 |
+
function decrypt($ciphertext)
|
2617 |
+
{
|
2618 |
+
if ($this->k <= 0) {
|
2619 |
+
return false;
|
2620 |
+
}
|
2621 |
+
|
2622 |
+
$ciphertext = str_split($ciphertext, $this->k);
|
2623 |
+
$ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
|
2624 |
+
|
2625 |
+
$plaintext = '';
|
2626 |
+
|
2627 |
+
switch ($this->encryptionMode) {
|
2628 |
+
case CRYPT_RSA_ENCRYPTION_PKCS1:
|
2629 |
+
$decrypt = '_rsaes_pkcs1_v1_5_decrypt';
|
2630 |
+
break;
|
2631 |
+
//case CRYPT_RSA_ENCRYPTION_OAEP:
|
2632 |
+
default:
|
2633 |
+
$decrypt = '_rsaes_oaep_decrypt';
|
2634 |
+
}
|
2635 |
+
|
2636 |
+
foreach ($ciphertext as $c) {
|
2637 |
+
$temp = $this->$decrypt($c);
|
2638 |
+
if ($temp === false) {
|
2639 |
+
return false;
|
2640 |
+
}
|
2641 |
+
$plaintext.= $temp;
|
2642 |
+
}
|
2643 |
+
|
2644 |
+
return $plaintext;
|
2645 |
+
}
|
2646 |
+
|
2647 |
+
/**
|
2648 |
+
* Create a signature
|
2649 |
+
*
|
2650 |
+
* @see verify()
|
2651 |
+
* @access public
|
2652 |
+
* @param String $message
|
2653 |
+
* @return String
|
2654 |
+
*/
|
2655 |
+
function sign($message)
|
2656 |
+
{
|
2657 |
+
if (empty($this->modulus) || empty($this->exponent)) {
|
2658 |
+
return false;
|
2659 |
+
}
|
2660 |
+
|
2661 |
+
switch ($this->signatureMode) {
|
2662 |
+
case CRYPT_RSA_SIGNATURE_PKCS1:
|
2663 |
+
return $this->_rsassa_pkcs1_v1_5_sign($message);
|
2664 |
+
//case CRYPT_RSA_SIGNATURE_PSS:
|
2665 |
+
default:
|
2666 |
+
return $this->_rsassa_pss_sign($message);
|
2667 |
+
}
|
2668 |
+
}
|
2669 |
+
|
2670 |
+
/**
|
2671 |
+
* Verifies a signature
|
2672 |
+
*
|
2673 |
+
* @see sign()
|
2674 |
+
* @access public
|
2675 |
+
* @param String $message
|
2676 |
+
* @param String $signature
|
2677 |
+
* @return Boolean
|
2678 |
+
*/
|
2679 |
+
function verify($message, $signature)
|
2680 |
+
{
|
2681 |
+
if (empty($this->modulus) || empty($this->exponent)) {
|
2682 |
+
return false;
|
2683 |
+
}
|
2684 |
+
|
2685 |
+
switch ($this->signatureMode) {
|
2686 |
+
case CRYPT_RSA_SIGNATURE_PKCS1:
|
2687 |
+
return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
|
2688 |
+
//case CRYPT_RSA_SIGNATURE_PSS:
|
2689 |
+
default:
|
2690 |
+
return $this->_rsassa_pss_verify($message, $signature);
|
2691 |
+
}
|
2692 |
+
}
|
2693 |
+
}
|
lib/PHPSecLib/Crypt/Random.php
ADDED
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Random Number Generator
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Here's a short example of how to use this library:
|
10 |
+
* <code>
|
11 |
+
* <?php
|
12 |
+
* include('Crypt/Random.php');
|
13 |
+
*
|
14 |
+
* echo bin2hex(crypt_random_string(8));
|
15 |
+
* ?>
|
16 |
+
* </code>
|
17 |
+
*
|
18 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
19 |
+
* of this software and associated documentation files (the "Software"), to deal
|
20 |
+
* in the Software without restriction, including without limitation the rights
|
21 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
22 |
+
* copies of the Software, and to permit persons to whom the Software is
|
23 |
+
* furnished to do so, subject to the following conditions:
|
24 |
+
*
|
25 |
+
* The above copyright notice and this permission notice shall be included in
|
26 |
+
* all copies or substantial portions of the Software.
|
27 |
+
*
|
28 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
29 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
30 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
31 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
32 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
33 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
34 |
+
* THE SOFTWARE.
|
35 |
+
*
|
36 |
+
* @category Crypt
|
37 |
+
* @package Crypt_Random
|
38 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
39 |
+
* @copyright MMVII Jim Wigginton
|
40 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
41 |
+
* @link http://phpseclib.sourceforge.net
|
42 |
+
*/
|
43 |
+
|
44 |
+
/**
|
45 |
+
* "Is Windows" test
|
46 |
+
*
|
47 |
+
* @access private
|
48 |
+
*/
|
49 |
+
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Generate a random string.
|
53 |
+
*
|
54 |
+
* Although microoptimizations are generally discouraged as they impair readability this function is ripe with
|
55 |
+
* microoptimizations because this function has the potential of being called a huge number of times.
|
56 |
+
* eg. for RSA key generation.
|
57 |
+
*
|
58 |
+
* @param Integer $length
|
59 |
+
* @return String
|
60 |
+
* @access public
|
61 |
+
*/
|
62 |
+
function crypt_random_string($length)
|
63 |
+
{
|
64 |
+
if (CRYPT_RANDOM_IS_WINDOWS) {
|
65 |
+
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
|
66 |
+
// ie. class_alias is a function that was introduced in PHP 5.3
|
67 |
+
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
|
68 |
+
return mcrypt_create_iv($length);
|
69 |
+
}
|
70 |
+
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
|
71 |
+
// to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
|
72 |
+
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
|
73 |
+
// call php_win32_get_random_bytes():
|
74 |
+
//
|
75 |
+
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
|
76 |
+
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
|
77 |
+
//
|
78 |
+
// php_win32_get_random_bytes() is defined thusly:
|
79 |
+
//
|
80 |
+
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
|
81 |
+
//
|
82 |
+
// we're calling it, all the same, in the off chance that the mcrypt extension is not available
|
83 |
+
if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
84 |
+
return openssl_random_pseudo_bytes($length);
|
85 |
+
}
|
86 |
+
} else {
|
87 |
+
// method 1. the fastest
|
88 |
+
if (function_exists('openssl_random_pseudo_bytes')) {
|
89 |
+
return openssl_random_pseudo_bytes($length);
|
90 |
+
}
|
91 |
+
// method 2
|
92 |
+
static $fp = true;
|
93 |
+
if ($fp === true) {
|
94 |
+
// warning's will be output unles the error suppression operator is used. errors such as
|
95 |
+
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
|
96 |
+
$fp = @fopen('/dev/urandom', 'rb');
|
97 |
+
}
|
98 |
+
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
|
99 |
+
return fread($fp, $length);
|
100 |
+
}
|
101 |
+
// method 3. pretty much does the same thing as method 2 per the following url:
|
102 |
+
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
|
103 |
+
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
|
104 |
+
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
|
105 |
+
// restrictions or some such
|
106 |
+
if (function_exists('mcrypt_create_iv')) {
|
107 |
+
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
108 |
+
}
|
109 |
+
}
|
110 |
+
// at this point we have no choice but to use a pure-PHP CSPRNG
|
111 |
+
|
112 |
+
// cascade entropy across multiple PHP instances by fixing the session and collecting all
|
113 |
+
// environmental variables, including the previous session data and the current session
|
114 |
+
// data.
|
115 |
+
//
|
116 |
+
// mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
|
117 |
+
// easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
|
118 |
+
// PHP isn't low level to be able to use those as sources and on a web server there's not likely
|
119 |
+
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
|
120 |
+
// however. a ton of people visiting the website. obviously you don't want to base your seeding
|
121 |
+
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
|
122 |
+
// by the user and (2) this isn't just looking at the data sent by the current user - it's based
|
123 |
+
// on the data sent by all users. one user requests the page and a hash of their info is saved.
|
124 |
+
// another user visits the page and the serialization of their data is utilized along with the
|
125 |
+
// server envirnment stuff and a hash of the previous http request data (which itself utilizes
|
126 |
+
// a hash of the session data before that). certainly an attacker should be assumed to have
|
127 |
+
// full control over his own http requests. he, however, is not going to have control over
|
128 |
+
// everyone's http requests.
|
129 |
+
static $crypto = false, $v;
|
130 |
+
if ($crypto === false) {
|
131 |
+
// save old session data
|
132 |
+
$old_session_id = session_id();
|
133 |
+
$old_use_cookies = ini_get('session.use_cookies');
|
134 |
+
$old_session_cache_limiter = session_cache_limiter();
|
135 |
+
if (isset($_SESSION)) {
|
136 |
+
$_OLD_SESSION = $_SESSION;
|
137 |
+
}
|
138 |
+
if ($old_session_id != '') {
|
139 |
+
session_write_close();
|
140 |
+
}
|
141 |
+
|
142 |
+
session_id(1);
|
143 |
+
ini_set('session.use_cookies', 0);
|
144 |
+
session_cache_limiter('');
|
145 |
+
session_start();
|
146 |
+
|
147 |
+
$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
|
148 |
+
serialize($_SERVER) .
|
149 |
+
serialize($_POST) .
|
150 |
+
serialize($_GET) .
|
151 |
+
serialize($_COOKIE) .
|
152 |
+
serialize($GLOBALS) .
|
153 |
+
serialize($_SESSION) .
|
154 |
+
serialize($_OLD_SESSION)
|
155 |
+
));
|
156 |
+
if (!isset($_SESSION['count'])) {
|
157 |
+
$_SESSION['count'] = 0;
|
158 |
+
}
|
159 |
+
$_SESSION['count']++;
|
160 |
+
|
161 |
+
session_write_close();
|
162 |
+
|
163 |
+
// restore old session data
|
164 |
+
if ($old_session_id != '') {
|
165 |
+
session_id($old_session_id);
|
166 |
+
session_start();
|
167 |
+
ini_set('session.use_cookies', $old_use_cookies);
|
168 |
+
session_cache_limiter($old_session_cache_limiter);
|
169 |
+
} else {
|
170 |
+
if (isset($_OLD_SESSION)) {
|
171 |
+
$_SESSION = $_OLD_SESSION;
|
172 |
+
unset($_OLD_SESSION);
|
173 |
+
} else {
|
174 |
+
unset($_SESSION);
|
175 |
+
}
|
176 |
+
}
|
177 |
+
|
178 |
+
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
|
179 |
+
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
|
180 |
+
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
|
181 |
+
// original hash and the current hash. we'll be emulating that. for more info see the following URL:
|
182 |
+
//
|
183 |
+
// http://tools.ietf.org/html/rfc4253#section-7.2
|
184 |
+
//
|
185 |
+
// see the is_string($crypto) part for an example of how to expand the keys
|
186 |
+
$key = pack('H*', sha1($seed . 'A'));
|
187 |
+
$iv = pack('H*', sha1($seed . 'C'));
|
188 |
+
|
189 |
+
// ciphers are used as per the nist.gov link below. also, see this link:
|
190 |
+
//
|
191 |
+
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
|
192 |
+
switch (true) {
|
193 |
+
case class_exists('Crypt_AES'):
|
194 |
+
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
|
195 |
+
break;
|
196 |
+
case class_exists('Crypt_TripleDES'):
|
197 |
+
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
|
198 |
+
break;
|
199 |
+
case class_exists('Crypt_DES'):
|
200 |
+
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
|
201 |
+
break;
|
202 |
+
case class_exists('Crypt_RC4'):
|
203 |
+
$crypto = new Crypt_RC4();
|
204 |
+
break;
|
205 |
+
default:
|
206 |
+
$crypto = $seed;
|
207 |
+
return crypt_random_string($length);
|
208 |
+
}
|
209 |
+
|
210 |
+
$crypto->setKey($key);
|
211 |
+
$crypto->setIV($iv);
|
212 |
+
$crypto->enableContinuousBuffer();
|
213 |
+
}
|
214 |
+
|
215 |
+
if (is_string($crypto)) {
|
216 |
+
// the following is based off of ANSI X9.31:
|
217 |
+
//
|
218 |
+
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
|
219 |
+
//
|
220 |
+
// OpenSSL uses that same standard for it's random numbers:
|
221 |
+
//
|
222 |
+
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
|
223 |
+
// (do a search for "ANS X9.31 A.2.4")
|
224 |
+
//
|
225 |
+
// ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
|
226 |
+
// later on in the code) but if they're not we'll use sha1
|
227 |
+
$result = '';
|
228 |
+
while (strlen($result) < $length) { // each loop adds 20 bytes
|
229 |
+
// microtime() isn't packed as "densely" as it could be but then neither is that the idea.
|
230 |
+
// the idea is simply to ensure that each "block" has a unique element to it.
|
231 |
+
$i = pack('H*', sha1(microtime()));
|
232 |
+
$r = pack('H*', sha1($i ^ $v));
|
233 |
+
$v = pack('H*', sha1($r ^ $i));
|
234 |
+
$result.= $r;
|
235 |
+
}
|
236 |
+
return substr($result, 0, $length);
|
237 |
+
}
|
238 |
+
|
239 |
+
//return $crypto->encrypt(str_repeat("\0", $length));
|
240 |
+
|
241 |
+
$result = '';
|
242 |
+
while (strlen($result) < $length) {
|
243 |
+
$i = $crypto->encrypt(microtime());
|
244 |
+
$r = $crypto->encrypt($i ^ $v);
|
245 |
+
$v = $crypto->encrypt($r ^ $i);
|
246 |
+
$result.= $r;
|
247 |
+
}
|
248 |
+
return substr($result, 0, $length);
|
249 |
+
}
|
lib/PHPSecLib/Crypt/Rijndael.php
ADDED
@@ -0,0 +1,2062 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of Rijndael.
|
6 |
+
*
|
7 |
+
* Does not use mcrypt, even when available, for reasons that are explained below.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
|
12 |
+
* {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
13 |
+
* {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
|
14 |
+
* 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until
|
15 |
+
* {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
|
16 |
+
*
|
17 |
+
* Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
|
18 |
+
* does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
|
19 |
+
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
|
20 |
+
* algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
|
21 |
+
* are first defined as valid key / block lengths in
|
22 |
+
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
|
23 |
+
* Extensions: Other block and Cipher Key lengths.
|
24 |
+
*
|
25 |
+
* {@internal The variable names are the same as those in
|
26 |
+
* {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
|
27 |
+
*
|
28 |
+
* Here's a short example of how to use this library:
|
29 |
+
* <code>
|
30 |
+
* <?php
|
31 |
+
* include('Crypt/Rijndael.php');
|
32 |
+
*
|
33 |
+
* $rijndael = new Crypt_Rijndael();
|
34 |
+
*
|
35 |
+
* $rijndael->setKey('abcdefghijklmnop');
|
36 |
+
*
|
37 |
+
* $size = 10 * 1024;
|
38 |
+
* $plaintext = '';
|
39 |
+
* for ($i = 0; $i < $size; $i++) {
|
40 |
+
* $plaintext.= 'a';
|
41 |
+
* }
|
42 |
+
*
|
43 |
+
* echo $rijndael->decrypt($rijndael->encrypt($plaintext));
|
44 |
+
* ?>
|
45 |
+
* </code>
|
46 |
+
*
|
47 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
48 |
+
* of this software and associated documentation files (the "Software"), to deal
|
49 |
+
* in the Software without restriction, including without limitation the rights
|
50 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
51 |
+
* copies of the Software, and to permit persons to whom the Software is
|
52 |
+
* furnished to do so, subject to the following conditions:
|
53 |
+
*
|
54 |
+
* The above copyright notice and this permission notice shall be included in
|
55 |
+
* all copies or substantial portions of the Software.
|
56 |
+
*
|
57 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
58 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
59 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
60 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
61 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
62 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
63 |
+
* THE SOFTWARE.
|
64 |
+
*
|
65 |
+
* @category Crypt
|
66 |
+
* @package Crypt_Rijndael
|
67 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
68 |
+
* @copyright MMVIII Jim Wigginton
|
69 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
70 |
+
* @link http://phpseclib.sourceforge.net
|
71 |
+
*/
|
72 |
+
|
73 |
+
/**#@+
|
74 |
+
* @access public
|
75 |
+
* @see Crypt_Rijndael::encrypt()
|
76 |
+
* @see Crypt_Rijndael::decrypt()
|
77 |
+
*/
|
78 |
+
/**
|
79 |
+
* Encrypt / decrypt using the Counter mode.
|
80 |
+
*
|
81 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
82 |
+
*
|
83 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
84 |
+
*/
|
85 |
+
define('CRYPT_RIJNDAEL_MODE_CTR', -1);
|
86 |
+
/**
|
87 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
88 |
+
*
|
89 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
90 |
+
*/
|
91 |
+
define('CRYPT_RIJNDAEL_MODE_ECB', 1);
|
92 |
+
/**
|
93 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
94 |
+
*
|
95 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
96 |
+
*/
|
97 |
+
define('CRYPT_RIJNDAEL_MODE_CBC', 2);
|
98 |
+
/**
|
99 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
100 |
+
*
|
101 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
102 |
+
*/
|
103 |
+
define('CRYPT_RIJNDAEL_MODE_CFB', 3);
|
104 |
+
/**
|
105 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
106 |
+
*
|
107 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
108 |
+
*/
|
109 |
+
define('CRYPT_RIJNDAEL_MODE_OFB', 4);
|
110 |
+
/**#@-*/
|
111 |
+
|
112 |
+
/**#@+
|
113 |
+
* @access private
|
114 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
115 |
+
*/
|
116 |
+
/**
|
117 |
+
* Toggles the internal implementation
|
118 |
+
*/
|
119 |
+
define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
|
120 |
+
/**
|
121 |
+
* Toggles the mcrypt implementation
|
122 |
+
*/
|
123 |
+
define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
|
124 |
+
/**#@-*/
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Pure-PHP implementation of Rijndael.
|
128 |
+
*
|
129 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
130 |
+
* @version 0.1.0
|
131 |
+
* @access public
|
132 |
+
* @package Crypt_Rijndael
|
133 |
+
*/
|
134 |
+
class Crypt_Rijndael {
|
135 |
+
/**
|
136 |
+
* The Encryption Mode
|
137 |
+
*
|
138 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
139 |
+
* @var Integer
|
140 |
+
* @access private
|
141 |
+
*/
|
142 |
+
var $mode;
|
143 |
+
|
144 |
+
/**
|
145 |
+
* The Key
|
146 |
+
*
|
147 |
+
* @see Crypt_Rijndael::setKey()
|
148 |
+
* @var String
|
149 |
+
* @access private
|
150 |
+
*/
|
151 |
+
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
152 |
+
|
153 |
+
/**
|
154 |
+
* The Initialization Vector
|
155 |
+
*
|
156 |
+
* @see Crypt_Rijndael::setIV()
|
157 |
+
* @var String
|
158 |
+
* @access private
|
159 |
+
*/
|
160 |
+
var $iv = '';
|
161 |
+
|
162 |
+
/**
|
163 |
+
* A "sliding" Initialization Vector
|
164 |
+
*
|
165 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
166 |
+
* @var String
|
167 |
+
* @access private
|
168 |
+
*/
|
169 |
+
var $encryptIV = '';
|
170 |
+
|
171 |
+
/**
|
172 |
+
* A "sliding" Initialization Vector
|
173 |
+
*
|
174 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
175 |
+
* @var String
|
176 |
+
* @access private
|
177 |
+
*/
|
178 |
+
var $decryptIV = '';
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Continuous Buffer status
|
182 |
+
*
|
183 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
184 |
+
* @var Boolean
|
185 |
+
* @access private
|
186 |
+
*/
|
187 |
+
var $continuousBuffer = false;
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Padding status
|
191 |
+
*
|
192 |
+
* @see Crypt_Rijndael::enablePadding()
|
193 |
+
* @var Boolean
|
194 |
+
* @access private
|
195 |
+
*/
|
196 |
+
var $padding = true;
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Does the key schedule need to be (re)calculated?
|
200 |
+
*
|
201 |
+
* @see setKey()
|
202 |
+
* @see setBlockLength()
|
203 |
+
* @see setKeyLength()
|
204 |
+
* @var Boolean
|
205 |
+
* @access private
|
206 |
+
*/
|
207 |
+
var $changed = true;
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Has the key length explicitly been set or should it be derived from the key, itself?
|
211 |
+
*
|
212 |
+
* @see setKeyLength()
|
213 |
+
* @var Boolean
|
214 |
+
* @access private
|
215 |
+
*/
|
216 |
+
var $explicit_key_length = false;
|
217 |
+
|
218 |
+
/**
|
219 |
+
* The Key Schedule
|
220 |
+
*
|
221 |
+
* @see _setup()
|
222 |
+
* @var Array
|
223 |
+
* @access private
|
224 |
+
*/
|
225 |
+
var $w;
|
226 |
+
|
227 |
+
/**
|
228 |
+
* The Inverse Key Schedule
|
229 |
+
*
|
230 |
+
* @see _setup()
|
231 |
+
* @var Array
|
232 |
+
* @access private
|
233 |
+
*/
|
234 |
+
var $dw;
|
235 |
+
|
236 |
+
/**
|
237 |
+
* The Block Length
|
238 |
+
*
|
239 |
+
* @see setBlockLength()
|
240 |
+
* @var Integer
|
241 |
+
* @access private
|
242 |
+
* @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
|
243 |
+
* $Nb because we need this value and not $Nb to pad strings appropriately.
|
244 |
+
*/
|
245 |
+
var $block_size = 16;
|
246 |
+
|
247 |
+
/**
|
248 |
+
* The Block Length divided by 32
|
249 |
+
*
|
250 |
+
* @see setBlockLength()
|
251 |
+
* @var Integer
|
252 |
+
* @access private
|
253 |
+
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
|
254 |
+
* because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
|
255 |
+
* derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
|
256 |
+
* of that, we'll just precompute it once.
|
257 |
+
*
|
258 |
+
*/
|
259 |
+
var $Nb = 4;
|
260 |
+
|
261 |
+
/**
|
262 |
+
* The Key Length
|
263 |
+
*
|
264 |
+
* @see setKeyLength()
|
265 |
+
* @var Integer
|
266 |
+
* @access private
|
267 |
+
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
|
268 |
+
* because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
|
269 |
+
* derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
|
270 |
+
* of that, we'll just precompute it once.
|
271 |
+
*/
|
272 |
+
var $key_size = 16;
|
273 |
+
|
274 |
+
/**
|
275 |
+
* The Key Length divided by 32
|
276 |
+
*
|
277 |
+
* @see setKeyLength()
|
278 |
+
* @var Integer
|
279 |
+
* @access private
|
280 |
+
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
|
281 |
+
*/
|
282 |
+
var $Nk = 4;
|
283 |
+
|
284 |
+
/**
|
285 |
+
* The Number of Rounds
|
286 |
+
*
|
287 |
+
* @var Integer
|
288 |
+
* @access private
|
289 |
+
* @internal The max value is 14, the min value is 10.
|
290 |
+
*/
|
291 |
+
var $Nr;
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Shift offsets
|
295 |
+
*
|
296 |
+
* @var Array
|
297 |
+
* @access private
|
298 |
+
*/
|
299 |
+
var $c;
|
300 |
+
|
301 |
+
/**
|
302 |
+
* Precomputed mixColumns table
|
303 |
+
*
|
304 |
+
* @see Crypt_Rijndael()
|
305 |
+
* @var Array
|
306 |
+
* @access private
|
307 |
+
*/
|
308 |
+
var $t0;
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Precomputed mixColumns table
|
312 |
+
*
|
313 |
+
* @see Crypt_Rijndael()
|
314 |
+
* @var Array
|
315 |
+
* @access private
|
316 |
+
*/
|
317 |
+
var $t1;
|
318 |
+
|
319 |
+
/**
|
320 |
+
* Precomputed mixColumns table
|
321 |
+
*
|
322 |
+
* @see Crypt_Rijndael()
|
323 |
+
* @var Array
|
324 |
+
* @access private
|
325 |
+
*/
|
326 |
+
var $t2;
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Precomputed mixColumns table
|
330 |
+
*
|
331 |
+
* @see Crypt_Rijndael()
|
332 |
+
* @var Array
|
333 |
+
* @access private
|
334 |
+
*/
|
335 |
+
var $t3;
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Precomputed invMixColumns table
|
339 |
+
*
|
340 |
+
* @see Crypt_Rijndael()
|
341 |
+
* @var Array
|
342 |
+
* @access private
|
343 |
+
*/
|
344 |
+
var $dt0;
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Precomputed invMixColumns table
|
348 |
+
*
|
349 |
+
* @see Crypt_Rijndael()
|
350 |
+
* @var Array
|
351 |
+
* @access private
|
352 |
+
*/
|
353 |
+
var $dt1;
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Precomputed invMixColumns table
|
357 |
+
*
|
358 |
+
* @see Crypt_Rijndael()
|
359 |
+
* @var Array
|
360 |
+
* @access private
|
361 |
+
*/
|
362 |
+
var $dt2;
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Precomputed invMixColumns table
|
366 |
+
*
|
367 |
+
* @see Crypt_Rijndael()
|
368 |
+
* @var Array
|
369 |
+
* @access private
|
370 |
+
*/
|
371 |
+
var $dt3;
|
372 |
+
|
373 |
+
/**
|
374 |
+
* The SubByte S-Box
|
375 |
+
*
|
376 |
+
* @see Crypt_Rijndael::_encryptBlock()
|
377 |
+
* @var Array
|
378 |
+
* @access private
|
379 |
+
*/
|
380 |
+
var $sbox;
|
381 |
+
|
382 |
+
/**
|
383 |
+
* The inverse SubByte S-Box
|
384 |
+
*
|
385 |
+
* @see Crypt_Rijndael::_decryptBlock()
|
386 |
+
* @var Array
|
387 |
+
* @access private
|
388 |
+
*/
|
389 |
+
var $isbox;
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Performance-optimized callback function for en/decrypt()
|
393 |
+
*
|
394 |
+
* @see Crypt_Rijndael::encrypt()
|
395 |
+
* @see Crypt_Rijndael::decrypt()
|
396 |
+
* @see Crypt_Rijndael::inline_crypt_setup()
|
397 |
+
* @see Crypt_Rijndael::$use_inline_crypt
|
398 |
+
* @var Callback
|
399 |
+
* @access private
|
400 |
+
*/
|
401 |
+
var $inline_crypt;
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Holds whether performance-optimized $inline_crypt should be used or not.
|
405 |
+
*
|
406 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
407 |
+
* @see Crypt_Rijndael::inline_crypt_setup()
|
408 |
+
* @see Crypt_Rijndael::$inline_crypt
|
409 |
+
* @var Boolean
|
410 |
+
* @access private
|
411 |
+
*/
|
412 |
+
var $use_inline_crypt = true;
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Is the mode one that is paddable?
|
416 |
+
*
|
417 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
418 |
+
* @var Boolean
|
419 |
+
* @access private
|
420 |
+
*/
|
421 |
+
var $paddable = false;
|
422 |
+
|
423 |
+
/**
|
424 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
425 |
+
*
|
426 |
+
* @see Crypt_Rijndael::encrypt()
|
427 |
+
* @var String
|
428 |
+
* @access private
|
429 |
+
*/
|
430 |
+
var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
|
431 |
+
|
432 |
+
/**
|
433 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
434 |
+
*
|
435 |
+
* @see Crypt_Rijndael::decrypt()
|
436 |
+
* @var String
|
437 |
+
* @access private
|
438 |
+
*/
|
439 |
+
var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
|
440 |
+
|
441 |
+
/**
|
442 |
+
* Default Constructor.
|
443 |
+
*
|
444 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
445 |
+
* CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
|
446 |
+
*
|
447 |
+
* @param optional Integer $mode
|
448 |
+
* @return Crypt_Rijndael
|
449 |
+
* @access public
|
450 |
+
*/
|
451 |
+
function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
|
452 |
+
{
|
453 |
+
switch ($mode) {
|
454 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
455 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
456 |
+
$this->paddable = true;
|
457 |
+
$this->mode = $mode;
|
458 |
+
break;
|
459 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
460 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
461 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
462 |
+
$this->mode = $mode;
|
463 |
+
break;
|
464 |
+
default:
|
465 |
+
$this->paddable = true;
|
466 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
|
467 |
+
}
|
468 |
+
|
469 |
+
$t3 = &$this->t3;
|
470 |
+
$t2 = &$this->t2;
|
471 |
+
$t1 = &$this->t1;
|
472 |
+
$t0 = &$this->t0;
|
473 |
+
|
474 |
+
$dt3 = &$this->dt3;
|
475 |
+
$dt2 = &$this->dt2;
|
476 |
+
$dt1 = &$this->dt1;
|
477 |
+
$dt0 = &$this->dt0;
|
478 |
+
|
479 |
+
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
|
480 |
+
// precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
|
481 |
+
// those are the names we'll use.
|
482 |
+
$t3 = array(
|
483 |
+
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
|
484 |
+
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
|
485 |
+
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
|
486 |
+
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
|
487 |
+
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
|
488 |
+
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
|
489 |
+
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
|
490 |
+
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
|
491 |
+
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
|
492 |
+
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
|
493 |
+
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
|
494 |
+
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
|
495 |
+
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
|
496 |
+
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
|
497 |
+
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
|
498 |
+
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
|
499 |
+
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
|
500 |
+
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
|
501 |
+
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
|
502 |
+
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
|
503 |
+
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
|
504 |
+
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
|
505 |
+
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
|
506 |
+
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
|
507 |
+
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
|
508 |
+
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
|
509 |
+
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
|
510 |
+
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
|
511 |
+
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
|
512 |
+
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
|
513 |
+
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
|
514 |
+
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
|
515 |
+
);
|
516 |
+
|
517 |
+
$dt3 = array(
|
518 |
+
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
|
519 |
+
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
|
520 |
+
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
|
521 |
+
0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
|
522 |
+
0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
|
523 |
+
0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
|
524 |
+
0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
|
525 |
+
0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
|
526 |
+
0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
|
527 |
+
0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
|
528 |
+
0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
|
529 |
+
0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
|
530 |
+
0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
|
531 |
+
0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
|
532 |
+
0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
|
533 |
+
0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
|
534 |
+
0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
|
535 |
+
0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
|
536 |
+
0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
|
537 |
+
0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
|
538 |
+
0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
|
539 |
+
0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
|
540 |
+
0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
|
541 |
+
0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
|
542 |
+
0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
|
543 |
+
0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
|
544 |
+
0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
|
545 |
+
0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
|
546 |
+
0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
|
547 |
+
0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
|
548 |
+
0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
|
549 |
+
0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
|
550 |
+
);
|
551 |
+
|
552 |
+
for ($i = 0; $i < 256; $i++) {
|
553 |
+
$t2[] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
|
554 |
+
$t1[] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
|
555 |
+
$t0[] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
|
556 |
+
|
557 |
+
$dt2[] = (($dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
|
558 |
+
$dt1[] = (($dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
|
559 |
+
$dt0[] = (($dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
|
560 |
+
}
|
561 |
+
|
562 |
+
// sbox for the S-Box substitution
|
563 |
+
$this->sbox = array(
|
564 |
+
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
565 |
+
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
566 |
+
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
567 |
+
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
568 |
+
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
569 |
+
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
570 |
+
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
571 |
+
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
572 |
+
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
573 |
+
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
574 |
+
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
575 |
+
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
576 |
+
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
577 |
+
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
578 |
+
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
579 |
+
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
|
580 |
+
);
|
581 |
+
|
582 |
+
// sbox for the inverse S-Box substitution
|
583 |
+
$this->isbox = array(
|
584 |
+
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
|
585 |
+
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
|
586 |
+
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
|
587 |
+
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
|
588 |
+
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
|
589 |
+
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
|
590 |
+
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
|
591 |
+
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
|
592 |
+
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
|
593 |
+
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
|
594 |
+
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
|
595 |
+
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
|
596 |
+
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
|
597 |
+
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
|
598 |
+
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
|
599 |
+
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
|
600 |
+
);
|
601 |
+
|
602 |
+
if (!function_exists('create_function') || !is_callable('create_function')) {
|
603 |
+
$this->use_inline_crypt = false;
|
604 |
+
}
|
605 |
+
}
|
606 |
+
|
607 |
+
/**
|
608 |
+
* Sets the key.
|
609 |
+
*
|
610 |
+
* Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
|
611 |
+
* whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
|
612 |
+
* up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
|
613 |
+
* excess bits.
|
614 |
+
*
|
615 |
+
* If the key is not explicitly set, it'll be assumed to be all null bytes.
|
616 |
+
*
|
617 |
+
* @access public
|
618 |
+
* @param String $key
|
619 |
+
*/
|
620 |
+
function setKey($key)
|
621 |
+
{
|
622 |
+
$this->key = $key;
|
623 |
+
$this->changed = true;
|
624 |
+
}
|
625 |
+
|
626 |
+
/**
|
627 |
+
* Sets the initialization vector. (optional)
|
628 |
+
*
|
629 |
+
* SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
|
630 |
+
* to be all zero's.
|
631 |
+
*
|
632 |
+
* @access public
|
633 |
+
* @param String $iv
|
634 |
+
*/
|
635 |
+
function setIV($iv)
|
636 |
+
{
|
637 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));
|
638 |
+
}
|
639 |
+
|
640 |
+
/**
|
641 |
+
* Sets the key length
|
642 |
+
*
|
643 |
+
* Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
|
644 |
+
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
645 |
+
*
|
646 |
+
* @access public
|
647 |
+
* @param Integer $length
|
648 |
+
*/
|
649 |
+
function setKeyLength($length)
|
650 |
+
{
|
651 |
+
$length >>= 5;
|
652 |
+
if ($length > 8) {
|
653 |
+
$length = 8;
|
654 |
+
} else if ($length < 4) {
|
655 |
+
$length = 4;
|
656 |
+
}
|
657 |
+
$this->Nk = $length;
|
658 |
+
$this->key_size = $length << 2;
|
659 |
+
|
660 |
+
$this->explicit_key_length = true;
|
661 |
+
$this->changed = true;
|
662 |
+
}
|
663 |
+
|
664 |
+
/**
|
665 |
+
* Sets the password.
|
666 |
+
*
|
667 |
+
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
|
668 |
+
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
|
669 |
+
* $hash, $salt, $method
|
670 |
+
* Set $dkLen by calling setKeyLength()
|
671 |
+
*
|
672 |
+
* @param String $password
|
673 |
+
* @param optional String $method
|
674 |
+
* @access public
|
675 |
+
*/
|
676 |
+
function setPassword($password, $method = 'pbkdf2')
|
677 |
+
{
|
678 |
+
$key = '';
|
679 |
+
|
680 |
+
switch ($method) {
|
681 |
+
default: // 'pbkdf2'
|
682 |
+
list(, , $hash, $salt, $count) = func_get_args();
|
683 |
+
if (!isset($hash)) {
|
684 |
+
$hash = 'sha1';
|
685 |
+
}
|
686 |
+
// WPA and WPA2 use the SSID as the salt
|
687 |
+
if (!isset($salt)) {
|
688 |
+
$salt = 'phpseclib';
|
689 |
+
}
|
690 |
+
// RFC2898#section-4.2 uses 1,000 iterations by default
|
691 |
+
// WPA and WPA2 use 4,096.
|
692 |
+
if (!isset($count)) {
|
693 |
+
$count = 1000;
|
694 |
+
}
|
695 |
+
|
696 |
+
if (!class_exists('Crypt_Hash')) {
|
697 |
+
require_once('Crypt/Hash.php');
|
698 |
+
}
|
699 |
+
|
700 |
+
$i = 1;
|
701 |
+
while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size
|
702 |
+
//$dk.= $this->_pbkdf($password, $salt, $count, $i++);
|
703 |
+
$hmac = new Crypt_Hash();
|
704 |
+
$hmac->setHash($hash);
|
705 |
+
$hmac->setKey($password);
|
706 |
+
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
707 |
+
for ($j = 2; $j <= $count; $j++) {
|
708 |
+
$u = $hmac->hash($u);
|
709 |
+
$f^= $u;
|
710 |
+
}
|
711 |
+
$key.= $f;
|
712 |
+
}
|
713 |
+
}
|
714 |
+
|
715 |
+
$this->setKey(substr($key, 0, $this->key_size));
|
716 |
+
}
|
717 |
+
|
718 |
+
/**
|
719 |
+
* Sets the block length
|
720 |
+
*
|
721 |
+
* Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
|
722 |
+
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
723 |
+
*
|
724 |
+
* @access public
|
725 |
+
* @param Integer $length
|
726 |
+
*/
|
727 |
+
function setBlockLength($length)
|
728 |
+
{
|
729 |
+
$length >>= 5;
|
730 |
+
if ($length > 8) {
|
731 |
+
$length = 8;
|
732 |
+
} else if ($length < 4) {
|
733 |
+
$length = 4;
|
734 |
+
}
|
735 |
+
$this->Nb = $length;
|
736 |
+
$this->block_size = $length << 2;
|
737 |
+
$this->changed = true;
|
738 |
+
}
|
739 |
+
|
740 |
+
/**
|
741 |
+
* Generate CTR XOR encryption key
|
742 |
+
*
|
743 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
744 |
+
* plaintext / ciphertext in CTR mode.
|
745 |
+
*
|
746 |
+
* @see Crypt_Rijndael::decrypt()
|
747 |
+
* @see Crypt_Rijndael::encrypt()
|
748 |
+
* @access public
|
749 |
+
* @param Integer $length
|
750 |
+
* @param String $iv
|
751 |
+
*/
|
752 |
+
function _generate_xor($length, &$iv)
|
753 |
+
{
|
754 |
+
$xor = '';
|
755 |
+
$block_size = $this->block_size;
|
756 |
+
$num_blocks = floor(($length + ($block_size - 1)) / $block_size);
|
757 |
+
for ($i = 0; $i < $num_blocks; $i++) {
|
758 |
+
$xor.= $iv;
|
759 |
+
for ($j = 4; $j <= $block_size; $j+=4) {
|
760 |
+
$temp = substr($iv, -$j, 4);
|
761 |
+
switch ($temp) {
|
762 |
+
case "\xFF\xFF\xFF\xFF":
|
763 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
764 |
+
break;
|
765 |
+
case "\x7F\xFF\xFF\xFF":
|
766 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
767 |
+
break 2;
|
768 |
+
default:
|
769 |
+
extract(unpack('Ncount', $temp));
|
770 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
771 |
+
break 2;
|
772 |
+
}
|
773 |
+
}
|
774 |
+
}
|
775 |
+
|
776 |
+
return $xor;
|
777 |
+
}
|
778 |
+
|
779 |
+
/**
|
780 |
+
* Encrypts a message.
|
781 |
+
*
|
782 |
+
* $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
|
783 |
+
* implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
|
784 |
+
* necessary are discussed in the following
|
785 |
+
* URL:
|
786 |
+
*
|
787 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
788 |
+
*
|
789 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
790 |
+
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
|
791 |
+
* length.
|
792 |
+
*
|
793 |
+
* @see Crypt_Rijndael::decrypt()
|
794 |
+
* @access public
|
795 |
+
* @param String $plaintext
|
796 |
+
*/
|
797 |
+
function encrypt($plaintext)
|
798 |
+
{
|
799 |
+
if ($this->changed) {
|
800 |
+
$this->_setup();
|
801 |
+
}
|
802 |
+
if ($this->use_inline_crypt) {
|
803 |
+
$inline = $this->inline_crypt;
|
804 |
+
return $inline('encrypt', $this, $plaintext);
|
805 |
+
}
|
806 |
+
if ($this->paddable) {
|
807 |
+
$plaintext = $this->_pad($plaintext);
|
808 |
+
}
|
809 |
+
|
810 |
+
$block_size = $this->block_size;
|
811 |
+
$buffer = &$this->enbuffer;
|
812 |
+
$ciphertext = '';
|
813 |
+
switch ($this->mode) {
|
814 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
815 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
816 |
+
$ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
|
817 |
+
}
|
818 |
+
break;
|
819 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
820 |
+
$xor = $this->encryptIV;
|
821 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
822 |
+
$block = substr($plaintext, $i, $block_size);
|
823 |
+
$block = $this->_encryptBlock($block ^ $xor);
|
824 |
+
$xor = $block;
|
825 |
+
$ciphertext.= $block;
|
826 |
+
}
|
827 |
+
if ($this->continuousBuffer) {
|
828 |
+
$this->encryptIV = $xor;
|
829 |
+
}
|
830 |
+
break;
|
831 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
832 |
+
$xor = $this->encryptIV;
|
833 |
+
if (strlen($buffer['encrypted'])) {
|
834 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
835 |
+
$block = substr($plaintext, $i, $block_size);
|
836 |
+
if (strlen($block) > strlen($buffer['encrypted'])) {
|
837 |
+
$buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
838 |
+
}
|
839 |
+
$key = $this->_string_shift($buffer['encrypted'], $block_size);
|
840 |
+
$ciphertext.= $block ^ $key;
|
841 |
+
}
|
842 |
+
} else {
|
843 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
844 |
+
$block = substr($plaintext, $i, $block_size);
|
845 |
+
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
846 |
+
$ciphertext.= $block ^ $key;
|
847 |
+
}
|
848 |
+
}
|
849 |
+
if ($this->continuousBuffer) {
|
850 |
+
$this->encryptIV = $xor;
|
851 |
+
if ($start = strlen($plaintext) % $block_size) {
|
852 |
+
$buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
|
853 |
+
}
|
854 |
+
}
|
855 |
+
break;
|
856 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
857 |
+
// cfb loosely routines inspired by openssl's:
|
858 |
+
// http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1
|
859 |
+
if ($this->continuousBuffer) {
|
860 |
+
$iv = &$this->encryptIV;
|
861 |
+
$pos = &$buffer['pos'];
|
862 |
+
} else {
|
863 |
+
$iv = $this->encryptIV;
|
864 |
+
$pos = 0;
|
865 |
+
}
|
866 |
+
$len = strlen($plaintext);
|
867 |
+
$i = 0;
|
868 |
+
if ($pos) {
|
869 |
+
$orig_pos = $pos;
|
870 |
+
$max = $block_size - $pos;
|
871 |
+
if ($len >= $max) {
|
872 |
+
$i = $max;
|
873 |
+
$len-= $max;
|
874 |
+
$pos = 0;
|
875 |
+
} else {
|
876 |
+
$i = $len;
|
877 |
+
$pos+= $len;
|
878 |
+
$len = 0;
|
879 |
+
}
|
880 |
+
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
|
881 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
882 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
883 |
+
}
|
884 |
+
while ($len >= $block_size) {
|
885 |
+
$iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
|
886 |
+
$ciphertext.= $iv;
|
887 |
+
$len-= $block_size;
|
888 |
+
$i+= $block_size;
|
889 |
+
}
|
890 |
+
if ($len) {
|
891 |
+
$iv = $this->_encryptBlock($iv);
|
892 |
+
$block = $iv ^ substr($plaintext, $i);
|
893 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
894 |
+
$ciphertext.= $block;
|
895 |
+
$pos = $len;
|
896 |
+
}
|
897 |
+
break;
|
898 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
899 |
+
$xor = $this->encryptIV;
|
900 |
+
if (strlen($buffer['xor'])) {
|
901 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
902 |
+
$block = substr($plaintext, $i, $block_size);
|
903 |
+
if (strlen($block) > strlen($buffer['xor'])) {
|
904 |
+
$xor = $this->_encryptBlock($xor);
|
905 |
+
$buffer['xor'].= $xor;
|
906 |
+
}
|
907 |
+
$key = $this->_string_shift($buffer['xor'], $block_size);
|
908 |
+
$ciphertext.= $block ^ $key;
|
909 |
+
}
|
910 |
+
} else {
|
911 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
912 |
+
$xor = $this->_encryptBlock($xor);
|
913 |
+
$ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
|
914 |
+
}
|
915 |
+
$key = $xor;
|
916 |
+
}
|
917 |
+
if ($this->continuousBuffer) {
|
918 |
+
$this->encryptIV = $xor;
|
919 |
+
if ($start = strlen($plaintext) % $block_size) {
|
920 |
+
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
921 |
+
}
|
922 |
+
}
|
923 |
+
}
|
924 |
+
|
925 |
+
return $ciphertext;
|
926 |
+
}
|
927 |
+
|
928 |
+
/**
|
929 |
+
* Decrypts a message.
|
930 |
+
*
|
931 |
+
* If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
|
932 |
+
* it is.
|
933 |
+
*
|
934 |
+
* @see Crypt_Rijndael::encrypt()
|
935 |
+
* @access public
|
936 |
+
* @param String $ciphertext
|
937 |
+
*/
|
938 |
+
function decrypt($ciphertext)
|
939 |
+
{
|
940 |
+
if ($this->changed) {
|
941 |
+
$this->_setup();
|
942 |
+
}
|
943 |
+
if ($this->use_inline_crypt) {
|
944 |
+
$inline = $this->inline_crypt;
|
945 |
+
return $inline('decrypt', $this, $ciphertext);
|
946 |
+
}
|
947 |
+
if ($this->paddable) {
|
948 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
949 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
950 |
+
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
|
951 |
+
}
|
952 |
+
|
953 |
+
$block_size = $this->block_size;
|
954 |
+
$buffer = &$this->debuffer;
|
955 |
+
$plaintext = '';
|
956 |
+
switch ($this->mode) {
|
957 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
958 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
959 |
+
$plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
|
960 |
+
}
|
961 |
+
break;
|
962 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
963 |
+
$xor = $this->decryptIV;
|
964 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
965 |
+
$block = substr($ciphertext, $i, $block_size);
|
966 |
+
$plaintext.= $this->_decryptBlock($block) ^ $xor;
|
967 |
+
$xor = $block;
|
968 |
+
}
|
969 |
+
if ($this->continuousBuffer) {
|
970 |
+
$this->decryptIV = $xor;
|
971 |
+
}
|
972 |
+
break;
|
973 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
974 |
+
$xor = $this->decryptIV;
|
975 |
+
if (strlen($buffer['ciphertext'])) {
|
976 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
977 |
+
$block = substr($ciphertext, $i, $block_size);
|
978 |
+
if (strlen($block) > strlen($buffer['ciphertext'])) {
|
979 |
+
$buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
980 |
+
}
|
981 |
+
$key = $this->_string_shift($buffer['ciphertext'], $block_size);
|
982 |
+
$plaintext.= $block ^ $key;
|
983 |
+
}
|
984 |
+
} else {
|
985 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
986 |
+
$block = substr($ciphertext, $i, $block_size);
|
987 |
+
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
988 |
+
$plaintext.= $block ^ $key;
|
989 |
+
}
|
990 |
+
}
|
991 |
+
if ($this->continuousBuffer) {
|
992 |
+
$this->decryptIV = $xor;
|
993 |
+
if ($start = strlen($ciphertext) % $block_size) {
|
994 |
+
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
|
995 |
+
}
|
996 |
+
}
|
997 |
+
break;
|
998 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
999 |
+
if ($this->continuousBuffer) {
|
1000 |
+
$iv = &$this->decryptIV;
|
1001 |
+
$pos = &$buffer['pos'];
|
1002 |
+
} else {
|
1003 |
+
$iv = $this->decryptIV;
|
1004 |
+
$pos = 0;
|
1005 |
+
}
|
1006 |
+
$len = strlen($ciphertext);
|
1007 |
+
$i = 0;
|
1008 |
+
if ($pos) {
|
1009 |
+
$orig_pos = $pos;
|
1010 |
+
$max = $block_size - $pos;
|
1011 |
+
if ($len >= $max) {
|
1012 |
+
$i = $max;
|
1013 |
+
$len-= $max;
|
1014 |
+
$pos = 0;
|
1015 |
+
} else {
|
1016 |
+
$i = $len;
|
1017 |
+
$pos+= $len;
|
1018 |
+
$len = 0;
|
1019 |
+
}
|
1020 |
+
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
|
1021 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
1022 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
1023 |
+
}
|
1024 |
+
while ($len >= $block_size) {
|
1025 |
+
$iv = $this->_encryptBlock($iv);
|
1026 |
+
$cb = substr($ciphertext, $i, $block_size);
|
1027 |
+
$plaintext.= $iv ^ $cb;
|
1028 |
+
$iv = $cb;
|
1029 |
+
$len-= $block_size;
|
1030 |
+
$i+= $block_size;
|
1031 |
+
}
|
1032 |
+
if ($len) {
|
1033 |
+
$iv = $this->_encryptBlock($iv);
|
1034 |
+
$plaintext.= $iv ^ substr($ciphertext, $i);
|
1035 |
+
$iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
|
1036 |
+
$pos = $len;
|
1037 |
+
}
|
1038 |
+
break;
|
1039 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
1040 |
+
$xor = $this->decryptIV;
|
1041 |
+
if (strlen($buffer['xor'])) {
|
1042 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
1043 |
+
$block = substr($ciphertext, $i, $block_size);
|
1044 |
+
if (strlen($block) > strlen($buffer['xor'])) {
|
1045 |
+
$xor = $this->_encryptBlock($xor);
|
1046 |
+
$buffer['xor'].= $xor;
|
1047 |
+
}
|
1048 |
+
$key = $this->_string_shift($buffer['xor'], $block_size);
|
1049 |
+
$plaintext.= $block ^ $key;
|
1050 |
+
}
|
1051 |
+
} else {
|
1052 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
1053 |
+
$xor = $this->_encryptBlock($xor);
|
1054 |
+
$plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
|
1055 |
+
}
|
1056 |
+
$key = $xor;
|
1057 |
+
}
|
1058 |
+
if ($this->continuousBuffer) {
|
1059 |
+
$this->decryptIV = $xor;
|
1060 |
+
if ($start = strlen($ciphertext) % $block_size) {
|
1061 |
+
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
1062 |
+
}
|
1063 |
+
}
|
1064 |
+
}
|
1065 |
+
|
1066 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
/**
|
1070 |
+
* Encrypts a block
|
1071 |
+
*
|
1072 |
+
* @access private
|
1073 |
+
* @param String $in
|
1074 |
+
* @return String
|
1075 |
+
*/
|
1076 |
+
function _encryptBlock($in)
|
1077 |
+
{
|
1078 |
+
$state = array();
|
1079 |
+
$words = unpack('N*word', $in);
|
1080 |
+
|
1081 |
+
$w = $this->w;
|
1082 |
+
$t0 = $this->t0;
|
1083 |
+
$t1 = $this->t1;
|
1084 |
+
$t2 = $this->t2;
|
1085 |
+
$t3 = $this->t3;
|
1086 |
+
$Nb = $this->Nb;
|
1087 |
+
$Nr = $this->Nr;
|
1088 |
+
$c = $this->c;
|
1089 |
+
|
1090 |
+
// addRoundKey
|
1091 |
+
$i = -1;
|
1092 |
+
foreach ($words as $word) {
|
1093 |
+
$state[] = $word ^ $w[0][++$i];
|
1094 |
+
}
|
1095 |
+
|
1096 |
+
// fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
|
1097 |
+
// subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
|
1098 |
+
// Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
|
1099 |
+
// Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
|
1100 |
+
// Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
|
1101 |
+
// equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
|
1102 |
+
|
1103 |
+
// [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
|
1104 |
+
$temp = array();
|
1105 |
+
for ($round = 1; $round < $Nr; ++$round) {
|
1106 |
+
$i = 0; // $c[0] == 0
|
1107 |
+
$j = $c[1];
|
1108 |
+
$k = $c[2];
|
1109 |
+
$l = $c[3];
|
1110 |
+
|
1111 |
+
while ($i < $Nb) {
|
1112 |
+
$temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
|
1113 |
+
$t1[$state[$j] >> 16 & 0x000000FF] ^
|
1114 |
+
$t2[$state[$k] >> 8 & 0x000000FF] ^
|
1115 |
+
$t3[$state[$l] & 0x000000FF] ^
|
1116 |
+
$w[$round][$i];
|
1117 |
+
++$i;
|
1118 |
+
$j = ($j + 1) % $Nb;
|
1119 |
+
$k = ($k + 1) % $Nb;
|
1120 |
+
$l = ($l + 1) % $Nb;
|
1121 |
+
}
|
1122 |
+
$state = $temp;
|
1123 |
+
}
|
1124 |
+
|
1125 |
+
// subWord
|
1126 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1127 |
+
$state[$i] = $this->_subWord($state[$i]);
|
1128 |
+
}
|
1129 |
+
|
1130 |
+
// shiftRows + addRoundKey
|
1131 |
+
$i = 0; // $c[0] == 0
|
1132 |
+
$j = $c[1];
|
1133 |
+
$k = $c[2];
|
1134 |
+
$l = $c[3];
|
1135 |
+
while ($i < $Nb) {
|
1136 |
+
$temp[$i] = ($state[$i] & 0xFF000000) ^
|
1137 |
+
($state[$j] & 0x00FF0000) ^
|
1138 |
+
($state[$k] & 0x0000FF00) ^
|
1139 |
+
($state[$l] & 0x000000FF) ^
|
1140 |
+
$w[$Nr][$i];
|
1141 |
+
++$i;
|
1142 |
+
$j = ($j + 1) % $Nb;
|
1143 |
+
$k = ($k + 1) % $Nb;
|
1144 |
+
$l = ($l + 1) % $Nb;
|
1145 |
+
}
|
1146 |
+
|
1147 |
+
// 100% ugly switch/case code... but ~5% faster ("smart code" below commented out)
|
1148 |
+
switch ($Nb) {
|
1149 |
+
case 8:
|
1150 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
|
1151 |
+
case 7:
|
1152 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
|
1153 |
+
case 6:
|
1154 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
|
1155 |
+
case 5:
|
1156 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
|
1157 |
+
default:
|
1158 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
|
1159 |
+
}
|
1160 |
+
/*
|
1161 |
+
$state = $temp;
|
1162 |
+
|
1163 |
+
array_unshift($state, 'N*');
|
1164 |
+
|
1165 |
+
return call_user_func_array('pack', $state);
|
1166 |
+
*/
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
/**
|
1170 |
+
* Decrypts a block
|
1171 |
+
*
|
1172 |
+
* @access private
|
1173 |
+
* @param String $in
|
1174 |
+
* @return String
|
1175 |
+
*/
|
1176 |
+
function _decryptBlock($in)
|
1177 |
+
{
|
1178 |
+
$state = array();
|
1179 |
+
$words = unpack('N*word', $in);
|
1180 |
+
|
1181 |
+
$dw = $this->dw;
|
1182 |
+
$dt0 = $this->dt0;
|
1183 |
+
$dt1 = $this->dt1;
|
1184 |
+
$dt2 = $this->dt2;
|
1185 |
+
$dt3 = $this->dt3;
|
1186 |
+
$Nb = $this->Nb;
|
1187 |
+
$Nr = $this->Nr;
|
1188 |
+
$c = $this->c;
|
1189 |
+
|
1190 |
+
// addRoundKey
|
1191 |
+
$i = -1;
|
1192 |
+
foreach ($words as $word) {
|
1193 |
+
$state[] = $word ^ $dw[$Nr][++$i];
|
1194 |
+
}
|
1195 |
+
|
1196 |
+
$temp = array();
|
1197 |
+
for ($round = $Nr - 1; $round > 0; --$round) {
|
1198 |
+
$i = 0; // $c[0] == 0
|
1199 |
+
$j = $Nb - $c[1];
|
1200 |
+
$k = $Nb - $c[2];
|
1201 |
+
$l = $Nb - $c[3];
|
1202 |
+
|
1203 |
+
while ($i < $Nb) {
|
1204 |
+
$temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
|
1205 |
+
$dt1[$state[$j] >> 16 & 0x000000FF] ^
|
1206 |
+
$dt2[$state[$k] >> 8 & 0x000000FF] ^
|
1207 |
+
$dt3[$state[$l] & 0x000000FF] ^
|
1208 |
+
$dw[$round][$i];
|
1209 |
+
++$i;
|
1210 |
+
$j = ($j + 1) % $Nb;
|
1211 |
+
$k = ($k + 1) % $Nb;
|
1212 |
+
$l = ($l + 1) % $Nb;
|
1213 |
+
}
|
1214 |
+
$state = $temp;
|
1215 |
+
}
|
1216 |
+
|
1217 |
+
// invShiftRows + invSubWord + addRoundKey
|
1218 |
+
$i = 0; // $c[0] == 0
|
1219 |
+
$j = $Nb - $c[1];
|
1220 |
+
$k = $Nb - $c[2];
|
1221 |
+
$l = $Nb - $c[3];
|
1222 |
+
|
1223 |
+
while ($i < $Nb) {
|
1224 |
+
$temp[$i] = $dw[0][$i] ^
|
1225 |
+
$this->_invSubWord(($state[$i] & 0xFF000000) |
|
1226 |
+
($state[$j] & 0x00FF0000) |
|
1227 |
+
($state[$k] & 0x0000FF00) |
|
1228 |
+
($state[$l] & 0x000000FF));
|
1229 |
+
++$i;
|
1230 |
+
$j = ($j + 1) % $Nb;
|
1231 |
+
$k = ($k + 1) % $Nb;
|
1232 |
+
$l = ($l + 1) % $Nb;
|
1233 |
+
}
|
1234 |
+
|
1235 |
+
switch ($Nb) {
|
1236 |
+
case 8:
|
1237 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
|
1238 |
+
case 7:
|
1239 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
|
1240 |
+
case 6:
|
1241 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
|
1242 |
+
case 5:
|
1243 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
|
1244 |
+
default:
|
1245 |
+
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
|
1246 |
+
}
|
1247 |
+
/*
|
1248 |
+
$state = $temp;
|
1249 |
+
|
1250 |
+
array_unshift($state, 'N*');
|
1251 |
+
|
1252 |
+
return call_user_func_array('pack', $state);
|
1253 |
+
*/
|
1254 |
+
}
|
1255 |
+
|
1256 |
+
/**
|
1257 |
+
* Setup Rijndael
|
1258 |
+
*
|
1259 |
+
* Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
|
1260 |
+
* key schedule.
|
1261 |
+
*
|
1262 |
+
* @access private
|
1263 |
+
*/
|
1264 |
+
function _setup()
|
1265 |
+
{
|
1266 |
+
// Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
|
1267 |
+
// See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
|
1268 |
+
static $rcon = array(0,
|
1269 |
+
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
|
1270 |
+
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
|
1271 |
+
0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
|
1272 |
+
0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
|
1273 |
+
0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
|
1274 |
+
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
|
1275 |
+
);
|
1276 |
+
|
1277 |
+
if (!$this->explicit_key_length) {
|
1278 |
+
// we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
|
1279 |
+
$length = strlen($this->key) >> 2;
|
1280 |
+
if ($length > 8) {
|
1281 |
+
$length = 8;
|
1282 |
+
} else if ($length < 4) {
|
1283 |
+
$length = 4;
|
1284 |
+
}
|
1285 |
+
$this->Nk = $length;
|
1286 |
+
$this->key_size = $length << 2;
|
1287 |
+
}
|
1288 |
+
|
1289 |
+
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
|
1290 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
|
1291 |
+
|
1292 |
+
// see Rijndael-ammended.pdf#page=44
|
1293 |
+
$this->Nr = max($this->Nk, $this->Nb) + 6;
|
1294 |
+
|
1295 |
+
// shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
|
1296 |
+
// "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
|
1297 |
+
// shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
|
1298 |
+
// "Table 2: Shift offsets for different block lengths"
|
1299 |
+
switch ($this->Nb) {
|
1300 |
+
case 4:
|
1301 |
+
case 5:
|
1302 |
+
case 6:
|
1303 |
+
$this->c = array(0, 1, 2, 3);
|
1304 |
+
break;
|
1305 |
+
case 7:
|
1306 |
+
$this->c = array(0, 1, 2, 4);
|
1307 |
+
break;
|
1308 |
+
case 8:
|
1309 |
+
$this->c = array(0, 1, 3, 4);
|
1310 |
+
}
|
1311 |
+
|
1312 |
+
$key = $this->key;
|
1313 |
+
|
1314 |
+
$w = array_values(unpack('N*words', $key));
|
1315 |
+
|
1316 |
+
$length = $this->Nb * ($this->Nr + 1);
|
1317 |
+
for ($i = $this->Nk; $i < $length; $i++) {
|
1318 |
+
$temp = $w[$i - 1];
|
1319 |
+
if ($i % $this->Nk == 0) {
|
1320 |
+
// according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
|
1321 |
+
// on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
|
1322 |
+
// 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
|
1323 |
+
// with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
|
1324 |
+
$temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
|
1325 |
+
$temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
|
1326 |
+
} else if ($this->Nk > 6 && $i % $this->Nk == 4) {
|
1327 |
+
$temp = $this->_subWord($temp);
|
1328 |
+
}
|
1329 |
+
$w[$i] = $w[$i - $this->Nk] ^ $temp;
|
1330 |
+
}
|
1331 |
+
|
1332 |
+
// convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
|
1333 |
+
// and generate the inverse key schedule. more specifically,
|
1334 |
+
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
|
1335 |
+
// "The key expansion for the Inverse Cipher is defined as follows:
|
1336 |
+
// 1. Apply the Key Expansion.
|
1337 |
+
// 2. Apply InvMixColumn to all Round Keys except the first and the last one."
|
1338 |
+
// also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
|
1339 |
+
$temp = $this->w = $this->dw = array();
|
1340 |
+
for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
|
1341 |
+
if ($col == $this->Nb) {
|
1342 |
+
if ($row == 0) {
|
1343 |
+
$this->dw[0] = $this->w[0];
|
1344 |
+
} else {
|
1345 |
+
// subWord + invMixColumn + invSubWord = invMixColumn
|
1346 |
+
$j = 0;
|
1347 |
+
while ($j < $this->Nb) {
|
1348 |
+
$dw = $this->_subWord($this->w[$row][$j]);
|
1349 |
+
$temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^
|
1350 |
+
$this->dt1[$dw >> 16 & 0x000000FF] ^
|
1351 |
+
$this->dt2[$dw >> 8 & 0x000000FF] ^
|
1352 |
+
$this->dt3[$dw & 0x000000FF];
|
1353 |
+
$j++;
|
1354 |
+
}
|
1355 |
+
$this->dw[$row] = $temp;
|
1356 |
+
}
|
1357 |
+
|
1358 |
+
$col = 0;
|
1359 |
+
$row++;
|
1360 |
+
}
|
1361 |
+
$this->w[$row][$col] = $w[$i];
|
1362 |
+
}
|
1363 |
+
|
1364 |
+
$this->dw[$row] = $this->w[$row];
|
1365 |
+
|
1366 |
+
// In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending)
|
1367 |
+
if ($this->use_inline_crypt) {
|
1368 |
+
$this->dw = array_reverse($this->dw);
|
1369 |
+
$w = array_pop($this->w);
|
1370 |
+
$dw = array_pop($this->dw);
|
1371 |
+
foreach ($this->w as $r => $wr) {
|
1372 |
+
foreach ($wr as $c => $wc) {
|
1373 |
+
$w[] = $wc;
|
1374 |
+
$dw[] = $this->dw[$r][$c];
|
1375 |
+
}
|
1376 |
+
}
|
1377 |
+
$this->w = $w;
|
1378 |
+
$this->dw = $dw;
|
1379 |
+
|
1380 |
+
$this->inline_crypt_setup();
|
1381 |
+
}
|
1382 |
+
|
1383 |
+
$this->changed = false;
|
1384 |
+
}
|
1385 |
+
|
1386 |
+
/**
|
1387 |
+
* Performs S-Box substitutions
|
1388 |
+
*
|
1389 |
+
* @access private
|
1390 |
+
*/
|
1391 |
+
function _subWord($word)
|
1392 |
+
{
|
1393 |
+
$sbox = $this->sbox;
|
1394 |
+
|
1395 |
+
return $sbox[$word & 0x000000FF] |
|
1396 |
+
($sbox[$word >> 8 & 0x000000FF] << 8) |
|
1397 |
+
($sbox[$word >> 16 & 0x000000FF] << 16) |
|
1398 |
+
($sbox[$word >> 24 & 0x000000FF] << 24);
|
1399 |
+
}
|
1400 |
+
|
1401 |
+
/**
|
1402 |
+
* Performs inverse S-Box substitutions
|
1403 |
+
*
|
1404 |
+
* @access private
|
1405 |
+
*/
|
1406 |
+
function _invSubWord($word)
|
1407 |
+
{
|
1408 |
+
$isbox = $this->isbox;
|
1409 |
+
|
1410 |
+
return $isbox[$word & 0x000000FF] |
|
1411 |
+
($isbox[$word >> 8 & 0x000000FF] << 8) |
|
1412 |
+
($isbox[$word >> 16 & 0x000000FF] << 16) |
|
1413 |
+
($isbox[$word >> 24 & 0x000000FF] << 24);
|
1414 |
+
}
|
1415 |
+
|
1416 |
+
/**
|
1417 |
+
* Pad "packets".
|
1418 |
+
*
|
1419 |
+
* Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
|
1420 |
+
* of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
|
1421 |
+
* pad the input so that it is of the proper length.
|
1422 |
+
*
|
1423 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
|
1424 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
1425 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
1426 |
+
* transmitted separately)
|
1427 |
+
*
|
1428 |
+
* @see Crypt_Rijndael::disablePadding()
|
1429 |
+
* @access public
|
1430 |
+
*/
|
1431 |
+
function enablePadding()
|
1432 |
+
{
|
1433 |
+
$this->padding = true;
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
/**
|
1437 |
+
* Do not pad packets.
|
1438 |
+
*
|
1439 |
+
* @see Crypt_Rijndael::enablePadding()
|
1440 |
+
* @access public
|
1441 |
+
*/
|
1442 |
+
function disablePadding()
|
1443 |
+
{
|
1444 |
+
$this->padding = false;
|
1445 |
+
}
|
1446 |
+
|
1447 |
+
/**
|
1448 |
+
* Pads a string
|
1449 |
+
*
|
1450 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
|
1451 |
+
* $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
|
1452 |
+
* chr($block_size - (strlen($text) % $block_size)
|
1453 |
+
*
|
1454 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
1455 |
+
* and padding will, hence forth, be enabled.
|
1456 |
+
*
|
1457 |
+
* @see Crypt_Rijndael::_unpad()
|
1458 |
+
* @access private
|
1459 |
+
*/
|
1460 |
+
function _pad($text)
|
1461 |
+
{
|
1462 |
+
$length = strlen($text);
|
1463 |
+
|
1464 |
+
if (!$this->padding) {
|
1465 |
+
if ($length % $this->block_size == 0) {
|
1466 |
+
return $text;
|
1467 |
+
} else {
|
1468 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
|
1469 |
+
$this->padding = true;
|
1470 |
+
}
|
1471 |
+
}
|
1472 |
+
|
1473 |
+
$pad = $this->block_size - ($length % $this->block_size);
|
1474 |
+
|
1475 |
+
return str_pad($text, $length + $pad, chr($pad));
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
/**
|
1479 |
+
* Unpads a string.
|
1480 |
+
*
|
1481 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
1482 |
+
* and false will be returned.
|
1483 |
+
*
|
1484 |
+
* @see Crypt_Rijndael::_pad()
|
1485 |
+
* @access private
|
1486 |
+
*/
|
1487 |
+
function _unpad($text)
|
1488 |
+
{
|
1489 |
+
if (!$this->padding) {
|
1490 |
+
return $text;
|
1491 |
+
}
|
1492 |
+
|
1493 |
+
$length = ord($text[strlen($text) - 1]);
|
1494 |
+
|
1495 |
+
if (!$length || $length > $this->block_size) {
|
1496 |
+
return false;
|
1497 |
+
}
|
1498 |
+
|
1499 |
+
return substr($text, 0, -$length);
|
1500 |
+
}
|
1501 |
+
|
1502 |
+
/**
|
1503 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
1504 |
+
*
|
1505 |
+
* Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
1506 |
+
* will yield different outputs:
|
1507 |
+
*
|
1508 |
+
* <code>
|
1509 |
+
* echo $rijndael->encrypt(substr($plaintext, 0, 16));
|
1510 |
+
* echo $rijndael->encrypt(substr($plaintext, 16, 16));
|
1511 |
+
* </code>
|
1512 |
+
* <code>
|
1513 |
+
* echo $rijndael->encrypt($plaintext);
|
1514 |
+
* </code>
|
1515 |
+
*
|
1516 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
1517 |
+
* another, as demonstrated with the following:
|
1518 |
+
*
|
1519 |
+
* <code>
|
1520 |
+
* $rijndael->encrypt(substr($plaintext, 0, 16));
|
1521 |
+
* echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
|
1522 |
+
* </code>
|
1523 |
+
* <code>
|
1524 |
+
* echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
|
1525 |
+
* </code>
|
1526 |
+
*
|
1527 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
1528 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
1529 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
1530 |
+
*
|
1531 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
|
1532 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
1533 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
1534 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
1535 |
+
*
|
1536 |
+
* @see Crypt_Rijndael::disableContinuousBuffer()
|
1537 |
+
* @access public
|
1538 |
+
*/
|
1539 |
+
function enableContinuousBuffer()
|
1540 |
+
{
|
1541 |
+
$this->continuousBuffer = true;
|
1542 |
+
}
|
1543 |
+
|
1544 |
+
/**
|
1545 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
1546 |
+
*
|
1547 |
+
* The default behavior.
|
1548 |
+
*
|
1549 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
1550 |
+
* @access public
|
1551 |
+
*/
|
1552 |
+
function disableContinuousBuffer()
|
1553 |
+
{
|
1554 |
+
$this->continuousBuffer = false;
|
1555 |
+
$this->encryptIV = $this->iv;
|
1556 |
+
$this->decryptIV = $this->iv;
|
1557 |
+
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
|
1558 |
+
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
|
1559 |
+
}
|
1560 |
+
|
1561 |
+
/**
|
1562 |
+
* String Shift
|
1563 |
+
*
|
1564 |
+
* Inspired by array_shift
|
1565 |
+
*
|
1566 |
+
* @param String $string
|
1567 |
+
* @param optional Integer $index
|
1568 |
+
* @return String
|
1569 |
+
* @access private
|
1570 |
+
*/
|
1571 |
+
function _string_shift(&$string, $index = 1)
|
1572 |
+
{
|
1573 |
+
$substr = substr($string, 0, $index);
|
1574 |
+
$string = substr($string, $index);
|
1575 |
+
return $substr;
|
1576 |
+
}
|
1577 |
+
|
1578 |
+
/**
|
1579 |
+
* Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
|
1580 |
+
*
|
1581 |
+
* @see Crypt_Rijndael::encrypt()
|
1582 |
+
* @see Crypt_Rijndael::decrypt()
|
1583 |
+
* @access private
|
1584 |
+
*/
|
1585 |
+
function inline_crypt_setup()
|
1586 |
+
{
|
1587 |
+
// Note: inline_crypt_setup() will be called only if $this->changed === true
|
1588 |
+
// So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
|
1589 |
+
// However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
|
1590 |
+
|
1591 |
+
$lambda_functions =& Crypt_Rijndael::get_lambda_functions();
|
1592 |
+
$block_size = $this->block_size;
|
1593 |
+
$mode = $this->mode;
|
1594 |
+
|
1595 |
+
// The first 5 generated $lambda_functions will use the key-words hardcoded for better performance.
|
1596 |
+
// For memory reason we limit those ultra-optimized function code to 5.
|
1597 |
+
// After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array.
|
1598 |
+
if (count($lambda_functions) < 5) {
|
1599 |
+
$w = $this->w;
|
1600 |
+
$dw = $this->dw;
|
1601 |
+
$init_encryptBlock = '';
|
1602 |
+
$init_decryptBlock = '';
|
1603 |
+
} else {
|
1604 |
+
for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
|
1605 |
+
$w[] = '$w_'.$i;
|
1606 |
+
$dw[] = '$dw_'.$i;
|
1607 |
+
}
|
1608 |
+
$init_encryptBlock = 'extract($self->w, EXTR_PREFIX_ALL, "w");';
|
1609 |
+
$init_decryptBlock = 'extract($self->dw, EXTR_PREFIX_ALL, "dw");';
|
1610 |
+
}
|
1611 |
+
|
1612 |
+
$code_hash = md5("$mode, $block_size, " . implode(',', $w));
|
1613 |
+
|
1614 |
+
if (!isset($lambda_functions[$code_hash])) {
|
1615 |
+
$Nr = $this->Nr;
|
1616 |
+
$Nb = $this->Nb;
|
1617 |
+
$c = $this->c;
|
1618 |
+
|
1619 |
+
// Generating encrypt code:
|
1620 |
+
$init_encryptBlock.= '
|
1621 |
+
$t0 = $self->t0;
|
1622 |
+
$t1 = $self->t1;
|
1623 |
+
$t2 = $self->t2;
|
1624 |
+
$t3 = $self->t3;
|
1625 |
+
$sbox = $self->sbox;';
|
1626 |
+
|
1627 |
+
$s = 'e';
|
1628 |
+
$e = 's';
|
1629 |
+
$wc = $Nb - 1;
|
1630 |
+
|
1631 |
+
// Preround: addRoundKey
|
1632 |
+
$_encryptBlock = '$in = unpack("N*", $in);'."\n";
|
1633 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1634 |
+
$_encryptBlock .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
|
1635 |
+
}
|
1636 |
+
|
1637 |
+
// Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
|
1638 |
+
for ($round = 1; $round < $Nr; ++$round) {
|
1639 |
+
list($s, $e) = array($e, $s);
|
1640 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1641 |
+
$_encryptBlock.=
|
1642 |
+
'$'.$e.$i.' =
|
1643 |
+
$t0[($'.$s.$i .' >> 24) & 0xff] ^
|
1644 |
+
$t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
|
1645 |
+
$t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
|
1646 |
+
$t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
|
1647 |
+
'.$w[++$wc].";\n";
|
1648 |
+
}
|
1649 |
+
}
|
1650 |
+
|
1651 |
+
// Finalround: subWord + shiftRows + addRoundKey
|
1652 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1653 |
+
$_encryptBlock.=
|
1654 |
+
'$'.$e.$i.' =
|
1655 |
+
$sbox[ $'.$e.$i.' & 0xff] |
|
1656 |
+
($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
|
1657 |
+
($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
|
1658 |
+
($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
|
1659 |
+
}
|
1660 |
+
$_encryptBlock .= '$in = pack("N*"'."\n";
|
1661 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1662 |
+
$_encryptBlock.= ',
|
1663 |
+
($'.$e.$i .' & 0xFF000000) ^
|
1664 |
+
($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^
|
1665 |
+
($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^
|
1666 |
+
($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^
|
1667 |
+
'.$w[$i]."\n";
|
1668 |
+
}
|
1669 |
+
$_encryptBlock .= ');';
|
1670 |
+
|
1671 |
+
// Generating decrypt code:
|
1672 |
+
$init_decryptBlock.= '
|
1673 |
+
$dt0 = $self->dt0;
|
1674 |
+
$dt1 = $self->dt1;
|
1675 |
+
$dt2 = $self->dt2;
|
1676 |
+
$dt3 = $self->dt3;
|
1677 |
+
$isbox = $self->isbox;';
|
1678 |
+
|
1679 |
+
$s = 'e';
|
1680 |
+
$e = 's';
|
1681 |
+
$wc = $Nb - 1;
|
1682 |
+
|
1683 |
+
// Preround: addRoundKey
|
1684 |
+
$_decryptBlock = '$in = unpack("N*", $in);'."\n";
|
1685 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1686 |
+
$_decryptBlock .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
|
1687 |
+
}
|
1688 |
+
|
1689 |
+
// Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
|
1690 |
+
for ($round = 1; $round < $Nr; ++$round) {
|
1691 |
+
list($s, $e) = array($e, $s);
|
1692 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1693 |
+
$_decryptBlock.=
|
1694 |
+
'$'.$e.$i.' =
|
1695 |
+
$dt0[($'.$s.$i .' >> 24) & 0xff] ^
|
1696 |
+
$dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
|
1697 |
+
$dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
|
1698 |
+
$dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
|
1699 |
+
'.$dw[++$wc].";\n";
|
1700 |
+
}
|
1701 |
+
}
|
1702 |
+
|
1703 |
+
// Finalround: subWord + shiftRows + addRoundKey
|
1704 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1705 |
+
$_decryptBlock.=
|
1706 |
+
'$'.$e.$i.' =
|
1707 |
+
$isbox[ $'.$e.$i.' & 0xff] |
|
1708 |
+
($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
|
1709 |
+
($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
|
1710 |
+
($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
|
1711 |
+
}
|
1712 |
+
$_decryptBlock .= '$in = pack("N*"'."\n";
|
1713 |
+
for ($i = 0; $i < $Nb; ++$i) {
|
1714 |
+
$_decryptBlock.= ',
|
1715 |
+
($'.$e.$i. ' & 0xFF000000) ^
|
1716 |
+
($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^
|
1717 |
+
($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^
|
1718 |
+
($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^
|
1719 |
+
'.$dw[$i]."\n";
|
1720 |
+
}
|
1721 |
+
$_decryptBlock .= ');';
|
1722 |
+
|
1723 |
+
// Generating mode of operation code:
|
1724 |
+
switch ($mode) {
|
1725 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
1726 |
+
$encrypt = $init_encryptBlock . '
|
1727 |
+
$ciphertext = "";
|
1728 |
+
$text = $self->_pad($text);
|
1729 |
+
$plaintext_len = strlen($text);
|
1730 |
+
|
1731 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1732 |
+
$in = substr($text, $i, '.$block_size.');
|
1733 |
+
'.$_encryptBlock.'
|
1734 |
+
$ciphertext.= $in;
|
1735 |
+
}
|
1736 |
+
|
1737 |
+
return $ciphertext;
|
1738 |
+
';
|
1739 |
+
|
1740 |
+
$decrypt = $init_decryptBlock . '
|
1741 |
+
$plaintext = "";
|
1742 |
+
$text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
|
1743 |
+
$ciphertext_len = strlen($text);
|
1744 |
+
|
1745 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1746 |
+
$in = substr($text, $i, '.$block_size.');
|
1747 |
+
'.$_decryptBlock.'
|
1748 |
+
$plaintext.= $in;
|
1749 |
+
}
|
1750 |
+
|
1751 |
+
return $self->_unpad($plaintext);
|
1752 |
+
';
|
1753 |
+
break;
|
1754 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
1755 |
+
$encrypt = $init_encryptBlock . '
|
1756 |
+
$ciphertext = "";
|
1757 |
+
$text = $self->_pad($text);
|
1758 |
+
$plaintext_len = strlen($text);
|
1759 |
+
|
1760 |
+
$in = $self->encryptIV;
|
1761 |
+
|
1762 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1763 |
+
$in = substr($text, $i, '.$block_size.') ^ $in;
|
1764 |
+
'.$_encryptBlock.'
|
1765 |
+
$ciphertext.= $in;
|
1766 |
+
}
|
1767 |
+
|
1768 |
+
if ($self->continuousBuffer) {
|
1769 |
+
$self->encryptIV = $in;
|
1770 |
+
}
|
1771 |
+
|
1772 |
+
return $ciphertext;
|
1773 |
+
';
|
1774 |
+
|
1775 |
+
$decrypt = $init_decryptBlock . '
|
1776 |
+
$plaintext = "";
|
1777 |
+
$text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
|
1778 |
+
$ciphertext_len = strlen($text);
|
1779 |
+
|
1780 |
+
$iv = $self->decryptIV;
|
1781 |
+
|
1782 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1783 |
+
$in = $block = substr($text, $i, '.$block_size.');
|
1784 |
+
'.$_decryptBlock.'
|
1785 |
+
$plaintext.= $in ^ $iv;
|
1786 |
+
$iv = $block;
|
1787 |
+
}
|
1788 |
+
|
1789 |
+
if ($self->continuousBuffer) {
|
1790 |
+
$self->decryptIV = $iv;
|
1791 |
+
}
|
1792 |
+
|
1793 |
+
return $self->_unpad($plaintext);
|
1794 |
+
';
|
1795 |
+
break;
|
1796 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
1797 |
+
$encrypt = $init_encryptBlock . '
|
1798 |
+
$ciphertext = "";
|
1799 |
+
$plaintext_len = strlen($text);
|
1800 |
+
$xor = $self->encryptIV;
|
1801 |
+
$buffer = &$self->enbuffer;
|
1802 |
+
|
1803 |
+
if (strlen($buffer["encrypted"])) {
|
1804 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1805 |
+
$block = substr($text, $i, '.$block_size.');
|
1806 |
+
if (strlen($block) > strlen($buffer["encrypted"])) {
|
1807 |
+
$in = $self->_generate_xor('.$block_size.', $xor);
|
1808 |
+
'.$_encryptBlock.'
|
1809 |
+
$buffer["encrypted"].= $in;
|
1810 |
+
}
|
1811 |
+
$key = $self->_string_shift($buffer["encrypted"], '.$block_size.');
|
1812 |
+
$ciphertext.= $block ^ $key;
|
1813 |
+
}
|
1814 |
+
} else {
|
1815 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1816 |
+
$block = substr($text, $i, '.$block_size.');
|
1817 |
+
$in = $self->_generate_xor('.$block_size.', $xor);
|
1818 |
+
'.$_encryptBlock.'
|
1819 |
+
$key = $in;
|
1820 |
+
$ciphertext.= $block ^ $key;
|
1821 |
+
}
|
1822 |
+
}
|
1823 |
+
if ($self->continuousBuffer) {
|
1824 |
+
$self->encryptIV = $xor;
|
1825 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
1826 |
+
$buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
|
1827 |
+
}
|
1828 |
+
}
|
1829 |
+
|
1830 |
+
return $ciphertext;
|
1831 |
+
';
|
1832 |
+
|
1833 |
+
$decrypt = $init_encryptBlock . '
|
1834 |
+
$plaintext = "";
|
1835 |
+
$ciphertext_len = strlen($text);
|
1836 |
+
$xor = $self->decryptIV;
|
1837 |
+
$buffer = &$self->debuffer;
|
1838 |
+
|
1839 |
+
if (strlen($buffer["ciphertext"])) {
|
1840 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1841 |
+
$block = substr($text, $i, '.$block_size.');
|
1842 |
+
if (strlen($block) > strlen($buffer["ciphertext"])) {
|
1843 |
+
$in = $self->_generate_xor('.$block_size.', $xor);
|
1844 |
+
'.$_encryptBlock.'
|
1845 |
+
$buffer["ciphertext"].= $in;
|
1846 |
+
}
|
1847 |
+
$key = $self->_string_shift($buffer["ciphertext"], '.$block_size.');
|
1848 |
+
$plaintext.= $block ^ $key;
|
1849 |
+
}
|
1850 |
+
} else {
|
1851 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1852 |
+
$block = substr($text, $i, '.$block_size.');
|
1853 |
+
$in = $self->_generate_xor('.$block_size.', $xor);
|
1854 |
+
'.$_encryptBlock.'
|
1855 |
+
$key = $in;
|
1856 |
+
$plaintext.= $block ^ $key;
|
1857 |
+
}
|
1858 |
+
}
|
1859 |
+
if ($self->continuousBuffer) {
|
1860 |
+
$self->decryptIV = $xor;
|
1861 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
1862 |
+
$buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
|
1863 |
+
}
|
1864 |
+
}
|
1865 |
+
|
1866 |
+
return $plaintext;
|
1867 |
+
';
|
1868 |
+
break;
|
1869 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
1870 |
+
$encrypt = $init_encryptBlock . '
|
1871 |
+
$ciphertext = "";
|
1872 |
+
$buffer = &$self->enbuffer;
|
1873 |
+
|
1874 |
+
if ($self->continuousBuffer) {
|
1875 |
+
$iv = &$self->encryptIV;
|
1876 |
+
$pos = &$buffer["pos"];
|
1877 |
+
} else {
|
1878 |
+
$iv = $self->encryptIV;
|
1879 |
+
$pos = 0;
|
1880 |
+
}
|
1881 |
+
$len = strlen($text);
|
1882 |
+
$i = 0;
|
1883 |
+
if ($pos) {
|
1884 |
+
$orig_pos = $pos;
|
1885 |
+
$max = '.$block_size.' - $pos;
|
1886 |
+
if ($len >= $max) {
|
1887 |
+
$i = $max;
|
1888 |
+
$len-= $max;
|
1889 |
+
$pos = 0;
|
1890 |
+
} else {
|
1891 |
+
$i = $len;
|
1892 |
+
$pos+= $len;
|
1893 |
+
$len = 0;
|
1894 |
+
}
|
1895 |
+
$ciphertext = substr($iv, $orig_pos) ^ $text;
|
1896 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
1897 |
+
}
|
1898 |
+
while ($len >= '.$block_size.') {
|
1899 |
+
$in = $iv;
|
1900 |
+
'.$_encryptBlock.';
|
1901 |
+
$iv = $in ^ substr($text, $i, '.$block_size.');
|
1902 |
+
$ciphertext.= $iv;
|
1903 |
+
$len-= '.$block_size.';
|
1904 |
+
$i+= '.$block_size.';
|
1905 |
+
}
|
1906 |
+
if ($len) {
|
1907 |
+
$in = $iv;
|
1908 |
+
'.$_encryptBlock.'
|
1909 |
+
$iv = $in;
|
1910 |
+
$block = $iv ^ substr($text, $i);
|
1911 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
1912 |
+
$ciphertext.= $block;
|
1913 |
+
$pos = $len;
|
1914 |
+
}
|
1915 |
+
return $ciphertext;
|
1916 |
+
';
|
1917 |
+
|
1918 |
+
$decrypt = $init_encryptBlock . '
|
1919 |
+
$plaintext = "";
|
1920 |
+
$buffer = &$self->debuffer;
|
1921 |
+
|
1922 |
+
if ($self->continuousBuffer) {
|
1923 |
+
$iv = &$self->decryptIV;
|
1924 |
+
$pos = &$buffer["pos"];
|
1925 |
+
} else {
|
1926 |
+
$iv = $self->decryptIV;
|
1927 |
+
$pos = 0;
|
1928 |
+
}
|
1929 |
+
$len = strlen($text);
|
1930 |
+
$i = 0;
|
1931 |
+
if ($pos) {
|
1932 |
+
$orig_pos = $pos;
|
1933 |
+
$max = '.$block_size.' - $pos;
|
1934 |
+
if ($len >= $max) {
|
1935 |
+
$i = $max;
|
1936 |
+
$len-= $max;
|
1937 |
+
$pos = 0;
|
1938 |
+
} else {
|
1939 |
+
$i = $len;
|
1940 |
+
$pos+= $len;
|
1941 |
+
$len = 0;
|
1942 |
+
}
|
1943 |
+
$plaintext = substr($iv, $orig_pos) ^ $text;
|
1944 |
+
$iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
|
1945 |
+
}
|
1946 |
+
while ($len >= '.$block_size.') {
|
1947 |
+
$in = $iv;
|
1948 |
+
'.$_encryptBlock.'
|
1949 |
+
$iv = $in;
|
1950 |
+
$cb = substr($text, $i, '.$block_size.');
|
1951 |
+
$plaintext.= $iv ^ $cb;
|
1952 |
+
$iv = $cb;
|
1953 |
+
$len-= '.$block_size.';
|
1954 |
+
$i+= '.$block_size.';
|
1955 |
+
}
|
1956 |
+
if ($len) {
|
1957 |
+
$in = $iv;
|
1958 |
+
'.$_encryptBlock.'
|
1959 |
+
$iv = $in;
|
1960 |
+
$plaintext.= $iv ^ substr($text, $i);
|
1961 |
+
$iv = substr_replace($iv, substr($text, $i), 0, $len);
|
1962 |
+
$pos = $len;
|
1963 |
+
}
|
1964 |
+
|
1965 |
+
return $plaintext;
|
1966 |
+
';
|
1967 |
+
break;
|
1968 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
1969 |
+
$encrypt = $init_encryptBlock . '
|
1970 |
+
$ciphertext = "";
|
1971 |
+
$plaintext_len = strlen($text);
|
1972 |
+
$xor = $self->encryptIV;
|
1973 |
+
$buffer = &$self->enbuffer;
|
1974 |
+
|
1975 |
+
if (strlen($buffer["xor"])) {
|
1976 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1977 |
+
$block = substr($text, $i, '.$block_size.');
|
1978 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
1979 |
+
$in = $xor;
|
1980 |
+
'.$_encryptBlock.'
|
1981 |
+
$xor = $in;
|
1982 |
+
$buffer["xor"].= $xor;
|
1983 |
+
}
|
1984 |
+
$key = $self->_string_shift($buffer["xor"], '.$block_size.');
|
1985 |
+
$ciphertext.= $block ^ $key;
|
1986 |
+
}
|
1987 |
+
} else {
|
1988 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1989 |
+
$in = $xor;
|
1990 |
+
'.$_encryptBlock.'
|
1991 |
+
$xor = $in;
|
1992 |
+
$ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
|
1993 |
+
}
|
1994 |
+
$key = $xor;
|
1995 |
+
}
|
1996 |
+
if ($self->continuousBuffer) {
|
1997 |
+
$self->encryptIV = $xor;
|
1998 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
1999 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
2000 |
+
}
|
2001 |
+
}
|
2002 |
+
return $ciphertext;
|
2003 |
+
';
|
2004 |
+
|
2005 |
+
$decrypt = $init_encryptBlock . '
|
2006 |
+
$plaintext = "";
|
2007 |
+
$ciphertext_len = strlen($text);
|
2008 |
+
$xor = $self->decryptIV;
|
2009 |
+
$buffer = &$self->debuffer;
|
2010 |
+
|
2011 |
+
if (strlen($buffer["xor"])) {
|
2012 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2013 |
+
$block = substr($text, $i, '.$block_size.');
|
2014 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
2015 |
+
$in = $xor;
|
2016 |
+
'.$_encryptBlock.'
|
2017 |
+
$xor = $in;
|
2018 |
+
$buffer["xor"].= $xor;
|
2019 |
+
}
|
2020 |
+
$key = $self->_string_shift($buffer["xor"], '.$block_size.');
|
2021 |
+
$plaintext.= $block ^ $key;
|
2022 |
+
}
|
2023 |
+
} else {
|
2024 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
2025 |
+
$in = $xor;
|
2026 |
+
'.$_encryptBlock.'
|
2027 |
+
$xor = $in;
|
2028 |
+
$plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
|
2029 |
+
}
|
2030 |
+
$key = $xor;
|
2031 |
+
}
|
2032 |
+
if ($self->continuousBuffer) {
|
2033 |
+
$self->decryptIV = $xor;
|
2034 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
2035 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
2036 |
+
}
|
2037 |
+
}
|
2038 |
+
return $plaintext;
|
2039 |
+
';
|
2040 |
+
break;
|
2041 |
+
}
|
2042 |
+
$lambda_functions[$code_hash] = create_function('$action, &$self, $text', 'if ($action == "encrypt") { '.$encrypt.' } else { '.$decrypt.' }');
|
2043 |
+
}
|
2044 |
+
$this->inline_crypt = $lambda_functions[$code_hash];
|
2045 |
+
}
|
2046 |
+
|
2047 |
+
/**
|
2048 |
+
* Holds the lambda_functions table (classwide)
|
2049 |
+
*
|
2050 |
+
* @see Crypt_Rijndael::inline_crypt_setup()
|
2051 |
+
* @return Array
|
2052 |
+
* @access private
|
2053 |
+
*/
|
2054 |
+
function &get_lambda_functions()
|
2055 |
+
{
|
2056 |
+
static $functions = array();
|
2057 |
+
return $functions;
|
2058 |
+
}
|
2059 |
+
}
|
2060 |
+
|
2061 |
+
// vim: ts=4:sw=4:et:
|
2062 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/Crypt/TripleDES.php
ADDED
@@ -0,0 +1,842 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of Triple DES.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Here's a short example of how to use this library:
|
12 |
+
* <code>
|
13 |
+
* <?php
|
14 |
+
* include('Crypt/TripleDES.php');
|
15 |
+
*
|
16 |
+
* $des = new Crypt_TripleDES();
|
17 |
+
*
|
18 |
+
* $des->setKey('abcdefghijklmnopqrstuvwx');
|
19 |
+
*
|
20 |
+
* $size = 10 * 1024;
|
21 |
+
* $plaintext = '';
|
22 |
+
* for ($i = 0; $i < $size; $i++) {
|
23 |
+
* $plaintext.= 'a';
|
24 |
+
* }
|
25 |
+
*
|
26 |
+
* echo $des->decrypt($des->encrypt($plaintext));
|
27 |
+
* ?>
|
28 |
+
* </code>
|
29 |
+
*
|
30 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
31 |
+
* of this software and associated documentation files (the "Software"), to deal
|
32 |
+
* in the Software without restriction, including without limitation the rights
|
33 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
34 |
+
* copies of the Software, and to permit persons to whom the Software is
|
35 |
+
* furnished to do so, subject to the following conditions:
|
36 |
+
*
|
37 |
+
* The above copyright notice and this permission notice shall be included in
|
38 |
+
* all copies or substantial portions of the Software.
|
39 |
+
*
|
40 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
41 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
42 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
43 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
44 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
45 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
46 |
+
* THE SOFTWARE.
|
47 |
+
*
|
48 |
+
* @category Crypt
|
49 |
+
* @package Crypt_TripleDES
|
50 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
51 |
+
* @copyright MMVII Jim Wigginton
|
52 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
53 |
+
* @link http://phpseclib.sourceforge.net
|
54 |
+
*/
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Include Crypt_DES
|
58 |
+
*/
|
59 |
+
if (!class_exists('Crypt_DES')) {
|
60 |
+
require_once('DES.php');
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Encrypt / decrypt using inner chaining
|
65 |
+
*
|
66 |
+
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
|
67 |
+
*/
|
68 |
+
define('CRYPT_DES_MODE_3CBC', -2);
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Encrypt / decrypt using outer chaining
|
72 |
+
*
|
73 |
+
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
|
74 |
+
*/
|
75 |
+
define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Pure-PHP implementation of Triple DES.
|
79 |
+
*
|
80 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
81 |
+
* @version 0.1.0
|
82 |
+
* @access public
|
83 |
+
* @package Crypt_TerraDES
|
84 |
+
*/
|
85 |
+
class Crypt_TripleDES extends Crypt_DES {
|
86 |
+
/**
|
87 |
+
* The Crypt_DES objects
|
88 |
+
*
|
89 |
+
* @var Array
|
90 |
+
* @access private
|
91 |
+
*/
|
92 |
+
var $des;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Default Constructor.
|
96 |
+
*
|
97 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
98 |
+
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
|
99 |
+
*
|
100 |
+
* @param optional Integer $mode
|
101 |
+
* @return Crypt_TripleDES
|
102 |
+
* @access public
|
103 |
+
*/
|
104 |
+
function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
|
105 |
+
{
|
106 |
+
if ( !defined('CRYPT_DES_MODE') ) {
|
107 |
+
switch (true) {
|
108 |
+
case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()):
|
109 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
|
110 |
+
break;
|
111 |
+
default:
|
112 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
if ( $mode == CRYPT_DES_MODE_3CBC ) {
|
117 |
+
$this->mode = CRYPT_DES_MODE_3CBC;
|
118 |
+
$this->des = array(
|
119 |
+
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
120 |
+
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
121 |
+
new Crypt_DES(CRYPT_DES_MODE_CBC)
|
122 |
+
);
|
123 |
+
$this->paddable = true;
|
124 |
+
|
125 |
+
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
|
126 |
+
$this->des[0]->disablePadding();
|
127 |
+
$this->des[1]->disablePadding();
|
128 |
+
$this->des[2]->disablePadding();
|
129 |
+
|
130 |
+
return;
|
131 |
+
}
|
132 |
+
|
133 |
+
switch ( CRYPT_DES_MODE ) {
|
134 |
+
case CRYPT_DES_MODE_MCRYPT:
|
135 |
+
switch ($mode) {
|
136 |
+
case CRYPT_DES_MODE_ECB:
|
137 |
+
$this->paddable = true;
|
138 |
+
$this->mode = MCRYPT_MODE_ECB;
|
139 |
+
break;
|
140 |
+
case CRYPT_DES_MODE_CTR:
|
141 |
+
$this->mode = 'ctr';
|
142 |
+
break;
|
143 |
+
case CRYPT_DES_MODE_CFB:
|
144 |
+
$this->mode = 'ncfb';
|
145 |
+
$this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
|
146 |
+
break;
|
147 |
+
case CRYPT_DES_MODE_OFB:
|
148 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
149 |
+
break;
|
150 |
+
case CRYPT_DES_MODE_CBC:
|
151 |
+
default:
|
152 |
+
$this->paddable = true;
|
153 |
+
$this->mode = MCRYPT_MODE_CBC;
|
154 |
+
}
|
155 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
|
156 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
|
157 |
+
|
158 |
+
break;
|
159 |
+
default:
|
160 |
+
$this->des = array(
|
161 |
+
new Crypt_DES(CRYPT_DES_MODE_ECB),
|
162 |
+
new Crypt_DES(CRYPT_DES_MODE_ECB),
|
163 |
+
new Crypt_DES(CRYPT_DES_MODE_ECB)
|
164 |
+
);
|
165 |
+
|
166 |
+
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
|
167 |
+
$this->des[0]->disablePadding();
|
168 |
+
$this->des[1]->disablePadding();
|
169 |
+
$this->des[2]->disablePadding();
|
170 |
+
|
171 |
+
switch ($mode) {
|
172 |
+
case CRYPT_DES_MODE_ECB:
|
173 |
+
case CRYPT_DES_MODE_CBC:
|
174 |
+
$this->paddable = true;
|
175 |
+
$this->mode = $mode;
|
176 |
+
break;
|
177 |
+
case CRYPT_DES_MODE_CTR:
|
178 |
+
case CRYPT_DES_MODE_CFB:
|
179 |
+
case CRYPT_DES_MODE_OFB:
|
180 |
+
$this->mode = $mode;
|
181 |
+
break;
|
182 |
+
default:
|
183 |
+
$this->paddable = true;
|
184 |
+
$this->mode = CRYPT_DES_MODE_CBC;
|
185 |
+
}
|
186 |
+
if (function_exists('create_function') && is_callable('create_function')) {
|
187 |
+
$this->inline_crypt_setup(3);
|
188 |
+
$this->use_inline_crypt = true;
|
189 |
+
}
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Sets the key.
|
195 |
+
*
|
196 |
+
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
|
197 |
+
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
|
198 |
+
*
|
199 |
+
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
200 |
+
*
|
201 |
+
* If the key is not explicitly set, it'll be assumed to be all zero's.
|
202 |
+
*
|
203 |
+
* @access public
|
204 |
+
* @param String $key
|
205 |
+
*/
|
206 |
+
function setKey($key)
|
207 |
+
{
|
208 |
+
$length = strlen($key);
|
209 |
+
if ($length > 8) {
|
210 |
+
$key = str_pad($key, 24, chr(0));
|
211 |
+
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
|
212 |
+
// http://php.net/function.mcrypt-encrypt#47973
|
213 |
+
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
|
214 |
+
} else {
|
215 |
+
$key = str_pad($key, 8, chr(0));
|
216 |
+
}
|
217 |
+
$this->key = $key;
|
218 |
+
switch (true) {
|
219 |
+
case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
|
220 |
+
case $this->mode == CRYPT_DES_MODE_3CBC:
|
221 |
+
$this->des[0]->setKey(substr($key, 0, 8));
|
222 |
+
$this->des[1]->setKey(substr($key, 8, 8));
|
223 |
+
$this->des[2]->setKey(substr($key, 16, 8));
|
224 |
+
|
225 |
+
// Merge the three DES-1-dim-key-arrays for 3DES-inline-en/decrypting
|
226 |
+
if ($this->use_inline_crypt && $this->mode != CRYPT_DES_MODE_3CBC) {
|
227 |
+
$this->keys = array(
|
228 |
+
CRYPT_DES_ENCRYPT_1DIM => array_merge(
|
229 |
+
$this->des[0]->keys[CRYPT_DES_ENCRYPT_1DIM],
|
230 |
+
$this->des[1]->keys[CRYPT_DES_DECRYPT_1DIM],
|
231 |
+
$this->des[2]->keys[CRYPT_DES_ENCRYPT_1DIM]
|
232 |
+
),
|
233 |
+
CRYPT_DES_DECRYPT_1DIM => array_merge(
|
234 |
+
$this->des[2]->keys[CRYPT_DES_DECRYPT_1DIM],
|
235 |
+
$this->des[1]->keys[CRYPT_DES_ENCRYPT_1DIM],
|
236 |
+
$this->des[0]->keys[CRYPT_DES_DECRYPT_1DIM]
|
237 |
+
),
|
238 |
+
);
|
239 |
+
}
|
240 |
+
}
|
241 |
+
$this->enchanged = $this->dechanged = true;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Sets the password.
|
246 |
+
*
|
247 |
+
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
|
248 |
+
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
|
249 |
+
* $hash, $salt, $method
|
250 |
+
*
|
251 |
+
* @param String $password
|
252 |
+
* @param optional String $method
|
253 |
+
* @access public
|
254 |
+
*/
|
255 |
+
function setPassword($password, $method = 'pbkdf2')
|
256 |
+
{
|
257 |
+
$key = '';
|
258 |
+
|
259 |
+
switch ($method) {
|
260 |
+
default: // 'pbkdf2'
|
261 |
+
list(, , $hash, $salt, $count) = func_get_args();
|
262 |
+
if (!isset($hash)) {
|
263 |
+
$hash = 'sha1';
|
264 |
+
}
|
265 |
+
// WPA and WPA2 use the SSID as the salt
|
266 |
+
if (!isset($salt)) {
|
267 |
+
$salt = 'phpseclib';
|
268 |
+
}
|
269 |
+
// RFC2898#section-4.2 uses 1,000 iterations by default
|
270 |
+
// WPA and WPA2 use 4,096.
|
271 |
+
if (!isset($count)) {
|
272 |
+
$count = 1000;
|
273 |
+
}
|
274 |
+
|
275 |
+
if (!class_exists('Crypt_Hash')) {
|
276 |
+
require_once('Crypt/Hash.php');
|
277 |
+
}
|
278 |
+
|
279 |
+
$i = 1;
|
280 |
+
while (strlen($key) < 24) { // $dkLen == 24
|
281 |
+
$hmac = new Crypt_Hash();
|
282 |
+
$hmac->setHash($hash);
|
283 |
+
$hmac->setKey($password);
|
284 |
+
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
285 |
+
for ($j = 2; $j <= $count; $j++) {
|
286 |
+
$u = $hmac->hash($u);
|
287 |
+
$f^= $u;
|
288 |
+
}
|
289 |
+
$key.= $f;
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
$this->setKey($key);
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Sets the initialization vector. (optional)
|
298 |
+
*
|
299 |
+
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
|
300 |
+
* to be all zero's.
|
301 |
+
*
|
302 |
+
* @access public
|
303 |
+
* @param String $iv
|
304 |
+
*/
|
305 |
+
function setIV($iv)
|
306 |
+
{
|
307 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
|
308 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
309 |
+
$this->des[0]->setIV($iv);
|
310 |
+
$this->des[1]->setIV($iv);
|
311 |
+
$this->des[2]->setIV($iv);
|
312 |
+
}
|
313 |
+
$this->enchanged = $this->dechanged = true;
|
314 |
+
}
|
315 |
+
|
316 |
+
/**
|
317 |
+
* Encrypts a message.
|
318 |
+
*
|
319 |
+
* @access public
|
320 |
+
* @param String $plaintext
|
321 |
+
*/
|
322 |
+
function encrypt($plaintext)
|
323 |
+
{
|
324 |
+
if ($this->paddable) {
|
325 |
+
$plaintext = $this->_pad($plaintext);
|
326 |
+
}
|
327 |
+
|
328 |
+
// if the key is smaller then 8, do what we'd normally do
|
329 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
|
330 |
+
$ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
|
331 |
+
|
332 |
+
return $ciphertext;
|
333 |
+
}
|
334 |
+
|
335 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
336 |
+
if ($this->enchanged) {
|
337 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
338 |
+
if ($this->mode == 'ncfb') {
|
339 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
340 |
+
}
|
341 |
+
$this->enchanged = false;
|
342 |
+
}
|
343 |
+
|
344 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
345 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
346 |
+
} else {
|
347 |
+
$iv = &$this->encryptIV;
|
348 |
+
$pos = &$this->enbuffer['pos'];
|
349 |
+
$len = strlen($plaintext);
|
350 |
+
$ciphertext = '';
|
351 |
+
$i = 0;
|
352 |
+
if ($pos) {
|
353 |
+
$orig_pos = $pos;
|
354 |
+
$max = 8 - $pos;
|
355 |
+
if ($len >= $max) {
|
356 |
+
$i = $max;
|
357 |
+
$len-= $max;
|
358 |
+
$pos = 0;
|
359 |
+
} else {
|
360 |
+
$i = $len;
|
361 |
+
$pos+= $len;
|
362 |
+
$len = 0;
|
363 |
+
}
|
364 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
365 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
366 |
+
$this->enbuffer['enmcrypt_init'] = true;
|
367 |
+
}
|
368 |
+
if ($len >= 8) {
|
369 |
+
if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) {
|
370 |
+
if ($this->enbuffer['enmcrypt_init'] === true) {
|
371 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
372 |
+
$this->enbuffer['enmcrypt_init'] = false;
|
373 |
+
}
|
374 |
+
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8));
|
375 |
+
$iv = substr($ciphertext, -8);
|
376 |
+
$i = strlen($ciphertext);
|
377 |
+
$len%= 8;
|
378 |
+
} else {
|
379 |
+
while ($len >= 8) {
|
380 |
+
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8);
|
381 |
+
$ciphertext.= $iv;
|
382 |
+
$len-= 8;
|
383 |
+
$i+= 8;
|
384 |
+
}
|
385 |
+
}
|
386 |
+
}
|
387 |
+
if ($len) {
|
388 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
389 |
+
$block = $iv ^ substr($plaintext, $i);
|
390 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
391 |
+
$ciphertext.= $block;
|
392 |
+
$pos = $len;
|
393 |
+
}
|
394 |
+
return $ciphertext;
|
395 |
+
}
|
396 |
+
|
397 |
+
if (!$this->continuousBuffer) {
|
398 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
399 |
+
}
|
400 |
+
|
401 |
+
return $ciphertext;
|
402 |
+
}
|
403 |
+
|
404 |
+
if (strlen($this->key) <= 8) {
|
405 |
+
$this->des[0]->mode = $this->mode;
|
406 |
+
|
407 |
+
return $this->des[0]->encrypt($plaintext);
|
408 |
+
}
|
409 |
+
|
410 |
+
if ($this->use_inline_crypt) {
|
411 |
+
$inline = $this->inline_crypt;
|
412 |
+
return $inline('encrypt', $this, $plaintext);
|
413 |
+
}
|
414 |
+
|
415 |
+
$des = $this->des;
|
416 |
+
|
417 |
+
$buffer = &$this->enbuffer;
|
418 |
+
$continuousBuffer = $this->continuousBuffer;
|
419 |
+
$ciphertext = '';
|
420 |
+
switch ($this->mode) {
|
421 |
+
case CRYPT_DES_MODE_ECB:
|
422 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
423 |
+
$block = substr($plaintext, $i, 8);
|
424 |
+
// all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
|
425 |
+
// only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
|
426 |
+
// function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
|
427 |
+
// encryption and decryption take more time, per this:
|
428 |
+
//
|
429 |
+
// http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
|
430 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
431 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
|
432 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
433 |
+
$ciphertext.= $block;
|
434 |
+
}
|
435 |
+
break;
|
436 |
+
case CRYPT_DES_MODE_CBC:
|
437 |
+
$xor = $this->encryptIV;
|
438 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
439 |
+
$block = substr($plaintext, $i, 8) ^ $xor;
|
440 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
441 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
|
442 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
443 |
+
$xor = $block;
|
444 |
+
$ciphertext.= $block;
|
445 |
+
}
|
446 |
+
if ($this->continuousBuffer) {
|
447 |
+
$this->encryptIV = $xor;
|
448 |
+
}
|
449 |
+
break;
|
450 |
+
case CRYPT_DES_MODE_CTR:
|
451 |
+
$xor = $this->encryptIV;
|
452 |
+
if (strlen($buffer['encrypted'])) {
|
453 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
454 |
+
$block = substr($plaintext, $i, 8);
|
455 |
+
if (strlen($block) > strlen($buffer['encrypted'])) {
|
456 |
+
$key = $this->_generate_xor($xor);
|
457 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
458 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
459 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
460 |
+
$buffer['encrypted'].= $key;
|
461 |
+
}
|
462 |
+
$key = $this->_string_shift($buffer['encrypted']);
|
463 |
+
$ciphertext.= $block ^ $key;
|
464 |
+
}
|
465 |
+
} else {
|
466 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
467 |
+
$block = substr($plaintext, $i, 8);
|
468 |
+
$key = $this->_generate_xor($xor);
|
469 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
470 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
471 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
472 |
+
$ciphertext.= $block ^ $key;
|
473 |
+
}
|
474 |
+
}
|
475 |
+
if ($this->continuousBuffer) {
|
476 |
+
$this->encryptIV = $xor;
|
477 |
+
if ($start = strlen($plaintext) & 7) {
|
478 |
+
$buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
|
479 |
+
}
|
480 |
+
}
|
481 |
+
break;
|
482 |
+
case CRYPT_DES_MODE_CFB:
|
483 |
+
if (strlen($buffer['xor'])) {
|
484 |
+
$ciphertext = $plaintext ^ $buffer['xor'];
|
485 |
+
$iv = $buffer['encrypted'] . $ciphertext;
|
486 |
+
$start = strlen($ciphertext);
|
487 |
+
$buffer['encrypted'].= $ciphertext;
|
488 |
+
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
|
489 |
+
} else {
|
490 |
+
$ciphertext = '';
|
491 |
+
$iv = $this->encryptIV;
|
492 |
+
$start = 0;
|
493 |
+
}
|
494 |
+
|
495 |
+
for ($i = $start; $i < strlen($plaintext); $i+=8) {
|
496 |
+
$block = substr($plaintext, $i, 8);
|
497 |
+
$iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
498 |
+
$iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
|
499 |
+
$xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
500 |
+
|
501 |
+
$iv = $block ^ $xor;
|
502 |
+
if ($continuousBuffer && strlen($iv) != 8) {
|
503 |
+
$buffer = array(
|
504 |
+
'encrypted' => $iv,
|
505 |
+
'xor' => substr($xor, strlen($iv))
|
506 |
+
);
|
507 |
+
}
|
508 |
+
$ciphertext.= $iv;
|
509 |
+
}
|
510 |
+
|
511 |
+
if ($this->continuousBuffer) {
|
512 |
+
$this->encryptIV = $iv;
|
513 |
+
}
|
514 |
+
break;
|
515 |
+
case CRYPT_DES_MODE_OFB:
|
516 |
+
$xor = $this->encryptIV;
|
517 |
+
if (strlen($buffer['xor'])) {
|
518 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
519 |
+
$block = substr($plaintext, $i, 8);
|
520 |
+
if (strlen($block) > strlen($buffer['xor'])) {
|
521 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
522 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
523 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
524 |
+
$buffer['xor'].= $xor;
|
525 |
+
}
|
526 |
+
$key = $this->_string_shift($buffer['xor']);
|
527 |
+
$ciphertext.= $block ^ $key;
|
528 |
+
}
|
529 |
+
} else {
|
530 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
531 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
532 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
533 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
534 |
+
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
|
535 |
+
}
|
536 |
+
$key = $xor;
|
537 |
+
}
|
538 |
+
if ($this->continuousBuffer) {
|
539 |
+
$this->encryptIV = $xor;
|
540 |
+
if ($start = strlen($plaintext) & 7) {
|
541 |
+
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
542 |
+
}
|
543 |
+
}
|
544 |
+
}
|
545 |
+
|
546 |
+
return $ciphertext;
|
547 |
+
}
|
548 |
+
|
549 |
+
/**
|
550 |
+
* Decrypts a message.
|
551 |
+
*
|
552 |
+
* @access public
|
553 |
+
* @param String $ciphertext
|
554 |
+
*/
|
555 |
+
function decrypt($ciphertext)
|
556 |
+
{
|
557 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
|
558 |
+
$plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
|
559 |
+
|
560 |
+
return $this->_unpad($plaintext);
|
561 |
+
}
|
562 |
+
|
563 |
+
if ($this->paddable) {
|
564 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
565 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
566 |
+
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
|
567 |
+
}
|
568 |
+
|
569 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
570 |
+
if ($this->dechanged) {
|
571 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
572 |
+
if ($this->mode == 'ncfb') {
|
573 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
574 |
+
}
|
575 |
+
$this->dechanged = false;
|
576 |
+
}
|
577 |
+
|
578 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
579 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
580 |
+
} else {
|
581 |
+
$iv = &$this->decryptIV;
|
582 |
+
$pos = &$this->debuffer['pos'];
|
583 |
+
$len = strlen($ciphertext);
|
584 |
+
$plaintext = '';
|
585 |
+
$i = 0;
|
586 |
+
if ($pos) {
|
587 |
+
$orig_pos = $pos;
|
588 |
+
$max = 8 - $pos;
|
589 |
+
if ($len >= $max) {
|
590 |
+
$i = $max;
|
591 |
+
$len-= $max;
|
592 |
+
$pos = 0;
|
593 |
+
} else {
|
594 |
+
$i = $len;
|
595 |
+
$pos+= $len;
|
596 |
+
$len = 0;
|
597 |
+
}
|
598 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
599 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
600 |
+
}
|
601 |
+
if ($len >= 8) {
|
602 |
+
$cb = substr($ciphertext, $i, $len - $len % 8);
|
603 |
+
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
604 |
+
$iv = substr($cb, -8);
|
605 |
+
$len%= 8;
|
606 |
+
}
|
607 |
+
if ($len) {
|
608 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
609 |
+
$cb = substr($ciphertext, -$len);
|
610 |
+
$plaintext.= $iv ^ $cb;
|
611 |
+
$iv = substr_replace($iv, $cb, 0, $len);
|
612 |
+
$pos = $len;
|
613 |
+
}
|
614 |
+
return $plaintext;
|
615 |
+
}
|
616 |
+
|
617 |
+
if (!$this->continuousBuffer) {
|
618 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
619 |
+
}
|
620 |
+
|
621 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
622 |
+
}
|
623 |
+
|
624 |
+
if (strlen($this->key) <= 8) {
|
625 |
+
$this->des[0]->mode = $this->mode;
|
626 |
+
$plaintext = $this->des[0]->decrypt($ciphertext);
|
627 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
628 |
+
}
|
629 |
+
|
630 |
+
if ($this->use_inline_crypt) {
|
631 |
+
$inline = $this->inline_crypt;
|
632 |
+
return $inline('decrypt', $this, $ciphertext);
|
633 |
+
}
|
634 |
+
|
635 |
+
$des = $this->des;
|
636 |
+
|
637 |
+
$buffer = &$this->debuffer;
|
638 |
+
$continuousBuffer = $this->continuousBuffer;
|
639 |
+
$plaintext = '';
|
640 |
+
switch ($this->mode) {
|
641 |
+
case CRYPT_DES_MODE_ECB:
|
642 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
643 |
+
$block = substr($ciphertext, $i, 8);
|
644 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
|
645 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
646 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
|
647 |
+
$plaintext.= $block;
|
648 |
+
}
|
649 |
+
break;
|
650 |
+
case CRYPT_DES_MODE_CBC:
|
651 |
+
$xor = $this->decryptIV;
|
652 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
653 |
+
$orig = $block = substr($ciphertext, $i, 8);
|
654 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
|
655 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
656 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
|
657 |
+
$plaintext.= $block ^ $xor;
|
658 |
+
$xor = $orig;
|
659 |
+
}
|
660 |
+
if ($this->continuousBuffer) {
|
661 |
+
$this->decryptIV = $xor;
|
662 |
+
}
|
663 |
+
break;
|
664 |
+
case CRYPT_DES_MODE_CTR:
|
665 |
+
$xor = $this->decryptIV;
|
666 |
+
if (strlen($buffer['ciphertext'])) {
|
667 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
668 |
+
$block = substr($ciphertext, $i, 8);
|
669 |
+
if (strlen($block) > strlen($buffer['ciphertext'])) {
|
670 |
+
$key = $this->_generate_xor($xor);
|
671 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
672 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
673 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
674 |
+
$buffer['ciphertext'].= $key;
|
675 |
+
}
|
676 |
+
$key = $this->_string_shift($buffer['ciphertext']);
|
677 |
+
$plaintext.= $block ^ $key;
|
678 |
+
}
|
679 |
+
} else {
|
680 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
681 |
+
$block = substr($ciphertext, $i, 8);
|
682 |
+
$key = $this->_generate_xor($xor);
|
683 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
684 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
685 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
686 |
+
$plaintext.= $block ^ $key;
|
687 |
+
}
|
688 |
+
}
|
689 |
+
if ($this->continuousBuffer) {
|
690 |
+
$this->decryptIV = $xor;
|
691 |
+
if ($start = strlen($plaintext) & 7) {
|
692 |
+
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
|
693 |
+
}
|
694 |
+
}
|
695 |
+
break;
|
696 |
+
case CRYPT_DES_MODE_CFB:
|
697 |
+
if (strlen($buffer['ciphertext'])) {
|
698 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
699 |
+
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
700 |
+
if (strlen($buffer['ciphertext']) != 8) {
|
701 |
+
$block = $this->decryptIV;
|
702 |
+
} else {
|
703 |
+
$block = $buffer['ciphertext'];
|
704 |
+
$xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
|
705 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
706 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
707 |
+
$buffer['ciphertext'] = '';
|
708 |
+
}
|
709 |
+
$start = strlen($plaintext);
|
710 |
+
} else {
|
711 |
+
$plaintext = '';
|
712 |
+
$xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
|
713 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
714 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
715 |
+
$start = 0;
|
716 |
+
}
|
717 |
+
|
718 |
+
for ($i = $start; $i < strlen($ciphertext); $i+=8) {
|
719 |
+
$block = substr($ciphertext, $i, 8);
|
720 |
+
$plaintext.= $block ^ $xor;
|
721 |
+
if ($continuousBuffer && strlen($block) != 8) {
|
722 |
+
$buffer['ciphertext'].= $block;
|
723 |
+
$block = $xor;
|
724 |
+
} else if (strlen($block) == 8) {
|
725 |
+
$xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
726 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
727 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
728 |
+
}
|
729 |
+
}
|
730 |
+
if ($this->continuousBuffer) {
|
731 |
+
$this->decryptIV = $block;
|
732 |
+
}
|
733 |
+
break;
|
734 |
+
case CRYPT_DES_MODE_OFB:
|
735 |
+
$xor = $this->decryptIV;
|
736 |
+
if (strlen($buffer['xor'])) {
|
737 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
738 |
+
$block = substr($ciphertext, $i, 8);
|
739 |
+
if (strlen($block) > strlen($buffer['xor'])) {
|
740 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
741 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
742 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
743 |
+
$buffer['xor'].= $xor;
|
744 |
+
}
|
745 |
+
$key = $this->_string_shift($buffer['xor']);
|
746 |
+
$plaintext.= $block ^ $key;
|
747 |
+
}
|
748 |
+
} else {
|
749 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
750 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
751 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
752 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
753 |
+
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
|
754 |
+
}
|
755 |
+
$key = $xor;
|
756 |
+
}
|
757 |
+
if ($this->continuousBuffer) {
|
758 |
+
$this->decryptIV = $xor;
|
759 |
+
if ($start = strlen($ciphertext) & 7) {
|
760 |
+
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
|
761 |
+
}
|
762 |
+
}
|
763 |
+
}
|
764 |
+
|
765 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
766 |
+
}
|
767 |
+
|
768 |
+
/**
|
769 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
770 |
+
*
|
771 |
+
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
772 |
+
* will yield different outputs:
|
773 |
+
*
|
774 |
+
* <code>
|
775 |
+
* echo $des->encrypt(substr($plaintext, 0, 8));
|
776 |
+
* echo $des->encrypt(substr($plaintext, 8, 8));
|
777 |
+
* </code>
|
778 |
+
* <code>
|
779 |
+
* echo $des->encrypt($plaintext);
|
780 |
+
* </code>
|
781 |
+
*
|
782 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
783 |
+
* another, as demonstrated with the following:
|
784 |
+
*
|
785 |
+
* <code>
|
786 |
+
* $des->encrypt(substr($plaintext, 0, 8));
|
787 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
788 |
+
* </code>
|
789 |
+
* <code>
|
790 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
791 |
+
* </code>
|
792 |
+
*
|
793 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
794 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
795 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
796 |
+
*
|
797 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
798 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
799 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
800 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
801 |
+
*
|
802 |
+
* @see Crypt_TripleDES::disableContinuousBuffer()
|
803 |
+
* @access public
|
804 |
+
*/
|
805 |
+
function enableContinuousBuffer()
|
806 |
+
{
|
807 |
+
$this->continuousBuffer = true;
|
808 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
809 |
+
$this->des[0]->enableContinuousBuffer();
|
810 |
+
$this->des[1]->enableContinuousBuffer();
|
811 |
+
$this->des[2]->enableContinuousBuffer();
|
812 |
+
}
|
813 |
+
}
|
814 |
+
|
815 |
+
/**
|
816 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
817 |
+
*
|
818 |
+
* The default behavior.
|
819 |
+
*
|
820 |
+
* @see Crypt_TripleDES::enableContinuousBuffer()
|
821 |
+
* @access public
|
822 |
+
*/
|
823 |
+
function disableContinuousBuffer()
|
824 |
+
{
|
825 |
+
$this->continuousBuffer = false;
|
826 |
+
$this->encryptIV = $this->iv;
|
827 |
+
$this->decryptIV = $this->iv;
|
828 |
+
$this->enchanged = true;
|
829 |
+
$this->dechanged = true;
|
830 |
+
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
831 |
+
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
832 |
+
|
833 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
834 |
+
$this->des[0]->disableContinuousBuffer();
|
835 |
+
$this->des[1]->disableContinuousBuffer();
|
836 |
+
$this->des[2]->disableContinuousBuffer();
|
837 |
+
}
|
838 |
+
}
|
839 |
+
}
|
840 |
+
|
841 |
+
// vim: ts=4:sw=4:et:
|
842 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/Crypt/Twofish.php
ADDED
@@ -0,0 +1,1664 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of Twofish.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Useful resources are as follows:
|
12 |
+
*
|
13 |
+
* - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
|
14 |
+
*
|
15 |
+
* Here's a short example of how to use this library:
|
16 |
+
* <code>
|
17 |
+
* <?php
|
18 |
+
* include('Crypt/Twofish.php');
|
19 |
+
*
|
20 |
+
* $Twofish = new Crypt_Twofish();
|
21 |
+
*
|
22 |
+
* $Twofish->setKey('12345678901234567890123456789012');
|
23 |
+
*
|
24 |
+
* $plaintext = str_repeat('a', 1024);
|
25 |
+
*
|
26 |
+
* echo $Twofish->decrypt($Twofish->encrypt($plaintext));
|
27 |
+
* ?>
|
28 |
+
* </code>
|
29 |
+
*
|
30 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
31 |
+
* of this software and associated documentation files (the "Software"), to deal
|
32 |
+
* in the Software without restriction, including without limitation the rights
|
33 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
34 |
+
* copies of the Software, and to permit persons to whom the Software is
|
35 |
+
* furnished to do so, subject to the following conditions:
|
36 |
+
*
|
37 |
+
* The above copyright notice and this permission notice shall be included in
|
38 |
+
* all copies or substantial portions of the Software.
|
39 |
+
*
|
40 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
41 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
42 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
43 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
44 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
45 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
46 |
+
* THE SOFTWARE.
|
47 |
+
*
|
48 |
+
* @category Crypt
|
49 |
+
* @package Crypt_Twofish
|
50 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
51 |
+
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
|
52 |
+
* @copyright MMVII Jim Wigginton
|
53 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
54 |
+
* @version 1.0
|
55 |
+
* @link http://phpseclib.sourceforge.net
|
56 |
+
*/
|
57 |
+
|
58 |
+
/**#@+
|
59 |
+
* @access public
|
60 |
+
* @see Crypt_Twofish::encrypt()
|
61 |
+
* @see Crypt_Twofish::decrypt()
|
62 |
+
*/
|
63 |
+
/**
|
64 |
+
* Encrypt / decrypt using the Counter mode.
|
65 |
+
*
|
66 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
67 |
+
*
|
68 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
69 |
+
*/
|
70 |
+
define('CRYPT_TWOFISH_MODE_CTR', -1);
|
71 |
+
/**
|
72 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
73 |
+
*
|
74 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
75 |
+
*/
|
76 |
+
define('CRYPT_TWOFISH_MODE_ECB', 1);
|
77 |
+
/**
|
78 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
79 |
+
*
|
80 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
81 |
+
*/
|
82 |
+
define('CRYPT_TWOFISH_MODE_CBC', 2);
|
83 |
+
/**
|
84 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
85 |
+
*
|
86 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
87 |
+
*/
|
88 |
+
define('CRYPT_TWOFISH_MODE_CFB', 3);
|
89 |
+
/**
|
90 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
91 |
+
*
|
92 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
93 |
+
*/
|
94 |
+
define('CRYPT_TWOFISH_MODE_OFB', 4);
|
95 |
+
/**#@-*/
|
96 |
+
|
97 |
+
/**#@+
|
98 |
+
* @access private
|
99 |
+
* @see Crypt_Twofish::Crypt_Twofish()
|
100 |
+
*/
|
101 |
+
/**
|
102 |
+
* Toggles the internal implementation
|
103 |
+
*/
|
104 |
+
define('CRYPT_TWOFISH_MODE_INTERNAL', 1);
|
105 |
+
/**
|
106 |
+
* Toggles the mcrypt implementation
|
107 |
+
*/
|
108 |
+
define('CRYPT_TWOFISH_MODE_MCRYPT', 2);
|
109 |
+
/**#@-*/
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Pure-PHP implementation of Twofish.
|
113 |
+
*
|
114 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
115 |
+
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
|
116 |
+
* @version 1.0
|
117 |
+
* @access public
|
118 |
+
* @package Crypt_Twofish
|
119 |
+
*/
|
120 |
+
class Crypt_Twofish {
|
121 |
+
/**
|
122 |
+
* The Key as String
|
123 |
+
*
|
124 |
+
* @see Crypt_Twofish::setKey()
|
125 |
+
* @var Array
|
126 |
+
* @access private
|
127 |
+
*/
|
128 |
+
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
129 |
+
|
130 |
+
/**
|
131 |
+
* The Encryption Mode
|
132 |
+
*
|
133 |
+
* @see Crypt_Twofish::Crypt_Twofish()
|
134 |
+
* @var Integer
|
135 |
+
* @access private
|
136 |
+
*/
|
137 |
+
var $mode;
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Continuous Buffer status
|
141 |
+
*
|
142 |
+
* @see Crypt_Twofish::enableContinuousBuffer()
|
143 |
+
* @var Boolean
|
144 |
+
* @access private
|
145 |
+
*/
|
146 |
+
var $continuousBuffer = false;
|
147 |
+
|
148 |
+
/**
|
149 |
+
* Padding status
|
150 |
+
*
|
151 |
+
* @see Crypt_Twofish::enablePadding()
|
152 |
+
* @var Boolean
|
153 |
+
* @access private
|
154 |
+
*/
|
155 |
+
var $padding = true;
|
156 |
+
|
157 |
+
/**
|
158 |
+
* The Initialization Vector
|
159 |
+
*
|
160 |
+
* @see Crypt_Twofish::setIV()
|
161 |
+
* @var String
|
162 |
+
* @access private
|
163 |
+
*/
|
164 |
+
var $iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
165 |
+
|
166 |
+
/**
|
167 |
+
* A "sliding" Initialization Vector
|
168 |
+
*
|
169 |
+
* @see Crypt_Twofish::enableContinuousBuffer()
|
170 |
+
* @var String
|
171 |
+
* @access private
|
172 |
+
*/
|
173 |
+
var $encryptIV = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
174 |
+
|
175 |
+
/**
|
176 |
+
* A "sliding" Initialization Vector
|
177 |
+
*
|
178 |
+
* @see Crypt_Twofish::enableContinuousBuffer()
|
179 |
+
* @var String
|
180 |
+
* @access private
|
181 |
+
*/
|
182 |
+
var $decryptIV = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
183 |
+
|
184 |
+
/**
|
185 |
+
* mcrypt resource for encryption
|
186 |
+
*
|
187 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
188 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
189 |
+
*
|
190 |
+
* @see Crypt_Twofish::encrypt()
|
191 |
+
* @var String
|
192 |
+
* @access private
|
193 |
+
*/
|
194 |
+
var $enmcrypt;
|
195 |
+
|
196 |
+
/**
|
197 |
+
* mcrypt resource for decryption
|
198 |
+
*
|
199 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
200 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
201 |
+
*
|
202 |
+
* @see Crypt_Twofish::decrypt()
|
203 |
+
* @var String
|
204 |
+
* @access private
|
205 |
+
*/
|
206 |
+
var $demcrypt;
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Does the enmcrypt resource need to be (re)initialized?
|
210 |
+
*
|
211 |
+
* @see Crypt_Twofish::setKey()
|
212 |
+
* @see Crypt_Twofish::setIV()
|
213 |
+
* @var Boolean
|
214 |
+
* @access private
|
215 |
+
*/
|
216 |
+
var $enchanged = true;
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Does the demcrypt resource need to be (re)initialized?
|
220 |
+
*
|
221 |
+
* @see Crypt_Twofish::setKey()
|
222 |
+
* @see Crypt_Twofish::setIV()
|
223 |
+
* @var Boolean
|
224 |
+
* @access private
|
225 |
+
*/
|
226 |
+
var $dechanged = true;
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Is the mode one that is paddable?
|
230 |
+
*
|
231 |
+
* @see Crypt_Twofish::Crypt_Twofish()
|
232 |
+
* @var Boolean
|
233 |
+
* @access private
|
234 |
+
*/
|
235 |
+
var $paddable = false;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
239 |
+
*
|
240 |
+
* @see Crypt_Twofish::encrypt()
|
241 |
+
* @var Array
|
242 |
+
* @access private
|
243 |
+
*/
|
244 |
+
var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
248 |
+
*
|
249 |
+
* @see Crypt_Twofish::decrypt()
|
250 |
+
* @var Array
|
251 |
+
* @access private
|
252 |
+
*/
|
253 |
+
var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
254 |
+
|
255 |
+
/**
|
256 |
+
* mcrypt resource for CFB mode
|
257 |
+
*
|
258 |
+
* @see Crypt_Twofish::encrypt()
|
259 |
+
* @see Crypt_Twofish::decrypt()
|
260 |
+
* @var String
|
261 |
+
* @access private
|
262 |
+
*/
|
263 |
+
var $ecb;
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Performance-optimized callback function for en/decrypt()
|
267 |
+
*
|
268 |
+
* @var Callback
|
269 |
+
* @access private
|
270 |
+
*/
|
271 |
+
var $inline_crypt;
|
272 |
+
|
273 |
+
/**
|
274 |
+
* Q-Table
|
275 |
+
*
|
276 |
+
* @var Array
|
277 |
+
* @access private
|
278 |
+
*/
|
279 |
+
var $q0 = array (
|
280 |
+
0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
|
281 |
+
0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
|
282 |
+
0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
|
283 |
+
0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
|
284 |
+
0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
|
285 |
+
0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
|
286 |
+
0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
|
287 |
+
0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
|
288 |
+
0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
|
289 |
+
0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
|
290 |
+
0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
|
291 |
+
0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
|
292 |
+
0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
|
293 |
+
0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
|
294 |
+
0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
|
295 |
+
0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
|
296 |
+
0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
|
297 |
+
0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
|
298 |
+
0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
|
299 |
+
0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
|
300 |
+
0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
|
301 |
+
0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
|
302 |
+
0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
|
303 |
+
0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
|
304 |
+
0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
|
305 |
+
0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
|
306 |
+
0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
|
307 |
+
0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
|
308 |
+
0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
|
309 |
+
0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
|
310 |
+
0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
|
311 |
+
0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
|
312 |
+
);
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Q-Table
|
316 |
+
*
|
317 |
+
* @var Array
|
318 |
+
* @access private
|
319 |
+
*/
|
320 |
+
var $q1 = array (
|
321 |
+
0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
|
322 |
+
0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
|
323 |
+
0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
|
324 |
+
0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
|
325 |
+
0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
|
326 |
+
0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
|
327 |
+
0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
|
328 |
+
0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
|
329 |
+
0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
|
330 |
+
0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
|
331 |
+
0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
|
332 |
+
0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
|
333 |
+
0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
|
334 |
+
0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
|
335 |
+
0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
|
336 |
+
0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
|
337 |
+
0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
|
338 |
+
0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
|
339 |
+
0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
|
340 |
+
0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
|
341 |
+
0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
|
342 |
+
0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
|
343 |
+
0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
|
344 |
+
0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
|
345 |
+
0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
|
346 |
+
0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
|
347 |
+
0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
|
348 |
+
0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
|
349 |
+
0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
|
350 |
+
0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
|
351 |
+
0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
|
352 |
+
0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
|
353 |
+
);
|
354 |
+
|
355 |
+
/**
|
356 |
+
* M-Table
|
357 |
+
*
|
358 |
+
* @var Array
|
359 |
+
* @access private
|
360 |
+
*/
|
361 |
+
var $m0 = array (
|
362 |
+
0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
|
363 |
+
0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
|
364 |
+
0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
|
365 |
+
0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
|
366 |
+
0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
|
367 |
+
0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
|
368 |
+
0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
|
369 |
+
0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
|
370 |
+
0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
|
371 |
+
0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
|
372 |
+
0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
|
373 |
+
0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
|
374 |
+
0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
|
375 |
+
0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
|
376 |
+
0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
|
377 |
+
0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
|
378 |
+
0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
|
379 |
+
0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
|
380 |
+
0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
|
381 |
+
0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
|
382 |
+
0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
|
383 |
+
0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
|
384 |
+
0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
|
385 |
+
0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
|
386 |
+
0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
|
387 |
+
0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
|
388 |
+
0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
|
389 |
+
0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
|
390 |
+
0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
|
391 |
+
0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
|
392 |
+
0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
|
393 |
+
0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
|
394 |
+
);
|
395 |
+
|
396 |
+
/**
|
397 |
+
* M-Table
|
398 |
+
*
|
399 |
+
* @var Array
|
400 |
+
* @access private
|
401 |
+
*/
|
402 |
+
var $m1 = array (
|
403 |
+
0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
|
404 |
+
0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
|
405 |
+
0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
|
406 |
+
0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
|
407 |
+
0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
|
408 |
+
0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
|
409 |
+
0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
|
410 |
+
0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
|
411 |
+
0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
|
412 |
+
0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
|
413 |
+
0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
|
414 |
+
0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
|
415 |
+
0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
|
416 |
+
0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
|
417 |
+
0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
|
418 |
+
0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
|
419 |
+
0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
|
420 |
+
0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
|
421 |
+
0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
|
422 |
+
0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
|
423 |
+
0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
|
424 |
+
0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
|
425 |
+
0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
|
426 |
+
0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
|
427 |
+
0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
|
428 |
+
0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
|
429 |
+
0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
|
430 |
+
0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
|
431 |
+
0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
|
432 |
+
0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
|
433 |
+
0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
|
434 |
+
0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
|
435 |
+
);
|
436 |
+
|
437 |
+
/**
|
438 |
+
* M-Table
|
439 |
+
*
|
440 |
+
* @var Array
|
441 |
+
* @access private
|
442 |
+
*/
|
443 |
+
var $m2 = array (
|
444 |
+
0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
|
445 |
+
0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
|
446 |
+
0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
|
447 |
+
0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
|
448 |
+
0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
|
449 |
+
0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
|
450 |
+
0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
|
451 |
+
0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
|
452 |
+
0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
|
453 |
+
0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
|
454 |
+
0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
|
455 |
+
0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
|
456 |
+
0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
|
457 |
+
0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
|
458 |
+
0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
|
459 |
+
0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
|
460 |
+
0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
|
461 |
+
0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
|
462 |
+
0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
|
463 |
+
0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
|
464 |
+
0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
|
465 |
+
0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
|
466 |
+
0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
|
467 |
+
0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
|
468 |
+
0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
|
469 |
+
0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
|
470 |
+
0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
|
471 |
+
0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
|
472 |
+
0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
|
473 |
+
0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
|
474 |
+
0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
|
475 |
+
0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
|
476 |
+
);
|
477 |
+
|
478 |
+
/**
|
479 |
+
* M-Table
|
480 |
+
*
|
481 |
+
* @var Array
|
482 |
+
* @access private
|
483 |
+
*/
|
484 |
+
var $m3 = array (
|
485 |
+
0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
|
486 |
+
0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
|
487 |
+
0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
|
488 |
+
0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
|
489 |
+
0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
|
490 |
+
0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
|
491 |
+
0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
|
492 |
+
0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
|
493 |
+
0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
|
494 |
+
0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
|
495 |
+
0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
|
496 |
+
0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
|
497 |
+
0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
|
498 |
+
0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
|
499 |
+
0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
|
500 |
+
0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
|
501 |
+
0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
|
502 |
+
0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
|
503 |
+
0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
|
504 |
+
0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
|
505 |
+
0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
|
506 |
+
0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
|
507 |
+
0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
|
508 |
+
0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
|
509 |
+
0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
|
510 |
+
0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
|
511 |
+
0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
|
512 |
+
0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
|
513 |
+
0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
|
514 |
+
0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
|
515 |
+
0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
|
516 |
+
0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
|
517 |
+
);
|
518 |
+
|
519 |
+
/**
|
520 |
+
* The Key Schedule Array
|
521 |
+
*
|
522 |
+
* @var Array
|
523 |
+
* @access private
|
524 |
+
*/
|
525 |
+
var $K = array();
|
526 |
+
|
527 |
+
/**
|
528 |
+
* The Key depended S-Table 0
|
529 |
+
*
|
530 |
+
* @var Array
|
531 |
+
* @access private
|
532 |
+
*/
|
533 |
+
var $S0 = array();
|
534 |
+
|
535 |
+
/**
|
536 |
+
* The Key depended S-Table 1
|
537 |
+
*
|
538 |
+
* @var Array
|
539 |
+
* @access private
|
540 |
+
*/
|
541 |
+
var $S1 = array();
|
542 |
+
|
543 |
+
/**
|
544 |
+
* The Key depended S-Table 2
|
545 |
+
*
|
546 |
+
* @var Array
|
547 |
+
* @access private
|
548 |
+
*/
|
549 |
+
var $S2 = array();
|
550 |
+
|
551 |
+
/**
|
552 |
+
* The Key depended S-Table 3
|
553 |
+
*
|
554 |
+
* @var Array
|
555 |
+
* @access private
|
556 |
+
*/
|
557 |
+
var $S3 = array();
|
558 |
+
|
559 |
+
/**
|
560 |
+
* Default Constructor.
|
561 |
+
*
|
562 |
+
* Determines whether or not the mcrypt extension should be used.
|
563 |
+
* If not explictly set, CRYPT_TWOFISH_MODE_CBC will be used.
|
564 |
+
*
|
565 |
+
* @param optional Integer $mode
|
566 |
+
* @access public
|
567 |
+
*/
|
568 |
+
function Crypt_Twofish($mode = CRYPT_TWOFISH_MODE_CBC)
|
569 |
+
{
|
570 |
+
if ( !defined('CRYPT_TWOFISH_MODE') ) {
|
571 |
+
switch (true) {
|
572 |
+
case extension_loaded('mcrypt') && in_array('twofish', mcrypt_list_algorithms()):
|
573 |
+
define('CRYPT_TWOFISH_MODE', CRYPT_TWOFISH_MODE_MCRYPT);
|
574 |
+
break;
|
575 |
+
default:
|
576 |
+
define('CRYPT_TWOFISH_MODE', CRYPT_TWOFISH_MODE_INTERNAL);
|
577 |
+
}
|
578 |
+
}
|
579 |
+
|
580 |
+
switch ( CRYPT_TWOFISH_MODE ) {
|
581 |
+
case CRYPT_TWOFISH_MODE_MCRYPT:
|
582 |
+
switch ($mode) {
|
583 |
+
case CRYPT_TWOFISH_MODE_ECB:
|
584 |
+
$this->paddable = true;
|
585 |
+
$this->mode = MCRYPT_MODE_ECB;
|
586 |
+
break;
|
587 |
+
case CRYPT_TWOFISH_MODE_CTR:
|
588 |
+
$this->mode = 'ctr';
|
589 |
+
break;
|
590 |
+
case CRYPT_TWOFISH_MODE_CFB:
|
591 |
+
$this->mode = 'ncfb';
|
592 |
+
$this->ecb = mcrypt_module_open(MCRYPT_TWOFISH, '', MCRYPT_MODE_ECB, '');
|
593 |
+
break;
|
594 |
+
case CRYPT_TWOFISH_MODE_OFB:
|
595 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
596 |
+
break;
|
597 |
+
case CRYPT_TWOFISH_MODE_CBC:
|
598 |
+
default:
|
599 |
+
$this->paddable = true;
|
600 |
+
$this->mode = MCRYPT_MODE_CBC;
|
601 |
+
}
|
602 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_TWOFISH, '', $this->mode, '');
|
603 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_TWOFISH, '', $this->mode, '');
|
604 |
+
|
605 |
+
break;
|
606 |
+
default:
|
607 |
+
switch ($mode) {
|
608 |
+
case CRYPT_TWOFISH_MODE_ECB:
|
609 |
+
case CRYPT_TWOFISH_MODE_CBC:
|
610 |
+
$this->paddable = true;
|
611 |
+
$this->mode = $mode;
|
612 |
+
break;
|
613 |
+
case CRYPT_TWOFISH_MODE_CTR:
|
614 |
+
case CRYPT_TWOFISH_MODE_CFB:
|
615 |
+
case CRYPT_TWOFISH_MODE_OFB:
|
616 |
+
$this->mode = $mode;
|
617 |
+
break;
|
618 |
+
default:
|
619 |
+
$this->paddable = true;
|
620 |
+
$this->mode = CRYPT_TWOFISH_MODE_CBC;
|
621 |
+
}
|
622 |
+
$this->inline_crypt_setup();
|
623 |
+
}
|
624 |
+
}
|
625 |
+
|
626 |
+
/**
|
627 |
+
* Sets the key.
|
628 |
+
*
|
629 |
+
* Keys can be of any length. Twofish, itself, requires the use of a key that's 128, 192 or 256-bits long.
|
630 |
+
* If the key is less than 256-bits we round the length up to the closest valid key length,
|
631 |
+
* padding $key with null bytes. If the key is more than 256-bits, we trim the excess bits.
|
632 |
+
*
|
633 |
+
* If the key is not explicitly set, it'll be assumed a 128 bits key to be all null bytes.
|
634 |
+
*
|
635 |
+
* @access public
|
636 |
+
* @param String $key
|
637 |
+
*/
|
638 |
+
function setKey($key)
|
639 |
+
{
|
640 |
+
$keylength = strlen($key);
|
641 |
+
switch (true) {
|
642 |
+
case $keylength <= 16:
|
643 |
+
$key.= str_repeat("\0", 16 - $keylength);
|
644 |
+
break;
|
645 |
+
case $keylength <= 24:
|
646 |
+
$key.= str_repeat("\0", 24 - $keylength);
|
647 |
+
break;
|
648 |
+
case $keylength <= 32:
|
649 |
+
$key.= str_repeat("\0", 32 - $keylength);
|
650 |
+
break;
|
651 |
+
default:
|
652 |
+
$key = substr($key, 0, 32);
|
653 |
+
}
|
654 |
+
$this->key = $key;
|
655 |
+
|
656 |
+
$this->enchanged = true;
|
657 |
+
$this->dechanged = true;
|
658 |
+
|
659 |
+
if (CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT) {
|
660 |
+
return;
|
661 |
+
}
|
662 |
+
|
663 |
+
/* Key expanding and generating the key-depended s-boxes */
|
664 |
+
$le_longs = unpack('V*', $key);
|
665 |
+
$key = unpack('C*', $key);
|
666 |
+
$m0 = $this->m0;
|
667 |
+
$m1 = $this->m1;
|
668 |
+
$m2 = $this->m2;
|
669 |
+
$m3 = $this->m3;
|
670 |
+
$q0 = $this->q0;
|
671 |
+
$q1 = $this->q1;
|
672 |
+
|
673 |
+
$K = $S0 = $S1 = $S2 = $S3 = array();
|
674 |
+
|
675 |
+
switch (strlen($this->key)) {
|
676 |
+
case 16:
|
677 |
+
list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[1], $le_longs[2]);
|
678 |
+
list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[3], $le_longs[4]);
|
679 |
+
for ($i = 0, $j = 1; $i < 40; $i+= 2,$j+= 2) {
|
680 |
+
$A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
|
681 |
+
$m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
|
682 |
+
$m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
|
683 |
+
$m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
|
684 |
+
$B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
|
685 |
+
$m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
|
686 |
+
$m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
|
687 |
+
$m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
|
688 |
+
$B = ($B << 8) | ($B >> 24 & 0xff);
|
689 |
+
$K[] = $A+= $B;
|
690 |
+
$K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
|
691 |
+
}
|
692 |
+
for ($i = 0; $i < 256; ++$i) {
|
693 |
+
$S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
|
694 |
+
$S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
|
695 |
+
$S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
|
696 |
+
$S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
|
697 |
+
}
|
698 |
+
break;
|
699 |
+
case 24:
|
700 |
+
list ($sb, $sa, $s9, $s8) = $this->mds_rem($le_longs[1], $le_longs[2]);
|
701 |
+
list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[3], $le_longs[4]);
|
702 |
+
list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[5], $le_longs[6]);
|
703 |
+
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
|
704 |
+
$A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
|
705 |
+
$m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
|
706 |
+
$m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
|
707 |
+
$m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
|
708 |
+
$B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
|
709 |
+
$m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
|
710 |
+
$m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
|
711 |
+
$m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
|
712 |
+
$B = ($B << 8) | ($B >> 24 & 0xff);
|
713 |
+
$K[] = $A+= $B;
|
714 |
+
$K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
|
715 |
+
}
|
716 |
+
for ($i = 0; $i < 256; ++$i) {
|
717 |
+
$S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
|
718 |
+
$S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
|
719 |
+
$S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
|
720 |
+
$S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
|
721 |
+
}
|
722 |
+
break;
|
723 |
+
default: // 32
|
724 |
+
list ($sf, $se, $sd, $sc) = $this->mds_rem($le_longs[1], $le_longs[2]);
|
725 |
+
list ($sb, $sa, $s9, $s8) = $this->mds_rem($le_longs[3], $le_longs[4]);
|
726 |
+
list ($s7, $s6, $s5, $s4) = $this->mds_rem($le_longs[5], $le_longs[6]);
|
727 |
+
list ($s3, $s2, $s1, $s0) = $this->mds_rem($le_longs[7], $le_longs[8]);
|
728 |
+
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
|
729 |
+
$A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
|
730 |
+
$m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
|
731 |
+
$m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
|
732 |
+
$m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
|
733 |
+
$B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
|
734 |
+
$m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
|
735 |
+
$m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
|
736 |
+
$m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
|
737 |
+
$B = ($B << 8) | ($B >> 24 & 0xff);
|
738 |
+
$K[] = $A+= $B;
|
739 |
+
$K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
|
740 |
+
}
|
741 |
+
for ($i = 0; $i < 256; ++$i) {
|
742 |
+
$S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
|
743 |
+
$S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
|
744 |
+
$S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
|
745 |
+
$S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
|
746 |
+
}
|
747 |
+
}
|
748 |
+
|
749 |
+
$this->K = $K;
|
750 |
+
$this->S0 = $S0;
|
751 |
+
$this->S1 = $S1;
|
752 |
+
$this->S2 = $S2;
|
753 |
+
$this->S3 = $S3;
|
754 |
+
}
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Sets the password.
|
758 |
+
*
|
759 |
+
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
|
760 |
+
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
|
761 |
+
* $hash, $salt, $count
|
762 |
+
*
|
763 |
+
* @param String $password
|
764 |
+
* @param optional String $method
|
765 |
+
* @access public
|
766 |
+
*/
|
767 |
+
function setPassword($password, $method = 'pbkdf2')
|
768 |
+
{
|
769 |
+
$key = '';
|
770 |
+
|
771 |
+
switch ($method) {
|
772 |
+
default: // 'pbkdf2'
|
773 |
+
list(, , $hash, $salt, $count) = func_get_args();
|
774 |
+
if (!isset($hash)) {
|
775 |
+
$hash = 'sha1';
|
776 |
+
}
|
777 |
+
// WPA and WPA2 use the SSID as the salt
|
778 |
+
if (!isset($salt)) {
|
779 |
+
$salt = 'phpseclib/salt';
|
780 |
+
}
|
781 |
+
// RFC2898#section-4.2 uses 1,000 iterations by default
|
782 |
+
// WPA and WPA2 use 4,096.
|
783 |
+
if (!isset($count)) {
|
784 |
+
$count = 1000;
|
785 |
+
}
|
786 |
+
|
787 |
+
if (!class_exists('Crypt_Hash')) {
|
788 |
+
require_once('Crypt/Hash.php');
|
789 |
+
}
|
790 |
+
|
791 |
+
$i = 1;
|
792 |
+
while (strlen($key) < 32) {
|
793 |
+
$hmac = new Crypt_Hash();
|
794 |
+
$hmac->setHash($hash);
|
795 |
+
$hmac->setKey($password);
|
796 |
+
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
797 |
+
for ($j = 2; $j <= $count; ++$j) {
|
798 |
+
$u = $hmac->hash($u);
|
799 |
+
$f^= $u;
|
800 |
+
}
|
801 |
+
$key.= $f;
|
802 |
+
}
|
803 |
+
}
|
804 |
+
|
805 |
+
$this->setKey($key);
|
806 |
+
}
|
807 |
+
|
808 |
+
/**
|
809 |
+
* Sets the initialization vector. (optional)
|
810 |
+
*
|
811 |
+
* SetIV is not required when CRYPT_TWOFISH_MODE_ECB is being used. If not explictly set, it'll be assumed
|
812 |
+
* to be all null bytes.
|
813 |
+
*
|
814 |
+
* @access public
|
815 |
+
* @param String $iv
|
816 |
+
*/
|
817 |
+
function setIV($iv)
|
818 |
+
{
|
819 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 16), 16, chr(0));
|
820 |
+
$this->enchanged = true;
|
821 |
+
$this->dechanged = true;
|
822 |
+
}
|
823 |
+
|
824 |
+
/**
|
825 |
+
* Encrypts a message.
|
826 |
+
*
|
827 |
+
* $plaintext will be padded with up to 16 additional bytes. Other Twofish implementations may or may not pad in the
|
828 |
+
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
829 |
+
* URL:
|
830 |
+
*
|
831 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
832 |
+
*
|
833 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
834 |
+
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
|
835 |
+
* length.
|
836 |
+
*
|
837 |
+
* @see Crypt_Twofish::decrypt()
|
838 |
+
* @access public
|
839 |
+
* @param String $plaintext
|
840 |
+
*/
|
841 |
+
function encrypt($plaintext)
|
842 |
+
{
|
843 |
+
if ( CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT ) {
|
844 |
+
if ($this->paddable) {
|
845 |
+
$plaintext = $this->_pad($plaintext);
|
846 |
+
}
|
847 |
+
|
848 |
+
if ($this->enchanged) {
|
849 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
850 |
+
if ($this->mode == 'ncfb') {
|
851 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
852 |
+
}
|
853 |
+
$this->enchanged = false;
|
854 |
+
}
|
855 |
+
|
856 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
857 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
858 |
+
} else {
|
859 |
+
$iv = &$this->encryptIV;
|
860 |
+
$pos = &$this->enbuffer['pos'];
|
861 |
+
$len = strlen($plaintext);
|
862 |
+
$ciphertext = '';
|
863 |
+
$i = 0;
|
864 |
+
if ($pos) {
|
865 |
+
$orig_pos = $pos;
|
866 |
+
$max = 16 - $pos;
|
867 |
+
if ($len >= $max) {
|
868 |
+
$i = $max;
|
869 |
+
$len-= $max;
|
870 |
+
$pos = 0;
|
871 |
+
} else {
|
872 |
+
$i = $len;
|
873 |
+
$pos+= $len;
|
874 |
+
$len = 0;
|
875 |
+
}
|
876 |
+
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
877 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
878 |
+
$this->enbuffer['enmcrypt_init'] = true;
|
879 |
+
}
|
880 |
+
if ($len >= 16) {
|
881 |
+
if ($this->enbuffer['enmcrypt_init'] === false || $len > 600) {
|
882 |
+
if ($this->enbuffer['enmcrypt_init'] === true) {
|
883 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
884 |
+
$this->enbuffer['enmcrypt_init'] = false;
|
885 |
+
}
|
886 |
+
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
|
887 |
+
$iv = substr($ciphertext, -16);
|
888 |
+
$len%= 16;
|
889 |
+
} else {
|
890 |
+
while ($len >= 16) {
|
891 |
+
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16);
|
892 |
+
$ciphertext.= $iv;
|
893 |
+
$len-= 16;
|
894 |
+
$i+= 16;
|
895 |
+
}
|
896 |
+
}
|
897 |
+
}
|
898 |
+
if ($len) {
|
899 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
900 |
+
$block = $iv ^ substr($plaintext, -$len);
|
901 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
902 |
+
$ciphertext.= $block;
|
903 |
+
$pos = $len;
|
904 |
+
}
|
905 |
+
return $ciphertext;
|
906 |
+
}
|
907 |
+
|
908 |
+
if (!$this->continuousBuffer) {
|
909 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
910 |
+
}
|
911 |
+
|
912 |
+
return $ciphertext;
|
913 |
+
}
|
914 |
+
|
915 |
+
if (empty($this->K)) {
|
916 |
+
$this->setKey($this->key);
|
917 |
+
}
|
918 |
+
|
919 |
+
$inline = $this->inline_crypt;
|
920 |
+
return $inline('encrypt', $this, $plaintext);
|
921 |
+
}
|
922 |
+
|
923 |
+
/**
|
924 |
+
* Decrypts a message.
|
925 |
+
*
|
926 |
+
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
|
927 |
+
*
|
928 |
+
* @see Crypt_Twofish::encrypt()
|
929 |
+
* @access public
|
930 |
+
* @param String $ciphertext
|
931 |
+
*/
|
932 |
+
function decrypt($ciphertext)
|
933 |
+
{
|
934 |
+
if ( CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT ) {
|
935 |
+
if ($this->paddable) {
|
936 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
937 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
938 |
+
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + (16 - strlen($ciphertext) % 16) % 16, chr(0));
|
939 |
+
}
|
940 |
+
|
941 |
+
if ($this->dechanged) {
|
942 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
943 |
+
if ($this->mode == 'ncfb') {
|
944 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
945 |
+
}
|
946 |
+
$this->dechanged = false;
|
947 |
+
}
|
948 |
+
|
949 |
+
if ($this->mode != 'ncfb' || !$this->continuousBuffer) {
|
950 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
951 |
+
} else {
|
952 |
+
$iv = &$this->decryptIV;
|
953 |
+
$pos = &$this->debuffer['pos'];
|
954 |
+
$len = strlen($ciphertext);
|
955 |
+
$plaintext = '';
|
956 |
+
$i = 0;
|
957 |
+
if ($pos) {
|
958 |
+
$orig_pos = $pos;
|
959 |
+
$max = 16 - $pos;
|
960 |
+
if ($len >= $max) {
|
961 |
+
$i = $max;
|
962 |
+
$len-= $max;
|
963 |
+
$pos = 0;
|
964 |
+
} else {
|
965 |
+
$i = $len;
|
966 |
+
$pos+= $len;
|
967 |
+
$len = 0;
|
968 |
+
}
|
969 |
+
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
970 |
+
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
971 |
+
}
|
972 |
+
if ($len >= 16) {
|
973 |
+
$cb = substr($ciphertext, $i, $len - $len % 16);
|
974 |
+
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
975 |
+
$iv = substr($cb, -16);
|
976 |
+
$len%= 16;
|
977 |
+
}
|
978 |
+
if ($len) {
|
979 |
+
$iv = mcrypt_generic($this->ecb, $iv);
|
980 |
+
$plaintext.= $iv ^ substr($ciphertext, -$len);
|
981 |
+
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
|
982 |
+
$pos = $len;
|
983 |
+
}
|
984 |
+
return $plaintext;
|
985 |
+
}
|
986 |
+
|
987 |
+
if (!$this->continuousBuffer) {
|
988 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
989 |
+
}
|
990 |
+
|
991 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
992 |
+
}
|
993 |
+
|
994 |
+
if (empty($this->K)) {
|
995 |
+
$this->setKey($this->key);
|
996 |
+
}
|
997 |
+
|
998 |
+
$inline = $this->inline_crypt;
|
999 |
+
return $inline('decrypt', $this, $ciphertext);
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
/**
|
1003 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
1004 |
+
*
|
1005 |
+
* @see Crypt_Twofish::disableContinuousBuffer()
|
1006 |
+
* @access public
|
1007 |
+
*/
|
1008 |
+
function enableContinuousBuffer()
|
1009 |
+
{
|
1010 |
+
$this->continuousBuffer = true;
|
1011 |
+
}
|
1012 |
+
|
1013 |
+
/**
|
1014 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
1015 |
+
*
|
1016 |
+
* The default behavior.
|
1017 |
+
*
|
1018 |
+
* @see Crypt_Twofish::enableContinuousBuffer()
|
1019 |
+
* @access public
|
1020 |
+
*/
|
1021 |
+
function disableContinuousBuffer()
|
1022 |
+
{
|
1023 |
+
$this->continuousBuffer = false;
|
1024 |
+
$this->encryptIV = $this->iv;
|
1025 |
+
$this->decryptIV = $this->iv;
|
1026 |
+
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
1027 |
+
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
|
1028 |
+
|
1029 |
+
if (CRYPT_TWOFISH_MODE == CRYPT_TWOFISH_MODE_MCRYPT) {
|
1030 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
1031 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
1032 |
+
}
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
/**
|
1036 |
+
* Pad "packets".
|
1037 |
+
*
|
1038 |
+
* Twofish works by encrypting 16 bytes at a time. If you ever need to encrypt or decrypt something that's not
|
1039 |
+
* a multiple of 16, it becomes necessary to pad the input so that it's length is a multiple of eight.
|
1040 |
+
*
|
1041 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
|
1042 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
1043 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
1044 |
+
* transmitted separately)
|
1045 |
+
*
|
1046 |
+
* @see Crypt_Twofish::disablePadding()
|
1047 |
+
* @access public
|
1048 |
+
*/
|
1049 |
+
function enablePadding()
|
1050 |
+
{
|
1051 |
+
$this->padding = true;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
/**
|
1055 |
+
* Do not pad packets.
|
1056 |
+
*
|
1057 |
+
* @see Crypt_Twofish::enablePadding()
|
1058 |
+
* @access public
|
1059 |
+
*/
|
1060 |
+
function disablePadding()
|
1061 |
+
{
|
1062 |
+
$this->padding = false;
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
/**
|
1066 |
+
* Pads a string
|
1067 |
+
*
|
1068 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (16).
|
1069 |
+
*
|
1070 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
1071 |
+
* and padding will, hence forth, be enabled.
|
1072 |
+
*
|
1073 |
+
* @see Crypt_Twofish::_unpad()
|
1074 |
+
* @access private
|
1075 |
+
*/
|
1076 |
+
function _pad($text)
|
1077 |
+
{
|
1078 |
+
$length = strlen($text);
|
1079 |
+
|
1080 |
+
if (!$this->padding) {
|
1081 |
+
if ($length % 16 == 0) {
|
1082 |
+
return $text;
|
1083 |
+
} else {
|
1084 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size (16)");
|
1085 |
+
$this->padding = true;
|
1086 |
+
}
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
$pad = 16 - ($length % 16);
|
1090 |
+
|
1091 |
+
return str_pad($text, $length + $pad, chr($pad));
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
/**
|
1095 |
+
* Unpads a string
|
1096 |
+
*
|
1097 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
1098 |
+
* and false will be returned.
|
1099 |
+
*
|
1100 |
+
* @see Crypt_Twofish::_pad()
|
1101 |
+
* @access private
|
1102 |
+
*/
|
1103 |
+
function _unpad($text)
|
1104 |
+
{
|
1105 |
+
if (!$this->padding) {
|
1106 |
+
return $text;
|
1107 |
+
}
|
1108 |
+
|
1109 |
+
$length = ord($text[strlen($text) - 1]);
|
1110 |
+
|
1111 |
+
if (!$length || $length > 16) {
|
1112 |
+
return false;
|
1113 |
+
}
|
1114 |
+
|
1115 |
+
return substr($text, 0, -$length);
|
1116 |
+
}
|
1117 |
+
|
1118 |
+
/**
|
1119 |
+
* String Shift
|
1120 |
+
*
|
1121 |
+
* Inspired by array_shift
|
1122 |
+
*
|
1123 |
+
* @param String $string
|
1124 |
+
* @return String
|
1125 |
+
* @access private
|
1126 |
+
*/
|
1127 |
+
function _string_shift(&$string)
|
1128 |
+
{
|
1129 |
+
$substr = substr($string, 0, 16);
|
1130 |
+
$string = substr($string, 16);
|
1131 |
+
return $substr;
|
1132 |
+
}
|
1133 |
+
|
1134 |
+
/**
|
1135 |
+
* Generate CTR XOR encryption key
|
1136 |
+
*
|
1137 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
1138 |
+
* plaintext / ciphertext in CTR mode.
|
1139 |
+
*
|
1140 |
+
* @see Crypt_Twofish::decrypt()
|
1141 |
+
* @see Crypt_Twofish::encrypt()
|
1142 |
+
* @access public
|
1143 |
+
* @param String $iv
|
1144 |
+
*/
|
1145 |
+
function _generate_xor(&$iv)
|
1146 |
+
{
|
1147 |
+
$xor = $iv;
|
1148 |
+
for ($j = 4; $j <= 16; $j+=4) {
|
1149 |
+
$temp = substr($iv, -$j, 4);
|
1150 |
+
switch ($temp) {
|
1151 |
+
case "\xFF\xFF\xFF\xFF":
|
1152 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
1153 |
+
break;
|
1154 |
+
case "\x7F\xFF\xFF\xFF":
|
1155 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
1156 |
+
break 2;
|
1157 |
+
default:
|
1158 |
+
extract(unpack('Ncount', $temp));
|
1159 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
1160 |
+
break 2;
|
1161 |
+
}
|
1162 |
+
}
|
1163 |
+
|
1164 |
+
return $xor;
|
1165 |
+
}
|
1166 |
+
|
1167 |
+
/**
|
1168 |
+
* mds_rem function using by the twofish cipher algorithm
|
1169 |
+
*
|
1170 |
+
* @access private
|
1171 |
+
* @param String $A
|
1172 |
+
* @param String $B
|
1173 |
+
* @return Array
|
1174 |
+
*/
|
1175 |
+
function mds_rem($A, $B)
|
1176 |
+
{
|
1177 |
+
// No gain by unrolling this loop.
|
1178 |
+
for ($i = 0; $i < 8; ++$i) {
|
1179 |
+
// Get most significant coefficient.
|
1180 |
+
$t = 0xff & ($B >> 24);
|
1181 |
+
|
1182 |
+
// Shift the others up.
|
1183 |
+
$B = ($B << 8) | (0xff & ($A >> 24));
|
1184 |
+
$A<<= 8;
|
1185 |
+
|
1186 |
+
$u = $t << 1;
|
1187 |
+
|
1188 |
+
// Subtract the modular polynomial on overflow.
|
1189 |
+
if ($t & 0x80) {
|
1190 |
+
$u^= 0x14d;
|
1191 |
+
}
|
1192 |
+
|
1193 |
+
// Remove t * (a * x^2 + 1).
|
1194 |
+
$B ^= $t ^ ($u << 16);
|
1195 |
+
|
1196 |
+
// Form u = a*t + t/a = t*(a + 1/a).
|
1197 |
+
$u^= 0x7fffffff & ($t >> 1);
|
1198 |
+
|
1199 |
+
// Add the modular polynomial on underflow.
|
1200 |
+
if ($t & 0x01) $u^= 0xa6 ;
|
1201 |
+
|
1202 |
+
// Remove t * (a + 1/a) * (x^3 + x).
|
1203 |
+
$B^= ($u << 24) | ($u << 8);
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
return array(
|
1207 |
+
0xff & $B >> 24,
|
1208 |
+
0xff & $B >> 16,
|
1209 |
+
0xff & $B >> 8,
|
1210 |
+
0xff & $B);
|
1211 |
+
}
|
1212 |
+
|
1213 |
+
/**
|
1214 |
+
* Creates performance-optimized function for de/encrypt(), storing it in $this->inline_crypt
|
1215 |
+
*
|
1216 |
+
* @access private
|
1217 |
+
*/
|
1218 |
+
function inline_crypt_setup()
|
1219 |
+
{
|
1220 |
+
$lambda_functions =& Crypt_Twofish::get_lambda_functions();
|
1221 |
+
$block_size = 16;
|
1222 |
+
$mode = $this->mode;
|
1223 |
+
$code_hash = "$mode";
|
1224 |
+
|
1225 |
+
if (!isset($lambda_functions[$code_hash])) {
|
1226 |
+
$init_cryptBlock = '
|
1227 |
+
$S0 = $self->S0;
|
1228 |
+
$S1 = $self->S1;
|
1229 |
+
$S2 = $self->S2;
|
1230 |
+
$S3 = $self->S3;
|
1231 |
+
extract($self->K, EXTR_PREFIX_ALL, "K");
|
1232 |
+
';
|
1233 |
+
|
1234 |
+
// Generating encrypt code:
|
1235 |
+
$_encryptBlock = '
|
1236 |
+
$in = unpack("V4", $in);
|
1237 |
+
$R0 = $K_0 ^ $in[1];
|
1238 |
+
$R1 = $K_1 ^ $in[2];
|
1239 |
+
$R2 = $K_2 ^ $in[3];
|
1240 |
+
$R3 = $K_3 ^ $in[4];
|
1241 |
+
';
|
1242 |
+
for ($ki = 7, $i = 0; $i < 8; ++$i) {
|
1243 |
+
$_encryptBlock.= '
|
1244 |
+
$t0 = $S0[ $R0 & 0xff] ^
|
1245 |
+
$S1[($R0 >> 8) & 0xff] ^
|
1246 |
+
$S2[($R0 >> 16) & 0xff] ^
|
1247 |
+
$S3[($R0 >> 24) & 0xff];
|
1248 |
+
$t1 = $S0[($R1 >> 24) & 0xff] ^
|
1249 |
+
$S1[ $R1 & 0xff] ^
|
1250 |
+
$S2[($R1 >> 8) & 0xff] ^
|
1251 |
+
$S3[($R1 >> 16) & 0xff];
|
1252 |
+
$R2^= ($t0 + $t1 + $K_'.(++$ki).');
|
1253 |
+
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
|
1254 |
+
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K_'.(++$ki).');
|
1255 |
+
|
1256 |
+
$t0 = $S0[ $R2 & 0xff] ^
|
1257 |
+
$S1[($R2 >> 8) & 0xff] ^
|
1258 |
+
$S2[($R2 >> 16) & 0xff] ^
|
1259 |
+
$S3[($R2 >> 24) & 0xff];
|
1260 |
+
$t1 = $S0[($R3 >> 24) & 0xff] ^
|
1261 |
+
$S1[ $R3 & 0xff] ^
|
1262 |
+
$S2[($R3 >> 8) & 0xff] ^
|
1263 |
+
$S3[($R3 >> 16) & 0xff];
|
1264 |
+
$R0^= ($t0 + $t1 + $K_'.(++$ki).');
|
1265 |
+
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
|
1266 |
+
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K_'.(++$ki).');
|
1267 |
+
';
|
1268 |
+
}
|
1269 |
+
$_encryptBlock.= '
|
1270 |
+
$in = pack("V4", $K_4 ^ $R2,
|
1271 |
+
$K_5 ^ $R3,
|
1272 |
+
$K_6 ^ $R0,
|
1273 |
+
$K_7 ^ $R1);
|
1274 |
+
';
|
1275 |
+
|
1276 |
+
// Generating decrypt code:
|
1277 |
+
$_decryptBlock = '
|
1278 |
+
$in = unpack("V4", $in);
|
1279 |
+
$R0 = $K_4 ^ $in[1];
|
1280 |
+
$R1 = $K_5 ^ $in[2];
|
1281 |
+
$R2 = $K_6 ^ $in[3];
|
1282 |
+
$R3 = $K_7 ^ $in[4];
|
1283 |
+
';
|
1284 |
+
for ($ki = 40, $i = 0; $i < 8; ++$i) {
|
1285 |
+
$_decryptBlock.= '
|
1286 |
+
$t0 = $S0[$R0 & 0xff] ^
|
1287 |
+
$S1[$R0 >> 8 & 0xff] ^
|
1288 |
+
$S2[$R0 >> 16 & 0xff] ^
|
1289 |
+
$S3[$R0 >> 24 & 0xff];
|
1290 |
+
$t1 = $S0[$R1 >> 24 & 0xff] ^
|
1291 |
+
$S1[$R1 & 0xff] ^
|
1292 |
+
$S2[$R1 >> 8 & 0xff] ^
|
1293 |
+
$S3[$R1 >> 16 & 0xff];
|
1294 |
+
$R3^= $t0 + ($t1 << 1) + $K_'.(--$ki).';
|
1295 |
+
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
|
1296 |
+
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K_'.(--$ki).');
|
1297 |
+
|
1298 |
+
$t0 = $S0[$R2 & 0xff] ^
|
1299 |
+
$S1[$R2 >> 8 & 0xff] ^
|
1300 |
+
$S2[$R2 >> 16 & 0xff] ^
|
1301 |
+
$S3[$R2 >> 24 & 0xff];
|
1302 |
+
$t1 = $S0[$R3 >> 24 & 0xff] ^
|
1303 |
+
$S1[$R3 & 0xff] ^
|
1304 |
+
$S2[$R3 >> 8 & 0xff] ^
|
1305 |
+
$S3[$R3 >> 16 & 0xff];
|
1306 |
+
$R1^= $t0 + ($t1 << 1) + $K_'.(--$ki).';
|
1307 |
+
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
|
1308 |
+
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K_'.(--$ki).');
|
1309 |
+
';
|
1310 |
+
}
|
1311 |
+
$_decryptBlock.= '
|
1312 |
+
$in = pack("V4", $K_0 ^ $R2,
|
1313 |
+
$K_1 ^ $R3,
|
1314 |
+
$K_2 ^ $R0,
|
1315 |
+
$K_3 ^ $R1);
|
1316 |
+
';
|
1317 |
+
|
1318 |
+
// Generating mode of operation code:
|
1319 |
+
switch ($mode) {
|
1320 |
+
case CRYPT_TWOFISH_MODE_ECB:
|
1321 |
+
$encrypt = '
|
1322 |
+
$ciphertext = "";
|
1323 |
+
$text = $self->_pad($text);
|
1324 |
+
$plaintext_len = strlen($text);
|
1325 |
+
|
1326 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1327 |
+
$in = substr($text, $i, '.$block_size.');
|
1328 |
+
'.$_encryptBlock.'
|
1329 |
+
$ciphertext.= $in;
|
1330 |
+
}
|
1331 |
+
|
1332 |
+
return $ciphertext;
|
1333 |
+
';
|
1334 |
+
|
1335 |
+
$decrypt = '
|
1336 |
+
$plaintext = "";
|
1337 |
+
$text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
|
1338 |
+
$ciphertext_len = strlen($text);
|
1339 |
+
|
1340 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1341 |
+
$in = substr($text, $i, '.$block_size.');
|
1342 |
+
'.$_decryptBlock.'
|
1343 |
+
$plaintext.= $in;
|
1344 |
+
}
|
1345 |
+
|
1346 |
+
return $self->_unpad($plaintext);
|
1347 |
+
';
|
1348 |
+
break;
|
1349 |
+
case CRYPT_TWOFISH_MODE_CBC:
|
1350 |
+
$encrypt = '
|
1351 |
+
$ciphertext = "";
|
1352 |
+
$text = $self->_pad($text);
|
1353 |
+
$plaintext_len = strlen($text);
|
1354 |
+
|
1355 |
+
$in = $self->encryptIV;
|
1356 |
+
|
1357 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1358 |
+
$in = substr($text, $i, '.$block_size.') ^ $in;
|
1359 |
+
'.$_encryptBlock.'
|
1360 |
+
$ciphertext.= $in;
|
1361 |
+
}
|
1362 |
+
|
1363 |
+
if ($self->continuousBuffer) {
|
1364 |
+
$self->encryptIV = $in;
|
1365 |
+
}
|
1366 |
+
|
1367 |
+
return $ciphertext;
|
1368 |
+
';
|
1369 |
+
|
1370 |
+
$decrypt = '
|
1371 |
+
$plaintext = "";
|
1372 |
+
$text = str_pad($text, strlen($text) + ('.$block_size.' - strlen($text) % '.$block_size.') % '.$block_size.', chr(0));
|
1373 |
+
$ciphertext_len = strlen($text);
|
1374 |
+
|
1375 |
+
$iv = $self->decryptIV;
|
1376 |
+
|
1377 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1378 |
+
$in = $block = substr($text, $i, '.$block_size.');
|
1379 |
+
'.$_decryptBlock.'
|
1380 |
+
$plaintext.= $in ^ $iv;
|
1381 |
+
$iv = $block;
|
1382 |
+
}
|
1383 |
+
|
1384 |
+
if ($self->continuousBuffer) {
|
1385 |
+
$self->decryptIV = $iv;
|
1386 |
+
}
|
1387 |
+
|
1388 |
+
return $self->_unpad($plaintext);
|
1389 |
+
';
|
1390 |
+
break;
|
1391 |
+
case CRYPT_TWOFISH_MODE_CTR:
|
1392 |
+
$encrypt = '
|
1393 |
+
$ciphertext = "";
|
1394 |
+
$plaintext_len = strlen($text);
|
1395 |
+
$xor = $self->encryptIV;
|
1396 |
+
$buffer = &$self->enbuffer;
|
1397 |
+
|
1398 |
+
if (strlen($buffer["encrypted"])) {
|
1399 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1400 |
+
$block = substr($text, $i, '.$block_size.');
|
1401 |
+
if (strlen($block) > strlen($buffer["encrypted"])) {
|
1402 |
+
$in = $self->_generate_xor($xor);
|
1403 |
+
'.$_encryptBlock.'
|
1404 |
+
$buffer["encrypted"].= $in;
|
1405 |
+
}
|
1406 |
+
$key = $self->_string_shift($buffer["encrypted"]);
|
1407 |
+
$ciphertext.= $block ^ $key;
|
1408 |
+
}
|
1409 |
+
} else {
|
1410 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1411 |
+
$block = substr($text, $i, '.$block_size.');
|
1412 |
+
$in = $self->_generate_xor($xor);
|
1413 |
+
'.$_encryptBlock.'
|
1414 |
+
$key = $in;
|
1415 |
+
$ciphertext.= $block ^ $key;
|
1416 |
+
}
|
1417 |
+
}
|
1418 |
+
if ($self->continuousBuffer) {
|
1419 |
+
$self->encryptIV = $xor;
|
1420 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
1421 |
+
$buffer["encrypted"] = substr($key, $start) . $buffer["encrypted"];
|
1422 |
+
}
|
1423 |
+
}
|
1424 |
+
|
1425 |
+
return $ciphertext;
|
1426 |
+
';
|
1427 |
+
|
1428 |
+
$decrypt = '
|
1429 |
+
$plaintext = "";
|
1430 |
+
$ciphertext_len = strlen($text);
|
1431 |
+
$xor = $self->decryptIV;
|
1432 |
+
$buffer = &$self->debuffer;
|
1433 |
+
|
1434 |
+
if (strlen($buffer["ciphertext"])) {
|
1435 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1436 |
+
$block = substr($text, $i, '.$block_size.');
|
1437 |
+
if (strlen($block) > strlen($buffer["ciphertext"])) {
|
1438 |
+
$in = $self->_generate_xor($xor);
|
1439 |
+
'.$_encryptBlock.'
|
1440 |
+
$buffer["ciphertext"].= $in;
|
1441 |
+
}
|
1442 |
+
$key = $self->_string_shift($buffer["ciphertext"]);
|
1443 |
+
$plaintext.= $block ^ $key;
|
1444 |
+
}
|
1445 |
+
} else {
|
1446 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1447 |
+
$block = substr($text, $i, '.$block_size.');
|
1448 |
+
$in = $self->_generate_xor($xor);
|
1449 |
+
'.$_encryptBlock.'
|
1450 |
+
$key = $in;
|
1451 |
+
$plaintext.= $block ^ $key;
|
1452 |
+
}
|
1453 |
+
}
|
1454 |
+
if ($self->continuousBuffer) {
|
1455 |
+
$self->decryptIV = $xor;
|
1456 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
1457 |
+
$buffer["ciphertext"] = substr($key, $start) . $buffer["ciphertext"];
|
1458 |
+
}
|
1459 |
+
}
|
1460 |
+
|
1461 |
+
return $plaintext;
|
1462 |
+
';
|
1463 |
+
break;
|
1464 |
+
case CRYPT_TWOFISH_MODE_CFB:
|
1465 |
+
$encrypt = '
|
1466 |
+
$ciphertext = "";
|
1467 |
+
$buffer = &$self->enbuffer;
|
1468 |
+
|
1469 |
+
if ($self->continuousBuffer) {
|
1470 |
+
$iv = &$self->encryptIV;
|
1471 |
+
$pos = &$buffer["pos"];
|
1472 |
+
} else {
|
1473 |
+
$iv = $self->encryptIV;
|
1474 |
+
$pos = 0;
|
1475 |
+
}
|
1476 |
+
$len = strlen($text);
|
1477 |
+
$i = 0;
|
1478 |
+
if ($pos) {
|
1479 |
+
$orig_pos = $pos;
|
1480 |
+
$max = '.$block_size.' - $pos;
|
1481 |
+
if ($len >= $max) {
|
1482 |
+
$i = $max;
|
1483 |
+
$len-= $max;
|
1484 |
+
$pos = 0;
|
1485 |
+
} else {
|
1486 |
+
$i = $len;
|
1487 |
+
$pos+= $len;
|
1488 |
+
$len = 0;
|
1489 |
+
}
|
1490 |
+
$ciphertext = substr($iv, $orig_pos) ^ $text;
|
1491 |
+
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
1492 |
+
}
|
1493 |
+
while ($len >= '.$block_size.') {
|
1494 |
+
$in = $iv;
|
1495 |
+
'.$_encryptBlock.';
|
1496 |
+
$iv = $in ^ substr($text, $i, '.$block_size.');
|
1497 |
+
$ciphertext.= $iv;
|
1498 |
+
$len-= '.$block_size.';
|
1499 |
+
$i+= '.$block_size.';
|
1500 |
+
}
|
1501 |
+
if ($len) {
|
1502 |
+
$in = $iv;
|
1503 |
+
'.$_encryptBlock.'
|
1504 |
+
$iv = $in;
|
1505 |
+
$block = $iv ^ substr($text, $i);
|
1506 |
+
$iv = substr_replace($iv, $block, 0, $len);
|
1507 |
+
$ciphertext.= $block;
|
1508 |
+
$pos = $len;
|
1509 |
+
}
|
1510 |
+
return $ciphertext;
|
1511 |
+
';
|
1512 |
+
|
1513 |
+
$decrypt = '
|
1514 |
+
$plaintext = "";
|
1515 |
+
$buffer = &$self->debuffer;
|
1516 |
+
|
1517 |
+
if ($self->continuousBuffer) {
|
1518 |
+
$iv = &$self->decryptIV;
|
1519 |
+
$pos = &$buffer["pos"];
|
1520 |
+
} else {
|
1521 |
+
$iv = $self->decryptIV;
|
1522 |
+
$pos = 0;
|
1523 |
+
}
|
1524 |
+
$len = strlen($text);
|
1525 |
+
$i = 0;
|
1526 |
+
if ($pos) {
|
1527 |
+
$orig_pos = $pos;
|
1528 |
+
$max = '.$block_size.' - $pos;
|
1529 |
+
if ($len >= $max) {
|
1530 |
+
$i = $max;
|
1531 |
+
$len-= $max;
|
1532 |
+
$pos = 0;
|
1533 |
+
} else {
|
1534 |
+
$i = $len;
|
1535 |
+
$pos+= $len;
|
1536 |
+
$len = 0;
|
1537 |
+
}
|
1538 |
+
$plaintext = substr($iv, $orig_pos) ^ $text;
|
1539 |
+
$iv = substr_replace($iv, substr($text, 0, $i), $orig_pos, $i);
|
1540 |
+
}
|
1541 |
+
while ($len >= '.$block_size.') {
|
1542 |
+
$in = $iv;
|
1543 |
+
'.$_encryptBlock.'
|
1544 |
+
$iv = $in;
|
1545 |
+
$cb = substr($text, $i, '.$block_size.');
|
1546 |
+
$plaintext.= $iv ^ $cb;
|
1547 |
+
$iv = $cb;
|
1548 |
+
$len-= '.$block_size.';
|
1549 |
+
$i+= '.$block_size.';
|
1550 |
+
}
|
1551 |
+
if ($len) {
|
1552 |
+
$in = $iv;
|
1553 |
+
'.$_encryptBlock.'
|
1554 |
+
$iv = $in;
|
1555 |
+
$plaintext.= $iv ^ substr($text, $i);
|
1556 |
+
$iv = substr_replace($iv, substr($text, $i), 0, $len);
|
1557 |
+
$pos = $len;
|
1558 |
+
}
|
1559 |
+
|
1560 |
+
return $plaintext;
|
1561 |
+
';
|
1562 |
+
break;
|
1563 |
+
case CRYPT_TWOFISH_MODE_OFB:
|
1564 |
+
$encrypt = '
|
1565 |
+
$ciphertext = "";
|
1566 |
+
$plaintext_len = strlen($text);
|
1567 |
+
$xor = $self->encryptIV;
|
1568 |
+
$buffer = &$self->enbuffer;
|
1569 |
+
|
1570 |
+
if (strlen($buffer["xor"])) {
|
1571 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1572 |
+
$block = substr($text, $i, '.$block_size.');
|
1573 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
1574 |
+
$in = $xor;
|
1575 |
+
'.$_encryptBlock.'
|
1576 |
+
$xor = $in;
|
1577 |
+
$buffer["xor"].= $xor;
|
1578 |
+
}
|
1579 |
+
$key = $self->_string_shift($buffer["xor"]);
|
1580 |
+
$ciphertext.= $block ^ $key;
|
1581 |
+
}
|
1582 |
+
} else {
|
1583 |
+
for ($i = 0; $i < $plaintext_len; $i+= '.$block_size.') {
|
1584 |
+
$in = $xor;
|
1585 |
+
'.$_encryptBlock.'
|
1586 |
+
$xor = $in;
|
1587 |
+
$ciphertext.= substr($text, $i, '.$block_size.') ^ $xor;
|
1588 |
+
}
|
1589 |
+
$key = $xor;
|
1590 |
+
}
|
1591 |
+
if ($self->continuousBuffer) {
|
1592 |
+
$self->encryptIV = $xor;
|
1593 |
+
if ($start = $plaintext_len % '.$block_size.') {
|
1594 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
1595 |
+
}
|
1596 |
+
}
|
1597 |
+
return $ciphertext;
|
1598 |
+
';
|
1599 |
+
|
1600 |
+
$decrypt = '
|
1601 |
+
$plaintext = "";
|
1602 |
+
$ciphertext_len = strlen($text);
|
1603 |
+
$xor = $self->decryptIV;
|
1604 |
+
$buffer = &$self->debuffer;
|
1605 |
+
|
1606 |
+
if (strlen($buffer["xor"])) {
|
1607 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1608 |
+
$block = substr($text, $i, '.$block_size.');
|
1609 |
+
if (strlen($block) > strlen($buffer["xor"])) {
|
1610 |
+
$in = $xor;
|
1611 |
+
'.$_encryptBlock.'
|
1612 |
+
$xor = $in;
|
1613 |
+
$buffer["xor"].= $xor;
|
1614 |
+
}
|
1615 |
+
$key = $self->_string_shift($buffer["xor"]);
|
1616 |
+
$plaintext.= $block ^ $key;
|
1617 |
+
}
|
1618 |
+
} else {
|
1619 |
+
for ($i = 0; $i < $ciphertext_len; $i+= '.$block_size.') {
|
1620 |
+
$in = $xor;
|
1621 |
+
'.$_encryptBlock.'
|
1622 |
+
$xor = $in;
|
1623 |
+
$plaintext.= substr($text, $i, '.$block_size.') ^ $xor;
|
1624 |
+
}
|
1625 |
+
$key = $xor;
|
1626 |
+
}
|
1627 |
+
if ($self->continuousBuffer) {
|
1628 |
+
$self->decryptIV = $xor;
|
1629 |
+
if ($start = $ciphertext_len % '.$block_size.') {
|
1630 |
+
$buffer["xor"] = substr($key, $start) . $buffer["xor"];
|
1631 |
+
}
|
1632 |
+
}
|
1633 |
+
return $plaintext;
|
1634 |
+
';
|
1635 |
+
break;
|
1636 |
+
}
|
1637 |
+
$fnc_head = '$action, &$self, $text';
|
1638 |
+
$fnc_body = $init_cryptBlock . 'if ($action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }';
|
1639 |
+
|
1640 |
+
if (function_exists('create_function') && is_callable('create_function')) {
|
1641 |
+
$lambda_functions[$code_hash] = create_function($fnc_head, $fnc_body);
|
1642 |
+
} else {
|
1643 |
+
eval('function ' . ($lambda_functions[$code_hash] = 'f' . md5(microtime())) . '(' . $fnc_head . ') { ' . $fnc_body . ' }');
|
1644 |
+
}
|
1645 |
+
}
|
1646 |
+
$this->inline_crypt = $lambda_functions[$code_hash];
|
1647 |
+
}
|
1648 |
+
|
1649 |
+
/**
|
1650 |
+
* Holds the lambda_functions table (classwide)
|
1651 |
+
*
|
1652 |
+
* @see inline_crypt_setup()
|
1653 |
+
* @return Array
|
1654 |
+
* @access private
|
1655 |
+
*/
|
1656 |
+
function &get_lambda_functions()
|
1657 |
+
{
|
1658 |
+
static $functions = array();
|
1659 |
+
return $functions;
|
1660 |
+
}
|
1661 |
+
}
|
1662 |
+
|
1663 |
+
// vim: ts=4:sw=4:et:
|
1664 |
+
// vim6: fdl=1:
|
lib/PHPSecLib/File/ANSI.php
ADDED
@@ -0,0 +1,560 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP ANSI Decoder
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* If you call read() in Net_SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
|
10 |
+
* They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
|
11 |
+
* {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
|
12 |
+
* color to display them in, etc. File_ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
|
13 |
+
*
|
14 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 |
+
* of this software and associated documentation files (the "Software"), to deal
|
16 |
+
* in the Software without restriction, including without limitation the rights
|
17 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
18 |
+
* copies of the Software, and to permit persons to whom the Software is
|
19 |
+
* furnished to do so, subject to the following conditions:
|
20 |
+
*
|
21 |
+
* The above copyright notice and this permission notice shall be included in
|
22 |
+
* all copies or substantial portions of the Software.
|
23 |
+
*
|
24 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
29 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
30 |
+
* THE SOFTWARE.
|
31 |
+
*
|
32 |
+
* @category File
|
33 |
+
* @package File_ANSI
|
34 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
35 |
+
* @copyright MMXII Jim Wigginton
|
36 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
37 |
+
* @link http://phpseclib.sourceforge.net
|
38 |
+
*/
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Pure-PHP ANSI Decoder
|
42 |
+
*
|
43 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
44 |
+
* @version 0.3.0
|
45 |
+
* @access public
|
46 |
+
* @package File_ANSI
|
47 |
+
*/
|
48 |
+
class File_ANSI {
|
49 |
+
/**
|
50 |
+
* Max Width
|
51 |
+
*
|
52 |
+
* @var Integer
|
53 |
+
* @access private
|
54 |
+
*/
|
55 |
+
var $max_x;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Max Height
|
59 |
+
*
|
60 |
+
* @var Integer
|
61 |
+
* @access private
|
62 |
+
*/
|
63 |
+
var $max_y;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Max History
|
67 |
+
*
|
68 |
+
* @var Integer
|
69 |
+
* @access private
|
70 |
+
*/
|
71 |
+
var $max_history;
|
72 |
+
|
73 |
+
/**
|
74 |
+
* History
|
75 |
+
*
|
76 |
+
* @var Array
|
77 |
+
* @access private
|
78 |
+
*/
|
79 |
+
var $history;
|
80 |
+
|
81 |
+
/**
|
82 |
+
* History Attributes
|
83 |
+
*
|
84 |
+
* @var Array
|
85 |
+
* @access private
|
86 |
+
*/
|
87 |
+
var $history_attrs;
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Current Column
|
91 |
+
*
|
92 |
+
* @var Integer
|
93 |
+
* @access private
|
94 |
+
*/
|
95 |
+
var $x;
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Current Row
|
99 |
+
*
|
100 |
+
* @var Integer
|
101 |
+
* @access private
|
102 |
+
*/
|
103 |
+
var $y;
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Old Column
|
107 |
+
*
|
108 |
+
* @var Integer
|
109 |
+
* @access private
|
110 |
+
*/
|
111 |
+
var $old_x;
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Old Row
|
115 |
+
*
|
116 |
+
* @var Integer
|
117 |
+
* @access private
|
118 |
+
*/
|
119 |
+
var $old_y;
|
120 |
+
|
121 |
+
/**
|
122 |
+
* An empty attribute row
|
123 |
+
*
|
124 |
+
* @var Array
|
125 |
+
* @access private
|
126 |
+
*/
|
127 |
+
var $attr_row;
|
128 |
+
|
129 |
+
/**
|
130 |
+
* The current screen text
|
131 |
+
*
|
132 |
+
* @var Array
|
133 |
+
* @access private
|
134 |
+
*/
|
135 |
+
var $screen;
|
136 |
+
|
137 |
+
/**
|
138 |
+
* The current screen attributes
|
139 |
+
*
|
140 |
+
* @var Array
|
141 |
+
* @access private
|
142 |
+
*/
|
143 |
+
var $attrs;
|
144 |
+
|
145 |
+
/**
|
146 |
+
* The current foreground color
|
147 |
+
*
|
148 |
+
* @var String
|
149 |
+
* @access private
|
150 |
+
*/
|
151 |
+
var $foreground;
|
152 |
+
|
153 |
+
/**
|
154 |
+
* The current background color
|
155 |
+
*
|
156 |
+
* @var String
|
157 |
+
* @access private
|
158 |
+
*/
|
159 |
+
var $background;
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Bold flag
|
163 |
+
*
|
164 |
+
* @var Boolean
|
165 |
+
* @access private
|
166 |
+
*/
|
167 |
+
var $bold;
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Underline flag
|
171 |
+
*
|
172 |
+
* @var Boolean
|
173 |
+
* @access private
|
174 |
+
*/
|
175 |
+
var $underline;
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Blink flag
|
179 |
+
*
|
180 |
+
* @var Boolean
|
181 |
+
* @access private
|
182 |
+
*/
|
183 |
+
var $blink;
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Reverse flag
|
187 |
+
*
|
188 |
+
* @var Boolean
|
189 |
+
* @access private
|
190 |
+
*/
|
191 |
+
var $reverse;
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Color flag
|
195 |
+
*
|
196 |
+
* @var Boolean
|
197 |
+
* @access private
|
198 |
+
*/
|
199 |
+
var $color;
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Current ANSI code
|
203 |
+
*
|
204 |
+
* @var String
|
205 |
+
* @access private
|
206 |
+
*/
|
207 |
+
var $ansi;
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Default Constructor.
|
211 |
+
*
|
212 |
+
* @return File_ANSI
|
213 |
+
* @access public
|
214 |
+
*/
|
215 |
+
function File_ANSI()
|
216 |
+
{
|
217 |
+
$this->setHistory(200);
|
218 |
+
$this->setDimensions(80, 24);
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Set terminal width and height
|
223 |
+
*
|
224 |
+
* Resets the screen as well
|
225 |
+
*
|
226 |
+
* @param Integer $x
|
227 |
+
* @param Integer $y
|
228 |
+
* @access public
|
229 |
+
*/
|
230 |
+
function setDimensions($x, $y)
|
231 |
+
{
|
232 |
+
$this->max_x = $x - 1;
|
233 |
+
$this->max_y = $y - 1;
|
234 |
+
$this->x = $this->y = 0;
|
235 |
+
$this->history = $this->history_attrs = array();
|
236 |
+
$this->attr_row = array_fill(0, $this->max_x + 1, '');
|
237 |
+
$this->screen = array_fill(0, $this->max_y + 1, '');
|
238 |
+
$this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
|
239 |
+
$this->foreground = 'white';
|
240 |
+
$this->background = 'black';
|
241 |
+
$this->bold = false;
|
242 |
+
$this->underline = false;
|
243 |
+
$this->blink = false;
|
244 |
+
$this->reverse = false;
|
245 |
+
$this->color = false;
|
246 |
+
|
247 |
+
$this->ansi = '';
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Set the number of lines that should be logged past the terminal height
|
252 |
+
*
|
253 |
+
* @param Integer $x
|
254 |
+
* @param Integer $y
|
255 |
+
* @access public
|
256 |
+
*/
|
257 |
+
function setHistory($history)
|
258 |
+
{
|
259 |
+
$this->max_history = $history;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Load a string
|
264 |
+
*
|
265 |
+
* @param String $source
|
266 |
+
* @access public
|
267 |
+
*/
|
268 |
+
function loadString($source)
|
269 |
+
{
|
270 |
+
$this->setDimensions($this->max_x + 1, $this->max_y + 1);
|
271 |
+
$this->appendString($source);
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Appdend a string
|
276 |
+
*
|
277 |
+
* @param String $source
|
278 |
+
* @access public
|
279 |
+
*/
|
280 |
+
function appendString($source)
|
281 |
+
{
|
282 |
+
for ($i = 0; $i < strlen($source); $i++) {
|
283 |
+
if (strlen($this->ansi)) {
|
284 |
+
$this->ansi.= $source[$i];
|
285 |
+
$chr = ord($source[$i]);
|
286 |
+
// http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
|
287 |
+
// single character CSI's not currently supported
|
288 |
+
switch (true) {
|
289 |
+
case $this->ansi == "\x1B=":
|
290 |
+
$this->ansi = '';
|
291 |
+
continue 2;
|
292 |
+
case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
|
293 |
+
case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
|
294 |
+
break;
|
295 |
+
default:
|
296 |
+
continue 2;
|
297 |
+
}
|
298 |
+
// http://ascii-table.com/ansi-escape-sequences-vt-100.php
|
299 |
+
switch ($this->ansi) {
|
300 |
+
case "\x1B[H": // Move cursor to upper left corner
|
301 |
+
$this->old_x = $this->x;
|
302 |
+
$this->old_y = $this->y;
|
303 |
+
$this->x = $this->y = 0;
|
304 |
+
break;
|
305 |
+
case "\x1B[J": // Clear screen from cursor down
|
306 |
+
$this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
|
307 |
+
$this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
|
308 |
+
|
309 |
+
$this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
|
310 |
+
$this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
|
311 |
+
|
312 |
+
if (count($this->history) == $this->max_history) {
|
313 |
+
array_shift($this->history);
|
314 |
+
array_shift($this->history_attrs);
|
315 |
+
}
|
316 |
+
case "\x1B[K": // Clear screen from cursor right
|
317 |
+
$this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
|
318 |
+
|
319 |
+
array_splice($this->attrs[$this->y], $this->x + 1);
|
320 |
+
break;
|
321 |
+
case "\x1B[2K": // Clear entire line
|
322 |
+
$this->screen[$this->y] = str_repeat(' ', $this->x);
|
323 |
+
$this->attrs[$this->y] = $this->attr_row;
|
324 |
+
break;
|
325 |
+
case "\x1B[?1h": // set cursor key to application
|
326 |
+
case "\x1B[?25h": // show the cursor
|
327 |
+
break;
|
328 |
+
case "\x1BE": // Move to next line
|
329 |
+
$this->_newLine();
|
330 |
+
$this->x = 0;
|
331 |
+
break;
|
332 |
+
default:
|
333 |
+
switch (true) {
|
334 |
+
case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
|
335 |
+
$this->old_x = $this->x;
|
336 |
+
$this->old_y = $this->y;
|
337 |
+
$this->x = $match[2] - 1;
|
338 |
+
$this->y = $match[1] - 1;
|
339 |
+
break;
|
340 |
+
case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
|
341 |
+
$this->old_x = $this->x;
|
342 |
+
$x = $match[1] - 1;
|
343 |
+
break;
|
344 |
+
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
|
345 |
+
break;
|
346 |
+
case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
|
347 |
+
$mods = explode(';', $match[1]);
|
348 |
+
foreach ($mods as $mod) {
|
349 |
+
switch ($mod) {
|
350 |
+
case 0: // Turn off character attributes
|
351 |
+
$this->attrs[$this->y][$this->x] = '';
|
352 |
+
|
353 |
+
if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>';
|
354 |
+
if ($this->underline) $this->attrs[$this->y][$this->x].= '</underline>';
|
355 |
+
if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>';
|
356 |
+
if ($this->color) $this->attrs[$this->y][$this->x].= '</span>';
|
357 |
+
|
358 |
+
if ($this->reverse) {
|
359 |
+
$temp = $this->background;
|
360 |
+
$this->background = $this->foreground;
|
361 |
+
$this->foreground = $temp;
|
362 |
+
}
|
363 |
+
|
364 |
+
$this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false;
|
365 |
+
break;
|
366 |
+
case 1: // Turn bold mode on
|
367 |
+
if (!$this->bold) {
|
368 |
+
$this->attrs[$this->y][$this->x] = '<b>';
|
369 |
+
$this->bold = true;
|
370 |
+
}
|
371 |
+
break;
|
372 |
+
case 4: // Turn underline mode on
|
373 |
+
if (!$this->underline) {
|
374 |
+
$this->attrs[$this->y][$this->x] = '<u>';
|
375 |
+
$this->underline = true;
|
376 |
+
}
|
377 |
+
break;
|
378 |
+
case 5: // Turn blinking mode on
|
379 |
+
if (!$this->blink) {
|
380 |
+
$this->attrs[$this->y][$this->x] = '<blink>';
|
381 |
+
$this->blink = true;
|
382 |
+
}
|
383 |
+
break;
|
384 |
+
case 7: // Turn reverse video on
|
385 |
+
$this->reverse = !$this->reverse;
|
386 |
+
$temp = $this->background;
|
387 |
+
$this->background = $this->foreground;
|
388 |
+
$this->foreground = $temp;
|
389 |
+
$this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">';
|
390 |
+
if ($this->color) {
|
391 |
+
$this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x];
|
392 |
+
}
|
393 |
+
$this->color = true;
|
394 |
+
break;
|
395 |
+
default: // set colors
|
396 |
+
//$front = $this->reverse ? &$this->background : &$this->foreground;
|
397 |
+
$front = &$this->{ $this->reverse ? 'background' : 'foreground' };
|
398 |
+
//$back = $this->reverse ? &$this->foreground : &$this->background;
|
399 |
+
$back = &$this->{ $this->reverse ? 'foreground' : 'background' };
|
400 |
+
switch ($mod) {
|
401 |
+
case 30: $front = 'black'; break;
|
402 |
+
case 31: $front = 'red'; break;
|
403 |
+
case 32: $front = 'green'; break;
|
404 |
+
case 33: $front = 'yellow'; break;
|
405 |
+
case 34: $front = 'blue'; break;
|
406 |
+
case 35: $front = 'magenta'; break;
|
407 |
+
case 36: $front = 'cyan'; break;
|
408 |
+
case 37: $front = 'white'; break;
|
409 |
+
|
410 |
+
case 40: $back = 'black'; break;
|
411 |
+
case 41: $back = 'red'; break;
|
412 |
+
case 42: $back = 'green'; break;
|
413 |
+
case 43: $back = 'yellow'; break;
|
414 |
+
case 44: $back = 'blue'; break;
|
415 |
+
case 45: $back = 'magenta'; break;
|
416 |
+
case 46: $back = 'cyan'; break;
|
417 |
+
case 47: $back = 'white'; break;
|
418 |
+
|
419 |
+
default:
|
420 |
+
user_error('Unsupported attribute: ' . $mod);
|
421 |
+
$this->ansi = '';
|
422 |
+
break 2;
|
423 |
+
}
|
424 |
+
|
425 |
+
unset($temp);
|
426 |
+
$this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">';
|
427 |
+
if ($this->color) {
|
428 |
+
$this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x];
|
429 |
+
}
|
430 |
+
$this->color = true;
|
431 |
+
}
|
432 |
+
}
|
433 |
+
break;
|
434 |
+
default:
|
435 |
+
user_error("{$this->ansi} unsupported\r\n");
|
436 |
+
}
|
437 |
+
}
|
438 |
+
$this->ansi = '';
|
439 |
+
continue;
|
440 |
+
}
|
441 |
+
|
442 |
+
switch ($source[$i]) {
|
443 |
+
case "\r":
|
444 |
+
$this->x = 0;
|
445 |
+
break;
|
446 |
+
case "\n":
|
447 |
+
$this->_newLine();
|
448 |
+
break;
|
449 |
+
case "\x0F": // shift
|
450 |
+
break;
|
451 |
+
case "\x1B": // start ANSI escape code
|
452 |
+
$this->ansi.= "\x1B";
|
453 |
+
break;
|
454 |
+
default:
|
455 |
+
$this->screen[$this->y] = substr_replace(
|
456 |
+
$this->screen[$this->y],
|
457 |
+
$source[$i],
|
458 |
+
$this->x,
|
459 |
+
1
|
460 |
+
);
|
461 |
+
|
462 |
+
if ($this->x > $this->max_x) {
|
463 |
+
$this->x = 0;
|
464 |
+
$this->y++;
|
465 |
+
} else {
|
466 |
+
$this->x++;
|
467 |
+
}
|
468 |
+
}
|
469 |
+
}
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Add a new line
|
474 |
+
*
|
475 |
+
* Also update the $this->screen and $this->history buffers
|
476 |
+
*
|
477 |
+
* @access private
|
478 |
+
*/
|
479 |
+
function _newLine()
|
480 |
+
{
|
481 |
+
//if ($this->y < $this->max_y) {
|
482 |
+
// $this->y++;
|
483 |
+
//}
|
484 |
+
|
485 |
+
while ($this->y >= $this->max_y) {
|
486 |
+
$this->history = array_merge($this->history, array(array_shift($this->screen)));
|
487 |
+
$this->screen[] = '';
|
488 |
+
|
489 |
+
$this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
|
490 |
+
$this->attrs[] = $this->attr_row;
|
491 |
+
|
492 |
+
if (count($this->history) >= $this->max_history) {
|
493 |
+
array_shift($this->history);
|
494 |
+
array_shift($this->history_attrs);
|
495 |
+
}
|
496 |
+
|
497 |
+
$this->y--;
|
498 |
+
}
|
499 |
+
$this->y++;
|
500 |
+
}
|
501 |
+
|
502 |
+
/**
|
503 |
+
* Returns the current screen without preformating
|
504 |
+
*
|
505 |
+
* @access private
|
506 |
+
* @return String
|
507 |
+
*/
|
508 |
+
function _getScreen()
|
509 |
+
{
|
510 |
+
$output = '';
|
511 |
+
for ($i = 0; $i <= $this->max_y; $i++) {
|
512 |
+
for ($j = 0; $j <= $this->max_x + 1; $j++) {
|
513 |
+
if (isset($this->attrs[$i][$j])) {
|
514 |
+
$output.= $this->attrs[$i][$j];
|
515 |
+
}
|
516 |
+
if (isset($this->screen[$i][$j])) {
|
517 |
+
$output.= htmlspecialchars($this->screen[$i][$j]);
|
518 |
+
}
|
519 |
+
}
|
520 |
+
$output.= "\r\n";
|
521 |
+
}
|
522 |
+
return rtrim($output);
|
523 |
+
}
|
524 |
+
|
525 |
+
/**
|
526 |
+
* Returns the current screen
|
527 |
+
*
|
528 |
+
* @access public
|
529 |
+
* @return String
|
530 |
+
*/
|
531 |
+
function getScreen()
|
532 |
+
{
|
533 |
+
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $this->_getScreen() . '</pre>';
|
534 |
+
}
|
535 |
+
|
536 |
+
/**
|
537 |
+
* Returns the current screen and the x previous lines
|
538 |
+
*
|
539 |
+
* @access public
|
540 |
+
* @return String
|
541 |
+
*/
|
542 |
+
function getHistory()
|
543 |
+
{
|
544 |
+
$scrollback = '';
|
545 |
+
for ($i = 0; $i < count($this->history); $i++) {
|
546 |
+
for ($j = 0; $j <= $this->max_x + 1; $j++) {
|
547 |
+
if (isset($this->history_attrs[$i][$j])) {
|
548 |
+
$scrollback.= $this->history_attrs[$i][$j];
|
549 |
+
}
|
550 |
+
if (isset($this->history[$i][$j])) {
|
551 |
+
$scrollback.= htmlspecialchars($this->history[$i][$j]);
|
552 |
+
}
|
553 |
+
}
|
554 |
+
$scrollback.= "\r\n";
|
555 |
+
}
|
556 |
+
$scrollback.= $this->_getScreen();
|
557 |
+
|
558 |
+
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $scrollback . '</pre>';
|
559 |
+
}
|
560 |
+
}
|
lib/PHPSecLib/File/ASN1.php
ADDED
@@ -0,0 +1,1293 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP ASN.1 Parser
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* ASN.1 provides the semantics for data encoded using various schemes. The most commonly
|
10 |
+
* utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
|
11 |
+
* DER blobs.
|
12 |
+
*
|
13 |
+
* File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
|
14 |
+
*
|
15 |
+
* Uses the 1988 ASN.1 syntax.
|
16 |
+
*
|
17 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
18 |
+
* of this software and associated documentation files (the "Software"), to deal
|
19 |
+
* in the Software without restriction, including without limitation the rights
|
20 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
21 |
+
* copies of the Software, and to permit persons to whom the Software is
|
22 |
+
* furnished to do so, subject to the following conditions:
|
23 |
+
*
|
24 |
+
* The above copyright notice and this permission notice shall be included in
|
25 |
+
* all copies or substantial portions of the Software.
|
26 |
+
*
|
27 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
28 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
29 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
30 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
31 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
32 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
33 |
+
* THE SOFTWARE.
|
34 |
+
*
|
35 |
+
* @category File
|
36 |
+
* @package File_ASN1
|
37 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
38 |
+
* @copyright MMXII Jim Wigginton
|
39 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
40 |
+
* @link http://phpseclib.sourceforge.net
|
41 |
+
*/
|
42 |
+
|
43 |
+
/**#@+
|
44 |
+
* Tag Classes
|
45 |
+
*
|
46 |
+
* @access private
|
47 |
+
* @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
|
48 |
+
*/
|
49 |
+
define('FILE_ASN1_CLASS_UNIVERSAL', 0);
|
50 |
+
define('FILE_ASN1_CLASS_APPLICATION', 1);
|
51 |
+
define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
|
52 |
+
define('FILE_ASN1_CLASS_PRIVATE', 3);
|
53 |
+
/**#@-*/
|
54 |
+
|
55 |
+
/**#@+
|
56 |
+
* Tag Classes
|
57 |
+
*
|
58 |
+
* @access private
|
59 |
+
* @link http://www.obj-sys.com/asn1tutorial/node124.html
|
60 |
+
*/
|
61 |
+
define('FILE_ASN1_TYPE_BOOLEAN', 1);
|
62 |
+
define('FILE_ASN1_TYPE_INTEGER', 2);
|
63 |
+
define('FILE_ASN1_TYPE_BIT_STRING', 3);
|
64 |
+
define('FILE_ASN1_TYPE_OCTET_STRING', 4);
|
65 |
+
define('FILE_ASN1_TYPE_NULL', 5);
|
66 |
+
define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER',6);
|
67 |
+
//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR',7);
|
68 |
+
//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
|
69 |
+
define('FILE_ASN1_TYPE_REAL', 9);
|
70 |
+
define('FILE_ASN1_TYPE_ENUMERATED', 10);
|
71 |
+
//define('FILE_ASN1_TYPE_EMBEDDED', 11);
|
72 |
+
define('FILE_ASN1_TYPE_UTF8_STRING', 12);
|
73 |
+
//define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
|
74 |
+
define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
|
75 |
+
define('FILE_ASN1_TYPE_SET', 17); // SET OF
|
76 |
+
/**#@-*/
|
77 |
+
/**#@+
|
78 |
+
* More Tag Classes
|
79 |
+
*
|
80 |
+
* @access private
|
81 |
+
* @link http://www.obj-sys.com/asn1tutorial/node10.html
|
82 |
+
*/
|
83 |
+
define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
|
84 |
+
define('FILE_ASN1_TYPE_PRINTABLE_STRING',19);
|
85 |
+
define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
|
86 |
+
define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
|
87 |
+
define('FILE_ASN1_TYPE_IA5_STRING', 22);
|
88 |
+
define('FILE_ASN1_TYPE_UTC_TIME', 23);
|
89 |
+
define('FILE_ASN1_TYPE_GENERALIZED_TIME',24);
|
90 |
+
define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
|
91 |
+
define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
|
92 |
+
define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
|
93 |
+
define('FILE_ASN1_TYPE_UNIVERSAL_STRING',28);
|
94 |
+
//define('FILE_ASN1_TYPE_CHARACTER_STRING',29);
|
95 |
+
define('FILE_ASN1_TYPE_BMP_STRING', 30);
|
96 |
+
/**#@-*/
|
97 |
+
|
98 |
+
/**#@+
|
99 |
+
* Tag Aliases
|
100 |
+
*
|
101 |
+
* These tags are kinda place holders for other tags.
|
102 |
+
*
|
103 |
+
* @access private
|
104 |
+
*/
|
105 |
+
define('FILE_ASN1_TYPE_CHOICE', -1);
|
106 |
+
define('FILE_ASN1_TYPE_ANY', -2);
|
107 |
+
/**#@-*/
|
108 |
+
|
109 |
+
/**
|
110 |
+
* ASN.1 Element
|
111 |
+
*
|
112 |
+
* Bypass normal encoding rules in File_ASN1::encodeDER()
|
113 |
+
*
|
114 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
115 |
+
* @version 0.3.0
|
116 |
+
* @access public
|
117 |
+
* @package File_ASN1
|
118 |
+
*/
|
119 |
+
class File_ASN1_Element {
|
120 |
+
/**
|
121 |
+
* Raw element value
|
122 |
+
*
|
123 |
+
* @var String
|
124 |
+
* @access private
|
125 |
+
*/
|
126 |
+
var $element;
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Constructor
|
130 |
+
*
|
131 |
+
* @param String $encoded
|
132 |
+
* @return File_ASN1_Element
|
133 |
+
* @access public
|
134 |
+
*/
|
135 |
+
function File_ASN1_Element($encoded)
|
136 |
+
{
|
137 |
+
$this->element = $encoded;
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Pure-PHP ASN.1 Parser
|
143 |
+
*
|
144 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
145 |
+
* @version 0.3.0
|
146 |
+
* @access public
|
147 |
+
* @package File_ASN1
|
148 |
+
*/
|
149 |
+
class File_ASN1 {
|
150 |
+
/**
|
151 |
+
* ASN.1 object identifier
|
152 |
+
*
|
153 |
+
* @var Array
|
154 |
+
* @access private
|
155 |
+
* @link http://en.wikipedia.org/wiki/Object_identifier
|
156 |
+
*/
|
157 |
+
var $oids = array();
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Default date format
|
161 |
+
*
|
162 |
+
* @var String
|
163 |
+
* @access private
|
164 |
+
* @link http://php.net/class.datetime
|
165 |
+
*/
|
166 |
+
var $format = 'D, d M y H:i:s O';
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Default date format
|
170 |
+
*
|
171 |
+
* @var Array
|
172 |
+
* @access private
|
173 |
+
* @see File_ASN1::setTimeFormat()
|
174 |
+
* @see File_ASN1::asn1map()
|
175 |
+
* @link http://php.net/class.datetime
|
176 |
+
*/
|
177 |
+
var $encoded;
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Filters
|
181 |
+
*
|
182 |
+
* If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
|
183 |
+
*
|
184 |
+
* @var Array
|
185 |
+
* @access private
|
186 |
+
* @see File_ASN1::_encode_der()
|
187 |
+
*/
|
188 |
+
var $filters;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Type mapping table for the ANY type.
|
192 |
+
*
|
193 |
+
* Structured or unknown types are mapped to a FILE_ASN1_Element.
|
194 |
+
* Unambiguous types get the direct mapping (int/real/bool).
|
195 |
+
* Others are mapped as a choice, with an extra indexing level.
|
196 |
+
*
|
197 |
+
* @var Array
|
198 |
+
* @access public
|
199 |
+
*/
|
200 |
+
var $ANYmap = array(
|
201 |
+
FILE_ASN1_TYPE_BOOLEAN => true,
|
202 |
+
FILE_ASN1_TYPE_INTEGER => true,
|
203 |
+
FILE_ASN1_TYPE_BIT_STRING => 'bitString',
|
204 |
+
FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
|
205 |
+
FILE_ASN1_TYPE_NULL => 'null',
|
206 |
+
FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
|
207 |
+
FILE_ASN1_TYPE_REAL => true,
|
208 |
+
FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
|
209 |
+
FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
|
210 |
+
FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
|
211 |
+
FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
|
212 |
+
FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
|
213 |
+
FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
|
214 |
+
FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
|
215 |
+
FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
|
216 |
+
FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
|
217 |
+
FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
|
218 |
+
FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
|
219 |
+
FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
|
220 |
+
FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
|
221 |
+
//FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
|
222 |
+
FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
|
223 |
+
);
|
224 |
+
|
225 |
+
/**
|
226 |
+
* String type to character size mapping table.
|
227 |
+
*
|
228 |
+
* Non-convertable types are absent from this table.
|
229 |
+
* size == 0 indicates variable length encoding.
|
230 |
+
*
|
231 |
+
* @var Array
|
232 |
+
* @access public
|
233 |
+
*/
|
234 |
+
var $stringTypeSize = array(
|
235 |
+
FILE_ASN1_TYPE_UTF8_STRING => 0,
|
236 |
+
FILE_ASN1_TYPE_BMP_STRING => 2,
|
237 |
+
FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
|
238 |
+
FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
|
239 |
+
FILE_ASN1_TYPE_TELETEX_STRING => 1,
|
240 |
+
FILE_ASN1_TYPE_IA5_STRING => 1,
|
241 |
+
FILE_ASN1_TYPE_VISIBLE_STRING => 1,
|
242 |
+
);
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Default Constructor.
|
246 |
+
*
|
247 |
+
* @access public
|
248 |
+
*/
|
249 |
+
function File_ASN1()
|
250 |
+
{
|
251 |
+
static $static_init = null;
|
252 |
+
if (!$static_init) {
|
253 |
+
$static_init = true;
|
254 |
+
if (!class_exists('Math_BigInteger')) {
|
255 |
+
require_once('Math/BigInteger.php');
|
256 |
+
}
|
257 |
+
}
|
258 |
+
}
|
259 |
+
|
260 |
+
/**
|
261 |
+
* Parse BER-encoding
|
262 |
+
*
|
263 |
+
* Serves a similar purpose to openssl's asn1parse
|
264 |
+
*
|
265 |
+
* @param String $encoded
|
266 |
+
* @return Array
|
267 |
+
* @access public
|
268 |
+
*/
|
269 |
+
function decodeBER($encoded)
|
270 |
+
{
|
271 |
+
if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
|
272 |
+
$encoded = $encoded->element;
|
273 |
+
}
|
274 |
+
|
275 |
+
$this->encoded = $encoded;
|
276 |
+
return $this->_decode_ber($encoded);
|
277 |
+
}
|
278 |
+
|
279 |
+
/**
|
280 |
+
* Parse BER-encoding (Helper function)
|
281 |
+
*
|
282 |
+
* Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
|
283 |
+
* $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
|
284 |
+
* FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
|
285 |
+
*
|
286 |
+
* @param String $encoded
|
287 |
+
* @param Integer $start
|
288 |
+
* @return Array
|
289 |
+
* @access private
|
290 |
+
*/
|
291 |
+
function _decode_ber(&$encoded, $start = 0)
|
292 |
+
{
|
293 |
+
$decoded = array();
|
294 |
+
|
295 |
+
while ( strlen($encoded) ) {
|
296 |
+
$current = array('start' => $start);
|
297 |
+
|
298 |
+
$type = ord($this->_string_shift($encoded));
|
299 |
+
$start++;
|
300 |
+
|
301 |
+
$constructed = ($type >> 5) & 1;
|
302 |
+
|
303 |
+
$tag = $type & 0x1F;
|
304 |
+
if ($tag == 0x1F) {
|
305 |
+
$tag = 0;
|
306 |
+
// process septets (since the eighth bit is ignored, it's not an octet)
|
307 |
+
do {
|
308 |
+
$loop = ord($encoded[0]) >> 7;
|
309 |
+
$tag <<= 7;
|
310 |
+
$tag |= ord($this->_string_shift($encoded)) & 0x7F;
|
311 |
+
$start++;
|
312 |
+
} while ( $loop );
|
313 |
+
}
|
314 |
+
|
315 |
+
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
|
316 |
+
$length = ord($this->_string_shift($encoded));
|
317 |
+
$start++;
|
318 |
+
if ( $length == 0x80 ) { // indefinite length
|
319 |
+
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
|
320 |
+
// immediately available." -- paragraph 8.1.3.2.c
|
321 |
+
//if ( !$constructed ) {
|
322 |
+
// return false;
|
323 |
+
//}
|
324 |
+
$length = strlen($encoded);
|
325 |
+
} elseif ( $length & 0x80 ) { // definite length, long form
|
326 |
+
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
|
327 |
+
// support it up to four.
|
328 |
+
$length&= 0x7F;
|
329 |
+
$temp = $this->_string_shift($encoded, $length);
|
330 |
+
// tags of indefinite length don't really have a header length; this length includes the tag
|
331 |
+
$current+= array('headerlength' => $length + 2);
|
332 |
+
$start+= $length;
|
333 |
+
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
|
334 |
+
} else {
|
335 |
+
$current+= array('headerlength' => 2);
|
336 |
+
}
|
337 |
+
|
338 |
+
// End-of-content, see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
|
339 |
+
if (!$type && !$length) {
|
340 |
+
return $decoded;
|
341 |
+
}
|
342 |
+
$content = $this->_string_shift($encoded, $length);
|
343 |
+
|
344 |
+
/* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
|
345 |
+
built-in types. It defines an application-independent data type that must be distinguishable from all other
|
346 |
+
data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
|
347 |
+
have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
|
348 |
+
a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
|
349 |
+
alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
|
350 |
+
data type; the term CONTEXT-SPECIFIC does not appear.
|
351 |
+
|
352 |
+
-- http://www.obj-sys.com/asn1tutorial/node12.html */
|
353 |
+
$class = ($type >> 6) & 3;
|
354 |
+
switch ($class) {
|
355 |
+
case FILE_ASN1_CLASS_APPLICATION:
|
356 |
+
case FILE_ASN1_CLASS_PRIVATE:
|
357 |
+
case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
|
358 |
+
$decoded[] = array(
|
359 |
+
'type' => $class,
|
360 |
+
'constant' => $tag,
|
361 |
+
'content' => $constructed ? $this->_decode_ber($content, $start) : $content,
|
362 |
+
'length' => $length + $start - $current['start']
|
363 |
+
) + $current;
|
364 |
+
$start+= $length;
|
365 |
+
continue 2;
|
366 |
+
}
|
367 |
+
|
368 |
+
$current+= array('type' => $tag);
|
369 |
+
|
370 |
+
// decode UNIVERSAL tags
|
371 |
+
switch ($tag) {
|
372 |
+
case FILE_ASN1_TYPE_BOOLEAN:
|
373 |
+
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
|
374 |
+
//if (strlen($content) != 1) {
|
375 |
+
// return false;
|
376 |
+
//}
|
377 |
+
$current['content'] = (bool) ord($content[0]);
|
378 |
+
break;
|
379 |
+
case FILE_ASN1_TYPE_INTEGER:
|
380 |
+
case FILE_ASN1_TYPE_ENUMERATED:
|
381 |
+
$current['content'] = new Math_BigInteger($content, -256);
|
382 |
+
break;
|
383 |
+
case FILE_ASN1_TYPE_REAL: // not currently supported
|
384 |
+
return false;
|
385 |
+
case FILE_ASN1_TYPE_BIT_STRING:
|
386 |
+
// The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
|
387 |
+
// the number of unused bits in the final subsequent octet. The number shall be in the range zero to
|
388 |
+
// seven.
|
389 |
+
if (!$constructed) {
|
390 |
+
$current['content'] = $content;
|
391 |
+
} else {
|
392 |
+
$temp = $this->_decode_ber($content, $start);
|
393 |
+
$length-= strlen($content);
|
394 |
+
$last = count($temp) - 1;
|
395 |
+
for ($i = 0; $i < $last; $i++) {
|
396 |
+
// all subtags should be bit strings
|
397 |
+
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
|
398 |
+
// return false;
|
399 |
+
//}
|
400 |
+
$current['content'].= substr($temp[$i]['content'], 1);
|
401 |
+
}
|
402 |
+
// all subtags should be bit strings
|
403 |
+
//if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
|
404 |
+
// return false;
|
405 |
+
//}
|
406 |
+
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
|
407 |
+
}
|
408 |
+
break;
|
409 |
+
case FILE_ASN1_TYPE_OCTET_STRING:
|
410 |
+
if (!$constructed) {
|
411 |
+
$current['content'] = $content;
|
412 |
+
} else {
|
413 |
+
$temp = $this->_decode_ber($content, $start);
|
414 |
+
$length-= strlen($content);
|
415 |
+
for ($i = 0, $size = count($temp); $i < $size; $i++) {
|
416 |
+
// all subtags should be octet strings
|
417 |
+
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
|
418 |
+
// return false;
|
419 |
+
//}
|
420 |
+
$current['content'].= $temp[$i]['content'];
|
421 |
+
}
|
422 |
+
// $length =
|
423 |
+
}
|
424 |
+
break;
|
425 |
+
case FILE_ASN1_TYPE_NULL:
|
426 |
+
// "The contents octets shall not contain any octets." -- paragraph 8.8.2
|
427 |
+
//if (strlen($content)) {
|
428 |
+
// return false;
|
429 |
+
//}
|
430 |
+
break;
|
431 |
+
case FILE_ASN1_TYPE_SEQUENCE:
|
432 |
+
case FILE_ASN1_TYPE_SET:
|
433 |
+
$current['content'] = $this->_decode_ber($content, $start);
|
434 |
+
break;
|
435 |
+
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
436 |
+
$temp = ord($this->_string_shift($content));
|
437 |
+
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
|
438 |
+
$valuen = 0;
|
439 |
+
// process septets
|
440 |
+
while (strlen($content)) {
|
441 |
+
$temp = ord($this->_string_shift($content));
|
442 |
+
$valuen <<= 7;
|
443 |
+
$valuen |= $temp & 0x7F;
|
444 |
+
if (~$temp & 0x80) {
|
445 |
+
$current['content'].= ".$valuen";
|
446 |
+
$valuen = 0;
|
447 |
+
}
|
448 |
+
}
|
449 |
+
// the eighth bit of the last byte should not be 1
|
450 |
+
//if ($temp >> 7) {
|
451 |
+
// return false;
|
452 |
+
//}
|
453 |
+
break;
|
454 |
+
/* Each character string type shall be encoded as if it had been declared:
|
455 |
+
[UNIVERSAL x] IMPLICIT OCTET STRING
|
456 |
+
|
457 |
+
-- X.690-0207.pdf#page=23 (paragraph 8.21.3)
|
458 |
+
|
459 |
+
Per that, we're not going to do any validation. If there are any illegal characters in the string,
|
460 |
+
we don't really care */
|
461 |
+
case FILE_ASN1_TYPE_NUMERIC_STRING:
|
462 |
+
// 0,1,2,3,4,5,6,7,8,9, and space
|
463 |
+
case FILE_ASN1_TYPE_PRINTABLE_STRING:
|
464 |
+
// Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
|
465 |
+
// hyphen, full stop, solidus, colon, equal sign, question mark
|
466 |
+
case FILE_ASN1_TYPE_TELETEX_STRING:
|
467 |
+
// The Teletex character set in CCITT's T61, space, and delete
|
468 |
+
// see http://en.wikipedia.org/wiki/Teletex#Character_sets
|
469 |
+
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
|
470 |
+
// The Videotex character set in CCITT's T.100 and T.101, space, and delete
|
471 |
+
case FILE_ASN1_TYPE_VISIBLE_STRING:
|
472 |
+
// Printing character sets of international ASCII, and space
|
473 |
+
case FILE_ASN1_TYPE_IA5_STRING:
|
474 |
+
// International Alphabet 5 (International ASCII)
|
475 |
+
case FILE_ASN1_TYPE_GRAPHIC_STRING:
|
476 |
+
// All registered G sets, and space
|
477 |
+
case FILE_ASN1_TYPE_GENERAL_STRING:
|
478 |
+
// All registered C and G sets, space and delete
|
479 |
+
case FILE_ASN1_TYPE_UTF8_STRING:
|
480 |
+
// ????
|
481 |
+
case FILE_ASN1_TYPE_BMP_STRING:
|
482 |
+
$current['content'] = $content;
|
483 |
+
break;
|
484 |
+
case FILE_ASN1_TYPE_UTC_TIME:
|
485 |
+
case FILE_ASN1_TYPE_GENERALIZED_TIME:
|
486 |
+
$current['content'] = $this->_decodeTime($content, $tag);
|
487 |
+
default:
|
488 |
+
|
489 |
+
}
|
490 |
+
|
491 |
+
$start+= $length;
|
492 |
+
$decoded[] = $current + array('length' => $start - $current['start']);
|
493 |
+
}
|
494 |
+
|
495 |
+
return $decoded;
|
496 |
+
}
|
497 |
+
|
498 |
+
/**
|
499 |
+
* ASN.1 Decode
|
500 |
+
*
|
501 |
+
* Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
|
502 |
+
*
|
503 |
+
* @param Array $decoded
|
504 |
+
* @param Array $mapping
|
505 |
+
* @return Array
|
506 |
+
* @access public
|
507 |
+
*/
|
508 |
+
function asn1map($decoded, $mapping)
|
509 |
+
{
|
510 |
+
if (isset($mapping['explicit'])) {
|
511 |
+
$decoded = $decoded['content'][0];
|
512 |
+
}
|
513 |
+
|
514 |
+
switch (true) {
|
515 |
+
case $mapping['type'] == FILE_ASN1_TYPE_ANY:
|
516 |
+
$intype = $decoded['type'];
|
517 |
+
if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || ($this->encoded[$decoded['start']] & 0x20)) {
|
518 |
+
return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
|
519 |
+
}
|
520 |
+
$inmap = $this->ANYmap[$intype];
|
521 |
+
if (is_string($inmap)) {
|
522 |
+
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping));
|
523 |
+
}
|
524 |
+
break;
|
525 |
+
case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
|
526 |
+
foreach ($mapping['children'] as $key => $option) {
|
527 |
+
switch (true) {
|
528 |
+
case isset($option['constant']) && $option['constant'] == $decoded['constant']:
|
529 |
+
case !isset($option['constant']) && $option['type'] == $decoded['type']:
|
530 |
+
$value = $this->asn1map($decoded, $option);
|
531 |
+
break;
|
532 |
+
case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
|
533 |
+
$v = $this->asn1map($decoded, $option);
|
534 |
+
if (isset($v)) {
|
535 |
+
$value = $v;
|
536 |
+
}
|
537 |
+
}
|
538 |
+
if (isset($value)) {
|
539 |
+
return array($key => $value);
|
540 |
+
}
|
541 |
+
}
|
542 |
+
return NULL;
|
543 |
+
case isset($mapping['implicit']):
|
544 |
+
case isset($mapping['explicit']):
|
545 |
+
case $decoded['type'] == $mapping['type']:
|
546 |
+
break;
|
547 |
+
default:
|
548 |
+
return NULL;
|
549 |
+
}
|
550 |
+
|
551 |
+
if (isset($mapping['implicit'])) {
|
552 |
+
$decoded['type'] = $mapping['type'];
|
553 |
+
}
|
554 |
+
|
555 |
+
switch ($decoded['type']) {
|
556 |
+
case FILE_ASN1_TYPE_SEQUENCE:
|
557 |
+
$map = array();
|
558 |
+
|
559 |
+
// ignore the min and max
|
560 |
+
if (isset($mapping['min']) && isset($mapping['max'])) {
|
561 |
+
$child = $mapping['children'];
|
562 |
+
foreach ($decoded['content'] as $content) {
|
563 |
+
if (($map[] = $this->asn1map($content, $child)) === NULL) {
|
564 |
+
return NULL;
|
565 |
+
}
|
566 |
+
}
|
567 |
+
|
568 |
+
return $map;
|
569 |
+
}
|
570 |
+
|
571 |
+
$n = count($decoded['content']);
|
572 |
+
$i = 0;
|
573 |
+
|
574 |
+
foreach ($mapping['children'] as $key => $child) {
|
575 |
+
$maymatch = $i < $n; // Match only existing input.
|
576 |
+
if ($maymatch) {
|
577 |
+
$temp = $decoded['content'][$i];
|
578 |
+
|
579 |
+
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
|
580 |
+
// Get the mapping and input class & constant.
|
581 |
+
$childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
|
582 |
+
$constant = NULL;
|
583 |
+
if (isset($temp['constant'])) {
|
584 |
+
$tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
585 |
+
}
|
586 |
+
if (isset($child['class'])) {
|
587 |
+
$childClass = $child['class'];
|
588 |
+
$constant = $child['cast'];
|
589 |
+
}
|
590 |
+
elseif (isset($child['constant'])) {
|
591 |
+
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
592 |
+
$constant = $child['constant'];
|
593 |
+
}
|
594 |
+
|
595 |
+
if (isset($constant) && isset($temp['constant'])) {
|
596 |
+
// Can only match if constants and class match.
|
597 |
+
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
|
598 |
+
} else {
|
599 |
+
// Can only match if no constant expected and type matches or is generic.
|
600 |
+
$maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
|
601 |
+
}
|
602 |
+
}
|
603 |
+
}
|
604 |
+
|
605 |
+
if ($maymatch) {
|
606 |
+
// Attempt submapping.
|
607 |
+
$candidate = $this->asn1map($temp, $child);
|
608 |
+
$maymatch = $candidate !== NULL;
|
609 |
+
}
|
610 |
+
|
611 |
+
if ($maymatch) {
|
612 |
+
// Got the match: use it.
|
613 |
+
$map[$key] = $candidate;
|
614 |
+
$i++;
|
615 |
+
} elseif (isset($child['default'])) {
|
616 |
+
$map[$key] = $child['default']; // Use default.
|
617 |
+
} elseif (!isset($child['optional'])) {
|
618 |
+
return NULL; // Syntax error.
|
619 |
+
}
|
620 |
+
}
|
621 |
+
|
622 |
+
// Fail mapping if all input items have not been consumed.
|
623 |
+
return $i < $n? NULL: $map;
|
624 |
+
|
625 |
+
// the main diff between sets and sequences is the encapsulation of the foreach in another for loop
|
626 |
+
case FILE_ASN1_TYPE_SET:
|
627 |
+
$map = array();
|
628 |
+
|
629 |
+
// ignore the min and max
|
630 |
+
if (isset($mapping['min']) && isset($mapping['max'])) {
|
631 |
+
$child = $mapping['children'];
|
632 |
+
foreach ($decoded['content'] as $content) {
|
633 |
+
if (($map[] = $this->asn1map($content, $child)) === NULL) {
|
634 |
+
return NULL;
|
635 |
+
}
|
636 |
+
}
|
637 |
+
|
638 |
+
return $map;
|
639 |
+
}
|
640 |
+
|
641 |
+
for ($i = 0; $i < count($decoded['content']); $i++) {
|
642 |
+
$temp = $decoded['content'][$i];
|
643 |
+
$tempClass = FILE_ASN1_CLASS_UNIVERSAL;
|
644 |
+
if (isset($temp['constant'])) {
|
645 |
+
$tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
646 |
+
}
|
647 |
+
|
648 |
+
foreach ($mapping['children'] as $key => $child) {
|
649 |
+
if (isset($map[$key])) {
|
650 |
+
continue;
|
651 |
+
}
|
652 |
+
$maymatch = true;
|
653 |
+
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
|
654 |
+
$childClass = FILE_ASN1_CLASS_UNIVERSAL;
|
655 |
+
$constant = NULL;
|
656 |
+
if (isset($child['class'])) {
|
657 |
+
$childClass = $child['class'];
|
658 |
+
$constant = $child['cast'];
|
659 |
+
}
|
660 |
+
elseif (isset($child['constant'])) {
|
661 |
+
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
|
662 |
+
$constant = $child['constant'];
|
663 |
+
}
|
664 |
+
|
665 |
+
if (isset($constant) && isset($temp['constant'])) {
|
666 |
+
// Can only match if constants and class match.
|
667 |
+
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
|
668 |
+
} else {
|
669 |
+
// Can only match if no constant expected and type matches or is generic.
|
670 |
+
$maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
|
671 |
+
}
|
672 |
+
}
|
673 |
+
|
674 |
+
if ($maymatch) {
|
675 |
+
// Attempt submapping.
|
676 |
+
$candidate = $this->asn1map($temp, $child);
|
677 |
+
$maymatch = $candidate !== NULL;
|
678 |
+
}
|
679 |
+
|
680 |
+
if (!$maymatch) {
|
681 |
+
break;
|
682 |
+
}
|
683 |
+
|
684 |
+
// Got the match: use it.
|
685 |
+
$map[$key] = $candidate;
|
686 |
+
break;
|
687 |
+
}
|
688 |
+
}
|
689 |
+
|
690 |
+
foreach ($mapping['children'] as $key => $child) {
|
691 |
+
if (!isset($map[$key])) {
|
692 |
+
if (isset($child['default'])) {
|
693 |
+
$map[$key] = $child['default'];
|
694 |
+
} elseif (!isset($child['optional'])) {
|
695 |
+
return NULL;
|
696 |
+
}
|
697 |
+
}
|
698 |
+
}
|
699 |
+
return $map;
|
700 |
+
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
701 |
+
return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
|
702 |
+
case FILE_ASN1_TYPE_UTC_TIME:
|
703 |
+
case FILE_ASN1_TYPE_GENERALIZED_TIME:
|
704 |
+
if (isset($mapping['implicit'])) {
|
705 |
+
$decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
|
706 |
+
}
|
707 |
+
return @date($this->format, $decoded['content']);
|
708 |
+
case FILE_ASN1_TYPE_BIT_STRING:
|
709 |
+
if (isset($mapping['mapping'])) {
|
710 |
+
$offset = ord($decoded['content'][0]);
|
711 |
+
$size = (strlen($decoded['content']) - 1) * 8 - $offset;
|
712 |
+
/*
|
713 |
+
From X.680-0207.pdf#page=46 (21.7):
|
714 |
+
|
715 |
+
"When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
|
716 |
+
arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
|
717 |
+
therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
|
718 |
+
0 bits."
|
719 |
+
*/
|
720 |
+
$bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
|
721 |
+
for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
|
722 |
+
$current = ord($decoded['content'][$i]);
|
723 |
+
for ($j = $offset; $j < 8; $j++) {
|
724 |
+
$bits[] = (bool) ($current & (1 << $j));
|
725 |
+
}
|
726 |
+
$offset = 0;
|
727 |
+
}
|
728 |
+
$values = array();
|
729 |
+
$map = array_reverse($mapping['mapping']);
|
730 |
+
foreach ($map as $i => $value) {
|
731 |
+
if ($bits[$i]) {
|
732 |
+
$values[] = $value;
|
733 |
+
}
|
734 |
+
}
|
735 |
+
return $values;
|
736 |
+
}
|
737 |
+
case FILE_ASN1_TYPE_OCTET_STRING:
|
738 |
+
return base64_encode($decoded['content']);
|
739 |
+
case FILE_ASN1_TYPE_NULL:
|
740 |
+
return '';
|
741 |
+
case FILE_ASN1_TYPE_BOOLEAN:
|
742 |
+
return $decoded['content'];
|
743 |
+
case FILE_ASN1_TYPE_NUMERIC_STRING:
|
744 |
+
case FILE_ASN1_TYPE_PRINTABLE_STRING:
|
745 |
+
case FILE_ASN1_TYPE_TELETEX_STRING:
|
746 |
+
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
|
747 |
+
case FILE_ASN1_TYPE_IA5_STRING:
|
748 |
+
case FILE_ASN1_TYPE_GRAPHIC_STRING:
|
749 |
+
case FILE_ASN1_TYPE_VISIBLE_STRING:
|
750 |
+
case FILE_ASN1_TYPE_GENERAL_STRING:
|
751 |
+
case FILE_ASN1_TYPE_UNIVERSAL_STRING:
|
752 |
+
case FILE_ASN1_TYPE_UTF8_STRING:
|
753 |
+
case FILE_ASN1_TYPE_BMP_STRING:
|
754 |
+
return $decoded['content'];
|
755 |
+
case FILE_ASN1_TYPE_INTEGER:
|
756 |
+
case FILE_ASN1_TYPE_ENUMERATED:
|
757 |
+
$temp = $decoded['content'];
|
758 |
+
if (isset($mapping['implicit'])) {
|
759 |
+
$temp = new Math_BigInteger($decoded['content'], -256);
|
760 |
+
}
|
761 |
+
if (isset($mapping['mapping'])) {
|
762 |
+
$temp = (int) $temp->toString();
|
763 |
+
return isset($mapping['mapping'][$temp]) ?
|
764 |
+
$mapping['mapping'][$temp] :
|
765 |
+
false;
|
766 |
+
}
|
767 |
+
return $temp;
|
768 |
+
}
|
769 |
+
}
|
770 |
+
|
771 |
+
/**
|
772 |
+
* ASN.1 Encode
|
773 |
+
*
|
774 |
+
* DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
|
775 |
+
* an ASN.1 compiler.
|
776 |
+
*
|
777 |
+
* @param String $source
|
778 |
+
* @param String $mapping
|
779 |
+
* @param Integer $idx
|
780 |
+
* @return String
|
781 |
+
* @access public
|
782 |
+
*/
|
783 |
+
function encodeDER($source, $mapping)
|
784 |
+
{
|
785 |
+
$this->location = array();
|
786 |
+
return $this->_encode_der($source, $mapping);
|
787 |
+
}
|
788 |
+
|
789 |
+
/**
|
790 |
+
* ASN.1 Encode (Helper function)
|
791 |
+
*
|
792 |
+
* @param String $source
|
793 |
+
* @param String $mapping
|
794 |
+
* @param Integer $idx
|
795 |
+
* @return String
|
796 |
+
* @access private
|
797 |
+
*/
|
798 |
+
function _encode_der($source, $mapping, $idx = NULL)
|
799 |
+
{
|
800 |
+
if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
|
801 |
+
return $source->element;
|
802 |
+
}
|
803 |
+
|
804 |
+
// do not encode (implicitly optional) fields with value set to default
|
805 |
+
if (isset($mapping['default']) && $source === $mapping['default']) {
|
806 |
+
return '';
|
807 |
+
}
|
808 |
+
|
809 |
+
if (isset($idx)) {
|
810 |
+
$this->location[] = $idx;
|
811 |
+
}
|
812 |
+
|
813 |
+
$tag = $mapping['type'];
|
814 |
+
|
815 |
+
switch ($tag) {
|
816 |
+
case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
|
817 |
+
case FILE_ASN1_TYPE_SEQUENCE:
|
818 |
+
$tag|= 0x20; // set the constructed bit
|
819 |
+
$value = '';
|
820 |
+
|
821 |
+
// ignore the min and max
|
822 |
+
if (isset($mapping['min']) && isset($mapping['max'])) {
|
823 |
+
$child = $mapping['children'];
|
824 |
+
|
825 |
+
foreach ($source as $content) {
|
826 |
+
$temp = $this->_encode_der($content, $child);
|
827 |
+
if ($temp === false) {
|
828 |
+
return false;
|
829 |
+
}
|
830 |
+
$value.= $temp;
|
831 |
+
}
|
832 |
+
break;
|
833 |
+
}
|
834 |
+
|
835 |
+
foreach ($mapping['children'] as $key => $child) {
|
836 |
+
if (!isset($source[$key])) {
|
837 |
+
if (!isset($child['optional'])) {
|
838 |
+
return false;
|
839 |
+
}
|
840 |
+
continue;
|
841 |
+
}
|
842 |
+
|
843 |
+
$temp = $this->_encode_der($source[$key], $child, $key);
|
844 |
+
if ($temp === false) {
|
845 |
+
return false;
|
846 |
+
}
|
847 |
+
|
848 |
+
// An empty child encoding means it has been optimized out.
|
849 |
+
// Else we should have at least one tag byte.
|
850 |
+
if ($temp === '') {
|
851 |
+
continue;
|
852 |
+
}
|
853 |
+
|
854 |
+
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
|
855 |
+
if (isset($child['constant'])) {
|
856 |
+
/*
|
857 |
+
From X.680-0207.pdf#page=58 (30.6):
|
858 |
+
|
859 |
+
"The tagging construction specifies explicit tagging if any of the following holds:
|
860 |
+
...
|
861 |
+
c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
|
862 |
+
AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
|
863 |
+
an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
|
864 |
+
*/
|
865 |
+
if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
|
866 |
+
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
|
867 |
+
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
|
868 |
+
} else {
|
869 |
+
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
|
870 |
+
$temp = $subtag . substr($temp, 1);
|
871 |
+
}
|
872 |
+
}
|
873 |
+
$value.= $temp;
|
874 |
+
}
|
875 |
+
break;
|
876 |
+
case FILE_ASN1_TYPE_CHOICE:
|
877 |
+
$temp = false;
|
878 |
+
|
879 |
+
foreach ($mapping['children'] as $key => $child) {
|
880 |
+
if (!isset($source[$key])) {
|
881 |
+
continue;
|
882 |
+
}
|
883 |
+
|
884 |
+
$temp = $this->_encode_der($source[$key], $child, $key);
|
885 |
+
if ($temp === false) {
|
886 |
+
return false;
|
887 |
+
}
|
888 |
+
|
889 |
+
// An empty child encoding means it has been optimized out.
|
890 |
+
// Else we should have at least one tag byte.
|
891 |
+
if ($temp === '') {
|
892 |
+
continue;
|
893 |
+
}
|
894 |
+
|
895 |
+
$tag = ord($temp[0]);
|
896 |
+
|
897 |
+
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
|
898 |
+
if (isset($child['constant'])) {
|
899 |
+
if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
|
900 |
+
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
|
901 |
+
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
|
902 |
+
} else {
|
903 |
+
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
|
904 |
+
$temp = $subtag . substr($temp, 1);
|
905 |
+
}
|
906 |
+
}
|
907 |
+
}
|
908 |
+
|
909 |
+
if (isset($idx)) {
|
910 |
+
array_pop($this->location);
|
911 |
+
}
|
912 |
+
|
913 |
+
if ($temp && isset($mapping['cast'])) {
|
914 |
+
$temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
|
915 |
+
}
|
916 |
+
|
917 |
+
return $temp;
|
918 |
+
case FILE_ASN1_TYPE_INTEGER:
|
919 |
+
case FILE_ASN1_TYPE_ENUMERATED:
|
920 |
+
if (!isset($mapping['mapping'])) {
|
921 |
+
$value = $source->toBytes(true);
|
922 |
+
} else {
|
923 |
+
$value = array_search($source, $mapping['mapping']);
|
924 |
+
if ($value === false) {
|
925 |
+
return false;
|
926 |
+
}
|
927 |
+
$value = new Math_BigInteger($value);
|
928 |
+
$value = $value->toBytes(true);
|
929 |
+
if (!strlen($value)) {
|
930 |
+
$value = chr(0);
|
931 |
+
}
|
932 |
+
}
|
933 |
+
break;
|
934 |
+
case FILE_ASN1_TYPE_UTC_TIME:
|
935 |
+
case FILE_ASN1_TYPE_GENERALIZED_TIME:
|
936 |
+
$format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
|
937 |
+
$format.= 'mdHis';
|
938 |
+
$value = @gmdate($format, strtotime($source)) . 'Z';
|
939 |
+
break;
|
940 |
+
case FILE_ASN1_TYPE_BIT_STRING:
|
941 |
+
if (isset($mapping['mapping'])) {
|
942 |
+
$bits = array_fill(0, count($mapping['mapping']), 0);
|
943 |
+
$size = 0;
|
944 |
+
for ($i = 0; $i < count($mapping['mapping']); $i++) {
|
945 |
+
if (in_array($mapping['mapping'][$i], $source)) {
|
946 |
+
$bits[$i] = 1;
|
947 |
+
$size = $i;
|
948 |
+
}
|
949 |
+
}
|
950 |
+
|
951 |
+
$offset = 8 - (($size + 1) & 7);
|
952 |
+
$offset = $offset !== 8 ? $offset : 0;
|
953 |
+
|
954 |
+
$value = chr($offset);
|
955 |
+
|
956 |
+
for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
|
957 |
+
unset($bits[$i]);
|
958 |
+
}
|
959 |
+
|
960 |
+
$bits = implode('', array_pad($bits, $size + $offset + 1, 0));
|
961 |
+
$bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
|
962 |
+
foreach ($bytes as $byte) {
|
963 |
+
$value.= chr(bindec($byte));
|
964 |
+
}
|
965 |
+
|
966 |
+
break;
|
967 |
+
}
|
968 |
+
case FILE_ASN1_TYPE_OCTET_STRING:
|
969 |
+
/* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
|
970 |
+
the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
|
971 |
+
|
972 |
+
-- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
|
973 |
+
$value = base64_decode($source);
|
974 |
+
break;
|
975 |
+
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
|
976 |
+
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
|
977 |
+
if ($oid === false) {
|
978 |
+
user_error('Invalid OID');
|
979 |
+
return false;
|
980 |
+
}
|
981 |
+
$value = '';
|
982 |
+
$parts = explode('.', $oid);
|
983 |
+
$value = chr(40 * $parts[0] + $parts[1]);
|
984 |
+
for ($i = 2; $i < count($parts); $i++) {
|
985 |
+
$temp = '';
|
986 |
+
if (!$parts[$i]) {
|
987 |
+
$temp = "\0";
|
988 |
+
} else {
|
989 |
+
while ($parts[$i]) {
|
990 |
+
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
|
991 |
+
$parts[$i] >>= 7;
|
992 |
+
}
|
993 |
+
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
|
994 |
+
}
|
995 |
+
$value.= $temp;
|
996 |
+
}
|
997 |
+
break;
|
998 |
+
case FILE_ASN1_TYPE_ANY:
|
999 |
+
$loc = $this->location;
|
1000 |
+
if (isset($idx)) {
|
1001 |
+
array_pop($this->location);
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
switch (true) {
|
1005 |
+
case !isset($source):
|
1006 |
+
return $this->_encode_der(NULL, array('type' => FILE_ASN1_TYPE_NULL) + $mapping);
|
1007 |
+
case is_int($source):
|
1008 |
+
case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
|
1009 |
+
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping);
|
1010 |
+
case is_float($source):
|
1011 |
+
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping);
|
1012 |
+
case is_bool($source):
|
1013 |
+
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping);
|
1014 |
+
case is_array($source) && count($source) == 1:
|
1015 |
+
$typename = implode('', array_keys($source));
|
1016 |
+
$outtype = array_search($typename, $this->ANYmap, true);
|
1017 |
+
if ($outtype !== false) {
|
1018 |
+
return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping);
|
1019 |
+
}
|
1020 |
+
}
|
1021 |
+
|
1022 |
+
$filters = $this->filters;
|
1023 |
+
foreach ($loc as $part) {
|
1024 |
+
if (!isset($filters[$part])) {
|
1025 |
+
$filters = false;
|
1026 |
+
break;
|
1027 |
+
}
|
1028 |
+
$filters = $filters[$part];
|
1029 |
+
}
|
1030 |
+
if ($filters === false) {
|
1031 |
+
user_error('No filters defined for ' . implode('/', $loc));
|
1032 |
+
return false;
|
1033 |
+
}
|
1034 |
+
return $this->_encode_der($source, $filters + $mapping);
|
1035 |
+
case FILE_ASN1_TYPE_NULL:
|
1036 |
+
$value = '';
|
1037 |
+
break;
|
1038 |
+
case FILE_ASN1_TYPE_NUMERIC_STRING:
|
1039 |
+
case FILE_ASN1_TYPE_TELETEX_STRING:
|
1040 |
+
case FILE_ASN1_TYPE_PRINTABLE_STRING:
|
1041 |
+
case FILE_ASN1_TYPE_UNIVERSAL_STRING:
|
1042 |
+
case FILE_ASN1_TYPE_UTF8_STRING:
|
1043 |
+
case FILE_ASN1_TYPE_BMP_STRING:
|
1044 |
+
case FILE_ASN1_TYPE_IA5_STRING:
|
1045 |
+
case FILE_ASN1_TYPE_VISIBLE_STRING:
|
1046 |
+
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
|
1047 |
+
case FILE_ASN1_TYPE_GRAPHIC_STRING:
|
1048 |
+
case FILE_ASN1_TYPE_GENERAL_STRING:
|
1049 |
+
$value = $source;
|
1050 |
+
break;
|
1051 |
+
case FILE_ASN1_TYPE_BOOLEAN:
|
1052 |
+
$value = $source ? "\xFF" : "\x00";
|
1053 |
+
break;
|
1054 |
+
default:
|
1055 |
+
user_error('Mapping provides no type definition for ' . implode('/', $this->location));
|
1056 |
+
return false;
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
if (isset($idx)) {
|
1060 |
+
array_pop($this->location);
|
1061 |
+
}
|
1062 |
+
|
1063 |
+
if (isset($mapping['cast'])) {
|
1064 |
+
$tag = ($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast'];
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
|
1068 |
+
}
|
1069 |
+
|
1070 |
+
/**
|
1071 |
+
* DER-encode the length
|
1072 |
+
*
|
1073 |
+
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
1074 |
+
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
1075 |
+
*
|
1076 |
+
* @access private
|
1077 |
+
* @param Integer $length
|
1078 |
+
* @return String
|
1079 |
+
*/
|
1080 |
+
function _encodeLength($length)
|
1081 |
+
{
|
1082 |
+
if ($length <= 0x7F) {
|
1083 |
+
return chr($length);
|
1084 |
+
}
|
1085 |
+
|
1086 |
+
$temp = ltrim(pack('N', $length), chr(0));
|
1087 |
+
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
/**
|
1091 |
+
* BER-decode the time
|
1092 |
+
*
|
1093 |
+
* Called by _decode_ber() and in the case of implicit tags asn1map().
|
1094 |
+
*
|
1095 |
+
* @access private
|
1096 |
+
* @param String $content
|
1097 |
+
* @param Integer $tag
|
1098 |
+
* @return String
|
1099 |
+
*/
|
1100 |
+
function _decodeTime($content, $tag)
|
1101 |
+
{
|
1102 |
+
/* UTCTime:
|
1103 |
+
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
|
1104 |
+
http://www.obj-sys.com/asn1tutorial/node15.html
|
1105 |
+
|
1106 |
+
GeneralizedTime:
|
1107 |
+
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
|
1108 |
+
http://www.obj-sys.com/asn1tutorial/node14.html */
|
1109 |
+
|
1110 |
+
$pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
|
1111 |
+
'#(..)(..)(..)(..)(..)(..)(.*)#' :
|
1112 |
+
'#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
|
1113 |
+
|
1114 |
+
preg_match($pattern, $content, $matches);
|
1115 |
+
|
1116 |
+
list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
|
1117 |
+
|
1118 |
+
if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
|
1119 |
+
$year = $year >= 50 ? "19$year" : "20$year";
|
1120 |
+
}
|
1121 |
+
|
1122 |
+
if ($timezone == 'Z') {
|
1123 |
+
$mktime = 'gmmktime';
|
1124 |
+
$timezone = 0;
|
1125 |
+
} elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
|
1126 |
+
$mktime = 'gmmktime';
|
1127 |
+
$timezone = 60 * $matches[3] + 3600 * $matches[2];
|
1128 |
+
if ($matches[1] == '-') {
|
1129 |
+
$timezone = -$timezone;
|
1130 |
+
}
|
1131 |
+
} else {
|
1132 |
+
$mktime = 'mktime';
|
1133 |
+
$timezone = 0;
|
1134 |
+
}
|
1135 |
+
|
1136 |
+
return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
|
1137 |
+
}
|
1138 |
+
|
1139 |
+
/**
|
1140 |
+
* Set the time format
|
1141 |
+
*
|
1142 |
+
* Sets the time / date format for asn1map().
|
1143 |
+
*
|
1144 |
+
* @access public
|
1145 |
+
* @param String $format
|
1146 |
+
*/
|
1147 |
+
function setTimeFormat($format)
|
1148 |
+
{
|
1149 |
+
$this->format = $format;
|
1150 |
+
}
|
1151 |
+
|
1152 |
+
/**
|
1153 |
+
* Load OIDs
|
1154 |
+
*
|
1155 |
+
* Load the relevant OIDs for a particular ASN.1 semantic mapping.
|
1156 |
+
*
|
1157 |
+
* @access public
|
1158 |
+
* @param Array $oids
|
1159 |
+
*/
|
1160 |
+
function loadOIDs($oids)
|
1161 |
+
{
|
1162 |
+
$this->oids = $oids;
|
1163 |
+
}
|
1164 |
+
|
1165 |
+
/**
|
1166 |
+
* Load filters
|
1167 |
+
*
|
1168 |
+
* See File_X509, etc, for an example.
|
1169 |
+
*
|
1170 |
+
* @access public
|
1171 |
+
* @param Array $filters
|
1172 |
+
*/
|
1173 |
+
function loadFilters($filters)
|
1174 |
+
{
|
1175 |
+
$this->filters = $filters;
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
/**
|
1179 |
+
* String Shift
|
1180 |
+
*
|
1181 |
+
* Inspired by array_shift
|
1182 |
+
*
|
1183 |
+
* @param String $string
|
1184 |
+
* @param optional Integer $index
|
1185 |
+
* @return String
|
1186 |
+
* @access private
|
1187 |
+
*/
|
1188 |
+
function _string_shift(&$string, $index = 1)
|
1189 |
+
{
|
1190 |
+
$substr = substr($string, 0, $index);
|
1191 |
+
$string = substr($string, $index);
|
1192 |
+
return $substr;
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
/**
|
1196 |
+
* String type conversion
|
1197 |
+
*
|
1198 |
+
* This is a lazy conversion, dealing only with character size.
|
1199 |
+
* No real conversion table is used.
|
1200 |
+
*
|
1201 |
+
* @param String $in
|
1202 |
+
* @param optional Integer $from
|
1203 |
+
* @param optional Integer $to
|
1204 |
+
* @return String
|
1205 |
+
* @access public
|
1206 |
+
*/
|
1207 |
+
function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
|
1208 |
+
{
|
1209 |
+
if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
|
1210 |
+
return false;
|
1211 |
+
}
|
1212 |
+
$insize = $this->stringTypeSize[$from];
|
1213 |
+
$outsize = $this->stringTypeSize[$to];
|
1214 |
+
$inlength = strlen($in);
|
1215 |
+
$out = '';
|
1216 |
+
|
1217 |
+
for ($i = 0; $i < $inlength;) {
|
1218 |
+
if ($inlength - $i < $insize) {
|
1219 |
+
return false;
|
1220 |
+
}
|
1221 |
+
|
1222 |
+
// Get an input character as a 32-bit value.
|
1223 |
+
$c = ord($in[$i++]);
|
1224 |
+
switch (true) {
|
1225 |
+
case $insize == 4:
|
1226 |
+
$c = ($c << 8) | ord($in[$i++]);
|
1227 |
+
$c = ($c << 8) | ord($in[$i++]);
|
1228 |
+
case $insize == 2:
|
1229 |
+
$c = ($c << 8) | ord($in[$i++]);
|
1230 |
+
case $insize == 1:
|
1231 |
+
break;
|
1232 |
+
case ($c & 0x80) == 0x00:
|
1233 |
+
break;
|
1234 |
+
case ($c & 0x40) == 0x00:
|
1235 |
+
return false;
|
1236 |
+
default:
|
1237 |
+
$bit = 6;
|
1238 |
+
do {
|
1239 |
+
if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
|
1240 |
+
return false;
|
1241 |
+
}
|
1242 |
+
$c = ($c << 6) | (ord($in[$i++]) & 0x3F);
|
1243 |
+
$bit += 5;
|
1244 |
+
$mask = 1 << $bit;
|
1245 |
+
} while ($c & $bit);
|
1246 |
+
$c &= $mask - 1;
|
1247 |
+
break;
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
// Convert and append the character to output string.
|
1251 |
+
$v = '';
|
1252 |
+
switch (true) {
|
1253 |
+
case $outsize == 4:
|
1254 |
+
$v .= chr($c & 0xFF);
|
1255 |
+
$c >>= 8;
|
1256 |
+
$v .= chr($c & 0xFF);
|
1257 |
+
$c >>= 8;
|
1258 |
+
case $outsize == 2:
|
1259 |
+
$v .= chr($c & 0xFF);
|
1260 |
+
$c >>= 8;
|
1261 |
+
case $outsize == 1:
|
1262 |
+
$v .= chr($c & 0xFF);
|
1263 |
+
$c >>= 8;
|
1264 |
+
if ($c) {
|
1265 |
+
return false;
|
1266 |
+
}
|
1267 |
+
break;
|
1268 |
+
case ($c & 0x80000000) != 0:
|
1269 |
+
return false;
|
1270 |
+
case $c >= 0x04000000:
|
1271 |
+
$v .= chr(0x80 | ($c & 0x3F));
|
1272 |
+
$c = ($c >> 6) | 0x04000000;
|
1273 |
+
case $c >= 0x00200000:
|
1274 |
+
$v .= chr(0x80 | ($c & 0x3F));
|
1275 |
+
$c = ($c >> 6) | 0x00200000;
|
1276 |
+
case $c >= 0x00010000:
|
1277 |
+
$v .= chr(0x80 | ($c & 0x3F));
|
1278 |
+
$c = ($c >> 6) | 0x00010000;
|
1279 |
+
case $c >= 0x00000800:
|
1280 |
+
$v .= chr(0x80 | ($c & 0x3F));
|
1281 |
+
$c = ($c >> 6) | 0x00000800;
|
1282 |
+
case $c >= 0x00000080:
|
1283 |
+
$v .= chr(0x80 | ($c & 0x3F));
|
1284 |
+
$c = ($c >> 6) | 0x000000C0;
|
1285 |
+
default:
|
1286 |
+
$v .= chr($c);
|
1287 |
+
break;
|
1288 |
+
}
|
1289 |
+
$out .= strrev($v);
|
1290 |
+
}
|
1291 |
+
return $out;
|
1292 |
+
}
|
1293 |
+
}
|
lib/PHPSecLib/File/X509.php
ADDED
@@ -0,0 +1,4351 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP X.509 Parser
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Encode and decode X.509 certificates.
|
10 |
+
*
|
11 |
+
* The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and
|
12 |
+
* {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}.
|
13 |
+
*
|
14 |
+
* Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a
|
15 |
+
* portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is
|
16 |
+
* used. Problem is, if the parameter is there and it just so happens to have the default value there are two ways that that parameter can
|
17 |
+
* be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the
|
18 |
+
* the certificate all together unless the certificate is re-signed.
|
19 |
+
*
|
20 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
21 |
+
* of this software and associated documentation files (the "Software"), to deal
|
22 |
+
* in the Software without restriction, including without limitation the rights
|
23 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
24 |
+
* copies of the Software, and to permit persons to whom the Software is
|
25 |
+
* furnished to do so, subject to the following conditions:
|
26 |
+
*
|
27 |
+
* The above copyright notice and this permission notice shall be included in
|
28 |
+
* all copies or substantial portions of the Software.
|
29 |
+
*
|
30 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
31 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
32 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
33 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
34 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
35 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
36 |
+
* THE SOFTWARE.
|
37 |
+
*
|
38 |
+
* @category File
|
39 |
+
* @package File_X509
|
40 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
41 |
+
* @copyright MMXII Jim Wigginton
|
42 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
43 |
+
* @link http://phpseclib.sourceforge.net
|
44 |
+
*/
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Include File_ASN1
|
48 |
+
*/
|
49 |
+
if (!class_exists('File_ASN1')) {
|
50 |
+
require_once('ASN1.php');
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Flag to only accept signatures signed by certificate authorities
|
55 |
+
*
|
56 |
+
* Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
|
57 |
+
*
|
58 |
+
* @access public
|
59 |
+
*/
|
60 |
+
define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1);
|
61 |
+
|
62 |
+
/**#@+
|
63 |
+
* @access public
|
64 |
+
* @see File_X509::getDN()
|
65 |
+
*/
|
66 |
+
/**
|
67 |
+
* Return internal array representation
|
68 |
+
*/
|
69 |
+
define('FILE_X509_DN_ARRAY', 0);
|
70 |
+
/**
|
71 |
+
* Return string
|
72 |
+
*/
|
73 |
+
define('FILE_X509_DN_STRING', 1);
|
74 |
+
/**
|
75 |
+
* Return ASN.1 name string
|
76 |
+
*/
|
77 |
+
define('FILE_X509_DN_ASN1', 2);
|
78 |
+
/**
|
79 |
+
* Return OpenSSL compatible array
|
80 |
+
*/
|
81 |
+
define('FILE_X509_DN_OPENSSL', 3);
|
82 |
+
/**
|
83 |
+
* Return canonical ASN.1 RDNs string
|
84 |
+
*/
|
85 |
+
define('FILE_X509_DN_CANON', 4);
|
86 |
+
/**
|
87 |
+
* Return name hash for file indexing
|
88 |
+
*/
|
89 |
+
define('FILE_X509_DN_HASH', 5);
|
90 |
+
/**#@-*/
|
91 |
+
|
92 |
+
/**#@+
|
93 |
+
* @access public
|
94 |
+
* @see File_X509::saveX509()
|
95 |
+
* @see File_X509::saveCSR()
|
96 |
+
* @see File_X509::saveCRL()
|
97 |
+
*/
|
98 |
+
/**
|
99 |
+
* Save as PEM
|
100 |
+
*
|
101 |
+
* ie. a base64-encoded PEM with a header and a footer
|
102 |
+
*/
|
103 |
+
define('FILE_X509_FORMAT_PEM', 0);
|
104 |
+
/**
|
105 |
+
* Save as DER
|
106 |
+
*/
|
107 |
+
define('FILE_X509_FORMAT_DER', 1);
|
108 |
+
/**
|
109 |
+
* Save as a SPKAC
|
110 |
+
*
|
111 |
+
* Only works on CSRs. Not currently supported.
|
112 |
+
*/
|
113 |
+
define('FILE_X509_FORMAT_SPKAC', 2);
|
114 |
+
/**#@-*/
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Attribute value disposition.
|
118 |
+
* If disposition is >= 0, this is the index of the target value.
|
119 |
+
*/
|
120 |
+
define('FILE_X509_ATTR_ALL', -1); // All attribute values (array).
|
121 |
+
define('FILE_X509_ATTR_APPEND', -2); // Add a value.
|
122 |
+
define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Pure-PHP X.509 Parser
|
126 |
+
*
|
127 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
128 |
+
* @version 0.3.1
|
129 |
+
* @access public
|
130 |
+
* @package File_X509
|
131 |
+
*/
|
132 |
+
class File_X509 {
|
133 |
+
/**
|
134 |
+
* ASN.1 syntax for X.509 certificates
|
135 |
+
*
|
136 |
+
* @var Array
|
137 |
+
* @access private
|
138 |
+
*/
|
139 |
+
var $Certificate;
|
140 |
+
|
141 |
+
/**#@+
|
142 |
+
* ASN.1 syntax for various extensions
|
143 |
+
*
|
144 |
+
* @access private
|
145 |
+
*/
|
146 |
+
var $DirectoryString;
|
147 |
+
var $PKCS9String;
|
148 |
+
var $AttributeValue;
|
149 |
+
var $Extensions;
|
150 |
+
var $KeyUsage;
|
151 |
+
var $ExtKeyUsageSyntax;
|
152 |
+
var $BasicConstraints;
|
153 |
+
var $KeyIdentifier;
|
154 |
+
var $CRLDistributionPoints;
|
155 |
+
var $AuthorityKeyIdentifier;
|
156 |
+
var $CertificatePolicies;
|
157 |
+
var $AuthorityInfoAccessSyntax;
|
158 |
+
var $SubjectAltName;
|
159 |
+
var $PrivateKeyUsagePeriod;
|
160 |
+
var $IssuerAltName;
|
161 |
+
var $PolicyMappings;
|
162 |
+
var $NameConstraints;
|
163 |
+
|
164 |
+
var $CPSuri;
|
165 |
+
var $UserNotice;
|
166 |
+
|
167 |
+
var $netscape_cert_type;
|
168 |
+
var $netscape_comment;
|
169 |
+
var $netscape_ca_policy_url;
|
170 |
+
|
171 |
+
var $Name;
|
172 |
+
var $RelativeDistinguishedName;
|
173 |
+
var $CRLNumber;
|
174 |
+
var $CRLReason;
|
175 |
+
var $IssuingDistributionPoint;
|
176 |
+
var $InvalidityDate;
|
177 |
+
var $CertificateIssuer;
|
178 |
+
var $HoldInstructionCode;
|
179 |
+
var $SignedPublicKeyAndChallenge;
|
180 |
+
/**#@-*/
|
181 |
+
|
182 |
+
/**
|
183 |
+
* ASN.1 syntax for Certificate Signing Requests (RFC2986)
|
184 |
+
*
|
185 |
+
* @var Array
|
186 |
+
* @access private
|
187 |
+
*/
|
188 |
+
var $CertificationRequest;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* ASN.1 syntax for Certificate Revocation Lists (RFC5280)
|
192 |
+
*
|
193 |
+
* @var Array
|
194 |
+
* @access private
|
195 |
+
*/
|
196 |
+
var $CertificateList;
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Distinguished Name
|
200 |
+
*
|
201 |
+
* @var Array
|
202 |
+
* @access private
|
203 |
+
*/
|
204 |
+
var $dn;
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Public key
|
208 |
+
*
|
209 |
+
* @var String
|
210 |
+
* @access private
|
211 |
+
*/
|
212 |
+
var $publicKey;
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Private key
|
216 |
+
*
|
217 |
+
* @var String
|
218 |
+
* @access private
|
219 |
+
*/
|
220 |
+
var $privateKey;
|
221 |
+
|
222 |
+
/**
|
223 |
+
* Object identifiers for X.509 certificates
|
224 |
+
*
|
225 |
+
* @var Array
|
226 |
+
* @access private
|
227 |
+
* @link http://en.wikipedia.org/wiki/Object_identifier
|
228 |
+
*/
|
229 |
+
var $oids;
|
230 |
+
|
231 |
+
/**
|
232 |
+
* The certificate authorities
|
233 |
+
*
|
234 |
+
* @var Array
|
235 |
+
* @access private
|
236 |
+
*/
|
237 |
+
var $CAs;
|
238 |
+
|
239 |
+
/**
|
240 |
+
* The currently loaded certificate
|
241 |
+
*
|
242 |
+
* @var Array
|
243 |
+
* @access private
|
244 |
+
*/
|
245 |
+
var $currentCert;
|
246 |
+
|
247 |
+
/**
|
248 |
+
* The signature subject
|
249 |
+
*
|
250 |
+
* There's no guarantee File_X509 is going to reencode an X.509 cert in the same way it was originally
|
251 |
+
* encoded so we take save the portion of the original cert that the signature would have made for.
|
252 |
+
*
|
253 |
+
* @var String
|
254 |
+
* @access private
|
255 |
+
*/
|
256 |
+
var $signatureSubject;
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Certificate Start Date
|
260 |
+
*
|
261 |
+
* @var String
|
262 |
+
* @access private
|
263 |
+
*/
|
264 |
+
var $startDate;
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Certificate End Date
|
268 |
+
*
|
269 |
+
* @var String
|
270 |
+
* @access private
|
271 |
+
*/
|
272 |
+
var $endDate;
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Serial Number
|
276 |
+
*
|
277 |
+
* @var String
|
278 |
+
* @access private
|
279 |
+
*/
|
280 |
+
var $serialNumber;
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Key Identifier
|
284 |
+
*
|
285 |
+
* See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
|
286 |
+
* {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
|
287 |
+
*
|
288 |
+
* @var String
|
289 |
+
* @access private
|
290 |
+
*/
|
291 |
+
var $currentKeyIdentifier;
|
292 |
+
|
293 |
+
/**
|
294 |
+
* CA Flag
|
295 |
+
*
|
296 |
+
* @var Boolean
|
297 |
+
* @access private
|
298 |
+
*/
|
299 |
+
var $caFlag = false;
|
300 |
+
|
301 |
+
/**
|
302 |
+
* Default Constructor.
|
303 |
+
*
|
304 |
+
* @return File_X509
|
305 |
+
* @access public
|
306 |
+
*/
|
307 |
+
function File_X509()
|
308 |
+
{
|
309 |
+
// Explicitly Tagged Module, 1988 Syntax
|
310 |
+
// http://tools.ietf.org/html/rfc5280#appendix-A.1
|
311 |
+
|
312 |
+
$this->DirectoryString = array(
|
313 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
314 |
+
'children' => array(
|
315 |
+
'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING),
|
316 |
+
'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
|
317 |
+
'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING),
|
318 |
+
'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING),
|
319 |
+
'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING)
|
320 |
+
)
|
321 |
+
);
|
322 |
+
|
323 |
+
$this->PKCS9String = array(
|
324 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
325 |
+
'children' => array(
|
326 |
+
'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
|
327 |
+
'directoryString' => $this->DirectoryString
|
328 |
+
)
|
329 |
+
);
|
330 |
+
|
331 |
+
$this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY);
|
332 |
+
|
333 |
+
$AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
|
334 |
+
|
335 |
+
$AttributeTypeAndValue = array(
|
336 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
337 |
+
'children' => array(
|
338 |
+
'type' => $AttributeType,
|
339 |
+
'value'=> $this->AttributeValue
|
340 |
+
)
|
341 |
+
);
|
342 |
+
|
343 |
+
/*
|
344 |
+
In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
|
345 |
+
but they can be useful at times when either there is no unique attribute in the entry or you
|
346 |
+
want to ensure that the entry's DN contains some useful identifying information.
|
347 |
+
|
348 |
+
- https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
|
349 |
+
*/
|
350 |
+
$this->RelativeDistinguishedName = array(
|
351 |
+
'type' => FILE_ASN1_TYPE_SET,
|
352 |
+
'min' => 1,
|
353 |
+
'max' => -1,
|
354 |
+
'children' => $AttributeTypeAndValue
|
355 |
+
);
|
356 |
+
|
357 |
+
// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
|
358 |
+
$RDNSequence = array(
|
359 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
360 |
+
// RDNSequence does not define a min or a max, which means it doesn't have one
|
361 |
+
'min' => 0,
|
362 |
+
'max' => -1,
|
363 |
+
'children' => $this->RelativeDistinguishedName
|
364 |
+
);
|
365 |
+
|
366 |
+
$this->Name = array(
|
367 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
368 |
+
'children' => array(
|
369 |
+
'rdnSequence' => $RDNSequence
|
370 |
+
)
|
371 |
+
);
|
372 |
+
|
373 |
+
// http://tools.ietf.org/html/rfc5280#section-4.1.1.2
|
374 |
+
$AlgorithmIdentifier = array(
|
375 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
376 |
+
'children' => array(
|
377 |
+
'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
|
378 |
+
'parameters' => array(
|
379 |
+
'type' => FILE_ASN1_TYPE_ANY,
|
380 |
+
'optional' => true
|
381 |
+
)
|
382 |
+
)
|
383 |
+
);
|
384 |
+
|
385 |
+
/*
|
386 |
+
A certificate using system MUST reject the certificate if it encounters
|
387 |
+
a critical extension it does not recognize; however, a non-critical
|
388 |
+
extension may be ignored if it is not recognized.
|
389 |
+
|
390 |
+
http://tools.ietf.org/html/rfc5280#section-4.2
|
391 |
+
*/
|
392 |
+
$Extension = array(
|
393 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
394 |
+
'children' => array(
|
395 |
+
'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
|
396 |
+
'critical' => array(
|
397 |
+
'type' => FILE_ASN1_TYPE_BOOLEAN,
|
398 |
+
'optional' => true,
|
399 |
+
'default' => false
|
400 |
+
),
|
401 |
+
'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING)
|
402 |
+
)
|
403 |
+
);
|
404 |
+
|
405 |
+
$this->Extensions = array(
|
406 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
407 |
+
'min' => 1,
|
408 |
+
// technically, it's MAX, but we'll assume anything < 0 is MAX
|
409 |
+
'max' => -1,
|
410 |
+
// if 'children' isn't an array then 'min' and 'max' must be defined
|
411 |
+
'children' => $Extension
|
412 |
+
);
|
413 |
+
|
414 |
+
$SubjectPublicKeyInfo = array(
|
415 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
416 |
+
'children' => array(
|
417 |
+
'algorithm' => $AlgorithmIdentifier,
|
418 |
+
'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
|
419 |
+
)
|
420 |
+
);
|
421 |
+
|
422 |
+
$UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING);
|
423 |
+
|
424 |
+
$Time = array(
|
425 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
426 |
+
'children' => array(
|
427 |
+
'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME),
|
428 |
+
'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
|
429 |
+
)
|
430 |
+
);
|
431 |
+
|
432 |
+
// http://tools.ietf.org/html/rfc5280#section-4.1.2.5
|
433 |
+
$Validity = array(
|
434 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
435 |
+
'children' => array(
|
436 |
+
'notBefore' => $Time,
|
437 |
+
'notAfter' => $Time
|
438 |
+
)
|
439 |
+
);
|
440 |
+
|
441 |
+
$CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
|
442 |
+
|
443 |
+
$Version = array(
|
444 |
+
'type' => FILE_ASN1_TYPE_INTEGER,
|
445 |
+
'mapping' => array('v1', 'v2', 'v3')
|
446 |
+
);
|
447 |
+
|
448 |
+
// assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
|
449 |
+
$TBSCertificate = array(
|
450 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
451 |
+
'children' => array(
|
452 |
+
// technically, default implies optional, but we'll define it as being optional, none-the-less, just to
|
453 |
+
// reenforce that fact
|
454 |
+
'version' => array(
|
455 |
+
'constant' => 0,
|
456 |
+
'optional' => true,
|
457 |
+
'explicit' => true,
|
458 |
+
'default' => 'v1'
|
459 |
+
) + $Version,
|
460 |
+
'serialNumber' => $CertificateSerialNumber,
|
461 |
+
'signature' => $AlgorithmIdentifier,
|
462 |
+
'issuer' => $this->Name,
|
463 |
+
'validity' => $Validity,
|
464 |
+
'subject' => $this->Name,
|
465 |
+
'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
|
466 |
+
// implicit means that the T in the TLV structure is to be rewritten, regardless of the type
|
467 |
+
'issuerUniqueID' => array(
|
468 |
+
'constant' => 1,
|
469 |
+
'optional' => true,
|
470 |
+
'implicit' => true
|
471 |
+
) + $UniqueIdentifier,
|
472 |
+
'subjectUniqueID' => array(
|
473 |
+
'constant' => 2,
|
474 |
+
'optional' => true,
|
475 |
+
'implicit' => true
|
476 |
+
) + $UniqueIdentifier,
|
477 |
+
// <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
|
478 |
+
// it's not IMPLICIT, it's EXPLICIT
|
479 |
+
'extensions' => array(
|
480 |
+
'constant' => 3,
|
481 |
+
'optional' => true,
|
482 |
+
'explicit' => true
|
483 |
+
) + $this->Extensions
|
484 |
+
)
|
485 |
+
);
|
486 |
+
|
487 |
+
$this->Certificate = array(
|
488 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
489 |
+
'children' => array(
|
490 |
+
'tbsCertificate' => $TBSCertificate,
|
491 |
+
'signatureAlgorithm' => $AlgorithmIdentifier,
|
492 |
+
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
|
493 |
+
)
|
494 |
+
);
|
495 |
+
|
496 |
+
$this->KeyUsage = array(
|
497 |
+
'type' => FILE_ASN1_TYPE_BIT_STRING,
|
498 |
+
'mapping' => array(
|
499 |
+
'digitalSignature',
|
500 |
+
'nonRepudiation',
|
501 |
+
'keyEncipherment',
|
502 |
+
'dataEncipherment',
|
503 |
+
'keyAgreement',
|
504 |
+
'keyCertSign',
|
505 |
+
'cRLSign',
|
506 |
+
'encipherOnly',
|
507 |
+
'decipherOnly'
|
508 |
+
)
|
509 |
+
);
|
510 |
+
|
511 |
+
$this->BasicConstraints = array(
|
512 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
513 |
+
'children' => array(
|
514 |
+
'cA' => array(
|
515 |
+
'type' => FILE_ASN1_TYPE_BOOLEAN,
|
516 |
+
'optional' => true,
|
517 |
+
'default' => false
|
518 |
+
),
|
519 |
+
'pathLenConstraint' => array(
|
520 |
+
'type' => FILE_ASN1_TYPE_INTEGER,
|
521 |
+
'optional' => true
|
522 |
+
)
|
523 |
+
)
|
524 |
+
);
|
525 |
+
|
526 |
+
$this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING);
|
527 |
+
|
528 |
+
$OrganizationalUnitNames = array(
|
529 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
530 |
+
'min' => 1,
|
531 |
+
'max' => 4, // ub-organizational-units
|
532 |
+
'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
|
533 |
+
);
|
534 |
+
|
535 |
+
$PersonalName = array(
|
536 |
+
'type' => FILE_ASN1_TYPE_SET,
|
537 |
+
'children' => array(
|
538 |
+
'surname' => array(
|
539 |
+
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
|
540 |
+
'constant' => 0,
|
541 |
+
'optional' => true,
|
542 |
+
'implicit' => true
|
543 |
+
),
|
544 |
+
'given-name' => array(
|
545 |
+
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
|
546 |
+
'constant' => 1,
|
547 |
+
'optional' => true,
|
548 |
+
'implicit' => true
|
549 |
+
),
|
550 |
+
'initials' => array(
|
551 |
+
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
|
552 |
+
'constant' => 2,
|
553 |
+
'optional' => true,
|
554 |
+
'implicit' => true
|
555 |
+
),
|
556 |
+
'generation-qualifier' => array(
|
557 |
+
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
|
558 |
+
'constant' => 3,
|
559 |
+
'optional' => true,
|
560 |
+
'implicit' => true
|
561 |
+
)
|
562 |
+
)
|
563 |
+
);
|
564 |
+
|
565 |
+
$NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
|
566 |
+
|
567 |
+
$OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
|
568 |
+
|
569 |
+
$PrivateDomainName = array(
|
570 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
571 |
+
'children' => array(
|
572 |
+
'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
|
573 |
+
'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
|
574 |
+
)
|
575 |
+
);
|
576 |
+
|
577 |
+
$TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
|
578 |
+
|
579 |
+
$NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
|
580 |
+
|
581 |
+
$AdministrationDomainName = array(
|
582 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
583 |
+
// if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
|
584 |
+
// (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
|
585 |
+
'class' => FILE_ASN1_CLASS_APPLICATION,
|
586 |
+
'cast' => 2,
|
587 |
+
'children' => array(
|
588 |
+
'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
|
589 |
+
'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
|
590 |
+
)
|
591 |
+
);
|
592 |
+
|
593 |
+
$CountryName = array(
|
594 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
595 |
+
// if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
|
596 |
+
// (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
|
597 |
+
'class' => FILE_ASN1_CLASS_APPLICATION,
|
598 |
+
'cast' => 1,
|
599 |
+
'children' => array(
|
600 |
+
'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
|
601 |
+
'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
|
602 |
+
)
|
603 |
+
);
|
604 |
+
|
605 |
+
$AnotherName = array(
|
606 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
607 |
+
'children' => array(
|
608 |
+
'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
|
609 |
+
'value' => array(
|
610 |
+
'type' => FILE_ASN1_TYPE_ANY,
|
611 |
+
'constant' => 0,
|
612 |
+
'optional' => true,
|
613 |
+
'explicit' => true
|
614 |
+
)
|
615 |
+
)
|
616 |
+
);
|
617 |
+
|
618 |
+
$ExtensionAttribute = array(
|
619 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
620 |
+
'children' => array(
|
621 |
+
'extension-attribute-type' => array(
|
622 |
+
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
|
623 |
+
'constant' => 0,
|
624 |
+
'optional' => true,
|
625 |
+
'implicit' => true
|
626 |
+
),
|
627 |
+
'extension-attribute-value' => array(
|
628 |
+
'type' => FILE_ASN1_TYPE_ANY,
|
629 |
+
'constant' => 1,
|
630 |
+
'optional' => true,
|
631 |
+
'explicit' => true
|
632 |
+
)
|
633 |
+
)
|
634 |
+
);
|
635 |
+
|
636 |
+
$ExtensionAttributes = array(
|
637 |
+
'type' => FILE_ASN1_TYPE_SET,
|
638 |
+
'min' => 1,
|
639 |
+
'max' => 256, // ub-extension-attributes
|
640 |
+
'children' => $ExtensionAttribute
|
641 |
+
);
|
642 |
+
|
643 |
+
$BuiltInDomainDefinedAttribute = array(
|
644 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
645 |
+
'children' => array(
|
646 |
+
'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
|
647 |
+
'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
|
648 |
+
)
|
649 |
+
);
|
650 |
+
|
651 |
+
$BuiltInDomainDefinedAttributes = array(
|
652 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
653 |
+
'min' => 1,
|
654 |
+
'max' => 4, // ub-domain-defined-attributes
|
655 |
+
'children' => $BuiltInDomainDefinedAttribute
|
656 |
+
);
|
657 |
+
|
658 |
+
$BuiltInStandardAttributes = array(
|
659 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
660 |
+
'children' => array(
|
661 |
+
'country-name' => array('optional' => true) + $CountryName,
|
662 |
+
'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
|
663 |
+
'network-address' => array(
|
664 |
+
'constant' => 0,
|
665 |
+
'optional' => true,
|
666 |
+
'implicit' => true
|
667 |
+
) + $NetworkAddress,
|
668 |
+
'terminal-identifier' => array(
|
669 |
+
'constant' => 1,
|
670 |
+
'optional' => true,
|
671 |
+
'implicit' => true
|
672 |
+
) + $TerminalIdentifier,
|
673 |
+
'private-domain-name' => array(
|
674 |
+
'constant' => 2,
|
675 |
+
'optional' => true,
|
676 |
+
'explicit' => true
|
677 |
+
) + $PrivateDomainName,
|
678 |
+
'organization-name' => array(
|
679 |
+
'constant' => 3,
|
680 |
+
'optional' => true,
|
681 |
+
'implicit' => true
|
682 |
+
) + $OrganizationName,
|
683 |
+
'numeric-user-identifier' => array(
|
684 |
+
'constant' => 4,
|
685 |
+
'optional' => true,
|
686 |
+
'implicit' => true
|
687 |
+
) + $NumericUserIdentifier,
|
688 |
+
'personal-name' => array(
|
689 |
+
'constant' => 5,
|
690 |
+
'optional' => true,
|
691 |
+
'implicit' => true
|
692 |
+
) + $PersonalName,
|
693 |
+
'organizational-unit-names' => array(
|
694 |
+
'constant' => 6,
|
695 |
+
'optional' => true,
|
696 |
+
'implicit' => true
|
697 |
+
) + $OrganizationalUnitNames
|
698 |
+
)
|
699 |
+
);
|
700 |
+
|
701 |
+
$ORAddress = array(
|
702 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
703 |
+
'children' => array(
|
704 |
+
'built-in-standard-attributes' => $BuiltInStandardAttributes,
|
705 |
+
'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
|
706 |
+
'extension-attributes' => array('optional' => true) + $ExtensionAttributes
|
707 |
+
)
|
708 |
+
);
|
709 |
+
|
710 |
+
$EDIPartyName = array(
|
711 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
712 |
+
'children' => array(
|
713 |
+
'nameAssigner' => array(
|
714 |
+
'constant' => 0,
|
715 |
+
'optional' => true,
|
716 |
+
'implicit' => true
|
717 |
+
) + $this->DirectoryString,
|
718 |
+
// partyName is technically required but File_ASN1 doesn't currently support non-optional constants and
|
719 |
+
// setting it to optional gets the job done in any event.
|
720 |
+
'partyName' => array(
|
721 |
+
'constant' => 1,
|
722 |
+
'optional' => true,
|
723 |
+
'implicit' => true
|
724 |
+
) + $this->DirectoryString
|
725 |
+
)
|
726 |
+
);
|
727 |
+
|
728 |
+
$GeneralName = array(
|
729 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
730 |
+
'children' => array(
|
731 |
+
'otherName' => array(
|
732 |
+
'constant' => 0,
|
733 |
+
'optional' => true,
|
734 |
+
'implicit' => true
|
735 |
+
) + $AnotherName,
|
736 |
+
'rfc822Name' => array(
|
737 |
+
'type' => FILE_ASN1_TYPE_IA5_STRING,
|
738 |
+
'constant' => 1,
|
739 |
+
'optional' => true,
|
740 |
+
'implicit' => true
|
741 |
+
),
|
742 |
+
'dNSName' => array(
|
743 |
+
'type' => FILE_ASN1_TYPE_IA5_STRING,
|
744 |
+
'constant' => 2,
|
745 |
+
'optional' => true,
|
746 |
+
'implicit' => true
|
747 |
+
),
|
748 |
+
'x400Address' => array(
|
749 |
+
'constant' => 3,
|
750 |
+
'optional' => true,
|
751 |
+
'implicit' => true
|
752 |
+
) + $ORAddress,
|
753 |
+
'directoryName' => array(
|
754 |
+
'constant' => 4,
|
755 |
+
'optional' => true,
|
756 |
+
'explicit' => true
|
757 |
+
) + $this->Name,
|
758 |
+
'ediPartyName' => array(
|
759 |
+
'constant' => 5,
|
760 |
+
'optional' => true,
|
761 |
+
'implicit' => true
|
762 |
+
) + $EDIPartyName,
|
763 |
+
'uniformResourceIdentifier' => array(
|
764 |
+
'type' => FILE_ASN1_TYPE_IA5_STRING,
|
765 |
+
'constant' => 6,
|
766 |
+
'optional' => true,
|
767 |
+
'implicit' => true
|
768 |
+
),
|
769 |
+
'iPAddress' => array(
|
770 |
+
'type' => FILE_ASN1_TYPE_OCTET_STRING,
|
771 |
+
'constant' => 7,
|
772 |
+
'optional' => true,
|
773 |
+
'implicit' => true
|
774 |
+
),
|
775 |
+
'registeredID' => array(
|
776 |
+
'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER,
|
777 |
+
'constant' => 8,
|
778 |
+
'optional' => true,
|
779 |
+
'implicit' => true
|
780 |
+
)
|
781 |
+
)
|
782 |
+
);
|
783 |
+
|
784 |
+
$GeneralNames = array(
|
785 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
786 |
+
'min' => 1,
|
787 |
+
'max' => -1,
|
788 |
+
'children' => $GeneralName
|
789 |
+
);
|
790 |
+
|
791 |
+
$this->IssuerAltName = $GeneralNames;
|
792 |
+
|
793 |
+
$ReasonFlags = array(
|
794 |
+
'type' => FILE_ASN1_TYPE_BIT_STRING,
|
795 |
+
'mapping' => array(
|
796 |
+
'unused',
|
797 |
+
'keyCompromise',
|
798 |
+
'cACompromise',
|
799 |
+
'affiliationChanged',
|
800 |
+
'superseded',
|
801 |
+
'cessationOfOperation',
|
802 |
+
'certificateHold',
|
803 |
+
'privilegeWithdrawn',
|
804 |
+
'aACompromise'
|
805 |
+
)
|
806 |
+
);
|
807 |
+
|
808 |
+
$DistributionPointName = array(
|
809 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
810 |
+
'children' => array(
|
811 |
+
'fullName' => array(
|
812 |
+
'constant' => 0,
|
813 |
+
'optional' => true,
|
814 |
+
'implicit' => true
|
815 |
+
) + $GeneralNames,
|
816 |
+
'nameRelativeToCRLIssuer' => array(
|
817 |
+
'constant' => 1,
|
818 |
+
'optional' => true,
|
819 |
+
'implicit' => true
|
820 |
+
) + $this->RelativeDistinguishedName
|
821 |
+
)
|
822 |
+
);
|
823 |
+
|
824 |
+
$DistributionPoint = array(
|
825 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
826 |
+
'children' => array(
|
827 |
+
'distributionPoint' => array(
|
828 |
+
'constant' => 0,
|
829 |
+
'optional' => true,
|
830 |
+
'explicit' => true
|
831 |
+
) + $DistributionPointName,
|
832 |
+
'reasons' => array(
|
833 |
+
'constant' => 1,
|
834 |
+
'optional' => true,
|
835 |
+
'implicit' => true
|
836 |
+
) + $ReasonFlags,
|
837 |
+
'cRLIssuer' => array(
|
838 |
+
'constant' => 2,
|
839 |
+
'optional' => true,
|
840 |
+
'implicit' => true
|
841 |
+
) + $GeneralNames
|
842 |
+
)
|
843 |
+
);
|
844 |
+
|
845 |
+
$this->CRLDistributionPoints = array(
|
846 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
847 |
+
'min' => 1,
|
848 |
+
'max' => -1,
|
849 |
+
'children' => $DistributionPoint
|
850 |
+
);
|
851 |
+
|
852 |
+
$this->AuthorityKeyIdentifier = array(
|
853 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
854 |
+
'children' => array(
|
855 |
+
'keyIdentifier' => array(
|
856 |
+
'constant' => 0,
|
857 |
+
'optional' => true,
|
858 |
+
'implicit' => true
|
859 |
+
) + $this->KeyIdentifier,
|
860 |
+
'authorityCertIssuer' => array(
|
861 |
+
'constant' => 1,
|
862 |
+
'optional' => true,
|
863 |
+
'implicit' => true
|
864 |
+
) + $GeneralNames,
|
865 |
+
'authorityCertSerialNumber' => array(
|
866 |
+
'constant' => 2,
|
867 |
+
'optional' => true,
|
868 |
+
'implicit' => true
|
869 |
+
) + $CertificateSerialNumber
|
870 |
+
)
|
871 |
+
);
|
872 |
+
|
873 |
+
$PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
|
874 |
+
|
875 |
+
$PolicyQualifierInfo = array(
|
876 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
877 |
+
'children' => array(
|
878 |
+
'policyQualifierId' => $PolicyQualifierId,
|
879 |
+
'qualifier' => array('type' => FILE_ASN1_TYPE_ANY)
|
880 |
+
)
|
881 |
+
);
|
882 |
+
|
883 |
+
$CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
|
884 |
+
|
885 |
+
$PolicyInformation = array(
|
886 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
887 |
+
'children' => array(
|
888 |
+
'policyIdentifier' => $CertPolicyId,
|
889 |
+
'policyQualifiers' => array(
|
890 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
891 |
+
'min' => 0,
|
892 |
+
'max' => -1,
|
893 |
+
'optional' => true,
|
894 |
+
'children' => $PolicyQualifierInfo
|
895 |
+
)
|
896 |
+
)
|
897 |
+
);
|
898 |
+
|
899 |
+
$this->CertificatePolicies = array(
|
900 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
901 |
+
'min' => 1,
|
902 |
+
'max' => -1,
|
903 |
+
'children' => $PolicyInformation
|
904 |
+
);
|
905 |
+
|
906 |
+
$this->PolicyMappings = array(
|
907 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
908 |
+
'min' => 1,
|
909 |
+
'max' => -1,
|
910 |
+
'children' => array(
|
911 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
912 |
+
'children' => array(
|
913 |
+
'issuerDomainPolicy' => $CertPolicyId,
|
914 |
+
'subjectDomainPolicy' => $CertPolicyId
|
915 |
+
)
|
916 |
+
)
|
917 |
+
);
|
918 |
+
|
919 |
+
$KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
|
920 |
+
|
921 |
+
$this->ExtKeyUsageSyntax = array(
|
922 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
923 |
+
'min' => 1,
|
924 |
+
'max' => -1,
|
925 |
+
'children' => $KeyPurposeId
|
926 |
+
);
|
927 |
+
|
928 |
+
$AccessDescription = array(
|
929 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
930 |
+
'children' => array(
|
931 |
+
'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
|
932 |
+
'accessLocation' => $GeneralName
|
933 |
+
)
|
934 |
+
);
|
935 |
+
|
936 |
+
$this->AuthorityInfoAccessSyntax = array(
|
937 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
938 |
+
'min' => 1,
|
939 |
+
'max' => -1,
|
940 |
+
'children' => $AccessDescription
|
941 |
+
);
|
942 |
+
|
943 |
+
$this->SubjectAltName = $GeneralNames;
|
944 |
+
|
945 |
+
$this->PrivateKeyUsagePeriod = array(
|
946 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
947 |
+
'children' => array(
|
948 |
+
'notBefore' => array(
|
949 |
+
'constant' => 0,
|
950 |
+
'optional' => true,
|
951 |
+
'implicit' => true,
|
952 |
+
'type' => FILE_ASN1_TYPE_GENERALIZED_TIME),
|
953 |
+
'notAfter' => array(
|
954 |
+
'constant' => 1,
|
955 |
+
'optional' => true,
|
956 |
+
'implicit' => true,
|
957 |
+
'type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
|
958 |
+
)
|
959 |
+
);
|
960 |
+
|
961 |
+
$BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER);
|
962 |
+
|
963 |
+
$GeneralSubtree = array(
|
964 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
965 |
+
'children' => array(
|
966 |
+
'base' => $GeneralName,
|
967 |
+
'minimum' => array(
|
968 |
+
'constant' => 0,
|
969 |
+
'optional' => true,
|
970 |
+
'implicit' => true,
|
971 |
+
'default' => new Math_BigInteger(0)
|
972 |
+
) + $BaseDistance,
|
973 |
+
'maximum' => array(
|
974 |
+
'constant' => 1,
|
975 |
+
'optional' => true,
|
976 |
+
'implicit' => true,
|
977 |
+
) + $BaseDistance
|
978 |
+
)
|
979 |
+
);
|
980 |
+
|
981 |
+
$GeneralSubtrees = array(
|
982 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
983 |
+
'min' => 1,
|
984 |
+
'max' => -1,
|
985 |
+
'children' => $GeneralSubtree
|
986 |
+
);
|
987 |
+
|
988 |
+
$this->NameConstraints = array(
|
989 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
990 |
+
'children' => array(
|
991 |
+
'permittedSubtrees' => array(
|
992 |
+
'constant' => 0,
|
993 |
+
'optional' => true,
|
994 |
+
'implicit' => true
|
995 |
+
) + $GeneralSubtrees,
|
996 |
+
'excludedSubtrees' => array(
|
997 |
+
'constant' => 1,
|
998 |
+
'optional' => true,
|
999 |
+
'implicit' => true
|
1000 |
+
) + $GeneralSubtrees
|
1001 |
+
)
|
1002 |
+
);
|
1003 |
+
|
1004 |
+
$this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING);
|
1005 |
+
|
1006 |
+
$DisplayText = array(
|
1007 |
+
'type' => FILE_ASN1_TYPE_CHOICE,
|
1008 |
+
'children' => array(
|
1009 |
+
'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
|
1010 |
+
'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING),
|
1011 |
+
'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING),
|
1012 |
+
'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING)
|
1013 |
+
)
|
1014 |
+
);
|
1015 |
+
|
1016 |
+
$NoticeReference = array(
|
1017 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1018 |
+
'children' => array(
|
1019 |
+
'organization' => $DisplayText,
|
1020 |
+
'noticeNumbers' => array(
|
1021 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1022 |
+
'min' => 1,
|
1023 |
+
'max' => 200,
|
1024 |
+
'children' => array('type' => FILE_ASN1_TYPE_INTEGER)
|
1025 |
+
)
|
1026 |
+
)
|
1027 |
+
);
|
1028 |
+
|
1029 |
+
$this->UserNotice = array(
|
1030 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1031 |
+
'children' => array(
|
1032 |
+
'noticeRef' => array(
|
1033 |
+
'optional' => true,
|
1034 |
+
'implicit' => true
|
1035 |
+
) + $NoticeReference,
|
1036 |
+
'explicitText' => array(
|
1037 |
+
'optional' => true,
|
1038 |
+
'implicit' => true
|
1039 |
+
) + $DisplayText
|
1040 |
+
)
|
1041 |
+
);
|
1042 |
+
|
1043 |
+
// mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
|
1044 |
+
$this->netscape_cert_type = array(
|
1045 |
+
'type' => FILE_ASN1_TYPE_BIT_STRING,
|
1046 |
+
'mapping' => array(
|
1047 |
+
'SSLClient',
|
1048 |
+
'SSLServer',
|
1049 |
+
'Email',
|
1050 |
+
'ObjectSigning',
|
1051 |
+
'Reserved',
|
1052 |
+
'SSLCA',
|
1053 |
+
'EmailCA',
|
1054 |
+
'ObjectSigningCA'
|
1055 |
+
)
|
1056 |
+
);
|
1057 |
+
|
1058 |
+
$this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING);
|
1059 |
+
$this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING);
|
1060 |
+
|
1061 |
+
// attribute is used in RFC2986 but we're using the RFC5280 definition
|
1062 |
+
|
1063 |
+
$Attribute = array(
|
1064 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1065 |
+
'children' => array(
|
1066 |
+
'type' => $AttributeType,
|
1067 |
+
'value'=> array(
|
1068 |
+
'type' => FILE_ASN1_TYPE_SET,
|
1069 |
+
'min' => 1,
|
1070 |
+
'max' => -1,
|
1071 |
+
'children' => $this->AttributeValue
|
1072 |
+
)
|
1073 |
+
)
|
1074 |
+
);
|
1075 |
+
|
1076 |
+
// adapted from <http://tools.ietf.org/html/rfc2986>
|
1077 |
+
|
1078 |
+
$Attributes = array(
|
1079 |
+
'type' => FILE_ASN1_TYPE_SET,
|
1080 |
+
'min' => 1,
|
1081 |
+
'max' => -1,
|
1082 |
+
'children' => $Attribute
|
1083 |
+
);
|
1084 |
+
|
1085 |
+
$CertificationRequestInfo = array(
|
1086 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1087 |
+
'children' => array(
|
1088 |
+
'version' => array(
|
1089 |
+
'type' => FILE_ASN1_TYPE_INTEGER,
|
1090 |
+
'mapping' => array('v1')
|
1091 |
+
),
|
1092 |
+
'subject' => $this->Name,
|
1093 |
+
'subjectPKInfo' => $SubjectPublicKeyInfo,
|
1094 |
+
'attributes' => array(
|
1095 |
+
'constant' => 0,
|
1096 |
+
'optional' => true,
|
1097 |
+
'implicit' => true
|
1098 |
+
) + $Attributes,
|
1099 |
+
)
|
1100 |
+
);
|
1101 |
+
|
1102 |
+
$this->CertificationRequest = array(
|
1103 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1104 |
+
'children' => array(
|
1105 |
+
'certificationRequestInfo' => $CertificationRequestInfo,
|
1106 |
+
'signatureAlgorithm' => $AlgorithmIdentifier,
|
1107 |
+
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
|
1108 |
+
)
|
1109 |
+
);
|
1110 |
+
|
1111 |
+
$RevokedCertificate = array(
|
1112 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1113 |
+
'children' => array(
|
1114 |
+
'userCertificate' => $CertificateSerialNumber,
|
1115 |
+
'revocationDate' => $Time,
|
1116 |
+
'crlEntryExtensions' => array(
|
1117 |
+
'optional' => true
|
1118 |
+
) + $this->Extensions
|
1119 |
+
)
|
1120 |
+
);
|
1121 |
+
|
1122 |
+
$TBSCertList = array(
|
1123 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1124 |
+
'children' => array(
|
1125 |
+
'version' => array(
|
1126 |
+
'optional' => true,
|
1127 |
+
'default' => 'v1'
|
1128 |
+
) + $Version,
|
1129 |
+
'signature' => $AlgorithmIdentifier,
|
1130 |
+
'issuer' => $this->Name,
|
1131 |
+
'thisUpdate' => $Time,
|
1132 |
+
'nextUpdate' => array(
|
1133 |
+
'optional' => true
|
1134 |
+
) + $Time,
|
1135 |
+
'revokedCertificates' => array(
|
1136 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1137 |
+
'optional' => true,
|
1138 |
+
'min' => 0,
|
1139 |
+
'max' => -1,
|
1140 |
+
'children' => $RevokedCertificate
|
1141 |
+
),
|
1142 |
+
'crlExtensions' => array(
|
1143 |
+
'constant' => 0,
|
1144 |
+
'optional' => true,
|
1145 |
+
'explicit' => true
|
1146 |
+
) + $this->Extensions
|
1147 |
+
)
|
1148 |
+
);
|
1149 |
+
|
1150 |
+
$this->CertificateList = array(
|
1151 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1152 |
+
'children' => array(
|
1153 |
+
'tbsCertList' => $TBSCertList,
|
1154 |
+
'signatureAlgorithm' => $AlgorithmIdentifier,
|
1155 |
+
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
|
1156 |
+
)
|
1157 |
+
);
|
1158 |
+
|
1159 |
+
$this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
|
1160 |
+
|
1161 |
+
$this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED,
|
1162 |
+
'mapping' => array(
|
1163 |
+
'unspecified',
|
1164 |
+
'keyCompromise',
|
1165 |
+
'cACompromise',
|
1166 |
+
'affiliationChanged',
|
1167 |
+
'superseded',
|
1168 |
+
'cessationOfOperation',
|
1169 |
+
'certificateHold',
|
1170 |
+
// Value 7 is not used.
|
1171 |
+
8 => 'removeFromCRL',
|
1172 |
+
'privilegeWithdrawn',
|
1173 |
+
'aACompromise'
|
1174 |
+
)
|
1175 |
+
);
|
1176 |
+
|
1177 |
+
$this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE,
|
1178 |
+
'children' => array(
|
1179 |
+
'distributionPoint' => array(
|
1180 |
+
'constant' => 0,
|
1181 |
+
'optional' => true,
|
1182 |
+
'explicit' => true
|
1183 |
+
) + $DistributionPointName,
|
1184 |
+
'onlyContainsUserCerts' => array(
|
1185 |
+
'type' => FILE_ASN1_TYPE_BOOLEAN,
|
1186 |
+
'constant' => 1,
|
1187 |
+
'optional' => true,
|
1188 |
+
'default' => false,
|
1189 |
+
'implicit' => true
|
1190 |
+
),
|
1191 |
+
'onlyContainsCACerts' => array(
|
1192 |
+
'type' => FILE_ASN1_TYPE_BOOLEAN,
|
1193 |
+
'constant' => 2,
|
1194 |
+
'optional' => true,
|
1195 |
+
'default' => false,
|
1196 |
+
'implicit' => true
|
1197 |
+
),
|
1198 |
+
'onlySomeReasons' => array(
|
1199 |
+
'constant' => 3,
|
1200 |
+
'optional' => true,
|
1201 |
+
'implicit' => true
|
1202 |
+
) + $ReasonFlags,
|
1203 |
+
'indirectCRL' => array(
|
1204 |
+
'type' => FILE_ASN1_TYPE_BOOLEAN,
|
1205 |
+
'constant' => 4,
|
1206 |
+
'optional' => true,
|
1207 |
+
'default' => false,
|
1208 |
+
'implicit' => true
|
1209 |
+
),
|
1210 |
+
'onlyContainsAttributeCerts' => array(
|
1211 |
+
'type' => FILE_ASN1_TYPE_BOOLEAN,
|
1212 |
+
'constant' => 5,
|
1213 |
+
'optional' => true,
|
1214 |
+
'default' => false,
|
1215 |
+
'implicit' => true
|
1216 |
+
)
|
1217 |
+
)
|
1218 |
+
);
|
1219 |
+
|
1220 |
+
$this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME);
|
1221 |
+
|
1222 |
+
$this->CertificateIssuer = $GeneralNames;
|
1223 |
+
|
1224 |
+
$this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
|
1225 |
+
|
1226 |
+
$PublicKeyAndChallenge = array(
|
1227 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1228 |
+
'children' => array(
|
1229 |
+
'spki' => $SubjectPublicKeyInfo,
|
1230 |
+
'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING)
|
1231 |
+
)
|
1232 |
+
);
|
1233 |
+
|
1234 |
+
$this->SignedPublicKeyAndChallenge = array(
|
1235 |
+
'type' => FILE_ASN1_TYPE_SEQUENCE,
|
1236 |
+
'children' => array(
|
1237 |
+
'publicKeyAndChallenge' => $PublicKeyAndChallenge,
|
1238 |
+
'signatureAlgorithm' => $AlgorithmIdentifier,
|
1239 |
+
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
|
1240 |
+
)
|
1241 |
+
);
|
1242 |
+
|
1243 |
+
// OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
|
1244 |
+
$this->oids = array(
|
1245 |
+
'1.3.6.1.5.5.7' => 'id-pkix',
|
1246 |
+
'1.3.6.1.5.5.7.1' => 'id-pe',
|
1247 |
+
'1.3.6.1.5.5.7.2' => 'id-qt',
|
1248 |
+
'1.3.6.1.5.5.7.3' => 'id-kp',
|
1249 |
+
'1.3.6.1.5.5.7.48' => 'id-ad',
|
1250 |
+
'1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
|
1251 |
+
'1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
|
1252 |
+
'1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
|
1253 |
+
'1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
|
1254 |
+
'1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
|
1255 |
+
'1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
|
1256 |
+
'2.5.4' => 'id-at',
|
1257 |
+
'2.5.4.41' => 'id-at-name',
|
1258 |
+
'2.5.4.4' => 'id-at-surname',
|
1259 |
+
'2.5.4.42' => 'id-at-givenName',
|
1260 |
+
'2.5.4.43' => 'id-at-initials',
|
1261 |
+
'2.5.4.44' => 'id-at-generationQualifier',
|
1262 |
+
'2.5.4.3' => 'id-at-commonName',
|
1263 |
+
'2.5.4.7' => 'id-at-localityName',
|
1264 |
+
'2.5.4.8' => 'id-at-stateOrProvinceName',
|
1265 |
+
'2.5.4.10' => 'id-at-organizationName',
|
1266 |
+
'2.5.4.11' => 'id-at-organizationalUnitName',
|
1267 |
+
'2.5.4.12' => 'id-at-title',
|
1268 |
+
'2.5.4.13' => 'id-at-description',
|
1269 |
+
'2.5.4.46' => 'id-at-dnQualifier',
|
1270 |
+
'2.5.4.6' => 'id-at-countryName',
|
1271 |
+
'2.5.4.5' => 'id-at-serialNumber',
|
1272 |
+
'2.5.4.65' => 'id-at-pseudonym',
|
1273 |
+
'2.5.4.17' => 'id-at-postalCode',
|
1274 |
+
'2.5.4.9' => 'id-at-streetAddress',
|
1275 |
+
'2.5.4.45' => 'id-at-uniqueIdentifier',
|
1276 |
+
'2.5.4.72' => 'id-at-role',
|
1277 |
+
|
1278 |
+
'0.9.2342.19200300.100.1.25' => 'id-domainComponent',
|
1279 |
+
'1.2.840.113549.1.9' => 'pkcs-9',
|
1280 |
+
'1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
|
1281 |
+
'2.5.29' => 'id-ce',
|
1282 |
+
'2.5.29.35' => 'id-ce-authorityKeyIdentifier',
|
1283 |
+
'2.5.29.14' => 'id-ce-subjectKeyIdentifier',
|
1284 |
+
'2.5.29.15' => 'id-ce-keyUsage',
|
1285 |
+
'2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
|
1286 |
+
'2.5.29.32' => 'id-ce-certificatePolicies',
|
1287 |
+
'2.5.29.32.0' => 'anyPolicy',
|
1288 |
+
|
1289 |
+
'2.5.29.33' => 'id-ce-policyMappings',
|
1290 |
+
'2.5.29.17' => 'id-ce-subjectAltName',
|
1291 |
+
'2.5.29.18' => 'id-ce-issuerAltName',
|
1292 |
+
'2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
|
1293 |
+
'2.5.29.19' => 'id-ce-basicConstraints',
|
1294 |
+
'2.5.29.30' => 'id-ce-nameConstraints',
|
1295 |
+
'2.5.29.36' => 'id-ce-policyConstraints',
|
1296 |
+
'2.5.29.31' => 'id-ce-cRLDistributionPoints',
|
1297 |
+
'2.5.29.37' => 'id-ce-extKeyUsage',
|
1298 |
+
'2.5.29.37.0' => 'anyExtendedKeyUsage',
|
1299 |
+
'1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
|
1300 |
+
'1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
|
1301 |
+
'1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
|
1302 |
+
'1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
|
1303 |
+
'1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
|
1304 |
+
'1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
|
1305 |
+
'2.5.29.54' => 'id-ce-inhibitAnyPolicy',
|
1306 |
+
'2.5.29.46' => 'id-ce-freshestCRL',
|
1307 |
+
'1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
|
1308 |
+
'1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
|
1309 |
+
'2.5.29.20' => 'id-ce-cRLNumber',
|
1310 |
+
'2.5.29.28' => 'id-ce-issuingDistributionPoint',
|
1311 |
+
'2.5.29.27' => 'id-ce-deltaCRLIndicator',
|
1312 |
+
'2.5.29.21' => 'id-ce-cRLReasons',
|
1313 |
+
'2.5.29.29' => 'id-ce-certificateIssuer',
|
1314 |
+
'2.5.29.23' => 'id-ce-holdInstructionCode',
|
1315 |
+
'1.2.840.10040.2' => 'holdInstruction',
|
1316 |
+
'1.2.840.10040.2.1' => 'id-holdinstruction-none',
|
1317 |
+
'1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
|
1318 |
+
'1.2.840.10040.2.3' => 'id-holdinstruction-reject',
|
1319 |
+
'2.5.29.24' => 'id-ce-invalidityDate',
|
1320 |
+
|
1321 |
+
'1.2.840.113549.2.2' => 'md2',
|
1322 |
+
'1.2.840.113549.2.5' => 'md5',
|
1323 |
+
'1.3.14.3.2.26' => 'id-sha1',
|
1324 |
+
'1.2.840.10040.4.1' => 'id-dsa',
|
1325 |
+
'1.2.840.10040.4.3' => 'id-dsa-with-sha1',
|
1326 |
+
'1.2.840.113549.1.1' => 'pkcs-1',
|
1327 |
+
'1.2.840.113549.1.1.1' => 'rsaEncryption',
|
1328 |
+
'1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
|
1329 |
+
'1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
|
1330 |
+
'1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
|
1331 |
+
'1.2.840.10046.2.1' => 'dhpublicnumber',
|
1332 |
+
'2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
|
1333 |
+
'1.2.840.10045' => 'ansi-X9-62',
|
1334 |
+
'1.2.840.10045.4' => 'id-ecSigType',
|
1335 |
+
'1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
|
1336 |
+
'1.2.840.10045.1' => 'id-fieldType',
|
1337 |
+
'1.2.840.10045.1.1' => 'prime-field',
|
1338 |
+
'1.2.840.10045.1.2' => 'characteristic-two-field',
|
1339 |
+
'1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
|
1340 |
+
'1.2.840.10045.1.2.3.1' => 'gnBasis',
|
1341 |
+
'1.2.840.10045.1.2.3.2' => 'tpBasis',
|
1342 |
+
'1.2.840.10045.1.2.3.3' => 'ppBasis',
|
1343 |
+
'1.2.840.10045.2' => 'id-publicKeyType',
|
1344 |
+
'1.2.840.10045.2.1' => 'id-ecPublicKey',
|
1345 |
+
'1.2.840.10045.3' => 'ellipticCurve',
|
1346 |
+
'1.2.840.10045.3.0' => 'c-TwoCurve',
|
1347 |
+
'1.2.840.10045.3.0.1' => 'c2pnb163v1',
|
1348 |
+
'1.2.840.10045.3.0.2' => 'c2pnb163v2',
|
1349 |
+
'1.2.840.10045.3.0.3' => 'c2pnb163v3',
|
1350 |
+
'1.2.840.10045.3.0.4' => 'c2pnb176w1',
|
1351 |
+
'1.2.840.10045.3.0.5' => 'c2pnb191v1',
|
1352 |
+
'1.2.840.10045.3.0.6' => 'c2pnb191v2',
|
1353 |
+
'1.2.840.10045.3.0.7' => 'c2pnb191v3',
|
1354 |
+
'1.2.840.10045.3.0.8' => 'c2pnb191v4',
|
1355 |
+
'1.2.840.10045.3.0.9' => 'c2pnb191v5',
|
1356 |
+
'1.2.840.10045.3.0.10' => 'c2pnb208w1',
|
1357 |
+
'1.2.840.10045.3.0.11' => 'c2pnb239v1',
|
1358 |
+
'1.2.840.10045.3.0.12' => 'c2pnb239v2',
|
1359 |
+
'1.2.840.10045.3.0.13' => 'c2pnb239v3',
|
1360 |
+
'1.2.840.10045.3.0.14' => 'c2pnb239v4',
|
1361 |
+
'1.2.840.10045.3.0.15' => 'c2pnb239v5',
|
1362 |
+
'1.2.840.10045.3.0.16' => 'c2pnb272w1',
|
1363 |
+
'1.2.840.10045.3.0.17' => 'c2pnb304w1',
|
1364 |
+
'1.2.840.10045.3.0.18' => 'c2pnb359v1',
|
1365 |
+
'1.2.840.10045.3.0.19' => 'c2pnb368w1',
|
1366 |
+
'1.2.840.10045.3.0.20' => 'c2pnb431r1',
|
1367 |
+
'1.2.840.10045.3.1' => 'primeCurve',
|
1368 |
+
'1.2.840.10045.3.1.1' => 'prime192v1',
|
1369 |
+
'1.2.840.10045.3.1.2' => 'prime192v2',
|
1370 |
+
'1.2.840.10045.3.1.3' => 'prime192v3',
|
1371 |
+
'1.2.840.10045.3.1.4' => 'prime239v1',
|
1372 |
+
'1.2.840.10045.3.1.5' => 'prime239v2',
|
1373 |
+
'1.2.840.10045.3.1.6' => 'prime239v3',
|
1374 |
+
'1.2.840.10045.3.1.7' => 'prime256v1',
|
1375 |
+
'1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
|
1376 |
+
'1.2.840.113549.1.1.9' => 'id-pSpecified',
|
1377 |
+
'1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
|
1378 |
+
'1.2.840.113549.1.1.8' => 'id-mgf1',
|
1379 |
+
'1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
|
1380 |
+
'1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
|
1381 |
+
'1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
|
1382 |
+
'1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
|
1383 |
+
'2.16.840.1.101.3.4.2.4' => 'id-sha224',
|
1384 |
+
'2.16.840.1.101.3.4.2.1' => 'id-sha256',
|
1385 |
+
'2.16.840.1.101.3.4.2.2' => 'id-sha384',
|
1386 |
+
'2.16.840.1.101.3.4.2.3' => 'id-sha512',
|
1387 |
+
'1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
|
1388 |
+
'1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
|
1389 |
+
'1.2.643.2.2.20' => 'id-GostR3410-2001',
|
1390 |
+
'1.2.643.2.2.19' => 'id-GostR3410-94',
|
1391 |
+
// Netscape Object Identifiers from "Netscape Certificate Extensions"
|
1392 |
+
'2.16.840.1.113730' => 'netscape',
|
1393 |
+
'2.16.840.1.113730.1' => 'netscape-cert-extension',
|
1394 |
+
'2.16.840.1.113730.1.1' => 'netscape-cert-type',
|
1395 |
+
'2.16.840.1.113730.1.13' => 'netscape-comment',
|
1396 |
+
'2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
|
1397 |
+
// the following are X.509 extensions not supported by phpseclib
|
1398 |
+
'1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
|
1399 |
+
'1.2.840.113533.7.65.0' => 'entrustVersInfo',
|
1400 |
+
'2.16.840.1.113733.1.6.9' => 'verisignPrivate',
|
1401 |
+
// for Certificate Signing Requests
|
1402 |
+
// see http://tools.ietf.org/html/rfc2985
|
1403 |
+
'1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
|
1404 |
+
'1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
|
1405 |
+
'1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
|
1406 |
+
);
|
1407 |
+
}
|
1408 |
+
|
1409 |
+
/**
|
1410 |
+
* Load X.509 certificate
|
1411 |
+
*
|
1412 |
+
* Returns an associative array describing the X.509 cert or a false if the cert failed to load
|
1413 |
+
*
|
1414 |
+
* @param String $cert
|
1415 |
+
* @access public
|
1416 |
+
* @return Mixed
|
1417 |
+
*/
|
1418 |
+
function loadX509($cert)
|
1419 |
+
{
|
1420 |
+
if (is_array($cert) && isset($cert['tbsCertificate'])) {
|
1421 |
+
unset($this->currentCert);
|
1422 |
+
unset($this->currentKeyIdentifier);
|
1423 |
+
$this->dn = $cert['tbsCertificate']['subject'];
|
1424 |
+
if (!isset($this->dn)) {
|
1425 |
+
return false;
|
1426 |
+
}
|
1427 |
+
$this->currentCert = $cert;
|
1428 |
+
|
1429 |
+
$currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
|
1430 |
+
$this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : NULL;
|
1431 |
+
|
1432 |
+
unset($this->signatureSubject);
|
1433 |
+
|
1434 |
+
return $cert;
|
1435 |
+
}
|
1436 |
+
|
1437 |
+
$asn1 = new File_ASN1();
|
1438 |
+
|
1439 |
+
$cert = $this->_extractBER($cert);
|
1440 |
+
|
1441 |
+
if ($cert === false) {
|
1442 |
+
$this->currentCert = false;
|
1443 |
+
return false;
|
1444 |
+
}
|
1445 |
+
|
1446 |
+
$asn1->loadOIDs($this->oids);
|
1447 |
+
$decoded = $asn1->decodeBER($cert);
|
1448 |
+
|
1449 |
+
if (!empty($decoded)) {
|
1450 |
+
$x509 = $asn1->asn1map($decoded[0], $this->Certificate);
|
1451 |
+
}
|
1452 |
+
if (!isset($x509) || $x509 === false) {
|
1453 |
+
$this->currentCert = false;
|
1454 |
+
return false;
|
1455 |
+
}
|
1456 |
+
|
1457 |
+
$this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
|
1458 |
+
|
1459 |
+
$this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
|
1460 |
+
|
1461 |
+
$key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
|
1462 |
+
$key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
|
1463 |
+
|
1464 |
+
$this->currentCert = $x509;
|
1465 |
+
$this->dn = $x509['tbsCertificate']['subject'];
|
1466 |
+
|
1467 |
+
$currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
|
1468 |
+
$this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : NULL;
|
1469 |
+
|
1470 |
+
return $x509;
|
1471 |
+
}
|
1472 |
+
|
1473 |
+
/**
|
1474 |
+
* Save X.509 certificate
|
1475 |
+
*
|
1476 |
+
* @param Array $cert
|
1477 |
+
* @param Integer $format optional
|
1478 |
+
* @access public
|
1479 |
+
* @return String
|
1480 |
+
*/
|
1481 |
+
function saveX509($cert, $format = FILE_X509_FORMAT_PEM)
|
1482 |
+
{
|
1483 |
+
if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
|
1484 |
+
return false;
|
1485 |
+
}
|
1486 |
+
|
1487 |
+
switch (true) {
|
1488 |
+
// "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
|
1489 |
+
case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
|
1490 |
+
case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
|
1491 |
+
break;
|
1492 |
+
default:
|
1493 |
+
switch ($algorithm) {
|
1494 |
+
case 'rsaEncryption':
|
1495 |
+
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] =
|
1496 |
+
base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
|
1497 |
+
}
|
1498 |
+
}
|
1499 |
+
|
1500 |
+
$asn1 = new File_ASN1();
|
1501 |
+
|
1502 |
+
$asn1->loadOIDs($this->oids);
|
1503 |
+
|
1504 |
+
$filters = array();
|
1505 |
+
$filters['tbsCertificate']['signature']['parameters'] =
|
1506 |
+
$filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] =
|
1507 |
+
$filters['tbsCertificate']['issuer']['rdnSequence']['value'] =
|
1508 |
+
$filters['tbsCertificate']['subject']['rdnSequence']['value'] =
|
1509 |
+
$filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] =
|
1510 |
+
$filters['signatureAlgorithm']['parameters'] =
|
1511 |
+
$filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] =
|
1512 |
+
//$filters['policyQualifiers']['qualifier'] =
|
1513 |
+
$filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] =
|
1514 |
+
$filters['directoryName']['rdnSequence']['value'] =
|
1515 |
+
array('type' => FILE_ASN1_TYPE_UTF8_STRING);
|
1516 |
+
/* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING.
|
1517 |
+
FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
|
1518 |
+
characters.
|
1519 |
+
*/
|
1520 |
+
$filters['policyQualifiers']['qualifier'] =
|
1521 |
+
array('type' => FILE_ASN1_TYPE_IA5_STRING);
|
1522 |
+
|
1523 |
+
$asn1->loadFilters($filters);
|
1524 |
+
|
1525 |
+
$this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
|
1526 |
+
|
1527 |
+
$cert = $asn1->encodeDER($cert, $this->Certificate);
|
1528 |
+
|
1529 |
+
switch ($format) {
|
1530 |
+
case FILE_X509_FORMAT_DER:
|
1531 |
+
return $cert;
|
1532 |
+
// case FILE_X509_FORMAT_PEM:
|
1533 |
+
default:
|
1534 |
+
return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
|
1535 |
+
}
|
1536 |
+
}
|
1537 |
+
|
1538 |
+
/**
|
1539 |
+
* Map extension values from octet string to extension-specific internal
|
1540 |
+
* format.
|
1541 |
+
*
|
1542 |
+
* @param Array ref $root
|
1543 |
+
* @param String $path
|
1544 |
+
* @param Object $asn1
|
1545 |
+
* @access private
|
1546 |
+
*/
|
1547 |
+
function _mapInExtensions(&$root, $path, $asn1)
|
1548 |
+
{
|
1549 |
+
$extensions = &$this->_subArray($root, $path);
|
1550 |
+
|
1551 |
+
if (is_array($extensions)) {
|
1552 |
+
for ($i = 0; $i < count($extensions); $i++) {
|
1553 |
+
$id = $extensions[$i]['extnId'];
|
1554 |
+
$value = &$extensions[$i]['extnValue'];
|
1555 |
+
$value = base64_decode($value);
|
1556 |
+
$decoded = $asn1->decodeBER($value);
|
1557 |
+
/* [extnValue] contains the DER encoding of an ASN.1 value
|
1558 |
+
corresponding to the extension type identified by extnID */
|
1559 |
+
$map = $this->_getMapping($id);
|
1560 |
+
if (!is_bool($map)) {
|
1561 |
+
$mapped = $asn1->asn1map($decoded[0], $map);
|
1562 |
+
$value = $mapped === false ? $decoded[0] : $mapped;
|
1563 |
+
|
1564 |
+
if ($id == 'id-ce-certificatePolicies') {
|
1565 |
+
for ($j = 0; $j < count($value); $j++) {
|
1566 |
+
if (!isset($value[$j]['policyQualifiers'])) {
|
1567 |
+
continue;
|
1568 |
+
}
|
1569 |
+
for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
|
1570 |
+
$subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
|
1571 |
+
$map = $this->_getMapping($subid);
|
1572 |
+
$subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
|
1573 |
+
if ($map !== false) {
|
1574 |
+
$decoded = $asn1->decodeBER($subvalue);
|
1575 |
+
$mapped = $asn1->asn1map($decoded[0], $map);
|
1576 |
+
$subvalue = $mapped === false ? $decoded[0] : $mapped;
|
1577 |
+
}
|
1578 |
+
}
|
1579 |
+
}
|
1580 |
+
}
|
1581 |
+
} elseif ($map) {
|
1582 |
+
$value = base64_encode($value);
|
1583 |
+
}
|
1584 |
+
}
|
1585 |
+
}
|
1586 |
+
}
|
1587 |
+
|
1588 |
+
/**
|
1589 |
+
* Map extension values from extension-specific internal format to
|
1590 |
+
* octet string.
|
1591 |
+
*
|
1592 |
+
* @param Array ref $root
|
1593 |
+
* @param String $path
|
1594 |
+
* @param Object $asn1
|
1595 |
+
* @access private
|
1596 |
+
*/
|
1597 |
+
function _mapOutExtensions(&$root, $path, $asn1)
|
1598 |
+
{
|
1599 |
+
$extensions = &$this->_subArray($root, $path);
|
1600 |
+
|
1601 |
+
if (is_array($extensions)) {
|
1602 |
+
$size = count($extensions);
|
1603 |
+
for ($i = 0; $i < $size; $i++) {
|
1604 |
+
$id = $extensions[$i]['extnId'];
|
1605 |
+
$value = &$extensions[$i]['extnValue'];
|
1606 |
+
|
1607 |
+
switch ($id) {
|
1608 |
+
case 'id-ce-certificatePolicies':
|
1609 |
+
for ($j = 0; $j < count($value); $j++) {
|
1610 |
+
if (!isset($value[$j]['policyQualifiers'])) {
|
1611 |
+
continue;
|
1612 |
+
}
|
1613 |
+
for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
|
1614 |
+
$subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
|
1615 |
+
$map = $this->_getMapping($subid);
|
1616 |
+
$subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
|
1617 |
+
if ($map !== false) {
|
1618 |
+
// by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's
|
1619 |
+
// actual type is FILE_ASN1_TYPE_ANY
|
1620 |
+
$subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map));
|
1621 |
+
}
|
1622 |
+
}
|
1623 |
+
}
|
1624 |
+
break;
|
1625 |
+
case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
|
1626 |
+
if (isset($value['authorityCertSerialNumber'])) {
|
1627 |
+
if ($value['authorityCertSerialNumber']->toBytes() == '') {
|
1628 |
+
$temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
|
1629 |
+
$value['authorityCertSerialNumber'] = new File_ASN1_Element($temp);
|
1630 |
+
}
|
1631 |
+
}
|
1632 |
+
}
|
1633 |
+
|
1634 |
+
/* [extnValue] contains the DER encoding of an ASN.1 value
|
1635 |
+
corresponding to the extension type identified by extnID */
|
1636 |
+
$map = $this->_getMapping($id);
|
1637 |
+
if (is_bool($map)) {
|
1638 |
+
if (!$map) {
|
1639 |
+
user_error($id . ' is not a currently supported extension');
|
1640 |
+
unset($extensions[$i]);
|
1641 |
+
}
|
1642 |
+
} else {
|
1643 |
+
$temp = $asn1->encodeDER($value, $map);
|
1644 |
+
$value = base64_encode($temp);
|
1645 |
+
}
|
1646 |
+
}
|
1647 |
+
}
|
1648 |
+
}
|
1649 |
+
|
1650 |
+
/**
|
1651 |
+
* Map attribute values from ANY type to attribute-specific internal
|
1652 |
+
* format.
|
1653 |
+
*
|
1654 |
+
* @param Array ref $root
|
1655 |
+
* @param String $path
|
1656 |
+
* @param Object $asn1
|
1657 |
+
* @access private
|
1658 |
+
*/
|
1659 |
+
function _mapInAttributes(&$root, $path, $asn1)
|
1660 |
+
{
|
1661 |
+
$attributes = &$this->_subArray($root, $path);
|
1662 |
+
|
1663 |
+
if (is_array($attributes)) {
|
1664 |
+
for ($i = 0; $i < count($attributes); $i++) {
|
1665 |
+
$id = $attributes[$i]['type'];
|
1666 |
+
/* $value contains the DER encoding of an ASN.1 value
|
1667 |
+
corresponding to the attribute type identified by type */
|
1668 |
+
$map = $this->_getMapping($id);
|
1669 |
+
if (is_array($attributes[$i]['value'])) {
|
1670 |
+
$values = &$attributes[$i]['value'];
|
1671 |
+
for ($j = 0; $j < count($values); $j++) {
|
1672 |
+
$value = $asn1->encodeDER($values[$j], $this->AttributeValue);
|
1673 |
+
$decoded = $asn1->decodeBER($value);
|
1674 |
+
if (!is_bool($map)) {
|
1675 |
+
$mapped = $asn1->asn1map($decoded[0], $map);
|
1676 |
+
if ($mapped !== false) {
|
1677 |
+
$values[$j] = $mapped;
|
1678 |
+
}
|
1679 |
+
if ($id == 'pkcs-9-at-extensionRequest') {
|
1680 |
+
$this->_mapInExtensions($values, $j, $asn1);
|
1681 |
+
}
|
1682 |
+
} elseif ($map) {
|
1683 |
+
$values[$j] = base64_encode($value);
|
1684 |
+
}
|
1685 |
+
}
|
1686 |
+
}
|
1687 |
+
}
|
1688 |
+
}
|
1689 |
+
}
|
1690 |
+
|
1691 |
+
/**
|
1692 |
+
* Map attribute values from attribute-specific internal format to
|
1693 |
+
* ANY type.
|
1694 |
+
*
|
1695 |
+
* @param Array ref $root
|
1696 |
+
* @param String $path
|
1697 |
+
* @param Object $asn1
|
1698 |
+
* @access private
|
1699 |
+
*/
|
1700 |
+
function _mapOutAttributes(&$root, $path, $asn1)
|
1701 |
+
{
|
1702 |
+
$attributes = &$this->_subArray($root, $path);
|
1703 |
+
|
1704 |
+
if (is_array($attributes)) {
|
1705 |
+
$size = count($attributes);
|
1706 |
+
for ($i = 0; $i < $size; $i++) {
|
1707 |
+
/* [value] contains the DER encoding of an ASN.1 value
|
1708 |
+
corresponding to the attribute type identified by type */
|
1709 |
+
$id = $attributes[$i]['type'];
|
1710 |
+
$map = $this->_getMapping($id);
|
1711 |
+
if ($map === false) {
|
1712 |
+
user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
|
1713 |
+
unset($attributes[$i]);
|
1714 |
+
}
|
1715 |
+
elseif (is_array($attributes[$i]['value'])) {
|
1716 |
+
$values = &$attributes[$i]['value'];
|
1717 |
+
for ($j = 0; $j < count($values); $j++) {
|
1718 |
+
switch ($id) {
|
1719 |
+
case 'pkcs-9-at-extensionRequest':
|
1720 |
+
$this->_mapOutExtensions($values, $j, $asn1);
|
1721 |
+
break;
|
1722 |
+
}
|
1723 |
+
|
1724 |
+
if (!is_bool($map)) {
|
1725 |
+
$temp = $asn1->encodeDER($values[$j], $map);
|
1726 |
+
$decoded = $asn1->decodeBER($temp);
|
1727 |
+
$values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
|
1728 |
+
}
|
1729 |
+
}
|
1730 |
+
}
|
1731 |
+
}
|
1732 |
+
}
|
1733 |
+
}
|
1734 |
+
|
1735 |
+
/**
|
1736 |
+
* Associate an extension ID to an extension mapping
|
1737 |
+
*
|
1738 |
+
* @param String $extnId
|
1739 |
+
* @access private
|
1740 |
+
* @return Mixed
|
1741 |
+
*/
|
1742 |
+
function _getMapping($extnId)
|
1743 |
+
{
|
1744 |
+
if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object
|
1745 |
+
return true;
|
1746 |
+
}
|
1747 |
+
|
1748 |
+
switch ($extnId) {
|
1749 |
+
case 'id-ce-keyUsage':
|
1750 |
+
return $this->KeyUsage;
|
1751 |
+
case 'id-ce-basicConstraints':
|
1752 |
+
return $this->BasicConstraints;
|
1753 |
+
case 'id-ce-subjectKeyIdentifier':
|
1754 |
+
return $this->KeyIdentifier;
|
1755 |
+
case 'id-ce-cRLDistributionPoints':
|
1756 |
+
return $this->CRLDistributionPoints;
|
1757 |
+
case 'id-ce-authorityKeyIdentifier':
|
1758 |
+
return $this->AuthorityKeyIdentifier;
|
1759 |
+
case 'id-ce-certificatePolicies':
|
1760 |
+
return $this->CertificatePolicies;
|
1761 |
+
case 'id-ce-extKeyUsage':
|
1762 |
+
return $this->ExtKeyUsageSyntax;
|
1763 |
+
case 'id-pe-authorityInfoAccess':
|
1764 |
+
return $this->AuthorityInfoAccessSyntax;
|
1765 |
+
case 'id-ce-subjectAltName':
|
1766 |
+
return $this->SubjectAltName;
|
1767 |
+
case 'id-ce-privateKeyUsagePeriod':
|
1768 |
+
return $this->PrivateKeyUsagePeriod;
|
1769 |
+
case 'id-ce-issuerAltName':
|
1770 |
+
return $this->IssuerAltName;
|
1771 |
+
case 'id-ce-policyMappings':
|
1772 |
+
return $this->PolicyMappings;
|
1773 |
+
case 'id-ce-nameConstraints':
|
1774 |
+
return $this->NameConstraints;
|
1775 |
+
|
1776 |
+
case 'netscape-cert-type':
|
1777 |
+
return $this->netscape_cert_type;
|
1778 |
+
case 'netscape-comment':
|
1779 |
+
return $this->netscape_comment;
|
1780 |
+
case 'netscape-ca-policy-url':
|
1781 |
+
return $this->netscape_ca_policy_url;
|
1782 |
+
|
1783 |
+
// since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
|
1784 |
+
// back around to asn1map() and we don't want it decoded again.
|
1785 |
+
//case 'id-qt-cps':
|
1786 |
+
// return $this->CPSuri;
|
1787 |
+
case 'id-qt-unotice':
|
1788 |
+
return $this->UserNotice;
|
1789 |
+
|
1790 |
+
// the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
|
1791 |
+
case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
|
1792 |
+
case 'entrustVersInfo':
|
1793 |
+
// http://support.microsoft.com/kb/287547
|
1794 |
+
case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
|
1795 |
+
case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
|
1796 |
+
// "SET Secure Electronic Transaction Specification"
|
1797 |
+
// http://www.maithean.com/docs/set_bk3.pdf
|
1798 |
+
case '2.23.42.7.0': // id-set-hashedRootKey
|
1799 |
+
return true;
|
1800 |
+
|
1801 |
+
// CSR attributes
|
1802 |
+
case 'pkcs-9-at-unstructuredName':
|
1803 |
+
return $this->PKCS9String;
|
1804 |
+
case 'pkcs-9-at-challengePassword':
|
1805 |
+
return $this->DirectoryString;
|
1806 |
+
case 'pkcs-9-at-extensionRequest':
|
1807 |
+
return $this->Extensions;
|
1808 |
+
|
1809 |
+
// CRL extensions.
|
1810 |
+
case 'id-ce-cRLNumber':
|
1811 |
+
return $this->CRLNumber;
|
1812 |
+
case 'id-ce-deltaCRLIndicator':
|
1813 |
+
return $this->CRLNumber;
|
1814 |
+
case 'id-ce-issuingDistributionPoint':
|
1815 |
+
return $this->IssuingDistributionPoint;
|
1816 |
+
case 'id-ce-freshestCRL':
|
1817 |
+
return $this->CRLDistributionPoints;
|
1818 |
+
case 'id-ce-cRLReasons':
|
1819 |
+
return $this->CRLReason;
|
1820 |
+
case 'id-ce-invalidityDate':
|
1821 |
+
return $this->InvalidityDate;
|
1822 |
+
case 'id-ce-certificateIssuer':
|
1823 |
+
return $this->CertificateIssuer;
|
1824 |
+
case 'id-ce-holdInstructionCode':
|
1825 |
+
return $this->HoldInstructionCode;
|
1826 |
+
}
|
1827 |
+
|
1828 |
+
return false;
|
1829 |
+
}
|
1830 |
+
|
1831 |
+
/**
|
1832 |
+
* Load an X.509 certificate as a certificate authority
|
1833 |
+
*
|
1834 |
+
* @param String $cert
|
1835 |
+
* @access public
|
1836 |
+
* @return Boolean
|
1837 |
+
*/
|
1838 |
+
function loadCA($cert)
|
1839 |
+
{
|
1840 |
+
$olddn = $this->dn;
|
1841 |
+
$oldcert = $this->currentCert;
|
1842 |
+
$oldsigsubj = $this->signatureSubject;
|
1843 |
+
$oldkeyid = $this->currentKeyIdentifier;
|
1844 |
+
|
1845 |
+
$cert = $this->loadX509($cert);
|
1846 |
+
if (!$cert) {
|
1847 |
+
$this->dn = $olddn;
|
1848 |
+
$this->currentCert = $oldcert;
|
1849 |
+
$this->signatureSubject = $oldsigsubj;
|
1850 |
+
$this->currentKeyIdentifier = $oldkeyid;
|
1851 |
+
|
1852 |
+
return false;
|
1853 |
+
}
|
1854 |
+
|
1855 |
+
/* From RFC5280 "PKIX Certificate and CRL Profile":
|
1856 |
+
|
1857 |
+
If the keyUsage extension is present, then the subject public key
|
1858 |
+
MUST NOT be used to verify signatures on certificates or CRLs unless
|
1859 |
+
the corresponding keyCertSign or cRLSign bit is set. */
|
1860 |
+
//$keyUsage = $this->getExtension('id-ce-keyUsage');
|
1861 |
+
//if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
|
1862 |
+
// return false;
|
1863 |
+
//}
|
1864 |
+
|
1865 |
+
/* From RFC5280 "PKIX Certificate and CRL Profile":
|
1866 |
+
|
1867 |
+
The cA boolean indicates whether the certified public key may be used
|
1868 |
+
to verify certificate signatures. If the cA boolean is not asserted,
|
1869 |
+
then the keyCertSign bit in the key usage extension MUST NOT be
|
1870 |
+
asserted. If the basic constraints extension is not present in a
|
1871 |
+
version 3 certificate, or the extension is present but the cA boolean
|
1872 |
+
is not asserted, then the certified public key MUST NOT be used to
|
1873 |
+
verify certificate signatures. */
|
1874 |
+
//$basicConstraints = $this->getExtension('id-ce-basicConstraints');
|
1875 |
+
//if (!$basicConstraints || !$basicConstraints['cA']) {
|
1876 |
+
// return false;
|
1877 |
+
//}
|
1878 |
+
|
1879 |
+
$this->CAs[] = $cert;
|
1880 |
+
|
1881 |
+
$this->dn = $olddn;
|
1882 |
+
$this->currentCert = $oldcert;
|
1883 |
+
$this->signatureSubject = $oldsigsubj;
|
1884 |
+
|
1885 |
+
return true;
|
1886 |
+
}
|
1887 |
+
|
1888 |
+
/**
|
1889 |
+
* Validate an X.509 certificate against a URL
|
1890 |
+
*
|
1891 |
+
* From RFC2818 "HTTP over TLS":
|
1892 |
+
*
|
1893 |
+
* Matching is performed using the matching rules specified by
|
1894 |
+
* [RFC2459]. If more than one identity of a given type is present in
|
1895 |
+
* the certificate (e.g., more than one dNSName name, a match in any one
|
1896 |
+
* of the set is considered acceptable.) Names may contain the wildcard
|
1897 |
+
* character * which is considered to match any single domain name
|
1898 |
+
* component or component fragment. E.g., *.a.com matches foo.a.com but
|
1899 |
+
* not bar.foo.a.com. f*.com matches foo.com but not bar.com.
|
1900 |
+
*
|
1901 |
+
* @param String $url
|
1902 |
+
* @access public
|
1903 |
+
* @return Boolean
|
1904 |
+
*/
|
1905 |
+
function validateURL($url)
|
1906 |
+
{
|
1907 |
+
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
|
1908 |
+
return false;
|
1909 |
+
}
|
1910 |
+
|
1911 |
+
$components = parse_url($url);
|
1912 |
+
if (!isset($components['host'])) {
|
1913 |
+
return false;
|
1914 |
+
}
|
1915 |
+
|
1916 |
+
if ($names = $this->getExtension('id-ce-subjectAltName')) {
|
1917 |
+
foreach ($names as $key => $value) {
|
1918 |
+
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
|
1919 |
+
switch ($key) {
|
1920 |
+
case 'dNSName':
|
1921 |
+
/* From RFC2818 "HTTP over TLS":
|
1922 |
+
|
1923 |
+
If a subjectAltName extension of type dNSName is present, that MUST
|
1924 |
+
be used as the identity. Otherwise, the (most specific) Common Name
|
1925 |
+
field in the Subject field of the certificate MUST be used. Although
|
1926 |
+
the use of the Common Name is existing practice, it is deprecated and
|
1927 |
+
Certification Authorities are encouraged to use the dNSName instead. */
|
1928 |
+
if (preg_match('#^' . $value . '$#', $components['host'])) {
|
1929 |
+
return true;
|
1930 |
+
}
|
1931 |
+
break;
|
1932 |
+
case 'iPAddress':
|
1933 |
+
/* From RFC2818 "HTTP over TLS":
|
1934 |
+
|
1935 |
+
In some cases, the URI is specified as an IP address rather than a
|
1936 |
+
hostname. In this case, the iPAddress subjectAltName must be present
|
1937 |
+
in the certificate and must exactly match the IP in the URI. */
|
1938 |
+
if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
|
1939 |
+
return true;
|
1940 |
+
}
|
1941 |
+
}
|
1942 |
+
}
|
1943 |
+
return false;
|
1944 |
+
}
|
1945 |
+
|
1946 |
+
if ($value = $this->getDNProp('id-at-commonName')) {
|
1947 |
+
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
|
1948 |
+
return preg_match('#^' . $value . '$#', $components['host']);
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
return false;
|
1952 |
+
}
|
1953 |
+
|
1954 |
+
/**
|
1955 |
+
* Validate a date
|
1956 |
+
*
|
1957 |
+
* If $date isn't defined it is assumed to be the current date.
|
1958 |
+
*
|
1959 |
+
* @param Integer $date optional
|
1960 |
+
* @access public
|
1961 |
+
*/
|
1962 |
+
function validateDate($date = NULL)
|
1963 |
+
{
|
1964 |
+
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
|
1965 |
+
return false;
|
1966 |
+
}
|
1967 |
+
|
1968 |
+
if (!isset($date)) {
|
1969 |
+
$date = time();
|
1970 |
+
}
|
1971 |
+
|
1972 |
+
$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
|
1973 |
+
$notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
|
1974 |
+
|
1975 |
+
$notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
|
1976 |
+
$notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
|
1977 |
+
|
1978 |
+
switch (true) {
|
1979 |
+
case $date < @strtotime($notBefore):
|
1980 |
+
case $date > @strtotime($notAfter):
|
1981 |
+
return false;
|
1982 |
+
}
|
1983 |
+
|
1984 |
+
return true;
|
1985 |
+
}
|
1986 |
+
|
1987 |
+
/**
|
1988 |
+
* Validate a signature
|
1989 |
+
*
|
1990 |
+
* Works on X.509 certs, CSR's and CRL's.
|
1991 |
+
* Returns true if the signature is verified, false if it is not correct or NULL on error
|
1992 |
+
*
|
1993 |
+
* By default returns false for self-signed certs. Call validateSignature(false) to make this support
|
1994 |
+
* self-signed.
|
1995 |
+
*
|
1996 |
+
* The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
|
1997 |
+
*
|
1998 |
+
* @param Boolean $caonly optional
|
1999 |
+
* @access public
|
2000 |
+
* @return Mixed
|
2001 |
+
*/
|
2002 |
+
function validateSignature($caonly = true)
|
2003 |
+
{
|
2004 |
+
if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
|
2005 |
+
return 0;
|
2006 |
+
}
|
2007 |
+
|
2008 |
+
/* TODO:
|
2009 |
+
"emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
|
2010 |
+
-- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
|
2011 |
+
|
2012 |
+
implement pathLenConstraint in the id-ce-basicConstraints extension */
|
2013 |
+
|
2014 |
+
switch (true) {
|
2015 |
+
case isset($this->currentCert['tbsCertificate']):
|
2016 |
+
// self-signed cert
|
2017 |
+
if ($this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']) {
|
2018 |
+
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
|
2019 |
+
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
|
2020 |
+
switch (true) {
|
2021 |
+
case !is_array($authorityKey):
|
2022 |
+
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
2023 |
+
$signingCert = $this->currentCert; // working cert
|
2024 |
+
}
|
2025 |
+
}
|
2026 |
+
|
2027 |
+
if (!empty($this->CAs)) {
|
2028 |
+
for ($i = 0; $i < count($this->CAs); $i++) {
|
2029 |
+
// even if the cert is a self-signed one we still want to see if it's a CA;
|
2030 |
+
// if not, we'll conditionally return an error
|
2031 |
+
$ca = $this->CAs[$i];
|
2032 |
+
if ($this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
|
2033 |
+
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
|
2034 |
+
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
|
2035 |
+
switch (true) {
|
2036 |
+
case !is_array($authorityKey):
|
2037 |
+
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
2038 |
+
$signingCert = $ca; // working cert
|
2039 |
+
break 2;
|
2040 |
+
}
|
2041 |
+
}
|
2042 |
+
}
|
2043 |
+
if (count($this->CAs) == $i && $caonly) {
|
2044 |
+
return false;
|
2045 |
+
}
|
2046 |
+
} elseif (!isset($signingCert) || $caonly) {
|
2047 |
+
return false;
|
2048 |
+
}
|
2049 |
+
return $this->_validateSignature(
|
2050 |
+
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
|
2051 |
+
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
|
2052 |
+
$this->currentCert['signatureAlgorithm']['algorithm'],
|
2053 |
+
substr(base64_decode($this->currentCert['signature']), 1),
|
2054 |
+
$this->signatureSubject
|
2055 |
+
);
|
2056 |
+
case isset($this->currentCert['certificationRequestInfo']):
|
2057 |
+
return $this->_validateSignature(
|
2058 |
+
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
|
2059 |
+
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
|
2060 |
+
$this->currentCert['signatureAlgorithm']['algorithm'],
|
2061 |
+
substr(base64_decode($this->currentCert['signature']), 1),
|
2062 |
+
$this->signatureSubject
|
2063 |
+
);
|
2064 |
+
case isset($this->currentCert['publicKeyAndChallenge']):
|
2065 |
+
return $this->_validateSignature(
|
2066 |
+
$this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
|
2067 |
+
$this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
|
2068 |
+
$this->currentCert['signatureAlgorithm']['algorithm'],
|
2069 |
+
substr(base64_decode($this->currentCert['signature']), 1),
|
2070 |
+
$this->signatureSubject
|
2071 |
+
);
|
2072 |
+
case isset($this->currentCert['tbsCertList']):
|
2073 |
+
if (!empty($this->CAs)) {
|
2074 |
+
for ($i = 0; $i < count($this->CAs); $i++) {
|
2075 |
+
$ca = $this->CAs[$i];
|
2076 |
+
if ($this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']) {
|
2077 |
+
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
|
2078 |
+
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
|
2079 |
+
switch (true) {
|
2080 |
+
case !is_array($authorityKey):
|
2081 |
+
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
2082 |
+
$signingCert = $ca; // working cert
|
2083 |
+
break 2;
|
2084 |
+
}
|
2085 |
+
}
|
2086 |
+
}
|
2087 |
+
}
|
2088 |
+
if (!isset($signingCert)) {
|
2089 |
+
return false;
|
2090 |
+
}
|
2091 |
+
return $this->_validateSignature(
|
2092 |
+
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
|
2093 |
+
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
|
2094 |
+
$this->currentCert['signatureAlgorithm']['algorithm'],
|
2095 |
+
substr(base64_decode($this->currentCert['signature']), 1),
|
2096 |
+
$this->signatureSubject
|
2097 |
+
);
|
2098 |
+
default:
|
2099 |
+
return false;
|
2100 |
+
}
|
2101 |
+
}
|
2102 |
+
|
2103 |
+
/**
|
2104 |
+
* Validates a signature
|
2105 |
+
*
|
2106 |
+
* Returns true if the signature is verified, false if it is not correct or NULL on error
|
2107 |
+
*
|
2108 |
+
* @param String $publicKeyAlgorithm
|
2109 |
+
* @param String $publicKey
|
2110 |
+
* @param String $signatureAlgorithm
|
2111 |
+
* @param String $signature
|
2112 |
+
* @param String $signatureSubject
|
2113 |
+
* @access private
|
2114 |
+
* @return Integer
|
2115 |
+
*/
|
2116 |
+
function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
|
2117 |
+
{
|
2118 |
+
switch ($publicKeyAlgorithm) {
|
2119 |
+
case 'rsaEncryption':
|
2120 |
+
if (!class_exists('Crypt_RSA')) {
|
2121 |
+
require_once('Crypt/RSA.php');
|
2122 |
+
}
|
2123 |
+
$rsa = new Crypt_RSA();
|
2124 |
+
$rsa->loadKey($publicKey);
|
2125 |
+
|
2126 |
+
switch ($signatureAlgorithm) {
|
2127 |
+
case 'md2WithRSAEncryption':
|
2128 |
+
case 'md5WithRSAEncryption':
|
2129 |
+
case 'sha1WithRSAEncryption':
|
2130 |
+
case 'sha224WithRSAEncryption':
|
2131 |
+
case 'sha256WithRSAEncryption':
|
2132 |
+
case 'sha384WithRSAEncryption':
|
2133 |
+
case 'sha512WithRSAEncryption':
|
2134 |
+
$rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
|
2135 |
+
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
2136 |
+
if (!@$rsa->verify($signatureSubject, $signature)) {
|
2137 |
+
return false;
|
2138 |
+
}
|
2139 |
+
break;
|
2140 |
+
default:
|
2141 |
+
return NULL;
|
2142 |
+
}
|
2143 |
+
break;
|
2144 |
+
default:
|
2145 |
+
return NULL;
|
2146 |
+
}
|
2147 |
+
|
2148 |
+
return true;
|
2149 |
+
}
|
2150 |
+
|
2151 |
+
/**
|
2152 |
+
* Reformat public keys
|
2153 |
+
*
|
2154 |
+
* Reformats a public key to a format supported by phpseclib (if applicable)
|
2155 |
+
*
|
2156 |
+
* @param String $algorithm
|
2157 |
+
* @param String $key
|
2158 |
+
* @access private
|
2159 |
+
* @return String
|
2160 |
+
*/
|
2161 |
+
function _reformatKey($algorithm, $key)
|
2162 |
+
{
|
2163 |
+
switch ($algorithm) {
|
2164 |
+
case 'rsaEncryption':
|
2165 |
+
return
|
2166 |
+
"-----BEGIN PUBLIC KEY-----\r\n" .
|
2167 |
+
// subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
|
2168 |
+
// in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
|
2169 |
+
// uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
|
2170 |
+
chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
|
2171 |
+
'-----END PUBLIC KEY-----';
|
2172 |
+
default:
|
2173 |
+
return $key;
|
2174 |
+
}
|
2175 |
+
}
|
2176 |
+
|
2177 |
+
/**
|
2178 |
+
* "Normalizes" a Distinguished Name property
|
2179 |
+
*
|
2180 |
+
* @param String $propName
|
2181 |
+
* @access private
|
2182 |
+
* @return Mixed
|
2183 |
+
*/
|
2184 |
+
function _translateDNProp($propName)
|
2185 |
+
{
|
2186 |
+
switch (strtolower($propName)) {
|
2187 |
+
case 'id-at-countryname':
|
2188 |
+
case 'countryname':
|
2189 |
+
case 'c':
|
2190 |
+
return 'id-at-countryName';
|
2191 |
+
case 'id-at-organizationname':
|
2192 |
+
case 'organizationname':
|
2193 |
+
case 'o':
|
2194 |
+
return 'id-at-organizationName';
|
2195 |
+
case 'id-at-dnqualifier':
|
2196 |
+
case 'dnqualifier':
|
2197 |
+
return 'id-at-dnQualifier';
|
2198 |
+
case 'id-at-commonname':
|
2199 |
+
case 'commonname':
|
2200 |
+
case 'cn':
|
2201 |
+
return 'id-at-commonName';
|
2202 |
+
case 'id-at-stateorprovinceName':
|
2203 |
+
case 'stateorprovincename':
|
2204 |
+
case 'state':
|
2205 |
+
case 'province':
|
2206 |
+
case 'provincename':
|
2207 |
+
case 'st':
|
2208 |
+
return 'id-at-stateOrProvinceName';
|
2209 |
+
case 'id-at-localityname':
|
2210 |
+
case 'localityname':
|
2211 |
+
case 'l':
|
2212 |
+
return 'id-at-localityName';
|
2213 |
+
case 'id-emailaddress':
|
2214 |
+
case 'emailaddress':
|
2215 |
+
return 'pkcs-9-at-emailAddress';
|
2216 |
+
case 'id-at-serialnumber':
|
2217 |
+
case 'serialnumber':
|
2218 |
+
return 'id-at-serialNumber';
|
2219 |
+
case 'id-at-postalcode':
|
2220 |
+
case 'postalcode':
|
2221 |
+
return 'id-at-postalCode';
|
2222 |
+
case 'id-at-streetaddress':
|
2223 |
+
case 'streetaddress':
|
2224 |
+
return 'id-at-streetAddress';
|
2225 |
+
case 'id-at-name':
|
2226 |
+
case 'name':
|
2227 |
+
return 'id-at-name';
|
2228 |
+
case 'id-at-givenname':
|
2229 |
+
case 'givenname':
|
2230 |
+
return 'id-at-givenName';
|
2231 |
+
case 'id-at-surname':
|
2232 |
+
case 'surname':
|
2233 |
+
case 'sn':
|
2234 |
+
return 'id-at-surname';
|
2235 |
+
case 'id-at-initials':
|
2236 |
+
case 'initials':
|
2237 |
+
return 'id-at-initials';
|
2238 |
+
case 'id-at-generationqualifier':
|
2239 |
+
case 'generationqualifier':
|
2240 |
+
return 'id-at-generationQualifier';
|
2241 |
+
case 'id-at-organizationalunitname':
|
2242 |
+
case 'organizationalunitname':
|
2243 |
+
case 'ou':
|
2244 |
+
return 'id-at-organizationalUnitName';
|
2245 |
+
case 'id-at-pseudonym':
|
2246 |
+
case 'pseudonym':
|
2247 |
+
return 'id-at-pseudonym';
|
2248 |
+
case 'id-at-title':
|
2249 |
+
case 'title':
|
2250 |
+
return 'id-at-title';
|
2251 |
+
case 'id-at-description':
|
2252 |
+
case 'description':
|
2253 |
+
return 'id-at-description';
|
2254 |
+
case 'id-at-role':
|
2255 |
+
case 'role':
|
2256 |
+
return 'id-at-role';
|
2257 |
+
case 'id-at-uniqueidentifier':
|
2258 |
+
case 'uniqueidentifier':
|
2259 |
+
case 'x500uniqueidentifier':
|
2260 |
+
return 'id-at-uniqueIdentifier';
|
2261 |
+
default:
|
2262 |
+
return false;
|
2263 |
+
}
|
2264 |
+
}
|
2265 |
+
|
2266 |
+
/**
|
2267 |
+
* Set a Distinguished Name property
|
2268 |
+
*
|
2269 |
+
* @param String $propName
|
2270 |
+
* @param Mixed $propValue
|
2271 |
+
* @param String $type optional
|
2272 |
+
* @access public
|
2273 |
+
* @return Boolean
|
2274 |
+
*/
|
2275 |
+
function setDNProp($propName, $propValue, $type = 'utf8String')
|
2276 |
+
{
|
2277 |
+
if (empty($this->dn)) {
|
2278 |
+
$this->dn = array('rdnSequence' => array());
|
2279 |
+
}
|
2280 |
+
|
2281 |
+
if (($propName = $this->_translateDNProp($propName)) === false) {
|
2282 |
+
return false;
|
2283 |
+
}
|
2284 |
+
|
2285 |
+
foreach ((array) $propValue as $v) {
|
2286 |
+
if (!is_array($v) && isset($type)) {
|
2287 |
+
$v = array($type => $v);
|
2288 |
+
}
|
2289 |
+
$this->dn['rdnSequence'][] = array(
|
2290 |
+
array(
|
2291 |
+
'type' => $propName,
|
2292 |
+
'value'=> $v
|
2293 |
+
)
|
2294 |
+
);
|
2295 |
+
}
|
2296 |
+
|
2297 |
+
return true;
|
2298 |
+
}
|
2299 |
+
|
2300 |
+
/**
|
2301 |
+
* Remove Distinguished Name properties
|
2302 |
+
*
|
2303 |
+
* @param String $propName
|
2304 |
+
* @access public
|
2305 |
+
*/
|
2306 |
+
function removeDNProp($propName)
|
2307 |
+
{
|
2308 |
+
if (empty($this->dn)) {
|
2309 |
+
return;
|
2310 |
+
}
|
2311 |
+
|
2312 |
+
if (($propName = $this->_translateDNProp($propName)) === false) {
|
2313 |
+
return;
|
2314 |
+
}
|
2315 |
+
|
2316 |
+
$dn = &$this->dn['rdnSequence'];
|
2317 |
+
$size = count($dn);
|
2318 |
+
for ($i = 0; $i < $size; $i++) {
|
2319 |
+
if ($dn[$i][0]['type'] == $propName) {
|
2320 |
+
unset($dn[$i]);
|
2321 |
+
}
|
2322 |
+
}
|
2323 |
+
|
2324 |
+
$dn = array_values($dn);
|
2325 |
+
}
|
2326 |
+
|
2327 |
+
/**
|
2328 |
+
* Get Distinguished Name properties
|
2329 |
+
*
|
2330 |
+
* @param String $propName
|
2331 |
+
* @param Array $dn optional
|
2332 |
+
* @param Boolean $withType optional
|
2333 |
+
* @return Mixed
|
2334 |
+
* @access public
|
2335 |
+
*/
|
2336 |
+
function getDNProp($propName, $dn = NULL, $withType = false)
|
2337 |
+
{
|
2338 |
+
if (!isset($dn)) {
|
2339 |
+
$dn = $this->dn;
|
2340 |
+
}
|
2341 |
+
|
2342 |
+
if (empty($dn)) {
|
2343 |
+
return false;
|
2344 |
+
}
|
2345 |
+
|
2346 |
+
if (($propName = $this->_translateDNProp($propName)) === false) {
|
2347 |
+
return false;
|
2348 |
+
}
|
2349 |
+
|
2350 |
+
$dn = $dn['rdnSequence'];
|
2351 |
+
$result = array();
|
2352 |
+
$asn1 = new File_ASN1();
|
2353 |
+
for ($i = 0; $i < count($dn); $i++) {
|
2354 |
+
if ($dn[$i][0]['type'] == $propName) {
|
2355 |
+
$v = $dn[$i][0]['value'];
|
2356 |
+
if (!$withType && is_array($v)) {
|
2357 |
+
foreach ($v as $type => $s) {
|
2358 |
+
$type = array_search($type, $asn1->ANYmap, true);
|
2359 |
+
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
|
2360 |
+
$s = $asn1->convert($s, $type);
|
2361 |
+
if ($s !== false) {
|
2362 |
+
$v = $s;
|
2363 |
+
break;
|
2364 |
+
}
|
2365 |
+
}
|
2366 |
+
}
|
2367 |
+
if (is_array($v)) {
|
2368 |
+
$v = array_pop($v); // Always strip data type.
|
2369 |
+
}
|
2370 |
+
}
|
2371 |
+
$result[] = $v;
|
2372 |
+
}
|
2373 |
+
}
|
2374 |
+
|
2375 |
+
return $result;
|
2376 |
+
}
|
2377 |
+
|
2378 |
+
/**
|
2379 |
+
* Set a Distinguished Name
|
2380 |
+
*
|
2381 |
+
* @param Mixed $dn
|
2382 |
+
* @param Boolean $merge optional
|
2383 |
+
* @param String $type optional
|
2384 |
+
* @access public
|
2385 |
+
* @return Boolean
|
2386 |
+
*/
|
2387 |
+
function setDN($dn, $merge = false, $type = 'utf8String')
|
2388 |
+
{
|
2389 |
+
if (!$merge) {
|
2390 |
+
$this->dn = NULL;
|
2391 |
+
}
|
2392 |
+
|
2393 |
+
if (is_array($dn)) {
|
2394 |
+
if (isset($dn['rdnSequence'])) {
|
2395 |
+
$this->dn = $dn; // No merge here.
|
2396 |
+
return true;
|
2397 |
+
}
|
2398 |
+
|
2399 |
+
// handles stuff generated by openssl_x509_parse()
|
2400 |
+
foreach ($dn as $prop => $value) {
|
2401 |
+
if (!$this->setDNProp($prop, $value, $type)) {
|
2402 |
+
return false;
|
2403 |
+
}
|
2404 |
+
}
|
2405 |
+
return true;
|
2406 |
+
}
|
2407 |
+
|
2408 |
+
// handles everything else
|
2409 |
+
$results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
|
2410 |
+
for ($i = 1; $i < count($results); $i+=2) {
|
2411 |
+
$prop = trim($results[$i], ', =/');
|
2412 |
+
$value = $results[$i + 1];
|
2413 |
+
if (!$this->setDNProp($prop, $value, $type)) {
|
2414 |
+
return false;
|
2415 |
+
}
|
2416 |
+
}
|
2417 |
+
|
2418 |
+
return true;
|
2419 |
+
}
|
2420 |
+
|
2421 |
+
/**
|
2422 |
+
* Get the Distinguished Name for a certificates subject
|
2423 |
+
*
|
2424 |
+
* @param Mixed $format optional
|
2425 |
+
* @param Array $dn optional
|
2426 |
+
* @access public
|
2427 |
+
* @return Boolean
|
2428 |
+
*/
|
2429 |
+
function getDN($format = FILE_X509_DN_ARRAY, $dn = NULL)
|
2430 |
+
{
|
2431 |
+
if (!isset($dn)) {
|
2432 |
+
$dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
|
2433 |
+
}
|
2434 |
+
|
2435 |
+
switch ((int) $format) {
|
2436 |
+
case FILE_X509_DN_ARRAY:
|
2437 |
+
return $dn;
|
2438 |
+
case FILE_X509_DN_ASN1:
|
2439 |
+
$asn1 = new File_ASN1();
|
2440 |
+
$asn1->loadOIDs($this->oids);
|
2441 |
+
$filters = array();
|
2442 |
+
$filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
|
2443 |
+
$asn1->loadFilters($filters);
|
2444 |
+
return $asn1->encodeDER($dn, $this->Name);
|
2445 |
+
case FILE_X509_DN_OPENSSL:
|
2446 |
+
$dn = $this->getDN(FILE_X509_DN_STRING, $dn);
|
2447 |
+
if ($dn === false) {
|
2448 |
+
return false;
|
2449 |
+
}
|
2450 |
+
$attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
|
2451 |
+
$dn = array();
|
2452 |
+
for ($i = 1; $i < count($attrs); $i += 2) {
|
2453 |
+
$prop = trim($attrs[$i], ', =/');
|
2454 |
+
$value = $attrs[$i + 1];
|
2455 |
+
if (!isset($dn[$prop])) {
|
2456 |
+
$dn[$prop] = $value;
|
2457 |
+
} else {
|
2458 |
+
$dn[$prop] = array_merge((array) $dn[$prop], array($value));
|
2459 |
+
}
|
2460 |
+
}
|
2461 |
+
return $dn;
|
2462 |
+
case FILE_X509_DN_CANON:
|
2463 |
+
// No SEQUENCE around RDNs and all string values normalized as
|
2464 |
+
// trimmed lowercase UTF-8 with all spacing as one blank.
|
2465 |
+
$asn1 = new File_ASN1();
|
2466 |
+
$asn1->loadOIDs($this->oids);
|
2467 |
+
$filters = array();
|
2468 |
+
$filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
|
2469 |
+
$asn1->loadFilters($filters);
|
2470 |
+
$result = '';
|
2471 |
+
foreach ($dn['rdnSequence'] as $rdn) {
|
2472 |
+
foreach ($rdn as &$attr) {
|
2473 |
+
if (is_array($attr['value'])) {
|
2474 |
+
foreach ($attr['value'] as $type => $v) {
|
2475 |
+
$type = array_search($type, $asn1->ANYmap, true);
|
2476 |
+
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
|
2477 |
+
$v = $asn1->convert($v, $type);
|
2478 |
+
if ($v !== false) {
|
2479 |
+
$v = preg_replace('/\s+/', ' ', $v);
|
2480 |
+
$attr['value'] = strtolower(trim($v));
|
2481 |
+
break;
|
2482 |
+
}
|
2483 |
+
}
|
2484 |
+
}
|
2485 |
+
}
|
2486 |
+
}
|
2487 |
+
$result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
|
2488 |
+
}
|
2489 |
+
return $result;
|
2490 |
+
case FILE_X509_DN_HASH:
|
2491 |
+
$dn = $this->getDN(FILE_X509_DN_CANON, $dn);
|
2492 |
+
if (!class_exists('Crypt_Hash')) {
|
2493 |
+
require_once('Crypt/Hash.php');
|
2494 |
+
}
|
2495 |
+
$hash = new Crypt_Hash('sha1');
|
2496 |
+
$hash = $hash->hash($dn);
|
2497 |
+
extract(unpack('Vhash', $hash));
|
2498 |
+
return strtolower(bin2hex(pack('N', $hash)));
|
2499 |
+
}
|
2500 |
+
|
2501 |
+
// Defaut is to return a string.
|
2502 |
+
$start = true;
|
2503 |
+
$output = '';
|
2504 |
+
$asn1 = new File_ASN1();
|
2505 |
+
foreach ($dn['rdnSequence'] as $field) {
|
2506 |
+
$prop = $field[0]['type'];
|
2507 |
+
$value = $field[0]['value'];
|
2508 |
+
|
2509 |
+
$delim = ', ';
|
2510 |
+
switch ($prop) {
|
2511 |
+
case 'id-at-countryName':
|
2512 |
+
$desc = 'C=';
|
2513 |
+
break;
|
2514 |
+
case 'id-at-stateOrProvinceName':
|
2515 |
+
$desc = 'ST=';
|
2516 |
+
break;
|
2517 |
+
case 'id-at-organizationName':
|
2518 |
+
$desc = 'O=';
|
2519 |
+
break;
|
2520 |
+
case 'id-at-organizationalUnitName':
|
2521 |
+
$desc = 'OU=';
|
2522 |
+
break;
|
2523 |
+
case 'id-at-commonName':
|
2524 |
+
$desc = 'CN=';
|
2525 |
+
break;
|
2526 |
+
case 'id-at-localityName':
|
2527 |
+
$desc = 'L=';
|
2528 |
+
break;
|
2529 |
+
case 'id-at-surname':
|
2530 |
+
$desc = 'SN=';
|
2531 |
+
break;
|
2532 |
+
case 'id-at-uniqueIdentifier':
|
2533 |
+
$delim = '/';
|
2534 |
+
$desc = 'x500UniqueIdentifier=';
|
2535 |
+
break;
|
2536 |
+
default:
|
2537 |
+
$delim = '/';
|
2538 |
+
$desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '=';
|
2539 |
+
}
|
2540 |
+
|
2541 |
+
if (!$start) {
|
2542 |
+
$output.= $delim;
|
2543 |
+
}
|
2544 |
+
if (is_array($value)) {
|
2545 |
+
foreach ($value as $type => $v) {
|
2546 |
+
$type = array_search($type, $asn1->ANYmap, true);
|
2547 |
+
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
|
2548 |
+
$v = $asn1->convert($v, $type);
|
2549 |
+
if ($v !== false) {
|
2550 |
+
$value = $v;
|
2551 |
+
break;
|
2552 |
+
}
|
2553 |
+
}
|
2554 |
+
}
|
2555 |
+
if (is_array($value)) {
|
2556 |
+
$value = array_pop($value); // Always strip data type.
|
2557 |
+
}
|
2558 |
+
}
|
2559 |
+
$output.= $desc . $value;
|
2560 |
+
$start = false;
|
2561 |
+
}
|
2562 |
+
|
2563 |
+
return $output;
|
2564 |
+
}
|
2565 |
+
|
2566 |
+
/**
|
2567 |
+
* Get the Distinguished Name for a certificate/crl issuer
|
2568 |
+
*
|
2569 |
+
* @param Integer $format optional
|
2570 |
+
* @access public
|
2571 |
+
* @return Mixed
|
2572 |
+
*/
|
2573 |
+
function getIssuerDN($format = FILE_X509_DN_ARRAY)
|
2574 |
+
{
|
2575 |
+
switch (true) {
|
2576 |
+
case !isset($this->currentCert) || !is_array($this->currentCert):
|
2577 |
+
break;
|
2578 |
+
case isset($this->currentCert['tbsCertificate']):
|
2579 |
+
return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
|
2580 |
+
case isset($this->currentCert['tbsCertList']):
|
2581 |
+
return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
|
2582 |
+
}
|
2583 |
+
|
2584 |
+
return false;
|
2585 |
+
}
|
2586 |
+
|
2587 |
+
/**
|
2588 |
+
* Get the Distinguished Name for a certificate/csr subject
|
2589 |
+
* Alias of getDN()
|
2590 |
+
*
|
2591 |
+
* @param Integer $format optional
|
2592 |
+
* @access public
|
2593 |
+
* @return Mixed
|
2594 |
+
*/
|
2595 |
+
function getSubjectDN($format = FILE_X509_DN_ARRAY)
|
2596 |
+
{
|
2597 |
+
switch (true) {
|
2598 |
+
case !empty($this->dn):
|
2599 |
+
return $this->getDN($format);
|
2600 |
+
case !isset($this->currentCert) || !is_array($this->currentCert):
|
2601 |
+
break;
|
2602 |
+
case isset($this->currentCert['tbsCertificate']):
|
2603 |
+
return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
|
2604 |
+
case isset($this->currentCert['certificationRequestInfo']):
|
2605 |
+
return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
|
2606 |
+
}
|
2607 |
+
|
2608 |
+
return false;
|
2609 |
+
}
|
2610 |
+
|
2611 |
+
/**
|
2612 |
+
* Get an individual Distinguished Name property for a certificate/crl issuer
|
2613 |
+
*
|
2614 |
+
* @param String $propName
|
2615 |
+
* @param Boolean $withType optional
|
2616 |
+
* @access public
|
2617 |
+
* @return Mixed
|
2618 |
+
*/
|
2619 |
+
function getIssuerDNProp($propName, $withType = false)
|
2620 |
+
{
|
2621 |
+
switch (true) {
|
2622 |
+
case !isset($this->currentCert) || !is_array($this->currentCert):
|
2623 |
+
break;
|
2624 |
+
case isset($this->currentCert['tbsCertificate']):
|
2625 |
+
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
|
2626 |
+
case isset($this->currentCert['tbsCertList']):
|
2627 |
+
return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
|
2628 |
+
}
|
2629 |
+
|
2630 |
+
return false;
|
2631 |
+
}
|
2632 |
+
|
2633 |
+
/**
|
2634 |
+
* Get an individual Distinguished Name property for a certificate/csr subject
|
2635 |
+
*
|
2636 |
+
* @param String $propName
|
2637 |
+
* @param Boolean $withType optional
|
2638 |
+
* @access public
|
2639 |
+
* @return Mixed
|
2640 |
+
*/
|
2641 |
+
function getSubjectDNProp($propName, $withType = false)
|
2642 |
+
{
|
2643 |
+
switch (true) {
|
2644 |
+
case !empty($this->dn):
|
2645 |
+
return $this->getDNProp($propName, NULL, $withType);
|
2646 |
+
case !isset($this->currentCert) || !is_array($this->currentCert):
|
2647 |
+
break;
|
2648 |
+
case isset($this->currentCert['tbsCertificate']):
|
2649 |
+
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
|
2650 |
+
case isset($this->currentCert['certificationRequestInfo']):
|
2651 |
+
return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
|
2652 |
+
}
|
2653 |
+
|
2654 |
+
return false;
|
2655 |
+
}
|
2656 |
+
|
2657 |
+
/**
|
2658 |
+
* Get the certificate chain for the current cert
|
2659 |
+
*
|
2660 |
+
* @access public
|
2661 |
+
* @return Mixed
|
2662 |
+
*/
|
2663 |
+
function getChain()
|
2664 |
+
{
|
2665 |
+
$chain = array($this->currentCert);
|
2666 |
+
|
2667 |
+
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
|
2668 |
+
return false;
|
2669 |
+
}
|
2670 |
+
if (empty($this->CAs)) {
|
2671 |
+
return $chain;
|
2672 |
+
}
|
2673 |
+
while (true) {
|
2674 |
+
$currentCert = $chain[count($chain) - 1];
|
2675 |
+
for ($i = 0; $i < count($this->CAs); $i++) {
|
2676 |
+
$ca = $this->CAs[$i];
|
2677 |
+
if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
|
2678 |
+
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
|
2679 |
+
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
|
2680 |
+
switch (true) {
|
2681 |
+
case !is_array($authorityKey):
|
2682 |
+
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
2683 |
+
if ($currentCert === $ca) {
|
2684 |
+
break 3;
|
2685 |
+
}
|
2686 |
+
$chain[] = $ca;
|
2687 |
+
break 2;
|
2688 |
+
}
|
2689 |
+
}
|
2690 |
+
}
|
2691 |
+
if ($i == count($this->CAs)) {
|
2692 |
+
break;
|
2693 |
+
}
|
2694 |
+
}
|
2695 |
+
foreach ($chain as $key=>$value) {
|
2696 |
+
$chain[$key] = new File_X509();
|
2697 |
+
$chain[$key]->loadX509($value);
|
2698 |
+
}
|
2699 |
+
return $chain;
|
2700 |
+
}
|
2701 |
+
|
2702 |
+
/**
|
2703 |
+
* Set public key
|
2704 |
+
*
|
2705 |
+
* Key needs to be a Crypt_RSA object
|
2706 |
+
*
|
2707 |
+
* @param Object $key
|
2708 |
+
* @access public
|
2709 |
+
* @return Boolean
|
2710 |
+
*/
|
2711 |
+
function setPublicKey($key)
|
2712 |
+
{
|
2713 |
+
$this->publicKey = $key;
|
2714 |
+
}
|
2715 |
+
|
2716 |
+
/**
|
2717 |
+
* Set private key
|
2718 |
+
*
|
2719 |
+
* Key needs to be a Crypt_RSA object
|
2720 |
+
*
|
2721 |
+
* @param Object $key
|
2722 |
+
* @access public
|
2723 |
+
*/
|
2724 |
+
function setPrivateKey($key)
|
2725 |
+
{
|
2726 |
+
$this->privateKey = $key;
|
2727 |
+
}
|
2728 |
+
|
2729 |
+
/**
|
2730 |
+
* Gets the public key
|
2731 |
+
*
|
2732 |
+
* Returns a Crypt_RSA object or a false.
|
2733 |
+
*
|
2734 |
+
* @access public
|
2735 |
+
* @return Mixed
|
2736 |
+
*/
|
2737 |
+
function getPublicKey()
|
2738 |
+
{
|
2739 |
+
if (isset($this->publicKey)) {
|
2740 |
+
return $this->publicKey;
|
2741 |
+
}
|
2742 |
+
|
2743 |
+
if (isset($this->currentCert) && is_array($this->currentCert)) {
|
2744 |
+
foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
|
2745 |
+
$keyinfo = $this->_subArray($this->currentCert, $path);
|
2746 |
+
if (!empty($keyinfo)) {
|
2747 |
+
break;
|
2748 |
+
}
|
2749 |
+
}
|
2750 |
+
}
|
2751 |
+
if (empty($keyinfo)) {
|
2752 |
+
return false;
|
2753 |
+
}
|
2754 |
+
|
2755 |
+
$key = $keyinfo['subjectPublicKey'];
|
2756 |
+
|
2757 |
+
switch ($keyinfo['algorithm']['algorithm']) {
|
2758 |
+
case 'rsaEncryption':
|
2759 |
+
if (!class_exists('Crypt_RSA')) {
|
2760 |
+
require_once('Crypt/RSA.php');
|
2761 |
+
}
|
2762 |
+
$publicKey = new Crypt_RSA();
|
2763 |
+
$publicKey->loadKey($key);
|
2764 |
+
$publicKey->setPublicKey();
|
2765 |
+
break;
|
2766 |
+
default:
|
2767 |
+
return false;
|
2768 |
+
}
|
2769 |
+
|
2770 |
+
return $publicKey;
|
2771 |
+
}
|
2772 |
+
|
2773 |
+
/**
|
2774 |
+
* Load a Certificate Signing Request
|
2775 |
+
*
|
2776 |
+
* @param String $csr
|
2777 |
+
* @access public
|
2778 |
+
* @return Mixed
|
2779 |
+
*/
|
2780 |
+
function loadCSR($csr)
|
2781 |
+
{
|
2782 |
+
if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
|
2783 |
+
unset($this->currentCert);
|
2784 |
+
unset($this->currentKeyIdentifier);
|
2785 |
+
unset($this->signatureSubject);
|
2786 |
+
$this->dn = $csr['certificationRequestInfo']['subject'];
|
2787 |
+
if (!isset($this->dn)) {
|
2788 |
+
return false;
|
2789 |
+
}
|
2790 |
+
|
2791 |
+
$this->currentCert = $csr;
|
2792 |
+
return $csr;
|
2793 |
+
}
|
2794 |
+
|
2795 |
+
// see http://tools.ietf.org/html/rfc2986
|
2796 |
+
|
2797 |
+
$asn1 = new File_ASN1();
|
2798 |
+
|
2799 |
+
$csr = $this->_extractBER($csr);
|
2800 |
+
$orig = $csr;
|
2801 |
+
|
2802 |
+
if ($csr === false) {
|
2803 |
+
$this->currentCert = false;
|
2804 |
+
return false;
|
2805 |
+
}
|
2806 |
+
|
2807 |
+
$asn1->loadOIDs($this->oids);
|
2808 |
+
$decoded = $asn1->decodeBER($csr);
|
2809 |
+
|
2810 |
+
if (empty($decoded)) {
|
2811 |
+
$this->currentCert = false;
|
2812 |
+
return false;
|
2813 |
+
}
|
2814 |
+
|
2815 |
+
$csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
|
2816 |
+
if (!isset($csr) || $csr === false) {
|
2817 |
+
$this->currentCert = false;
|
2818 |
+
return false;
|
2819 |
+
}
|
2820 |
+
|
2821 |
+
$this->dn = $csr['certificationRequestInfo']['subject'];
|
2822 |
+
$this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
|
2823 |
+
|
2824 |
+
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
|
2825 |
+
|
2826 |
+
$algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
|
2827 |
+
$key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
|
2828 |
+
$key = $this->_reformatKey($algorithm, $key);
|
2829 |
+
|
2830 |
+
switch ($algorithm) {
|
2831 |
+
case 'rsaEncryption':
|
2832 |
+
if (!class_exists('Crypt_RSA')) {
|
2833 |
+
require_once('Crypt/RSA.php');
|
2834 |
+
}
|
2835 |
+
$this->publicKey = new Crypt_RSA();
|
2836 |
+
$this->publicKey->loadKey($key);
|
2837 |
+
$this->publicKey->setPublicKey();
|
2838 |
+
break;
|
2839 |
+
default:
|
2840 |
+
$this->publicKey = NULL;
|
2841 |
+
}
|
2842 |
+
|
2843 |
+
$this->currentKeyIdentifier = NULL;
|
2844 |
+
$this->currentCert = $csr;
|
2845 |
+
|
2846 |
+
return $csr;
|
2847 |
+
}
|
2848 |
+
|
2849 |
+
/**
|
2850 |
+
* Save CSR request
|
2851 |
+
*
|
2852 |
+
* @param Array $csr
|
2853 |
+
* @param Integer $format optional
|
2854 |
+
* @access public
|
2855 |
+
* @return String
|
2856 |
+
*/
|
2857 |
+
function saveCSR($csr, $format = FILE_X509_FORMAT_PEM)
|
2858 |
+
{
|
2859 |
+
if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
|
2860 |
+
return false;
|
2861 |
+
}
|
2862 |
+
|
2863 |
+
switch (true) {
|
2864 |
+
case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
|
2865 |
+
case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']);
|
2866 |
+
break;
|
2867 |
+
default:
|
2868 |
+
switch ($algorithm) {
|
2869 |
+
case 'rsaEncryption':
|
2870 |
+
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] =
|
2871 |
+
base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
|
2872 |
+
}
|
2873 |
+
}
|
2874 |
+
|
2875 |
+
$asn1 = new File_ASN1();
|
2876 |
+
|
2877 |
+
$asn1->loadOIDs($this->oids);
|
2878 |
+
|
2879 |
+
$filters = array();
|
2880 |
+
$filters['certificationRequestInfo']['subject']['rdnSequence']['value'] =
|
2881 |
+
array('type' => FILE_ASN1_TYPE_UTF8_STRING);
|
2882 |
+
|
2883 |
+
$asn1->loadFilters($filters);
|
2884 |
+
|
2885 |
+
$this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
|
2886 |
+
$csr = $asn1->encodeDER($csr, $this->CertificationRequest);
|
2887 |
+
|
2888 |
+
switch ($format) {
|
2889 |
+
case FILE_X509_FORMAT_DER:
|
2890 |
+
return $csr;
|
2891 |
+
// case FILE_X509_FORMAT_PEM:
|
2892 |
+
default:
|
2893 |
+
return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
|
2894 |
+
}
|
2895 |
+
}
|
2896 |
+
|
2897 |
+
/**
|
2898 |
+
* Load a SPKAC CSR
|
2899 |
+
*
|
2900 |
+
* SPKAC's are produced by the HTML5 keygen element:
|
2901 |
+
*
|
2902 |
+
* https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
|
2903 |
+
*
|
2904 |
+
* @param String $csr
|
2905 |
+
* @access public
|
2906 |
+
* @return Mixed
|
2907 |
+
*/
|
2908 |
+
function loadSPKAC($csr)
|
2909 |
+
{
|
2910 |
+
if (is_array($csr) && isset($csr['publicKeyAndChallenge'])) {
|
2911 |
+
unset($this->currentCert);
|
2912 |
+
unset($this->currentKeyIdentifier);
|
2913 |
+
unset($this->signatureSubject);
|
2914 |
+
$this->currentCert = $csr;
|
2915 |
+
return $csr;
|
2916 |
+
}
|
2917 |
+
|
2918 |
+
// see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
|
2919 |
+
|
2920 |
+
$asn1 = new File_ASN1();
|
2921 |
+
|
2922 |
+
$temp = preg_replace('#(?:^[^=]+=)|[\r\n\\\]#', '', $csr);
|
2923 |
+
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
|
2924 |
+
if ($temp != false) {
|
2925 |
+
$csr = $temp;
|
2926 |
+
}
|
2927 |
+
$orig = $csr;
|
2928 |
+
|
2929 |
+
if ($csr === false) {
|
2930 |
+
$this->currentCert = false;
|
2931 |
+
return false;
|
2932 |
+
}
|
2933 |
+
|
2934 |
+
$asn1->loadOIDs($this->oids);
|
2935 |
+
$decoded = $asn1->decodeBER($csr);
|
2936 |
+
|
2937 |
+
if (empty($decoded)) {
|
2938 |
+
$this->currentCert = false;
|
2939 |
+
return false;
|
2940 |
+
}
|
2941 |
+
|
2942 |
+
$csr = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
|
2943 |
+
|
2944 |
+
if (!isset($csr) || $csr === false) {
|
2945 |
+
$this->currentCert = false;
|
2946 |
+
return false;
|
2947 |
+
}
|
2948 |
+
|
2949 |
+
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
|
2950 |
+
|
2951 |
+
$algorithm = &$csr['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
|
2952 |
+
$key = &$csr['publicKeyAndChallenge']['spki']['subjectPublicKey'];
|
2953 |
+
$key = $this->_reformatKey($algorithm, $key);
|
2954 |
+
|
2955 |
+
switch ($algorithm) {
|
2956 |
+
case 'rsaEncryption':
|
2957 |
+
if (!class_exists('Crypt_RSA')) {
|
2958 |
+
require_once('Crypt/RSA.php');
|
2959 |
+
}
|
2960 |
+
$this->publicKey = new Crypt_RSA();
|
2961 |
+
$this->publicKey->loadKey($key);
|
2962 |
+
$this->publicKey->setPublicKey();
|
2963 |
+
break;
|
2964 |
+
default:
|
2965 |
+
$this->publicKey = NULL;
|
2966 |
+
}
|
2967 |
+
|
2968 |
+
$this->currentKeyIdentifier = NULL;
|
2969 |
+
$this->currentCert = $csr;
|
2970 |
+
|
2971 |
+
return $csr;
|
2972 |
+
}
|
2973 |
+
|
2974 |
+
/**
|
2975 |
+
* Load a Certificate Revocation List
|
2976 |
+
*
|
2977 |
+
* @param String $crl
|
2978 |
+
* @access public
|
2979 |
+
* @return Mixed
|
2980 |
+
*/
|
2981 |
+
function loadCRL($crl)
|
2982 |
+
{
|
2983 |
+
if (is_array($crl) && isset($crl['tbsCertList'])) {
|
2984 |
+
$this->currentCert = $crl;
|
2985 |
+
unset($this->signatureSubject);
|
2986 |
+
return $crl;
|
2987 |
+
}
|
2988 |
+
|
2989 |
+
$asn1 = new File_ASN1();
|
2990 |
+
|
2991 |
+
$crl = $this->_extractBER($crl);
|
2992 |
+
$orig = $crl;
|
2993 |
+
|
2994 |
+
if ($crl === false) {
|
2995 |
+
$this->currentCert = false;
|
2996 |
+
return false;
|
2997 |
+
}
|
2998 |
+
|
2999 |
+
$asn1->loadOIDs($this->oids);
|
3000 |
+
$decoded = $asn1->decodeBER($crl);
|
3001 |
+
|
3002 |
+
if (empty($decoded)) {
|
3003 |
+
$this->currentCert = false;
|
3004 |
+
return false;
|
3005 |
+
}
|
3006 |
+
|
3007 |
+
$crl = $asn1->asn1map($decoded[0], $this->CertificateList);
|
3008 |
+
if (!isset($crl) || $crl === false) {
|
3009 |
+
$this->currentCert = false;
|
3010 |
+
return false;
|
3011 |
+
}
|
3012 |
+
|
3013 |
+
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
|
3014 |
+
|
3015 |
+
$this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
|
3016 |
+
$rclist = &$this->_subArray($crl,'tbsCertList/revokedCertificates');
|
3017 |
+
if (is_array($rclist)) {
|
3018 |
+
foreach ($rclist as $i => $extension) {
|
3019 |
+
$this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1);
|
3020 |
+
}
|
3021 |
+
}
|
3022 |
+
|
3023 |
+
$this->currentKeyIdentifier = NULL;
|
3024 |
+
$this->currentCert = $crl;
|
3025 |
+
|
3026 |
+
return $crl;
|
3027 |
+
}
|
3028 |
+
|
3029 |
+
/**
|
3030 |
+
* Save Certificate Revocation List.
|
3031 |
+
*
|
3032 |
+
* @param Array $crl
|
3033 |
+
* @param Integer $format optional
|
3034 |
+
* @access public
|
3035 |
+
* @return String
|
3036 |
+
*/
|
3037 |
+
function saveCRL($crl, $format = FILE_X509_FORMAT_PEM)
|
3038 |
+
{
|
3039 |
+
if (!is_array($crl) || !isset($crl['tbsCertList'])) {
|
3040 |
+
return false;
|
3041 |
+
}
|
3042 |
+
|
3043 |
+
$asn1 = new File_ASN1();
|
3044 |
+
|
3045 |
+
$asn1->loadOIDs($this->oids);
|
3046 |
+
|
3047 |
+
$filters = array();
|
3048 |
+
$filters['tbsCertList']['issuer']['rdnSequence']['value'] =
|
3049 |
+
$filters['tbsCertList']['signature']['parameters'] =
|
3050 |
+
$filters['signatureAlgorithm']['parameters'] =
|
3051 |
+
array('type' => FILE_ASN1_TYPE_UTF8_STRING);
|
3052 |
+
|
3053 |
+
if (empty($crl['tbsCertList']['signature']['parameters'])) {
|
3054 |
+
$filters['tbsCertList']['signature']['parameters'] =
|
3055 |
+
array('type' => FILE_ASN1_TYPE_NULL);
|
3056 |
+
}
|
3057 |
+
|
3058 |
+
if (empty($crl['signatureAlgorithm']['parameters'])) {
|
3059 |
+
$filters['signatureAlgorithm']['parameters'] =
|
3060 |
+
array('type' => FILE_ASN1_TYPE_NULL);
|
3061 |
+
}
|
3062 |
+
|
3063 |
+
$asn1->loadFilters($filters);
|
3064 |
+
|
3065 |
+
$this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
|
3066 |
+
$rclist = &$this->_subArray($crl,'tbsCertList/revokedCertificates');
|
3067 |
+
if (is_array($rclist)) {
|
3068 |
+
foreach ($rclist as $i => $extension) {
|
3069 |
+
$this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
|
3070 |
+
}
|
3071 |
+
}
|
3072 |
+
|
3073 |
+
$crl = $asn1->encodeDER($crl, $this->CertificateList);
|
3074 |
+
|
3075 |
+
switch ($format) {
|
3076 |
+
case FILE_X509_FORMAT_DER:
|
3077 |
+
return $crl;
|
3078 |
+
// case FILE_X509_FORMAT_PEM:
|
3079 |
+
default:
|
3080 |
+
return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
|
3081 |
+
}
|
3082 |
+
}
|
3083 |
+
|
3084 |
+
/**
|
3085 |
+
* Sign an X.509 certificate
|
3086 |
+
*
|
3087 |
+
* $issuer's private key needs to be loaded.
|
3088 |
+
* $subject can be either an existing X.509 cert (if you want to resign it),
|
3089 |
+
* a CSR or something with the DN and public key explicitly set.
|
3090 |
+
*
|
3091 |
+
* @param File_X509 $issuer
|
3092 |
+
* @param File_X509 $subject
|
3093 |
+
* @param String $signatureAlgorithm optional
|
3094 |
+
* @access public
|
3095 |
+
* @return Mixed
|
3096 |
+
*/
|
3097 |
+
function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
|
3098 |
+
{
|
3099 |
+
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
|
3100 |
+
return false;
|
3101 |
+
}
|
3102 |
+
|
3103 |
+
if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
|
3104 |
+
return false;
|
3105 |
+
}
|
3106 |
+
|
3107 |
+
$currentCert = isset($this->currentCert) ? $this->currentCert : NULL;
|
3108 |
+
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: NULL;
|
3109 |
+
|
3110 |
+
if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
|
3111 |
+
$this->currentCert = $subject->currentCert;
|
3112 |
+
$this->currentCert['tbsCertificate']['signature']['algorithm'] =
|
3113 |
+
$this->currentCert['signatureAlgorithm']['algorithm'] =
|
3114 |
+
$signatureAlgorithm;
|
3115 |
+
if (!empty($this->startDate)) {
|
3116 |
+
$this->currentCert['tbsCertificate']['validity']['notBefore']['generalTime'] = $this->startDate;
|
3117 |
+
unset($this->currentCert['tbsCertificate']['validity']['notBefore']['utcTime']);
|
3118 |
+
}
|
3119 |
+
if (!empty($this->endDate)) {
|
3120 |
+
$this->currentCert['tbsCertificate']['validity']['notAfter']['generalTime'] = $this->endDate;
|
3121 |
+
unset($this->currentCert['tbsCertificate']['validity']['notAfter']['utcTime']);
|
3122 |
+
}
|
3123 |
+
if (!empty($this->serialNumber)) {
|
3124 |
+
$this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
|
3125 |
+
}
|
3126 |
+
if (!empty($subject->dn)) {
|
3127 |
+
$this->currentCert['tbsCertificate']['subject'] = $subject->dn;
|
3128 |
+
}
|
3129 |
+
if (!empty($subject->publicKey)) {
|
3130 |
+
$this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
|
3131 |
+
}
|
3132 |
+
$this->removeExtension('id-ce-authorityKeyIdentifier');
|
3133 |
+
if (isset($subject->domains)) {
|
3134 |
+
$this->removeExtension('id-ce-subjectAltName');
|
3135 |
+
}
|
3136 |
+
} else if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
|
3137 |
+
return false;
|
3138 |
+
} else {
|
3139 |
+
if (!isset($subject->publicKey)) {
|
3140 |
+
return false;
|
3141 |
+
}
|
3142 |
+
|
3143 |
+
$startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M y H:i:s O');
|
3144 |
+
$endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M y H:i:s O', strtotime('+1 year'));
|
3145 |
+
$serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new Math_BigInteger();
|
3146 |
+
|
3147 |
+
$this->currentCert = array(
|
3148 |
+
'tbsCertificate' =>
|
3149 |
+
array(
|
3150 |
+
'version' => 'v3',
|
3151 |
+
'serialNumber' => $serialNumber, // $this->setserialNumber()
|
3152 |
+
'signature' => array('algorithm' => $signatureAlgorithm),
|
3153 |
+
'issuer' => false, // this is going to be overwritten later
|
3154 |
+
'validity' => array(
|
3155 |
+
'notBefore' => array('generalTime' => $startDate), // $this->setStartDate()
|
3156 |
+
'notAfter' => array('generalTime' => $endDate) // $this->setEndDate()
|
3157 |
+
),
|
3158 |
+
'subject' => $subject->dn,
|
3159 |
+
'subjectPublicKeyInfo' => $subjectPublicKey
|
3160 |
+
),
|
3161 |
+
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
|
3162 |
+
'signature' => false // this is going to be overwritten later
|
3163 |
+
);
|
3164 |
+
|
3165 |
+
// Copy extensions from CSR.
|
3166 |
+
$csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
|
3167 |
+
|
3168 |
+
if (!empty($csrexts)) {
|
3169 |
+
$this->currentCert['tbsCertificate']['extensions'] = $csrexts;
|
3170 |
+
}
|
3171 |
+
}
|
3172 |
+
|
3173 |
+
$this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
|
3174 |
+
|
3175 |
+
if (isset($issuer->currentKeyIdentifier)) {
|
3176 |
+
$this->setExtension('id-ce-authorityKeyIdentifier', array(
|
3177 |
+
//'authorityCertIssuer' => array(
|
3178 |
+
// array(
|
3179 |
+
// 'directoryName' => $issuer->dn
|
3180 |
+
// )
|
3181 |
+
//),
|
3182 |
+
'keyIdentifier' => $issuer->currentKeyIdentifier
|
3183 |
+
)
|
3184 |
+
);
|
3185 |
+
//$extensions = &$this->currentCert['tbsCertificate']['extensions'];
|
3186 |
+
//if (isset($issuer->serialNumber)) {
|
3187 |
+
// $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
|
3188 |
+
//}
|
3189 |
+
//unset($extensions);
|
3190 |
+
}
|
3191 |
+
|
3192 |
+
if (isset($subject->currentKeyIdentifier)) {
|
3193 |
+
$this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
|
3194 |
+
}
|
3195 |
+
|
3196 |
+
if (isset($subject->domains) && count($subject->domains) > 1) {
|
3197 |
+
$this->setExtension('id-ce-subjectAltName',
|
3198 |
+
array_map(array('File_X509', '_dnsName'), $subject->domains));
|
3199 |
+
}
|
3200 |
+
|
3201 |
+
if ($this->caFlag) {
|
3202 |
+
$keyUsage = $this->getExtension('id-ce-keyUsage');
|
3203 |
+
if (!$keyUsage) {
|
3204 |
+
$keyUsage = array();
|
3205 |
+
}
|
3206 |
+
|
3207 |
+
$this->setExtension('id-ce-keyUsage',
|
3208 |
+
array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
|
3209 |
+
);
|
3210 |
+
|
3211 |
+
$basicConstraints = $this->getExtension('id-ce-basicConstraints');
|
3212 |
+
if (!$basicConstraints) {
|
3213 |
+
$basicConstraints = array();
|
3214 |
+
}
|
3215 |
+
|
3216 |
+
$this->setExtension('id-ce-basicConstraints',
|
3217 |
+
array_unique(array_merge(array('cA' => true), $basicConstraints)), true);
|
3218 |
+
|
3219 |
+
if (!isset($subject->currentKeyIdentifier)) {
|
3220 |
+
$this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
|
3221 |
+
}
|
3222 |
+
}
|
3223 |
+
|
3224 |
+
// resync $this->signatureSubject
|
3225 |
+
// save $tbsCertificate in case there are any File_ASN1_Element objects in it
|
3226 |
+
$tbsCertificate = $this->currentCert['tbsCertificate'];
|
3227 |
+
$this->loadX509($this->saveX509($this->currentCert));
|
3228 |
+
|
3229 |
+
$result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
|
3230 |
+
$result['tbsCertificate'] = $tbsCertificate;
|
3231 |
+
|
3232 |
+
$this->currentCert = $currentCert;
|
3233 |
+
$this->signatureSubject = $signatureSubject;
|
3234 |
+
|
3235 |
+
return $result;
|
3236 |
+
}
|
3237 |
+
|
3238 |
+
/**
|
3239 |
+
* Sign a CSR
|
3240 |
+
*
|
3241 |
+
* @access public
|
3242 |
+
* @return Mixed
|
3243 |
+
*/
|
3244 |
+
function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
|
3245 |
+
{
|
3246 |
+
if (!is_object($this->privateKey) || empty($this->dn)) {
|
3247 |
+
return false;
|
3248 |
+
}
|
3249 |
+
|
3250 |
+
$origPublicKey = $this->publicKey;
|
3251 |
+
$class = get_class($this->privateKey);
|
3252 |
+
$this->publicKey = new $class();
|
3253 |
+
$this->publicKey->loadKey($this->privateKey->getPublicKey());
|
3254 |
+
$this->publicKey->setPublicKey();
|
3255 |
+
if (!($publicKey = $this->_formatSubjectPublicKey())) {
|
3256 |
+
return false;
|
3257 |
+
}
|
3258 |
+
$this->publicKey = $origPublicKey;
|
3259 |
+
|
3260 |
+
$currentCert = isset($this->currentCert) ? $this->currentCert : NULL;
|
3261 |
+
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: NULL;
|
3262 |
+
|
3263 |
+
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
|
3264 |
+
$this->currentCert['signatureAlgorithm']['algorithm'] =
|
3265 |
+
$signatureAlgorithm;
|
3266 |
+
if (!empty($this->dn)) {
|
3267 |
+
$this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
|
3268 |
+
}
|
3269 |
+
$this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
|
3270 |
+
} else {
|
3271 |
+
$this->currentCert = array(
|
3272 |
+
'certificationRequestInfo' =>
|
3273 |
+
array(
|
3274 |
+
'version' => 'v1',
|
3275 |
+
'subject' => $this->dn,
|
3276 |
+
'subjectPKInfo' => $publicKey
|
3277 |
+
),
|
3278 |
+
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
|
3279 |
+
'signature' => false // this is going to be overwritten later
|
3280 |
+
);
|
3281 |
+
}
|
3282 |
+
|
3283 |
+
// resync $this->signatureSubject
|
3284 |
+
// save $certificationRequestInfo in case there are any File_ASN1_Element objects in it
|
3285 |
+
$certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
|
3286 |
+
$this->loadCSR($this->saveCSR($this->currentCert));
|
3287 |
+
|
3288 |
+
$result = $this->_sign($this->privateKey, $signatureAlgorithm);
|
3289 |
+
$result['certificationRequestInfo'] = $certificationRequestInfo;
|
3290 |
+
|
3291 |
+
$this->currentCert = $currentCert;
|
3292 |
+
$this->signatureSubject = $signatureSubject;
|
3293 |
+
|
3294 |
+
return $result;
|
3295 |
+
}
|
3296 |
+
|
3297 |
+
/**
|
3298 |
+
* Sign a CRL
|
3299 |
+
*
|
3300 |
+
* $issuer's private key needs to be loaded.
|
3301 |
+
*
|
3302 |
+
* @param File_X509 $issuer
|
3303 |
+
* @param File_X509 $crl
|
3304 |
+
* @param String $signatureAlgorithm optional
|
3305 |
+
* @access public
|
3306 |
+
* @return Mixed
|
3307 |
+
*/
|
3308 |
+
function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
|
3309 |
+
{
|
3310 |
+
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
|
3311 |
+
return false;
|
3312 |
+
}
|
3313 |
+
|
3314 |
+
$currentCert = isset($this->currentCert) ? $this->currentCert : NULL;
|
3315 |
+
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : NULL;
|
3316 |
+
$thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M y H:i:s O');
|
3317 |
+
|
3318 |
+
if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
|
3319 |
+
$this->currentCert = $crl->currentCert;
|
3320 |
+
$this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
|
3321 |
+
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
|
3322 |
+
} else {
|
3323 |
+
$this->currentCert = array(
|
3324 |
+
'tbsCertList' =>
|
3325 |
+
array(
|
3326 |
+
'version' => 'v2',
|
3327 |
+
'signature' => array('algorithm' => $signatureAlgorithm),
|
3328 |
+
'issuer' => false, // this is going to be overwritten later
|
3329 |
+
'thisUpdate' => array('generalTime' => $thisUpdate) // $this->setStartDate()
|
3330 |
+
),
|
3331 |
+
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
|
3332 |
+
'signature' => false // this is going to be overwritten later
|
3333 |
+
);
|
3334 |
+
}
|
3335 |
+
|
3336 |
+
$tbsCertList = &$this->currentCert['tbsCertList'];
|
3337 |
+
$tbsCertList['issuer'] = $issuer->dn;
|
3338 |
+
$tbsCertList['thisUpdate'] = array('generalTime' => $thisUpdate);
|
3339 |
+
|
3340 |
+
if (!empty($this->endDate)) {
|
3341 |
+
$tbsCertList['nextUpdate'] = array('generalTime' => $this->endDate); // $this->setEndDate()
|
3342 |
+
} else {
|
3343 |
+
unset($tbsCertList['nextUpdate']);
|
3344 |
+
}
|
3345 |
+
|
3346 |
+
if (!empty($this->serialNumber)) {
|
3347 |
+
$crlNumber = $this->serialNumber;
|
3348 |
+
}
|
3349 |
+
else {
|
3350 |
+
$crlNumber = $this->getExtension('id-ce-cRLNumber');
|
3351 |
+
$crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : NULL;
|
3352 |
+
}
|
3353 |
+
|
3354 |
+
$this->removeExtension('id-ce-authorityKeyIdentifier');
|
3355 |
+
$this->removeExtension('id-ce-issuerAltName');
|
3356 |
+
|
3357 |
+
// Be sure version >= v2 if some extension found.
|
3358 |
+
$version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
|
3359 |
+
if (!$version) {
|
3360 |
+
if (!empty($tbsCertList['crlExtensions'])) {
|
3361 |
+
$version = 1; // v2.
|
3362 |
+
}
|
3363 |
+
elseif (!empty($tbsCertList['revokedCertificates'])) {
|
3364 |
+
foreach ($tbsCertList['revokedCertificates'] as $cert) {
|
3365 |
+
if (!empty($cert['crlEntryExtensions'])) {
|
3366 |
+
$version = 1; // v2.
|
3367 |
+
}
|
3368 |
+
}
|
3369 |
+
}
|
3370 |
+
|
3371 |
+
if ($version) {
|
3372 |
+
$tbsCertList['version'] = $version;
|
3373 |
+
}
|
3374 |
+
}
|
3375 |
+
|
3376 |
+
// Store additional extensions.
|
3377 |
+
if (!empty($tbsCertList['version'])) { // At least v2.
|
3378 |
+
if (!empty($crlNumber)) {
|
3379 |
+
$this->setExtension('id-ce-cRLNumber', $crlNumber);
|
3380 |
+
}
|
3381 |
+
|
3382 |
+
if (isset($issuer->currentKeyIdentifier)) {
|
3383 |
+
$this->setExtension('id-ce-authorityKeyIdentifier', array(
|
3384 |
+
//'authorityCertIssuer' => array(
|
3385 |
+
// array(
|
3386 |
+
// 'directoryName' => $issuer->dn
|
3387 |
+
// )
|
3388 |
+
//),
|
3389 |
+
'keyIdentifier' => $issuer->currentKeyIdentifier
|
3390 |
+
)
|
3391 |
+
);
|
3392 |
+
//$extensions = &$tbsCertList['crlExtensions'];
|
3393 |
+
//if (isset($issuer->serialNumber)) {
|
3394 |
+
// $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
|
3395 |
+
//}
|
3396 |
+
//unset($extensions);
|
3397 |
+
}
|
3398 |
+
|
3399 |
+
$issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);
|
3400 |
+
|
3401 |
+
if ($issuerAltName !== false) {
|
3402 |
+
$this->setExtension('id-ce-issuerAltName', $issuerAltName);
|
3403 |
+
}
|
3404 |
+
}
|
3405 |
+
|
3406 |
+
if (empty($tbsCertList['revokedCertificates'])) {
|
3407 |
+
unset($tbsCertList['revokedCertificates']);
|
3408 |
+
}
|
3409 |
+
|
3410 |
+
unset($tbsCertList);
|
3411 |
+
|
3412 |
+
// resync $this->signatureSubject
|
3413 |
+
// save $tbsCertList in case there are any File_ASN1_Element objects in it
|
3414 |
+
$tbsCertList = $this->currentCert['tbsCertList'];
|
3415 |
+
$this->loadCRL($this->saveCRL($this->currentCert));
|
3416 |
+
|
3417 |
+
$result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
|
3418 |
+
$result['tbsCertList'] = $tbsCertList;
|
3419 |
+
|
3420 |
+
$this->currentCert = $currentCert;
|
3421 |
+
$this->signatureSubject = $signatureSubject;
|
3422 |
+
|
3423 |
+
return $result;
|
3424 |
+
}
|
3425 |
+
|
3426 |
+
/**
|
3427 |
+
* X.509 certificate signing helper function.
|
3428 |
+
*
|
3429 |
+
* @param Object $key
|
3430 |
+
* @param File_X509 $subject
|
3431 |
+
* @param String $signatureAlgorithm
|
3432 |
+
* @access public
|
3433 |
+
* @return Mixed
|
3434 |
+
*/
|
3435 |
+
function _sign($key, $signatureAlgorithm)
|
3436 |
+
{
|
3437 |
+
switch (strtolower(get_class($key))) {
|
3438 |
+
case 'crypt_rsa':
|
3439 |
+
switch ($signatureAlgorithm) {
|
3440 |
+
case 'md2WithRSAEncryption':
|
3441 |
+
case 'md5WithRSAEncryption':
|
3442 |
+
case 'sha1WithRSAEncryption':
|
3443 |
+
case 'sha224WithRSAEncryption':
|
3444 |
+
case 'sha256WithRSAEncryption':
|
3445 |
+
case 'sha384WithRSAEncryption':
|
3446 |
+
case 'sha512WithRSAEncryption':
|
3447 |
+
$key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
|
3448 |
+
$key->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
3449 |
+
|
3450 |
+
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
|
3451 |
+
return $this->currentCert;
|
3452 |
+
}
|
3453 |
+
default:
|
3454 |
+
return false;
|
3455 |
+
}
|
3456 |
+
}
|
3457 |
+
|
3458 |
+
/**
|
3459 |
+
* Set certificate start date
|
3460 |
+
*
|
3461 |
+
* @param String $date
|
3462 |
+
* @access public
|
3463 |
+
*/
|
3464 |
+
function setStartDate($date)
|
3465 |
+
{
|
3466 |
+
$this->startDate = @date('D, d M y H:i:s O', @strtotime($date));
|
3467 |
+
}
|
3468 |
+
|
3469 |
+
/**
|
3470 |
+
* Set certificate end date
|
3471 |
+
*
|
3472 |
+
* @param String $date
|
3473 |
+
* @access public
|
3474 |
+
*/
|
3475 |
+
function setEndDate($date)
|
3476 |
+
{
|
3477 |
+
/*
|
3478 |
+
To indicate that a certificate has no well-defined expiration date,
|
3479 |
+
the notAfter SHOULD be assigned the GeneralizedTime value of
|
3480 |
+
99991231235959Z.
|
3481 |
+
|
3482 |
+
-- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
|
3483 |
+
*/
|
3484 |
+
if (strtolower($date) == 'lifetime') {
|
3485 |
+
$temp = '99991231235959Z';
|
3486 |
+
$asn1 = new File_ASN1();
|
3487 |
+
$temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
|
3488 |
+
$this->endDate = new File_ASN1_Element($temp);
|
3489 |
+
} else {
|
3490 |
+
$this->endDate = @date('D, d M y H:i:s O', @strtotime($date));
|
3491 |
+
}
|
3492 |
+
}
|
3493 |
+
|
3494 |
+
/**
|
3495 |
+
* Set Serial Number
|
3496 |
+
*
|
3497 |
+
* @param String $serial
|
3498 |
+
* @param $base optional
|
3499 |
+
* @access public
|
3500 |
+
*/
|
3501 |
+
function setSerialNumber($serial, $base = -256)
|
3502 |
+
{
|
3503 |
+
$this->serialNumber = new Math_BigInteger($serial, $base);
|
3504 |
+
}
|
3505 |
+
|
3506 |
+
/**
|
3507 |
+
* Turns the certificate into a certificate authority
|
3508 |
+
*
|
3509 |
+
* @access public
|
3510 |
+
*/
|
3511 |
+
function makeCA()
|
3512 |
+
{
|
3513 |
+
$this->caFlag = true;
|
3514 |
+
}
|
3515 |
+
|
3516 |
+
/**
|
3517 |
+
* Get a reference to a subarray
|
3518 |
+
*
|
3519 |
+
* @param array $root
|
3520 |
+
* @param String $path absolute path with / as component separator
|
3521 |
+
* @param Boolean $create optional
|
3522 |
+
* @access private
|
3523 |
+
* @return array item ref or false
|
3524 |
+
*/
|
3525 |
+
function &_subArray(&$root, $path, $create = false)
|
3526 |
+
{
|
3527 |
+
$false = false;
|
3528 |
+
|
3529 |
+
if (!is_array($root)) {
|
3530 |
+
return $false;
|
3531 |
+
}
|
3532 |
+
|
3533 |
+
foreach (explode('/', $path) as $i) {
|
3534 |
+
if (!is_array($root)) {
|
3535 |
+
return $false;
|
3536 |
+
}
|
3537 |
+
|
3538 |
+
if (!isset($root[$i])) {
|
3539 |
+
if (!$create) {
|
3540 |
+
return $false;
|
3541 |
+
}
|
3542 |
+
|
3543 |
+
$root[$i] = array();
|
3544 |
+
}
|
3545 |
+
|
3546 |
+
$root = &$root[$i];
|
3547 |
+
}
|
3548 |
+
|
3549 |
+
return $root;
|
3550 |
+
}
|
3551 |
+
|
3552 |
+
/**
|
3553 |
+
* Get a reference to an extension subarray
|
3554 |
+
*
|
3555 |
+
* @param array $root
|
3556 |
+
* @param String $path optional absolute path with / as component separator
|
3557 |
+
* @param Boolean $create optional
|
3558 |
+
* @access private
|
3559 |
+
* @return array ref or false
|
3560 |
+
*/
|
3561 |
+
function &_extensions(&$root, $path = NULL, $create = false)
|
3562 |
+
{
|
3563 |
+
if (!isset($root)) {
|
3564 |
+
$root = $this->currentCert;
|
3565 |
+
}
|
3566 |
+
|
3567 |
+
switch (true) {
|
3568 |
+
case !empty($path):
|
3569 |
+
case !is_array($root):
|
3570 |
+
break;
|
3571 |
+
case isset($root['tbsCertificate']):
|
3572 |
+
$path = 'tbsCertificate/extensions';
|
3573 |
+
break;
|
3574 |
+
case isset($root['tbsCertList']):
|
3575 |
+
$path = 'tbsCertList/crlExtensions';
|
3576 |
+
break;
|
3577 |
+
case isset($root['certificationRequestInfo']):
|
3578 |
+
$pth = 'certificationRequestInfo/attributes';
|
3579 |
+
$attributes = &$this->_subArray($root, $pth, $create);
|
3580 |
+
|
3581 |
+
if (is_array($attributes)) {
|
3582 |
+
foreach ($attributes as $key => $value) {
|
3583 |
+
if ($value['type'] == 'pkcs-9-at-extensionRequest') {
|
3584 |
+
$path = "$pth/$key/value/0";
|
3585 |
+
break 2;
|
3586 |
+
}
|
3587 |
+
}
|
3588 |
+
if ($create) {
|
3589 |
+
$key = count($attributes);
|
3590 |
+
$attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
|
3591 |
+
$path = "$pth/$key/value/0";
|
3592 |
+
}
|
3593 |
+
}
|
3594 |
+
break;
|
3595 |
+
}
|
3596 |
+
|
3597 |
+
$extensions = &$this->_subArray($root, $path, $create);
|
3598 |
+
|
3599 |
+
if (!is_array($extensions)) {
|
3600 |
+
$false = false;
|
3601 |
+
return $false;
|
3602 |
+
}
|
3603 |
+
|
3604 |
+
return $extensions;
|
3605 |
+
}
|
3606 |
+
|
3607 |
+
/**
|
3608 |
+
* Remove an Extension
|
3609 |
+
*
|
3610 |
+
* @param String $id
|
3611 |
+
* @param String $path optional
|
3612 |
+
* @access private
|
3613 |
+
* @return Boolean
|
3614 |
+
*/
|
3615 |
+
function _removeExtension($id, $path = NULL)
|
3616 |
+
{
|
3617 |
+
$extensions = &$this->_extensions($this->currentCert, $path);
|
3618 |
+
|
3619 |
+
if (!is_array($extensions)) {
|
3620 |
+
return false;
|
3621 |
+
}
|
3622 |
+
|
3623 |
+
$result = false;
|
3624 |
+
foreach ($extensions as $key => $value) {
|
3625 |
+
if ($value['extnId'] == $id) {
|
3626 |
+
unset($extensions[$key]);
|
3627 |
+
$result = true;
|
3628 |
+
}
|
3629 |
+
}
|
3630 |
+
|
3631 |
+
$extensions = array_values($extensions);
|
3632 |
+
return $result;
|
3633 |
+
}
|
3634 |
+
|
3635 |
+
/**
|
3636 |
+
* Get an Extension
|
3637 |
+
*
|
3638 |
+
* Returns the extension if it exists and false if not
|
3639 |
+
*
|
3640 |
+
* @param String $id
|
3641 |
+
* @param Array $cert optional
|
3642 |
+
* @param String $path optional
|
3643 |
+
* @access private
|
3644 |
+
* @return Mixed
|
3645 |
+
*/
|
3646 |
+
function _getExtension($id, $cert = NULL, $path = NULL)
|
3647 |
+
{
|
3648 |
+
$extensions = $this->_extensions($cert, $path);
|
3649 |
+
|
3650 |
+
if (!is_array($extensions)) {
|
3651 |
+
return false;
|
3652 |
+
}
|
3653 |
+
|
3654 |
+
foreach ($extensions as $key => $value) {
|
3655 |
+
if ($value['extnId'] == $id) {
|
3656 |
+
return $value['extnValue'];
|
3657 |
+
}
|
3658 |
+
}
|
3659 |
+
|
3660 |
+
return false;
|
3661 |
+
}
|
3662 |
+
|
3663 |
+
/**
|
3664 |
+
* Returns a list of all extensions in use
|
3665 |
+
*
|
3666 |
+
* @param array $cert optional
|
3667 |
+
* @param String $path optional
|
3668 |
+
* @access private
|
3669 |
+
* @return Array
|
3670 |
+
*/
|
3671 |
+
function _getExtensions($cert = NULL, $path = NULL)
|
3672 |
+
{
|
3673 |
+
$exts = $this->_extensions($cert, $path);
|
3674 |
+
$extensions = array();
|
3675 |
+
|
3676 |
+
if (is_array($exts)) {
|
3677 |
+
foreach ($exts as $extension) {
|
3678 |
+
$extensions[] = $extension['extnId'];
|
3679 |
+
}
|
3680 |
+
}
|
3681 |
+
|
3682 |
+
return $extensions;
|
3683 |
+
}
|
3684 |
+
|
3685 |
+
/**
|
3686 |
+
* Set an Extension
|
3687 |
+
*
|
3688 |
+
* @param String $id
|
3689 |
+
* @param Mixed $value
|
3690 |
+
* @param Boolean $critical optional
|
3691 |
+
* @param Boolean $replace optional
|
3692 |
+
* @param String $path optional
|
3693 |
+
* @access private
|
3694 |
+
* @return Boolean
|
3695 |
+
*/
|
3696 |
+
function _setExtension($id, $value, $critical = false, $replace = true, $path = NULL)
|
3697 |
+
{
|
3698 |
+
$extensions = &$this->_extensions($this->currentCert, $path, true);
|
3699 |
+
|
3700 |
+
if (!is_array($extensions)) {
|
3701 |
+
return false;
|
3702 |
+
}
|
3703 |
+
|
3704 |
+
$newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);
|
3705 |
+
|
3706 |
+
foreach ($extensions as $key => $value) {
|
3707 |
+
if ($value['extnId'] == $id) {
|
3708 |
+
if (!$replace) {
|
3709 |
+
return false;
|
3710 |
+
}
|
3711 |
+
|
3712 |
+
$extensions[$key] = $newext;
|
3713 |
+
return true;
|
3714 |
+
}
|
3715 |
+
}
|
3716 |
+
|
3717 |
+
$extensions[] = $newext;
|
3718 |
+
return true;
|
3719 |
+
}
|
3720 |
+
|
3721 |
+
/**
|
3722 |
+
* Remove a certificate, CSR or CRL Extension
|
3723 |
+
*
|
3724 |
+
* @param String $id
|
3725 |
+
* @access public
|
3726 |
+
* @return Boolean
|
3727 |
+
*/
|
3728 |
+
function removeExtension($id)
|
3729 |
+
{
|
3730 |
+
return $this->_removeExtension($id);
|
3731 |
+
}
|
3732 |
+
|
3733 |
+
/**
|
3734 |
+
* Get a certificate, CSR or CRL Extension
|
3735 |
+
*
|
3736 |
+
* Returns the extension if it exists and false if not
|
3737 |
+
*
|
3738 |
+
* @param String $id
|
3739 |
+
* @param Array $cert optional
|
3740 |
+
* @access public
|
3741 |
+
* @return Mixed
|
3742 |
+
*/
|
3743 |
+
function getExtension($id, $cert = NULL)
|
3744 |
+
{
|
3745 |
+
return $this->_getExtension($id, $cert);
|
3746 |
+
}
|
3747 |
+
|
3748 |
+
/**
|
3749 |
+
* Returns a list of all extensions in use in certificate, CSR or CRL
|
3750 |
+
*
|
3751 |
+
* @param array $cert optional
|
3752 |
+
* @access public
|
3753 |
+
* @return Array
|
3754 |
+
*/
|
3755 |
+
function getExtensions($cert = NULL)
|
3756 |
+
{
|
3757 |
+
return $this->_getExtensions($cert);
|
3758 |
+
}
|
3759 |
+
|
3760 |
+
/**
|
3761 |
+
* Set a certificate, CSR or CRL Extension
|
3762 |
+
*
|
3763 |
+
* @param String $id
|
3764 |
+
* @param Mixed $value
|
3765 |
+
* @param Boolean $critical optional
|
3766 |
+
* @param Boolean $replace optional
|
3767 |
+
* @access public
|
3768 |
+
* @return Boolean
|
3769 |
+
*/
|
3770 |
+
function setExtension($id, $value, $critical = false, $replace = true)
|
3771 |
+
{
|
3772 |
+
return $this->_setExtension($id, $value, $critical, $replace);
|
3773 |
+
}
|
3774 |
+
|
3775 |
+
/**
|
3776 |
+
* Remove a CSR attribute.
|
3777 |
+
*
|
3778 |
+
* @param String $id
|
3779 |
+
* @param Integer $disposition optional
|
3780 |
+
* @access public
|
3781 |
+
* @return Boolean
|
3782 |
+
*/
|
3783 |
+
function removeAttribute($id, $disposition = FILE_X509_ATTR_ALL)
|
3784 |
+
{
|
3785 |
+
$attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');
|
3786 |
+
|
3787 |
+
if (!is_array($attributes)) {
|
3788 |
+
return false;
|
3789 |
+
}
|
3790 |
+
|
3791 |
+
$result = false;
|
3792 |
+
foreach ($attributes as $key => $attribute) {
|
3793 |
+
if ($attribute['type'] == $id) {
|
3794 |
+
$n = count($attribute['value']);
|
3795 |
+
switch (true) {
|
3796 |
+
case $disposition == FILE_X509_ATTR_APPEND:
|
3797 |
+
case $disposition == FILE_X509_ATTR_REPLACE:
|
3798 |
+
return false;
|
3799 |
+
case $disposition >= $n:
|
3800 |
+
$disposition -= $n;
|
3801 |
+
break;
|
3802 |
+
case $disposition == FILE_X509_ATTR_ALL:
|
3803 |
+
case $n == 1:
|
3804 |
+
unset($attributes[$key]);
|
3805 |
+
$result = true;
|
3806 |
+
break;
|
3807 |
+
default:
|
3808 |
+
unset($attributes[$key]['value'][$disposition]);
|
3809 |
+
$attributes[$key]['value'] = array_values($attributes[$key]['value']);
|
3810 |
+
$result = true;
|
3811 |
+
break;
|
3812 |
+
}
|
3813 |
+
if ($result && $disposition != FILE_X509_ATTR_ALL) {
|
3814 |
+
break;
|
3815 |
+
}
|
3816 |
+
}
|
3817 |
+
}
|
3818 |
+
|
3819 |
+
$attributes = array_values($attributes);
|
3820 |
+
return $result;
|
3821 |
+
}
|
3822 |
+
|
3823 |
+
/**
|
3824 |
+
* Get a CSR attribute
|
3825 |
+
*
|
3826 |
+
* Returns the attribute if it exists and false if not
|
3827 |
+
*
|
3828 |
+
* @param String $id
|
3829 |
+
* @param Integer $disposition optional
|
3830 |
+
* @param Array $csr optional
|
3831 |
+
* @access public
|
3832 |
+
* @return Mixed
|
3833 |
+
*/
|
3834 |
+
function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = NULL)
|
3835 |
+
{
|
3836 |
+
if (empty($csr)) {
|
3837 |
+
$csr = $this->currentCert;
|
3838 |
+
}
|
3839 |
+
|
3840 |
+
$attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
|
3841 |
+
|
3842 |
+
if (!is_array($attributes)) {
|
3843 |
+
return false;
|
3844 |
+
}
|
3845 |
+
|
3846 |
+
foreach ($attributes as $key => $attribute) {
|
3847 |
+
if ($attribute['type'] == $id) {
|
3848 |
+
$n = count($attribute['value']);
|
3849 |
+
switch (true) {
|
3850 |
+
case $disposition == FILE_X509_ATTR_APPEND:
|
3851 |
+
case $disposition == FILE_X509_ATTR_REPLACE:
|
3852 |
+
return false;
|
3853 |
+
case $disposition == FILE_X509_ATTR_ALL:
|
3854 |
+
return $attribute['value'];
|
3855 |
+
case $disposition >= $n:
|
3856 |
+
$disposition -= $n;
|
3857 |
+
break;
|
3858 |
+
default:
|
3859 |
+
return $attribute['value'][$disposition];
|
3860 |
+
}
|
3861 |
+
}
|
3862 |
+
}
|
3863 |
+
|
3864 |
+
return false;
|
3865 |
+
}
|
3866 |
+
|
3867 |
+
/**
|
3868 |
+
* Returns a list of all CSR attributes in use
|
3869 |
+
*
|
3870 |
+
* @param array $csr optional
|
3871 |
+
* @access public
|
3872 |
+
* @return Array
|
3873 |
+
*/
|
3874 |
+
function getAttributes($csr = NULL)
|
3875 |
+
{
|
3876 |
+
if (empty($csr)) {
|
3877 |
+
$csr = $this->currentCert;
|
3878 |
+
}
|
3879 |
+
|
3880 |
+
$attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
|
3881 |
+
$attrs = array();
|
3882 |
+
|
3883 |
+
if (is_array($attributes)) {
|
3884 |
+
foreach ($attributes as $attribute) {
|
3885 |
+
$attrs[] = $attribute['type'];
|
3886 |
+
}
|
3887 |
+
}
|
3888 |
+
|
3889 |
+
return $attrs;
|
3890 |
+
}
|
3891 |
+
|
3892 |
+
/**
|
3893 |
+
* Set a CSR attribute
|
3894 |
+
*
|
3895 |
+
* @param String $id
|
3896 |
+
* @param Mixed $value
|
3897 |
+
* @param Boolean $disposition optional
|
3898 |
+
* @access public
|
3899 |
+
* @return Boolean
|
3900 |
+
*/
|
3901 |
+
function setAttribute($id, $value, $disposition = FILE_X509_ATTR_ALL)
|
3902 |
+
{
|
3903 |
+
$attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);
|
3904 |
+
|
3905 |
+
if (!is_array($attributes)) {
|
3906 |
+
return false;
|
3907 |
+
}
|
3908 |
+
|
3909 |
+
switch ($disposition) {
|
3910 |
+
case FILE_X509_ATTR_REPLACE:
|
3911 |
+
$disposition = FILE_X509_ATTR_APPEND;
|
3912 |
+
case FILE_X509_ATTR_ALL:
|
3913 |
+
$this->removeAttribute($id);
|
3914 |
+
break;
|
3915 |
+
}
|
3916 |
+
|
3917 |
+
foreach ($attributes as $key => $attribute) {
|
3918 |
+
if ($attribute['type'] == $id) {
|
3919 |
+
$n = count($attribute['value']);
|
3920 |
+
switch (true) {
|
3921 |
+
case $disposition == FILE_X509_ATTR_APPEND:
|
3922 |
+
$last = $key;
|
3923 |
+
break;
|
3924 |
+
case $disposition >= $n;
|
3925 |
+
$disposition -= $n;
|
3926 |
+
break;
|
3927 |
+
default:
|
3928 |
+
$attributes[$key]['value'][$disposition] = $value;
|
3929 |
+
return true;
|
3930 |
+
}
|
3931 |
+
}
|
3932 |
+
}
|
3933 |
+
|
3934 |
+
switch (true) {
|
3935 |
+
case $disposition >= 0:
|
3936 |
+
return false;
|
3937 |
+
case isset($last):
|
3938 |
+
$attributes[$last]['value'][] = $value;
|
3939 |
+
break;
|
3940 |
+
default:
|
3941 |
+
$attributes[] = array('type' => $id, 'value' => $disposition == FILE_X509_ATTR_ALL ? $value: array($value));
|
3942 |
+
break;
|
3943 |
+
}
|
3944 |
+
|
3945 |
+
return true;
|
3946 |
+
}
|
3947 |
+
|
3948 |
+
/**
|
3949 |
+
* Sets the subject key identifier
|
3950 |
+
*
|
3951 |
+
* This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions.
|
3952 |
+
*
|
3953 |
+
* @param String $value
|
3954 |
+
* @access public
|
3955 |
+
*/
|
3956 |
+
function setKeyIdentifier($value)
|
3957 |
+
{
|
3958 |
+
if (empty($value)) {
|
3959 |
+
unset($this->currentKeyIdentifier);
|
3960 |
+
} else {
|
3961 |
+
$this->currentKeyIdentifier = base64_encode($value);
|
3962 |
+
}
|
3963 |
+
}
|
3964 |
+
|
3965 |
+
/**
|
3966 |
+
* Compute a public key identifier.
|
3967 |
+
*
|
3968 |
+
* Although key identifiers may be set to any unique value, this function
|
3969 |
+
* computes key identifiers from public key according to the two
|
3970 |
+
* recommended methods (4.2.1.2 RFC 3280).
|
3971 |
+
* Highly polymorphic: try to accept all possible forms of key:
|
3972 |
+
* - Key object
|
3973 |
+
* - File_X509 object with public or private key defined
|
3974 |
+
* - Certificate or CSR array
|
3975 |
+
* - File_ASN1_Element object
|
3976 |
+
* - PEM or DER string
|
3977 |
+
*
|
3978 |
+
* @param Mixed $key optional
|
3979 |
+
* @param Integer $method optional
|
3980 |
+
* @access public
|
3981 |
+
* @return String binary key identifier
|
3982 |
+
*/
|
3983 |
+
function computeKeyIdentifier($key = NULL, $method = 1)
|
3984 |
+
{
|
3985 |
+
if (is_null($key)) {
|
3986 |
+
$key = $this;
|
3987 |
+
}
|
3988 |
+
|
3989 |
+
switch (true) {
|
3990 |
+
case is_string($key):
|
3991 |
+
break;
|
3992 |
+
case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
|
3993 |
+
return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
|
3994 |
+
case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
|
3995 |
+
return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
|
3996 |
+
case !is_object($key):
|
3997 |
+
return false;
|
3998 |
+
case strtolower(get_class($key)) == 'file_asn1_element':
|
3999 |
+
// Assume the element is a bitstring-packed key.
|
4000 |
+
$asn1 = new File_ASN1();
|
4001 |
+
$decoded = $asn1->decodeBER($key->element);
|
4002 |
+
if (empty($decoded)) {
|
4003 |
+
return false;
|
4004 |
+
}
|
4005 |
+
$raw = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING));
|
4006 |
+
if (empty($raw)) {
|
4007 |
+
return false;
|
4008 |
+
}
|
4009 |
+
$raw = base64_decode($raw);
|
4010 |
+
// If the key is private, compute identifier from its corresponding public key.
|
4011 |
+
if (!class_exists('Crypt_RSA')) {
|
4012 |
+
require_once('Crypt/RSA.php');
|
4013 |
+
}
|
4014 |
+
$key = new Crypt_RSA();
|
4015 |
+
if (!$key->loadKey($raw)) {
|
4016 |
+
return false; // Not an unencrypted RSA key.
|
4017 |
+
}
|
4018 |
+
if ($key->getPrivateKey() !== false) { // If private.
|
4019 |
+
return $this->computeKeyIdentifier($key, $method);
|
4020 |
+
}
|
4021 |
+
$key = $raw; // Is a public key.
|
4022 |
+
break;
|
4023 |
+
case strtolower(get_class($key)) == 'file_x509':
|
4024 |
+
if (isset($key->publicKey)) {
|
4025 |
+
return $this->computeKeyIdentifier($key->publicKey, $method);
|
4026 |
+
}
|
4027 |
+
if (isset($key->privateKey)) {
|
4028 |
+
return $this->computeKeyIdentifier($key->privateKey, $method);
|
4029 |
+
}
|
4030 |
+
if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
|
4031 |
+
return $this->computeKeyIdentifier($key->currentCert, $method);
|
4032 |
+
}
|
4033 |
+
return false;
|
4034 |
+
default: // Should be a key object (i.e.: Crypt_RSA).
|
4035 |
+
$key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW);
|
4036 |
+
break;
|
4037 |
+
}
|
4038 |
+
|
4039 |
+
// If in PEM format, convert to binary.
|
4040 |
+
if (preg_match('#^-----BEGIN #', $key)) {
|
4041 |
+
$key = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $key));
|
4042 |
+
}
|
4043 |
+
|
4044 |
+
// Now we have the key string: compute its sha-1 sum.
|
4045 |
+
if (!class_exists('Crypt_Hash')) {
|
4046 |
+
require_once('Crypt/Hash.php');
|
4047 |
+
}
|
4048 |
+
$hash = new Crypt_Hash('sha1');
|
4049 |
+
$hash = $hash->hash($key);
|
4050 |
+
|
4051 |
+
if ($method == 2) {
|
4052 |
+
$hash = substr($hash, -8);
|
4053 |
+
$hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
|
4054 |
+
}
|
4055 |
+
|
4056 |
+
return $hash;
|
4057 |
+
}
|
4058 |
+
|
4059 |
+
/**
|
4060 |
+
* Format a public key as appropriate
|
4061 |
+
*
|
4062 |
+
* @access private
|
4063 |
+
* @return Array
|
4064 |
+
*/
|
4065 |
+
function _formatSubjectPublicKey()
|
4066 |
+
{
|
4067 |
+
if (!isset($this->publicKey) || !is_object($this->publicKey)) {
|
4068 |
+
return false;
|
4069 |
+
}
|
4070 |
+
|
4071 |
+
switch (strtolower(get_class($this->publicKey))) {
|
4072 |
+
case 'crypt_rsa':
|
4073 |
+
// the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
|
4074 |
+
// the former is a good example of how to do fuzzing on the public key
|
4075 |
+
//return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
|
4076 |
+
return array(
|
4077 |
+
'algorithm' => array('algorithm' => 'rsaEncryption'),
|
4078 |
+
'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW)
|
4079 |
+
);
|
4080 |
+
default:
|
4081 |
+
return false;
|
4082 |
+
}
|
4083 |
+
}
|
4084 |
+
|
4085 |
+
/**
|
4086 |
+
* Set the domain name's which the cert is to be valid for
|
4087 |
+
*
|
4088 |
+
* @access public
|
4089 |
+
* @return Array
|
4090 |
+
*/
|
4091 |
+
function setDomain()
|
4092 |
+
{
|
4093 |
+
$this->domains = func_get_args();
|
4094 |
+
$this->removeDNProp('id-at-commonName');
|
4095 |
+
$this->setDNProp('id-at-commonName', $this->domains[0]);
|
4096 |
+
}
|
4097 |
+
|
4098 |
+
/**
|
4099 |
+
* Helper function to build domain array
|
4100 |
+
*
|
4101 |
+
* @access private
|
4102 |
+
* @param String $domain
|
4103 |
+
* @return Array
|
4104 |
+
*/
|
4105 |
+
function _dnsName($domain)
|
4106 |
+
{
|
4107 |
+
return array('dNSName' => $domain);
|
4108 |
+
}
|
4109 |
+
|
4110 |
+
/**
|
4111 |
+
* Get the index of a revoked certificate.
|
4112 |
+
*
|
4113 |
+
* @param array $rclist
|
4114 |
+
* @param String $serial
|
4115 |
+
* @param Boolean $create optional
|
4116 |
+
* @access private
|
4117 |
+
* @return Integer or false
|
4118 |
+
*/
|
4119 |
+
function _revokedCertificate(&$rclist, $serial, $create = false)
|
4120 |
+
{
|
4121 |
+
$serial = new Math_BigInteger($serial);
|
4122 |
+
|
4123 |
+
foreach ($rclist as $i => $rc) {
|
4124 |
+
if (!($serial->compare($rc['userCertificate']))) {
|
4125 |
+
return $i;
|
4126 |
+
}
|
4127 |
+
}
|
4128 |
+
|
4129 |
+
if (!$create) {
|
4130 |
+
return false;
|
4131 |
+
}
|
4132 |
+
|
4133 |
+
$i = count($rclist);
|
4134 |
+
$rclist[] = array('userCertificate' => $serial,
|
4135 |
+
'revocationDate' => array('generalTime' => @date('D, d M y H:i:s O')));
|
4136 |
+
return $i;
|
4137 |
+
}
|
4138 |
+
|
4139 |
+
/**
|
4140 |
+
* Revoke a certificate.
|
4141 |
+
*
|
4142 |
+
* @param String $serial
|
4143 |
+
* @param String $date optional
|
4144 |
+
* @access public
|
4145 |
+
* @return Boolean
|
4146 |
+
*/
|
4147 |
+
function revoke($serial, $date = NULL)
|
4148 |
+
{
|
4149 |
+
if (isset($this->currentCert['tbsCertList'])) {
|
4150 |
+
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
|
4151 |
+
if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
|
4152 |
+
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
|
4153 |
+
|
4154 |
+
if (!empty($date)) {
|
4155 |
+
$rclist[$i]['revocationDate'] = array('generalTime' => $date);
|
4156 |
+
}
|
4157 |
+
|
4158 |
+
return true;
|
4159 |
+
}
|
4160 |
+
}
|
4161 |
+
}
|
4162 |
+
}
|
4163 |
+
|
4164 |
+
return false;
|
4165 |
+
}
|
4166 |
+
|
4167 |
+
/**
|
4168 |
+
* Unrevoke a certificate.
|
4169 |
+
*
|
4170 |
+
* @param String $serial
|
4171 |
+
* @access public
|
4172 |
+
* @return Boolean
|
4173 |
+
*/
|
4174 |
+
function unrevoke($serial)
|
4175 |
+
{
|
4176 |
+
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
|
4177 |
+
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
|
4178 |
+
unset($rclist[$i]);
|
4179 |
+
$rclist = array_values($rclist);
|
4180 |
+
return true;
|
4181 |
+
}
|
4182 |
+
}
|
4183 |
+
|
4184 |
+
return false;
|
4185 |
+
}
|
4186 |
+
|
4187 |
+
/**
|
4188 |
+
* Get a revoked certificate.
|
4189 |
+
*
|
4190 |
+
* @param String $serial
|
4191 |
+
* @access public
|
4192 |
+
* @return Mixed
|
4193 |
+
*/
|
4194 |
+
function getRevoked($serial)
|
4195 |
+
{
|
4196 |
+
if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
|
4197 |
+
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
|
4198 |
+
return $rclist[$i];
|
4199 |
+
}
|
4200 |
+
}
|
4201 |
+
|
4202 |
+
return false;
|
4203 |
+
}
|
4204 |
+
|
4205 |
+
/**
|
4206 |
+
* List revoked certificates
|
4207 |
+
*
|
4208 |
+
* @param array $crl optional
|
4209 |
+
* @access public
|
4210 |
+
* @return array
|
4211 |
+
*/
|
4212 |
+
function listRevoked($crl = NULL)
|
4213 |
+
{
|
4214 |
+
if (!isset($crl)) {
|
4215 |
+
$crl = $this->currentCert;
|
4216 |
+
}
|
4217 |
+
|
4218 |
+
if (!isset($crl['tbsCertList'])) {
|
4219 |
+
return false;
|
4220 |
+
}
|
4221 |
+
|
4222 |
+
$result = array();
|
4223 |
+
|
4224 |
+
if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
|
4225 |
+
foreach ($rclist as $rc) {
|
4226 |
+
$result[] = $rc['userCertificate']->toString();
|
4227 |
+
}
|
4228 |
+
}
|
4229 |
+
|
4230 |
+
return $result;
|
4231 |
+
}
|
4232 |
+
|
4233 |
+
/**
|
4234 |
+
* Remove a Revoked Certificate Extension
|
4235 |
+
*
|
4236 |
+
* @param String $serial
|
4237 |
+
* @param String $id
|
4238 |
+
* @access public
|
4239 |
+
* @return Boolean
|
4240 |
+
*/
|
4241 |
+
function removeRevokedCertificateExtension($serial, $id)
|
4242 |
+
{
|
4243 |
+
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
|
4244 |
+
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
|
4245 |
+
return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
|
4246 |
+
}
|
4247 |
+
}
|
4248 |
+
|
4249 |
+
return false;
|
4250 |
+
}
|
4251 |
+
|
4252 |
+
/**
|
4253 |
+
* Get a Revoked Certificate Extension
|
4254 |
+
*
|
4255 |
+
* Returns the extension if it exists and false if not
|
4256 |
+
*
|
4257 |
+
* @param String $serial
|
4258 |
+
* @param String $id
|
4259 |
+
* @param Array $crl optional
|
4260 |
+
* @access public
|
4261 |
+
* @return Mixed
|
4262 |
+
*/
|
4263 |
+
function getRevokedCertificateExtension($serial, $id, $crl = NULL)
|
4264 |
+
{
|
4265 |
+
if (!isset($crl)) {
|
4266 |
+
$crl = $this->currentCert;
|
4267 |
+
}
|
4268 |
+
|
4269 |
+
if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
|
4270 |
+
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
|
4271 |
+
return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
|
4272 |
+
}
|
4273 |
+
}
|
4274 |
+
|
4275 |
+
return false;
|
4276 |
+
}
|
4277 |
+
|
4278 |
+
/**
|
4279 |
+
* Returns a list of all extensions in use for a given revoked certificate
|
4280 |
+
*
|
4281 |
+
* @param String $serial
|
4282 |
+
* @param array $crl optional
|
4283 |
+
* @access public
|
4284 |
+
* @return Array
|
4285 |
+
*/
|
4286 |
+
function getRevokedCertificateExtensions($serial, $crl = NULL)
|
4287 |
+
{
|
4288 |
+
if (!isset($crl)) {
|
4289 |
+
$crl = $this->currentCert;
|
4290 |
+
}
|
4291 |
+
|
4292 |
+
if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
|
4293 |
+
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
|
4294 |
+
return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
|
4295 |
+
}
|
4296 |
+
}
|
4297 |
+
|
4298 |
+
return false;
|
4299 |
+
}
|
4300 |
+
|
4301 |
+
/**
|
4302 |
+
* Set a Revoked Certificate Extension
|
4303 |
+
*
|
4304 |
+
* @param String $serial
|
4305 |
+
* @param String $id
|
4306 |
+
* @param Mixed $value
|
4307 |
+
* @param Boolean $critical optional
|
4308 |
+
* @param Boolean $replace optional
|
4309 |
+
* @access public
|
4310 |
+
* @return Boolean
|
4311 |
+
*/
|
4312 |
+
function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
|
4313 |
+
{
|
4314 |
+
if (isset($this->currentCert['tbsCertList'])) {
|
4315 |
+
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
|
4316 |
+
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
|
4317 |
+
return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
|
4318 |
+
}
|
4319 |
+
}
|
4320 |
+
}
|
4321 |
+
|
4322 |
+
return false;
|
4323 |
+
}
|
4324 |
+
|
4325 |
+
/**
|
4326 |
+
* Extract raw BER from Base64 encoding
|
4327 |
+
*
|
4328 |
+
* @access private
|
4329 |
+
* @param String $str
|
4330 |
+
* @return String
|
4331 |
+
*/
|
4332 |
+
function _extractBER($str)
|
4333 |
+
{
|
4334 |
+
/*
|
4335 |
+
X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them above and beyond the ceritificate. ie.
|
4336 |
+
some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
4337 |
+
|
4338 |
+
Bag Attributes
|
4339 |
+
localKeyID: 01 00 00 00
|
4340 |
+
subject=/O=organization/OU=org unit/CN=common name
|
4341 |
+
issuer=/O=organization/CN=common name
|
4342 |
+
*/
|
4343 |
+
$temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1);
|
4344 |
+
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
4345 |
+
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
4346 |
+
// remove new lines
|
4347 |
+
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
4348 |
+
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
|
4349 |
+
return $temp != false ? $temp : $str;
|
4350 |
+
}
|
4351 |
+
}
|
lib/PHPSecLib/Math/BigInteger.php
ADDED
@@ -0,0 +1,3650 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP arbitrary precision integer arithmetic library.
|
6 |
+
*
|
7 |
+
* Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
|
8 |
+
* and an internal implementation, otherwise.
|
9 |
+
*
|
10 |
+
* PHP versions 4 and 5
|
11 |
+
*
|
12 |
+
* {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
|
13 |
+
* {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
|
14 |
+
*
|
15 |
+
* Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
|
16 |
+
* base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
|
17 |
+
* value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
|
18 |
+
* point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
|
19 |
+
* used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
|
20 |
+
* which only supports integers. Although this fact will slow this library down, the fact that such a high
|
21 |
+
* base is being used should more than compensate.
|
22 |
+
*
|
23 |
+
* When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again,
|
24 |
+
* allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
|
25 |
+
* subtraction).
|
26 |
+
*
|
27 |
+
* Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
|
28 |
+
* (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
|
29 |
+
*
|
30 |
+
* Useful resources are as follows:
|
31 |
+
*
|
32 |
+
* - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
|
33 |
+
* - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
|
34 |
+
* - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
|
35 |
+
*
|
36 |
+
* Here's an example of how to use this library:
|
37 |
+
* <code>
|
38 |
+
* <?php
|
39 |
+
* include('Math/BigInteger.php');
|
40 |
+
*
|
41 |
+
* $a = new Math_BigInteger(2);
|
42 |
+
* $b = new Math_BigInteger(3);
|
43 |
+
*
|
44 |
+
* $c = $a->add($b);
|
45 |
+
*
|
46 |
+
* echo $c->toString(); // outputs 5
|
47 |
+
* ?>
|
48 |
+
* </code>
|
49 |
+
*
|
50 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
51 |
+
* of this software and associated documentation files (the "Software"), to deal
|
52 |
+
* in the Software without restriction, including without limitation the rights
|
53 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
54 |
+
* copies of the Software, and to permit persons to whom the Software is
|
55 |
+
* furnished to do so, subject to the following conditions:
|
56 |
+
*
|
57 |
+
* The above copyright notice and this permission notice shall be included in
|
58 |
+
* all copies or substantial portions of the Software.
|
59 |
+
*
|
60 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
61 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
62 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
63 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
64 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
65 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
66 |
+
* THE SOFTWARE.
|
67 |
+
*
|
68 |
+
* @category Math
|
69 |
+
* @package Math_BigInteger
|
70 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
71 |
+
* @copyright MMVI Jim Wigginton
|
72 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
73 |
+
* @link http://pear.php.net/package/Math_BigInteger
|
74 |
+
*/
|
75 |
+
|
76 |
+
/**#@+
|
77 |
+
* Reduction constants
|
78 |
+
*
|
79 |
+
* @access private
|
80 |
+
* @see Math_BigInteger::_reduce()
|
81 |
+
*/
|
82 |
+
/**
|
83 |
+
* @see Math_BigInteger::_montgomery()
|
84 |
+
* @see Math_BigInteger::_prepMontgomery()
|
85 |
+
*/
|
86 |
+
define('MATH_BIGINTEGER_MONTGOMERY', 0);
|
87 |
+
/**
|
88 |
+
* @see Math_BigInteger::_barrett()
|
89 |
+
*/
|
90 |
+
define('MATH_BIGINTEGER_BARRETT', 1);
|
91 |
+
/**
|
92 |
+
* @see Math_BigInteger::_mod2()
|
93 |
+
*/
|
94 |
+
define('MATH_BIGINTEGER_POWEROF2', 2);
|
95 |
+
/**
|
96 |
+
* @see Math_BigInteger::_remainder()
|
97 |
+
*/
|
98 |
+
define('MATH_BIGINTEGER_CLASSIC', 3);
|
99 |
+
/**
|
100 |
+
* @see Math_BigInteger::__clone()
|
101 |
+
*/
|
102 |
+
define('MATH_BIGINTEGER_NONE', 4);
|
103 |
+
/**#@-*/
|
104 |
+
|
105 |
+
/**#@+
|
106 |
+
* Array constants
|
107 |
+
*
|
108 |
+
* Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
|
109 |
+
* multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
|
110 |
+
*
|
111 |
+
* @access private
|
112 |
+
*/
|
113 |
+
/**
|
114 |
+
* $result[MATH_BIGINTEGER_VALUE] contains the value.
|
115 |
+
*/
|
116 |
+
define('MATH_BIGINTEGER_VALUE', 0);
|
117 |
+
/**
|
118 |
+
* $result[MATH_BIGINTEGER_SIGN] contains the sign.
|
119 |
+
*/
|
120 |
+
define('MATH_BIGINTEGER_SIGN', 1);
|
121 |
+
/**#@-*/
|
122 |
+
|
123 |
+
/**#@+
|
124 |
+
* @access private
|
125 |
+
* @see Math_BigInteger::_montgomery()
|
126 |
+
* @see Math_BigInteger::_barrett()
|
127 |
+
*/
|
128 |
+
/**
|
129 |
+
* Cache constants
|
130 |
+
*
|
131 |
+
* $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
|
132 |
+
*/
|
133 |
+
define('MATH_BIGINTEGER_VARIABLE', 0);
|
134 |
+
/**
|
135 |
+
* $cache[MATH_BIGINTEGER_DATA] contains the cached data.
|
136 |
+
*/
|
137 |
+
define('MATH_BIGINTEGER_DATA', 1);
|
138 |
+
/**#@-*/
|
139 |
+
|
140 |
+
/**#@+
|
141 |
+
* Mode constants.
|
142 |
+
*
|
143 |
+
* @access private
|
144 |
+
* @see Math_BigInteger::Math_BigInteger()
|
145 |
+
*/
|
146 |
+
/**
|
147 |
+
* To use the pure-PHP implementation
|
148 |
+
*/
|
149 |
+
define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
|
150 |
+
/**
|
151 |
+
* To use the BCMath library
|
152 |
+
*
|
153 |
+
* (if enabled; otherwise, the internal implementation will be used)
|
154 |
+
*/
|
155 |
+
define('MATH_BIGINTEGER_MODE_BCMATH', 2);
|
156 |
+
/**
|
157 |
+
* To use the GMP library
|
158 |
+
*
|
159 |
+
* (if present; otherwise, either the BCMath or the internal implementation will be used)
|
160 |
+
*/
|
161 |
+
define('MATH_BIGINTEGER_MODE_GMP', 3);
|
162 |
+
/**#@-*/
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Karatsuba Cutoff
|
166 |
+
*
|
167 |
+
* At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
|
168 |
+
*
|
169 |
+
* @access private
|
170 |
+
*/
|
171 |
+
define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
|
175 |
+
* numbers.
|
176 |
+
*
|
177 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
178 |
+
* @version 1.0.0RC4
|
179 |
+
* @access public
|
180 |
+
* @package Math_BigInteger
|
181 |
+
*/
|
182 |
+
class Math_BigInteger {
|
183 |
+
/**
|
184 |
+
* Holds the BigInteger's value.
|
185 |
+
*
|
186 |
+
* @var Array
|
187 |
+
* @access private
|
188 |
+
*/
|
189 |
+
var $value;
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Holds the BigInteger's magnitude.
|
193 |
+
*
|
194 |
+
* @var Boolean
|
195 |
+
* @access private
|
196 |
+
*/
|
197 |
+
var $is_negative = false;
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Random number generator function
|
201 |
+
*
|
202 |
+
* @see setRandomGenerator()
|
203 |
+
* @access private
|
204 |
+
*/
|
205 |
+
var $generator = 'mt_rand';
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Precision
|
209 |
+
*
|
210 |
+
* @see setPrecision()
|
211 |
+
* @access private
|
212 |
+
*/
|
213 |
+
var $precision = -1;
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Precision Bitmask
|
217 |
+
*
|
218 |
+
* @see setPrecision()
|
219 |
+
* @access private
|
220 |
+
*/
|
221 |
+
var $bitmask = false;
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Mode independent value used for serialization.
|
225 |
+
*
|
226 |
+
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
|
227 |
+
* a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
|
228 |
+
* however, $this->hex is only calculated when $this->__sleep() is called.
|
229 |
+
*
|
230 |
+
* @see __sleep()
|
231 |
+
* @see __wakeup()
|
232 |
+
* @var String
|
233 |
+
* @access private
|
234 |
+
*/
|
235 |
+
var $hex;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
|
239 |
+
*
|
240 |
+
* If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
|
241 |
+
* two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
|
242 |
+
*
|
243 |
+
* Here's an example:
|
244 |
+
* <code>
|
245 |
+
* <?php
|
246 |
+
* include('Math/BigInteger.php');
|
247 |
+
*
|
248 |
+
* $a = new Math_BigInteger('0x32', 16); // 50 in base-16
|
249 |
+
*
|
250 |
+
* echo $a->toString(); // outputs 50
|
251 |
+
* ?>
|
252 |
+
* </code>
|
253 |
+
*
|
254 |
+
* @param optional $x base-10 number or base-$base number if $base set.
|
255 |
+
* @param optional integer $base
|
256 |
+
* @return Math_BigInteger
|
257 |
+
* @access public
|
258 |
+
*/
|
259 |
+
function Math_BigInteger($x = 0, $base = 10)
|
260 |
+
{
|
261 |
+
if ( !defined('MATH_BIGINTEGER_MODE') ) {
|
262 |
+
switch (true) {
|
263 |
+
case extension_loaded('gmp'):
|
264 |
+
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
|
265 |
+
break;
|
266 |
+
case extension_loaded('bcmath'):
|
267 |
+
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
|
268 |
+
break;
|
269 |
+
default:
|
270 |
+
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
|
271 |
+
}
|
272 |
+
}
|
273 |
+
|
274 |
+
if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
275 |
+
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
276 |
+
}
|
277 |
+
|
278 |
+
if (!defined('PHP_INT_SIZE')) {
|
279 |
+
define('PHP_INT_SIZE', 4);
|
280 |
+
}
|
281 |
+
|
282 |
+
if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
|
283 |
+
switch (PHP_INT_SIZE) {
|
284 |
+
case 8: // use 64-bit integers if int size is 8 bytes
|
285 |
+
define('MATH_BIGINTEGER_BASE', 31);
|
286 |
+
define('MATH_BIGINTEGER_BASE_FULL', 0x80000000);
|
287 |
+
define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF);
|
288 |
+
define('MATH_BIGINTEGER_MSB', 0x40000000);
|
289 |
+
// 10**9 is the closest we can get to 2**31 without passing it
|
290 |
+
define('MATH_BIGINTEGER_MAX10', 1000000000);
|
291 |
+
define('MATH_BIGINTEGER_MAX10_LEN', 9);
|
292 |
+
// the largest digit that may be used in addition / subtraction
|
293 |
+
define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
|
294 |
+
break;
|
295 |
+
//case 4: // use 64-bit floats if int size is 4 bytes
|
296 |
+
default:
|
297 |
+
define('MATH_BIGINTEGER_BASE', 26);
|
298 |
+
define('MATH_BIGINTEGER_BASE_FULL', 0x4000000);
|
299 |
+
define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF);
|
300 |
+
define('MATH_BIGINTEGER_MSB', 0x2000000);
|
301 |
+
// 10**7 is the closest to 2**26 without passing it
|
302 |
+
define('MATH_BIGINTEGER_MAX10', 10000000);
|
303 |
+
define('MATH_BIGINTEGER_MAX10_LEN', 7);
|
304 |
+
// the largest digit that may be used in addition / subtraction
|
305 |
+
// we do pow(2, 52) instead of using 4503599627370496 directly because some
|
306 |
+
// PHP installations will truncate 4503599627370496.
|
307 |
+
define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
|
308 |
+
}
|
309 |
+
}
|
310 |
+
|
311 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
312 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
313 |
+
if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
|
314 |
+
$this->value = $x;
|
315 |
+
return;
|
316 |
+
}
|
317 |
+
$this->value = gmp_init(0);
|
318 |
+
break;
|
319 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
320 |
+
$this->value = '0';
|
321 |
+
break;
|
322 |
+
default:
|
323 |
+
$this->value = array();
|
324 |
+
}
|
325 |
+
|
326 |
+
// '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
|
327 |
+
// '0' is the only value like this per http://php.net/empty
|
328 |
+
if (empty($x) && (abs($base) != 256 || $x !== '0')) {
|
329 |
+
return;
|
330 |
+
}
|
331 |
+
|
332 |
+
switch ($base) {
|
333 |
+
case -256:
|
334 |
+
if (ord($x[0]) & 0x80) {
|
335 |
+
$x = ~$x;
|
336 |
+
$this->is_negative = true;
|
337 |
+
}
|
338 |
+
case 256:
|
339 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
340 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
341 |
+
$sign = $this->is_negative ? '-' : '';
|
342 |
+
$this->value = gmp_init($sign . '0x' . bin2hex($x));
|
343 |
+
break;
|
344 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
345 |
+
// round $len to the nearest 4 (thanks, DavidMJ!)
|
346 |
+
$len = (strlen($x) + 3) & 0xFFFFFFFC;
|
347 |
+
|
348 |
+
$x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
|
349 |
+
|
350 |
+
for ($i = 0; $i < $len; $i+= 4) {
|
351 |
+
$this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
|
352 |
+
$this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
|
353 |
+
}
|
354 |
+
|
355 |
+
if ($this->is_negative) {
|
356 |
+
$this->value = '-' . $this->value;
|
357 |
+
}
|
358 |
+
|
359 |
+
break;
|
360 |
+
// converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
|
361 |
+
default:
|
362 |
+
while (strlen($x)) {
|
363 |
+
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
if ($this->is_negative) {
|
368 |
+
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
|
369 |
+
$this->is_negative = false;
|
370 |
+
}
|
371 |
+
$temp = $this->add(new Math_BigInteger('-1'));
|
372 |
+
$this->value = $temp->value;
|
373 |
+
}
|
374 |
+
break;
|
375 |
+
case 16:
|
376 |
+
case -16:
|
377 |
+
if ($base > 0 && $x[0] == '-') {
|
378 |
+
$this->is_negative = true;
|
379 |
+
$x = substr($x, 1);
|
380 |
+
}
|
381 |
+
|
382 |
+
$x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
|
383 |
+
|
384 |
+
$is_negative = false;
|
385 |
+
if ($base < 0 && hexdec($x[0]) >= 8) {
|
386 |
+
$this->is_negative = $is_negative = true;
|
387 |
+
$x = bin2hex(~pack('H*', $x));
|
388 |
+
}
|
389 |
+
|
390 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
391 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
392 |
+
$temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
|
393 |
+
$this->value = gmp_init($temp);
|
394 |
+
$this->is_negative = false;
|
395 |
+
break;
|
396 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
397 |
+
$x = ( strlen($x) & 1 ) ? '0' . $x : $x;
|
398 |
+
$temp = new Math_BigInteger(pack('H*', $x), 256);
|
399 |
+
$this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
|
400 |
+
$this->is_negative = false;
|
401 |
+
break;
|
402 |
+
default:
|
403 |
+
$x = ( strlen($x) & 1 ) ? '0' . $x : $x;
|
404 |
+
$temp = new Math_BigInteger(pack('H*', $x), 256);
|
405 |
+
$this->value = $temp->value;
|
406 |
+
}
|
407 |
+
|
408 |
+
if ($is_negative) {
|
409 |
+
$temp = $this->add(new Math_BigInteger('-1'));
|
410 |
+
$this->value = $temp->value;
|
411 |
+
}
|
412 |
+
break;
|
413 |
+
case 10:
|
414 |
+
case -10:
|
415 |
+
// (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
|
416 |
+
// (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
|
417 |
+
// [^-0-9].*: find any non-numeric characters and then any characters that follow that
|
418 |
+
$x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
|
419 |
+
|
420 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
421 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
422 |
+
$this->value = gmp_init($x);
|
423 |
+
break;
|
424 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
425 |
+
// explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
|
426 |
+
// results then doing it on '-1' does (modInverse does $x[0])
|
427 |
+
$this->value = $x === '-' ? '0' : (string) $x;
|
428 |
+
break;
|
429 |
+
default:
|
430 |
+
$temp = new Math_BigInteger();
|
431 |
+
|
432 |
+
$multiplier = new Math_BigInteger();
|
433 |
+
$multiplier->value = array(MATH_BIGINTEGER_MAX10);
|
434 |
+
|
435 |
+
if ($x[0] == '-') {
|
436 |
+
$this->is_negative = true;
|
437 |
+
$x = substr($x, 1);
|
438 |
+
}
|
439 |
+
|
440 |
+
$x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
|
441 |
+
|
442 |
+
while (strlen($x)) {
|
443 |
+
$temp = $temp->multiply($multiplier);
|
444 |
+
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
|
445 |
+
$x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
|
446 |
+
}
|
447 |
+
|
448 |
+
$this->value = $temp->value;
|
449 |
+
}
|
450 |
+
break;
|
451 |
+
case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
|
452 |
+
case -2:
|
453 |
+
if ($base > 0 && $x[0] == '-') {
|
454 |
+
$this->is_negative = true;
|
455 |
+
$x = substr($x, 1);
|
456 |
+
}
|
457 |
+
|
458 |
+
$x = preg_replace('#^([01]*).*#', '$1', $x);
|
459 |
+
$x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
|
460 |
+
|
461 |
+
$str = '0x';
|
462 |
+
while (strlen($x)) {
|
463 |
+
$part = substr($x, 0, 4);
|
464 |
+
$str.= dechex(bindec($part));
|
465 |
+
$x = substr($x, 4);
|
466 |
+
}
|
467 |
+
|
468 |
+
if ($this->is_negative) {
|
469 |
+
$str = '-' . $str;
|
470 |
+
}
|
471 |
+
|
472 |
+
$temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
|
473 |
+
$this->value = $temp->value;
|
474 |
+
$this->is_negative = $temp->is_negative;
|
475 |
+
|
476 |
+
break;
|
477 |
+
default:
|
478 |
+
// base not supported, so we'll let $this == 0
|
479 |
+
}
|
480 |
+
}
|
481 |
+
|
482 |
+
/**
|
483 |
+
* Converts a BigInteger to a byte string (eg. base-256).
|
484 |
+
*
|
485 |
+
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
486 |
+
* saved as two's compliment.
|
487 |
+
*
|
488 |
+
* Here's an example:
|
489 |
+
* <code>
|
490 |
+
* <?php
|
491 |
+
* include('Math/BigInteger.php');
|
492 |
+
*
|
493 |
+
* $a = new Math_BigInteger('65');
|
494 |
+
*
|
495 |
+
* echo $a->toBytes(); // outputs chr(65)
|
496 |
+
* ?>
|
497 |
+
* </code>
|
498 |
+
*
|
499 |
+
* @param Boolean $twos_compliment
|
500 |
+
* @return String
|
501 |
+
* @access public
|
502 |
+
* @internal Converts a base-2**26 number to base-2**8
|
503 |
+
*/
|
504 |
+
function toBytes($twos_compliment = false)
|
505 |
+
{
|
506 |
+
if ($twos_compliment) {
|
507 |
+
$comparison = $this->compare(new Math_BigInteger());
|
508 |
+
if ($comparison == 0) {
|
509 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
510 |
+
}
|
511 |
+
|
512 |
+
$temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
|
513 |
+
$bytes = $temp->toBytes();
|
514 |
+
|
515 |
+
if (empty($bytes)) { // eg. if the number we're trying to convert is -1
|
516 |
+
$bytes = chr(0);
|
517 |
+
}
|
518 |
+
|
519 |
+
if (ord($bytes[0]) & 0x80) {
|
520 |
+
$bytes = chr(0) . $bytes;
|
521 |
+
}
|
522 |
+
|
523 |
+
return $comparison < 0 ? ~$bytes : $bytes;
|
524 |
+
}
|
525 |
+
|
526 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
527 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
528 |
+
if (gmp_cmp($this->value, gmp_init(0)) == 0) {
|
529 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
530 |
+
}
|
531 |
+
|
532 |
+
$temp = gmp_strval(gmp_abs($this->value), 16);
|
533 |
+
$temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
|
534 |
+
$temp = pack('H*', $temp);
|
535 |
+
|
536 |
+
return $this->precision > 0 ?
|
537 |
+
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
538 |
+
ltrim($temp, chr(0));
|
539 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
540 |
+
if ($this->value === '0') {
|
541 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
542 |
+
}
|
543 |
+
|
544 |
+
$value = '';
|
545 |
+
$current = $this->value;
|
546 |
+
|
547 |
+
if ($current[0] == '-') {
|
548 |
+
$current = substr($current, 1);
|
549 |
+
}
|
550 |
+
|
551 |
+
while (bccomp($current, '0', 0) > 0) {
|
552 |
+
$temp = bcmod($current, '16777216');
|
553 |
+
$value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
|
554 |
+
$current = bcdiv($current, '16777216', 0);
|
555 |
+
}
|
556 |
+
|
557 |
+
return $this->precision > 0 ?
|
558 |
+
substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
559 |
+
ltrim($value, chr(0));
|
560 |
+
}
|
561 |
+
|
562 |
+
if (!count($this->value)) {
|
563 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
564 |
+
}
|
565 |
+
$result = $this->_int2bytes($this->value[count($this->value) - 1]);
|
566 |
+
|
567 |
+
$temp = $this->copy();
|
568 |
+
|
569 |
+
for ($i = count($temp->value) - 2; $i >= 0; --$i) {
|
570 |
+
$temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
|
571 |
+
$result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
|
572 |
+
}
|
573 |
+
|
574 |
+
return $this->precision > 0 ?
|
575 |
+
str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
|
576 |
+
$result;
|
577 |
+
}
|
578 |
+
|
579 |
+
/**
|
580 |
+
* Converts a BigInteger to a hex string (eg. base-16)).
|
581 |
+
*
|
582 |
+
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
583 |
+
* saved as two's compliment.
|
584 |
+
*
|
585 |
+
* Here's an example:
|
586 |
+
* <code>
|
587 |
+
* <?php
|
588 |
+
* include('Math/BigInteger.php');
|
589 |
+
*
|
590 |
+
* $a = new Math_BigInteger('65');
|
591 |
+
*
|
592 |
+
* echo $a->toHex(); // outputs '41'
|
593 |
+
* ?>
|
594 |
+
* </code>
|
595 |
+
*
|
596 |
+
* @param Boolean $twos_compliment
|
597 |
+
* @return String
|
598 |
+
* @access public
|
599 |
+
* @internal Converts a base-2**26 number to base-2**8
|
600 |
+
*/
|
601 |
+
function toHex($twos_compliment = false)
|
602 |
+
{
|
603 |
+
return bin2hex($this->toBytes($twos_compliment));
|
604 |
+
}
|
605 |
+
|
606 |
+
/**
|
607 |
+
* Converts a BigInteger to a bit string (eg. base-2).
|
608 |
+
*
|
609 |
+
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
610 |
+
* saved as two's compliment.
|
611 |
+
*
|
612 |
+
* Here's an example:
|
613 |
+
* <code>
|
614 |
+
* <?php
|
615 |
+
* include('Math/BigInteger.php');
|
616 |
+
*
|
617 |
+
* $a = new Math_BigInteger('65');
|
618 |
+
*
|
619 |
+
* echo $a->toBits(); // outputs '1000001'
|
620 |
+
* ?>
|
621 |
+
* </code>
|
622 |
+
*
|
623 |
+
* @param Boolean $twos_compliment
|
624 |
+
* @return String
|
625 |
+
* @access public
|
626 |
+
* @internal Converts a base-2**26 number to base-2**2
|
627 |
+
*/
|
628 |
+
function toBits($twos_compliment = false)
|
629 |
+
{
|
630 |
+
$hex = $this->toHex($twos_compliment);
|
631 |
+
$bits = '';
|
632 |
+
for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
|
633 |
+
$bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
|
634 |
+
}
|
635 |
+
if ($start) { // hexdec('') == 0
|
636 |
+
$bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
|
637 |
+
}
|
638 |
+
$result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
|
639 |
+
|
640 |
+
if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
|
641 |
+
return '0' . $result;
|
642 |
+
}
|
643 |
+
|
644 |
+
return $result;
|
645 |
+
}
|
646 |
+
|
647 |
+
/**
|
648 |
+
* Converts a BigInteger to a base-10 number.
|
649 |
+
*
|
650 |
+
* Here's an example:
|
651 |
+
* <code>
|
652 |
+
* <?php
|
653 |
+
* include('Math/BigInteger.php');
|
654 |
+
*
|
655 |
+
* $a = new Math_BigInteger('50');
|
656 |
+
*
|
657 |
+
* echo $a->toString(); // outputs 50
|
658 |
+
* ?>
|
659 |
+
* </code>
|
660 |
+
*
|
661 |
+
* @return String
|
662 |
+
* @access public
|
663 |
+
* @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
|
664 |
+
*/
|
665 |
+
function toString()
|
666 |
+
{
|
667 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
668 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
669 |
+
return gmp_strval($this->value);
|
670 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
671 |
+
if ($this->value === '0') {
|
672 |
+
return '0';
|
673 |
+
}
|
674 |
+
|
675 |
+
return ltrim($this->value, '0');
|
676 |
+
}
|
677 |
+
|
678 |
+
if (!count($this->value)) {
|
679 |
+
return '0';
|
680 |
+
}
|
681 |
+
|
682 |
+
$temp = $this->copy();
|
683 |
+
$temp->is_negative = false;
|
684 |
+
|
685 |
+
$divisor = new Math_BigInteger();
|
686 |
+
$divisor->value = array(MATH_BIGINTEGER_MAX10);
|
687 |
+
$result = '';
|
688 |
+
while (count($temp->value)) {
|
689 |
+
list($temp, $mod) = $temp->divide($divisor);
|
690 |
+
$result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
|
691 |
+
}
|
692 |
+
$result = ltrim($result, '0');
|
693 |
+
if (empty($result)) {
|
694 |
+
$result = '0';
|
695 |
+
}
|
696 |
+
|
697 |
+
if ($this->is_negative) {
|
698 |
+
$result = '-' . $result;
|
699 |
+
}
|
700 |
+
|
701 |
+
return $result;
|
702 |
+
}
|
703 |
+
|
704 |
+
/**
|
705 |
+
* Copy an object
|
706 |
+
*
|
707 |
+
* PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
|
708 |
+
* that all objects are passed by value, when appropriate. More information can be found here:
|
709 |
+
*
|
710 |
+
* {@link http://php.net/language.oop5.basic#51624}
|
711 |
+
*
|
712 |
+
* @access public
|
713 |
+
* @see __clone()
|
714 |
+
* @return Math_BigInteger
|
715 |
+
*/
|
716 |
+
function copy()
|
717 |
+
{
|
718 |
+
$temp = new Math_BigInteger();
|
719 |
+
$temp->value = $this->value;
|
720 |
+
$temp->is_negative = $this->is_negative;
|
721 |
+
$temp->generator = $this->generator;
|
722 |
+
$temp->precision = $this->precision;
|
723 |
+
$temp->bitmask = $this->bitmask;
|
724 |
+
return $temp;
|
725 |
+
}
|
726 |
+
|
727 |
+
/**
|
728 |
+
* __toString() magic method
|
729 |
+
*
|
730 |
+
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
|
731 |
+
* toString().
|
732 |
+
*
|
733 |
+
* @access public
|
734 |
+
* @internal Implemented per a suggestion by Techie-Michael - thanks!
|
735 |
+
*/
|
736 |
+
function __toString()
|
737 |
+
{
|
738 |
+
return $this->toString();
|
739 |
+
}
|
740 |
+
|
741 |
+
/**
|
742 |
+
* __clone() magic method
|
743 |
+
*
|
744 |
+
* Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
|
745 |
+
* directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
|
746 |
+
* only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
|
747 |
+
* call Math_BigInteger::copy(), instead.
|
748 |
+
*
|
749 |
+
* @access public
|
750 |
+
* @see copy()
|
751 |
+
* @return Math_BigInteger
|
752 |
+
*/
|
753 |
+
function __clone()
|
754 |
+
{
|
755 |
+
return $this->copy();
|
756 |
+
}
|
757 |
+
|
758 |
+
/**
|
759 |
+
* __sleep() magic method
|
760 |
+
*
|
761 |
+
* Will be called, automatically, when serialize() is called on a Math_BigInteger object.
|
762 |
+
*
|
763 |
+
* @see __wakeup()
|
764 |
+
* @access public
|
765 |
+
*/
|
766 |
+
function __sleep()
|
767 |
+
{
|
768 |
+
$this->hex = $this->toHex(true);
|
769 |
+
$vars = array('hex');
|
770 |
+
if ($this->generator != 'mt_rand') {
|
771 |
+
$vars[] = 'generator';
|
772 |
+
}
|
773 |
+
if ($this->precision > 0) {
|
774 |
+
$vars[] = 'precision';
|
775 |
+
}
|
776 |
+
return $vars;
|
777 |
+
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* __wakeup() magic method
|
782 |
+
*
|
783 |
+
* Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
|
784 |
+
*
|
785 |
+
* @see __sleep()
|
786 |
+
* @access public
|
787 |
+
*/
|
788 |
+
function __wakeup()
|
789 |
+
{
|
790 |
+
$temp = new Math_BigInteger($this->hex, -16);
|
791 |
+
$this->value = $temp->value;
|
792 |
+
$this->is_negative = $temp->is_negative;
|
793 |
+
$this->setRandomGenerator($this->generator);
|
794 |
+
if ($this->precision > 0) {
|
795 |
+
// recalculate $this->bitmask
|
796 |
+
$this->setPrecision($this->precision);
|
797 |
+
}
|
798 |
+
}
|
799 |
+
|
800 |
+
/**
|
801 |
+
* Adds two BigIntegers.
|
802 |
+
*
|
803 |
+
* Here's an example:
|
804 |
+
* <code>
|
805 |
+
* <?php
|
806 |
+
* include('Math/BigInteger.php');
|
807 |
+
*
|
808 |
+
* $a = new Math_BigInteger('10');
|
809 |
+
* $b = new Math_BigInteger('20');
|
810 |
+
*
|
811 |
+
* $c = $a->add($b);
|
812 |
+
*
|
813 |
+
* echo $c->toString(); // outputs 30
|
814 |
+
* ?>
|
815 |
+
* </code>
|
816 |
+
*
|
817 |
+
* @param Math_BigInteger $y
|
818 |
+
* @return Math_BigInteger
|
819 |
+
* @access public
|
820 |
+
* @internal Performs base-2**52 addition
|
821 |
+
*/
|
822 |
+
function add($y)
|
823 |
+
{
|
824 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
825 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
826 |
+
$temp = new Math_BigInteger();
|
827 |
+
$temp->value = gmp_add($this->value, $y->value);
|
828 |
+
|
829 |
+
return $this->_normalize($temp);
|
830 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
831 |
+
$temp = new Math_BigInteger();
|
832 |
+
$temp->value = bcadd($this->value, $y->value, 0);
|
833 |
+
|
834 |
+
return $this->_normalize($temp);
|
835 |
+
}
|
836 |
+
|
837 |
+
$temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
|
838 |
+
|
839 |
+
$result = new Math_BigInteger();
|
840 |
+
$result->value = $temp[MATH_BIGINTEGER_VALUE];
|
841 |
+
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
|
842 |
+
|
843 |
+
return $this->_normalize($result);
|
844 |
+
}
|
845 |
+
|
846 |
+
/**
|
847 |
+
* Performs addition.
|
848 |
+
*
|
849 |
+
* @param Array $x_value
|
850 |
+
* @param Boolean $x_negative
|
851 |
+
* @param Array $y_value
|
852 |
+
* @param Boolean $y_negative
|
853 |
+
* @return Array
|
854 |
+
* @access private
|
855 |
+
*/
|
856 |
+
function _add($x_value, $x_negative, $y_value, $y_negative)
|
857 |
+
{
|
858 |
+
$x_size = count($x_value);
|
859 |
+
$y_size = count($y_value);
|
860 |
+
|
861 |
+
if ($x_size == 0) {
|
862 |
+
return array(
|
863 |
+
MATH_BIGINTEGER_VALUE => $y_value,
|
864 |
+
MATH_BIGINTEGER_SIGN => $y_negative
|
865 |
+
);
|
866 |
+
} else if ($y_size == 0) {
|
867 |
+
return array(
|
868 |
+
MATH_BIGINTEGER_VALUE => $x_value,
|
869 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
870 |
+
);
|
871 |
+
}
|
872 |
+
|
873 |
+
// subtract, if appropriate
|
874 |
+
if ( $x_negative != $y_negative ) {
|
875 |
+
if ( $x_value == $y_value ) {
|
876 |
+
return array(
|
877 |
+
MATH_BIGINTEGER_VALUE => array(),
|
878 |
+
MATH_BIGINTEGER_SIGN => false
|
879 |
+
);
|
880 |
+
}
|
881 |
+
|
882 |
+
$temp = $this->_subtract($x_value, false, $y_value, false);
|
883 |
+
$temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
|
884 |
+
$x_negative : $y_negative;
|
885 |
+
|
886 |
+
return $temp;
|
887 |
+
}
|
888 |
+
|
889 |
+
if ($x_size < $y_size) {
|
890 |
+
$size = $x_size;
|
891 |
+
$value = $y_value;
|
892 |
+
} else {
|
893 |
+
$size = $y_size;
|
894 |
+
$value = $x_value;
|
895 |
+
}
|
896 |
+
|
897 |
+
$value[] = 0; // just in case the carry adds an extra digit
|
898 |
+
|
899 |
+
$carry = 0;
|
900 |
+
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
|
901 |
+
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
|
902 |
+
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
903 |
+
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
|
904 |
+
|
905 |
+
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
|
906 |
+
|
907 |
+
$value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
|
908 |
+
$value[$j] = $temp;
|
909 |
+
}
|
910 |
+
|
911 |
+
if ($j == $size) { // ie. if $y_size is odd
|
912 |
+
$sum = $x_value[$i] + $y_value[$i] + $carry;
|
913 |
+
$carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
|
914 |
+
$value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
|
915 |
+
++$i; // ie. let $i = $j since we've just done $value[$i]
|
916 |
+
}
|
917 |
+
|
918 |
+
if ($carry) {
|
919 |
+
for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
|
920 |
+
$value[$i] = 0;
|
921 |
+
}
|
922 |
+
++$value[$i];
|
923 |
+
}
|
924 |
+
|
925 |
+
return array(
|
926 |
+
MATH_BIGINTEGER_VALUE => $this->_trim($value),
|
927 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
928 |
+
);
|
929 |
+
}
|
930 |
+
|
931 |
+
/**
|
932 |
+
* Subtracts two BigIntegers.
|
933 |
+
*
|
934 |
+
* Here's an example:
|
935 |
+
* <code>
|
936 |
+
* <?php
|
937 |
+
* include('Math/BigInteger.php');
|
938 |
+
*
|
939 |
+
* $a = new Math_BigInteger('10');
|
940 |
+
* $b = new Math_BigInteger('20');
|
941 |
+
*
|
942 |
+
* $c = $a->subtract($b);
|
943 |
+
*
|
944 |
+
* echo $c->toString(); // outputs -10
|
945 |
+
* ?>
|
946 |
+
* </code>
|
947 |
+
*
|
948 |
+
* @param Math_BigInteger $y
|
949 |
+
* @return Math_BigInteger
|
950 |
+
* @access public
|
951 |
+
* @internal Performs base-2**52 subtraction
|
952 |
+
*/
|
953 |
+
function subtract($y)
|
954 |
+
{
|
955 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
956 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
957 |
+
$temp = new Math_BigInteger();
|
958 |
+
$temp->value = gmp_sub($this->value, $y->value);
|
959 |
+
|
960 |
+
return $this->_normalize($temp);
|
961 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
962 |
+
$temp = new Math_BigInteger();
|
963 |
+
$temp->value = bcsub($this->value, $y->value, 0);
|
964 |
+
|
965 |
+
return $this->_normalize($temp);
|
966 |
+
}
|
967 |
+
|
968 |
+
$temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
|
969 |
+
|
970 |
+
$result = new Math_BigInteger();
|
971 |
+
$result->value = $temp[MATH_BIGINTEGER_VALUE];
|
972 |
+
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
|
973 |
+
|
974 |
+
return $this->_normalize($result);
|
975 |
+
}
|
976 |
+
|
977 |
+
/**
|
978 |
+
* Performs subtraction.
|
979 |
+
*
|
980 |
+
* @param Array $x_value
|
981 |
+
* @param Boolean $x_negative
|
982 |
+
* @param Array $y_value
|
983 |
+
* @param Boolean $y_negative
|
984 |
+
* @return Array
|
985 |
+
* @access private
|
986 |
+
*/
|
987 |
+
function _subtract($x_value, $x_negative, $y_value, $y_negative)
|
988 |
+
{
|
989 |
+
$x_size = count($x_value);
|
990 |
+
$y_size = count($y_value);
|
991 |
+
|
992 |
+
if ($x_size == 0) {
|
993 |
+
return array(
|
994 |
+
MATH_BIGINTEGER_VALUE => $y_value,
|
995 |
+
MATH_BIGINTEGER_SIGN => !$y_negative
|
996 |
+
);
|
997 |
+
} else if ($y_size == 0) {
|
998 |
+
return array(
|
999 |
+
MATH_BIGINTEGER_VALUE => $x_value,
|
1000 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
1001 |
+
);
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
// add, if appropriate (ie. -$x - +$y or +$x - -$y)
|
1005 |
+
if ( $x_negative != $y_negative ) {
|
1006 |
+
$temp = $this->_add($x_value, false, $y_value, false);
|
1007 |
+
$temp[MATH_BIGINTEGER_SIGN] = $x_negative;
|
1008 |
+
|
1009 |
+
return $temp;
|
1010 |
+
}
|
1011 |
+
|
1012 |
+
$diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
|
1013 |
+
|
1014 |
+
if ( !$diff ) {
|
1015 |
+
return array(
|
1016 |
+
MATH_BIGINTEGER_VALUE => array(),
|
1017 |
+
MATH_BIGINTEGER_SIGN => false
|
1018 |
+
);
|
1019 |
+
}
|
1020 |
+
|
1021 |
+
// switch $x and $y around, if appropriate.
|
1022 |
+
if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
|
1023 |
+
$temp = $x_value;
|
1024 |
+
$x_value = $y_value;
|
1025 |
+
$y_value = $temp;
|
1026 |
+
|
1027 |
+
$x_negative = !$x_negative;
|
1028 |
+
|
1029 |
+
$x_size = count($x_value);
|
1030 |
+
$y_size = count($y_value);
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
// at this point, $x_value should be at least as big as - if not bigger than - $y_value
|
1034 |
+
|
1035 |
+
$carry = 0;
|
1036 |
+
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
|
1037 |
+
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
|
1038 |
+
$carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
1039 |
+
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
|
1040 |
+
|
1041 |
+
$temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);
|
1042 |
+
|
1043 |
+
$x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
|
1044 |
+
$x_value[$j] = $temp;
|
1045 |
+
}
|
1046 |
+
|
1047 |
+
if ($j == $y_size) { // ie. if $y_size is odd
|
1048 |
+
$sum = $x_value[$i] - $y_value[$i] - $carry;
|
1049 |
+
$carry = $sum < 0;
|
1050 |
+
$x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
|
1051 |
+
++$i;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
if ($carry) {
|
1055 |
+
for (; !$x_value[$i]; ++$i) {
|
1056 |
+
$x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
|
1057 |
+
}
|
1058 |
+
--$x_value[$i];
|
1059 |
+
}
|
1060 |
+
|
1061 |
+
return array(
|
1062 |
+
MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
|
1063 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
1064 |
+
);
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
/**
|
1068 |
+
* Multiplies two BigIntegers
|
1069 |
+
*
|
1070 |
+
* Here's an example:
|
1071 |
+
* <code>
|
1072 |
+
* <?php
|
1073 |
+
* include('Math/BigInteger.php');
|
1074 |
+
*
|
1075 |
+
* $a = new Math_BigInteger('10');
|
1076 |
+
* $b = new Math_BigInteger('20');
|
1077 |
+
*
|
1078 |
+
* $c = $a->multiply($b);
|
1079 |
+
*
|
1080 |
+
* echo $c->toString(); // outputs 200
|
1081 |
+
* ?>
|
1082 |
+
* </code>
|
1083 |
+
*
|
1084 |
+
* @param Math_BigInteger $x
|
1085 |
+
* @return Math_BigInteger
|
1086 |
+
* @access public
|
1087 |
+
*/
|
1088 |
+
function multiply($x)
|
1089 |
+
{
|
1090 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
1091 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
1092 |
+
$temp = new Math_BigInteger();
|
1093 |
+
$temp->value = gmp_mul($this->value, $x->value);
|
1094 |
+
|
1095 |
+
return $this->_normalize($temp);
|
1096 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
1097 |
+
$temp = new Math_BigInteger();
|
1098 |
+
$temp->value = bcmul($this->value, $x->value, 0);
|
1099 |
+
|
1100 |
+
return $this->_normalize($temp);
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
$temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
|
1104 |
+
|
1105 |
+
$product = new Math_BigInteger();
|
1106 |
+
$product->value = $temp[MATH_BIGINTEGER_VALUE];
|
1107 |
+
$product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
|
1108 |
+
|
1109 |
+
return $this->_normalize($product);
|
1110 |
+
}
|
1111 |
+
|
1112 |
+
/**
|
1113 |
+
* Performs multiplication.
|
1114 |
+
*
|
1115 |
+
* @param Array $x_value
|
1116 |
+
* @param Boolean $x_negative
|
1117 |
+
* @param Array $y_value
|
1118 |
+
* @param Boolean $y_negative
|
1119 |
+
* @return Array
|
1120 |
+
* @access private
|
1121 |
+
*/
|
1122 |
+
function _multiply($x_value, $x_negative, $y_value, $y_negative)
|
1123 |
+
{
|
1124 |
+
//if ( $x_value == $y_value ) {
|
1125 |
+
// return array(
|
1126 |
+
// MATH_BIGINTEGER_VALUE => $this->_square($x_value),
|
1127 |
+
// MATH_BIGINTEGER_SIGN => $x_sign != $y_value
|
1128 |
+
// );
|
1129 |
+
//}
|
1130 |
+
|
1131 |
+
$x_length = count($x_value);
|
1132 |
+
$y_length = count($y_value);
|
1133 |
+
|
1134 |
+
if ( !$x_length || !$y_length ) { // a 0 is being multiplied
|
1135 |
+
return array(
|
1136 |
+
MATH_BIGINTEGER_VALUE => array(),
|
1137 |
+
MATH_BIGINTEGER_SIGN => false
|
1138 |
+
);
|
1139 |
+
}
|
1140 |
+
|
1141 |
+
return array(
|
1142 |
+
MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
|
1143 |
+
$this->_trim($this->_regularMultiply($x_value, $y_value)) :
|
1144 |
+
$this->_trim($this->_karatsuba($x_value, $y_value)),
|
1145 |
+
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
|
1146 |
+
);
|
1147 |
+
}
|
1148 |
+
|
1149 |
+
/**
|
1150 |
+
* Performs long multiplication on two BigIntegers
|
1151 |
+
*
|
1152 |
+
* Modeled after 'multiply' in MutableBigInteger.java.
|
1153 |
+
*
|
1154 |
+
* @param Array $x_value
|
1155 |
+
* @param Array $y_value
|
1156 |
+
* @return Array
|
1157 |
+
* @access private
|
1158 |
+
*/
|
1159 |
+
function _regularMultiply($x_value, $y_value)
|
1160 |
+
{
|
1161 |
+
$x_length = count($x_value);
|
1162 |
+
$y_length = count($y_value);
|
1163 |
+
|
1164 |
+
if ( !$x_length || !$y_length ) { // a 0 is being multiplied
|
1165 |
+
return array();
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
if ( $x_length < $y_length ) {
|
1169 |
+
$temp = $x_value;
|
1170 |
+
$x_value = $y_value;
|
1171 |
+
$y_value = $temp;
|
1172 |
+
|
1173 |
+
$x_length = count($x_value);
|
1174 |
+
$y_length = count($y_value);
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
$product_value = $this->_array_repeat(0, $x_length + $y_length);
|
1178 |
+
|
1179 |
+
// the following for loop could be removed if the for loop following it
|
1180 |
+
// (the one with nested for loops) initially set $i to 0, but
|
1181 |
+
// doing so would also make the result in one set of unnecessary adds,
|
1182 |
+
// since on the outermost loops first pass, $product->value[$k] is going
|
1183 |
+
// to always be 0
|
1184 |
+
|
1185 |
+
$carry = 0;
|
1186 |
+
|
1187 |
+
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
|
1188 |
+
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
|
1189 |
+
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
1190 |
+
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
1191 |
+
}
|
1192 |
+
|
1193 |
+
$product_value[$j] = $carry;
|
1194 |
+
|
1195 |
+
// the above for loop is what the previous comment was talking about. the
|
1196 |
+
// following for loop is the "one with nested for loops"
|
1197 |
+
for ($i = 1; $i < $y_length; ++$i) {
|
1198 |
+
$carry = 0;
|
1199 |
+
|
1200 |
+
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
|
1201 |
+
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
|
1202 |
+
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
1203 |
+
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
$product_value[$k] = $carry;
|
1207 |
+
}
|
1208 |
+
|
1209 |
+
return $product_value;
|
1210 |
+
}
|
1211 |
+
|
1212 |
+
/**
|
1213 |
+
* Performs Karatsuba multiplication on two BigIntegers
|
1214 |
+
*
|
1215 |
+
* See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
|
1216 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
|
1217 |
+
*
|
1218 |
+
* @param Array $x_value
|
1219 |
+
* @param Array $y_value
|
1220 |
+
* @return Array
|
1221 |
+
* @access private
|
1222 |
+
*/
|
1223 |
+
function _karatsuba($x_value, $y_value)
|
1224 |
+
{
|
1225 |
+
$m = min(count($x_value) >> 1, count($y_value) >> 1);
|
1226 |
+
|
1227 |
+
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
|
1228 |
+
return $this->_regularMultiply($x_value, $y_value);
|
1229 |
+
}
|
1230 |
+
|
1231 |
+
$x1 = array_slice($x_value, $m);
|
1232 |
+
$x0 = array_slice($x_value, 0, $m);
|
1233 |
+
$y1 = array_slice($y_value, $m);
|
1234 |
+
$y0 = array_slice($y_value, 0, $m);
|
1235 |
+
|
1236 |
+
$z2 = $this->_karatsuba($x1, $y1);
|
1237 |
+
$z0 = $this->_karatsuba($x0, $y0);
|
1238 |
+
|
1239 |
+
$z1 = $this->_add($x1, false, $x0, false);
|
1240 |
+
$temp = $this->_add($y1, false, $y0, false);
|
1241 |
+
$z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
|
1242 |
+
$temp = $this->_add($z2, false, $z0, false);
|
1243 |
+
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
|
1244 |
+
|
1245 |
+
$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
|
1246 |
+
$z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
|
1247 |
+
|
1248 |
+
$xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
|
1249 |
+
$xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
|
1250 |
+
|
1251 |
+
return $xy[MATH_BIGINTEGER_VALUE];
|
1252 |
+
}
|
1253 |
+
|
1254 |
+
/**
|
1255 |
+
* Performs squaring
|
1256 |
+
*
|
1257 |
+
* @param Array $x
|
1258 |
+
* @return Array
|
1259 |
+
* @access private
|
1260 |
+
*/
|
1261 |
+
function _square($x = false)
|
1262 |
+
{
|
1263 |
+
return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
|
1264 |
+
$this->_trim($this->_baseSquare($x)) :
|
1265 |
+
$this->_trim($this->_karatsubaSquare($x));
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
/**
|
1269 |
+
* Performs traditional squaring on two BigIntegers
|
1270 |
+
*
|
1271 |
+
* Squaring can be done faster than multiplying a number by itself can be. See
|
1272 |
+
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
|
1273 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
|
1274 |
+
*
|
1275 |
+
* @param Array $value
|
1276 |
+
* @return Array
|
1277 |
+
* @access private
|
1278 |
+
*/
|
1279 |
+
function _baseSquare($value)
|
1280 |
+
{
|
1281 |
+
if ( empty($value) ) {
|
1282 |
+
return array();
|
1283 |
+
}
|
1284 |
+
$square_value = $this->_array_repeat(0, 2 * count($value));
|
1285 |
+
|
1286 |
+
for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
|
1287 |
+
$i2 = $i << 1;
|
1288 |
+
|
1289 |
+
$temp = $square_value[$i2] + $value[$i] * $value[$i];
|
1290 |
+
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
1291 |
+
$square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
1292 |
+
|
1293 |
+
// note how we start from $i+1 instead of 0 as we do in multiplication.
|
1294 |
+
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
|
1295 |
+
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
|
1296 |
+
$carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
|
1297 |
+
$square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
// the following line can yield values larger 2**15. at this point, PHP should switch
|
1301 |
+
// over to floats.
|
1302 |
+
$square_value[$i + $max_index + 1] = $carry;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
return $square_value;
|
1306 |
+
}
|
1307 |
+
|
1308 |
+
/**
|
1309 |
+
* Performs Karatsuba "squaring" on two BigIntegers
|
1310 |
+
*
|
1311 |
+
* See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
|
1312 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
|
1313 |
+
*
|
1314 |
+
* @param Array $value
|
1315 |
+
* @return Array
|
1316 |
+
* @access private
|
1317 |
+
*/
|
1318 |
+
function _karatsubaSquare($value)
|
1319 |
+
{
|
1320 |
+
$m = count($value) >> 1;
|
1321 |
+
|
1322 |
+
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
|
1323 |
+
return $this->_baseSquare($value);
|
1324 |
+
}
|
1325 |
+
|
1326 |
+
$x1 = array_slice($value, $m);
|
1327 |
+
$x0 = array_slice($value, 0, $m);
|
1328 |
+
|
1329 |
+
$z2 = $this->_karatsubaSquare($x1);
|
1330 |
+
$z0 = $this->_karatsubaSquare($x0);
|
1331 |
+
|
1332 |
+
$z1 = $this->_add($x1, false, $x0, false);
|
1333 |
+
$z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
|
1334 |
+
$temp = $this->_add($z2, false, $z0, false);
|
1335 |
+
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
|
1336 |
+
|
1337 |
+
$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
|
1338 |
+
$z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
|
1339 |
+
|
1340 |
+
$xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
|
1341 |
+
$xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
|
1342 |
+
|
1343 |
+
return $xx[MATH_BIGINTEGER_VALUE];
|
1344 |
+
}
|
1345 |
+
|
1346 |
+
/**
|
1347 |
+
* Divides two BigIntegers.
|
1348 |
+
*
|
1349 |
+
* Returns an array whose first element contains the quotient and whose second element contains the
|
1350 |
+
* "common residue". If the remainder would be positive, the "common residue" and the remainder are the
|
1351 |
+
* same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
|
1352 |
+
* and the divisor (basically, the "common residue" is the first positive modulo).
|
1353 |
+
*
|
1354 |
+
* Here's an example:
|
1355 |
+
* <code>
|
1356 |
+
* <?php
|
1357 |
+
* include('Math/BigInteger.php');
|
1358 |
+
*
|
1359 |
+
* $a = new Math_BigInteger('10');
|
1360 |
+
* $b = new Math_BigInteger('20');
|
1361 |
+
*
|
1362 |
+
* list($quotient, $remainder) = $a->divide($b);
|
1363 |
+
*
|
1364 |
+
* echo $quotient->toString(); // outputs 0
|
1365 |
+
* echo "\r\n";
|
1366 |
+
* echo $remainder->toString(); // outputs 10
|
1367 |
+
* ?>
|
1368 |
+
* </code>
|
1369 |
+
*
|
1370 |
+
* @param Math_BigInteger $y
|
1371 |
+
* @return Array
|
1372 |
+
* @access public
|
1373 |
+
* @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
|
1374 |
+
*/
|
1375 |
+
function divide($y)
|
1376 |
+
{
|
1377 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
1378 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
1379 |
+
$quotient = new Math_BigInteger();
|
1380 |
+
$remainder = new Math_BigInteger();
|
1381 |
+
|
1382 |
+
list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
|
1383 |
+
|
1384 |
+
if (gmp_sign($remainder->value) < 0) {
|
1385 |
+
$remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
|
1386 |
+
}
|
1387 |
+
|
1388 |
+
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
1389 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
1390 |
+
$quotient = new Math_BigInteger();
|
1391 |
+
$remainder = new Math_BigInteger();
|
1392 |
+
|
1393 |
+
$quotient->value = bcdiv($this->value, $y->value, 0);
|
1394 |
+
$remainder->value = bcmod($this->value, $y->value);
|
1395 |
+
|
1396 |
+
if ($remainder->value[0] == '-') {
|
1397 |
+
$remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
|
1398 |
+
}
|
1399 |
+
|
1400 |
+
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
1401 |
+
}
|
1402 |
+
|
1403 |
+
if (count($y->value) == 1) {
|
1404 |
+
list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
|
1405 |
+
$quotient = new Math_BigInteger();
|
1406 |
+
$remainder = new Math_BigInteger();
|
1407 |
+
$quotient->value = $q;
|
1408 |
+
$remainder->value = array($r);
|
1409 |
+
$quotient->is_negative = $this->is_negative != $y->is_negative;
|
1410 |
+
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
1411 |
+
}
|
1412 |
+
|
1413 |
+
static $zero;
|
1414 |
+
if ( !isset($zero) ) {
|
1415 |
+
$zero = new Math_BigInteger();
|
1416 |
+
}
|
1417 |
+
|
1418 |
+
$x = $this->copy();
|
1419 |
+
$y = $y->copy();
|
1420 |
+
|
1421 |
+
$x_sign = $x->is_negative;
|
1422 |
+
$y_sign = $y->is_negative;
|
1423 |
+
|
1424 |
+
$x->is_negative = $y->is_negative = false;
|
1425 |
+
|
1426 |
+
$diff = $x->compare($y);
|
1427 |
+
|
1428 |
+
if ( !$diff ) {
|
1429 |
+
$temp = new Math_BigInteger();
|
1430 |
+
$temp->value = array(1);
|
1431 |
+
$temp->is_negative = $x_sign != $y_sign;
|
1432 |
+
return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
|
1433 |
+
}
|
1434 |
+
|
1435 |
+
if ( $diff < 0 ) {
|
1436 |
+
// if $x is negative, "add" $y.
|
1437 |
+
if ( $x_sign ) {
|
1438 |
+
$x = $y->subtract($x);
|
1439 |
+
}
|
1440 |
+
return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
|
1441 |
+
}
|
1442 |
+
|
1443 |
+
// normalize $x and $y as described in HAC 14.23 / 14.24
|
1444 |
+
$msb = $y->value[count($y->value) - 1];
|
1445 |
+
for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
|
1446 |
+
$msb <<= 1;
|
1447 |
+
}
|
1448 |
+
$x->_lshift($shift);
|
1449 |
+
$y->_lshift($shift);
|
1450 |
+
$y_value = &$y->value;
|
1451 |
+
|
1452 |
+
$x_max = count($x->value) - 1;
|
1453 |
+
$y_max = count($y->value) - 1;
|
1454 |
+
|
1455 |
+
$quotient = new Math_BigInteger();
|
1456 |
+
$quotient_value = &$quotient->value;
|
1457 |
+
$quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
|
1458 |
+
|
1459 |
+
static $temp, $lhs, $rhs;
|
1460 |
+
if (!isset($temp)) {
|
1461 |
+
$temp = new Math_BigInteger();
|
1462 |
+
$lhs = new Math_BigInteger();
|
1463 |
+
$rhs = new Math_BigInteger();
|
1464 |
+
}
|
1465 |
+
$temp_value = &$temp->value;
|
1466 |
+
$rhs_value = &$rhs->value;
|
1467 |
+
|
1468 |
+
// $temp = $y << ($x_max - $y_max-1) in base 2**26
|
1469 |
+
$temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
|
1470 |
+
|
1471 |
+
while ( $x->compare($temp) >= 0 ) {
|
1472 |
+
// calculate the "common residue"
|
1473 |
+
++$quotient_value[$x_max - $y_max];
|
1474 |
+
$x = $x->subtract($temp);
|
1475 |
+
$x_max = count($x->value) - 1;
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
for ($i = $x_max; $i >= $y_max + 1; --$i) {
|
1479 |
+
$x_value = &$x->value;
|
1480 |
+
$x_window = array(
|
1481 |
+
isset($x_value[$i]) ? $x_value[$i] : 0,
|
1482 |
+
isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
|
1483 |
+
isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
|
1484 |
+
);
|
1485 |
+
$y_window = array(
|
1486 |
+
$y_value[$y_max],
|
1487 |
+
( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
|
1488 |
+
);
|
1489 |
+
|
1490 |
+
$q_index = $i - $y_max - 1;
|
1491 |
+
if ($x_window[0] == $y_window[0]) {
|
1492 |
+
$quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
|
1493 |
+
} else {
|
1494 |
+
$quotient_value[$q_index] = (int) (
|
1495 |
+
($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1])
|
1496 |
+
/
|
1497 |
+
$y_window[0]
|
1498 |
+
);
|
1499 |
+
}
|
1500 |
+
|
1501 |
+
$temp_value = array($y_window[1], $y_window[0]);
|
1502 |
+
|
1503 |
+
$lhs->value = array($quotient_value[$q_index]);
|
1504 |
+
$lhs = $lhs->multiply($temp);
|
1505 |
+
|
1506 |
+
$rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
|
1507 |
+
|
1508 |
+
while ( $lhs->compare($rhs) > 0 ) {
|
1509 |
+
--$quotient_value[$q_index];
|
1510 |
+
|
1511 |
+
$lhs->value = array($quotient_value[$q_index]);
|
1512 |
+
$lhs = $lhs->multiply($temp);
|
1513 |
+
}
|
1514 |
+
|
1515 |
+
$adjust = $this->_array_repeat(0, $q_index);
|
1516 |
+
$temp_value = array($quotient_value[$q_index]);
|
1517 |
+
$temp = $temp->multiply($y);
|
1518 |
+
$temp_value = &$temp->value;
|
1519 |
+
$temp_value = array_merge($adjust, $temp_value);
|
1520 |
+
|
1521 |
+
$x = $x->subtract($temp);
|
1522 |
+
|
1523 |
+
if ($x->compare($zero) < 0) {
|
1524 |
+
$temp_value = array_merge($adjust, $y_value);
|
1525 |
+
$x = $x->add($temp);
|
1526 |
+
|
1527 |
+
--$quotient_value[$q_index];
|
1528 |
+
}
|
1529 |
+
|
1530 |
+
$x_max = count($x_value) - 1;
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
// unnormalize the remainder
|
1534 |
+
$x->_rshift($shift);
|
1535 |
+
|
1536 |
+
$quotient->is_negative = $x_sign != $y_sign;
|
1537 |
+
|
1538 |
+
// calculate the "common residue", if appropriate
|
1539 |
+
if ( $x_sign ) {
|
1540 |
+
$y->_rshift($shift);
|
1541 |
+
$x = $y->subtract($x);
|
1542 |
+
}
|
1543 |
+
|
1544 |
+
return array($this->_normalize($quotient), $this->_normalize($x));
|
1545 |
+
}
|
1546 |
+
|
1547 |
+
/**
|
1548 |
+
* Divides a BigInteger by a regular integer
|
1549 |
+
*
|
1550 |
+
* abc / x = a00 / x + b0 / x + c / x
|
1551 |
+
*
|
1552 |
+
* @param Array $dividend
|
1553 |
+
* @param Array $divisor
|
1554 |
+
* @return Array
|
1555 |
+
* @access private
|
1556 |
+
*/
|
1557 |
+
function _divide_digit($dividend, $divisor)
|
1558 |
+
{
|
1559 |
+
$carry = 0;
|
1560 |
+
$result = array();
|
1561 |
+
|
1562 |
+
for ($i = count($dividend) - 1; $i >= 0; --$i) {
|
1563 |
+
$temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
|
1564 |
+
$result[$i] = (int) ($temp / $divisor);
|
1565 |
+
$carry = (int) ($temp - $divisor * $result[$i]);
|
1566 |
+
}
|
1567 |
+
|
1568 |
+
return array($result, $carry);
|
1569 |
+
}
|
1570 |
+
|
1571 |
+
/**
|
1572 |
+
* Performs modular exponentiation.
|
1573 |
+
*
|
1574 |
+
* Here's an example:
|
1575 |
+
* <code>
|
1576 |
+
* <?php
|
1577 |
+
* include('Math/BigInteger.php');
|
1578 |
+
*
|
1579 |
+
* $a = new Math_BigInteger('10');
|
1580 |
+
* $b = new Math_BigInteger('20');
|
1581 |
+
* $c = new Math_BigInteger('30');
|
1582 |
+
*
|
1583 |
+
* $c = $a->modPow($b, $c);
|
1584 |
+
*
|
1585 |
+
* echo $c->toString(); // outputs 10
|
1586 |
+
* ?>
|
1587 |
+
* </code>
|
1588 |
+
*
|
1589 |
+
* @param Math_BigInteger $e
|
1590 |
+
* @param Math_BigInteger $n
|
1591 |
+
* @return Math_BigInteger
|
1592 |
+
* @access public
|
1593 |
+
* @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
|
1594 |
+
* and although the approach involving repeated squaring does vastly better, it, too, is impractical
|
1595 |
+
* for our purposes. The reason being that division - by far the most complicated and time-consuming
|
1596 |
+
* of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
|
1597 |
+
*
|
1598 |
+
* Modular reductions resolve this issue. Although an individual modular reduction takes more time
|
1599 |
+
* then an individual division, when performed in succession (with the same modulo), they're a lot faster.
|
1600 |
+
*
|
1601 |
+
* The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
|
1602 |
+
* although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
|
1603 |
+
* base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
|
1604 |
+
* the product of two odd numbers is odd), but what about when RSA isn't used?
|
1605 |
+
*
|
1606 |
+
* In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
|
1607 |
+
* Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
|
1608 |
+
* modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
|
1609 |
+
* uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
|
1610 |
+
* the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
|
1611 |
+
* {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
|
1612 |
+
*/
|
1613 |
+
function modPow($e, $n)
|
1614 |
+
{
|
1615 |
+
$n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
|
1616 |
+
|
1617 |
+
if ($e->compare(new Math_BigInteger()) < 0) {
|
1618 |
+
$e = $e->abs();
|
1619 |
+
|
1620 |
+
$temp = $this->modInverse($n);
|
1621 |
+
if ($temp === false) {
|
1622 |
+
return false;
|
1623 |
+
}
|
1624 |
+
|
1625 |
+
return $this->_normalize($temp->modPow($e, $n));
|
1626 |
+
}
|
1627 |
+
|
1628 |
+
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
|
1629 |
+
$temp = new Math_BigInteger();
|
1630 |
+
$temp->value = gmp_powm($this->value, $e->value, $n->value);
|
1631 |
+
|
1632 |
+
return $this->_normalize($temp);
|
1633 |
+
}
|
1634 |
+
|
1635 |
+
if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
|
1636 |
+
list(, $temp) = $this->divide($n);
|
1637 |
+
return $temp->modPow($e, $n);
|
1638 |
+
}
|
1639 |
+
|
1640 |
+
if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
1641 |
+
$components = array(
|
1642 |
+
'modulus' => $n->toBytes(true),
|
1643 |
+
'publicExponent' => $e->toBytes(true)
|
1644 |
+
);
|
1645 |
+
|
1646 |
+
$components = array(
|
1647 |
+
'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
|
1648 |
+
'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
|
1649 |
+
);
|
1650 |
+
|
1651 |
+
$RSAPublicKey = pack('Ca*a*a*',
|
1652 |
+
48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
1653 |
+
$components['modulus'], $components['publicExponent']
|
1654 |
+
);
|
1655 |
+
|
1656 |
+
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
|
1657 |
+
$RSAPublicKey = chr(0) . $RSAPublicKey;
|
1658 |
+
$RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
|
1659 |
+
|
1660 |
+
$encapsulated = pack('Ca*a*',
|
1661 |
+
48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
|
1662 |
+
);
|
1663 |
+
|
1664 |
+
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
|
1665 |
+
chunk_split(base64_encode($encapsulated)) .
|
1666 |
+
'-----END PUBLIC KEY-----';
|
1667 |
+
|
1668 |
+
$plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
|
1669 |
+
|
1670 |
+
if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
|
1671 |
+
return new Math_BigInteger($result, 256);
|
1672 |
+
}
|
1673 |
+
}
|
1674 |
+
|
1675 |
+
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
|
1676 |
+
$temp = new Math_BigInteger();
|
1677 |
+
$temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
|
1678 |
+
|
1679 |
+
return $this->_normalize($temp);
|
1680 |
+
}
|
1681 |
+
|
1682 |
+
if ( empty($e->value) ) {
|
1683 |
+
$temp = new Math_BigInteger();
|
1684 |
+
$temp->value = array(1);
|
1685 |
+
return $this->_normalize($temp);
|
1686 |
+
}
|
1687 |
+
|
1688 |
+
if ( $e->value == array(1) ) {
|
1689 |
+
list(, $temp) = $this->divide($n);
|
1690 |
+
return $this->_normalize($temp);
|
1691 |
+
}
|
1692 |
+
|
1693 |
+
if ( $e->value == array(2) ) {
|
1694 |
+
$temp = new Math_BigInteger();
|
1695 |
+
$temp->value = $this->_square($this->value);
|
1696 |
+
list(, $temp) = $temp->divide($n);
|
1697 |
+
return $this->_normalize($temp);
|
1698 |
+
}
|
1699 |
+
|
1700 |
+
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
|
1701 |
+
|
1702 |
+
// is the modulo odd?
|
1703 |
+
if ( $n->value[0] & 1 ) {
|
1704 |
+
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
|
1705 |
+
}
|
1706 |
+
// if it's not, it's even
|
1707 |
+
|
1708 |
+
// find the lowest set bit (eg. the max pow of 2 that divides $n)
|
1709 |
+
for ($i = 0; $i < count($n->value); ++$i) {
|
1710 |
+
if ( $n->value[$i] ) {
|
1711 |
+
$temp = decbin($n->value[$i]);
|
1712 |
+
$j = strlen($temp) - strrpos($temp, '1') - 1;
|
1713 |
+
$j+= 26 * $i;
|
1714 |
+
break;
|
1715 |
+
}
|
1716 |
+
}
|
1717 |
+
// at this point, 2^$j * $n/(2^$j) == $n
|
1718 |
+
|
1719 |
+
$mod1 = $n->copy();
|
1720 |
+
$mod1->_rshift($j);
|
1721 |
+
$mod2 = new Math_BigInteger();
|
1722 |
+
$mod2->value = array(1);
|
1723 |
+
$mod2->_lshift($j);
|
1724 |
+
|
1725 |
+
$part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
|
1726 |
+
$part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
|
1727 |
+
|
1728 |
+
$y1 = $mod2->modInverse($mod1);
|
1729 |
+
$y2 = $mod1->modInverse($mod2);
|
1730 |
+
|
1731 |
+
$result = $part1->multiply($mod2);
|
1732 |
+
$result = $result->multiply($y1);
|
1733 |
+
|
1734 |
+
$temp = $part2->multiply($mod1);
|
1735 |
+
$temp = $temp->multiply($y2);
|
1736 |
+
|
1737 |
+
$result = $result->add($temp);
|
1738 |
+
list(, $result) = $result->divide($n);
|
1739 |
+
|
1740 |
+
return $this->_normalize($result);
|
1741 |
+
}
|
1742 |
+
|
1743 |
+
/**
|
1744 |
+
* Performs modular exponentiation.
|
1745 |
+
*
|
1746 |
+
* Alias for Math_BigInteger::modPow()
|
1747 |
+
*
|
1748 |
+
* @param Math_BigInteger $e
|
1749 |
+
* @param Math_BigInteger $n
|
1750 |
+
* @return Math_BigInteger
|
1751 |
+
* @access public
|
1752 |
+
*/
|
1753 |
+
function powMod($e, $n)
|
1754 |
+
{
|
1755 |
+
return $this->modPow($e, $n);
|
1756 |
+
}
|
1757 |
+
|
1758 |
+
/**
|
1759 |
+
* Sliding Window k-ary Modular Exponentiation
|
1760 |
+
*
|
1761 |
+
* Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
|
1762 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
|
1763 |
+
* however, this function performs a modular reduction after every multiplication and squaring operation.
|
1764 |
+
* As such, this function has the same preconditions that the reductions being used do.
|
1765 |
+
*
|
1766 |
+
* @param Math_BigInteger $e
|
1767 |
+
* @param Math_BigInteger $n
|
1768 |
+
* @param Integer $mode
|
1769 |
+
* @return Math_BigInteger
|
1770 |
+
* @access private
|
1771 |
+
*/
|
1772 |
+
function _slidingWindow($e, $n, $mode)
|
1773 |
+
{
|
1774 |
+
static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
|
1775 |
+
//static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
|
1776 |
+
|
1777 |
+
$e_value = $e->value;
|
1778 |
+
$e_length = count($e_value) - 1;
|
1779 |
+
$e_bits = decbin($e_value[$e_length]);
|
1780 |
+
for ($i = $e_length - 1; $i >= 0; --$i) {
|
1781 |
+
$e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
|
1782 |
+
}
|
1783 |
+
|
1784 |
+
$e_length = strlen($e_bits);
|
1785 |
+
|
1786 |
+
// calculate the appropriate window size.
|
1787 |
+
// $window_size == 3 if $window_ranges is between 25 and 81, for example.
|
1788 |
+
for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
|
1789 |
+
|
1790 |
+
$n_value = $n->value;
|
1791 |
+
|
1792 |
+
// precompute $this^0 through $this^$window_size
|
1793 |
+
$powers = array();
|
1794 |
+
$powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
|
1795 |
+
$powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
|
1796 |
+
|
1797 |
+
// we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
|
1798 |
+
// in a 1. ie. it's supposed to be odd.
|
1799 |
+
$temp = 1 << ($window_size - 1);
|
1800 |
+
for ($i = 1; $i < $temp; ++$i) {
|
1801 |
+
$i2 = $i << 1;
|
1802 |
+
$powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
|
1803 |
+
}
|
1804 |
+
|
1805 |
+
$result = array(1);
|
1806 |
+
$result = $this->_prepareReduce($result, $n_value, $mode);
|
1807 |
+
|
1808 |
+
for ($i = 0; $i < $e_length; ) {
|
1809 |
+
if ( !$e_bits[$i] ) {
|
1810 |
+
$result = $this->_squareReduce($result, $n_value, $mode);
|
1811 |
+
++$i;
|
1812 |
+
} else {
|
1813 |
+
for ($j = $window_size - 1; $j > 0; --$j) {
|
1814 |
+
if ( !empty($e_bits[$i + $j]) ) {
|
1815 |
+
break;
|
1816 |
+
}
|
1817 |
+
}
|
1818 |
+
|
1819 |
+
for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
|
1820 |
+
$result = $this->_squareReduce($result, $n_value, $mode);
|
1821 |
+
}
|
1822 |
+
|
1823 |
+
$result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
|
1824 |
+
|
1825 |
+
$i+=$j + 1;
|
1826 |
+
}
|
1827 |
+
}
|
1828 |
+
|
1829 |
+
$temp = new Math_BigInteger();
|
1830 |
+
$temp->value = $this->_reduce($result, $n_value, $mode);
|
1831 |
+
|
1832 |
+
return $temp;
|
1833 |
+
}
|
1834 |
+
|
1835 |
+
/**
|
1836 |
+
* Modular reduction
|
1837 |
+
*
|
1838 |
+
* For most $modes this will return the remainder.
|
1839 |
+
*
|
1840 |
+
* @see _slidingWindow()
|
1841 |
+
* @access private
|
1842 |
+
* @param Array $x
|
1843 |
+
* @param Array $n
|
1844 |
+
* @param Integer $mode
|
1845 |
+
* @return Array
|
1846 |
+
*/
|
1847 |
+
function _reduce($x, $n, $mode)
|
1848 |
+
{
|
1849 |
+
switch ($mode) {
|
1850 |
+
case MATH_BIGINTEGER_MONTGOMERY:
|
1851 |
+
return $this->_montgomery($x, $n);
|
1852 |
+
case MATH_BIGINTEGER_BARRETT:
|
1853 |
+
return $this->_barrett($x, $n);
|
1854 |
+
case MATH_BIGINTEGER_POWEROF2:
|
1855 |
+
$lhs = new Math_BigInteger();
|
1856 |
+
$lhs->value = $x;
|
1857 |
+
$rhs = new Math_BigInteger();
|
1858 |
+
$rhs->value = $n;
|
1859 |
+
return $x->_mod2($n);
|
1860 |
+
case MATH_BIGINTEGER_CLASSIC:
|
1861 |
+
$lhs = new Math_BigInteger();
|
1862 |
+
$lhs->value = $x;
|
1863 |
+
$rhs = new Math_BigInteger();
|
1864 |
+
$rhs->value = $n;
|
1865 |
+
list(, $temp) = $lhs->divide($rhs);
|
1866 |
+
return $temp->value;
|
1867 |
+
case MATH_BIGINTEGER_NONE:
|
1868 |
+
return $x;
|
1869 |
+
default:
|
1870 |
+
// an invalid $mode was provided
|
1871 |
+
}
|
1872 |
+
}
|
1873 |
+
|
1874 |
+
/**
|
1875 |
+
* Modular reduction preperation
|
1876 |
+
*
|
1877 |
+
* @see _slidingWindow()
|
1878 |
+
* @access private
|
1879 |
+
* @param Array $x
|
1880 |
+
* @param Array $n
|
1881 |
+
* @param Integer $mode
|
1882 |
+
* @return Array
|
1883 |
+
*/
|
1884 |
+
function _prepareReduce($x, $n, $mode)
|
1885 |
+
{
|
1886 |
+
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
|
1887 |
+
return $this->_prepMontgomery($x, $n);
|
1888 |
+
}
|
1889 |
+
return $this->_reduce($x, $n, $mode);
|
1890 |
+
}
|
1891 |
+
|
1892 |
+
/**
|
1893 |
+
* Modular multiply
|
1894 |
+
*
|
1895 |
+
* @see _slidingWindow()
|
1896 |
+
* @access private
|
1897 |
+
* @param Array $x
|
1898 |
+
* @param Array $y
|
1899 |
+
* @param Array $n
|
1900 |
+
* @param Integer $mode
|
1901 |
+
* @return Array
|
1902 |
+
*/
|
1903 |
+
function _multiplyReduce($x, $y, $n, $mode)
|
1904 |
+
{
|
1905 |
+
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
|
1906 |
+
return $this->_montgomeryMultiply($x, $y, $n);
|
1907 |
+
}
|
1908 |
+
$temp = $this->_multiply($x, false, $y, false);
|
1909 |
+
return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
|
1910 |
+
}
|
1911 |
+
|
1912 |
+
/**
|
1913 |
+
* Modular square
|
1914 |
+
*
|
1915 |
+
* @see _slidingWindow()
|
1916 |
+
* @access private
|
1917 |
+
* @param Array $x
|
1918 |
+
* @param Array $n
|
1919 |
+
* @param Integer $mode
|
1920 |
+
* @return Array
|
1921 |
+
*/
|
1922 |
+
function _squareReduce($x, $n, $mode)
|
1923 |
+
{
|
1924 |
+
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
|
1925 |
+
return $this->_montgomeryMultiply($x, $x, $n);
|
1926 |
+
}
|
1927 |
+
return $this->_reduce($this->_square($x), $n, $mode);
|
1928 |
+
}
|
1929 |
+
|
1930 |
+
/**
|
1931 |
+
* Modulos for Powers of Two
|
1932 |
+
*
|
1933 |
+
* Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
|
1934 |
+
* we'll just use this function as a wrapper for doing that.
|
1935 |
+
*
|
1936 |
+
* @see _slidingWindow()
|
1937 |
+
* @access private
|
1938 |
+
* @param Math_BigInteger
|
1939 |
+
* @return Math_BigInteger
|
1940 |
+
*/
|
1941 |
+
function _mod2($n)
|
1942 |
+
{
|
1943 |
+
$temp = new Math_BigInteger();
|
1944 |
+
$temp->value = array(1);
|
1945 |
+
return $this->bitwise_and($n->subtract($temp));
|
1946 |
+
}
|
1947 |
+
|
1948 |
+
/**
|
1949 |
+
* Barrett Modular Reduction
|
1950 |
+
*
|
1951 |
+
* See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
|
1952 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
|
1953 |
+
* so as not to require negative numbers (initially, this script didn't support negative numbers).
|
1954 |
+
*
|
1955 |
+
* Employs "folding", as described at
|
1956 |
+
* {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
|
1957 |
+
* it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
|
1958 |
+
*
|
1959 |
+
* Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
|
1960 |
+
* usable on account of (1) its not using reasonable radix points as discussed in
|
1961 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
|
1962 |
+
* radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
|
1963 |
+
* (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
|
1964 |
+
* comments for details.
|
1965 |
+
*
|
1966 |
+
* @see _slidingWindow()
|
1967 |
+
* @access private
|
1968 |
+
* @param Array $n
|
1969 |
+
* @param Array $m
|
1970 |
+
* @return Array
|
1971 |
+
*/
|
1972 |
+
function _barrett($n, $m)
|
1973 |
+
{
|
1974 |
+
static $cache = array(
|
1975 |
+
MATH_BIGINTEGER_VARIABLE => array(),
|
1976 |
+
MATH_BIGINTEGER_DATA => array()
|
1977 |
+
);
|
1978 |
+
|
1979 |
+
$m_length = count($m);
|
1980 |
+
|
1981 |
+
// if ($this->_compare($n, $this->_square($m)) >= 0) {
|
1982 |
+
if (count($n) > 2 * $m_length) {
|
1983 |
+
$lhs = new Math_BigInteger();
|
1984 |
+
$rhs = new Math_BigInteger();
|
1985 |
+
$lhs->value = $n;
|
1986 |
+
$rhs->value = $m;
|
1987 |
+
list(, $temp) = $lhs->divide($rhs);
|
1988 |
+
return $temp->value;
|
1989 |
+
}
|
1990 |
+
|
1991 |
+
// if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
|
1992 |
+
if ($m_length < 5) {
|
1993 |
+
return $this->_regularBarrett($n, $m);
|
1994 |
+
}
|
1995 |
+
|
1996 |
+
// n = 2 * m.length
|
1997 |
+
|
1998 |
+
if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
|
1999 |
+
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
|
2000 |
+
$cache[MATH_BIGINTEGER_VARIABLE][] = $m;
|
2001 |
+
|
2002 |
+
$lhs = new Math_BigInteger();
|
2003 |
+
$lhs_value = &$lhs->value;
|
2004 |
+
$lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
|
2005 |
+
$lhs_value[] = 1;
|
2006 |
+
$rhs = new Math_BigInteger();
|
2007 |
+
$rhs->value = $m;
|
2008 |
+
|
2009 |
+
list($u, $m1) = $lhs->divide($rhs);
|
2010 |
+
$u = $u->value;
|
2011 |
+
$m1 = $m1->value;
|
2012 |
+
|
2013 |
+
$cache[MATH_BIGINTEGER_DATA][] = array(
|
2014 |
+
'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
|
2015 |
+
'm1'=> $m1 // m.length
|
2016 |
+
);
|
2017 |
+
} else {
|
2018 |
+
extract($cache[MATH_BIGINTEGER_DATA][$key]);
|
2019 |
+
}
|
2020 |
+
|
2021 |
+
$cutoff = $m_length + ($m_length >> 1);
|
2022 |
+
$lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
|
2023 |
+
$msd = array_slice($n, $cutoff); // m.length >> 1
|
2024 |
+
$lsd = $this->_trim($lsd);
|
2025 |
+
$temp = $this->_multiply($msd, false, $m1, false);
|
2026 |
+
$n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
|
2027 |
+
|
2028 |
+
if ($m_length & 1) {
|
2029 |
+
return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
|
2030 |
+
}
|
2031 |
+
|
2032 |
+
// (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
|
2033 |
+
$temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
|
2034 |
+
// if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
|
2035 |
+
// if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
|
2036 |
+
$temp = $this->_multiply($temp, false, $u, false);
|
2037 |
+
// if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
|
2038 |
+
// if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
|
2039 |
+
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
|
2040 |
+
// if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
|
2041 |
+
// if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
|
2042 |
+
$temp = $this->_multiply($temp, false, $m, false);
|
2043 |
+
|
2044 |
+
// at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
|
2045 |
+
// number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
|
2046 |
+
// following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
|
2047 |
+
|
2048 |
+
$result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
|
2049 |
+
|
2050 |
+
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
|
2051 |
+
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
|
2052 |
+
}
|
2053 |
+
|
2054 |
+
return $result[MATH_BIGINTEGER_VALUE];
|
2055 |
+
}
|
2056 |
+
|
2057 |
+
/**
|
2058 |
+
* (Regular) Barrett Modular Reduction
|
2059 |
+
*
|
2060 |
+
* For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this
|
2061 |
+
* is that this function does not fold the denominator into a smaller form.
|
2062 |
+
*
|
2063 |
+
* @see _slidingWindow()
|
2064 |
+
* @access private
|
2065 |
+
* @param Array $x
|
2066 |
+
* @param Array $n
|
2067 |
+
* @return Array
|
2068 |
+
*/
|
2069 |
+
function _regularBarrett($x, $n)
|
2070 |
+
{
|
2071 |
+
static $cache = array(
|
2072 |
+
MATH_BIGINTEGER_VARIABLE => array(),
|
2073 |
+
MATH_BIGINTEGER_DATA => array()
|
2074 |
+
);
|
2075 |
+
|
2076 |
+
$n_length = count($n);
|
2077 |
+
|
2078 |
+
if (count($x) > 2 * $n_length) {
|
2079 |
+
$lhs = new Math_BigInteger();
|
2080 |
+
$rhs = new Math_BigInteger();
|
2081 |
+
$lhs->value = $x;
|
2082 |
+
$rhs->value = $n;
|
2083 |
+
list(, $temp) = $lhs->divide($rhs);
|
2084 |
+
return $temp->value;
|
2085 |
+
}
|
2086 |
+
|
2087 |
+
if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
|
2088 |
+
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
|
2089 |
+
$cache[MATH_BIGINTEGER_VARIABLE][] = $n;
|
2090 |
+
$lhs = new Math_BigInteger();
|
2091 |
+
$lhs_value = &$lhs->value;
|
2092 |
+
$lhs_value = $this->_array_repeat(0, 2 * $n_length);
|
2093 |
+
$lhs_value[] = 1;
|
2094 |
+
$rhs = new Math_BigInteger();
|
2095 |
+
$rhs->value = $n;
|
2096 |
+
list($temp, ) = $lhs->divide($rhs); // m.length
|
2097 |
+
$cache[MATH_BIGINTEGER_DATA][] = $temp->value;
|
2098 |
+
}
|
2099 |
+
|
2100 |
+
// 2 * m.length - (m.length - 1) = m.length + 1
|
2101 |
+
$temp = array_slice($x, $n_length - 1);
|
2102 |
+
// (m.length + 1) + m.length = 2 * m.length + 1
|
2103 |
+
$temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
|
2104 |
+
// (2 * m.length + 1) - (m.length - 1) = m.length + 2
|
2105 |
+
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
|
2106 |
+
|
2107 |
+
// m.length + 1
|
2108 |
+
$result = array_slice($x, 0, $n_length + 1);
|
2109 |
+
// m.length + 1
|
2110 |
+
$temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
|
2111 |
+
// $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
|
2112 |
+
|
2113 |
+
if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
|
2114 |
+
$corrector_value = $this->_array_repeat(0, $n_length + 1);
|
2115 |
+
$corrector_value[] = 1;
|
2116 |
+
$result = $this->_add($result, false, $corrector_value, false);
|
2117 |
+
$result = $result[MATH_BIGINTEGER_VALUE];
|
2118 |
+
}
|
2119 |
+
|
2120 |
+
// at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
|
2121 |
+
$result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
|
2122 |
+
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
|
2123 |
+
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEG
|