ManageWP Worker - Version 3.9.27

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 Icon 128x128 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 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
- $this->site_name = str_replace(array(
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
- 'google_drive' => 8,
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
- $changed = array('execution_time' => 0, 'memory_limit' => 0);
115
-
116
- $memory_limit = trim(ini_get('memory_limit'));
117
- $last = strtolower(substr($memory_limit, -1));
118
-
119
- if($last == 'g')
120
- $memory_limit = ((int) $memory_limit)*1024;
121
- else if($last == 'm')
122
- $memory_limit = (int) $memory_limit;
123
- if($last == 'k')
124
- $memory_limit = ((int) $memory_limit)/1024;
125
-
126
- if ( $memory_limit < 384 ) {
127
- @ini_set('memory_limit', '384M');
128
- $changed['memory_limit'] = 1;
129
- }
130
-
131
- if ( (int) @ini_get('max_execution_time') < 600 ) {
132
- @set_time_limit(600); //ten minutes
133
- $changed['execution_time'] = 1;
134
- }
135
-
136
- return $changed;
137
- }
138
-
139
- /**
140
- * Returns backup settings from local database for all tasks
141
- *
142
- * @return mixed|boolean
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
- //Make sure backup cron job is set
164
- if (!wp_next_scheduled('mwp_backup_tasks')) {
165
- wp_schedule_event( time(), 'tenminutes', 'mwp_backup_tasks' );
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
- $result = $this->backup($args, $task_name);
213
  $backup_settings = $this->tasks;
214
-
215
  if (is_array($result) && array_key_exists('error', $result)) {
216
- $return = $result;
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
- $this->check_cron_remove();
235
-
236
- $failed_emails = array();
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
- 'worker_version' => MMB_WORKER_VERSION
249
  );
250
-
251
  if (isset($setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'])) {
252
- $check_data['mwp_google_drive_refresh_token'] = true;
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
- $potential_token = substr($check, 8);
266
- if (substr($check, 0, 8) == 'token - ' && $potential_token != 'not found') {
267
- $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
268
- $settings[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
269
- $setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
270
- }
271
  } else {
272
- $potential_token = isset($check['google_drive_token']) ? $check['google_drive_token'] : false;
273
- if ($potential_token) {
274
- $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
275
- $settings[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
276
- $setting['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $potential_token;
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
- $update['time'] = time();
289
  }
290
-
291
  //Update task with next schedule
292
  $this->set_backup_task($update);
293
-
294
- $result = $this->backup($setting['task_args'], $task_name);
295
  $error = '';
296
-
297
  if (is_array($result) && array_key_exists('error', $result)) {
298
- $error = $result;
299
- $this->set_backup_task(array(
300
- 'task_name' => $task_name,
301
- 'args' => $settings[$task_name]['task_args'],
302
- 'error' => $error
303
- ));
304
  } else {
305
- if (@count($setting['task_args']['account_info'])) {
306
- // Old way through sheduling.
307
- // wp_schedule_single_event(time(), 'mmb_scheduled_remote_upload', array('args' => array('task_name' => $task_name)));
308
- $nonce = substr(wp_hash(wp_nonce_tick() . 'mmb-backup-nonce' . 0, 'nonce'), -12, 10);
309
- $cron_url = site_url('index.php');
310
- $backup_file = $this->tasks[$task_name]['task_results'][count($this->tasks[$task_name]['task_results']) - 1]['server']['file_url'];
311
- $del_host_file = $this->tasks[$task_name]['task_args']['del_host_file'];
312
- $public_key = get_option('_worker_public_key');
313
- $args = array(
314
- 'body' => array(
315
- 'backup_cron_action' => 'mmb_remote_upload',
316
- 'args' => json_encode(array('task_name' => $task_name, 'backup_file' => $backup_file, 'del_host_file' => $del_host_file)),
317
- 'mmb_backup_nonce' => $nonce,
318
- 'public_key' => $public_key,
319
- ),
320
- 'timeout' => 0.01,
321
- 'blocking' => false,
322
- 'sslverify' => apply_filters('https_local_ssl_verify', true)
323
- );
324
- wp_remote_post($cron_url, $args);
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
- if ($google_drive_token) {
344
- $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
345
- }
346
-
347
- $settings = $this->tasks;
348
- if(!array_key_exists($task_name,$settings)){
349
- return array('error' => $task_name." does not exist.");
350
- } else {
351
- $setting = $settings[$task_name];
352
- }
353
-
354
- $this->set_backup_task(array(
355
- 'task_name' => $task_name,
356
- 'args' => $settings[$task_name]['task_args'],
357
- 'time' => time()
358
- ));
359
-
360
- //Run backup
361
- $result = $this->backup($setting['task_args'], $task_name);
362
-
363
- //Check for error
364
- if (is_array($result) && array_key_exists('error', $result)) {
365
- $this->set_backup_task(array(
366
- 'task_name' => $task_name,
367
- 'args' => $settings[$task_name]['task_args'],
368
- 'error' => $result
369
- ));
370
- return $result;
371
- } else {
372
- return $this->get_backup_stats();
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
- if (!empty($account_info)) {
396
- $found = false;
397
- $destinations = array('mwp_ftp', 'mwp_amazon_s3', 'mwp_dropbox', 'mwp_google_drive', 'mwp_email');
398
- foreach($destinations as $dest) {
399
- $found = $found || (isset($account_info[$dest]));
400
- }
401
- if (!$found) {
402
- $error_message = 'Remote destination is not supported, please update your client plugin.';
403
- return array(
404
- 'error' => $error_message
405
- );
406
- }
407
- }
408
-
409
  //Try increase memory limit and execution time
410
- $this->set_memory();
411
-
412
  //Remove old backup(s)
413
  $removed = $this->remove_old_backups($task_name);
414
  if (is_array($removed) && isset($removed['error'])) {
415
- $error_message = $removed['error'];
416
- return $removed;
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
- $error_message = 'Permission denied, make sure you have write permission to wp-content folder.';
424
  return array(
425
- 'error' => $error_message
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
- $error_message = $db_backup['error'];
449
- return array(
450
- 'error' => $error_message
451
- );
452
  }
453
  } elseif (trim($what) == 'full') {
454
  if (!$exclude) {
455
- $exclude = array();
456
  }
457
  if (!$include) {
458
- $include = array();
459
  }
460
- $content_backup = $this->backup_full($task_name, $backup_file, $exclude, $include);
461
  if (is_array($content_backup) && array_key_exists('error', $content_backup)) {
462
- $error_message = $content_backup['error'];
463
- return array(
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
- $paths['google_drive'] = basename($backup_url);
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
- $this->update_status($task_name, $this->statuses['finished'], true);
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
- $this->update_status($task_name, $this->statuses['db_dump']);
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
- $zip_archive_db_result = false;
576
- if (class_exists("ZipArchive")) {
577
- $this->_log("DB zip, fallback to ZipArchive");
578
- $zip_archive_db_result = $this->zip_archive_backup_db($task_name, $db_result, $backup_file);
579
- }
580
-
581
- if (!$zip_archive_db_result) {
582
- $this->_log("DB zip, fallback to PclZip");
583
- $pclzip_db_result = $this->pclzip_backup_db($task_name, $backup_file);
584
- if (!$pclzip_db_result) {
585
- @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
586
- @unlink($db_result);
587
- @rmdir(MWP_DB_DIR);
588
 
589
  if($archive->error_code!=''){
590
  $archive->error_code = 'pclZip error ('.$archive->error_code . '): .';
591
  }
592
- return array(
593
- 'error' => 'Failed to zip database. ' . $archive->error_code . $archive->error_string
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
- trim(basename(WP_CONTENT_DIR)) . "/managewp/backups",
605
- trim(basename(WP_CONTENT_DIR)) . "/" . md5('mmb-worker') . "/mwp_backups"
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
- return $zip_result;
616
  }
617
-
618
  if (!$zip_result) {
619
- $zip_archive_result = false;
620
- if (class_exists("ZipArchive")) {
621
- $this->_log("Files zip fallback to ZipArchive");
622
- $zip_archive_result = $this->zip_archive_backup($task_name, $backup_file, $exclude, $include);
623
- }
624
-
625
- if (!$zip_archive_result) {
626
- $this->_log("Files zip fallback to PclZip");
627
- $pclzip_result = $this->pclzip_backup($task_name, $backup_file, $exclude, $include);
628
- if (!$pclzip_result) {
629
- @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
630
- @unlink($db_result);
631
- @rmdir(MWP_DB_DIR);
632
-
633
- if (!$pclzip_result) {
634
- @unlink($backup_file);
635
- return array(
636
- 'error' => 'Failed to zip files. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
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
- $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
659
- $comp_level = $disable_comp ? '-0' : '-1';
660
- $zip = $this->get_zip();
661
- //Add database file
662
- chdir(MWP_BACKUP_DIR);
663
- $command = "$zip -q -r $comp_level $backup_file 'mwp_db'";
664
-
665
- ob_start();
666
- $this->_log("Executing $command");
667
- $result = $this->mmb_exec($command);
668
- ob_get_clean();
669
-
670
- return $result;
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
- $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
683
- if (!$disable_comp) {
684
- $this->_log("Compression is not supported by ZipArchive");
685
- }
686
- $zip = new ZipArchive();
687
- $result = $zip->open($backup_file, ZIPARCHIVE::OVERWRITE); // Tries to open $backup_file for acrhiving
688
- if ($result === true) {
689
- $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
690
- $result = $result && $zip->addFile($db_result, "mwp_db/" . basename($db_result)); // Tries to add db dump form mwp_db dir to $backup_file
691
- $result = $result && $zip->close(); // Tries to close $backup_file
692
- } else {
693
- $result = false;
694
- }
695
-
696
- return $result; // true if $backup_file iz zipped successfully, false if error is occured in zip process
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
- $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
708
- define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
709
- require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
710
- $zip = new PclZip($backup_file);
711
-
712
- if ($disable_comp) {
713
- $result = $zip->add(MWP_BACKUP_DIR, PCLZIP_OPT_REMOVE_PATH, MWP_BACKUP_DIR, PCLZIP_OPT_NO_COMPRESSION) !== 0;
714
- } else {
715
- $result = $zip->add(MWP_BACKUP_DIR, PCLZIP_OPT_REMOVE_PATH, MWP_BACKUP_DIR) !== 0;
716
- }
717
-
718
- return $result;
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
- $filelist = $this->get_backup_files($exclude, $include);
845
- $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
846
- if (!$disable_comp) {
847
- $this->_log("Compression is not supported by ZipArchive");
848
- }
849
-
850
- $zip = new ZipArchive();
851
- if ($overwrite) {
852
- $result = $zip->open($backup_file, ZipArchive::OVERWRITE); // Tries to open $backup_file for acrhiving
853
- } else {
854
- $result = $zip->open($backup_file); // Tries to open $backup_file for acrhiving
855
- }
856
- if ($result === true) {
857
- foreach ($filelist as $file) {
858
- $result = $result && $zip->addFile($file, sprintf("%s", str_replace(ABSPATH, '', $file))); // Tries to add a new file to $backup_file
859
- }
860
- $result = $result && $zip->close(); // Tries to close $backup_file
861
- } else {
862
- $result = false;
863
- }
864
-
865
- return $result; // true if $backup_file iz zipped successfully, false if error is occured in zip process
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
- define('PCLZIP_TEMPORARY_DIR', MWP_BACKUP_DIR . '/');
880
- require_once ABSPATH . '/wp-admin/includes/class-pclzip.php';
881
- $zip = new PclZip($backup_file);
882
- $add = array(
883
- trim(WPINC),
884
- trim(basename(WP_CONTENT_DIR)),
885
- "wp-admin"
886
- );
887
-
888
- $include_data = array();
889
- if (!empty($include)) {
890
- foreach ($include as $data) {
891
- if ($data && file_exists(ABSPATH . $data))
892
- $include_data[] = ABSPATH . $data . '/';
893
- }
894
- }
895
- $include_data = array_merge($add, $include_data);
896
-
897
- if ($handle = opendir(ABSPATH)) {
898
- while (false !== ($file = readdir($handle))) {
899
- if ($file != "." && $file != ".." && !is_dir($file) && file_exists(ABSPATH . $file)) {
900
- $include_data[] = ABSPATH . $file;
901
- }
902
- }
903
- closedir($handle);
904
- }
905
-
906
- $disable_comp = $this->tasks[$task_name]['task_args']['disable_comp'];
907
-
908
- if ($disable_comp) {
909
- $result = $zip->add($include_data, PCLZIP_OPT_REMOVE_PATH, ABSPATH, PCLZIP_OPT_NO_COMPRESSION) !== 0;
910
- } else {
911
- $result = $zip->add($include_data, PCLZIP_OPT_REMOVE_PATH, ABSPATH) !== 0;
912
- }
913
-
914
- $exclude_data = array();
915
- if (!empty($exclude)) {
916
- foreach ($exclude as $data) {
917
- if (file_exists(ABSPATH . $data)) {
918
- if (is_dir(ABSPATH . $data))
919
- $exclude_data[] = $data . '/';
920
- else
921
- $exclude_data[] = $data;
922
- }
923
- }
924
- }
925
- $result = $result && $zip->delete(PCLZIP_OPT_BY_NAME, $exclude_data);
926
-
927
- return $result;
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
- $add = array(
941
- trim(WPINC),
942
- trim(basename(WP_CONTENT_DIR)),
943
- "wp-admin"
944
- );
945
-
946
- $include = array_merge($add, $include);
947
-
948
- $filelist = array();
949
- if ($handle = opendir(ABSPATH)) {
950
- while (false !== ($file = readdir($handle))) {
951
- if (is_dir($file) && file_exists(ABSPATH . $file) && !(in_array($file, $include))) {
952
- $exclude[] = $file;
953
- }
954
- }
955
- closedir($handle);
956
- }
957
-
958
- $filelist = get_all_files_from_dir(ABSPATH, $exclude);
959
-
960
- return $filelist;
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
- $this->update_status($task_name, $this->statuses['db_dump']);
973
- $db_result = $this->backup_db();
974
-
975
- if ($db_result == false) {
976
- return array(
977
- 'error' => 'Failed to backup database.'
978
- );
979
- } else if (is_array($db_result) && isset($db_result['error'])) {
980
- return array(
981
- 'error' => $db_result['error']
982
- );
983
- }
984
-
985
- $this->update_status($task_name, $this->statuses['db_dump'], true);
986
- $this->update_status($task_name, $this->statuses['db_zip']);
987
- @file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
988
- $zip_db_result = $this->zip_backup_db($task_name, $backup_file);
989
-
990
- if (!$zip_db_result) {
991
- $zip_archive_db_result = false;
992
- if (class_exists("ZipArchive")) {
993
- $this->_log("DB zip, fallback to ZipArchive");
994
- $zip_archive_db_result = $this->zip_archive_backup_db($task_name, $db_result, $backup_file);
995
- }
996
-
997
- if (!$zip_archive_db_result) {
998
- $this->_log("DB zip, fallback to PclZip");
999
- $pclzip_db_result = $this->pclzip_backup_db($task_name, $backup_file);
1000
- if (!$pclzip_db_result) {
1001
- @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
1002
- @unlink($db_result);
1003
- @rmdir(MWP_DB_DIR);
1004
-
1005
- return array(
1006
- 'error' => 'Failed to zip database. pclZip error (' . $archive->error_code . '): .' . $archive->error_string
1007
- );
1008
- }
1009
- }
1010
- }
1011
-
1012
- @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
1013
- @unlink($db_result);
1014
- @rmdir(MWP_DB_DIR);
1015
-
1016
- $this->update_status($task_name, $this->statuses['db_zip'], true);
1017
-
1018
- return true;
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
- $this->_log("DB dump fallback to php");
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
- function backup_db_php($file) {
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
- $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
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
- } elseif (isset($task['task_results'][$result_id]['amazons3'])) {
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- $dropbox_file = $task['task_results'][$result_id]['dropbox'];
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
- return array(
1244
- 'error' => 'Failed to download file from Google Drive, reason: ' . $backup_file['error']
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
- $restore_options = array();
1291
- $restore_options['mwp_notifications'] = get_option('mwp_notifications');
1292
- $restore_options['mwp_pageview_alerts'] = get_option('mwp_pageview_alerts');
1293
- $restore_options['user_hit_count'] = get_option('user_hit_count');
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
- $this->_log("Files uznip fallback to pclZip");
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
- return array(
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
- $wpdb->query($query);
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
- //restore worker options
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
- return array('error' => 'Cannot access database file.');
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
- $this->_log('DB restore fallback to PHP');
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
- $local_query = 'SHOW TABLE STATUS FROM `'. DB_NAME.'`';
1539
- $result = mysql_query($local_query);
1540
- if (mysql_num_rows($result)){
1541
- while ($row = mysql_fetch_array($result))
1542
- {
1543
- $local_query = 'OPTIMIZE TABLE '.$row[0];
1544
- $resultat = mysql_query($local_query);
 
 
 
 
 
 
 
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
- $this->_log("Type: exec");
1616
- $this->_log("Command: ".$command);
1617
- $this->_log("Return: ".$return);
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
- $this->_log("Type: system");
1627
- $this->_log("Command: ".$command);
1628
- $this->_log("Return: ".$return);
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
- $this->_log("Return: ".$return);
1641
  if ($rawreturn)
1642
  return $return;
1643
-
1644
  return $return ? false : true;
1645
  }
1646
-
1647
  if ($rawreturn)
1648
- return -1;
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
- $reqs = array();
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
- $exec_time = ini_get('max_execution_time');
1747
- $reqs['Execution time']['status'] .= $exec_time ? ' (will try '.$exec_time . 's)' : ' (unknown)';
1748
  }
1749
  if($changed['memory_limit']){
1750
- $mem_limit = ini_get('memory_limit');
1751
- $reqs['Memory limit']['status'] .= $mem_limit ? ' (will try '.$mem_limit.')' : ' (unknown)';
1752
  }
1753
-
1754
  if(defined('MWP_SHOW_LOG') && MWP_SHOW_LOG == true){
1755
- $md5 = get_option('mwp_log_md5');
1756
- if ($md5 !== false) {
1757
- global $mmb_plugin_url;
1758
- $md5 = "<a href='$mmb_plugin_url/log_$md5' target='_blank'>$md5</a>";
1759
- } else {
1760
- $md5 = "not created";
1761
- }
1762
- $reqs['Backup Log']['status'] = $md5;
1763
- $reqs['Backup Log']['pass'] = true;
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
- return array(
1833
- 'error' => 'Failed to connect to ' . $ftp_hostname,
1834
- 'partial' => 1
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
- @ftp_pasv($conn_id,true);
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
- @ftp_pasv($conn_id,true);
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
- @ftp_pasv($conn_id,true);
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
- * Uploads backup file from server to Dropbox.
1981
  *
1982
  * @param array $args arguments passed to the function
1983
- * [consumer_key] -> consumer key of ManageWP Dropbox application
1984
- * [consumer_secret] -> consumer secret of ManageWP Dropbox application
1985
- * [oauth_token] -> oauth token of user on ManageWP Dropbox application
1986
- * [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
1987
- * [dropbox_destination] -> folder on user's Dropbox account which backup file should be upload to
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 bool|array true is successful, array with error message if not
1991
  */
1992
- function dropbox_backup($args) {
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
- $dropbox_destination .= '/' . $this->site_name . '/' . basename($backup_file);
2003
  else
2004
- $dropbox_destination .= '/' . basename($backup_file);
2005
-
2006
  try {
2007
- $dropbox->upload($backup_file, $dropbox_destination, true);
2008
  } catch (Exception $e) {
2009
- $this->_log($e->getMessage());
2010
- return array(
2011
- 'error' => $e->getMessage(),
2012
- 'partial' => 1
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
- extract($args);
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
- $dropbox_destination .= '/' . $this->site_name;
2043
-
2044
- try {
2045
- $dropbox->fileopsDelete($dropbox_destination . '/' . $backup_file);
2046
- } catch (Exception $e) {
2047
- $this->_log($e->getMessage());
2048
- /*return array(
2049
- 'error' => $e->getMessage(),
2050
- 'partial' => 1
2051
- );*/
2052
- }
2053
-
2054
- //return true;
2055
- }
2056
-
2057
- /**
2058
- * Downloads backup file from Dropbox to root folder on local server.
2059
- *
2060
- * @param array $args arguments passed to the function
2061
- * [consumer_key] -> consumer key of ManageWP Dropbox application
2062
- * [consumer_secret] -> consumer secret of ManageWP Dropbox application
2063
- * [oauth_token] -> oauth token of user on ManageWP Dropbox application
2064
- * [oauth_token_secret] -> oauth token secret of user on ManageWP Dropbox application
2065
- * [dropbox_destination] -> folder on user's Dropbox account which backup file should be deleted from
2066
- * [dropbox_site_folder] -> subfolder with site name in dropbox_destination which backup file should be deleted from
2067
- * [backup_file] -> absolute path of backup file on local server
2068
- * @return bool|array absolute path to downloaded file is successful, array with error message if not
2069
- */
2070
- function get_dropbox_backup($args) {
2071
- extract($args);
2072
-
2073
- global $mmb_plugin_dir;
2074
- require_once $mmb_plugin_dir . '/lib/dropbox.php';
2075
-
2076
- $dropbox = new Dropbox($consumer_key, $consumer_secret);
2077
  $dropbox->setOAuthTokens($oauth_token, $oauth_token_secret);
2078
-
2079
  if ($dropbox_site_folder == true)
2080
- $dropbox_destination .= '/' . $this->site_name;
2081
-
2082
- $temp = ABSPATH . 'mwp_temp_backup.zip';
2083
-
2084
- try {
2085
- $file = $dropbox->download($dropbox_destination.'/'.$backup_file);
2086
- $handle = @fopen($temp, 'w');
2087
- $result = fwrite($handle,$file);
2088
- fclose($handle);
2089
-
2090
- if($result)
2091
- return $temp;
2092
- else
2093
- return false;
2094
- } catch (Exception $e) {
2095
- $this->_log($e->getMessage());
2096
- return array(
2097
- 'error' => $e->getMessage(),
2098
- 'partial' => 1
2099
- );
2100
- }
2101
- }
2102
-
2103
- /**
2104
- * Uploads backup file from server to Amazon S3.
2105
- *
2106
- * @param array $args arguments passed to the function
2107
- * [as3_bucket_region] -> Amazon S3 bucket region
2108
- * [as3_bucket] -> Amazon S3 bucket
2109
- * [as3_access_key] -> Amazon S3 access key
2110
- * [as3_secure_key] -> Amazon S3 secure key
2111
- * [as3_directory] -> folder on user's Amazon S3 account which backup file should be upload to
2112
- * [as3_site_folder] -> subfolder with site name in as3_directory which backup file should be upload to
2113
- * [backup_file] -> absolute path of backup file on local server
2114
- * @return bool|array true is successful, array with error message if not
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
- $s3 = new mwpS3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
2127
- if ($s3->putObjectFile($backup_file, $as3_bucket, $as3_directory . '/' . basename($backup_file), mwpS3::ACL_PRIVATE)) {
2128
- return true;
2129
- } else {
2130
- return array(
2131
- 'error' => 'Failed to upload to Amazon S3. Please check your details and set upload/delete permissions on your bucket.',
2132
- 'partial' => 1
2133
- );
2134
- }
2135
- } catch (Exception $e) {
2136
- $err = $e->getMessage();
2137
- if($err){
2138
- return array(
2139
- 'error' => 'Failed to upload to AmazonS3 ('.$err.').'
2140
- );
2141
- } else {
2142
- return array(
2143
- 'error' => 'Failed to upload to Amazon S3.'
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
- if ($this->mmb_function_exists('curl_init')) {
2173
- require_once('lib/s3.php');
2174
- extract($args);
2175
- if ($as3_site_folder == true)
2176
- $as3_directory .= '/' . $this->site_name;
2177
- $endpoint = isset($as3_bucket_region) ? $as3_bucket_region : 's3.amazonaws.com';
2178
- try {
2179
- $s3 = new mwpS3(trim($as3_access_key), trim(str_replace(' ', '+', $as3_secure_key)), false, $endpoint);
2180
- $s3->deleteObject($as3_bucket, $as3_directory . '/' . $backup_file);
2181
- } catch (Exception $e){
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
- $s3 = new mwpS3($as3_access_key, str_replace(' ', '+', $as3_secure_key), false, $endpoint);
2207
- if ($as3_site_folder == true)
2208
- $as3_directory .= '/' . $this->site_name;
2209
-
2210
- $temp = ABSPATH . 'mwp_temp_backup.zip';
2211
- $s3->getObject($as3_bucket, $as3_directory . '/' . $backup_file, $temp);
2212
- } catch (Exception $e) {
2213
- return $temp;
2214
- }
2215
- return $temp;
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
- extract($args);
2230
-
2231
- global $mmb_plugin_dir;
2232
- require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
2233
- require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
2234
-
2235
- $gdrive_client = new Google_Client();
2236
- $gdrive_client->setUseObjects(true);
2237
- $gdrive_client->setAccessToken($google_drive_token);
2238
-
2239
- $gdrive_service = new Google_DriveService($gdrive_client);
2240
-
2241
- try {
2242
- $about = $gdrive_service->about->get();
2243
- $root_folder_id = $about->getRootFolderId();
2244
- } catch (Exception $e) {
2245
- return array(
2246
- 'error' => $e->getMessage(),
2247
- );
2248
- }
2249
-
2250
- try {
2251
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
2252
- $files = $list_files->getItems();
2253
- } catch (Exception $e) {
2254
- return array(
2255
- 'error' => $e->getMessage(),
2256
- );
2257
- }
2258
- if (isset($files[0])) {
2259
- $managewp_folder = $files[0];
2260
- }
2261
-
2262
- if (!isset($managewp_folder)) {
2263
- try {
2264
- $_managewp_folder = new Google_DriveFile();
2265
- $_managewp_folder->setTitle($google_drive_directory);
2266
- $_managewp_folder->setMimeType('application/vnd.google-apps.folder');
2267
-
2268
- if ($root_folder_id != null) {
2269
- $parent = new Google_ParentReference();
2270
- $parent->setId($root_folder_id);
2271
- $_managewp_folder->setParents(array($parent));
2272
- }
2273
-
2274
- $managewp_folder = $gdrive_service->files->insert($_managewp_folder, array());
2275
- } catch (Exception $e) {
2276
- return array(
2277
- 'error' => $e->getMessage(),
2278
- );
2279
- }
2280
- }
2281
-
2282
- if ($google_drive_site_folder) {
2283
- try {
2284
- $subfolder_title = $this->site_name;
2285
- $managewp_folder_id = $managewp_folder->getId();
2286
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
2287
- $files = $list_files->getItems();
2288
- } catch (Exception $e) {
2289
- return array(
2290
- 'error' => $e->getMessage(),
2291
- );
2292
- }
2293
- if (isset($files[0])) {
2294
- $backup_folder = $files[0];
2295
- } else {
2296
- try {
2297
- $_backup_folder = new Google_DriveFile();
2298
- $_backup_folder->setTitle($subfolder_title);
2299
- $_backup_folder->setMimeType('application/vnd.google-apps.folder');
2300
-
2301
- if (isset($managewp_folder)) {
2302
- $_backup_folder->setParents(array($managewp_folder));
2303
- }
2304
-
2305
- $backup_folder = $gdrive_service->files->insert($_backup_folder, array());
2306
- } catch (Exception $e) {
2307
- return array(
2308
- 'error' => $e->getMessage(),
2309
- );
2310
- }
2311
- }
2312
- } else {
2313
- $backup_folder = $managewp_folder;
2314
- }
2315
-
2316
- $file_path = explode('/', $backup_file);
2317
- $new_file = new Google_DriveFile();
2318
- $new_file->setTitle(end($file_path));
2319
- $new_file->setDescription('Backup file of site: ' . $this->site_name . '.');
2320
-
2321
- if ($backup_folder != null) {
2322
- $new_file->setParents(array($backup_folder));
2323
- }
2324
-
2325
- $tries = 1;
2326
-
2327
- while($tries <= 2) {
2328
- try {
2329
- $data = file_get_contents($backup_file);
2330
-
2331
- $createdFile = $gdrive_service->files->insert($new_file, array(
2332
- 'data' => $data,
2333
- ));
2334
-
2335
- break;
2336
- } catch (Exception $e) {
2337
- if ($e->getCode() >= 500 && $e->getCode() <= 504 && $mmb_gdrive_upload_tries <= 2) {
2338
- sleep(2);
2339
- $tries++;
2340
- } else {
2341
- return array(
2342
- 'error' => $e->getMessage(),
2343
- );
2344
- }
2345
- }
2346
- }
2347
-
2348
- return true;
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
- extract($args);
2363
-
2364
- global $mmb_plugin_dir;
2365
- require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
2366
- require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
2367
-
2368
- try {
2369
- $gdrive_client = new Google_Client();
2370
- $gdrive_client->setUseObjects(true);
2371
- $gdrive_client->setAccessToken($google_drive_token);
2372
- } catch (Exception $e) {
2373
- $this->_log($e->getMessage());
2374
- /*eturn array(
2375
- 'error' => $e->getMessage(),
2376
- );*/
2377
- }
2378
-
2379
- $gdrive_service = new Google_DriveService($gdrive_client);
2380
-
2381
- try {
2382
- $about = $gdrive_service->about->get();
2383
- $root_folder_id = $about->getRootFolderId();
2384
- } catch (Exception $e) {
2385
- $this->_log($e->getMessage());
2386
- /*return array(
2387
- 'error' => $e->getMessage(),
2388
- );*/
2389
- }
2390
-
2391
- try {
2392
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
2393
- $files = $list_files->getItems();
2394
- } catch (Exception $e) {
2395
- $this->_log($e->getMessage());
2396
- /*return array(
2397
- 'error' => $e->getMessage(),
2398
- );*/
2399
- }
2400
- if (isset($files[0])) {
2401
- $managewp_folder = $files[0];
2402
- } else {
2403
- $this->_log("This file does not exist.");
2404
- /*return array(
2405
- 'error' => "This file does not exist.",
2406
- );*/
2407
- }
2408
-
2409
- if ($google_drive_site_folder) {
2410
- try {
2411
- $subfolder_title = $this->site_name;
2412
- $managewp_folder_id = $managewp_folder->getId();
2413
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
2414
- $files = $list_files->getItems();
2415
- } catch (Exception $e) {
2416
- $this->_log($e->getMessage());
2417
- /*return array(
2418
- 'error' => $e->getMessage(),
2419
- );*/
2420
- }
2421
- if (isset($files[0])) {
2422
- $backup_folder = $files[0];
2423
- }
2424
- } else {
2425
- $backup_folder = $managewp_folder;
2426
- }
2427
-
2428
- if (isset($backup_folder)) {
2429
- try {
2430
- $backup_folder_id = $backup_folder->getId();
2431
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$backup_file' and '$backup_folder_id' in parents and trashed = false"));
2432
- $files = $list_files->getItems();;
2433
- } catch (Exception $e) {
2434
- $this->_log($e->getMessage());
2435
- /*return array(
2436
- 'error' => $e->getMessage(),
2437
- );*/
2438
- }
2439
- if (isset($files[0])) {
2440
- try {
2441
- $gdrive_service->files->delete($files[0]->getId());
2442
- } catch (Exception $e) {
2443
- $this->_log($e->getMessage());
2444
- /*return array(
2445
- 'error' => $e->getMessage(),
2446
- );*/
2447
- }
2448
- } else {
2449
- $this->_log("This file does not exist.");
2450
- /*return array(
2451
- 'error' => "This file does not exist.",
2452
- );*/
2453
- }
2454
- } else {
2455
- $this->_log("This file does not exist.");
2456
- /*return array(
2457
- 'error' => "This file does not exist.",
2458
- );*/
2459
- }
2460
-
2461
- //return true;
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
- extract($args);
2476
-
2477
- global $mmb_plugin_dir;
2478
- require_once("$mmb_plugin_dir/lib/google-api-client/Google_Client.php");
2479
- require_once("$mmb_plugin_dir/lib/google-api-client/contrib/Google_DriveService.php");
2480
-
2481
- try {
2482
- $gdrive_client = new Google_Client();
2483
- $gdrive_client->setUseObjects(true);
2484
- $gdrive_client->setAccessToken($google_drive_token);
2485
- } catch (Exception $e) {
2486
- return array(
2487
- 'error' => $e->getMessage(),
2488
- );
2489
- }
2490
-
2491
- $gdrive_service = new Google_DriveService($gdrive_client);
2492
-
2493
- try {
2494
- $about = $gdrive_service->about->get();
2495
- $root_folder_id = $about->getRootFolderId();
2496
- } catch (Exception $e) {
2497
- return array(
2498
- 'error' => $e->getMessage(),
2499
- );
2500
- }
2501
-
2502
- try {
2503
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$google_drive_directory' and '$root_folder_id' in parents and trashed = false"));
2504
- $files = $list_files->getItems();
2505
- } catch (Exception $e) {
2506
- return array(
2507
- 'error' => $e->getMessage(),
2508
- );
2509
- }
2510
- if (isset($files[0])) {
2511
- $managewp_folder = $files[0];
2512
- } else {
2513
- return array(
2514
- 'error' => "This file does not exist.",
2515
- );
2516
- }
2517
-
2518
- if ($google_drive_site_folder) {
2519
- try {
2520
- $subfolder_title = $this->site_name;
2521
- $managewp_folder_id = $managewp_folder->getId();
2522
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$subfolder_title' and '$managewp_folder_id' in parents and trashed = false"));
2523
- $files = $list_files->getItems();
2524
- } catch (Exception $e) {
2525
- return array(
2526
- 'error' => $e->getMessage(),
2527
- );
2528
- }
2529
- if (isset($files[0])) {
2530
- $backup_folder = $files[0];
2531
- }
2532
- } else {
2533
- $backup_folder = $managewp_folder;
2534
- }
2535
-
2536
- if (isset($backup_folder)) {
2537
- try {
2538
- $backup_folder_id = $backup_folder->getId();
2539
- $list_files = $gdrive_service->files->listFiles(array("q"=>"title='$backup_file' and '$backup_folder_id' in parents and trashed = false"));
2540
- $files = $list_files->getItems();
2541
- } catch (Exception $e) {
2542
- return array(
2543
- 'error' => $e->getMessage(),
2544
- );
2545
- }
2546
- if (isset($files[0])) {
2547
- try {
2548
- $download_url = $files[0]->getDownloadUrl();
2549
- if ($download_url) {
2550
- $request = new Google_HttpRequest($download_url, 'GET', null, null);
2551
- $http_request = Google_Client::$io->authenticatedRequest($request);
2552
- if ($http_request->getResponseHttpCode() == 200) {
2553
- $stream = $http_request->getResponseBody();
2554
- $local_destination = ABSPATH . 'mwp_temp_backup.zip';
2555
- $handle = @fopen($local_destination, 'w+');
2556
- $result = fwrite($handle, $stream);
2557
- fclose($handle);
2558
- if($result)
2559
- return $local_destination;
2560
- else
2561
- return array(
2562
- 'error' => "Write permission error.",
2563
- );
2564
- } else {
2565
- return array(
2566
- 'error' => "This file does not exist.",
2567
- );
2568
- }
2569
- } else {
2570
- return array(
2571
- 'error' => "This file does not exist.",
2572
- );
2573
- }
2574
- } catch (Exception $e) {
2575
- return array(
2576
- 'error' => $e->getMessage(),
2577
- );
2578
- }
2579
- } else {
2580
- return array(
2581
- 'error' => "This file does not exist.",
2582
- );
2583
- }
2584
- } else {
2585
- return array(
2586
- 'error' => "This file does not exist.",
2587
- );
2588
- }
2589
-
2590
- return false;
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
- function schedule_next($type, $schedule) {
2601
  $schedule = explode("|", $schedule);
2602
-
2603
- if (empty($schedule))
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
- if (!file_exists($result['server']['file_path'])) {
2692
- $info['task_results'][$key]['error'] = 'Backup created but manually removed from server.';
2693
- }
2694
  }
2695
  }
2696
  }
2697
  }
2698
  if (is_array($info['task_results']))
2699
- $stats[$task_name] = array_values($info['task_results']);
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
- $this->remove_dropbox_backup($args);
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
- $google_drive_file = $backups[$task_name]['task_results'][$i]['google_drive'];
2774
- $args = $backups[$task_name]['task_args']['account_info']['mwp_google_drive'];
2775
- $args['backup_file'] = $google_drive_file;
2776
- $this->remove_google_drive_backup($args);
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
- $backups[$task_name]['task_results'] = array_values($backups[$task_name]['task_results']);
2785
  else
2786
- $backups[$task_name]['task_results']=array();
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
- $this->tasks[$task_name]['task_args']['account_info']['mwp_google_drive']['google_drive_token'] = $google_drive_token;
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
- $dropbox_file = $backup['dropbox'];
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
- $google_drive_file = $backup['google_drive'];
2844
- $args = $tasks[$task_name]['task_args']['account_info']['mwp_google_drive'];
2845
- $args['backup_file'] = $google_drive_file;
2846
- $this->remove_google_drive_backup($args);
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
- @unlink(MWP_BACKUP_DIR.'/mwp_db/index.php');
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
- foreach ($files as $file) {
2889
- @unlink($file);
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
- foreach ($new as $b) {
2898
- $files[] = $b;
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
- $this->set_memory();
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
- $this->update_status($task_name, $this->statuses['ftp']);
2959
- $account_info['mwp_ftp']['backup_file'] = $backup_file;
2960
  $return = $this->ftp_backup($account_info['mwp_ftp']);
2961
  $this->wpdb_reconnect();
2962
-
 
 
 
 
 
 
 
 
 
 
 
 
2963
  if (!(is_array($return) && isset($return['error']))) {
2964
- $this->update_status($task_name, $this->statuses['ftp'], true);
2965
- $this->update_status($task_name, $this->statuses['finished'], true);
2966
  }
2967
  }
2968
-
2969
  if (isset($account_info['mwp_amazon_s3']) && !empty($account_info['mwp_amazon_s3'])) {
2970
- $this->update_status($task_name, $this->statuses['s3']);
2971
- $account_info['mwp_amazon_s3']['backup_file'] = $backup_file;
2972
  $return = $this->amazons3_backup($account_info['mwp_amazon_s3']);
2973
  $this->wpdb_reconnect();
2974
-
2975
  if (!(is_array($return) && isset($return['error']))) {
2976
- $this->update_status($task_name, $this->statuses['s3'], true);
2977
- $this->update_status($task_name, $this->statuses['finished'], true);
2978
  }
2979
  }
2980
-
2981
  if (isset($account_info['mwp_dropbox']) && !empty($account_info['mwp_dropbox'])) {
2982
- $this->update_status($task_name, $this->statuses['dropbox']);
2983
- $account_info['mwp_dropbox']['backup_file'] = $backup_file;
2984
  $return = $this->dropbox_backup($account_info['mwp_dropbox']);
2985
  $this->wpdb_reconnect();
2986
-
2987
  if (!(is_array($return) && isset($return['error']))) {
2988
- $this->update_status($task_name, $this->statuses['dropbox'], true);
2989
- $this->update_status($task_name, $this->statuses['finished'], true);
2990
  }
2991
  }
2992
-
2993
  if (isset($account_info['mwp_email']) && !empty($account_info['mwp_email'])) {
2994
- $this->update_status($task_name, $this->statuses['email']);
2995
- $account_info['mwp_email']['task_name'] = $task_name;
2996
- $account_info['mwp_email']['file_path'] = $backup_file;
2997
  $return = $this->email_backup($account_info['mwp_email']);
2998
  $this->wpdb_reconnect();
2999
-
3000
  if (!(is_array($return) && isset($return['error']))) {
3001
- $this->update_status($task_name, $this->statuses['email'], true);
3002
- $this->update_status($task_name, $this->statuses['finished'], true);
3003
  }
3004
  }
3005
-
3006
  if (isset($account_info['mwp_google_drive']) && !empty($account_info['mwp_google_drive'])) {
3007
- $this->update_status($task_name, $this->statuses['google_drive']);
3008
- $account_info['mwp_google_drive']['backup_file'] = $backup_file;
3009
- $return = $this->google_drive_backup($account_info['mwp_google_drive']);
3010
- $this->wpdb_reconnect();
3011
-
3012
- if (!(is_array($return) && isset($return['error']))) {
3013
- $this->update_status($task_name, $this->statuses['google_drive'], true);
3014
- $this->update_status($task_name, $this->statuses['finished'], true);
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
- if (is_array($result) && $result['body'] == 'mwp_delete_task') {
3059
- //$tasks = $this->get_backup_settings();
3060
- $tasks = $this->tasks;
3061
  unset($tasks[$args['task_name']]);
3062
- $this->update_tasks($tasks);
3063
- $this->cleanup();
3064
- return 'deleted';
3065
- } elseif(is_array($result) && $result['body'] == 'mwp_pause_task'){
3066
- return 'paused';
3067
- } elseif(is_array($result) && substr($result['body'], 0, 8) == 'token - '){
3068
- return $result['body'];
3069
- }
3070
  } else {
3071
- if (is_array($result) && $result['body']) {
3072
- $response = unserialize($result['body']);
3073
- if ($response['message'] == 'mwp_delete_task') {
3074
- $tasks = $this->tasks;
3075
  unset($tasks[$args['task_name']]);
3076
- $this->update_tasks($tasks);
3077
- $this->cleanup();
3078
  return 'deleted';
3079
- } elseif ($response['message'] == 'mwp_pause_task') {
3080
- return 'paused';
3081
- } elseif ($response['message'] == 'mwp_do_task') {
3082
- return $response;
3083
- }
3084
- }
3085
- }
3086
-
3087
- return false;
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
- global $wpdb;
3148
-
3149
- if(class_exists('wpdb') && function_exists('wp_set_wpdb_vars')){
3150
- @mysql_close($wpdb->dbh);
3151
- $wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
3152
- wp_set_wpdb_vars();
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
- function replace_htaccess($url) {
3163
- $file = @file_get_contents(ABSPATH.'.htaccess');
3164
- if ($file && strlen($file)) {
3165
- $args = parse_url($url);
3166
- $string = rtrim($args['path'], "/");
3167
- $regex = "/BEGIN WordPress(.*?)RewriteBase(.*?)\n(.*?)RewriteRule \.(.*?)index\.php(.*?)END WordPress/sm";
3168
- $replace = "BEGIN WordPress$1RewriteBase " . $string . "/ \n$3RewriteRule . " . $string . "/index.php$5END WordPress";
3169
- $file = preg_replace($regex, $replace, $file);
3170
- @file_put_contents(ABSPATH.'.htaccess', $file);
3171
- }
3172
- }
3173
-
3174
- /**
3175
- * Removes cron for checking scheduled tasks, if there are not any scheduled task.
3176
- *
3177
- * @return void
3178
- */
3179
- function check_cron_remove() {
3180
- if(empty($this->tasks) || (count($this->tasks) == 1 && isset($this->tasks['Backup Now'])) ){
3181
- wp_clear_scheduled_hook('mwp_backup_tasks');
3182
- exit;
3183
- }
3184
- }
3185
-
3186
- /**
3187
- * Re-add tasks on website re-add.
3188
- *
3189
- * @param array $params arguments passed to function
3190
- * @return array $params without backups
3191
- */
3192
- public function readd_tasks($params = array()) {
3193
- global $mmb_core;
3194
-
3195
- if( empty($params) || !isset($params['backups']) )
3196
- return $params;
3197
-
3198
- $before = array();
3199
- $tasks = $params['backups'];
3200
- if( !empty($tasks) ){
3201
- $mmb_backup = new MMB_Backup();
3202
-
3203
- if( function_exists( 'wp_next_scheduled' ) ){
3204
- if ( !wp_next_scheduled('mwp_backup_tasks') ) {
3205
- wp_schedule_event( time(), 'tenminutes', 'mwp_backup_tasks' );
3206
- }
3207
- }
3208
-
3209
- foreach( $tasks as $task ){
3210
- $before[$task['task_name']] = array();
3211
-
3212
- if(isset($task['secure'])){
3213
- if($decrypted = $mmb_core->_secure_data($task['secure'])){
3214
- $decrypted = maybe_unserialize($decrypted);
3215
- if(is_array($decrypted)){
3216
- foreach($decrypted as $key => $val){
3217
- if(!is_numeric($key))
3218
- $task[$key] = $val;
3219
- }
3220
- unset($task['secure']);
3221
- } else
3222
- $task['secure'] = $decrypted;
3223
- }
3224
-
3225
- }
3226
- if (isset($task['account_info']) && is_array($task['account_info'])) { //only if sends from master first time(secure data)
3227
- $task['args']['account_info'] = $task['account_info'];
3228
- }
3229
-
3230
- $before[$task['task_name']]['task_args'] = $task['args'];
3231
- $before[$task['task_name']]['task_args']['next'] = $mmb_backup->schedule_next($task['args']['type'], $task['args']['schedule']);
3232
- }
3233
- }
3234
- update_option('mwp_backup_tasks', $before);
3235
-
3236
- unset($params['backups']);
3237
- return $params;
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
- * Get all files in directory
3249
- *
3250
- * @param string $path Relative or absolute path to folder
3251
- * @param array $exclude List of excluded files or folders, relative to $path
3252
- * @return array List of all files in folder $path, exclude all files in $exclude array
3253
- */
3254
- function get_all_files_from_dir($path, $exclude = array()) {
3255
- if ($path[strlen($path) - 1] === "/") $path = substr($path, 0, -1);
3256
- global $directory_tree, $ignore_array;
3257
- $directory_tree = array();
3258
- foreach ($exclude as $file) {
3259
- if (!in_array($file, array('.', '..'))) {
3260
- if ($file[0] === "/") $path = substr($file, 1);
3261
- $ignore_array[] = "$path/$file";
3262
- }
3263
- }
3264
- get_all_files_from_dir_recursive($path);
3265
- return $directory_tree;
3266
- }
3267
  }
3268
 
3269
  if (!function_exists('get_all_files_from_dir_recursive')) {
3270
- /**
3271
- * Get all files in directory,
3272
- * wrapped function which writes in global variable
3273
- * and exclued files or folders are read from global variable
3274
- *
3275
- * @param string $path Relative or absolute path to folder
3276
- * @return void
3277
- */
3278
- function get_all_files_from_dir_recursive($path) {
3279
- if ($path[strlen($path) - 1] === "/") $path = substr($path, 0, -1);
3280
- global $directory_tree, $ignore_array;
3281
- $directory_tree_temp = array();
3282
- $dh = @opendir($path);
3283
-
3284
- while (false !== ($file = @readdir($dh))) {
3285
- if (!in_array($file, array('.', '..'))) {
3286
- if (!in_array("$path/$file", $ignore_array)) {
3287
- if (!is_dir("$path/$file")) {
3288
- $directory_tree[] = "$path/$file";
3289
- } else {
3290
- get_all_files_from_dir_recursive("$path/$file");
3291
- }
3292
- }
3293
- }
3294
- }
3295
- @closedir($dh);
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.26
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');
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
- if (!function_exists('wp_version_check'))
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
+ * &lt;?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
+ * ?&gt;
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