Google Analytics Counter Tracker - Version 1.0.0

Version Description

Download this release

Release Info

Developer Analytics Counter
Plugin Icon 128x128 Google Analytics Counter Tracker
Version 1.0.0
Comparing to
See all releases

Version 1.0.0

analytics-counter.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Google Analytics Counter Tracker
4
+
5
+ Description: Google analytics counter tracker - analyse the visitors hits on you website and display it graphically
6
+ Version: 1.0.0
7
+ Author: WPAdm
8
+ Author URI: http://www.wpadm.com
9
+ Plugin URI: http://www.wpadm.com
10
+ License: GPLv2 or later
11
+ */
12
+
13
+ define( 'WPADM_GA__VIEW_TITLE', 'Analytics Counter');
14
+ define( 'WPADM_GA__PLUGIN_NAME', basename(dirname(__FILE__)) );
15
+
16
+ define( 'WPADM_GA__MENU_PREFIX', 'wpadm-ga-menu-' );
17
+ define( 'WPADM_GA__PLUGIN_URL', plugin_dir_url( __FILE__ ) );
18
+ define( 'WPADM_GA__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
19
+ define( 'WPADM_GA__VIEW_DIR', plugin_dir_path( __FILE__ ) . 'view' . DIRECTORY_SEPARATOR );
20
+ define( 'WPADM_GA__VIEW_LAYOUT', WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'layout.php');
21
+
22
+ define( 'WPADM_GA__DB_VERSION', 1);
23
+
24
+ add_action('init', array( 'Wpadm_GA', 'init'));
25
+ add_action('admin_menu', array( 'Wpadm_GA', 'generateMenu'));
26
+
27
+ register_activation_hook(__FILE__, array( 'Wpadm_GA', 'plugin_activation'));
28
+ register_deactivation_hook(__FILE__, array( 'Wpadm_GA', 'plugin_deactivation'));
29
+
30
+ register_uninstall_hook(__FILE__, array( 'Wpadm_GA', 'plugin_uninstall'));
31
+
32
+ add_action( 'admin_enqueue_scripts', array( 'Wpadm_GA', 'registerPluginScripts') );
33
+
34
+ add_action('wp_footer', array('Wpadm_GA', 'generateGACodeOnSite'));
35
+
36
+ add_action( 'wp_ajax_getCache', array('Wpadm_GA_Cache', 'getCache') );
37
+ add_action( 'wp_ajax_setCache', array('Wpadm_GA_Cache', 'setCache') );
38
+
39
+
40
+ require_once( WPADM_GA__PLUGIN_DIR . 'class.wpadm-ga.php' );
41
+
class.wpadm-ga-cache.php ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: danilov
5
+ * Date: 23.11.2015
6
+ * Time: 9:33
7
+ */
8
+
9
+ class Wpadm_GA_Cache {
10
+
11
+ static function getCache() {
12
+ global $wpdb;
13
+
14
+ $query = $_POST['query'];
15
+ if (!$query || !is_array($query)) {
16
+ //todo: return error
17
+ wp_die();
18
+ }
19
+ $table_name = self::getTableName();
20
+
21
+ ksort($query);
22
+ $query = json_encode($query);
23
+
24
+ $request_type = $_POST['request_type'];
25
+ $object_type = $_POST['object_type'];
26
+
27
+
28
+ $sql = $wpdb->prepare(
29
+ "SELECT
30
+ html, result
31
+ FROM
32
+ {$table_name}
33
+ WHERE
34
+ `query`= '%s'
35
+ AND `object_type`='%s'
36
+ AND `request_type`='%s'
37
+ AND (expired_in =0 OR expired_in > %d)
38
+ ",
39
+ $query,
40
+ $object_type,
41
+ $request_type,
42
+ time()
43
+ );
44
+
45
+ $rows = $wpdb->get_results($sql, ARRAY_A);
46
+ if($rows) {
47
+ echo json_encode(
48
+ array(
49
+ 'status' => 'success',
50
+ 'html' => stripslashes($rows[0]['html']),
51
+ 'result' => stripslashes($rows[0]['result']),
52
+ )
53
+ );
54
+ } else {
55
+ echo json_encode(
56
+ array(
57
+ 'status' => 'empty'
58
+ )
59
+ );
60
+ }
61
+
62
+ wp_die();
63
+ }
64
+
65
+ static function setCache() {
66
+ global $wpdb;
67
+
68
+ $query = $_POST['query'];
69
+ if (!$query || !is_array($query)) {
70
+ wp_die();
71
+ }
72
+
73
+ $table_name = self::getTableName();
74
+ ksort($query);
75
+
76
+ $request_type = $_POST['request_type'];
77
+ $html = $_POST['html'];
78
+ $result = json_encode($_POST['result']);
79
+ $object_type = $_POST['object_type'];
80
+
81
+ if (isset($query['metrics']) && is_array($query['metrics'])) {
82
+ $query['metrics'] = implode(',', $query['metrics']);
83
+ }
84
+ if (isset($query['dimensions']) && is_array($query['dimensions'])) {
85
+ $query['dimensions'] = implode(',', $query['dimensions']);
86
+ }
87
+ if (isset($query['sort']) && is_array($query['sort'])) {
88
+ $query['sort'] = implode(',', $query['sort']);
89
+ }
90
+
91
+ $start_date_plus_day = new DateTime($query['start-date'] . '00:00:00');
92
+ $start_date_plus_day = new DateTime(date("Y-m-d",strtotime("+1 day", $start_date_plus_day->format('U'))) . ' 00:00:00');
93
+
94
+ $end_date = new DateTime($query['end-date'] . '23:59:59');
95
+ $now = new DateTime();
96
+ $expired_in = 0;
97
+
98
+ if ($end_date->format("Ymd") > $now->format('Ymd')) {
99
+
100
+ $now_plus_day = new DateTime(date("Y-m-d",strtotime("+1 day")) . ' 00:00:00');
101
+
102
+ $e_in = max($start_date_plus_day->format("Y-m-d"), $now_plus_day->format("Y-m-d"));
103
+ $e_in = new DateTime($e_in);
104
+ $expired_in = $e_in->format('U');
105
+ } elseif ($end_date->format("Ymd") == $now->format('Ymd')) {
106
+ $expired_in = $now->format('U');
107
+ }
108
+
109
+
110
+ $query = json_encode($query);
111
+
112
+ //заменить на insert ignore
113
+ $sql = $wpdb->prepare(
114
+ "DELETE FROM {$table_name} WHERE `query`= '%s' AND `object_type`='%s' AND `request_type`='%s'",
115
+ $query,
116
+ $object_type,
117
+ $request_type
118
+ );
119
+ $wpdb->query($sql);
120
+
121
+ $sql = $wpdb->prepare(
122
+ "
123
+ INSERT INTO {$table_name}
124
+ (`query`, `html`, `result`, `request_type`, `object_type`, `expired_in`)
125
+ VALUES
126
+ ('%s', '%s', '%s', '%s', '%s', '%d')
127
+ ",
128
+ $query,
129
+ $html,
130
+ $result,
131
+ $request_type,
132
+ $object_type,
133
+ $expired_in
134
+
135
+ );
136
+ $wpdb->query($sql);
137
+
138
+ echo json_encode(array(
139
+ 'status' => 'success'
140
+ ));
141
+
142
+
143
+ wp_die();
144
+
145
+ }
146
+
147
+ static protected function getTableName() {
148
+ global $wpdb;
149
+ return $wpdb->prefix . "wpadm_ga_cache";
150
+ }
151
+
152
+
153
+ static public function cronRemoveExpiredCache() {
154
+ global $wpdb;
155
+ $table_name = self::getTableName();
156
+ $sql = $wpdb->prepare(
157
+ "DELETE FROM {$table_name} WHERE expired_in != 0 AND expired_in < '%d'",
158
+ time()
159
+ );
160
+ $wpdb->query($sql);
161
+ }
162
+
163
+ }
class.wpadm-ga-options.php ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WPAdm_GA_Options
4
+ {
5
+ const OPTIONNAME = 'wpadm_ga';
6
+ const TYPE_CODE_UNIVERSAL = 'universal';
7
+
8
+ protected $ga_access_token = null;
9
+ protected $ga_expires_in = null;
10
+ protected $ga_created = null;
11
+ protected $ga_id = null;
12
+ protected $ga_url = null;
13
+ protected $ga_webPropertyId = null;
14
+ protected $ga_enableCode = null;
15
+ protected $ga_typeCode = '';
16
+
17
+ protected $wpadmin_token = null;
18
+
19
+
20
+ /**
21
+ * @var WPAdm_GA_Options
22
+ */
23
+ static protected $instance = null;
24
+
25
+ protected function __construct() {
26
+ $wpadm_ga = get_option(self::OPTIONNAME);
27
+ if (is_array($wpadm_ga)) {
28
+ $this->ga_access_token = (isset($wpadm_ga['ga_access_token'])) ? $wpadm_ga['ga_access_token'] : null;
29
+ $this->ga_created = (isset($wpadm_ga['ga_created'])) ? $wpadm_ga['ga_created'] : null;
30
+ $this->ga_expires_in = (isset($wpadm_ga['ga_expires_in'])) ? $wpadm_ga['ga_expires_in'] : null;
31
+ $this->ga_id = (isset($wpadm_ga['ga_id'])) ? $wpadm_ga['ga_id'] : null;
32
+ $this->ga_url = (isset($wpadm_ga['ga_url'])) ? $wpadm_ga['ga_url'] : null;
33
+ $this->ga_webPropertyId = (isset($wpadm_ga['ga_webPropertyId'])) ? $wpadm_ga['ga_webPropertyId'] : null;
34
+ $this->ga_enableCode = (isset($wpadm_ga['ga_enableCode'])) ? $wpadm_ga['ga_enableCode'] : null;
35
+ $this->ga_typeCode = self::TYPE_CODE_UNIVERSAL;
36
+ }
37
+ }
38
+
39
+ protected static function getInstance() {
40
+ $instance = new WPAdm_GA_Options();
41
+ self::$instance = $instance;
42
+ $instance->__construct();
43
+ }
44
+
45
+ public static function getGAAccessToken() {
46
+ return self::getVar('ga_access_token');
47
+ }
48
+
49
+ public static function getGAExpiresIn() {
50
+ return self::getVar('ga_expires_in');
51
+ }
52
+
53
+ public static function getGACreated() {
54
+ return self::getVar('ga_created');
55
+ }
56
+
57
+ public static function getGAId() {
58
+ return self::getVar('ga_id');
59
+ }
60
+
61
+ public static function getGAUrl() {
62
+ return self::getVar('ga_url');
63
+ }
64
+
65
+ public static function setGAAccessToken($ga_access_token) {
66
+ if (is_null(self::$instance)) {
67
+ self::getInstance();
68
+ }
69
+ self::$instance->ga_access_token = $ga_access_token;
70
+ self::saveOptions();
71
+
72
+ }
73
+
74
+ public static function setGAExpiresIn($ga_expires_in) {
75
+ if (is_null(self::$instance)) {
76
+ self::getInstance();
77
+ }
78
+ self::$instance->ga_expires_in = $ga_expires_in;
79
+ self::saveOptions();
80
+
81
+ }
82
+
83
+ public static function setGACreated($ga_created) {
84
+ if (is_null(self::$instance)) {
85
+ self::getInstance();
86
+ }
87
+ self::$instance->ga_created = $ga_created;
88
+ self::saveOptions();
89
+
90
+ }
91
+
92
+ public static function setGAId($ga_id) {
93
+ if (is_null(self::$instance)) {
94
+ self::getInstance();
95
+ }
96
+ self::$instance->ga_id = $ga_id;
97
+ self::saveOptions();
98
+ }
99
+
100
+ public static function setGAUrl($ga_url) {
101
+ if (is_null(self::$instance)) {
102
+ self::getInstance();
103
+ }
104
+ self::$instance->ga_url = $ga_url;
105
+ self::saveOptions();
106
+ }
107
+
108
+
109
+ /** webPropertyId */
110
+ public static function setGAWebPropertyId($ga_webPropertyId) {
111
+ if (is_null(self::$instance)) {
112
+ self::getInstance();
113
+ }
114
+ self::$instance->ga_webPropertyId = $ga_webPropertyId;
115
+ self::saveOptions();
116
+ }
117
+ public static function getGAWebPropertyId() {
118
+ return self::getVar('ga_webPropertyId');
119
+ }
120
+
121
+ /** enableCode */
122
+ public static function setGAEnableCode($ga_enableCode) {
123
+ if (is_null(self::$instance)) {
124
+ self::getInstance();
125
+ }
126
+ self::$instance->ga_enableCode = $ga_enableCode;
127
+ self::saveOptions();
128
+ }
129
+ public static function getGAEnableCode() {
130
+ return self::getVar('ga_enableCode');
131
+ }
132
+
133
+
134
+ /** typeCode */
135
+ public static function setGATypeCode($ga_typeCode) {
136
+ if (is_null(self::$instance)) {
137
+ self::getInstance();
138
+ }
139
+ self::$instance->ga_typeCode = $ga_typeCode;
140
+ self::saveOptions();
141
+ }
142
+ public static function getGATypeCode() {
143
+ return self::getVar('ga_typeCode');
144
+ }
145
+
146
+
147
+
148
+
149
+
150
+
151
+ protected static function getVar($var) {
152
+ if (is_null(self::$instance)) {
153
+ self::getInstance();
154
+ }
155
+ return self::$instance->$var;
156
+ }
157
+
158
+
159
+
160
+
161
+
162
+ protected static function saveOptions() {
163
+ if (is_null(self::$instance)) {
164
+ self::getInstance();
165
+ }
166
+ update_option(self::OPTIONNAME, array(
167
+ 'ga_access_token' => self::$instance->ga_access_token,
168
+ 'ga_created' => self::$instance->ga_created,
169
+ 'ga_expires_in' => self::$instance->ga_expires_in,
170
+ 'ga_id' => self::$instance->ga_id,
171
+ 'ga_url' => self::$instance->ga_url,
172
+ 'ga_webPropertyId' => self::getGAWebPropertyId(),
173
+ 'ga_enableCode' => self::getGAEnableCode(),
174
+ 'ga_typeCode' => self::TYPE_CODE_UNIVERSAL
175
+ ));
176
+
177
+ }
178
+
179
+ public static function gaTokenIsExpired() {
180
+
181
+ // if (!self::getGAExpiresIn()) {
182
+ // return true;
183
+ // }
184
+ //
185
+ // if (!self::getGACreated()) {
186
+ // return true;
187
+ // }
188
+
189
+
190
+ return ! (self::getGACreated()+self::getGAExpiresIn() > time());
191
+ }
192
+
193
+ }
class.wpadm-ga-view.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WPAdm_GA_View
4
+ {
5
+ public static $title = WPADM_GA__VIEW_TITLE;
6
+ public static $subtitle = '';
7
+ public static $content_file = '';
8
+
9
+ public static $errors = array();
10
+ }
class.wpadm-ga.php ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WPAdm_GA
4
+ {
5
+ const URL_GA_SERVER = 'http://secure.wpadm.com/ga/';
6
+ const URL_GA_AUTH = 'http://secure.wpadm.com/ga.php';
7
+ const URL_GA_PUB_KEY = 'http://secure.wpadm.com/ga/getPubKey';
8
+
9
+ const REQUEST_PARAM_NAME = 'wpadm_ga_request';
10
+
11
+ public function visitView() {
12
+
13
+ WPAdm_GA_View::$subtitle = 'Audience Overview';
14
+
15
+ if($template = self::getErrorTemplate()) {
16
+ WPAdm_GA_View::$content_file = $template;
17
+ } else {
18
+ if(WPAdm_GA_Options::gaTokenIsExpired() && !isset($_GET['token'])) {
19
+ ob_clean();
20
+ $location = self::URL_GA_AUTH . '?redirect=' . urlencode(home_url( add_query_arg( NULL, NULL ) ));
21
+ // wp_redirect($localion);
22
+ header("Location: $location");
23
+ }
24
+ WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'visit.php';
25
+ }
26
+ require WPADM_GA__VIEW_LAYOUT;
27
+ }
28
+
29
+
30
+
31
+ public function usersView() {
32
+ WPAdm_GA_View::$subtitle = 'Visitors Overview';
33
+
34
+ if($template = self::getErrorTemplate()) {
35
+ WPAdm_GA_View::$content_file = $template;
36
+ } else {
37
+ if(WPAdm_GA_Options::gaTokenIsExpired() && !isset($_GET['token'])) {
38
+ ob_clean();
39
+ $location = self::URL_GA_AUTH . '?redirect=' . urlencode(home_url( add_query_arg( NULL, NULL ) ));
40
+ header("Location: $location");
41
+ }
42
+ WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'users.php';
43
+ }
44
+ require WPADM_GA__VIEW_LAYOUT;
45
+ }
46
+
47
+ public function sourceView() {
48
+ WPAdm_GA_View::$subtitle = 'Source stat';
49
+ WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'source.php';
50
+ require WPADM_GA__VIEW_LAYOUT;
51
+ }
52
+
53
+ public function settingsView() {
54
+ WPAdm_GA_View::$subtitle = 'settings';
55
+
56
+ if($template = self::getErrorTemplate()) {
57
+ WPAdm_GA_View::$content_file = $template;
58
+ } else {
59
+ if(WPAdm_GA_Options::gaTokenIsExpired() && !isset($_GET['token'])) {
60
+ ob_clean();
61
+ $location = self::URL_GA_AUTH . '?redirect=' . urlencode(home_url( add_query_arg( NULL, NULL ) ));
62
+ header("Location: $location");
63
+ }
64
+ WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'settings.php';
65
+ }
66
+
67
+
68
+
69
+ //GA Account
70
+ $ga_accout_form = new wpadmForm();
71
+ $ga_accout_form->setValue('ga-id', WPAdm_GA_Options::getGAId());
72
+ $ga_accout_form->setValue('ga-webPropertyId', WPAdm_GA_Options::getGAWebPropertyId());
73
+ $ga_accout_form->setValue('ga-url', WPAdm_GA_Options::getGAUrl());
74
+ $ga_accout_form->setValue('ga-enableCode', WPAdm_GA_Options::getGAEnableCode());
75
+
76
+ if('POST' == strtoupper($_SERVER['REQUEST_METHOD'])
77
+ && isset($_POST['form_name'])
78
+ && 'ga-account' == $_POST['form_name']
79
+ ) {
80
+ $id = filter_input(INPUT_POST, 'ga-id', FILTER_SANITIZE_NUMBER_INT);
81
+ $url = filter_input(INPUT_POST, 'ga-url', FILTER_SANITIZE_URL);
82
+ $webPropertyId = filter_input(INPUT_POST, 'ga-webPropertyId', FILTER_SANITIZE_STRING);
83
+ $enableCode = (int)filter_input(INPUT_POST, 'ga-enableCode', FILTER_SANITIZE_NUMBER_INT);
84
+ $enableCode = ($enableCode) ? 1 : 0;
85
+
86
+ WPAdm_GA_Options::setGAId($id);
87
+ WPAdm_GA_Options::setGAUrl($url);
88
+ WPAdm_GA_Options::setGAWebPropertyId($webPropertyId);
89
+ WPAdm_GA_Options::setGAEnableCode($enableCode);
90
+
91
+ $ga_accout_form->setValue('ga-id', $id);
92
+ $ga_accout_form->setValue('ga-webPropertyId', $webPropertyId);
93
+ $ga_accout_form->setValue('ga-enableCode', $enableCode);
94
+
95
+ //redirect to stat
96
+ ob_clean();
97
+
98
+ if (isset($_GET['modal'])) {
99
+ echo '<script> top.frames.location.reload(false);</script>';
100
+ } else {
101
+ $location = admin_url() . 'options-general.php?page=wpadm-ga-menu-visit';
102
+ header("Location: $location");
103
+ }
104
+ exit;
105
+ }
106
+
107
+
108
+
109
+ // $wpadm_account_form = new wpadmAuthForm();
110
+
111
+ // if('POST' == strtoupper($_SERVER['REQUEST_METHOD'])
112
+ // && isset($_POST['form_name'])
113
+ // && 'wpadm-account' == $_POST['form_name']
114
+ // ) {
115
+ // $form_data = array(
116
+ // 'wpadm_username' => $_POST['wpadm_username'],
117
+ // 'wpadm_password' => $_POST['wpadm_password'],
118
+ // 'wpadm_password_confirm' => $_POST['wpadm_password_confirm'],
119
+ // 'wpadm_imnewuser_checkbox' => (isset($_POST['wpadm_imnewuser_checkbox'])&& $_POST['wpadm_imnewuser_checkbox'] == 1) ? 1 :0
120
+ // );
121
+ // $wpadm_account_form->setData($form_data);
122
+ //
123
+ // if ($wpadm_account_form->isValid()) {
124
+ //
125
+ // WPAdm_GA_Api::register();
126
+ // echo 'doit';
127
+ // exit;
128
+ // }
129
+ // }
130
+
131
+
132
+
133
+ // if('POST' == strtoupper($_SERVER['REQUEST_METHOD'])
134
+ // && isset($_POST['form_name'])
135
+ // && 'ga-account-logout' == $_POST['form_name']
136
+ // ) {
137
+ //
138
+ // $url = get_option('siteurl');
139
+ // $p_url = parse_url($url);
140
+ // $postdata = array(
141
+ // 'host' => $p_url['host'],
142
+ // );
143
+ //
144
+ // $response = wp_remote_post(self::URL_GA_SERVER . 'logout', array(
145
+ // 'method' => 'POST',
146
+ // 'timeout' => 45,
147
+ // 'body' => self::getParamsForRequest($postdata)
148
+ // ));
149
+ //
150
+ // if ( is_wp_error( $response ) ) {
151
+ // //todo: отработать исключение
152
+ // $error_message = $response->get_error_message();
153
+ // echo "Something went wrong: $error_message";
154
+ // } else {
155
+ //
156
+ // }
157
+ //
158
+ // echo '<!-- start dump --><pre><small>' . __FILE__ . "</small>\n";
159
+ // print_r($response['body']);
160
+ // echo '</pre><!-- end dump -->';
161
+ // exit;
162
+ //
163
+ //
164
+ // }
165
+
166
+
167
+
168
+ require WPADM_GA__VIEW_LAYOUT;
169
+ }
170
+
171
+
172
+ public static function plugin_activation() {
173
+ //get pub key
174
+ $response = wp_remote_post(self::URL_GA_PUB_KEY, array(
175
+ 'method' => 'POST',
176
+ 'timeout' => 45,
177
+ 'body' => array('refer'=>site_url())
178
+ ));
179
+
180
+ if ( is_wp_error( $response ) ) {
181
+ ////
182
+ $error_message = $response->get_error_message();
183
+ } else {
184
+ preg_match("|(-----BEGIN PUBLIC KEY-----.*-----END PUBLIC KEY-----)|Uis", $response['body'], $m);
185
+ if (isset($m[1]) && !empty($m[1])) {
186
+ update_option('wpadm_ga_pub_key', $m[1]);
187
+ }
188
+ }
189
+
190
+ self::cron_activation();
191
+ }
192
+
193
+ public static function plugin_deactivation() {
194
+ delete_option('wpadm_ga_pub_key');
195
+ delete_option('wpadm_ga');
196
+ self::cron_deactivation();
197
+ //todo: delete cahce table
198
+ }
199
+
200
+ public static function cron_activation() {
201
+ add_action('wpadm_ga_cache_clear', array('Wpadm_GA_Cache', 'cronRemoveExpiredCache'));
202
+ wp_clear_scheduled_hook('wpadm_ga_cache_clear');
203
+ wp_schedule_event(time(), 'daily', 'wpadm_ga_cache_clear');
204
+ }
205
+
206
+ public static function cron_deactivation() {
207
+ wp_clear_scheduled_hook('wpadm_ga_cache_clear');
208
+ }
209
+
210
+
211
+ public static function init() {
212
+ ob_start();
213
+ self::requireFiles();
214
+ self::checkDB();
215
+ $request_name = self::REQUEST_PARAM_NAME;
216
+ if( isset( $_POST[$request_name] ) && ! empty ( $_POST[$request_name] ) ) {
217
+ self::proccessRequest();
218
+ }
219
+
220
+
221
+ }
222
+
223
+ protected static function proccessRequest() {
224
+ $request_name = self::REQUEST_PARAM_NAME;
225
+ $params = unserialize(base64_decode($_POST[$request_name]));
226
+
227
+ $v = self::verifySignature($params['sign'], get_option('wpadm_ga_pub_key'), md5(serialize($params['data'])));
228
+
229
+ $request = $params['data'];
230
+
231
+ if($v && isset($request['action'])) {
232
+ switch($request['action']) {
233
+ case 'access_token':
234
+ WPAdm_GA_Options::setGAAccessToken($request['data']['access_token']);
235
+ WPAdm_GA_Options::setGAExpiresIn($request['data']['expires_in']);
236
+ WPAdm_GA_Options::setGACreated($request['data']['created']);
237
+
238
+ $ga_id = WPAdm_GA_Options::getGAId();
239
+ if (isset($request['data']['property']) && empty($ga_id)
240
+ && isset($request['data']['property']['ga_id']) && !empty($request['data']['property']['ga_id'])
241
+ && isset($request['data']['property']['ga_url']) && !empty($request['data']['property']['ga_url'])
242
+ && isset($request['data']['property']['ga_webPropertyId']) && !empty($request['data']['property']['ga_webPropertyId'])
243
+ ) {
244
+ WPAdm_GA_Options::setGAUrl($request['data']['property']['ga_url']);
245
+ WPAdm_GA_Options::setGAId($request['data']['property']['ga_id']);
246
+ WPAdm_GA_Options::setGAWebPropertyId($request['data']['property']['ga_webPropertyId']);
247
+ }
248
+
249
+ header("HTTP/1.0 201 Created");
250
+ break;
251
+ }
252
+ }
253
+ exit;
254
+ }
255
+
256
+
257
+
258
+ protected static function requireFiles() {
259
+ require_once( WPADM_GA__PLUGIN_DIR . 'class.wpadm-ga-options.php' );
260
+ require_once( WPADM_GA__PLUGIN_DIR . 'class.wpadm-ga-view.php' );
261
+ require_once( WPADM_GA__PLUGIN_DIR . 'class.wpadm-ga-cache.php' );
262
+
263
+ require_once( WPADM_GA__PLUGIN_DIR . 'form'.DIRECTORY_SEPARATOR.'wpadmForm.php' );
264
+ require_once( WPADM_GA__PLUGIN_DIR . 'form'.DIRECTORY_SEPARATOR.'wpadmAuthForm.php' );
265
+
266
+
267
+ }
268
+
269
+ public static function registerPluginStyles() {
270
+ wp_register_style( 'wpadm-ga-css', plugins_url(WPADM_GA__PLUGIN_NAME. '/view/scripts/wpadm-ga.css' ) );
271
+ wp_enqueue_style( 'wpadm-ga-css' );
272
+
273
+ wp_register_style( 'wpadm-daterangepicker-css', plugins_url(WPADM_GA__PLUGIN_NAME. '/view/scripts/daterangepicker/daterangepicker.css' ) );
274
+ wp_enqueue_style( 'wpadm-daterangepicker-css' );
275
+
276
+ }
277
+
278
+ public static function registerPluginScripts() {
279
+ wp_register_script( 'wpadm-ga-js', plugins_url(WPADM_GA__PLUGIN_NAME. '/view/scripts/wpadm-ga.js' ) );
280
+ wp_enqueue_script( 'wpadm-ga-js' );
281
+
282
+ wp_register_script( 'wpadm-moment-js', plugins_url(WPADM_GA__PLUGIN_NAME. '/view/scripts/moment.min.js' ) );
283
+ wp_enqueue_script( 'wpadm-moment-js' );
284
+
285
+ wp_register_script( 'wpadm-daterangepicker-js', plugins_url(WPADM_GA__PLUGIN_NAME. '/view/scripts/daterangepicker/daterangepicker.js' ) );
286
+ wp_enqueue_script( 'wpadm-daterangepicker-js' );
287
+ }
288
+
289
+ public static function generateMenu() {
290
+ $pages = array();
291
+
292
+ $menu_position = '1.9998887770';
293
+ $pages[] = add_menu_page(
294
+ 'Analytics Counter',
295
+ 'Analytics Counter',
296
+ 'read',
297
+ WPADM_GA__MENU_PREFIX . 'visit',
298
+ array('Wpadm_GA', 'visitView'),
299
+ plugins_url('/view/img/icon.png',__FILE__),
300
+ $menu_position
301
+ );
302
+ $pages[] = add_submenu_page(
303
+ WPADM_GA__MENU_PREFIX . 'visit',
304
+ 'Audience overview',
305
+ 'Audience overview',
306
+ 'read',
307
+ WPADM_GA__MENU_PREFIX . 'visit',
308
+ array('Wpadm_GA', 'visitView')
309
+ );
310
+
311
+
312
+ $pages[] = add_submenu_page(
313
+ WPADM_GA__MENU_PREFIX . 'visit',
314
+ 'Visitors overview',
315
+ 'Visitors overview',
316
+ 'read',
317
+ WPADM_GA__MENU_PREFIX . 'users',
318
+ array('Wpadm_GA', 'usersView')
319
+ );
320
+
321
+
322
+ $pages[] = add_options_page(
323
+ 'Analytics Counter Settings',
324
+ 'Analytics Counter',
325
+ 'administrator',
326
+ WPADM_GA__MENU_PREFIX . 'settings',
327
+ array('Wpadm_GA', 'settingsView')
328
+ );
329
+
330
+ foreach($pages as $page) {
331
+ add_action( 'admin_print_scripts-' . $page, array('Wpadm_GA', 'registerPluginScripts' ));
332
+ add_action( 'admin_print_styles-' . $page, array('Wpadm_GA', 'registerPluginStyles' ) );
333
+ }
334
+
335
+ }
336
+
337
+ public static function generateGACodeOnSite() {
338
+ if (WPAdm_GA_Options::getGAEnableCode() == 1 && WPAdm_GA_Options::getGAWebPropertyId()) {
339
+ require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR . 'ga_code_universal.php';
340
+ }
341
+ }
342
+
343
+
344
+ protected function getErrorTemplate() {
345
+ if(!get_option('wpadm_ga_pub_key')) {
346
+ return WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'error_admin_empty_pub_key.php';
347
+ }
348
+
349
+ $token = WPAdm_GA_Options::getGAAccessToken();
350
+ if (empty($token)) {
351
+ return WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'error_admin_empty_ga_token.php';
352
+ }
353
+
354
+ $site = WPAdm_GA_Options::getGAUrl();
355
+ if (empty($site) && $_GET['page'] != 'wpadm-ga-menu-settings') {
356
+ return WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'error_admin_empty_ga_site.php';
357
+ }
358
+
359
+ if(isset($_GET['google_oauth2_error'])) {
360
+ return WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'error_admin_google_error.php';
361
+ }
362
+
363
+ if(isset($_GET['error'])) {
364
+ return WPAdm_GA_View::$content_file = WPADM_GA__PLUGIN_DIR . 'view' . DIRECTORY_SEPARATOR . 'error_admin_wpadm_error.php';
365
+ }
366
+
367
+ return null;
368
+ }
369
+
370
+ function getParamsForRequest($data) {
371
+ $params = array(
372
+ 'data' => $data,
373
+ 'sign' => self::getSSLSign($data)
374
+ );
375
+
376
+ return array(REQUEST_PARAM_NAME => base64_encode(serialize($params)));
377
+ }
378
+
379
+ function getSSLSign($data) {
380
+ $str = md5(serialize($data));
381
+ if(function_exists('openssl_public_encrypt')) {
382
+ openssl_public_encrypt($str, $sign, get_option('wpadm_ga_pub_key'));
383
+ } else {
384
+ set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/lib/phpseclib');
385
+ require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'lib'.DIRECTORY_SEPARATOR . 'phpseclib' . DIRECTORY_SEPARATOR . 'Crypt'.DIRECTORY_SEPARATOR.'RSA.php';
386
+ $rsa = new Crypt_RSA();
387
+ $rsa->loadKey(get_option('wpadm_ga_pub_key'));
388
+ $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
389
+ $sign = $rsa->encrypt($str);
390
+ }
391
+ return $sign;
392
+ }
393
+
394
+ protected static function verifySignature($sign, $pub_key, $text) {
395
+ if (function_exists('openssl_public_decrypt')) {
396
+ openssl_public_decrypt($sign, $request_sign, $pub_key);
397
+ $ret = ($text == $request_sign);
398
+ return $ret;
399
+ } else {
400
+ set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/lib/phpseclib');
401
+ require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'lib'.DIRECTORY_SEPARATOR . 'phpseclib' . DIRECTORY_SEPARATOR . 'Crypt'.DIRECTORY_SEPARATOR.'RSA.php';
402
+ $rsa = new Crypt_RSA();
403
+ $rsa->loadKey($pub_key);
404
+ $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
405
+ return ($rsa->decrypt($sign) == $text);
406
+ }
407
+ }
408
+
409
+ protected static function decodeData($str) {
410
+ return json_decode(base64_decode($str), true);
411
+ }
412
+
413
+
414
+ protected static function checkDB() {
415
+ $opt_ver = WPADM_GA__PLUGIN_NAME . '-db-version';
416
+ $cur_version = get_option($opt_ver, 0);
417
+
418
+ if ($cur_version < WPADM_GA__DB_VERSION) {
419
+ global $wpdb;
420
+ $table_name = $wpdb->prefix . "wpadm_ga_cache";
421
+ $sql = "CREATE TABLE " . $table_name . " (
422
+ id int(11) NOT NULL AUTO_INCREMENT,
423
+ query text NOT NULL,
424
+ html text,
425
+ result text,
426
+ request_type varchar(20),
427
+ object_type varchar(20),
428
+ clearable tinyint(4) DEFAULT '1',
429
+ expired_in int(11) DEFAULT 0,
430
+ PRIMARY KEY (id)
431
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8";
432
+
433
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
434
+ dbDelta($sql);
435
+
436
+ $sql = $sql = "CREATE TABLE " . $table_name . " (
437
+ id int(11) NOT NULL AUTO_INCREMENT,
438
+ query text NOT NULL,
439
+ html text,
440
+ result text,
441
+ request_type varchar(20),
442
+ object_type varchar(20),
443
+ clearable tinyint(4) DEFAULT '1',
444
+ expired_in int(11) DEFAULT 0,
445
+ PRIMARY KEY (id),
446
+ KEY expired_in (expired_in),
447
+ FULLTEXT KEY query (query)
448
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8";
449
+
450
+ dbDelta($sql);
451
+
452
+ self::cron_activation();
453
+
454
+ update_option($opt_ver, WPADM_GA__DB_VERSION);
455
+ }
456
+ }
457
+
458
+ public static function plugin_uninstall() {
459
+ global $wpdb;
460
+ $table_name = $wpdb->prefix . "wpadm_ga_cache";
461
+ $sql = "DROP TABLE " . $table_name;
462
+ $wpdb->query($sql);
463
+
464
+ $opt_ver = WPADM_GA__PLUGIN_NAME . '-db-version';
465
+ delete_option($opt_ver);
466
+ }
467
+ }
468
+
form/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ header("HTTP/1.0 404 Not Found");
form/wpadmAuthForm.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class wpadmAuthForm extends wpadmForm
3
+ {
4
+ public function isValid() {
5
+ $data = $this->data;
6
+
7
+ if (empty($data['wpadm_username'])) {
8
+ $this->addError('Please enter e-mail', 'wpadm_username');
9
+ } elseif (!filter_var($data['wpadm_username'], FILTER_VALIDATE_EMAIL)) {
10
+ $this->addError('Please enter correct e-mail', 'wpadm_username');
11
+ }
12
+
13
+ if (empty($data['wpadm_password'])) {
14
+ $this->addError('Please enter password', 'wpadm_password');
15
+ }
16
+
17
+ if (!empty($data['wpadm_imnewuser_checkbox'])) {
18
+ if (empty($data['wpadm_password_confirm'])) {
19
+ $this->addError('Please enter confirm password', 'wpadm_password_confirm');
20
+ }
21
+
22
+ if ($data['wpadm_password'] != $data['wpadm_password_confirm']) {
23
+ $this->addError('Confirm password same as password', 'wpadm_password_confirm');
24
+ }
25
+ }
26
+ return empty($this->errors);
27
+ }
28
+ }
form/wpadmForm.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class wpadmForm {
3
+ public $errors = array();
4
+ protected $data = array();
5
+ public function bind($data) {
6
+ if(is_array($data)) {
7
+ $this->setData($data);
8
+ } elseif (is_object($data) && method_exists($data, 'getArrayCopy')) {
9
+ $this->setData($data->getArrayCopy());
10
+ }
11
+ }
12
+
13
+ public function setData(array $data) {
14
+
15
+ if (!is_array($this->data)) {
16
+ $this->data = array();
17
+ }
18
+
19
+ foreach($data as $k=>$v) {
20
+ $this->data[$k] = $v;
21
+ }
22
+
23
+ // $this->data = $data;
24
+ }
25
+
26
+ public function addError($error, $element) {
27
+ if (!$element) {
28
+ return false;
29
+ }
30
+ if (!isset($this->errors[$element])) {
31
+ $this->errors[$element] = array();
32
+ }
33
+ $this->errors[$element][] = $error;
34
+
35
+ return true;
36
+ }
37
+
38
+ public function clearError() {
39
+ $this->errors = array();
40
+ }
41
+
42
+ public function get($element) {
43
+ return array(
44
+ 'value' => $this->getValue($element),
45
+ 'errors' => $this->getErros($element),
46
+ );
47
+ }
48
+
49
+ public function getValue($element) {
50
+ return (isset($this->data[$element])) ? $this->data[$element] : null;
51
+ }
52
+
53
+ public function setValue($element, $value) {
54
+ $this->data[$element] = $value;
55
+ return $this;
56
+ }
57
+
58
+ /**
59
+ * @param $element
60
+ * @deprecated
61
+ *
62
+ * @return array
63
+ */
64
+ public function getErros($element) {
65
+ return (isset($this->errors[$element])) ? $this->errors[$element] : array();
66
+ }
67
+
68
+ public function getErrors($element) {
69
+ return (isset($this->errors[$element])) ? $this->errors[$element] : array();
70
+ }
71
+
72
+ public function isValid() {
73
+ return true;
74
+ }
75
+
76
+ }
index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ header("HTTP/1.0 404 Not Found");
lib/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ header("HTTP/1.0 404 Not Found");
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/Crypt/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ header("HTTP/1.0 404 Not Found");
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/File/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ header("HTTP/1.0 404 Not Found");
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_BIGINTEGER_SIGN], $n, false);
2124
+ }
2125
+
2126
+ return $result[MATH_BIGINTEGER_VALUE];
2127
+ }
2128
+
2129
+ /**
2130
+ * Performs long multiplication up to $stop digits
2131
+ *
2132
+ * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2133
+ *
2134
+ * @see _regularBarrett()
2135
+ * @param Array $x_value
2136
+ * @param Boolean $x_negative
2137
+ * @param Array $y_value
2138
+ * @param Boolean $y_negative
2139
+ * @param Integer $stop
2140
+ * @return Array
2141
+ * @access private
2142
+ */
2143
+ function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2144
+ {
2145
+ $x_length = count($x_value);
2146
+ $y_length = count($y_value);
2147
+
2148
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
2149
+ return array(
2150
+ MATH_BIGINTEGER_VALUE => array(),
2151
+ MATH_BIGINTEGER_SIGN => false
2152
+ );
2153
+ }
2154
+
2155
+ if ( $x_length < $y_length ) {
2156
+ $temp = $x_value;
2157
+ $x_value = $y_value;
2158
+ $y_value = $temp;
2159
+
2160
+ $x_length = count($x_value);
2161
+ $y_length = count($y_value);
2162
+ }
2163
+
2164
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
2165
+
2166
+ // the following for loop could be removed if the for loop following it
2167
+ // (the one with nested for loops) initially set $i to 0, but
2168
+ // doing so would also make the result in one set of unnecessary adds,
2169
+ // since on the outermost loops first pass, $product->value[$k] is going
2170
+ // to always be 0
2171
+
2172
+ $carry = 0;
2173
+
2174
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2175
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2176
+ $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
2177
+ $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2178
+ }
2179
+
2180
+ if ($j < $stop) {
2181
+ $product_value[$j] = $carry;
2182
+ }
2183
+
2184
+ // the above for loop is what the previous comment was talking about. the
2185
+ // following for loop is the "one with nested for loops"
2186
+
2187
+ for ($i = 1; $i < $y_length; ++$i) {
2188
+ $carry = 0;
2189
+
2190
+ for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2191
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2192
+ $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
2193
+ $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2194
+ }
2195
+
2196
+ if ($k < $stop) {
2197
+ $product_value[$k] = $carry;
2198
+ }
2199
+ }
2200
+
2201
+ return array(
2202
+ MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
2203
+ MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
2204
+ );
2205
+ }
2206
+
2207
+ /**
2208
+ * Montgomery Modular Reduction
2209
+ *
2210
+ * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2211
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2212
+ * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
2213
+ * to work correctly.
2214
+ *
2215
+ * @see _prepMontgomery()
2216
+ * @see _slidingWindow()
2217
+ * @access private
2218
+ * @param Array $x
2219
+ * @param Array $n
2220
+ * @return Array
2221
+ */
2222
+ function _montgomery($x, $n)
2223
+ {
2224
+ static $cache = array(
2225
+ MATH_BIGINTEGER_VARIABLE => array(),
2226
+ MATH_BIGINTEGER_DATA => array()
2227
+ );
2228
+
2229
+ if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2230
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2231
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
2232
+ $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
2233
+ }
2234
+
2235
+ $k = count($n);
2236
+
2237
+ $result = array(MATH_BIGINTEGER_VALUE => $x);
2238
+
2239
+ for ($i = 0; $i < $k; ++$i) {
2240
+ $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
2241
+ $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
2242
+ $temp = $this->_regularMultiply(array($temp), $n);
2243
+ $temp = array_merge($this->_array_repeat(0, $i), $temp);
2244
+ $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
2245
+ }
2246
+
2247
+ $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
2248
+
2249
+ if ($this->_compare($result, false, $n, false) >= 0) {
2250
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
2251
+ }
2252
+
2253
+ return $result[MATH_BIGINTEGER_VALUE];
2254
+ }
2255
+
2256
+ /**
2257
+ * Montgomery Multiply
2258
+ *
2259
+ * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2260
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2261
+ *
2262
+ * @see _prepMontgomery()
2263
+ * @see _montgomery()
2264
+ * @access private
2265
+ * @param Array $x
2266
+ * @param Array $y
2267
+ * @param Array $m
2268
+ * @return Array
2269
+ */
2270
+ function _montgomeryMultiply($x, $y, $m)
2271
+ {
2272
+ $temp = $this->_multiply($x, false, $y, false);
2273
+ return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
2274
+
2275
+ static $cache = array(
2276
+ MATH_BIGINTEGER_VARIABLE => array(),
2277
+ MATH_BIGINTEGER_DATA => array()
2278
+ );
2279
+
2280
+ if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2281
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2282
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2283
+ $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
2284
+ }
2285
+
2286
+ $n = max(count($x), count($y), count($m));
2287
+ $x = array_pad($x, $n, 0);
2288
+ $y = array_pad($y, $n, 0);
2289
+ $m = array_pad($m, $n, 0);
2290
+ $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
2291
+ for ($i = 0; $i < $n; ++$i) {
2292
+ $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
2293
+ $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
2294
+ $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
2295
+ $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));
2296
+ $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2297
+ $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2298
+ $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
2299
+ }
2300
+ if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
2301
+ $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
2302
+ }
2303
+ return $a[MATH_BIGINTEGER_VALUE];
2304
+ }
2305
+
2306
+ /**
2307
+ * Prepare a number for use in Montgomery Modular Reductions
2308
+ *
2309
+ * @see _montgomery()
2310
+ * @see _slidingWindow()
2311
+ * @access private
2312
+ * @param Array $x
2313
+ * @param Array $n
2314
+ * @return Array
2315
+ */
2316
+ function _prepMontgomery($x, $n)
2317
+ {
2318
+ $lhs = new Math_BigInteger();
2319
+ $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2320
+ $rhs = new Math_BigInteger();
2321
+ $rhs->value = $n;
2322
+
2323
+ list(, $temp) = $lhs->divide($rhs);
2324
+ return $temp->value;
2325
+ }
2326
+
2327
+ /**
2328
+ * Modular Inverse of a number mod 2**26 (eg. 67108864)
2329
+ *
2330
+ * Based off of the bnpInvDigit function implemented and justified in the following URL:
2331
+ *
2332
+ * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2333
+ *
2334
+ * The following URL provides more info:
2335
+ *
2336
+ * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2337
+ *
2338
+ * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
2339
+ * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2340
+ * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2341
+ * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
2342
+ * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
2343
+ * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
2344
+ * 40 bits, which only 64-bit floating points will support.
2345
+ *
2346
+ * Thanks to Pedro Gimeno Fortea for input!
2347
+ *
2348
+ * @see _montgomery()
2349
+ * @access private
2350
+ * @param Array $x
2351
+ * @return Integer
2352
+ */
2353
+ function _modInverse67108864($x) // 2**26 == 67,108,864
2354
+ {
2355
+ $x = -$x[0];
2356
+ $result = $x & 0x3; // x**-1 mod 2**2
2357
+ $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2358
+ $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
2359
+ $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2360
+ $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
2361
+ return $result & MATH_BIGINTEGER_MAX_DIGIT;
2362
+ }
2363
+
2364
+ /**
2365
+ * Calculates modular inverses.
2366
+ *
2367
+ * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
2368
+ *
2369
+ * Here's an example:
2370
+ * <code>
2371
+ * <?php
2372
+ * include('Math/BigInteger.php');
2373
+ *
2374
+ * $a = new Math_BigInteger(30);
2375
+ * $b = new Math_BigInteger(17);
2376
+ *
2377
+ * $c = $a->modInverse($b);
2378
+ * echo $c->toString(); // outputs 4
2379
+ *
2380
+ * echo "\r\n";
2381
+ *
2382
+ * $d = $a->multiply($c);
2383
+ * list(, $d) = $d->divide($b);
2384
+ * echo $d; // outputs 1 (as per the definition of modular inverse)
2385
+ * ?>
2386
+ * </code>
2387
+ *
2388
+ * @param Math_BigInteger $n
2389
+ * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
2390
+ * @access public
2391
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2392
+ */
2393
+ function modInverse($n)
2394
+ {
2395
+ switch ( MATH_BIGINTEGER_MODE ) {
2396
+ case MATH_BIGINTEGER_MODE_GMP:
2397
+ $temp = new Math_BigInteger();
2398
+ $temp->value = gmp_invert($this->value, $n->value);
2399
+
2400
+ return ( $temp->value === false ) ? false : $this->_normalize($temp);
2401
+ }
2402
+
2403
+ static $zero, $one;
2404
+ if (!isset($zero)) {
2405
+ $zero = new Math_BigInteger();
2406
+ $one = new Math_BigInteger(1);
2407
+ }
2408
+
2409
+ // $x mod -$n == $x mod $n.
2410
+ $n = $n->abs();
2411
+
2412
+ if ($this->compare($zero) < 0) {
2413
+ $temp = $this->abs();
2414
+ $temp = $temp->modInverse($n);
2415
+ return $this->_normalize($n->subtract($temp));
2416
+ }
2417
+
2418
+ extract($this->extendedGCD($n));
2419
+
2420
+ if (!$gcd->equals($one)) {
2421
+ return false;
2422
+ }
2423
+
2424
+ $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2425
+
2426
+ return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2427
+ }
2428
+
2429
+ /**
2430
+ * Calculates the greatest common divisor and Bezout's identity.
2431
+ *
2432
+ * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that
2433
+ * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
2434
+ * combination is returned is dependant upon which mode is in use. See
2435
+ * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
2436
+ *
2437
+ * Here's an example:
2438
+ * <code>
2439
+ * <?php
2440
+ * include('Math/BigInteger.php');
2441
+ *
2442
+ * $a = new Math_BigInteger(693);
2443
+ * $b = new Math_BigInteger(609);
2444
+ *
2445
+ * extract($a->extendedGCD($b));
2446
+ *
2447
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2448
+ * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2449
+ * ?>
2450
+ * </code>
2451
+ *
2452
+ * @param Math_BigInteger $n
2453
+ * @return Math_BigInteger
2454
+ * @access public
2455
+ * @internal Calculates the GCD using the binary xGCD algorithim described in
2456
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
2457
+ * the more traditional algorithim requires "relatively costly multiple-precision divisions".
2458
+ */
2459
+ function extendedGCD($n)
2460
+ {
2461
+ switch ( MATH_BIGINTEGER_MODE ) {
2462
+ case MATH_BIGINTEGER_MODE_GMP:
2463
+ extract(gmp_gcdext($this->value, $n->value));
2464
+
2465
+ return array(
2466
+ 'gcd' => $this->_normalize(new Math_BigInteger($g)),
2467
+ 'x' => $this->_normalize(new Math_BigInteger($s)),
2468
+ 'y' => $this->_normalize(new Math_BigInteger($t))
2469
+ );
2470
+ case MATH_BIGINTEGER_MODE_BCMATH:
2471
+ // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2472
+ // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
2473
+ // the basic extended euclidean algorithim is what we're using.
2474
+
2475
+ $u = $this->value;
2476
+ $v = $n->value;
2477
+
2478
+ $a = '1';
2479
+ $b = '0';
2480
+ $c = '0';
2481
+ $d = '1';
2482
+
2483
+ while (bccomp($v, '0', 0) != 0) {
2484
+ $q = bcdiv($u, $v, 0);
2485
+
2486
+ $temp = $u;
2487
+ $u = $v;
2488
+ $v = bcsub($temp, bcmul($v, $q, 0), 0);
2489
+
2490
+ $temp = $a;
2491
+ $a = $c;
2492
+ $c = bcsub($temp, bcmul($a, $q, 0), 0);
2493
+
2494
+ $temp = $b;
2495
+ $b = $d;
2496
+ $d = bcsub($temp, bcmul($b, $q, 0), 0);
2497
+ }
2498
+
2499
+ return array(
2500
+ 'gcd' => $this->_normalize(new Math_BigInteger($u)),
2501
+ 'x' => $this->_normalize(new Math_BigInteger($a)),
2502
+ 'y' => $this->_normalize(new Math_BigInteger($b))
2503
+ );
2504
+ }
2505
+
2506
+ $y = $n->copy();
2507
+ $x = $this->copy();
2508
+ $g = new Math_BigInteger();
2509
+ $g->value = array(1);
2510
+
2511
+ while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
2512
+ $x->_rshift(1);
2513
+ $y->_rshift(1);
2514
+ $g->_lshift(1);
2515
+ }
2516
+
2517
+ $u = $x->copy();
2518
+ $v = $y->copy();
2519
+
2520
+ $a = new Math_BigInteger();
2521
+ $b = new Math_BigInteger();
2522
+ $c = new Math_BigInteger();
2523
+ $d = new Math_BigInteger();
2524
+
2525
+ $a->value = $d->value = $g->value = array(1);
2526
+ $b->value = $c->value = array();
2527
+
2528
+ while ( !empty($u->value) ) {
2529
+ while ( !($u->value[0] & 1) ) {
2530
+ $u->_rshift(1);
2531
+ if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
2532
+ $a = $a->add($y);
2533
+ $b = $b->subtract($x);
2534
+ }
2535
+ $a->_rshift(1);
2536
+ $b->_rshift(1);
2537
+ }
2538
+
2539
+ while ( !($v->value[0] & 1) ) {
2540
+ $v->_rshift(1);
2541
+ if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
2542
+ $c = $c->add($y);
2543
+ $d = $d->subtract($x);
2544
+ }
2545
+ $c->_rshift(1);
2546
+ $d->_rshift(1);
2547
+ }
2548
+
2549
+ if ($u->compare($v) >= 0) {
2550
+ $u = $u->subtract($v);
2551
+ $a = $a->subtract($c);
2552
+ $b = $b->subtract($d);
2553
+ } else {
2554
+ $v = $v->subtract($u);
2555
+ $c = $c->subtract($a);
2556
+ $d = $d->subtract($b);
2557
+ }
2558
+ }
2559
+
2560
+ return array(
2561
+ 'gcd' => $this->_normalize($g->multiply($v)),
2562
+ 'x' => $this->_normalize($c),
2563
+ 'y' => $this->_normalize($d)
2564
+ );
2565
+ }
2566
+
2567
+ /**
2568
+ * Calculates the greatest common divisor
2569
+ *
2570
+ * Say you have 693 and 609. The GCD is 21.
2571
+ *
2572
+ * Here's an example:
2573
+ * <code>
2574
+ * <?php
2575
+ * include('Math/BigInteger.php');
2576
+ *
2577
+ * $a = new Math_BigInteger(693);
2578
+ * $b = new Math_BigInteger(609);
2579
+ *
2580
+ * $gcd = a->extendedGCD($b);
2581
+ *
2582
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2583
+ * ?>
2584
+ * </code>
2585
+ *
2586
+ * @param Math_BigInteger $n
2587
+ * @return Math_BigInteger
2588
+ * @access public
2589
+ */
2590
+ function gcd($n)
2591
+ {
2592
+ extract($this->extendedGCD($n));
2593
+ return $gcd;
2594
+ }
2595
+
2596
+ /**
2597
+ * Absolute value.
2598
+ *
2599
+ * @return Math_BigInteger
2600
+ * @access public
2601
+ */
2602
+ function abs()
2603
+ {
2604
+ $temp = new Math_BigInteger();
2605
+
2606
+ switch ( MATH_BIGINTEGER_MODE ) {
2607
+ case MATH_BIGINTEGER_MODE_GMP:
2608
+ $temp->value = gmp_abs($this->value);
2609
+ break;
2610
+ case MATH_BIGINTEGER_MODE_BCMATH:
2611
+ $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2612
+ break;
2613
+ default:
2614
+ $temp->value = $this->value;
2615
+ }
2616
+
2617
+ return $temp;
2618
+ }
2619
+
2620
+ /**
2621
+ * Compares two numbers.
2622
+ *
2623
+ * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
2624
+ * demonstrated thusly:
2625
+ *
2626
+ * $x > $y: $x->compare($y) > 0
2627
+ * $x < $y: $x->compare($y) < 0
2628
+ * $x == $y: $x->compare($y) == 0
2629
+ *
2630
+ * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
2631
+ *
2632
+ * @param Math_BigInteger $y
2633
+ * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
2634
+ * @access public
2635
+ * @see equals()
2636
+ * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2637
+ */
2638
+ function compare($y)
2639
+ {
2640
+ switch ( MATH_BIGINTEGER_MODE ) {
2641
+ case MATH_BIGINTEGER_MODE_GMP:
2642
+ return gmp_cmp($this->value, $y->value);
2643
+ case MATH_BIGINTEGER_MODE_BCMATH:
2644
+ return bccomp($this->value, $y->value, 0);
2645
+ }
2646
+
2647
+ return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2648
+ }
2649
+
2650
+ /**
2651
+ * Compares two numbers.
2652
+ *
2653
+ * @param Array $x_value
2654
+ * @param Boolean $x_negative
2655
+ * @param Array $y_value
2656
+ * @param Boolean $y_negative
2657
+ * @return Integer
2658
+ * @see compare()
2659
+ * @access private
2660
+ */
2661
+ function _compare($x_value, $x_negative, $y_value, $y_negative)
2662
+ {
2663
+ if ( $x_negative != $y_negative ) {
2664
+ return ( !$x_negative && $y_negative ) ? 1 : -1;
2665
+ }
2666
+
2667
+ $result = $x_negative ? -1 : 1;
2668
+
2669
+ if ( count($x_value) != count($y_value) ) {
2670
+ return ( count($x_value) > count($y_value) ) ? $result : -$result;
2671
+ }
2672
+ $size = max(count($x_value), count($y_value));
2673
+
2674
+ $x_value = array_pad($x_value, $size, 0);
2675
+ $y_value = array_pad($y_value, $size, 0);
2676
+
2677
+ for ($i = count($x_value) - 1; $i >= 0; --$i) {
2678
+ if ($x_value[$i] != $y_value[$i]) {
2679
+ return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
2680
+ }
2681
+ }
2682
+
2683
+ return 0;
2684
+ }
2685
+
2686
+ /**
2687
+ * Tests the equality of two numbers.
2688
+ *
2689
+ * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
2690
+ *
2691
+ * @param Math_BigInteger $x
2692
+ * @return Boolean
2693
+ * @access public
2694
+ * @see compare()
2695
+ */
2696
+ function equals($x)
2697
+ {
2698
+ switch ( MATH_BIGINTEGER_MODE ) {
2699
+ case MATH_BIGINTEGER_MODE_GMP:
2700
+ return gmp_cmp($this->value, $x->value) == 0;
2701
+ default:
2702
+ return $this->value === $x->value && $this->is_negative == $x->is_negative;
2703
+ }
2704
+ }
2705
+
2706
+ /**
2707
+ * Set Precision
2708
+ *
2709
+ * Some bitwise operations give different results depending on the precision being used. Examples include left
2710
+ * shift, not, and rotates.
2711
+ *
2712
+ * @param Integer $bits
2713
+ * @access public
2714
+ */
2715
+ function setPrecision($bits)
2716
+ {
2717
+ $this->precision = $bits;
2718
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
2719
+ $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2720
+ } else {
2721
+ $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
2722
+ }
2723
+
2724
+ $temp = $this->_normalize($this);
2725
+ $this->value = $temp->value;
2726
+ }
2727
+
2728
+ /**
2729
+ * Logical And
2730
+ *
2731
+ * @param Math_BigInteger $x
2732
+ * @access public
2733
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2734
+ * @return Math_BigInteger
2735
+ */
2736
+ function bitwise_and($x)
2737
+ {
2738
+ switch ( MATH_BIGINTEGER_MODE ) {
2739
+ case MATH_BIGINTEGER_MODE_GMP:
2740
+ $temp = new Math_BigInteger();
2741
+ $temp->value = gmp_and($this->value, $x->value);
2742
+
2743
+ return $this->_normalize($temp);
2744
+ case MATH_BIGINTEGER_MODE_BCMATH:
2745
+ $left = $this->toBytes();
2746
+ $right = $x->toBytes();
2747
+
2748
+ $length = max(strlen($left), strlen($right));
2749
+
2750
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2751
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2752
+
2753
+ return $this->_normalize(new Math_BigInteger($left & $right, 256));
2754
+ }
2755
+
2756
+ $result = $this->copy();
2757
+
2758
+ $length = min(count($x->value), count($this->value));
2759
+
2760
+ $result->value = array_slice($result->value, 0, $length);
2761
+
2762
+ for ($i = 0; $i < $length; ++$i) {
2763
+ $result->value[$i]&= $x->value[$i];
2764
+ }
2765
+
2766
+ return $this->_normalize($result);
2767
+ }
2768
+
2769
+ /**
2770
+ * Logical Or
2771
+ *
2772
+ * @param Math_BigInteger $x
2773
+ * @access public
2774
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2775
+ * @return Math_BigInteger
2776
+ */
2777
+ function bitwise_or($x)
2778
+ {
2779
+ switch ( MATH_BIGINTEGER_MODE ) {
2780
+ case MATH_BIGINTEGER_MODE_GMP:
2781
+ $temp = new Math_BigInteger();
2782
+ $temp->value = gmp_or($this->value, $x->value);
2783
+
2784
+ return $this->_normalize($temp);
2785
+ case MATH_BIGINTEGER_MODE_BCMATH:
2786
+ $left = $this->toBytes();
2787
+ $right = $x->toBytes();
2788
+
2789
+ $length = max(strlen($left), strlen($right));
2790
+
2791
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2792
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2793
+
2794
+ return $this->_normalize(new Math_BigInteger($left | $right, 256));
2795
+ }
2796
+
2797
+ $length = max(count($this->value), count($x->value));
2798
+ $result = $this->copy();
2799
+ $result->value = array_pad($result->value, $length, 0);
2800
+ $x->value = array_pad($x->value, $length, 0);
2801
+
2802
+ for ($i = 0; $i < $length; ++$i) {
2803
+ $result->value[$i]|= $x->value[$i];
2804
+ }
2805
+
2806
+ return $this->_normalize($result);
2807
+ }
2808
+
2809
+ /**
2810
+ * Logical Exclusive-Or
2811
+ *
2812
+ * @param Math_BigInteger $x
2813
+ * @access public
2814
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2815
+ * @return Math_BigInteger
2816
+ */
2817
+ function bitwise_xor($x)
2818
+ {
2819
+ switch ( MATH_BIGINTEGER_MODE ) {
2820
+ case MATH_BIGINTEGER_MODE_GMP:
2821
+ $temp = new Math_BigInteger();
2822
+ $temp->value = gmp_xor($this->value, $x->value);
2823
+
2824
+ return $this->_normalize($temp);
2825
+ case MATH_BIGINTEGER_MODE_BCMATH:
2826
+ $left = $this->toBytes();
2827
+ $right = $x->toBytes();
2828
+
2829
+ $length = max(strlen($left), strlen($right));
2830
+
2831
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2832
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2833
+
2834
+ return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
2835
+ }
2836
+
2837
+ $length = max(count($this->value), count($x->value));
2838
+ $result = $this->copy();
2839
+ $result->value = array_pad($result->value, $length, 0);
2840
+ $x->value = array_pad($x->value, $length, 0);
2841
+
2842
+ for ($i = 0; $i < $length; ++$i) {
2843
+ $result->value[$i]^= $x->value[$i];
2844
+ }
2845
+
2846
+ return $this->_normalize($result);
2847
+ }
2848
+
2849
+ /**
2850
+ * Logical Not
2851
+ *
2852
+ * @access public
2853
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2854
+ * @return Math_BigInteger
2855
+ */
2856
+ function bitwise_not()
2857
+ {
2858
+ // calculuate "not" without regard to $this->precision
2859
+ // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
2860
+ $temp = $this->toBytes();
2861
+ $pre_msb = decbin(ord($temp[0]));
2862
+ $temp = ~$temp;
2863
+ $msb = decbin(ord($temp[0]));
2864
+ if (strlen($msb) == 8) {
2865
+ $msb = substr($msb, strpos($msb, '0'));
2866
+ }
2867
+ $temp[0] = chr(bindec($msb));
2868
+
2869
+ // see if we need to add extra leading 1's
2870
+ $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2871
+ $new_bits = $this->precision - $current_bits;
2872
+ if ($new_bits <= 0) {
2873
+ return $this->_normalize(new Math_BigInteger($temp, 256));
2874
+ }
2875
+
2876
+ // generate as many leading 1's as we need to.
2877
+ $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2878
+ $this->_base256_lshift($leading_ones, $current_bits);
2879
+
2880
+ $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);
2881
+
2882
+ return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
2883
+ }
2884
+
2885
+ /**
2886
+ * Logical Right Shift
2887
+ *
2888
+ * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2889
+ *
2890
+ * @param Integer $shift
2891
+ * @return Math_BigInteger
2892
+ * @access public
2893
+ * @internal The only version that yields any speed increases is the internal version.
2894
+ */
2895
+ function bitwise_rightShift($shift)
2896
+ {
2897
+ $temp = new Math_BigInteger();
2898
+
2899
+ switch ( MATH_BIGINTEGER_MODE ) {
2900
+ case MATH_BIGINTEGER_MODE_GMP:
2901
+ static $two;
2902
+
2903
+ if (!isset($two)) {
2904
+ $two = gmp_init('2');
2905
+ }
2906
+
2907
+ $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2908
+
2909
+ break;
2910
+ case MATH_BIGINTEGER_MODE_BCMATH:
2911
+ $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2912
+
2913
+ break;
2914
+ default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2915
+ // and I don't want to do that...
2916
+ $temp->value = $this->value;
2917
+ $temp->_rshift($shift);
2918
+ }
2919
+
2920
+ return $this->_normalize($temp);
2921
+ }
2922
+
2923
+ /**
2924
+ * Logical Left Shift
2925
+ *
2926
+ * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2927
+ *
2928
+ * @param Integer $shift
2929
+ * @return Math_BigInteger
2930
+ * @access public
2931
+ * @internal The only version that yields any speed increases is the internal version.
2932
+ */
2933
+ function bitwise_leftShift($shift)
2934
+ {
2935
+ $temp = new Math_BigInteger();
2936
+
2937
+ switch ( MATH_BIGINTEGER_MODE ) {
2938
+ case MATH_BIGINTEGER_MODE_GMP:
2939
+ static $two;
2940
+
2941
+ if (!isset($two)) {
2942
+ $two = gmp_init('2');
2943
+ }
2944
+
2945
+ $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2946
+
2947
+ break;
2948
+ case MATH_BIGINTEGER_MODE_BCMATH:
2949
+ $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
2950
+
2951
+ break;
2952
+ default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
2953
+ // and I don't want to do that...
2954
+ $temp->value = $this->value;
2955
+ $temp->_lshift($shift);
2956
+ }
2957
+
2958
+ return $this->_normalize($temp);
2959
+ }
2960
+
2961
+ /**
2962
+ * Logical Left Rotate
2963
+ *
2964
+ * Instead of the top x bits being dropped they're appended to the shifted bit string.
2965
+ *
2966
+ * @param Integer $shift
2967
+ * @return Math_BigInteger
2968
+ * @access public
2969
+ */
2970
+ function bitwise_leftRotate($shift)
2971
+ {
2972
+ $bits = $this->toBytes();
2973
+
2974
+ if ($this->precision > 0) {
2975
+ $precision = $this->precision;
2976
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
2977
+ $mask = $this->bitmask->subtract(new Math_BigInteger(1));
2978
+ $mask = $mask->toBytes();
2979
+ } else {
2980
+ $mask = $this->bitmask->toBytes();
2981
+ }
2982
+ } else {
2983
+ $temp = ord($bits[0]);
2984
+ for ($i = 0; $temp >> $i; ++$i);
2985
+ $precision = 8 * strlen($bits) - 8 + $i;
2986
+ $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
2987
+ }
2988
+
2989
+ if ($shift < 0) {
2990
+ $shift+= $precision;
2991
+ }
2992
+ $shift%= $precision;
2993
+
2994
+ if (!$shift) {
2995
+ return $this->copy();
2996
+ }
2997
+
2998
+ $left = $this->bitwise_leftShift($shift);
2999
+ $left = $left->bitwise_and(new Math_BigInteger($mask, 256));
3000
+ $right = $this->bitwise_rightShift($precision - $shift);
3001
+ $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3002
+ return $this->_normalize($result);
3003
+ }
3004
+
3005
+ /**
3006
+ * Logical Right Rotate
3007
+ *
3008
+ * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
3009
+ *
3010
+ * @param Integer $shift
3011
+ * @return Math_BigInteger
3012
+ * @access public
3013
+ */
3014
+ function bitwise_rightRotate($shift)
3015
+ {
3016
+ return $this->bitwise_leftRotate(-$shift);
3017
+ }
3018
+
3019
+ /**
3020
+ * Set random number generator function
3021
+ *
3022
+ * This function is deprecated.
3023
+ *
3024
+ * @param String $generator
3025
+ * @access public
3026
+ */
3027
+ function setRandomGenerator($generator)
3028
+ {
3029
+ }
3030
+
3031
+ /**
3032
+ * Generate a random number
3033
+ *
3034
+ * @param optional Integer $min
3035
+ * @param optional Integer $max
3036
+ * @return Math_BigInteger
3037
+ * @access public
3038
+ */
3039
+ function random($min = false, $max = false)
3040
+ {
3041
+ if ($min === false) {
3042
+ $min = new Math_BigInteger(0);
3043
+ }
3044
+
3045
+ if ($max === false) {
3046
+ $max = new Math_BigInteger(0x7FFFFFFF);
3047
+ }
3048
+
3049
+ $compare = $max->compare($min);
3050
+
3051
+ if (!$compare) {
3052
+ return $this->_normalize($min);
3053
+ } else if ($compare < 0) {
3054
+ // if $min is bigger then $max, swap $min and $max
3055
+ $temp = $max;
3056
+ $max = $min;
3057
+ $min = $temp;
3058
+ }
3059
+
3060
+ $max = $max->subtract($min);
3061
+ $max = ltrim($max->toBytes(), chr(0));
3062
+ $size = strlen($max) - 1;
3063
+
3064
+ $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string'));
3065
+ if ($crypt_random) {
3066
+ $random = crypt_random_string($size);
3067
+ } else {
3068
+ $random = '';
3069
+
3070
+ if ($size & 1) {
3071
+ $random.= chr(mt_rand(0, 255));
3072
+ }
3073
+
3074
+ $blocks = $size >> 1;
3075
+ for ($i = 0; $i < $blocks; ++$i) {
3076
+ // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3077
+ $random.= pack('n', mt_rand(0, 0xFFFF));
3078
+ }
3079
+ }
3080
+
3081
+ $fragment = new Math_BigInteger($random, 256);
3082
+ $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ?
3083
+ ord($max[0]) - 1 : ord($max[0]);
3084
+
3085
+ if (!$crypt_random) {
3086
+ $msb = chr(mt_rand(0, $leading));
3087
+ } else {
3088
+ $cutoff = floor(0xFF / $leading) * $leading;
3089
+ while (true) {
3090
+ $msb = ord(crypt_random_string(1));
3091
+ if ($msb <= $cutoff) {
3092
+ $msb%= $leading;
3093
+ break;
3094
+ }
3095
+ }
3096
+ $msb = chr($msb);
3097
+ }
3098
+
3099
+ $random = new Math_BigInteger($msb . $random, 256);
3100
+
3101
+ return $this->_normalize($random->add($min));
3102
+ }
3103
+
3104
+ /**
3105
+ * Generate a random prime number.
3106
+ *
3107
+ * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed,
3108
+ * give up and return false.
3109
+ *
3110
+ * @param optional Integer $min
3111
+ * @param optional Integer $max
3112
+ * @param optional Integer $timeout
3113
+ * @return Math_BigInteger
3114
+ * @access public
3115
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3116
+ */
3117
+ function randomPrime($min = false, $max = false, $timeout = false)
3118
+ {
3119
+ if ($min === false) {
3120
+ $min = new Math_BigInteger(0);
3121
+ }
3122
+
3123
+ if ($max === false) {
3124
+ $max = new Math_BigInteger(0x7FFFFFFF);
3125
+ }
3126
+
3127
+ $compare = $max->compare($min);
3128
+
3129
+ if (!$compare) {
3130
+ return $min->isPrime() ? $min : false;
3131
+ } else if ($compare < 0) {
3132
+ // if $min is bigger then $max, swap $min and $max
3133
+ $temp = $max;
3134
+ $max = $min;
3135
+ $min = $temp;
3136
+ }
3137
+
3138
+ static $one, $two;
3139
+ if (!isset($one)) {
3140
+ $one = new Math_BigInteger(1);
3141
+ $two = new Math_BigInteger(2);
3142
+ }
3143
+
3144
+ $start = time();
3145
+
3146
+ $x = $this->random($min, $max);
3147
+
3148
+ // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3149
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
3150
+ $p->value = gmp_nextprime($x->value);
3151
+
3152
+ if ($p->compare($max) <= 0) {
3153
+ return $p;
3154
+ }
3155
+
3156
+ if (!$min->equals($x)) {
3157
+ $x = $x->subtract($one);
3158
+ }
3159
+
3160
+ return $x->randomPrime($min, $x);
3161
+ }
3162
+
3163
+ if ($x->equals($two)) {
3164
+ return $x;
3165
+ }
3166
+
3167
+ $x->_make_odd();
3168
+ if ($x->compare($max) > 0) {
3169
+ // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3170
+ if ($min->equals($max)) {
3171
+ return false;
3172
+ }
3173
+ $x = $min->copy();
3174
+ $x->_make_odd();
3175
+ }
3176
+
3177
+ $initial_x = $x->copy();
3178
+
3179
+ while (true) {
3180
+ if ($timeout !== false && time() - $start > $timeout) {
3181
+ return false;
3182
+ }
3183
+
3184
+ if ($x->isPrime()) {
3185
+ return $x;
3186
+ }
3187
+
3188
+ $x = $x->add($two);
3189
+
3190
+ if ($x->compare($max) > 0) {
3191
+ $x = $min->copy();
3192
+ if ($x->equals($two)) {
3193
+ return $x;
3194
+ }
3195
+ $x->_make_odd();
3196
+ }
3197
+
3198
+ if ($x->equals($initial_x)) {
3199
+ return false;
3200
+ }
3201
+ }
3202
+ }
3203
+
3204
+ /**
3205
+ * Make the current number odd
3206
+ *
3207
+ * If the current number is odd it'll be unchanged. If it's even, one will be added to it.
3208
+ *
3209
+ * @see randomPrime()
3210
+ * @access private
3211
+ */
3212
+ function _make_odd()
3213
+ {
3214
+ switch ( MATH_BIGINTEGER_MODE ) {
3215
+ case MATH_BIGINTEGER_MODE_GMP:
3216
+ gmp_setbit($this->value, 0);
3217
+ break;
3218
+ case MATH_BIGINTEGER_MODE_BCMATH:
3219
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3220
+ $this->value = bcadd($this->value, '1');
3221
+ }
3222
+ break;
3223
+ default:
3224
+ $this->value[0] |= 1;
3225
+ }
3226
+ }
3227
+
3228
+ /**
3229
+ * Checks a numer to see if it's prime
3230
+ *
3231
+ * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
3232
+ * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads
3233
+ * on a website instead of just one.
3234
+ *
3235
+ * @param optional Integer $t
3236
+ * @return Boolean
3237
+ * @access public
3238
+ * @internal Uses the
3239
+ * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
3240
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3241
+ */
3242
+ function isPrime($t = false)
3243
+ {
3244
+ $length = strlen($this->toBytes());
3245
+
3246
+ if (!$t) {
3247
+ // see HAC 4.49 "Note (controlling the error probability)"
3248
+ if ($length >= 163) { $t = 2; } // floor(1300 / 8)
3249
+ else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
3250
+ else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
3251
+ else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
3252
+ else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
3253
+ else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
3254
+ else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
3255
+ else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
3256
+ else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3257
+ else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3258
+ else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3259
+ else { $t = 27; }
3260
+ }
3261
+
3262
+ // ie. gmp_testbit($this, 0)
3263
+ // ie. isEven() or !isOdd()
3264
+ switch ( MATH_BIGINTEGER_MODE ) {
3265
+ case MATH_BIGINTEGER_MODE_GMP:
3266
+ return gmp_prob_prime($this->value, $t) != 0;
3267
+ case MATH_BIGINTEGER_MODE_BCMATH:
3268
+ if ($this->value === '2') {
3269
+ return true;
3270
+ }
3271
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3272
+ return false;
3273
+ }
3274
+ break;
3275
+ default:
3276
+ if ($this->value == array(2)) {
3277
+ return true;
3278
+ }
3279
+ if (~$this->value[0] & 1) {
3280
+ return false;
3281
+ }
3282
+ }
3283
+
3284
+ static $primes, $zero, $one, $two;
3285
+
3286
+ if (!isset($primes)) {
3287
+ $primes = array(
3288
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3289
+ 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3290
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3291
+ 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3292
+ 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3293
+ 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3294
+ 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3295
+ 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3296
+ 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3297
+ 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3298
+ 953, 967, 971, 977, 983, 991, 997
3299
+ );
3300
+
3301
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3302
+ for ($i = 0; $i < count($primes); ++$i) {
3303
+ $primes[$i] = new Math_BigInteger($primes[$i]);
3304
+ }
3305
+ }
3306
+
3307
+ $zero = new Math_BigInteger();
3308
+ $one = new Math_BigInteger(1);
3309
+ $two = new Math_BigInteger(2);
3310
+ }
3311
+
3312
+ if ($this->equals($one)) {
3313
+ return false;
3314
+ }
3315
+
3316
+ // see HAC 4.4.1 "Random search for probable primes"
3317
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3318
+ foreach ($primes as $prime) {
3319
+ list(, $r) = $this->divide($prime);
3320
+ if ($r->equals($zero)) {
3321
+ return $this->equals($prime);
3322
+ }
3323
+ }
3324
+ } else {
3325
+ $value = $this->value;
3326
+ foreach ($primes as $prime) {
3327
+ list(, $r) = $this->_divide_digit($value, $prime);
3328
+ if (!$r) {
3329
+ return count($value) == 1 && $value[0] == $prime;
3330
+ }
3331
+ }
3332
+ }
3333
+
3334
+ $n = $this->copy();
3335
+ $n_1 = $n->subtract($one);
3336
+ $n_2 = $n->subtract($two);
3337
+
3338
+ $r = $n_1->copy();
3339
+ $r_value = $r->value;
3340
+ // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3341
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3342
+ $s = 0;
3343
+ // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3344
+ while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3345
+ $r->value = bcdiv($r->value, '2', 0);
3346
+ ++$s;
3347
+ }
3348
+ } else {
3349
+ for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3350
+ $temp = ~$r_value[$i] & 0xFFFFFF;
3351
+ for ($j = 1; ($temp >> $j) & 1; ++$j);
3352
+ if ($j != 25) {
3353
+ break;
3354
+ }
3355
+ }
3356
+ $s = 26 * $i + $j - 1;
3357
+ $r->_rshift($s);
3358
+ }
3359
+
3360
+ for ($i = 0; $i < $t; ++$i) {
3361
+ $a = $this->random($two, $n_2);
3362
+ $y = $a->modPow($r, $n);
3363
+
3364
+ if (!$y->equals($one) && !$y->equals($n_1)) {
3365
+ for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3366
+ $y = $y->modPow($two, $n);
3367
+ if ($y->equals($one)) {
3368
+ return false;
3369
+ }
3370
+ }
3371
+
3372
+ if (!$y->equals($n_1)) {
3373
+ return false;
3374
+ }
3375
+ }
3376
+ }
3377
+ return true;
3378
+ }
3379
+
3380
+ /**
3381
+ * Logical Left Shift
3382
+ *
3383
+ * Shifts BigInteger's by $shift bits.
3384
+ *
3385
+ * @param Integer $shift
3386
+ * @access private
3387
+ */
3388
+ function _lshift($shift)
3389
+ {
3390
+ if ( $shift == 0 ) {
3391
+ return;
3392
+ }
3393
+
3394
+ $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3395
+ $shift %= MATH_BIGINTEGER_BASE;
3396
+ $shift = 1 << $shift;
3397
+
3398
+ $carry = 0;
3399
+
3400
+ for ($i = 0; $i < count($this->value); ++$i) {
3401
+ $temp = $this->value[$i] * $shift + $carry;
3402
+ $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);
3403
+ $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
3404
+ }
3405
+
3406
+ if ( $carry ) {
3407
+ $this->value[] = $carry;
3408
+ }
3409
+
3410
+ while ($num_digits--) {
3411
+ array_unshift($this->value, 0);
3412
+ }
3413
+ }
3414
+
3415
+ /**
3416
+ * Logical Right Shift
3417
+ *
3418
+ * Shifts BigInteger's by $shift bits.
3419
+ *
3420
+ * @param Integer $shift
3421
+ * @access private
3422
+ */
3423
+ function _rshift($shift)
3424
+ {
3425
+ if ($shift == 0) {
3426
+ return;
3427
+ }
3428
+
3429
+ $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3430
+ $shift %= MATH_BIGINTEGER_BASE;
3431
+ $carry_shift = MATH_BIGINTEGER_BASE - $shift;
3432
+ $carry_mask = (1 << $shift) - 1;
3433
+
3434
+ if ( $num_digits ) {
3435
+ $this->value = array_slice($this->value, $num_digits);
3436
+ }
3437
+
3438
+ $carry = 0;
3439
+
3440
+ for ($i = count($this->value) - 1; $i >= 0; --$i) {
3441
+ $temp = $this->value[$i] >> $shift | $carry;
3442
+ $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3443
+ $this->value[$i] = $temp;
3444
+ }
3445
+
3446
+ $this->value = $this->_trim($this->value);
3447
+ }
3448
+
3449
+ /**
3450
+ * Normalize
3451
+ *
3452
+ * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3453
+ *
3454
+ * @param Math_BigInteger
3455
+ * @return Math_BigInteger
3456
+ * @see _trim()
3457
+ * @access private
3458
+ */
3459
+ function _normalize($result)
3460
+ {
3461
+ $result->precision = $this->precision;
3462
+ $result->bitmask = $this->bitmask;
3463
+
3464
+ switch ( MATH_BIGINTEGER_MODE ) {
3465
+ case MATH_BIGINTEGER_MODE_GMP:
3466
+ if (!empty($result->bitmask->value)) {
3467
+ $result->value = gmp_and($result->value, $result->bitmask->value);
3468
+ }
3469
+
3470
+ return $result;
3471
+ case MATH_BIGINTEGER_MODE_BCMATH:
3472
+ if (!empty($result->bitmask->value)) {
3473
+ $result->value = bcmod($result->value, $result->bitmask->value);
3474
+ }
3475
+
3476
+ return $result;
3477
+ }
3478
+
3479
+ $value = &$result->value;
3480
+
3481
+ if ( !count($value) ) {
3482
+ return $result;
3483
+ }
3484
+
3485
+ $value = $this->_trim($value);
3486
+
3487
+ if (!empty($result->bitmask->value)) {
3488
+ $length = min(count($value), count($this->bitmask->value));
3489
+ $value = array_slice($value, 0, $length);
3490
+
3491
+ for ($i = 0; $i < $length; ++$i) {
3492
+ $value[$i] = $value[$i] & $this->bitmask->value[$i];
3493
+ }
3494
+ }
3495
+
3496
+ return $result;
3497
+ }
3498
+
3499
+ /**
3500
+ * Trim
3501
+ *
3502
+ * Removes leading zeros
3503
+ *
3504
+ * @param Array $value
3505
+ * @return Math_BigInteger
3506
+ * @access private
3507
+ */
3508
+ function _trim($value)
3509
+ {
3510
+ for ($i = count($value) - 1; $i >= 0; --$i) {
3511
+ if ( $value[$i] ) {
3512
+ break;
3513
+ }
3514
+ unset($value[$i]);
3515
+ }
3516
+
3517
+ return $value;
3518
+ }
3519
+
3520
+ /**
3521
+ * Array Repeat
3522
+ *
3523
+ * @param $input Array
3524
+ * @param $multiplier mixed
3525
+ * @return Array
3526
+ * @access private
3527
+ */
3528
+ function _array_repeat($input, $multiplier)
3529
+ {
3530
+ return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3531
+ }
3532
+
3533
+ /**
3534
+ * Logical Left Shift
3535
+ *
3536
+ * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3537
+ *
3538
+ * @param $x String
3539
+ * @param $shift Integer
3540
+ * @return String
3541
+ * @access private
3542
+ */
3543
+ function _base256_lshift(&$x, $shift)
3544
+ {
3545
+ if ($shift == 0) {
3546
+ return;
3547
+ }
3548
+
3549
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3550
+ $shift &= 7; // eg. $shift % 8
3551
+
3552
+ $carry = 0;
3553
+ for ($i = strlen($x) - 1; $i >= 0; --$i) {
3554
+ $temp = ord($x[$i]) << $shift | $carry;
3555
+ $x[$i] = chr($temp);
3556
+ $carry = $temp >> 8;
3557
+ }
3558
+ $carry = ($carry != 0) ? chr($carry) : '';
3559
+ $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3560
+ }
3561
+
3562
+ /**
3563
+ * Logical Right Shift
3564
+ *
3565
+ * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3566
+ *
3567
+ * @param $x String
3568
+ * @param $shift Integer
3569
+ * @return String
3570
+ * @access private
3571
+ */
3572
+ function _base256_rshift(&$x, $shift)
3573
+ {
3574
+ if ($shift == 0) {
3575
+ $x = ltrim($x, chr(0));
3576
+ return '';
3577
+ }
3578
+
3579
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3580
+ $shift &= 7; // eg. $shift % 8
3581
+
3582
+ $remainder = '';
3583
+ if ($num_bytes) {
3584
+ $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3585
+ $remainder = substr($x, $start);
3586
+ $x = substr($x, 0, -$num_bytes);
3587
+ }
3588
+
3589
+ $carry = 0;
3590
+ $carry_shift = 8 - $shift;
3591
+ for ($i = 0; $i < strlen($x); ++$i) {
3592
+ $temp = (ord($x[$i]) >> $shift) | $carry;
3593
+ $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3594
+ $x[$i] = chr($temp);
3595
+ }
3596
+ $x = ltrim($x, chr(0));
3597
+
3598
+ $remainder = chr($carry >> $carry_shift) . $remainder;
3599
+
3600
+ return ltrim($remainder, chr(0));
3601
+ }
3602
+
3603
+ // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3604
+ // at 32-bits, while java's longs are 64-bits.
3605
+
3606
+ /**
3607
+ * Converts 32-bit integers to bytes.
3608
+ *
3609
+ * @param Integer $x
3610
+ * @return String
3611
+ * @access private
3612
+ */
3613
+ function _int2bytes($x)
3614
+ {
3615
+ return ltrim(pack('N', $x), chr(0));
3616
+ }
3617
+
3618
+ /**
3619
+ * Converts bytes to 32-bit integers
3620
+ *
3621
+ * @param String $x
3622
+ * @return Integer
3623
+ * @access private
3624
+ */
3625
+ function _bytes2int($x)
3626
+ {
3627
+ $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3628
+ return $temp['int'];
3629
+ }
3630
+
3631
+ /**
3632
+ * DER-encode an integer
3633
+ *
3634
+ * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3635
+ *
3636
+ * @see modPow()
3637
+ * @access private
3638
+ * @param Integer $length
3639
+ * @return String
3640
+ */
3641
+ function _encodeASN1Length($length)
3642
+ {
3643
+ if ($length <= 0x7F) {
3644
+ return chr($length);
3645
+ }
3646
+
3647
+ $temp = ltrim(pack('N', $length), chr(0));
3648
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
3649
+ }
3650
+ }
lib/phpseclib/Math/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ header("HTTP/1.0 404 Not Found");
lib/phpseclib/Net/SCP.php ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of SCP.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
10
+ *
11
+ * Here's a short example of how to use this library:
12
+ * <code>
13
+ * <?php
14
+ * include('Net/SCP.php');
15
+ * include('Net/SSH2.php');
16
+ *
17
+ * $ssh = new Net_SSH2('www.domain.tld');
18
+ * if (!$ssh->login('username', 'password')) {
19
+ * exit('bad login');
20
+ * }
21
+
22
+ * $scp = new Net_SCP($ssh);
23
+ * $scp->put('abcd', str_repeat('x', 1024*1024));
24
+ * ?>
25
+ * </code>
26
+ *
27
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
28
+ * of this software and associated documentation files (the "Software"), to deal
29
+ * in the Software without restriction, including without limitation the rights
30
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31
+ * copies of the Software, and to permit persons to whom the Software is
32
+ * furnished to do so, subject to the following conditions:
33
+ *
34
+ * The above copyright notice and this permission notice shall be included in
35
+ * all copies or substantial portions of the Software.
36
+ *
37
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43
+ * THE SOFTWARE.
44
+ *
45
+ * @category Net
46
+ * @package Net_SCP
47
+ * @author Jim Wigginton <terrafrost@php.net>
48
+ * @copyright MMX Jim Wigginton
49
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
50
+ * @link http://phpseclib.sourceforge.net
51
+ */
52
+
53
+ /**#@+
54
+ * @access public
55
+ * @see Net_SCP::put()
56
+ */
57
+ /**
58
+ * Reads data from a local file.
59
+ */
60
+ define('NET_SCP_LOCAL_FILE', 1);
61
+ /**
62
+ * Reads data from a string.
63
+ */
64
+ define('NET_SCP_STRING', 2);
65
+ /**#@-*/
66
+
67
+ /**#@+
68
+ * @access private
69
+ * @see Net_SCP::_send()
70
+ * @see Net_SCP::_receive()
71
+ */
72
+ /**
73
+ * SSH1 is being used.
74
+ */
75
+ define('NET_SCP_SSH1', 1);
76
+ /**
77
+ * SSH2 is being used.
78
+ */
79
+ define('NET_SCP_SSH2', 2);
80
+ /**#@-*/
81
+
82
+ /**
83
+ * Pure-PHP implementations of SCP.
84
+ *
85
+ * @author Jim Wigginton <terrafrost@php.net>
86
+ * @version 0.1.0
87
+ * @access public
88
+ * @package Net_SCP
89
+ */
90
+ class Net_SCP {
91
+ /**
92
+ * SSH Object
93
+ *
94
+ * @var Object
95
+ * @access private
96
+ */
97
+ var $ssh;
98
+
99
+ /**
100
+ * Packet Size
101
+ *
102
+ * @var Integer
103
+ * @access private
104
+ */
105
+ var $packet_size;
106
+
107
+ /**
108
+ * Mode
109
+ *
110
+ * @var Integer
111
+ * @access private
112
+ */
113
+ var $mode;
114
+
115
+ /**
116
+ * Default Constructor.
117
+ *
118
+ * Connects to an SSH server
119
+ *
120
+ * @param String $host
121
+ * @param optional Integer $port
122
+ * @param optional Integer $timeout
123
+ * @return Net_SCP
124
+ * @access public
125
+ */
126
+ function Net_SCP($ssh)
127
+ {
128
+ if (!is_object($ssh)) {
129
+ return;
130
+ }
131
+
132
+ switch (strtolower(get_class($ssh))) {
133
+ case'net_ssh2':
134
+ $this->mode = NET_SCP_SSH2;
135
+ break;
136
+ case 'net_ssh1':
137
+ $this->packet_size = 50000;
138
+ $this->mode = NET_SCP_SSH1;
139
+ break;
140
+ default:
141
+ return;
142
+ }
143
+
144
+ $this->ssh = $ssh;
145
+ }
146
+
147
+ /**
148
+ * Uploads a file to the SCP server.
149
+ *
150
+ * By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
151
+ * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes
152
+ * long, containing 'filename.ext' as its contents.
153
+ *
154
+ * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
155
+ * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
156
+ * large $remote_file will be, as well.
157
+ *
158
+ * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
159
+ * care of that, yourself.
160
+ *
161
+ * @param String $remote_file
162
+ * @param String $data
163
+ * @param optional Integer $mode
164
+ * @return Boolean
165
+ * @access public
166
+ */
167
+ function put($remote_file, $data, $mode = NET_SCP_STRING)
168
+ {
169
+ if (!isset($this->ssh)) {
170
+ return false;
171
+ }
172
+
173
+ $this->ssh->exec('scp -t ' . $remote_file, false); // -t = to
174
+
175
+ $temp = $this->_receive();
176
+ if ($temp !== chr(0)) {
177
+ return false;
178
+ }
179
+
180
+ if ($this->mode == NET_SCP_SSH2) {
181
+ $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC];
182
+ }
183
+
184
+ $remote_file = basename($remote_file);
185
+ $this->_send('C0644 ' . strlen($data) . ' ' . $remote_file . "\n");
186
+
187
+ $temp = $this->_receive();
188
+ if ($temp !== chr(0)) {
189
+ return false;
190
+ }
191
+
192
+ if ($mode == NET_SCP_STRING) {
193
+ $this->_send($data);
194
+ } else {
195
+ if (!is_file($data)) {
196
+ user_error("$data is not a valid file", E_USER_NOTICE);
197
+ return false;
198
+ }
199
+ $fp = @fopen($data, 'rb');
200
+ if (!$fp) {
201
+ return false;
202
+ }
203
+ $size = filesize($data);
204
+ for ($i = 0; $i < $size; $i += $this->packet_size) {
205
+ $this->_send(fgets($fp, $this->packet_size));
206
+ }
207
+ fclose($fp);
208
+ }
209
+ $this->_close();
210
+ }
211
+
212
+ /**
213
+ * Downloads a file from the SCP server.
214
+ *
215
+ * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
216
+ * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
217
+ * operation
218
+ *
219
+ * @param String $remote_file
220
+ * @param optional String $local_file
221
+ * @return Mixed
222
+ * @access public
223
+ */
224
+ function get($remote_file, $local_file = false)
225
+ {
226
+ if (!isset($this->ssh)) {
227
+ return false;
228
+ }
229
+
230
+ $this->ssh->exec('scp -f ' . $remote_file, false); // -f = from
231
+
232
+ $this->_send("\0");
233
+
234
+ if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) {
235
+ return false;
236
+ }
237
+
238
+ $this->_send("\0");
239
+
240
+ $size = 0;
241
+
242
+ if ($local_file !== false) {
243
+ $fp = @fopen($local_file, 'wb');
244
+ if (!$fp) {
245
+ return false;
246
+ }
247
+ }
248
+
249
+ $content = '';
250
+ while ($size < $info['size']) {
251
+ $data = $this->_receive();
252
+ // SCP usually seems to split stuff out into 16k chunks
253
+ $size+= strlen($data);
254
+
255
+ if ($local_file === false) {
256
+ $content.= $data;
257
+ } else {
258
+ fputs($fp, $data);
259
+ }
260
+ }
261
+
262
+ $this->_close();
263
+
264
+ if ($local_file !== false) {
265
+ fclose($fp);
266
+ return true;
267
+ }
268
+
269
+ return $content;
270
+ }
271
+
272
+ /**
273
+ * Sends a packet to an SSH server
274
+ *
275
+ * @param String $data
276
+ * @access private
277
+ */
278
+ function _send($data)
279
+ {
280
+ switch ($this->mode) {
281
+ case NET_SCP_SSH2:
282
+ $this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data);
283
+ break;
284
+ case NET_SCP_SSH1:
285
+ $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
286
+ $this->ssh->_send_binary_packet($data);
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Receives a packet from an SSH server
292
+ *
293
+ * @return String
294
+ * @access private
295
+ */
296
+ function _receive()
297
+ {
298
+ switch ($this->mode) {
299
+ case NET_SCP_SSH2:
300
+ return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true);
301
+ case NET_SCP_SSH1:
302
+ if (!$this->ssh->bitmap) {
303
+ return false;
304
+ }
305
+ while (true) {
306
+ $response = $this->ssh->_get_binary_packet();
307
+ switch ($response[NET_SSH1_RESPONSE_TYPE]) {
308
+ case NET_SSH1_SMSG_STDOUT_DATA:
309
+ extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA]));
310
+ return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length);
311
+ case NET_SSH1_SMSG_STDERR_DATA:
312
+ break;
313
+ case NET_SSH1_SMSG_EXITSTATUS:
314
+ $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
315
+ fclose($this->ssh->fsock);
316
+ $this->ssh->bitmap = 0;
317
+ return false;
318
+ default:
319
+ user_error('Unknown packet received', E_USER_NOTICE);
320
+ return false;
321
+ }
322
+ }
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Closes the connection to an SSH server
328
+ *
329
+ * @access private
330
+ */
331
+ function _close()
332
+ {
333
+ switch ($this->mode) {
334
+ case NET_SCP_SSH2:
335
+ $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC);
336
+ break;
337
+ case NET_SCP_SSH1:
338
+ $this->ssh->disconnect();
339
+ }
340
+ }
341
+ }
lib/phpseclib/Net/SFTP.php ADDED
@@ -0,0 +1,2223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of SFTP.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Currently only supports SFTPv2 and v3, which, according to wikipedia.org, "is the most widely used version,
10
+ * implemented by the popular OpenSSH SFTP server". If you want SFTPv4/5/6 support, provide me with access
11
+ * to an SFTPv4/5/6 server.
12
+ *
13
+ * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
14
+ *
15
+ * Here's a short example of how to use this library:
16
+ * <code>
17
+ * <?php
18
+ * include('Net/SFTP.php');
19
+ *
20
+ * $sftp = new Net_SFTP('www.domain.tld');
21
+ * if (!$sftp->login('username', 'password')) {
22
+ * exit('Login Failed');
23
+ * }
24
+ *
25
+ * echo $sftp->pwd() . "\r\n";
26
+ * $sftp->put('filename.ext', 'hello, world!');
27
+ * print_r($sftp->nlist());
28
+ * ?>
29
+ * </code>
30
+ *
31
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
32
+ * of this software and associated documentation files (the "Software"), to deal
33
+ * in the Software without restriction, including without limitation the rights
34
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
+ * copies of the Software, and to permit persons to whom the Software is
36
+ * furnished to do so, subject to the following conditions:
37
+ *
38
+ * The above copyright notice and this permission notice shall be included in
39
+ * all copies or substantial portions of the Software.
40
+ *
41
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
+ * THE SOFTWARE.
48
+ *
49
+ * @category Net
50
+ * @package Net_SFTP
51
+ * @author Jim Wigginton <terrafrost@php.net>
52
+ * @copyright MMIX Jim Wigginton
53
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
54
+ * @link http://phpseclib.sourceforge.net
55
+ */
56
+
57
+ /**
58
+ * Include Net_SSH2
59
+ */
60
+ if (!class_exists('Net_SSH2')) {
61
+ require_once('SSH2.php');
62
+ }
63
+
64
+ /**#@+
65
+ * @access public
66
+ * @see Net_SFTP::getLog()
67
+ */
68
+ /**
69
+ * Returns the message numbers
70
+ */
71
+ define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE);
72
+ /**
73
+ * Returns the message content
74
+ */
75
+ define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX);
76
+ /**
77
+ * Outputs the message content in real-time.
78
+ */
79
+ define('NET_SFTP_LOG_REALTIME', 3);
80
+ /**#@-*/
81
+
82
+ /**
83
+ * SFTP channel constant
84
+ *
85
+ * Net_SSH2::exec() uses 0 and Net_SSH2::read() / Net_SSH2::write() use 1.
86
+ *
87
+ * @see Net_SSH2::_send_channel_packet()
88
+ * @see Net_SSH2::_get_channel_packet()
89
+ * @access private
90
+ */
91
+ define('NET_SFTP_CHANNEL', 2);
92
+
93
+ /**#@+
94
+ * @access public
95
+ * @see Net_SFTP::put()
96
+ */
97
+ /**
98
+ * Reads data from a local file.
99
+ */
100
+ define('NET_SFTP_LOCAL_FILE', 1);
101
+ /**
102
+ * Reads data from a string.
103
+ */
104
+ // this value isn't really used anymore but i'm keeping it reserved for historical reasons
105
+ define('NET_SFTP_STRING', 2);
106
+ /**
107
+ * Resumes an upload
108
+ */
109
+ define('NET_SFTP_RESUME', 4);
110
+ /**#@-*/
111
+
112
+ /**
113
+ * Pure-PHP implementations of SFTP.
114
+ *
115
+ * @author Jim Wigginton <terrafrost@php.net>
116
+ * @version 0.1.0
117
+ * @access public
118
+ * @package Net_SFTP
119
+ */
120
+ class Net_SFTP extends Net_SSH2 {
121
+ /**
122
+ * Packet Types
123
+ *
124
+ * @see Net_SFTP::Net_SFTP()
125
+ * @var Array
126
+ * @access private
127
+ */
128
+ var $packet_types = array();
129
+
130
+ /**
131
+ * Status Codes
132
+ *
133
+ * @see Net_SFTP::Net_SFTP()
134
+ * @var Array
135
+ * @access private
136
+ */
137
+ var $status_codes = array();
138
+
139
+ /**
140
+ * The Request ID
141
+ *
142
+ * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
143
+ * concurrent actions, so it's somewhat academic, here.
144
+ *
145
+ * @var Integer
146
+ * @see Net_SFTP::_send_sftp_packet()
147
+ * @access private
148
+ */
149
+ var $request_id = false;
150
+
151
+ /**
152
+ * The Packet Type
153
+ *
154
+ * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
155
+ * concurrent actions, so it's somewhat academic, here.
156
+ *
157
+ * @var Integer
158
+ * @see Net_SFTP::_get_sftp_packet()
159
+ * @access private
160
+ */
161
+ var $packet_type = -1;
162
+
163
+ /**
164
+ * Packet Buffer
165
+ *
166
+ * @var String
167
+ * @see Net_SFTP::_get_sftp_packet()
168
+ * @access private
169
+ */
170
+ var $packet_buffer = '';
171
+
172
+ /**
173
+ * Extensions supported by the server
174
+ *
175
+ * @var Array
176
+ * @see Net_SFTP::_initChannel()
177
+ * @access private
178
+ */
179
+ var $extensions = array();
180
+
181
+ /**
182
+ * Server SFTP version
183
+ *
184
+ * @var Integer
185
+ * @see Net_SFTP::_initChannel()
186
+ * @access private
187
+ */
188
+ var $version;
189
+
190
+ /**
191
+ * Current working directory
192
+ *
193
+ * @var String
194
+ * @see Net_SFTP::_realpath()
195
+ * @see Net_SFTP::chdir()
196
+ * @access private
197
+ */
198
+ var $pwd = false;
199
+
200
+ /**
201
+ * Packet Type Log
202
+ *
203
+ * @see Net_SFTP::getLog()
204
+ * @var Array
205
+ * @access private
206
+ */
207
+ var $packet_type_log = array();
208
+
209
+ /**
210
+ * Packet Log
211
+ *
212
+ * @see Net_SFTP::getLog()
213
+ * @var Array
214
+ * @access private
215
+ */
216
+ var $packet_log = array();
217
+
218
+ /**
219
+ * Error information
220
+ *
221
+ * @see Net_SFTP::getSFTPErrors()
222
+ * @see Net_SFTP::getLastSFTPError()
223
+ * @var String
224
+ * @access private
225
+ */
226
+ var $sftp_errors = array();
227
+
228
+ /**
229
+ * Directory Cache
230
+ *
231
+ * Rather than always having to open a directory and close it immediately there after to see if a file is a directory or
232
+ * rather than always
233
+ *
234
+ * @see Net_SFTP::_save_dir()
235
+ * @see Net_SFTP::_remove_dir()
236
+ * @see Net_SFTP::_is_dir()
237
+ * @var Array
238
+ * @access private
239
+ */
240
+ var $dirs = array();
241
+
242
+ /**
243
+ * Default Constructor.
244
+ *
245
+ * Connects to an SFTP server
246
+ *
247
+ * @param String $host
248
+ * @param optional Integer $port
249
+ * @param optional Integer $timeout
250
+ * @return Net_SFTP
251
+ * @access public
252
+ */
253
+ function Net_SFTP($host, $port = 22, $timeout = 10)
254
+ {
255
+ parent::Net_SSH2($host, $port, $timeout);
256
+ $this->packet_types = array(
257
+ 1 => 'NET_SFTP_INIT',
258
+ 2 => 'NET_SFTP_VERSION',
259
+ /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
260
+ SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
261
+ pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
262
+ 3 => 'NET_SFTP_OPEN',
263
+ 4 => 'NET_SFTP_CLOSE',
264
+ 5 => 'NET_SFTP_READ',
265
+ 6 => 'NET_SFTP_WRITE',
266
+ 7 => 'NET_SFTP_LSTAT',
267
+ 9 => 'NET_SFTP_SETSTAT',
268
+ 11 => 'NET_SFTP_OPENDIR',
269
+ 12 => 'NET_SFTP_READDIR',
270
+ 13 => 'NET_SFTP_REMOVE',
271
+ 14 => 'NET_SFTP_MKDIR',
272
+ 15 => 'NET_SFTP_RMDIR',
273
+ 16 => 'NET_SFTP_REALPATH',
274
+ 17 => 'NET_SFTP_STAT',
275
+ /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
276
+ SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
277
+ pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
278
+ 18 => 'NET_SFTP_RENAME',
279
+
280
+ 101=> 'NET_SFTP_STATUS',
281
+ 102=> 'NET_SFTP_HANDLE',
282
+ /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
283
+ SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
284
+ pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
285
+ 103=> 'NET_SFTP_DATA',
286
+ 104=> 'NET_SFTP_NAME',
287
+ 105=> 'NET_SFTP_ATTRS',
288
+
289
+ 200=> 'NET_SFTP_EXTENDED'
290
+ );
291
+ $this->status_codes = array(
292
+ 0 => 'NET_SFTP_STATUS_OK',
293
+ 1 => 'NET_SFTP_STATUS_EOF',
294
+ 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
295
+ 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
296
+ 4 => 'NET_SFTP_STATUS_FAILURE',
297
+ 5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
298
+ 6 => 'NET_SFTP_STATUS_NO_CONNECTION',
299
+ 7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
300
+ 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
301
+ 9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
302
+ 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
303
+ 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
304
+ 12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
305
+ 13 => 'NET_SFTP_STATUS_NO_MEDIA',
306
+ 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
307
+ 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
308
+ 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
309
+ 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
310
+ 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
311
+ 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
312
+ 20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
313
+ 21 => 'NET_SFTP_STATUS_LINK_LOOP',
314
+ 22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
315
+ 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
316
+ 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
317
+ 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
318
+ 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
319
+ 27 => 'NET_SFTP_STATUS_DELETE_PENDING',
320
+ 28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
321
+ 29 => 'NET_SFTP_STATUS_OWNER_INVALID',
322
+ 30 => 'NET_SFTP_STATUS_GROUP_INVALID',
323
+ 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
324
+ );
325
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
326
+ // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why
327
+ $this->attributes = array(
328
+ 0x00000001 => 'NET_SFTP_ATTR_SIZE',
329
+ 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
330
+ 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
331
+ 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
332
+ // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
333
+ // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
334
+ // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
335
+ // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
336
+ -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
337
+ );
338
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
339
+ // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
340
+ // the array for that $this->open5_flags and similarily alter the constant names.
341
+ $this->open_flags = array(
342
+ 0x00000001 => 'NET_SFTP_OPEN_READ',
343
+ 0x00000002 => 'NET_SFTP_OPEN_WRITE',
344
+ 0x00000004 => 'NET_SFTP_OPEN_APPEND',
345
+ 0x00000008 => 'NET_SFTP_OPEN_CREATE',
346
+ 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
347
+ 0x00000020 => 'NET_SFTP_OPEN_EXCL'
348
+ );
349
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
350
+ // see Net_SFTP::_parseLongname() for an explanation
351
+ $this->file_types = array(
352
+ 1 => 'NET_SFTP_TYPE_REGULAR',
353
+ 2 => 'NET_SFTP_TYPE_DIRECTORY',
354
+ 3 => 'NET_SFTP_TYPE_SYMLINK',
355
+ 4 => 'NET_SFTP_TYPE_SPECIAL',
356
+ 5 => 'NET_SFTP_TYPE_UNKNOWN',
357
+ // the followin types were first defined for use in SFTPv5+
358
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
359
+ 6 => 'NET_SFTP_TYPE_SOCKET',
360
+ 7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
361
+ 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
362
+ 9 => 'NET_SFTP_TYPE_FIFO'
363
+ );
364
+ $this->_define_array(
365
+ $this->packet_types,
366
+ $this->status_codes,
367
+ $this->attributes,
368
+ $this->open_flags,
369
+ $this->file_types
370
+ );
371
+ }
372
+
373
+ /**
374
+ * Login
375
+ *
376
+ * @param String $username
377
+ * @param optional String $password
378
+ * @return Boolean
379
+ * @access public
380
+ */
381
+ function login($username)
382
+ {
383
+ $args = func_get_args();
384
+ if (!call_user_func_array(array('Net_SSH2', 'login'), $args)) {
385
+ return false;
386
+ }
387
+
388
+ $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size;
389
+
390
+ $packet = pack('CNa*N3',
391
+ NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000);
392
+
393
+ if (!$this->_send_binary_packet($packet)) {
394
+ return false;
395
+ }
396
+
397
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
398
+
399
+ $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
400
+ if ($response === false) {
401
+ return false;
402
+ }
403
+
404
+ $packet = pack('CNNa*CNa*',
405
+ NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp');
406
+ if (!$this->_send_binary_packet($packet)) {
407
+ return false;
408
+ }
409
+
410
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
411
+
412
+ $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
413
+ if ($response === false) {
414
+ // from PuTTY's psftp.exe
415
+ $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
416
+ "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
417
+ "exec sftp-server";
418
+ // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
419
+ // is redundant
420
+ $packet = pack('CNNa*CNa*',
421
+ NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('exec'), 'exec', 1, strlen($command), $command);
422
+ if (!$this->_send_binary_packet($packet)) {
423
+ return false;
424
+ }
425
+
426
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
427
+
428
+ $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
429
+ if ($response === false) {
430
+ return false;
431
+ }
432
+ }
433
+
434
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
435
+
436
+ if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
437
+ return false;
438
+ }
439
+
440
+ $response = $this->_get_sftp_packet();
441
+ if ($this->packet_type != NET_SFTP_VERSION) {
442
+ user_error('Expected SSH_FXP_VERSION');
443
+ return false;
444
+ }
445
+
446
+ extract(unpack('Nversion', $this->_string_shift($response, 4)));
447
+ $this->version = $version;
448
+ while (!empty($response)) {
449
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
450
+ $key = $this->_string_shift($response, $length);
451
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
452
+ $value = $this->_string_shift($response, $length);
453
+ $this->extensions[$key] = $value;
454
+ }
455
+
456
+ /*
457
+ SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
458
+ however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
459
+ not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
460
+ one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
461
+ 'newline@vandyke.com' would.
462
+ */
463
+ /*
464
+ if (isset($this->extensions['newline@vandyke.com'])) {
465
+ $this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
466
+ unset($this->extensions['newline@vandyke.com']);
467
+ }
468
+ */
469
+
470
+ $this->request_id = 1;
471
+
472
+ /*
473
+ A Note on SFTPv4/5/6 support:
474
+ <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:
475
+
476
+ "If the client wishes to interoperate with servers that support noncontiguous version
477
+ numbers it SHOULD send '3'"
478
+
479
+ Given that the server only sends its version number after the client has already done so, the above
480
+ seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
481
+ most popular.
482
+
483
+ <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;
484
+
485
+ "If the server did not send the "versions" extension, or the version-from-list was not included, the
486
+ server MAY send a status response describing the failure, but MUST then close the channel without
487
+ processing any further requests."
488
+
489
+ So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
490
+ a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
491
+ v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
492
+ in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
493
+ channel and reopen it with a new and updated SSH_FXP_INIT packet.
494
+ */
495
+ switch ($this->version) {
496
+ case 2:
497
+ case 3:
498
+ break;
499
+ default:
500
+ return false;
501
+ }
502
+
503
+ $this->pwd = $this->_realpath('.');
504
+
505
+ $this->_save_dir($this->pwd);
506
+
507
+ return true;
508
+ }
509
+
510
+ /**
511
+ * Returns the current directory name
512
+ *
513
+ * @return Mixed
514
+ * @access public
515
+ */
516
+ function pwd()
517
+ {
518
+ return $this->pwd;
519
+ }
520
+
521
+ /**
522
+ * Logs errors
523
+ *
524
+ * @param String $response
525
+ * @param optional Integer $status
526
+ * @access public
527
+ */
528
+ function _logError($response, $status = -1)
529
+ {
530
+ if ($status == -1) {
531
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
532
+ }
533
+
534
+ $error = $this->status_codes[$status];
535
+
536
+ if ($this->version > 2) {
537
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
538
+ $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
539
+ } else {
540
+ $this->sftp_errors[] = $error;
541
+ }
542
+ }
543
+
544
+ /**
545
+ * Canonicalize the Server-Side Path Name
546
+ *
547
+ * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
548
+ * the absolute (canonicalized) path.
549
+ *
550
+ * @see Net_SFTP::chdir()
551
+ * @param String $path
552
+ * @return Mixed
553
+ * @access private
554
+ */
555
+ function _realpath($path)
556
+ {
557
+ if ($this->pwd === false) {
558
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
559
+ if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
560
+ return false;
561
+ }
562
+
563
+ $response = $this->_get_sftp_packet();
564
+ switch ($this->packet_type) {
565
+ case NET_SFTP_NAME:
566
+ // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
567
+ // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
568
+ // at is the first part and that part is defined the same in SFTP versions 3 through 6.
569
+ $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
570
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
571
+ return $this->_string_shift($response, $length);
572
+ case NET_SFTP_STATUS:
573
+ $this->_logError($response);
574
+ return false;
575
+ default:
576
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
577
+ return false;
578
+ }
579
+ }
580
+
581
+ if ($path[0] != '/') {
582
+ $path = $this->pwd . '/' . $path;
583
+ }
584
+
585
+ $path = explode('/', $path);
586
+ $new = array();
587
+ foreach ($path as $dir) {
588
+ if (!strlen($dir)) {
589
+ continue;
590
+ }
591
+ switch ($dir) {
592
+ case '..':
593
+ array_pop($new);
594
+ case '.':
595
+ break;
596
+ default:
597
+ $new[] = $dir;
598
+ }
599
+ }
600
+
601
+ return '/' . implode('/', $new);
602
+ }
603
+
604
+ /**
605
+ * Changes the current directory
606
+ *
607
+ * @param String $dir
608
+ * @return Boolean
609
+ * @access public
610
+ */
611
+ function chdir($dir)
612
+ {
613
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
614
+ return false;
615
+ }
616
+
617
+ if ($dir[strlen($dir) - 1] != '/') {
618
+ $dir.= '/';
619
+ }
620
+
621
+ $dir = $this->_realpath($dir);
622
+
623
+ // confirm that $dir is, in fact, a valid directory
624
+ if ($this->_is_dir($dir)) {
625
+ $this->pwd = $dir;
626
+ return true;
627
+ }
628
+
629
+ // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
630
+ // the currently logged in user has the appropriate permissions or not. maybe you could see if
631
+ // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
632
+ // way to get those with SFTP
633
+
634
+ if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
635
+ return false;
636
+ }
637
+
638
+ // see Net_SFTP::nlist() for a more thorough explanation of the following
639
+ $response = $this->_get_sftp_packet();
640
+ switch ($this->packet_type) {
641
+ case NET_SFTP_HANDLE:
642
+ $handle = substr($response, 4);
643
+ break;
644
+ case NET_SFTP_STATUS:
645
+ $this->_logError($response);
646
+ return false;
647
+ default:
648
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
649
+ return false;
650
+ }
651
+
652
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
653
+ return false;
654
+ }
655
+
656
+ $response = $this->_get_sftp_packet();
657
+ if ($this->packet_type != NET_SFTP_STATUS) {
658
+ user_error('Expected SSH_FXP_STATUS');
659
+ return false;
660
+ }
661
+
662
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
663
+ if ($status != NET_SFTP_STATUS_OK) {
664
+ $this->_logError($response, $status);
665
+ return false;
666
+ }
667
+
668
+ $this->_save_dir($dir);
669
+
670
+ $this->pwd = $dir;
671
+ return true;
672
+ }
673
+
674
+ /**
675
+ * Returns a list of files in the given directory
676
+ *
677
+ * @param optional String $dir
678
+ * @return Mixed
679
+ * @access public
680
+ */
681
+ function nlist($dir = '.')
682
+ {
683
+ return $this->_list($dir, false);
684
+ }
685
+
686
+ /**
687
+ * Returns a detailed list of files in the given directory
688
+ *
689
+ * @param optional String $dir
690
+ * @return Mixed
691
+ * @access public
692
+ */
693
+ function rawlist($dir = '.')
694
+ {
695
+ return $this->_list($dir, true);
696
+ }
697
+
698
+ /**
699
+ * Reads a list, be it detailed or not, of files in the given directory
700
+ *
701
+ * $realpath exists because, in the case of the recursive deletes and recursive chmod's $realpath has already
702
+ * been calculated.
703
+ *
704
+ * @param String $dir
705
+ * @param optional Boolean $raw
706
+ * @param optional Boolean $realpath
707
+ * @return Mixed
708
+ * @access private
709
+ */
710
+ function _list($dir, $raw = true, $realpath = true)
711
+ {
712
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
713
+ return false;
714
+ }
715
+
716
+ $dir = $this->_realpath($dir . '/');
717
+ if ($dir === false) {
718
+ return false;
719
+ }
720
+
721
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
722
+ if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
723
+ return false;
724
+ }
725
+
726
+ $response = $this->_get_sftp_packet();
727
+ switch ($this->packet_type) {
728
+ case NET_SFTP_HANDLE:
729
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
730
+ // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
731
+ // represent the length of the string and leave it at that
732
+ $handle = substr($response, 4);
733
+ break;
734
+ case NET_SFTP_STATUS:
735
+ // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
736
+ $this->_logError($response);
737
+ return false;
738
+ default:
739
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
740
+ return false;
741
+ }
742
+
743
+ $this->_save_dir($dir);
744
+
745
+ $contents = array();
746
+ while (true) {
747
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
748
+ // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
749
+ // SSH_MSG_CHANNEL_DATA messages is not known to me.
750
+ if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
751
+ return false;
752
+ }
753
+
754
+ $response = $this->_get_sftp_packet();
755
+ switch ($this->packet_type) {
756
+ case NET_SFTP_NAME:
757
+ extract(unpack('Ncount', $this->_string_shift($response, 4)));
758
+ for ($i = 0; $i < $count; $i++) {
759
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
760
+ $shortname = $this->_string_shift($response, $length);
761
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
762
+ $longname = $this->_string_shift($response, $length);
763
+ $attributes = $this->_parseAttributes($response);
764
+ if (!isset($attributes['type'])) {
765
+ $fileType = $this->_parseLongname($longname);
766
+ if ($fileType) {
767
+ $attributes['type'] = $fileType;
768
+ }
769
+ }
770
+ if (!$raw) {
771
+ $contents[] = $shortname;
772
+ } else {
773
+ $contents[$shortname] = $attributes;
774
+ }
775
+
776
+ if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
777
+ $this->_save_dir($dir . '/' . $shortname);
778
+ }
779
+ // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
780
+ // final SSH_FXP_STATUS packet should tell us that, already.
781
+ }
782
+ break;
783
+ case NET_SFTP_STATUS:
784
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
785
+ if ($status != NET_SFTP_STATUS_EOF) {
786
+ $this->_logError($response, $status);
787
+ return false;
788
+ }
789
+ break 2;
790
+ default:
791
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
792
+ return false;
793
+ }
794
+ }
795
+
796
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
797
+ return false;
798
+ }
799
+
800
+ // "The client MUST release all resources associated with the handle regardless of the status."
801
+ // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
802
+ $response = $this->_get_sftp_packet();
803
+ if ($this->packet_type != NET_SFTP_STATUS) {
804
+ user_error('Expected SSH_FXP_STATUS');
805
+ return false;
806
+ }
807
+
808
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
809
+ if ($status != NET_SFTP_STATUS_OK) {
810
+ $this->_logError($response, $status);
811
+ return false;
812
+ }
813
+
814
+ return $contents;
815
+ }
816
+
817
+ /**
818
+ * Returns the file size, in bytes, or false, on failure
819
+ *
820
+ * Files larger than 4GB will show up as being exactly 4GB.
821
+ *
822
+ * @param String $filename
823
+ * @return Mixed
824
+ * @access public
825
+ */
826
+ function size($filename)
827
+ {
828
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
829
+ return false;
830
+ }
831
+
832
+ $filename = $this->_realpath($filename);
833
+ if ($filename === false) {
834
+ return false;
835
+ }
836
+
837
+ return $this->_size($filename);
838
+ }
839
+
840
+ /**
841
+ * Save directories to cache
842
+ *
843
+ * @param String $dir
844
+ * @access private
845
+ */
846
+ function _save_dir($dir)
847
+ {
848
+ // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($dir, '/'))
849
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
850
+
851
+ $temp = &$this->dirs;
852
+ foreach ($dirs as $dir) {
853
+ if (!isset($temp[$dir])) {
854
+ $temp[$dir] = array();
855
+ }
856
+ $temp = &$temp[$dir];
857
+ }
858
+ }
859
+
860
+ /**
861
+ * Remove directories from cache
862
+ *
863
+ * @param String $dir
864
+ * @access private
865
+ */
866
+ function _remove_dir($dir)
867
+ {
868
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
869
+
870
+ $temp = &$this->dirs;
871
+ foreach ($dirs as $dir) {
872
+ if ($dir == end($dirs)) {
873
+ unset($temp[$dir]);
874
+ return true;
875
+ }
876
+ if (!isset($temp[$dir])) {
877
+ return false;
878
+ }
879
+ $temp = &$temp[$dir];
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Checks cache for directory
885
+ *
886
+ * Mainly used by chdir, which is, in turn, also used for determining whether or not an individual
887
+ * file is a directory or not by stat() and lstat()
888
+ *
889
+ * @param String $dir
890
+ * @access private
891
+ */
892
+ function _is_dir($dir)
893
+ {
894
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
895
+
896
+ $temp = &$this->dirs;
897
+ foreach ($dirs as $dir) {
898
+ if (!isset($temp[$dir])) {
899
+ return false;
900
+ }
901
+ $temp = &$temp[$dir];
902
+ }
903
+ return true;
904
+ }
905
+
906
+ /**
907
+ * Returns general information about a file.
908
+ *
909
+ * Returns an array on success and false otherwise.
910
+ *
911
+ * @param String $filename
912
+ * @return Mixed
913
+ * @access public
914
+ */
915
+ function stat($filename)
916
+ {
917
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
918
+ return false;
919
+ }
920
+
921
+ $filename = $this->_realpath($filename);
922
+ if ($filename === false) {
923
+ return false;
924
+ }
925
+
926
+ $stat = $this->_stat($filename, NET_SFTP_STAT);
927
+ if ($stat === false) {
928
+ return false;
929
+ }
930
+ if (isset($stat['type'])) {
931
+ return $stat;
932
+ }
933
+
934
+ $pwd = $this->pwd;
935
+ $stat['type'] = $this->chdir($filename) ?
936
+ NET_SFTP_TYPE_DIRECTORY :
937
+ NET_SFTP_TYPE_REGULAR;
938
+ $this->pwd = $pwd;
939
+
940
+ return $stat;
941
+ }
942
+
943
+ /**
944
+ * Returns general information about a file or symbolic link.
945
+ *
946
+ * Returns an array on success and false otherwise.
947
+ *
948
+ * @param String $filename
949
+ * @return Mixed
950
+ * @access public
951
+ */
952
+ function lstat($filename)
953
+ {
954
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
955
+ return false;
956
+ }
957
+
958
+ $filename = $this->_realpath($filename);
959
+ if ($filename === false) {
960
+ return false;
961
+ }
962
+
963
+ $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
964
+ if ($lstat === false) {
965
+ return false;
966
+ }
967
+ if (isset($lstat['type'])) {
968
+ return $lstat;
969
+ }
970
+
971
+ $stat = $this->_stat($filename, NET_SFTP_STAT);
972
+
973
+ if ($lstat != $stat) {
974
+ return array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
975
+ }
976
+
977
+ $pwd = $this->pwd;
978
+ $lstat['type'] = $this->chdir($filename) ?
979
+ NET_SFTP_TYPE_DIRECTORY :
980
+ NET_SFTP_TYPE_REGULAR;
981
+ $this->pwd = $pwd;
982
+
983
+ return $lstat;
984
+ }
985
+
986
+ /**
987
+ * Returns general information about a file or symbolic link
988
+ *
989
+ * Determines information without calling Net_SFTP::_realpath().
990
+ * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
991
+ *
992
+ * @param String $filename
993
+ * @param Integer $type
994
+ * @return Mixed
995
+ * @access private
996
+ */
997
+ function _stat($filename, $type)
998
+ {
999
+ // SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1000
+ $packet = pack('Na*', strlen($filename), $filename);
1001
+ if (!$this->_send_sftp_packet($type, $packet)) {
1002
+ return false;
1003
+ }
1004
+
1005
+ $response = $this->_get_sftp_packet();
1006
+ switch ($this->packet_type) {
1007
+ case NET_SFTP_ATTRS:
1008
+ return $this->_parseAttributes($response);
1009
+ case NET_SFTP_STATUS:
1010
+ $this->_logError($response);
1011
+ return false;
1012
+ }
1013
+
1014
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1015
+ return false;
1016
+ }
1017
+
1018
+ /**
1019
+ * Returns the file size, in bytes, or false, on failure
1020
+ *
1021
+ * Determines the size without calling Net_SFTP::_realpath()
1022
+ *
1023
+ * @param String $filename
1024
+ * @return Mixed
1025
+ * @access private
1026
+ */
1027
+ function _size($filename)
1028
+ {
1029
+ $result = $this->_stat($filename, NET_SFTP_STAT);
1030
+ if ($result === false) {
1031
+ return false;
1032
+ }
1033
+ return isset($result['size']) ? $result['size'] : -1;
1034
+ }
1035
+
1036
+ /**
1037
+ * Truncates a file to a given length
1038
+ *
1039
+ * @param String $filename
1040
+ * @param Integer $new_size
1041
+ * @return Boolean
1042
+ * @access public
1043
+ */
1044
+ function truncate($filename, $new_size)
1045
+ {
1046
+ $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 0x100000000, $new_size);
1047
+
1048
+ return $this->_setstat($filename, $attr, false);
1049
+ }
1050
+
1051
+ /**
1052
+ * Sets access and modification time of file.
1053
+ *
1054
+ * If the file does not exist, it will be created.
1055
+ *
1056
+ * @param String $filename
1057
+ * @param optional Integer $time
1058
+ * @param optional Integer $atime
1059
+ * @return Boolean
1060
+ * @access public
1061
+ */
1062
+ function touch($filename, $time = NULL, $atime = NULL)
1063
+ {
1064
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1065
+ return false;
1066
+ }
1067
+
1068
+ $filename = $this->_realpath($filename);
1069
+ if ($filename === false) {
1070
+ return false;
1071
+ }
1072
+
1073
+ if (!isset($time)) {
1074
+ $time = time();
1075
+ }
1076
+ if (!isset($atime)) {
1077
+ $atime = $time;
1078
+ }
1079
+
1080
+ $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
1081
+ $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
1082
+ $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
1083
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1084
+ return false;
1085
+ }
1086
+
1087
+ $response = $this->_get_sftp_packet();
1088
+ switch ($this->packet_type) {
1089
+ case NET_SFTP_HANDLE:
1090
+ $handle = substr($response, 4);
1091
+
1092
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
1093
+ return false;
1094
+ }
1095
+
1096
+ $response = $this->_get_sftp_packet();
1097
+ if ($this->packet_type != NET_SFTP_STATUS) {
1098
+ user_error('Expected SSH_FXP_STATUS');
1099
+ return false;
1100
+ }
1101
+
1102
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1103
+ if ($status != NET_SFTP_STATUS_OK) {
1104
+ $this->_logError($response, $status);
1105
+ return false;
1106
+ }
1107
+
1108
+ return true;
1109
+ case NET_SFTP_STATUS:
1110
+ $this->_logError($response);
1111
+ break;
1112
+ default:
1113
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1114
+ return false;
1115
+ }
1116
+
1117
+ return $this->_setstat($filename, $attr, false);
1118
+ }
1119
+
1120
+ /**
1121
+ * Changes file or directory owner
1122
+ *
1123
+ * Returns TRUE on success or FALSE on error.
1124
+ *
1125
+ * @param String $filename
1126
+ * @param Integer $uid
1127
+ * @param optional Boolean $recursive
1128
+ * @return Boolean
1129
+ * @access public
1130
+ */
1131
+ function chown($filename, $uid, $recursive = false)
1132
+ {
1133
+ // quoting from <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
1134
+ // "if the owner or group is specified as -1, then that ID is not changed"
1135
+ $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
1136
+
1137
+ return $this->_setstat($filename, $attr, $recursive);
1138
+ }
1139
+
1140
+ /**
1141
+ * Changes file or directory group
1142
+ *
1143
+ * Returns TRUE on success or FALSE on error.
1144
+ *
1145
+ * @param String $filename
1146
+ * @param Integer $gid
1147
+ * @param optional Boolean $recursive
1148
+ * @return Boolean
1149
+ * @access public
1150
+ */
1151
+ function chgrp($filename, $gid, $recursive = false)
1152
+ {
1153
+ $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
1154
+
1155
+ return $this->_setstat($filename, $attr, $recursive);
1156
+ }
1157
+
1158
+ /**
1159
+ * Set permissions on a file.
1160
+ *
1161
+ * Returns the new file permissions on success or FALSE on error.
1162
+ * If $recursive is true than this just returns TRUE or FALSE.
1163
+ *
1164
+ * @param Integer $mode
1165
+ * @param String $filename
1166
+ * @param optional Boolean $recursive
1167
+ * @return Mixed
1168
+ * @access public
1169
+ */
1170
+ function chmod($mode, $filename, $recursive = false)
1171
+ {
1172
+ if (is_string($mode) && is_int($filename)) {
1173
+ $temp = $mode;
1174
+ $mode = $filename;
1175
+ $filename = $temp;
1176
+ }
1177
+
1178
+ $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1179
+ if (!$this->_setstat($filename, $attr, $recursive)) {
1180
+ return false;
1181
+ }
1182
+ if ($recursive) {
1183
+ return true;
1184
+ }
1185
+
1186
+ // rather than return what the permissions *should* be, we'll return what they actually are. this will also
1187
+ // tell us if the file actually exists.
1188
+ // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1189
+ $packet = pack('Na*', strlen($filename), $filename);
1190
+ if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
1191
+ return false;
1192
+ }
1193
+
1194
+ $response = $this->_get_sftp_packet();
1195
+ switch ($this->packet_type) {
1196
+ case NET_SFTP_ATTRS:
1197
+ $attrs = $this->_parseAttributes($response);
1198
+ return $attrs['permissions'];
1199
+ case NET_SFTP_STATUS:
1200
+ $this->_logError($response);
1201
+ return false;
1202
+ }
1203
+
1204
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1205
+ return false;
1206
+ }
1207
+
1208
+ /**
1209
+ * Sets information about a file
1210
+ *
1211
+ * @param String $filename
1212
+ * @param String $attr
1213
+ * @param Boolean $recursive
1214
+ * @return Boolean
1215
+ * @access private
1216
+ */
1217
+ function _setstat($filename, $attr, $recursive)
1218
+ {
1219
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1220
+ return false;
1221
+ }
1222
+
1223
+ $filename = $this->_realpath($filename);
1224
+ if ($filename === false) {
1225
+ return false;
1226
+ }
1227
+
1228
+ if ($recursive) {
1229
+ $i = 0;
1230
+ $result = $this->_setstat_recursive($filename, $attr, $i);
1231
+ $this->_read_put_responses($i);
1232
+ return $result;
1233
+ }
1234
+
1235
+ // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
1236
+ // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
1237
+ if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
1238
+ return false;
1239
+ }
1240
+
1241
+ /*
1242
+ "Because some systems must use separate system calls to set various attributes, it is possible that a failure
1243
+ response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
1244
+ servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
1245
+
1246
+ -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
1247
+ */
1248
+ $response = $this->_get_sftp_packet();
1249
+ if ($this->packet_type != NET_SFTP_STATUS) {
1250
+ user_error('Expected SSH_FXP_STATUS');
1251
+ return false;
1252
+ }
1253
+
1254
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1255
+ if ($status != NET_SFTP_STATUS_OK) {
1256
+ $this->_logError($response, $status);
1257
+ return false;
1258
+ }
1259
+
1260
+ return true;
1261
+ }
1262
+
1263
+ /**
1264
+ * Recursively sets information on directories on the SFTP server
1265
+ *
1266
+ * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
1267
+ *
1268
+ * @param String $path
1269
+ * @param String $attr
1270
+ * @param Integer $i
1271
+ * @return Boolean
1272
+ * @access private
1273
+ */
1274
+ function _setstat_recursive($path, $attr, &$i)
1275
+ {
1276
+ if (!$this->_read_put_responses($i)) {
1277
+ return false;
1278
+ }
1279
+ $i = 0;
1280
+ $entries = $this->_list($path, true, false);
1281
+
1282
+ if ($entries === false) {
1283
+ return $this->_setstat($path, $attr, false);
1284
+ }
1285
+
1286
+ // normally $entries would have at least . and .. but it might not if the directories
1287
+ // permissions didn't allow reading
1288
+ if (empty($entries)) {
1289
+ return false;
1290
+ }
1291
+
1292
+ foreach ($entries as $filename=>$props) {
1293
+ if ($filename == '.' || $filename == '..') {
1294
+ continue;
1295
+ }
1296
+
1297
+ if (!isset($props['type'])) {
1298
+ return false;
1299
+ }
1300
+
1301
+ $temp = $path . '/' . $filename;
1302
+ if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
1303
+ if (!$this->_setstat_recursive($temp, $attr, $i)) {
1304
+ return false;
1305
+ }
1306
+ } else {
1307
+ if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
1308
+ return false;
1309
+ }
1310
+
1311
+ $i++;
1312
+
1313
+ if ($i >= 50) {
1314
+ if (!$this->_read_put_responses($i)) {
1315
+ return false;
1316
+ }
1317
+ $i = 0;
1318
+ }
1319
+ }
1320
+ }
1321
+
1322
+ if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
1323
+ return false;
1324
+ }
1325
+
1326
+ $i++;
1327
+
1328
+ if ($i >= 50) {
1329
+ if (!$this->_read_put_responses($i)) {
1330
+ return false;
1331
+ }
1332
+ $i = 0;
1333
+ }
1334
+
1335
+ return true;
1336
+ }
1337
+
1338
+ /**
1339
+ * Creates a directory.
1340
+ *
1341
+ * @param String $dir
1342
+ * @return Boolean
1343
+ * @access public
1344
+ */
1345
+ function mkdir($dir, $mode = -1, $recursive = false)
1346
+ {
1347
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1348
+ return false;
1349
+ }
1350
+
1351
+ $dir = $this->_realpath($dir);
1352
+ // by not providing any permissions, hopefully the server will use the logged in users umask - their
1353
+ // default permissions.
1354
+ $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1355
+
1356
+ if ($recursive) {
1357
+ $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
1358
+ if (empty($dirs[0])) {
1359
+ array_shift($dirs);
1360
+ $dirs[0] = '/' . $dirs[0];
1361
+ }
1362
+ for ($i = 0; $i < count($dirs); $i++) {
1363
+ $temp = array_slice($dirs, 0, $i + 1);
1364
+ $temp = implode('/', $temp);
1365
+ $result = $this->_mkdir_helper($temp, $attr);
1366
+ }
1367
+ return $result;
1368
+ }
1369
+
1370
+ return $this->_mkdir_helper($dir, $attr);
1371
+ }
1372
+
1373
+ /**
1374
+ * Helper function for directory creation
1375
+ *
1376
+ * @param String $dir
1377
+ * @return Boolean
1378
+ * @access private
1379
+ */
1380
+ function _mkdir_helper($dir, $attr)
1381
+ {
1382
+ if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) {
1383
+ return false;
1384
+ }
1385
+
1386
+ $response = $this->_get_sftp_packet();
1387
+ if ($this->packet_type != NET_SFTP_STATUS) {
1388
+ user_error('Expected SSH_FXP_STATUS');
1389
+ return false;
1390
+ }
1391
+
1392
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1393
+ if ($status != NET_SFTP_STATUS_OK) {
1394
+ $this->_logError($response, $status);
1395
+ return false;
1396
+ }
1397
+
1398
+ $this->_save_dir($dir);
1399
+
1400
+ return true;
1401
+ }
1402
+
1403
+ /**
1404
+ * Removes a directory.
1405
+ *
1406
+ * @param String $dir
1407
+ * @return Boolean
1408
+ * @access public
1409
+ */
1410
+ function rmdir($dir)
1411
+ {
1412
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1413
+ return false;
1414
+ }
1415
+
1416
+ $dir = $this->_realpath($dir);
1417
+ if ($dir === false) {
1418
+ return false;
1419
+ }
1420
+
1421
+ if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
1422
+ return false;
1423
+ }
1424
+
1425
+ $response = $this->_get_sftp_packet();
1426
+ if ($this->packet_type != NET_SFTP_STATUS) {
1427
+ user_error('Expected SSH_FXP_STATUS');
1428
+ return false;
1429
+ }
1430
+
1431
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1432
+ if ($status != NET_SFTP_STATUS_OK) {
1433
+ // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
1434
+ $this->_logError($response, $status);
1435
+ return false;
1436
+ }
1437
+
1438
+ $this->_remove_dir($dir);
1439
+
1440
+ return true;
1441
+ }
1442
+
1443
+ /**
1444
+ * Uploads a file to the SFTP server.
1445
+ *
1446
+ * By default, Net_SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
1447
+ * So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes
1448
+ * long, containing 'filename.ext' as its contents.
1449
+ *
1450
+ * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
1451
+ * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
1452
+ * large $remote_file will be, as well.
1453
+ *
1454
+ * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
1455
+ * care of that, yourself.
1456
+ *
1457
+ * As for $start... if it's negative (which it is by default) a new file will be created or an existing
1458
+ * file truncated depending on $mode | NET_SFTP_RESUME. If it's zero or positive it'll be updated at that
1459
+ * spot.
1460
+ *
1461
+ * @param String $remote_file
1462
+ * @param String $data
1463
+ * @param optional Integer $mode
1464
+ * @param optional Integer $start
1465
+ * @return Boolean
1466
+ * @access public
1467
+ * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode().
1468
+ */
1469
+ function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1)
1470
+ {
1471
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1472
+ return false;
1473
+ }
1474
+
1475
+ $remote_file = $this->_realpath($remote_file);
1476
+ if ($remote_file === false) {
1477
+ return false;
1478
+ }
1479
+
1480
+ $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
1481
+ // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
1482
+ // in practice, it doesn't seem to do that.
1483
+ //$flags|= ($mode & NET_SFTP_RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
1484
+
1485
+ // if NET_SFTP_OPEN_APPEND worked as it should the following (up until the -----------) wouldn't be necessary
1486
+ $offset = 0;
1487
+ if (($mode & NET_SFTP_RESUME) || $start >= 0) {
1488
+ if ($start >= 0) {
1489
+ $offset = $start;
1490
+ } else {
1491
+ $size = $this->_size($remote_file);
1492
+ $offset = $size !== false ? $size : 0;
1493
+ }
1494
+ } else {
1495
+ $flags|= NET_SFTP_OPEN_TRUNCATE;
1496
+ }
1497
+ // --------------
1498
+
1499
+ $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0);
1500
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1501
+ return false;
1502
+ }
1503
+
1504
+ $response = $this->_get_sftp_packet();
1505
+ switch ($this->packet_type) {
1506
+ case NET_SFTP_HANDLE:
1507
+ $handle = substr($response, 4);
1508
+ break;
1509
+ case NET_SFTP_STATUS:
1510
+ $this->_logError($response);
1511
+ return false;
1512
+ default:
1513
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1514
+ return false;
1515
+ }
1516
+
1517
+ $initialize = true;
1518
+
1519
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
1520
+ if ($mode & NET_SFTP_LOCAL_FILE) {
1521
+ if (!is_file($data)) {
1522
+ user_error("$data is not a valid file");
1523
+ return false;
1524
+ }
1525
+ $fp = @fopen($data, 'rb');
1526
+ if (!$fp) {
1527
+ return false;
1528
+ }
1529
+ $size = filesize($data);
1530
+ } else {
1531
+ $size = strlen($data);
1532
+ }
1533
+
1534
+ $sent = 0;
1535
+ $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
1536
+
1537
+ $sftp_packet_size = 4096; // PuTTY uses 4096
1538
+ $i = 0;
1539
+ while ($sent < $size) {
1540
+ $temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : $this->_string_shift($data, $sftp_packet_size);
1541
+ $subtemp = $offset + $sent;
1542
+ $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 0x100000000, $subtemp, strlen($temp), $temp);
1543
+ if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
1544
+ fclose($fp);
1545
+ return false;
1546
+ }
1547
+ $sent+= strlen($temp);
1548
+
1549
+ $i++;
1550
+
1551
+ if ($i == 50) {
1552
+ if (!$this->_read_put_responses($i)) {
1553
+ $i = 0;
1554
+ break;
1555
+ }
1556
+ $i = 0;
1557
+ }
1558
+ }
1559
+
1560
+ if (!$this->_read_put_responses($i)) {
1561
+ return false;
1562
+ }
1563
+
1564
+ if ($mode & NET_SFTP_LOCAL_FILE) {
1565
+ fclose($fp);
1566
+ }
1567
+
1568
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
1569
+ return false;
1570
+ }
1571
+
1572
+ $response = $this->_get_sftp_packet();
1573
+ if ($this->packet_type != NET_SFTP_STATUS) {
1574
+ user_error('Expected SSH_FXP_STATUS');
1575
+ return false;
1576
+ }
1577
+
1578
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1579
+ if ($status != NET_SFTP_STATUS_OK) {
1580
+ $this->_logError($response, $status);
1581
+ return false;
1582
+ }
1583
+
1584
+ return true;
1585
+ }
1586
+
1587
+ /**
1588
+ * Reads multiple successive SSH_FXP_WRITE responses
1589
+ *
1590
+ * Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i
1591
+ * SSH_FXP_WRITEs, in succession, and then reading $i responses.
1592
+ *
1593
+ * @param Integer $i
1594
+ * @return Boolean
1595
+ * @access private
1596
+ */
1597
+ function _read_put_responses($i)
1598
+ {
1599
+ while ($i--) {
1600
+ $response = $this->_get_sftp_packet();
1601
+ if ($this->packet_type != NET_SFTP_STATUS) {
1602
+ user_error('Expected SSH_FXP_STATUS');
1603
+ return false;
1604
+ }
1605
+
1606
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1607
+ if ($status != NET_SFTP_STATUS_OK) {
1608
+ $this->_logError($response, $status);
1609
+ break;
1610
+ }
1611
+ }
1612
+
1613
+ return $i < 0;
1614
+ }
1615
+
1616
+ /**
1617
+ * Downloads a file from the SFTP server.
1618
+ *
1619
+ * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
1620
+ * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
1621
+ * operation.
1622
+ *
1623
+ * $offset and $length can be used to download files in chunks.
1624
+ *
1625
+ * @param String $remote_file
1626
+ * @param optional String $local_file
1627
+ * @param optional Integer $offset
1628
+ * @param optional Integer $length
1629
+ * @return Mixed
1630
+ * @access public
1631
+ */
1632
+ function get($remote_file, $local_file = false, $offset = 0, $length = -1)
1633
+ {
1634
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1635
+ return false;
1636
+ }
1637
+
1638
+ $remote_file = $this->_realpath($remote_file);
1639
+ if ($remote_file === false) {
1640
+ return false;
1641
+ }
1642
+
1643
+ $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
1644
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1645
+ return false;
1646
+ }
1647
+
1648
+ $response = $this->_get_sftp_packet();
1649
+ switch ($this->packet_type) {
1650
+ case NET_SFTP_HANDLE:
1651
+ $handle = substr($response, 4);
1652
+ break;
1653
+ case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1654
+ $this->_logError($response);
1655
+ return false;
1656
+ default:
1657
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1658
+ return false;
1659
+ }
1660
+
1661
+ if ($local_file !== false) {
1662
+ $fp = fopen($local_file, 'wb');
1663
+ if (!$fp) {
1664
+ return false;
1665
+ }
1666
+ } else {
1667
+ $content = '';
1668
+ }
1669
+
1670
+ $size = (1 << 20) < $length || $length < 0 ? 1 << 20 : $length;
1671
+ while (true) {
1672
+ $packet = pack('Na*N3', strlen($handle), $handle, $offset / 0x100000000, $offset, $size);
1673
+ if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
1674
+ if ($local_file !== false) {
1675
+ fclose($fp);
1676
+ }
1677
+ return false;
1678
+ }
1679
+
1680
+ $response = $this->_get_sftp_packet();
1681
+ switch ($this->packet_type) {
1682
+ case NET_SFTP_DATA:
1683
+ $temp = substr($response, 4);
1684
+ $offset+= strlen($temp);
1685
+ if ($local_file === false) {
1686
+ $content.= $temp;
1687
+ } else {
1688
+ fputs($fp, $temp);
1689
+ }
1690
+ break;
1691
+ case NET_SFTP_STATUS:
1692
+ // could, in theory, return false if !strlen($content) but we'll hold off for the time being
1693
+ $this->_logError($response);
1694
+ break 2;
1695
+ default:
1696
+ user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
1697
+ if ($local_file !== false) {
1698
+ fclose($fp);
1699
+ }
1700
+ return false;
1701
+ }
1702
+
1703
+ if ($length > 0 && $length <= $offset - $size) {
1704
+ break;
1705
+ }
1706
+ }
1707
+
1708
+ if ($length > 0 && $length <= $offset - $size) {
1709
+ if ($local_file === false) {
1710
+ $content = substr($content, 0, $length);
1711
+ } else {
1712
+ ftruncate($fp, $length);
1713
+ }
1714
+ }
1715
+
1716
+ if ($local_file !== false) {
1717
+ fclose($fp);
1718
+ }
1719
+
1720
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
1721
+ return false;
1722
+ }
1723
+
1724
+ $response = $this->_get_sftp_packet();
1725
+ if ($this->packet_type != NET_SFTP_STATUS) {
1726
+ user_error('Expected SSH_FXP_STATUS');
1727
+ return false;
1728
+ }
1729
+
1730
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1731
+ if ($status != NET_SFTP_STATUS_OK) {
1732
+ $this->_logError($response, $status);
1733
+ return false;
1734
+ }
1735
+
1736
+ // if $content isn't set that means a file was written to
1737
+ if (isset($content)) {
1738
+ return $content;
1739
+ }
1740
+
1741
+ return true;
1742
+ }
1743
+
1744
+ /**
1745
+ * Deletes a file on the SFTP server.
1746
+ *
1747
+ * @param String $path
1748
+ * @param Boolean $recursive
1749
+ * @return Boolean
1750
+ * @access public
1751
+ */
1752
+ function delete($path, $recursive = true)
1753
+ {
1754
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1755
+ return false;
1756
+ }
1757
+
1758
+ $path = $this->_realpath($path);
1759
+ if ($path === false) {
1760
+ return false;
1761
+ }
1762
+
1763
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
1764
+ if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
1765
+ return false;
1766
+ }
1767
+
1768
+ $response = $this->_get_sftp_packet();
1769
+ if ($this->packet_type != NET_SFTP_STATUS) {
1770
+ user_error('Expected SSH_FXP_STATUS');
1771
+ return false;
1772
+ }
1773
+
1774
+ // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1775
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1776
+ if ($status != NET_SFTP_STATUS_OK) {
1777
+ $this->_logError($response, $status);
1778
+ if (!$recursive) {
1779
+ return false;
1780
+ }
1781
+ $i = 0;
1782
+ $result = $this->_delete_recursive($path, $i);
1783
+ $this->_read_put_responses($i);
1784
+ return $result;
1785
+ }
1786
+
1787
+ return true;
1788
+ }
1789
+
1790
+ /**
1791
+ * Recursively deletes directories on the SFTP server
1792
+ *
1793
+ * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
1794
+ *
1795
+ * @param String $path
1796
+ * @param Integer $i
1797
+ * @return Boolean
1798
+ * @access private
1799
+ */
1800
+ function _delete_recursive($path, &$i)
1801
+ {
1802
+ if (!$this->_read_put_responses($i)) {
1803
+ return false;
1804
+ }
1805
+ $i = 0;
1806
+ $entries = $this->_list($path, true, false);
1807
+
1808
+ // normally $entries would have at least . and .. but it might not if the directories
1809
+ // permissions didn't allow reading
1810
+ if (empty($entries)) {
1811
+ return false;
1812
+ }
1813
+
1814
+ foreach ($entries as $filename=>$props) {
1815
+ if ($filename == '.' || $filename == '..') {
1816
+ continue;
1817
+ }
1818
+
1819
+ if (!isset($props['type'])) {
1820
+ return false;
1821
+ }
1822
+
1823
+ $temp = $path . '/' . $filename;
1824
+ if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
1825
+ if (!$this->_delete_recursive($temp, $i)) {
1826
+ return false;
1827
+ }
1828
+ } else {
1829
+ if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) {
1830
+ return false;
1831
+ }
1832
+
1833
+ $i++;
1834
+
1835
+ if ($i >= 50) {
1836
+ if (!$this->_read_put_responses($i)) {
1837
+ return false;
1838
+ }
1839
+ $i = 0;
1840
+ }
1841
+ }
1842
+ }
1843
+
1844
+ if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
1845
+ return false;
1846
+ }
1847
+ $this->_remove_dir($path);
1848
+
1849
+ $i++;
1850
+
1851
+ if ($i >= 50) {
1852
+ if (!$this->_read_put_responses($i)) {
1853
+ return false;
1854
+ }
1855
+ $i = 0;
1856
+ }
1857
+
1858
+ return true;
1859
+ }
1860
+
1861
+ /**
1862
+ * Renames a file or a directory on the SFTP server
1863
+ *
1864
+ * @param String $oldname
1865
+ * @param String $newname
1866
+ * @return Boolean
1867
+ * @access public
1868
+ */
1869
+ function rename($oldname, $newname)
1870
+ {
1871
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1872
+ return false;
1873
+ }
1874
+
1875
+ $oldname = $this->_realpath($oldname);
1876
+ $newname = $this->_realpath($newname);
1877
+ if ($oldname === false || $newname === false) {
1878
+ return false;
1879
+ }
1880
+
1881
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
1882
+ $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
1883
+ if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
1884
+ return false;
1885
+ }
1886
+
1887
+ $response = $this->_get_sftp_packet();
1888
+ if ($this->packet_type != NET_SFTP_STATUS) {
1889
+ user_error('Expected SSH_FXP_STATUS');
1890
+ return false;
1891
+ }
1892
+
1893
+ // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1894
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1895
+ if ($status != NET_SFTP_STATUS_OK) {
1896
+ $this->_logError($response, $status);
1897
+ return false;
1898
+ }
1899
+
1900
+ return true;
1901
+ }
1902
+
1903
+ /**
1904
+ * Parse Attributes
1905
+ *
1906
+ * See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info.
1907
+ *
1908
+ * @param String $response
1909
+ * @return Array
1910
+ * @access private
1911
+ */
1912
+ function _parseAttributes(&$response)
1913
+ {
1914
+ $attr = array();
1915
+ extract(unpack('Nflags', $this->_string_shift($response, 4)));
1916
+ // SFTPv4+ have a type field (a byte) that follows the above flag field
1917
+ foreach ($this->attributes as $key => $value) {
1918
+ switch ($flags & $key) {
1919
+ case NET_SFTP_ATTR_SIZE: // 0x00000001
1920
+ // size is represented by a 64-bit integer, so we perhaps ought to be doing the following:
1921
+ // $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256);
1922
+ // of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB
1923
+ // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than
1924
+ // 4GB as being 4GB.
1925
+ extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8)));
1926
+ $attr['size'] = $upper ? 0x100000000 * $upper : 0;
1927
+ $attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
1928
+ break;
1929
+ case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
1930
+ $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
1931
+ break;
1932
+ case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
1933
+ $attr+= unpack('Npermissions', $this->_string_shift($response, 4));
1934
+ // mode == permissions; permissions was the original array key and is retained for bc purposes.
1935
+ // mode was added because that's the more industry standard terminology
1936
+ $attr+= array('mode' => $attr['permissions']);
1937
+ $fileType = $this->_parseMode($attr['permissions']);
1938
+ if ($fileType !== false) {
1939
+ $attr+= array('type' => $fileType);
1940
+ }
1941
+ break;
1942
+ case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
1943
+ $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
1944
+ break;
1945
+ case NET_SFTP_ATTR_EXTENDED: // 0x80000000
1946
+ extract(unpack('Ncount', $this->_string_shift($response, 4)));
1947
+ for ($i = 0; $i < $count; $i++) {
1948
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1949
+ $key = $this->_string_shift($response, $length);
1950
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1951
+ $attr[$key] = $this->_string_shift($response, $length);
1952
+ }
1953
+ }
1954
+ }
1955
+ return $attr;
1956
+ }
1957
+
1958
+ /**
1959
+ * Attempt to identify the file type
1960
+ *
1961
+ * Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway
1962
+ *
1963
+ * @param Integer $mode
1964
+ * @return Integer
1965
+ * @access private
1966
+ */
1967
+ function _parseMode($mode)
1968
+ {
1969
+ // values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12
1970
+ // see, also, http://linux.die.net/man/2/stat
1971
+ switch ($mode & 0170000) {// ie. 1111 0000 0000 0000
1972
+ case 0000000: // no file type specified - figure out the file type using alternative means
1973
+ return false;
1974
+ case 0040000:
1975
+ return NET_SFTP_TYPE_DIRECTORY;
1976
+ case 0100000:
1977
+ return NET_SFTP_TYPE_REGULAR;
1978
+ case 0120000:
1979
+ return NET_SFTP_TYPE_SYMLINK;
1980
+ // new types introduced in SFTPv5+
1981
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
1982
+ case 0010000: // named pipe (fifo)
1983
+ return NET_SFTP_TYPE_FIFO;
1984
+ case 0020000: // character special
1985
+ return NET_SFTP_TYPE_CHAR_DEVICE;
1986
+ case 0060000: // block special
1987
+ return NET_SFTP_BLOCK_DEVICE;
1988
+ case 0140000: // socket
1989
+ return NET_SFTP_TYPE_SOCKET;
1990
+ case 0160000: // whiteout
1991
+ // "SPECIAL should be used for files that are of
1992
+ // a known type which cannot be expressed in the protocol"
1993
+ return NET_SFTP_TYPE_SPECIAL;
1994
+ default:
1995
+ return NET_SFTP_TYPE_UNKNOWN;
1996
+ }
1997
+ }
1998
+
1999
+ /**
2000
+ * Parse Longname
2001
+ *
2002
+ * SFTPv3 doesn't provide any easy way of identifying a file type. You could try to open
2003
+ * a file as a directory and see if an error is returned or you could try to parse the
2004
+ * SFTPv3-specific longname field of the SSH_FXP_NAME packet. That's what this function does.
2005
+ * The result is returned using the
2006
+ * {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}.
2007
+ *
2008
+ * If the longname is in an unrecognized format bool(false) is returned.
2009
+ *
2010
+ * @param String $longname
2011
+ * @return Mixed
2012
+ * @access private
2013
+ */
2014
+ function _parseLongname($longname)
2015
+ {
2016
+ // http://en.wikipedia.org/wiki/Unix_file_types
2017
+ // http://en.wikipedia.org/wiki/Filesystem_permissions#Notation_of_traditional_Unix_permissions
2018
+ if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) {
2019
+ switch ($longname[0]) {
2020
+ case '-':
2021
+ return NET_SFTP_TYPE_REGULAR;
2022
+ case 'd':
2023
+ return NET_SFTP_TYPE_DIRECTORY;
2024
+ case 'l':
2025
+ return NET_SFTP_TYPE_SYMLINK;
2026
+ default:
2027
+ return NET_SFTP_TYPE_SPECIAL;
2028
+ }
2029
+ }
2030
+
2031
+ return false;
2032
+ }
2033
+
2034
+ /**
2035
+ * Sends SFTP Packets
2036
+ *
2037
+ * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
2038
+ *
2039
+ * @param Integer $type
2040
+ * @param String $data
2041
+ * @see Net_SFTP::_get_sftp_packet()
2042
+ * @see Net_SSH2::_send_channel_packet()
2043
+ * @return Boolean
2044
+ * @access private
2045
+ */
2046
+ function _send_sftp_packet($type, $data)
2047
+ {
2048
+ $packet = $this->request_id !== false ?
2049
+ pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
2050
+ pack('NCa*', strlen($data) + 1, $type, $data);
2051
+
2052
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
2053
+ $result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet);
2054
+ $stop = strtok(microtime(), ' ') + strtok('');
2055
+
2056
+ if (defined('NET_SFTP_LOGGING')) {
2057
+ $packet_type = '-> ' . $this->packet_types[$type] .
2058
+ ' (' . round($stop - $start, 4) . 's)';
2059
+ if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
2060
+ echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
2061
+ flush();
2062
+ ob_flush();
2063
+ } else {
2064
+ $this->packet_type_log[] = $packet_type;
2065
+ if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
2066
+ $this->packet_log[] = $data;
2067
+ }
2068
+ }
2069
+ }
2070
+
2071
+ return $result;
2072
+ }
2073
+
2074
+ /**
2075
+ * Receives SFTP Packets
2076
+ *
2077
+ * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
2078
+ *
2079
+ * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present.
2080
+ * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
2081
+ * messages containing one SFTP packet.
2082
+ *
2083
+ * @see Net_SFTP::_send_sftp_packet()
2084
+ * @return String
2085
+ * @access private
2086
+ */
2087
+ function _get_sftp_packet()
2088
+ {
2089
+ $this->curTimeout = false;
2090
+
2091
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
2092
+
2093
+ // SFTP packet length
2094
+ while (strlen($this->packet_buffer) < 4) {
2095
+ $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL);
2096
+ if (is_bool($temp)) {
2097
+ $this->packet_type = false;
2098
+ $this->packet_buffer = '';
2099
+ return false;
2100
+ }
2101
+ $this->packet_buffer.= $temp;
2102
+ }
2103
+ extract(unpack('Nlength', $this->_st