SSH SFTP Updater Support - Version 0.7.3

Version Description

  • TWEAK: Update phpseclib to latest version (1.0.10)
  • TWEAK: Ship complete phpseclib library so that other plugins using it after we have loaded it don't have problems
  • TWEAK: Some minor internal re-factoring
  • TWEAK: Adds a dismissable (and won't reappear for 12 months) notice about other plugins users may be interested in.
Download this release

Release Info

Developer DavidAnderson
Plugin Icon wp plugin SSH SFTP Updater Support
Version 0.7.3
Comparing to
See all releases

Code changes from version 0.7.2 to 0.7.3

css/ssh-sftp-updater-support-notices.css ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* CSS for adverts */
2
+
3
+ .updraft-ad-container {
4
+ margin-left: 0px !important;
5
+ }
6
+
7
+ .updraft_notice_container {
8
+ height: auto;
9
+ overflow: hidden;
10
+ }
11
+
12
+ .updraft_advert_content_left {
13
+ float: none;
14
+ width: 65px;
15
+ }
16
+
17
+ .updraft_advert_content_right {
18
+ float: none;
19
+ width: auto;
20
+ overflow: hidden;
21
+ }
22
+
23
+ .updraft_advert_bottom {
24
+ margin: 10px 0;
25
+ padding: 10px;
26
+ font-size: 140%;
27
+ background-color: #FFF;
28
+ border-color: #E6DB55;
29
+ border: 1px solid;
30
+ border-radius: 4px;
31
+ }
32
+
33
+ .updraft-advert-dismiss {
34
+ float: right;
35
+ font-size: 13px;
36
+ font-weight: normal;
37
+ }
38
+
39
+ h3.updraft_advert_heading {
40
+ margin-top: 5px !important;
41
+ margin-bottom: 5px !important;
42
+ }
43
+
44
+ h4.updraft_advert_heading {
45
+ margin-top: 2px !important;
46
+ margin-bottom: 3px !important;
47
+ }
48
+
49
+ .updraft_center_content {
50
+ text-align: center;
51
+ margin-bottom: 5px;
52
+ }
53
+
54
+ .updraft_notice_link {
55
+ padding-left: 5px;
56
+ }
57
+
58
+ .updraft_text_center {
59
+ text-align: center;
60
+ }
61
+
62
+ @media screen and (min-width: 560px) {
63
+
64
+ .updraft_advert_content_left {
65
+ float: left;
66
+ }
67
+
68
+ }
69
+
images/notices/keyy_logo.png ADDED
Binary file
images/notices/metaslider_logo.png ADDED
Binary file
images/notices/updraft_logo.png ADDED
Binary file
images/notices/wp_optimize_logo.png ADDED
Binary file
includes/ssh-sftp-updater-support-notices.php ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH')) die('No direct access allowed');
4
+
5
+ if (!class_exists('Updraft_Notices_1_0')) require_once(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/includes/updraft-notices.php');
6
+
7
+ class SSH_SFTP_Updater_Support_Notices extends Updraft_Notices_1_0 {
8
+
9
+ protected static $_instance = null;
10
+
11
+ private $initialized = false;
12
+
13
+ protected $self_affiliate_id = 212;
14
+
15
+ protected $notices_content = array();
16
+
17
+ /**
18
+ * Creates and returns the only notice instance
19
+ *
20
+ * @return a SSH_SFTP_Updater_Support_Notices instance
21
+ */
22
+ public static function instance() {
23
+ if (empty(self::$_instance)) {
24
+ self::$_instance = new self();
25
+ }
26
+ return self::$_instance;
27
+ }
28
+
29
+ /**
30
+ * This method gets any parent notices and adds its own notices to the notice array
31
+ *
32
+ * @return Array returns an array of notices
33
+ */
34
+ protected function populate_notices_content() {
35
+ global $ssh_sftp_updater_support;
36
+ $parent_notice_content = parent::populate_notices_content();
37
+ $child_notice_content = array(
38
+ 'updraftplus' => array(
39
+ 'prefix' => '',
40
+ 'title' => __('Make sure you backup before you optimize your database', 'ssh-sftp-updater-support'),
41
+ 'text' => __("UpdraftPlus is the world's most trusted backup plugin from the owners of SSH SFTP Updater Support", 'ssh-sftp-updater-support'),
42
+ 'image' => 'notices/updraft_logo.png',
43
+ 'button_link' => 'https://updraftplus.com/',
44
+ 'button_meta' => 'updraftplus',
45
+ 'dismiss_time' => 'dismiss_page_notice_until',
46
+ 'supported_positions' => $this->anywhere,
47
+ 'validity_function' => 'is_updraftplus_installed',
48
+ ),
49
+ 'updraftcentral' => array(
50
+ 'prefix' => '',
51
+ 'title' => __('Save Time and Money. Manage multiple WordPress sites from one location.', 'ssh-sftp-updater-support'),
52
+ 'text' => __('UpdraftCentral is a highly efficient way to take backup, update and manage multiple WP sites from one location.', 'ssh-sftp-updater-support'),
53
+ 'image' => 'notices/updraft_logo.png',
54
+ 'button_link' => 'https://updraftplus.com/updraftcentral/',
55
+ 'button_meta' => 'updraftcentral',
56
+ 'dismiss_time' => 'dismiss_page_notice_until',
57
+ 'supported_positions' => $this->anywhere,
58
+ 'validity_function' => 'is_updraftcentral_installed',
59
+ ),
60
+ 'wp-optimize' => array(
61
+ 'prefix' => '',
62
+ 'title' => 'WP-Optimize',
63
+ 'text' => __("After you've backed up your database, we recommend you install our WP-Optimize plugin to streamline it for better website performance.", 'ssh-sftp-updater-support'),
64
+ 'image' => 'notices/wp_optimize_logo.png',
65
+ 'button_link' => 'https://getwpo.com',
66
+ 'button_meta' => 'wp-optimize',
67
+ 'dismiss_time' => 'dismiss_page_notice_until',
68
+ 'supported_positions' => $this->anywhere,
69
+ 'validity_function' => 'is_wpo_installed',
70
+ ),
71
+ 'keyy' => array(
72
+ 'prefix' => '',
73
+ 'title' => 'Keyy: Instant and secure logon with a wave of your phone',
74
+ 'text' => __("Find out more about our revolutionary new WordPress plugin.", "ssh-sftp-updater-support"),
75
+ 'button_link' => 'https://getkeyy.com/',
76
+ 'button_meta' => 'keyy',
77
+ 'image' => 'notices/keyy_logo.png',
78
+ 'dismiss_time' => 'dismiss_page_notice_until',
79
+ 'supported_positions' => $this->anywhere,
80
+ 'validity_function' => 'is_keyy_installed',
81
+ ),
82
+ 'meta-slider' => array(
83
+ 'prefix' => '',
84
+ 'title' => __("MetaSlider: the world's #1 slider plugin from the makers of SSH SFTP Updater Support", "ssh-sftp-updater-support"),
85
+ 'text' => __("With MetaSlider, you can easily add style and flare with beautifully-designed sliders.", "ssh-sftp-updater-support"),
86
+ 'button_link' => 'https://metaslider.com',
87
+ 'button_meta' => 'metaslider',
88
+ 'image' => 'notices/metaslider_logo.png',
89
+ 'dismiss_time' => 'dismiss_page_notice_until',
90
+ 'supported_positions' => $this->anywhere,
91
+ 'validity_function' => 'is_metaslider_installed',
92
+ ),
93
+
94
+ );
95
+
96
+ return array_merge($parent_notice_content, $child_notice_content);
97
+ }
98
+
99
+ /**
100
+ * Call this method to setup the notices
101
+ */
102
+ public function notices_init() {
103
+ if ($this->initialized) return;
104
+ $this->initialized = true;
105
+ $this->notices_content = (defined('SSH_SFTP_UPDATER_SUPPORT_NOADS_B') && SSH_SFTP_UPDATER_SUPPORT_NOADS_B) ? array() : $this->populate_notices_content();
106
+ $our_version = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? SSH_SFTP_UPDATER_SUPPORT_VERSION.'.'.time() : SSH_SFTP_UPDATER_SUPPORT_VERSION;
107
+ $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
108
+ wp_enqueue_style('ssh-sftp-updater-support-notices-css', SSH_SFTP_UPDATER_SUPPORT_URL.'/css/ssh-sftp-updater-support-notices'.$min_or_not.'.css', array(), $our_version);
109
+ }
110
+
111
+ /**
112
+ * This method will call the parent is_plugin_installed and pass in the product updraftplus to check if that plugin is installed if it is then we shouldn't display the notice
113
+ *
114
+ * @param string $product the plugin slug
115
+ * @param boolean $also_require_active a bool to indicate if the plugin should also be active
116
+ * @return boolean a bool to indicate if the notice should be displayed or not
117
+ */
118
+ protected function is_updraftplus_installed($product = 'updraftplus', $also_require_active = false) {
119
+ return parent::is_plugin_installed($product, $also_require_active);
120
+ }
121
+
122
+ /**
123
+ * This method will call the parent is_plugin_installed and pass in the product updraftcentral to check if that plugin is installed if it is then we shouldn't display the notice
124
+ *
125
+ * @param string $product the plugin slug
126
+ * @param boolean $also_require_active a bool to indicate if the plugin should also be active
127
+ * @return boolean a bool to indicate if the notice should be displayed or not
128
+ */
129
+ protected function is_updraftcentral_installed($product = 'updraftcentral', $also_require_active = false) {
130
+ return parent::is_plugin_installed($product, $also_require_active);
131
+ }
132
+
133
+ /**
134
+ * This method will call the parent is_plugin_installed and pass in the product keyy to check if that plugin is installed if it is then we shouldn't display the notice
135
+ *
136
+ * @param string $product the plugin slug
137
+ * @param boolean $also_require_active a bool to indicate if the plugin should also be active
138
+ * @return boolean a bool to indicate if the notice should be displayed or not
139
+ */
140
+ protected function is_keyy_installed($product = 'keyy', $also_require_active = false) {
141
+ return parent::is_plugin_installed($product, $also_require_active);
142
+ }
143
+
144
+ /**
145
+ * This method will call the is premium function in the SSH_SFTP_Updater_Support_Notices object to check if this install is premium and if it is we won't display the notice
146
+ *
147
+ * @return boolean a bool to indicate if we should display the notice or not
148
+ */
149
+ protected function is_wpo_installed($product = 'wp-optimize', $also_require_active = false) {
150
+ return parent::is_plugin_installed($product, $also_require_active);
151
+ }
152
+
153
+ /**
154
+ * This method will check to see if Meta Slider plugin is installed.
155
+ *
156
+ * @param String $product the plugin slug
157
+ * @param boolean $also_require_active a bool to indicate if the plugin should be active or not
158
+ * @return boolean a bool to indicate if the notice should be displayed or not
159
+ */
160
+ protected function is_metaslider_installed($product = 'ml-slider', $also_require_active = false) {
161
+ return parent::is_plugin_installed($product, $also_require_active);
162
+ }
163
+
164
+
165
+ /**
166
+ * This method calls the parent verson and will work out if the user is using a non english language and if so returns true so that they can see the translation advert.
167
+ *
168
+ * @param String $plugin_base_dir the plugin base directory
169
+ * @param String $product_name the name of the plugin
170
+ * @return Boolean returns true if the user is using a non english language and could translate otherwise false
171
+ */
172
+ protected function translation_needed($plugin_base_dir = null, $product_name = null) {
173
+ return parent::translation_needed(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH, 'ssh-sftp-updater-support');
174
+ }
175
+
176
+ /**
177
+ * This method checks to see if the notices dismiss_time parameter has been dismissed
178
+ *
179
+ * @param String $dismiss_time a string containing the dimiss time ID
180
+ * @return Boolaen returns true if the notice has been dismissed and shouldn't be shown otherwise display it
181
+ */
182
+ protected function check_notice_dismissed($dismiss_time) {
183
+
184
+ $time_now = (defined('SSH_SFTP_UPDATER_SUPPORT_NOTICES_FORCE_TIME') ? SSH_SFTP_UPDATER_SUPPORT_NOTICES_FORCE_TIME : time());
185
+
186
+ $notice_dismiss = ($time_now < get_site_option('ssh_sftp_updater_support_dismiss_page_notice_until', 0));
187
+
188
+ $dismiss = false;
189
+
190
+ if ('dismiss_page_notice_until' == $dismiss_time) $dismiss = $notice_dismiss;
191
+
192
+ return $dismiss;
193
+ }
194
+
195
+ /**
196
+ * Check notice data for seasonal info and return true if we should display this notice.
197
+ *
198
+ * @param array $notice_data
199
+ * @return bool
200
+ */
201
+ protected function skip_seasonal_notices($notice_data) {
202
+ $time_now = defined('SSH_SFTP_UPDATER_SUPPORT_FORCE_TIME_NOTICES_FORCE_TIME') ? SSH_SFTP_UPDATER_SUPPORT_FORCE_TIME_NOTICES_FORCE_TIME : time();
203
+ $valid_from = strtotime($notice_data['valid_from']);
204
+ $valid_to = strtotime($notice_data['valid_to']);
205
+ $dismiss = $this->check_notice_dismissed($notice_data['dismiss_time']);
206
+ if (($time_now >= $valid_from && $time_now <= $valid_to) && !$dismiss) {
207
+ // return true so that we return this notice to be displayed
208
+ return true;
209
+ }
210
+
211
+ return false;
212
+ }
213
+
214
+ /**
215
+ * This method will create the chosen notice and the template to use and depending on the parameters either echo it to the page or return it
216
+ *
217
+ * @param Array $advert_information an array with the notice information in
218
+ * @param Boolean $return_instead_of_echo a bool value to indicate if the notice should be printed to page or returned
219
+ * @param String $position a string to indicate what template should be used
220
+ * @return String a notice to display
221
+ */
222
+ protected function render_specified_notice($advert_information, $return_instead_of_echo = false, $position = 'top') {
223
+
224
+ if ('bottom' == $position) {
225
+ $template_file = 'bottom-notice.php';
226
+ } elseif ('report' == $position) {
227
+ $template_file = 'report.php';
228
+ } elseif ('report-plain' == $position) {
229
+ $template_file = 'report-plain.php';
230
+ } else {
231
+ $template_file = 'horizontal-notice.php';
232
+ }
233
+
234
+ $extract_variables = array_merge($advert_information, array('ssh_sftp_updater_support_notices' => $this));
235
+
236
+ return SSH_SFTP_Updater_Support()->include_template('notices/'.$template_file, $return_instead_of_echo, $extract_variables);
237
+ }
238
+ }
includes/updraft-notices.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('ABSPATH')) die('No direct access allowed');
4
+
5
+ /**
6
+ * If we ever change the API of the Updraft_Notices class, then we'll need to rename and version it, e.g. Updraft_Notices_1_0, because otherwise a plugin may find that it's loaded an older instance than it wanted from another plugin.
7
+ */
8
+ abstract class Updraft_Notices_1_0 {
9
+
10
+ protected $notices_content;
11
+
12
+ /**
13
+ * These variables are just short-hands to be used in advert content.
14
+ *
15
+ * @var array
16
+ */
17
+ protected $dashboard_top = array('top');
18
+
19
+ protected $dashboard_top_or_report = array('top', 'report', 'report-plain');
20
+
21
+ protected $dashboard_bottom_or_report = array('bottom', 'report', 'report-plain');
22
+
23
+ protected $anywhere = array('top', 'bottom', 'report', 'report-plain');
24
+
25
+ protected $autobackup = array('autobackup');
26
+
27
+ protected $autobackup_bottom_or_report = array('autobackup', 'bottom', 'report', 'report-plain');
28
+
29
+ protected function populate_notices_content() {
30
+ // Global adverts that appear in all products will be returned to the child to display.
31
+ return array();
32
+ }
33
+
34
+ /**
35
+ * Call this method to setup the notices.
36
+ */
37
+ abstract protected function notices_init();
38
+
39
+ protected function is_plugin_installed($product = null, $also_require_active = false) {
40
+ if ($also_require_active) return class_exists($product);
41
+ if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
42
+ $plugins = get_plugins();
43
+ $product_file = false;
44
+ foreach ($plugins as $key => $value) {
45
+ if ($value['TextDomain'] == $product) {
46
+ // We have found the plugin so return false so that we do not display this advert.
47
+ return false;
48
+ }
49
+ }
50
+ return true;
51
+ }
52
+
53
+ protected function translation_needed($plugin_base_dir, $product_name) {
54
+ $wplang = get_locale();
55
+ if (strlen($wplang) < 1 || 'en_US' == $wplang || 'en_GB' == $wplang) return false;
56
+ if (defined('WP_LANG_DIR') && is_file(WP_LANG_DIR.'/plugins/'.$product_name.'-'.$wplang.'.mo')) return false;
57
+ if (is_file($plugin_base_dir.'/languages/'.$product_name.'-'.$wplang.'.mo')) return false;
58
+ return true;
59
+ }
60
+
61
+ public function do_notice($notice = false, $position = 'top', $return_instead_of_echo = false) {
62
+
63
+ $this->notices_init();
64
+
65
+ if (false === $notice) $notice = apply_filters('updraft_notices_force_id', false, $this);
66
+
67
+ $notice_content = $this->get_notice_data($notice, $position);
68
+
69
+ if (false != $notice_content) {
70
+ return $this->render_specified_notice($notice_content, $return_instead_of_echo, $position);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * This method will return a notice ready for display.
76
+ *
77
+ * @param boolean $notice Sends True or False if there are notices to show.
78
+ * @param string $position Which screen position the notice is.
79
+ * @return array Returns Notice data.
80
+ */
81
+ protected function get_notice_data($notice = false, $position = 'top') {
82
+
83
+ // If a specific notice has been passed to this method then return that notice.
84
+ if ($notice) {
85
+ if (!isset($this->notices_content[$notice])) return false;
86
+
87
+ // Does the notice support the position specified?
88
+ if (isset($this->notices_content[$notice]['supported_positions']) && !in_array($position, $this->notices_content[$notice]['supported_positions'])) return false;
89
+
90
+ // First check if the advert passed can be displayed and hasn't been dismissed, we do this by checking what dismissed value we should be checking.
91
+ $dismiss_time = $this->notices_content[$notice]['dismiss_time'];
92
+
93
+ $dismiss = $this->check_notice_dismissed($dismiss_time);
94
+
95
+ if ($dismiss) return false;
96
+
97
+ return $this->notices_content[$notice];
98
+ }
99
+
100
+ // Create an array to add non-seasonal adverts to so that if a seasonal advert can't be returned we can choose a random advert from this array.
101
+ $available_notices = array();
102
+
103
+ // If Advert wasn't passed then next we should check to see if a seasonal advert can be returned.
104
+ foreach ($this->notices_content as $notice_id => $notice_data) {
105
+ // Does the notice support the position specified?
106
+ if (isset($this->notices_content[$notice_id]['supported_positions']) && !in_array($position, $this->notices_content[$notice_id]['supported_positions'])) continue;
107
+
108
+ // If the advert has a validity function, then require the advert to be valid.
109
+ if (!empty($notice_data['validity_function']) && !call_user_func(array($this, $notice_data['validity_function']))) continue;
110
+
111
+
112
+ if (isset($notice_data['valid_from']) && isset($notice_data['valid_to'])) {
113
+ if ($this->skip_seasonal_notices($notice_data)) return $notice_data;
114
+ } else {
115
+ $dismiss_time = $this->notices_content[$notice_id]['dismiss_time'];
116
+ $dismiss = $this->check_notice_dismissed($dismiss_time);
117
+
118
+ if (!$dismiss) $available_notices[$notice_id] = $notice_data;
119
+ }
120
+ }
121
+
122
+ if (empty($available_notices)) return false;
123
+
124
+ // If a seasonal advert can't be returned then we will return a random advert.
125
+ // Using shuffle here as something like rand which produces a random number and uses that as the array index fails, this is because in future an advert may not be numbered and could have a string as its key which will then cause errors.
126
+ shuffle($available_notices);
127
+ return $available_notices[0];
128
+ }
129
+
130
+ protected function skip_seasonal_notices($notice_data) {
131
+ return false;
132
+ }
133
+
134
+ public function get_affiliate_id() {
135
+ return $this->self_affiliate_id;
136
+ }
137
+
138
+ abstract protected function check_notice_dismissed($dismiss_time);
139
+ }
index.html ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2
+ <HTML>
3
+ <HEAD>
4
+ <TITLE>Sorry!!</TITLE>
5
+ </HEAD>
6
+ <BODY>
7
+ &nbsp;
8
+ <h1>SSH SFTP Updater Support</h1>
9
+ </BODY>
10
+ </HTML>
phpseclib/Crypt/Base.php CHANGED
@@ -1,2616 +1,2660 @@
1
- <?php
2
-
3
- /**
4
- * Base Class for all Crypt_* cipher classes
5
- *
6
- * PHP versions 4 and 5
7
- *
8
- * Internally for phpseclib developers:
9
- * If you plan to add a new cipher class, please note following rules:
10
- *
11
- * - The new Crypt_* cipher class should extend Crypt_Base
12
- *
13
- * - Following methods are then required to be overridden/overloaded:
14
- *
15
- * - _encryptBlock()
16
- *
17
- * - _decryptBlock()
18
- *
19
- * - _setupKey()
20
- *
21
- * - All other methods are optional to be overridden/overloaded
22
- *
23
- * - Look at the source code of the current ciphers how they extend Crypt_Base
24
- * and take one of them as a start up for the new cipher class.
25
- *
26
- * - Please read all the other comments/notes/hints here also for each class var/method
27
- *
28
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
29
- * of this software and associated documentation files (the "Software"), to deal
30
- * in the Software without restriction, including without limitation the rights
31
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
- * copies of the Software, and to permit persons to whom the Software is
33
- * furnished to do so, subject to the following conditions:
34
- *
35
- * The above copyright notice and this permission notice shall be included in
36
- * all copies or substantial portions of the Software.
37
- *
38
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
- * THE SOFTWARE.
45
- *
46
- * @category Crypt
47
- * @package Crypt_Base
48
- * @author Jim Wigginton <terrafrost@php.net>
49
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
50
- * @copyright 2007 Jim Wigginton
51
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
- * @link http://phpseclib.sourceforge.net
53
- */
54
-
55
- /**#@+
56
- * @access public
57
- * @see self::encrypt()
58
- * @see self::decrypt()
59
- */
60
- /**
61
- * Encrypt / decrypt using the Counter mode.
62
- *
63
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
64
- *
65
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
66
- */
67
- define('CRYPT_MODE_CTR', -1);
68
- /**
69
- * Encrypt / decrypt using the Electronic Code Book mode.
70
- *
71
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
72
- */
73
- define('CRYPT_MODE_ECB', 1);
74
- /**
75
- * Encrypt / decrypt using the Code Book Chaining mode.
76
- *
77
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
78
- */
79
- define('CRYPT_MODE_CBC', 2);
80
- /**
81
- * Encrypt / decrypt using the Cipher Feedback mode.
82
- *
83
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
84
- */
85
- define('CRYPT_MODE_CFB', 3);
86
- /**
87
- * Encrypt / decrypt using the Output Feedback mode.
88
- *
89
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
90
- */
91
- define('CRYPT_MODE_OFB', 4);
92
- /**
93
- * Encrypt / decrypt using streaming mode.
94
- */
95
- define('CRYPT_MODE_STREAM', 5);
96
- /**#@-*/
97
-
98
- /**#@+
99
- * @access private
100
- * @see self::Crypt_Base()
101
- * @internal These constants are for internal use only
102
- */
103
- /**
104
- * Base value for the internal implementation $engine switch
105
- */
106
- define('CRYPT_ENGINE_INTERNAL', 1);
107
- /**
108
- * Base value for the mcrypt implementation $engine switch
109
- */
110
- define('CRYPT_ENGINE_MCRYPT', 2);
111
- /**
112
- * Base value for the OpenSSL implementation $engine switch
113
- */
114
- define('CRYPT_ENGINE_OPENSSL', 3);
115
- /**#@-*/
116
-
117
- /**
118
- * Base Class for all Crypt_* cipher classes
119
- *
120
- * @package Crypt_Base
121
- * @author Jim Wigginton <terrafrost@php.net>
122
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
123
- * @access public
124
- */
125
- class Crypt_Base
126
- {
127
- /**
128
- * The Encryption Mode
129
- *
130
- * @see self::Crypt_Base()
131
- * @var int
132
- * @access private
133
- */
134
- var $mode;
135
-
136
- /**
137
- * The Block Length of the block cipher
138
- *
139
- * @var int
140
- * @access private
141
- */
142
- var $block_size = 16;
143
-
144
- /**
145
- * The Key
146
- *
147
- * @see self::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 self::setIV()
157
- * @var string
158
- * @access private
159
- */
160
- var $iv;
161
-
162
- /**
163
- * A "sliding" Initialization Vector
164
- *
165
- * @see self::enableContinuousBuffer()
166
- * @see self::_clearBuffers()
167
- * @var string
168
- * @access private
169
- */
170
- var $encryptIV;
171
-
172
- /**
173
- * A "sliding" Initialization Vector
174
- *
175
- * @see self::enableContinuousBuffer()
176
- * @see self::_clearBuffers()
177
- * @var string
178
- * @access private
179
- */
180
- var $decryptIV;
181
-
182
- /**
183
- * Continuous Buffer status
184
- *
185
- * @see self::enableContinuousBuffer()
186
- * @var bool
187
- * @access private
188
- */
189
- var $continuousBuffer = false;
190
-
191
- /**
192
- * Encryption buffer for CTR, OFB and CFB modes
193
- *
194
- * @see self::encrypt()
195
- * @see self::_clearBuffers()
196
- * @var array
197
- * @access private
198
- */
199
- var $enbuffer;
200
-
201
- /**
202
- * Decryption buffer for CTR, OFB and CFB modes
203
- *
204
- * @see self::decrypt()
205
- * @see self::_clearBuffers()
206
- * @var array
207
- * @access private
208
- */
209
- var $debuffer;
210
-
211
- /**
212
- * mcrypt resource for encryption
213
- *
214
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
215
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
216
- *
217
- * @see self::encrypt()
218
- * @var resource
219
- * @access private
220
- */
221
- var $enmcrypt;
222
-
223
- /**
224
- * mcrypt resource for decryption
225
- *
226
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
227
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
228
- *
229
- * @see self::decrypt()
230
- * @var resource
231
- * @access private
232
- */
233
- var $demcrypt;
234
-
235
- /**
236
- * Does the enmcrypt resource need to be (re)initialized?
237
- *
238
- * @see Crypt_Twofish::setKey()
239
- * @see Crypt_Twofish::setIV()
240
- * @var bool
241
- * @access private
242
- */
243
- var $enchanged = true;
244
-
245
- /**
246
- * Does the demcrypt resource need to be (re)initialized?
247
- *
248
- * @see Crypt_Twofish::setKey()
249
- * @see Crypt_Twofish::setIV()
250
- * @var bool
251
- * @access private
252
- */
253
- var $dechanged = true;
254
-
255
- /**
256
- * mcrypt resource for CFB mode
257
- *
258
- * mcrypt's CFB mode, in (and only in) buffered context,
259
- * is broken, so phpseclib implements the CFB mode by it self,
260
- * even when the mcrypt php extension is available.
261
- *
262
- * In order to do the CFB-mode work (fast) phpseclib
263
- * use a separate ECB-mode mcrypt resource.
264
- *
265
- * @link http://phpseclib.sourceforge.net/cfb-demo.phps
266
- * @see self::encrypt()
267
- * @see self::decrypt()
268
- * @see self::_setupMcrypt()
269
- * @var resource
270
- * @access private
271
- */
272
- var $ecb;
273
-
274
- /**
275
- * Optimizing value while CFB-encrypting
276
- *
277
- * Only relevant if $continuousBuffer enabled
278
- * and $engine == CRYPT_ENGINE_MCRYPT
279
- *
280
- * It's faster to re-init $enmcrypt if
281
- * $buffer bytes > $cfb_init_len than
282
- * using the $ecb resource furthermore.
283
- *
284
- * This value depends of the chosen cipher
285
- * and the time it would be needed for it's
286
- * initialization [by mcrypt_generic_init()]
287
- * which, typically, depends on the complexity
288
- * on its internaly Key-expanding algorithm.
289
- *
290
- * @see self::encrypt()
291
- * @var int
292
- * @access private
293
- */
294
- var $cfb_init_len = 600;
295
-
296
- /**
297
- * Does internal cipher state need to be (re)initialized?
298
- *
299
- * @see self::setKey()
300
- * @see self::setIV()
301
- * @see self::disableContinuousBuffer()
302
- * @var bool
303
- * @access private
304
- */
305
- var $changed = true;
306
-
307
- /**
308
- * Padding status
309
- *
310
- * @see self::enablePadding()
311
- * @var bool
312
- * @access private
313
- */
314
- var $padding = true;
315
-
316
- /**
317
- * Is the mode one that is paddable?
318
- *
319
- * @see self::Crypt_Base()
320
- * @var bool
321
- * @access private
322
- */
323
- var $paddable = false;
324
-
325
- /**
326
- * Holds which crypt engine internaly should be use,
327
- * which will be determined automatically on __construct()
328
- *
329
- * Currently available $engines are:
330
- * - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
331
- * - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
332
- * - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
333
- *
334
- * @see self::_setEngine()
335
- * @see self::encrypt()
336
- * @see self::decrypt()
337
- * @var int
338
- * @access private
339
- */
340
- var $engine;
341
-
342
- /**
343
- * Holds the preferred crypt engine
344
- *
345
- * @see self::_setEngine()
346
- * @see self::setPreferredEngine()
347
- * @var int
348
- * @access private
349
- */
350
- var $preferredEngine;
351
-
352
- /**
353
- * The mcrypt specific name of the cipher
354
- *
355
- * Only used if $engine == CRYPT_ENGINE_MCRYPT
356
- *
357
- * @link http://www.php.net/mcrypt_module_open
358
- * @link http://www.php.net/mcrypt_list_algorithms
359
- * @see self::_setupMcrypt()
360
- * @var string
361
- * @access private
362
- */
363
- var $cipher_name_mcrypt;
364
-
365
- /**
366
- * The openssl specific name of the cipher
367
- *
368
- * Only used if $engine == CRYPT_ENGINE_OPENSSL
369
- *
370
- * @link http://www.php.net/openssl-get-cipher-methods
371
- * @var string
372
- * @access private
373
- */
374
- var $cipher_name_openssl;
375
-
376
- /**
377
- * The openssl specific name of the cipher in ECB mode
378
- *
379
- * If OpenSSL does not support the mode we're trying to use (CTR)
380
- * it can still be emulated with ECB mode.
381
- *
382
- * @link http://www.php.net/openssl-get-cipher-methods
383
- * @var string
384
- * @access private
385
- */
386
- var $cipher_name_openssl_ecb;
387
-
388
- /**
389
- * The default salt used by setPassword()
390
- *
391
- * @see self::setPassword()
392
- * @var string
393
- * @access private
394
- */
395
- var $password_default_salt = 'phpseclib/salt';
396
-
397
- /**
398
- * The namespace used by the cipher for its constants.
399
- *
400
- * ie: AES.php is using CRYPT_AES_MODE_* for its constants
401
- * so $const_namespace is AES
402
- *
403
- * DES.php is using CRYPT_DES_MODE_* for its constants
404
- * so $const_namespace is DES... and so on
405
- *
406
- * All CRYPT_<$const_namespace>_MODE_* are aliases of
407
- * the generic CRYPT_MODE_* constants, so both could be used
408
- * for each cipher.
409
- *
410
- * Example:
411
- * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
412
- * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
413
- *
414
- * @see self::Crypt_Base()
415
- * @var string
416
- * @access private
417
- */
418
- var $const_namespace;
419
-
420
- /**
421
- * The name of the performance-optimized callback function
422
- *
423
- * Used by encrypt() / decrypt()
424
- * only if $engine == CRYPT_ENGINE_INTERNAL
425
- *
426
- * @see self::encrypt()
427
- * @see self::decrypt()
428
- * @see self::_setupInlineCrypt()
429
- * @see self::$use_inline_crypt
430
- * @var Callback
431
- * @access private
432
- */
433
- var $inline_crypt;
434
-
435
- /**
436
- * Holds whether performance-optimized $inline_crypt() can/should be used.
437
- *
438
- * @see self::encrypt()
439
- * @see self::decrypt()
440
- * @see self::inline_crypt
441
- * @var mixed
442
- * @access private
443
- */
444
- var $use_inline_crypt;
445
-
446
- /**
447
- * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
448
- *
449
- * @see self::_openssl_ctr_process()
450
- * @var bool
451
- * @access private
452
- */
453
- var $openssl_emulate_ctr = false;
454
-
455
- /**
456
- * Determines what options are passed to openssl_encrypt/decrypt
457
- *
458
- * @see self::isValidEngine()
459
- * @var mixed
460
- * @access private
461
- */
462
- var $openssl_options;
463
-
464
- /**
465
- * Has the key length explicitly been set or should it be derived from the key, itself?
466
- *
467
- * @see self::setKeyLength()
468
- * @var bool
469
- * @access private
470
- */
471
- var $explicit_key_length = false;
472
-
473
- /**
474
- * Don't truncate / null pad key
475
- *
476
- * @see self::_clearBuffers()
477
- * @var bool
478
- * @access private
479
- */
480
- var $skip_key_adjustment = false;
481
-
482
- /**
483
- * Default Constructor.
484
- *
485
- * Determines whether or not the mcrypt extension should be used.
486
- *
487
- * $mode could be:
488
- *
489
- * - CRYPT_MODE_ECB
490
- *
491
- * - CRYPT_MODE_CBC
492
- *
493
- * - CRYPT_MODE_CTR
494
- *
495
- * - CRYPT_MODE_CFB
496
- *
497
- * - CRYPT_MODE_OFB
498
- *
499
- * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
500
- *
501
- * If not explicitly set, CRYPT_MODE_CBC will be used.
502
- *
503
- * @param int $mode
504
- * @access public
505
- */
506
- function __construct($mode = CRYPT_MODE_CBC)
507
- {
508
- // $mode dependent settings
509
- switch ($mode) {
510
- case CRYPT_MODE_ECB:
511
- $this->paddable = true;
512
- $this->mode = CRYPT_MODE_ECB;
513
- break;
514
- case CRYPT_MODE_CTR:
515
- case CRYPT_MODE_CFB:
516
- case CRYPT_MODE_OFB:
517
- case CRYPT_MODE_STREAM:
518
- $this->mode = $mode;
519
- break;
520
- case CRYPT_MODE_CBC:
521
- default:
522
- $this->paddable = true;
523
- $this->mode = CRYPT_MODE_CBC;
524
- }
525
-
526
- $this->_setEngine();
527
-
528
- // Determining whether inline crypting can be used by the cipher
529
- if ($this->use_inline_crypt !== false) {
530
- $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
531
- }
532
- }
533
-
534
- /**
535
- * PHP4 compatible Default Constructor.
536
- *
537
- * @see self::__construct()
538
- * @param int $mode
539
- * @access public
540
- */
541
- function Crypt_Base($mode = CRYPT_MODE_CBC)
542
- {
543
- $this->__construct($mode);
544
- }
545
-
546
- /**
547
- * Sets the initialization vector. (optional)
548
- *
549
- * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
550
- * to be all zero's.
551
- *
552
- * @access public
553
- * @param string $iv
554
- * @internal Can be overwritten by a sub class, but does not have to be
555
- */
556
- function setIV($iv)
557
- {
558
- if ($this->mode == CRYPT_MODE_ECB) {
559
- return;
560
- }
561
-
562
- $this->iv = $iv;
563
- $this->changed = true;
564
- }
565
-
566
- /**
567
- * Sets the key length.
568
- *
569
- * Keys with explicitly set lengths need to be treated accordingly
570
- *
571
- * @access public
572
- * @param int $length
573
- */
574
- function setKeyLength($length)
575
- {
576
- $this->explicit_key_length = true;
577
- $this->changed = true;
578
- $this->_setEngine();
579
- }
580
-
581
- /**
582
- * Returns the current key length in bits
583
- *
584
- * @access public
585
- * @return int
586
- */
587
- function getKeyLength()
588
- {
589
- return $this->key_length << 3;
590
- }
591
-
592
- /**
593
- * Returns the current block length in bits
594
- *
595
- * @access public
596
- * @return int
597
- */
598
- function getBlockLength()
599
- {
600
- return $this->block_size << 3;
601
- }
602
-
603
- /**
604
- * Sets the key.
605
- *
606
- * The min/max length(s) of the key depends on the cipher which is used.
607
- * If the key not fits the length(s) of the cipher it will paded with null bytes
608
- * up to the closest valid key length. If the key is more than max length,
609
- * we trim the excess bits.
610
- *
611
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
612
- *
613
- * @access public
614
- * @param string $key
615
- * @internal Could, but not must, extend by the child Crypt_* class
616
- */
617
- function setKey($key)
618
- {
619
- if (!$this->explicit_key_length) {
620
- $this->setKeyLength(strlen($key) << 3);
621
- $this->explicit_key_length = false;
622
- }
623
-
624
- $this->key = $key;
625
- $this->changed = true;
626
- $this->_setEngine();
627
- }
628
-
629
- /**
630
- * Sets the password.
631
- *
632
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
633
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
634
- * $hash, $salt, $count, $dkLen
635
- *
636
- * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
637
- *
638
- * @see Crypt/Hash.php
639
- * @param string $password
640
- * @param string $method
641
- * @return bool
642
- * @access public
643
- * @internal Could, but not must, extend by the child Crypt_* class
644
- */
645
- function setPassword($password, $method = 'pbkdf2')
646
- {
647
- $key = '';
648
-
649
- switch ($method) {
650
- default: // 'pbkdf2' or 'pbkdf1'
651
- $func_args = func_get_args();
652
-
653
- // Hash function
654
- $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
655
-
656
- // WPA and WPA2 use the SSID as the salt
657
- $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
658
-
659
- // RFC2898#section-4.2 uses 1,000 iterations by default
660
- // WPA and WPA2 use 4,096.
661
- $count = isset($func_args[4]) ? $func_args[4] : 1000;
662
-
663
- // Keylength
664
- if (isset($func_args[5])) {
665
- $dkLen = $func_args[5];
666
- } else {
667
- $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
668
- }
669
-
670
- switch (true) {
671
- case $method == 'pbkdf1':
672
- if (!class_exists('Crypt_Hash')) {
673
- include_once 'Crypt/Hash.php';
674
- }
675
- $hashObj = new Crypt_Hash();
676
- $hashObj->setHash($hash);
677
- if ($dkLen > $hashObj->getLength()) {
678
- user_error('Derived key too long');
679
- return false;
680
- }
681
- $t = $password . $salt;
682
- for ($i = 0; $i < $count; ++$i) {
683
- $t = $hashObj->hash($t);
684
- }
685
- $key = substr($t, 0, $dkLen);
686
-
687
- $this->setKey(substr($key, 0, $dkLen >> 1));
688
- $this->setIV(substr($key, $dkLen >> 1));
689
-
690
- return true;
691
- // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
692
- case !function_exists('hash_pbkdf2'):
693
- case !function_exists('hash_algos'):
694
- case !in_array($hash, hash_algos()):
695
- if (!class_exists('Crypt_Hash')) {
696
- include_once 'Crypt/Hash.php';
697
- }
698
- $i = 1;
699
- while (strlen($key) < $dkLen) {
700
- $hmac = new Crypt_Hash();
701
- $hmac->setHash($hash);
702
- $hmac->setKey($password);
703
- $f = $u = $hmac->hash($salt . pack('N', $i++));
704
- for ($j = 2; $j <= $count; ++$j) {
705
- $u = $hmac->hash($u);
706
- $f^= $u;
707
- }
708
- $key.= $f;
709
- }
710
- $key = substr($key, 0, $dkLen);
711
- break;
712
- default:
713
- $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
714
- }
715
- }
716
-
717
- $this->setKey($key);
718
-
719
- return true;
720
- }
721
-
722
- /**
723
- * Encrypts a message.
724
- *
725
- * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
726
- * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
727
- * necessary are discussed in the following
728
- * URL:
729
- *
730
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
731
- *
732
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
733
- * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
734
- * length.
735
- *
736
- * @see self::decrypt()
737
- * @access public
738
- * @param string $plaintext
739
- * @return string $ciphertext
740
- * @internal Could, but not must, extend by the child Crypt_* class
741
- */
742
- function encrypt($plaintext)
743
- {
744
- if ($this->paddable) {
745
- $plaintext = $this->_pad($plaintext);
746
- }
747
-
748
- if ($this->engine === CRYPT_ENGINE_OPENSSL) {
749
- if ($this->changed) {
750
- $this->_clearBuffers();
751
- $this->changed = false;
752
- }
753
- switch ($this->mode) {
754
- case CRYPT_MODE_STREAM:
755
- return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
756
- case CRYPT_MODE_ECB:
757
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
758
- return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
759
- case CRYPT_MODE_CBC:
760
- $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
761
- if (!defined('OPENSSL_RAW_DATA')) {
762
- $result = substr($result, 0, -$this->block_size);
763
- }
764
- if ($this->continuousBuffer) {
765
- $this->encryptIV = substr($result, -$this->block_size);
766
- }
767
- return $result;
768
- case CRYPT_MODE_CTR:
769
- return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
770
- case CRYPT_MODE_CFB:
771
- // cfb loosely routines inspired by openssl's:
772
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
773
- $ciphertext = '';
774
- if ($this->continuousBuffer) {
775
- $iv = &$this->encryptIV;
776
- $pos = &$this->enbuffer['pos'];
777
- } else {
778
- $iv = $this->encryptIV;
779
- $pos = 0;
780
- }
781
- $len = strlen($plaintext);
782
- $i = 0;
783
- if ($pos) {
784
- $orig_pos = $pos;
785
- $max = $this->block_size - $pos;
786
- if ($len >= $max) {
787
- $i = $max;
788
- $len-= $max;
789
- $pos = 0;
790
- } else {
791
- $i = $len;
792
- $pos+= $len;
793
- $len = 0;
794
- }
795
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
796
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
797
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
798
- $plaintext = substr($plaintext, $i);
799
- }
800
-
801
- $overflow = $len % $this->block_size;
802
-
803
- if ($overflow) {
804
- $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
805
- $iv = $this->_string_pop($ciphertext, $this->block_size);
806
-
807
- $size = $len - $overflow;
808
- $block = $iv ^ substr($plaintext, -$overflow);
809
- $iv = substr_replace($iv, $block, 0, $overflow);
810
- $ciphertext.= $block;
811
- $pos = $overflow;
812
- } elseif ($len) {
813
- $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
814
- $iv = substr($ciphertext, -$this->block_size);
815
- }
816
-
817
- return $ciphertext;
818
- case CRYPT_MODE_OFB:
819
- return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
820
- }
821
- }
822
-
823
- if ($this->engine === CRYPT_ENGINE_MCRYPT) {
824
- if ($this->changed) {
825
- $this->_setupMcrypt();
826
- $this->changed = false;
827
- }
828
- if ($this->enchanged) {
829
- @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
830
- $this->enchanged = false;
831
- }
832
-
833
- // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
834
- // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
835
- // rewritten CFB implementation the above outputs the same thing twice.
836
- if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
837
- $block_size = $this->block_size;
838
- $iv = &$this->encryptIV;
839
- $pos = &$this->enbuffer['pos'];
840
- $len = strlen($plaintext);
841
- $ciphertext = '';
842
- $i = 0;
843
- if ($pos) {
844
- $orig_pos = $pos;
845
- $max = $block_size - $pos;
846
- if ($len >= $max) {
847
- $i = $max;
848
- $len-= $max;
849
- $pos = 0;
850
- } else {
851
- $i = $len;
852
- $pos+= $len;
853
- $len = 0;
854
- }
855
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
856
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
857
- $this->enbuffer['enmcrypt_init'] = true;
858
- }
859
- if ($len >= $block_size) {
860
- if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
861
- if ($this->enbuffer['enmcrypt_init'] === true) {
862
- @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
863
- $this->enbuffer['enmcrypt_init'] = false;
864
- }
865
- $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
866
- $iv = substr($ciphertext, -$block_size);
867
- $len%= $block_size;
868
- } else {
869
- while ($len >= $block_size) {
870
- $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
871
- $ciphertext.= $iv;
872
- $len-= $block_size;
873
- $i+= $block_size;
874
- }
875
- }
876
- }
877
-
878
- if ($len) {
879
- $iv = @mcrypt_generic($this->ecb, $iv);
880
- $block = $iv ^ substr($plaintext, -$len);
881
- $iv = substr_replace($iv, $block, 0, $len);
882
- $ciphertext.= $block;
883
- $pos = $len;
884
- }
885
-
886
- return $ciphertext;
887
- }
888
-
889
- $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
890
-
891
- if (!$this->continuousBuffer) {
892
- @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
893
- }
894
-
895
- return $ciphertext;
896
- }
897
-
898
- if ($this->changed) {
899
- $this->_setup();
900
- $this->changed = false;
901
- }
902
- if ($this->use_inline_crypt) {
903
- $inline = $this->inline_crypt;
904
- return $inline('encrypt', $this, $plaintext);
905
- }
906
-
907
- $buffer = &$this->enbuffer;
908
- $block_size = $this->block_size;
909
- $ciphertext = '';
910
- switch ($this->mode) {
911
- case CRYPT_MODE_ECB:
912
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
913
- $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
914
- }
915
- break;
916
- case CRYPT_MODE_CBC:
917
- $xor = $this->encryptIV;
918
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
919
- $block = substr($plaintext, $i, $block_size);
920
- $block = $this->_encryptBlock($block ^ $xor);
921
- $xor = $block;
922
- $ciphertext.= $block;
923
- }
924
- if ($this->continuousBuffer) {
925
- $this->encryptIV = $xor;
926
- }
927
- break;
928
- case CRYPT_MODE_CTR:
929
- $xor = $this->encryptIV;
930
- if (strlen($buffer['ciphertext'])) {
931
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
932
- $block = substr($plaintext, $i, $block_size);
933
- if (strlen($block) > strlen($buffer['ciphertext'])) {
934
- $buffer['ciphertext'].= $this->_encryptBlock($xor);
935
- }
936
- $this->_increment_str($xor);
937
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
938
- $ciphertext.= $block ^ $key;
939
- }
940
- } else {
941
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
942
- $block = substr($plaintext, $i, $block_size);
943
- $key = $this->_encryptBlock($xor);
944
- $this->_increment_str($xor);
945
- $ciphertext.= $block ^ $key;
946
- }
947
- }
948
- if ($this->continuousBuffer) {
949
- $this->encryptIV = $xor;
950
- if ($start = strlen($plaintext) % $block_size) {
951
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
952
- }
953
- }
954
- break;
955
- case CRYPT_MODE_CFB:
956
- // cfb loosely routines inspired by openssl's:
957
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
958
- if ($this->continuousBuffer) {
959
- $iv = &$this->encryptIV;
960
- $pos = &$buffer['pos'];
961
- } else {
962
- $iv = $this->encryptIV;
963
- $pos = 0;
964
- }
965
- $len = strlen($plaintext);
966
- $i = 0;
967
- if ($pos) {
968
- $orig_pos = $pos;
969
- $max = $block_size - $pos;
970
- if ($len >= $max) {
971
- $i = $max;
972
- $len-= $max;
973
- $pos = 0;
974
- } else {
975
- $i = $len;
976
- $pos+= $len;
977
- $len = 0;
978
- }
979
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
980
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
981
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
982
- }
983
- while ($len >= $block_size) {
984
- $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
985
- $ciphertext.= $iv;
986
- $len-= $block_size;
987
- $i+= $block_size;
988
- }
989
- if ($len) {
990
- $iv = $this->_encryptBlock($iv);
991
- $block = $iv ^ substr($plaintext, $i);
992
- $iv = substr_replace($iv, $block, 0, $len);
993
- $ciphertext.= $block;
994
- $pos = $len;
995
- }
996
- break;
997
- case CRYPT_MODE_OFB:
998
- $xor = $this->encryptIV;
999
- if (strlen($buffer['xor'])) {
1000
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1001
- $block = substr($plaintext, $i, $block_size);
1002
- if (strlen($block) > strlen($buffer['xor'])) {
1003
- $xor = $this->_encryptBlock($xor);
1004
- $buffer['xor'].= $xor;
1005
- }
1006
- $key = $this->_string_shift($buffer['xor'], $block_size);
1007
- $ciphertext.= $block ^ $key;
1008
- }
1009
- } else {
1010
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1011
- $xor = $this->_encryptBlock($xor);
1012
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
1013
- }
1014
- $key = $xor;
1015
- }
1016
- if ($this->continuousBuffer) {
1017
- $this->encryptIV = $xor;
1018
- if ($start = strlen($plaintext) % $block_size) {
1019
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1020
- }
1021
- }
1022
- break;
1023
- case CRYPT_MODE_STREAM:
1024
- $ciphertext = $this->_encryptBlock($plaintext);
1025
- break;
1026
- }
1027
-
1028
- return $ciphertext;
1029
- }
1030
-
1031
- /**
1032
- * Decrypts a message.
1033
- *
1034
- * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1035
- * it is.
1036
- *
1037
- * @see self::encrypt()
1038
- * @access public
1039
- * @param string $ciphertext
1040
- * @return string $plaintext
1041
- * @internal Could, but not must, extend by the child Crypt_* class
1042
- */
1043
- function decrypt($ciphertext)
1044
- {
1045
- if ($this->paddable) {
1046
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
1047
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1048
- $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
1049
- }
1050
-
1051
- if ($this->engine === CRYPT_ENGINE_OPENSSL) {
1052
- if ($this->changed) {
1053
- $this->_clearBuffers();
1054
- $this->changed = false;
1055
- }
1056
- switch ($this->mode) {
1057
- case CRYPT_MODE_STREAM:
1058
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1059
- break;
1060
- case CRYPT_MODE_ECB:
1061
- if (!defined('OPENSSL_RAW_DATA')) {
1062
- $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1063
- }
1064
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1065
- break;
1066
- case CRYPT_MODE_CBC:
1067
- if (!defined('OPENSSL_RAW_DATA')) {
1068
- $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1069
- $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1070
- $offset = 2 * $this->block_size;
1071
- } else {
1072
- $offset = $this->block_size;
1073
- }
1074
- $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1075
- if ($this->continuousBuffer) {
1076
- $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1077
- }
1078
- break;
1079
- case CRYPT_MODE_CTR:
1080
- $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1081
- break;
1082
- case CRYPT_MODE_CFB:
1083
- // cfb loosely routines inspired by openssl's:
1084
- // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1085
- $plaintext = '';
1086
- if ($this->continuousBuffer) {
1087
- $iv = &$this->decryptIV;
1088
- $pos = &$this->buffer['pos'];
1089
- } else {
1090
- $iv = $this->decryptIV;
1091
- $pos = 0;
1092
- }
1093
- $len = strlen($ciphertext);
1094
- $i = 0;
1095
- if ($pos) {
1096
- $orig_pos = $pos;
1097
- $max = $this->block_size - $pos;
1098
- if ($len >= $max) {
1099
- $i = $max;
1100
- $len-= $max;
1101
- $pos = 0;
1102
- } else {
1103
- $i = $len;
1104
- $pos+= $len;
1105
- $len = 0;
1106
- }
1107
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1108
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1109
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1110
- $ciphertext = substr($ciphertext, $i);
1111
- }
1112
- $overflow = $len % $this->block_size;
1113
- if ($overflow) {
1114
- $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1115
- if ($len - $overflow) {
1116
- $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1117
- }
1118
- $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1119
- $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1120
- $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1121
- $pos = $overflow;
1122
- } elseif ($len) {
1123
- $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1124
- $iv = substr($ciphertext, -$this->block_size);
1125
- }
1126
- break;
1127
- case CRYPT_MODE_OFB:
1128
- $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1129
- }
1130
-
1131
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1132
- }
1133
-
1134
- if ($this->engine === CRYPT_ENGINE_MCRYPT) {
1135
- $block_size = $this->block_size;
1136
- if ($this->changed) {
1137
- $this->_setupMcrypt();
1138
- $this->changed = false;
1139
- }
1140
- if ($this->dechanged) {
1141
- @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1142
- $this->dechanged = false;
1143
- }
1144
-
1145
- if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
1146
- $iv = &$this->decryptIV;
1147
- $pos = &$this->debuffer['pos'];
1148
- $len = strlen($ciphertext);
1149
- $plaintext = '';
1150
- $i = 0;
1151
- if ($pos) {
1152
- $orig_pos = $pos;
1153
- $max = $block_size - $pos;
1154
- if ($len >= $max) {
1155
- $i = $max;
1156
- $len-= $max;
1157
- $pos = 0;
1158
- } else {
1159
- $i = $len;
1160
- $pos+= $len;
1161
- $len = 0;
1162
- }
1163
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1164
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1165
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1166
- }
1167
- if ($len >= $block_size) {
1168
- $cb = substr($ciphertext, $i, $len - $len % $block_size);
1169
- $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1170
- $iv = substr($cb, -$block_size);
1171
- $len%= $block_size;
1172
- }
1173
- if ($len) {
1174
- $iv = @mcrypt_generic($this->ecb, $iv);
1175
- $plaintext.= $iv ^ substr($ciphertext, -$len);
1176
- $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1177
- $pos = $len;
1178
- }
1179
-
1180
- return $plaintext;
1181
- }
1182
-
1183
- $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
1184
-
1185
- if (!$this->continuousBuffer) {
1186
- @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1187
- }
1188
-
1189
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1190
- }
1191
-
1192
- if ($this->changed) {
1193
- $this->_setup();
1194
- $this->changed = false;
1195
- }
1196
- if ($this->use_inline_crypt) {
1197
- $inline = $this->inline_crypt;
1198
- return $inline('decrypt', $this, $ciphertext);
1199
- }
1200
-
1201
- $block_size = $this->block_size;
1202
-
1203
- $buffer = &$this->debuffer;
1204
- $plaintext = '';
1205
- switch ($this->mode) {
1206
- case CRYPT_MODE_ECB:
1207
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1208
- $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1209
- }
1210
- break;
1211
- case CRYPT_MODE_CBC:
1212
- $xor = $this->decryptIV;
1213
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1214
- $block = substr($ciphertext, $i, $block_size);
1215
- $plaintext.= $this->_decryptBlock($block) ^ $xor;
1216
- $xor = $block;
1217
- }
1218
- if ($this->continuousBuffer) {
1219
- $this->decryptIV = $xor;
1220
- }
1221
- break;
1222
- case CRYPT_MODE_CTR:
1223
- $xor = $this->decryptIV;
1224
- if (strlen($buffer['ciphertext'])) {
1225
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1226
- $block = substr($ciphertext, $i, $block_size);
1227
- if (strlen($block) > strlen($buffer['ciphertext'])) {
1228
- $buffer['ciphertext'].= $this->_encryptBlock($xor);
1229
- $this->_increment_str($xor);
1230
- }
1231
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1232
- $plaintext.= $block ^ $key;
1233
- }
1234
- } else {
1235
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1236
- $block = substr($ciphertext, $i, $block_size);
1237
- $key = $this->_encryptBlock($xor);
1238
- $this->_increment_str($xor);
1239
- $plaintext.= $block ^ $key;
1240
- }
1241
- }
1242
- if ($this->continuousBuffer) {
1243
- $this->decryptIV = $xor;
1244
- if ($start = strlen($ciphertext) % $block_size) {
1245
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1246
- }
1247
- }
1248
- break;
1249
- case CRYPT_MODE_CFB:
1250
- if ($this->continuousBuffer) {
1251
- $iv = &$this->decryptIV;
1252
- $pos = &$buffer['pos'];
1253
- } else {
1254
- $iv = $this->decryptIV;
1255
- $pos = 0;
1256
- }
1257
- $len = strlen($ciphertext);
1258
- $i = 0;
1259
- if ($pos) {
1260
- $orig_pos = $pos;
1261
- $max = $block_size - $pos;
1262
- if ($len >= $max) {
1263
- $i = $max;
1264
- $len-= $max;
1265
- $pos = 0;
1266
- } else {
1267
- $i = $len;
1268
- $pos+= $len;
1269
- $len = 0;
1270
- }
1271
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1272
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1273
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1274
- }
1275
- while ($len >= $block_size) {
1276
- $iv = $this->_encryptBlock($iv);
1277
- $cb = substr($ciphertext, $i, $block_size);
1278
- $plaintext.= $iv ^ $cb;
1279
- $iv = $cb;
1280
- $len-= $block_size;
1281
- $i+= $block_size;
1282
- }
1283
- if ($len) {
1284
- $iv = $this->_encryptBlock($iv);
1285
- $plaintext.= $iv ^ substr($ciphertext, $i);
1286
- $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1287
- $pos = $len;
1288
- }
1289
- break;
1290
- case CRYPT_MODE_OFB:
1291
- $xor = $this->decryptIV;
1292
- if (strlen($buffer['xor'])) {
1293
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1294
- $block = substr($ciphertext, $i, $block_size);
1295
- if (strlen($block) > strlen($buffer['xor'])) {
1296
- $xor = $this->_encryptBlock($xor);
1297
- $buffer['xor'].= $xor;
1298
- }
1299
- $key = $this->_string_shift($buffer['xor'], $block_size);
1300
- $plaintext.= $block ^ $key;
1301
- }
1302
- } else {
1303
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1304
- $xor = $this->_encryptBlock($xor);
1305
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1306
- }
1307
- $key = $xor;
1308
- }
1309
- if ($this->continuousBuffer) {
1310
- $this->decryptIV = $xor;
1311
- if ($start = strlen($ciphertext) % $block_size) {
1312
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1313
- }
1314
- }
1315
- break;
1316
- case CRYPT_MODE_STREAM:
1317
- $plaintext = $this->_decryptBlock($ciphertext);
1318
- break;
1319
- }
1320
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1321
- }
1322
-
1323
- /**
1324
- * OpenSSL CTR Processor
1325
- *
1326
- * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1327
- * for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1328
- * and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1329
- * function will emulate CTR with ECB when necessary.
1330
- *
1331
- * @see self::encrypt()
1332
- * @see self::decrypt()
1333
- * @param string $plaintext
1334
- * @param string $encryptIV
1335
- * @param array $buffer
1336
- * @return string
1337
- * @access private
1338
- */
1339
- function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1340
- {
1341
- $ciphertext = '';
1342
-
1343
- $block_size = $this->block_size;
1344
- $key = $this->key;
1345
-
1346
- if ($this->openssl_emulate_ctr) {
1347
- $xor = $encryptIV;
1348
- if (strlen($buffer['ciphertext'])) {
1349
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1350
- $block = substr($plaintext, $i, $block_size);
1351
- if (strlen($block) > strlen($buffer['ciphertext'])) {
1352
- $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1353
- $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1354
- $buffer['ciphertext'].= $result;
1355
- }
1356
- $this->_increment_str($xor);
1357
- $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1358
- $ciphertext.= $block ^ $otp;
1359
- }
1360
- } else {
1361
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1362
- $block = substr($plaintext, $i, $block_size);
1363
- $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1364
- $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1365
- $this->_increment_str($xor);
1366
- $ciphertext.= $block ^ $otp;
1367
- }
1368
- }
1369
- if ($this->continuousBuffer) {
1370
- $encryptIV = $xor;
1371
- if ($start = strlen($plaintext) % $block_size) {
1372
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1373
- }
1374
- }
1375
-
1376
- return $ciphertext;
1377
- }
1378
-
1379
- if (strlen($buffer['ciphertext'])) {
1380
- $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1381
- $plaintext = substr($plaintext, strlen($ciphertext));
1382
-
1383
- if (!strlen($plaintext)) {
1384
- return $ciphertext;
1385
- }
1386
- }
1387
-
1388
- $overflow = strlen($plaintext) % $block_size;
1389
- if ($overflow) {
1390
- $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1391
- $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1392
- $temp = $this->_string_pop($encrypted, $block_size);
1393
- $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1394
- if ($this->continuousBuffer) {
1395
- $buffer['ciphertext'] = substr($temp, $overflow);
1396
- $encryptIV = $temp;
1397
- }
1398
- } elseif (!strlen($buffer['ciphertext'])) {
1399
- $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1400
- $temp = $this->_string_pop($ciphertext, $block_size);
1401
- if ($this->continuousBuffer) {
1402
- $encryptIV = $temp;
1403
- }
1404
- }
1405
- if ($this->continuousBuffer) {
1406
- if (!defined('OPENSSL_RAW_DATA')) {
1407
- $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1408
- }
1409
- $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1410
- if ($overflow) {
1411
- $this->_increment_str($encryptIV);
1412
- }
1413
- }
1414
-
1415
- return $ciphertext;
1416
- }
1417
-
1418
- /**
1419
- * OpenSSL OFB Processor
1420
- *
1421
- * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1422
- * for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1423
- * and Crypt_Base::decrypt().
1424
- *
1425
- * @see self::encrypt()
1426
- * @see self::decrypt()
1427
- * @param string $plaintext
1428
- * @param string $encryptIV
1429
- * @param array $buffer
1430
- * @return string
1431
- * @access private
1432
- */
1433
- function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1434
- {
1435
- if (strlen($buffer['xor'])) {
1436
- $ciphertext = $plaintext ^ $buffer['xor'];
1437
- $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1438
- $plaintext = substr($plaintext, strlen($ciphertext));
1439
- } else {
1440
- $ciphertext = '';
1441
- }
1442
-
1443
- $block_size = $this->block_size;
1444
-
1445
- $len = strlen($plaintext);
1446
- $key = $this->key;
1447
- $overflow = $len % $block_size;
1448
-
1449
- if (strlen($plaintext)) {
1450
- if ($overflow) {
1451
- $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1452
- $xor = $this->_string_pop($ciphertext, $block_size);
1453
- if ($this->continuousBuffer) {
1454
- $encryptIV = $xor;
1455
- }
1456
- $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1457
- if ($this->continuousBuffer) {
1458
- $buffer['xor'] = $xor;
1459
- }
1460
- } else {
1461
- $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1462
- if ($this->continuousBuffer) {
1463
- $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1464
- }
1465
- }
1466
- }
1467
-
1468
- return $ciphertext;
1469
- }
1470
-
1471
- /**
1472
- * phpseclib <-> OpenSSL Mode Mapper
1473
- *
1474
- * May need to be overwritten by classes extending this one in some cases
1475
- *
1476
- * @return int
1477
- * @access private
1478
- */
1479
- function _openssl_translate_mode()
1480
- {
1481
- switch ($this->mode) {
1482
- case CRYPT_MODE_ECB:
1483
- return 'ecb';
1484
- case CRYPT_MODE_CBC:
1485
- return 'cbc';
1486
- case CRYPT_MODE_CTR:
1487
- return 'ctr';
1488
- case CRYPT_MODE_CFB:
1489
- return 'cfb';
1490
- case CRYPT_MODE_OFB:
1491
- return 'ofb';
1492
- }
1493
- }
1494
-
1495
- /**
1496
- * Pad "packets".
1497
- *
1498
- * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1499
- * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1500
- * pad the input so that it is of the proper length.
1501
- *
1502
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1503
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1504
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1505
- * transmitted separately)
1506
- *
1507
- * @see self::disablePadding()
1508
- * @access public
1509
- */
1510
- function enablePadding()
1511
- {
1512
- $this->padding = true;
1513
- }
1514
-
1515
- /**
1516
- * Do not pad packets.
1517
- *
1518
- * @see self::enablePadding()
1519
- * @access public
1520
- */
1521
- function disablePadding()
1522
- {
1523
- $this->padding = false;
1524
- }
1525
-
1526
- /**
1527
- * Treat consecutive "packets" as if they are a continuous buffer.
1528
- *
1529
- * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1530
- * will yield different outputs:
1531
- *
1532
- * <code>
1533
- * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1534
- * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1535
- * </code>
1536
- * <code>
1537
- * echo $rijndael->encrypt($plaintext);
1538
- * </code>
1539
- *
1540
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1541
- * another, as demonstrated with the following:
1542
- *
1543
- * <code>
1544
- * $rijndael->encrypt(substr($plaintext, 0, 16));
1545
- * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1546
- * </code>
1547
- * <code>
1548
- * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1549
- * </code>
1550
- *
1551
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1552
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1553
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1554
- *
1555
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
1556
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1557
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1558
- * however, they are also less intuitive and more likely to cause you problems.
1559
- *
1560
- * @see self::disableContinuousBuffer()
1561
- * @access public
1562
- * @internal Could, but not must, extend by the child Crypt_* class
1563
- */
1564
- function enableContinuousBuffer()
1565
- {
1566
- if ($this->mode == CRYPT_MODE_ECB) {
1567
- return;
1568
- }
1569
-
1570
- $this->continuousBuffer = true;
1571
-
1572
- $this->_setEngine();
1573
- }
1574
-
1575
- /**
1576
- * Treat consecutive packets as if they are a discontinuous buffer.
1577
- *
1578
- * The default behavior.
1579
- *
1580
- * @see self::enableContinuousBuffer()
1581
- * @access public
1582
- * @internal Could, but not must, extend by the child Crypt_* class
1583
- */
1584
- function disableContinuousBuffer()
1585
- {
1586
- if ($this->mode == CRYPT_MODE_ECB) {
1587
- return;
1588
- }
1589
- if (!$this->continuousBuffer) {
1590
- return;
1591
- }
1592
-
1593
- $this->continuousBuffer = false;
1594
- $this->changed = true;
1595
-
1596
- $this->_setEngine();
1597
- }
1598
-
1599
- /**
1600
- * Test for engine validity
1601
- *
1602
- * @see self::Crypt_Base()
1603
- * @param int $engine
1604
- * @access public
1605
- * @return bool
1606
- */
1607
- function isValidEngine($engine)
1608
- {
1609
- switch ($engine) {
1610
- case CRYPT_ENGINE_OPENSSL:
1611
- if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) {
1612
- return false;
1613
- }
1614
- $this->openssl_emulate_ctr = false;
1615
- $result = $this->cipher_name_openssl &&
1616
- extension_loaded('openssl') &&
1617
- // PHP 5.3.0 - 5.3.2 did not let you set IV's
1618
- version_compare(PHP_VERSION, '5.3.3', '>=');
1619
- if (!$result) {
1620
- return false;
1621
- }
1622
-
1623
- // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1624
- // $options openssl_encrypt expected a boolean $raw_data.
1625
- if (!defined('OPENSSL_RAW_DATA')) {
1626
- $this->openssl_options = true;
1627
- } else {
1628
- $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1629
- }
1630
-
1631
- $methods = openssl_get_cipher_methods();
1632
- if (in_array($this->cipher_name_openssl, $methods)) {
1633
- return true;
1634
- }
1635
- // not all of openssl's symmetric cipher's support ctr. for those
1636
- // that don't we'll emulate it
1637
- switch ($this->mode) {
1638
- case CRYPT_MODE_CTR:
1639
- if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1640
- $this->openssl_emulate_ctr = true;
1641
- return true;
1642
- }
1643
- }
1644
- return false;
1645
- case CRYPT_ENGINE_MCRYPT:
1646
- return $this->cipher_name_mcrypt &&
1647
- extension_loaded('mcrypt') &&
1648
- in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
1649
- case CRYPT_ENGINE_INTERNAL:
1650
- return true;
1651
- }
1652
-
1653
- return false;
1654
- }
1655
-
1656
- /**
1657
- * Sets the preferred crypt engine
1658
- *
1659
- * Currently, $engine could be:
1660
- *
1661
- * - CRYPT_ENGINE_OPENSSL [very fast]
1662
- *
1663
- * - CRYPT_ENGINE_MCRYPT [fast]
1664
- *
1665
- * - CRYPT_ENGINE_INTERNAL [slow]
1666
- *
1667
- * If the preferred crypt engine is not available the fastest available one will be used
1668
- *
1669
- * @see self::Crypt_Base()
1670
- * @param int $engine
1671
- * @access public
1672
- */
1673
- function setPreferredEngine($engine)
1674
- {
1675
- switch ($engine) {
1676
- //case CRYPT_ENGINE_OPENSSL:
1677
- case CRYPT_ENGINE_MCRYPT:
1678
- case CRYPT_ENGINE_INTERNAL:
1679
- $this->preferredEngine = $engine;
1680
- break;
1681
- default:
1682
- $this->preferredEngine = CRYPT_ENGINE_OPENSSL;
1683
- }
1684
-
1685
- $this->_setEngine();
1686
- }
1687
-
1688
- /**
1689
- * Returns the engine currently being utilized
1690
- *
1691
- * @see self::_setEngine()
1692
- * @access public
1693
- */
1694
- function getEngine()
1695
- {
1696
- return $this->engine;
1697
- }
1698
-
1699
- /**
1700
- * Sets the engine as appropriate
1701
- *
1702
- * @see self::Crypt_Base()
1703
- * @access private
1704
- */
1705
- function _setEngine()
1706
- {
1707
- $this->engine = null;
1708
-
1709
- $candidateEngines = array(
1710
- $this->preferredEngine,
1711
- CRYPT_ENGINE_OPENSSL,
1712
- CRYPT_ENGINE_MCRYPT
1713
- );
1714
- foreach ($candidateEngines as $engine) {
1715
- if ($this->isValidEngine($engine)) {
1716
- $this->engine = $engine;
1717
- break;
1718
- }
1719
- }
1720
- if (!$this->engine) {
1721
- $this->engine = CRYPT_ENGINE_INTERNAL;
1722
- }
1723
-
1724
- if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) {
1725
- // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1726
- // (re)open them with the module named in $this->cipher_name_mcrypt
1727
- @mcrypt_module_close($this->enmcrypt);
1728
- @mcrypt_module_close($this->demcrypt);
1729
- $this->enmcrypt = null;
1730
- $this->demcrypt = null;
1731
-
1732
- if ($this->ecb) {
1733
- @mcrypt_module_close($this->ecb);
1734
- $this->ecb = null;
1735
- }
1736
- }
1737
-
1738
- $this->changed = true;
1739
- }
1740
-
1741
- /**
1742
- * Encrypts a block
1743
- *
1744
- * @access private
1745
- * @param string $in
1746
- * @return string
1747
- * @internal Must be extended by the child Crypt_* class
1748
- */
1749
- function _encryptBlock($in)
1750
- {
1751
- user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1752
- }
1753
-
1754
- /**
1755
- * Decrypts a block
1756
- *
1757
- * @access private
1758
- * @param string $in
1759
- * @return string
1760
- * @internal Must be extended by the child Crypt_* class
1761
- */
1762
- function _decryptBlock($in)
1763
- {
1764
- user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1765
- }
1766
-
1767
- /**
1768
- * Setup the key (expansion)
1769
- *
1770
- * Only used if $engine == CRYPT_ENGINE_INTERNAL
1771
- *
1772
- * @see self::_setup()
1773
- * @access private
1774
- * @internal Must be extended by the child Crypt_* class
1775
- */
1776
- function _setupKey()
1777
- {
1778
- user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1779
- }
1780
-
1781
- /**
1782
- * Setup the CRYPT_ENGINE_INTERNAL $engine
1783
- *
1784
- * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1785
- * Used (only) if $engine == CRYPT_ENGINE_INTERNAL
1786
- *
1787
- * _setup() will be called each time if $changed === true
1788
- * typically this happens when using one or more of following public methods:
1789
- *
1790
- * - setKey()
1791
- *
1792
- * - setIV()
1793
- *
1794
- * - disableContinuousBuffer()
1795
- *
1796
- * - First run of encrypt() / decrypt() with no init-settings
1797
- *
1798
- * @see self::setKey()
1799
- * @see self::setIV()
1800
- * @see self::disableContinuousBuffer()
1801
- * @access private
1802
- * @internal _setup() is always called before en/decryption.
1803
- * @internal Could, but not must, extend by the child Crypt_* class
1804
- */
1805
- function _setup()
1806
- {
1807
- $this->_clearBuffers();
1808
- $this->_setupKey();
1809
-
1810
- if ($this->use_inline_crypt) {
1811
- $this->_setupInlineCrypt();
1812
- }
1813
- }
1814
-
1815
- /**
1816
- * Setup the CRYPT_ENGINE_MCRYPT $engine
1817
- *
1818
- * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1819
- * Used (only) if $engine = CRYPT_ENGINE_MCRYPT
1820
- *
1821
- * _setupMcrypt() will be called each time if $changed === true
1822
- * typically this happens when using one or more of following public methods:
1823
- *
1824
- * - setKey()
1825
- *
1826
- * - setIV()
1827
- *
1828
- * - disableContinuousBuffer()
1829
- *
1830
- * - First run of encrypt() / decrypt()
1831
- *
1832
- * @see self::setKey()
1833
- * @see self::setIV()
1834
- * @see self::disableContinuousBuffer()
1835
- * @access private
1836
- * @internal Could, but not must, extend by the child Crypt_* class
1837
- */
1838
- function _setupMcrypt()
1839
- {
1840
- $this->_clearBuffers();
1841
- $this->enchanged = $this->dechanged = true;
1842
-
1843
- if (!isset($this->enmcrypt)) {
1844
- static $mcrypt_modes = array(
1845
- CRYPT_MODE_CTR => 'ctr',
1846
- CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
1847
- CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
1848
- CRYPT_MODE_CFB => 'ncfb',
1849
- CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
1850
- CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
1851
- );
1852
-
1853
- $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1854
- $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1855
-
1856
- // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1857
- // to workaround mcrypt's broken ncfb implementation in buffered mode
1858
- // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1859
- if ($this->mode == CRYPT_MODE_CFB) {
1860
- $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1861
- }
1862
- } // else should mcrypt_generic_deinit be called?
1863
-
1864
- if ($this->mode == CRYPT_MODE_CFB) {
1865
- @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1866
- }
1867
- }
1868
-
1869
- /**
1870
- * Pads a string
1871
- *
1872
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1873
- * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1874
- * chr($this->block_size - (strlen($text) % $this->block_size)
1875
- *
1876
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1877
- * and padding will, hence forth, be enabled.
1878
- *
1879
- * @see self::_unpad()
1880
- * @param string $text
1881
- * @access private
1882
- * @return string
1883
- */
1884
- function _pad($text)
1885
- {
1886
- $length = strlen($text);
1887
-
1888
- if (!$this->padding) {
1889
- if ($length % $this->block_size == 0) {
1890
- return $text;
1891
- } else {
1892
- user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1893
- $this->padding = true;
1894
- }
1895
- }
1896
-
1897
- $pad = $this->block_size - ($length % $this->block_size);
1898
-
1899
- return str_pad($text, $length + $pad, chr($pad));
1900
- }
1901
-
1902
- /**
1903
- * Unpads a string.
1904
- *
1905
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1906
- * and false will be returned.
1907
- *
1908
- * @see self::_pad()
1909
- * @param string $text
1910
- * @access private
1911
- * @return string
1912
- */
1913
- function _unpad($text)
1914
- {
1915
- if (!$this->padding) {
1916
- return $text;
1917
- }
1918
-
1919
- $length = ord($text[strlen($text) - 1]);
1920
-
1921
- if (!$length || $length > $this->block_size) {
1922
- return false;
1923
- }
1924
-
1925
- return substr($text, 0, -$length);
1926
- }
1927
-
1928
- /**
1929
- * Clears internal buffers
1930
- *
1931
- * Clearing/resetting the internal buffers is done everytime
1932
- * after disableContinuousBuffer() or on cipher $engine (re)init
1933
- * ie after setKey() or setIV()
1934
- *
1935
- * @access public
1936
- * @internal Could, but not must, extend by the child Crypt_* class
1937
- */
1938
- function _clearBuffers()
1939
- {
1940
- $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1941
-
1942
- // mcrypt's handling of invalid's $iv:
1943
- // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1944
- $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1945
-
1946
- if (!$this->skip_key_adjustment) {
1947
- $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1948
- }
1949
- }
1950
-
1951
- /**
1952
- * String Shift
1953
- *
1954
- * Inspired by array_shift
1955
- *
1956
- * @param string $string
1957
- * @param int $index
1958
- * @access private
1959
- * @return string
1960
- */
1961
- function _string_shift(&$string, $index = 1)
1962
- {
1963
- $substr = substr($string, 0, $index);
1964
- $string = substr($string, $index);
1965
- return $substr;
1966
- }
1967
-
1968
- /**
1969
- * String Pop
1970
- *
1971
- * Inspired by array_pop
1972
- *
1973
- * @param string $string
1974
- * @param int $index
1975
- * @access private
1976
- * @return string
1977
- */
1978
- function _string_pop(&$string, $index = 1)
1979
- {
1980
- $substr = substr($string, -$index);
1981
- $string = substr($string, 0, -$index);
1982
- return $substr;
1983
- }
1984
-
1985
- /**
1986
- * Increment the current string
1987
- *
1988
- * @see self::decrypt()
1989
- * @see self::encrypt()
1990
- * @param string $var
1991
- * @access private
1992
- */
1993
- function _increment_str(&$var)
1994
- {
1995
- for ($i = 4; $i <= strlen($var); $i+= 4) {
1996
- $temp = substr($var, -$i, 4);
1997
- switch ($temp) {
1998
- case "\xFF\xFF\xFF\xFF":
1999
- $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
2000
- break;
2001
- case "\x7F\xFF\xFF\xFF":
2002
- $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
2003
- return;
2004
- default:
2005
- $temp = unpack('Nnum', $temp);
2006
- $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
2007
- return;
2008
- }
2009
- }
2010
-
2011
- $remainder = strlen($var) % 4;
2012
-
2013
- if ($remainder == 0) {
2014
- return;
2015
- }
2016
-
2017
- $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
2018
- $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
2019
- $var = substr_replace($var, $temp, 0, $remainder);
2020
- }
2021
-
2022
- /**
2023
- * Setup the performance-optimized function for de/encrypt()
2024
- *
2025
- * Stores the created (or existing) callback function-name
2026
- * in $this->inline_crypt
2027
- *
2028
- * Internally for phpseclib developers:
2029
- *
2030
- * _setupInlineCrypt() would be called only if:
2031
- *
2032
- * - $engine == CRYPT_ENGINE_INTERNAL and
2033
- *
2034
- * - $use_inline_crypt === true
2035
- *
2036
- * - each time on _setup(), after(!) _setupKey()
2037
- *
2038
- *
2039
- * This ensures that _setupInlineCrypt() has always a
2040
- * full ready2go initializated internal cipher $engine state
2041
- * where, for example, the keys allready expanded,
2042
- * keys/block_size calculated and such.
2043
- *
2044
- * It is, each time if called, the responsibility of _setupInlineCrypt():
2045
- *
2046
- * - to set $this->inline_crypt to a valid and fully working callback function
2047
- * as a (faster) replacement for encrypt() / decrypt()
2048
- *
2049
- * - NOT to create unlimited callback functions (for memory reasons!)
2050
- * no matter how often _setupInlineCrypt() would be called. At some
2051
- * point of amount they must be generic re-useable.
2052
- *
2053
- * - the code of _setupInlineCrypt() it self,
2054
- * and the generated callback code,
2055
- * must be, in following order:
2056
- * - 100% safe
2057
- * - 100% compatible to encrypt()/decrypt()
2058
- * - using only php5+ features/lang-constructs/php-extensions if
2059
- * compatibility (down to php4) or fallback is provided
2060
- * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2061
- * - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2062
- * the reason for the existence of _setupInlineCrypt() :-)]
2063
- * - memory-nice
2064
- * - short (as good as possible)
2065
- *
2066
- * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2067
- * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
2068
- * - The following variable names are reserved:
2069
- * - $_* (all variable names prefixed with an underscore)
2070
- * - $self (object reference to it self. Do not use $this, but $self instead)
2071
- * - $in (the content of $in has to en/decrypt by the generated code)
2072
- * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2073
- *
2074
- *
2075
- * @see self::_setup()
2076
- * @see self::_createInlineCryptFunction()
2077
- * @see self::encrypt()
2078
- * @see self::decrypt()
2079
- * @access private
2080
- * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2081
- */
2082
- function _setupInlineCrypt()
2083
- {
2084
- // If, for any reason, an extending Crypt_Base() Crypt_* class
2085
- // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2086
- // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
2087
- // in the constructor at object instance-time
2088
- // or, if it's runtime-specific, at runtime
2089
-
2090
- $this->use_inline_crypt = false;
2091
- }
2092
-
2093
- /**
2094
- * Creates the performance-optimized function for en/decrypt()
2095
- *
2096
- * Internally for phpseclib developers:
2097
- *
2098
- * _createInlineCryptFunction():
2099
- *
2100
- * - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2101
- * with the current [$this->]mode of operation code
2102
- *
2103
- * - create the $inline function, which called by encrypt() / decrypt()
2104
- * as its replacement to speed up the en/decryption operations.
2105
- *
2106
- * - return the name of the created $inline callback function
2107
- *
2108
- * - used to speed up en/decryption
2109
- *
2110
- *
2111
- *
2112
- * The main reason why can speed up things [up to 50%] this way are:
2113
- *
2114
- * - using variables more effective then regular.
2115
- * (ie no use of expensive arrays but integers $k_0, $k_1 ...
2116
- * or even, for example, the pure $key[] values hardcoded)
2117
- *
2118
- * - avoiding 1000's of function calls of ie _encryptBlock()
2119
- * but inlining the crypt operations.
2120
- * in the mode of operation for() loop.
2121
- *
2122
- * - full loop unroll the (sometimes key-dependent) rounds
2123
- * avoiding this way ++$i counters and runtime-if's etc...
2124
- *
2125
- * The basic code architectur of the generated $inline en/decrypt()
2126
- * lambda function, in pseudo php, is:
2127
- *
2128
- * <code>
2129
- * +----------------------------------------------------------------------------------------------+
2130
- * | callback $inline = create_function: |
2131
- * | lambda_function_0001_crypt_ECB($action, $text) |
2132
- * | { |
2133
- * | INSERT PHP CODE OF: |
2134
- * | $cipher_code['init_crypt']; // general init code. |
2135
- * | // ie: $sbox'es declarations used for |
2136
- * | // encrypt and decrypt'ing. |
2137
- * | |
2138
- * | switch ($action) { |
2139
- * | case 'encrypt': |
2140
- * | INSERT PHP CODE OF: |
2141
- * | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
2142
- * | ie: specified $key or $box |
2143
- * | declarations for encrypt'ing. |
2144
- * | |
2145
- * | foreach ($ciphertext) { |
2146
- * | $in = $block_size of $ciphertext; |
2147
- * | |
2148
- * | INSERT PHP CODE OF: |
2149
- * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
2150
- * | // strlen($in) == $this->block_size |
2151
- * | // here comes the cipher algorithm in action |
2152
- * | // for encryption. |
2153
- * | // $cipher_code['encrypt_block'] has to |
2154
- * | // encrypt the content of the $in variable |
2155
- * | |
2156
- * | $plaintext .= $in; |
2157
- * | } |
2158
- * | return $plaintext; |
2159
- * | |
2160
- * | case 'decrypt': |
2161
- * | INSERT PHP CODE OF: |
2162
- * | $cipher_code['init_decrypt']; // decrypt sepcific init code |
2163
- * | ie: specified $key or $box |
2164
- * | declarations for decrypt'ing. |
2165
- * | foreach ($plaintext) { |
2166
- * | $in = $block_size of $plaintext; |
2167
- * | |
2168
- * | INSERT PHP CODE OF: |
2169
- * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
2170
- * | // strlen($in) == $this->block_size |
2171
- * | // here comes the cipher algorithm in action |
2172
- * | // for decryption. |
2173
- * | // $cipher_code['decrypt_block'] has to |
2174
- * | // decrypt the content of the $in variable |
2175
- * | $ciphertext .= $in; |
2176
- * | } |
2177
- * | return $ciphertext; |
2178
- * | } |
2179
- * | } |
2180
- * +----------------------------------------------------------------------------------------------+
2181
- * </code>
2182
- *
2183
- * See also the Crypt_*::_setupInlineCrypt()'s for
2184
- * productive inline $cipher_code's how they works.
2185
- *
2186
- * Structure of:
2187
- * <code>
2188
- * $cipher_code = array(
2189
- * 'init_crypt' => (string) '', // optional
2190
- * 'init_encrypt' => (string) '', // optional
2191
- * 'init_decrypt' => (string) '', // optional
2192
- * 'encrypt_block' => (string) '', // required
2193
- * 'decrypt_block' => (string) '' // required
2194
- * );
2195
- * </code>
2196
- *
2197
- * @see self::_setupInlineCrypt()
2198
- * @see self::encrypt()
2199
- * @see self::decrypt()
2200
- * @param array $cipher_code
2201
- * @access private
2202
- * @return string (the name of the created callback function)
2203
- */
2204
- function _createInlineCryptFunction($cipher_code)
2205
- {
2206
- $block_size = $this->block_size;
2207
-
2208
- // optional
2209
- $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
2210
- $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
2211
- $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
2212
- // required
2213
- $encrypt_block = $cipher_code['encrypt_block'];
2214
- $decrypt_block = $cipher_code['decrypt_block'];
2215
-
2216
- // Generating mode of operation inline code,
2217
- // merged with the $cipher_code algorithm
2218
- // for encrypt- and decryption.
2219
- switch ($this->mode) {
2220
- case CRYPT_MODE_ECB:
2221
- $encrypt = $init_encrypt . '
2222
- $_ciphertext = "";
2223
- $_plaintext_len = strlen($_text);
2224
-
2225
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2226
- $in = substr($_text, $_i, '.$block_size.');
2227
- '.$encrypt_block.'
2228
- $_ciphertext.= $in;
2229
- }
2230
-
2231
- return $_ciphertext;
2232
- ';
2233
-
2234
- $decrypt = $init_decrypt . '
2235
- $_plaintext = "";
2236
- $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2237
- $_ciphertext_len = strlen($_text);
2238
-
2239
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2240
- $in = substr($_text, $_i, '.$block_size.');
2241
- '.$decrypt_block.'
2242
- $_plaintext.= $in;
2243
- }
2244
-
2245
- return $self->_unpad($_plaintext);
2246
- ';
2247
- break;
2248
- case CRYPT_MODE_CTR:
2249
- $encrypt = $init_encrypt . '
2250
- $_ciphertext = "";
2251
- $_plaintext_len = strlen($_text);
2252
- $_xor = $self->encryptIV;
2253
- $_buffer = &$self->enbuffer;
2254
- if (strlen($_buffer["ciphertext"])) {
2255
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2256
- $_block = substr($_text, $_i, '.$block_size.');
2257
- if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2258
- $in = $_xor;
2259
- '.$encrypt_block.'
2260
- $self->_increment_str($_xor);
2261
- $_buffer["ciphertext"].= $in;
2262
- }
2263
- $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2264
- $_ciphertext.= $_block ^ $_key;
2265
- }
2266
- } else {
2267
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2268
- $_block = substr($_text, $_i, '.$block_size.');
2269
- $in = $_xor;
2270
- '.$encrypt_block.'
2271
- $self->_increment_str($_xor);
2272
- $_key = $in;
2273
- $_ciphertext.= $_block ^ $_key;
2274
- }
2275
- }
2276
- if ($self->continuousBuffer) {
2277
- $self->encryptIV = $_xor;
2278
- if ($_start = $_plaintext_len % '.$block_size.') {
2279
- $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2280
- }
2281
- }
2282
-
2283
- return $_ciphertext;
2284
- ';
2285
-
2286
- $decrypt = $init_encrypt . '
2287
- $_plaintext = "";
2288
- $_ciphertext_len = strlen($_text);
2289
- $_xor = $self->decryptIV;
2290
- $_buffer = &$self->debuffer;
2291
-
2292
- if (strlen($_buffer["ciphertext"])) {
2293
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2294
- $_block = substr($_text, $_i, '.$block_size.');
2295
- if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2296
- $in = $_xor;
2297
- '.$encrypt_block.'
2298
- $self->_increment_str($_xor);
2299
- $_buffer["ciphertext"].= $in;
2300
- }
2301
- $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2302
- $_plaintext.= $_block ^ $_key;
2303
- }
2304
- } else {
2305
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2306
- $_block = substr($_text, $_i, '.$block_size.');
2307
- $in = $_xor;
2308
- '.$encrypt_block.'
2309
- $self->_increment_str($_xor);
2310
- $_key = $in;
2311
- $_plaintext.= $_block ^ $_key;
2312
- }
2313
- }
2314
- if ($self->continuousBuffer) {
2315
- $self->decryptIV = $_xor;
2316
- if ($_start = $_ciphertext_len % '.$block_size.') {
2317
- $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2318
- }
2319
- }
2320
-
2321
- return $_plaintext;
2322
- ';
2323
- break;
2324
- case CRYPT_MODE_CFB:
2325
- $encrypt = $init_encrypt . '
2326
- $_ciphertext = "";
2327
- $_buffer = &$self->enbuffer;
2328
-
2329
- if ($self->continuousBuffer) {
2330
- $_iv = &$self->encryptIV;
2331
- $_pos = &$_buffer["pos"];
2332
- } else {
2333
- $_iv = $self->encryptIV;
2334
- $_pos = 0;
2335
- }
2336
- $_len = strlen($_text);
2337
- $_i = 0;
2338
- if ($_pos) {
2339
- $_orig_pos = $_pos;
2340
- $_max = '.$block_size.' - $_pos;
2341
- if ($_len >= $_max) {
2342
- $_i = $_max;
2343
- $_len-= $_max;
2344
- $_pos = 0;
2345
- } else {
2346
- $_i = $_len;
2347
- $_pos+= $_len;
2348
- $_len = 0;
2349
- }
2350
- $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2351
- $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2352
- }
2353
- while ($_len >= '.$block_size.') {
2354
- $in = $_iv;
2355
- '.$encrypt_block.';
2356
- $_iv = $in ^ substr($_text, $_i, '.$block_size.');
2357
- $_ciphertext.= $_iv;
2358
- $_len-= '.$block_size.';
2359
- $_i+= '.$block_size.';
2360
- }
2361
- if ($_len) {
2362
- $in = $_iv;
2363
- '.$encrypt_block.'
2364
- $_iv = $in;
2365
- $_block = $_iv ^ substr($_text, $_i);
2366
- $_iv = substr_replace($_iv, $_block, 0, $_len);
2367
- $_ciphertext.= $_block;
2368
- $_pos = $_len;
2369
- }
2370
- return $_ciphertext;
2371
- ';
2372
-
2373
- $decrypt = $init_encrypt . '
2374
- $_plaintext = "";
2375
- $_buffer = &$self->debuffer;
2376
-
2377
- if ($self->continuousBuffer) {
2378
- $_iv = &$self->decryptIV;
2379
- $_pos = &$_buffer["pos"];
2380
- } else {
2381
- $_iv = $self->decryptIV;
2382
- $_pos = 0;
2383
- }
2384
- $_len = strlen($_text);
2385
- $_i = 0;
2386
- if ($_pos) {
2387
- $_orig_pos = $_pos;
2388
- $_max = '.$block_size.' - $_pos;
2389
- if ($_len >= $_max) {
2390
- $_i = $_max;
2391
- $_len-= $_max;
2392
- $_pos = 0;
2393
- } else {
2394
- $_i = $_len;
2395
- $_pos+= $_len;
2396
- $_len = 0;
2397
- }
2398
- $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2399
- $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2400
- }
2401
- while ($_len >= '.$block_size.') {
2402
- $in = $_iv;
2403
- '.$encrypt_block.'
2404
- $_iv = $in;
2405
- $cb = substr($_text, $_i, '.$block_size.');
2406
- $_plaintext.= $_iv ^ $cb;
2407
- $_iv = $cb;
2408
- $_len-= '.$block_size.';
2409
- $_i+= '.$block_size.';
2410
- }
2411
- if ($_len) {
2412
- $in = $_iv;
2413
- '.$encrypt_block.'
2414
- $_iv = $in;
2415
- $_plaintext.= $_iv ^ substr($_text, $_i);
2416
- $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2417
- $_pos = $_len;
2418
- }
2419
-
2420
- return $_plaintext;
2421
- ';
2422
- break;
2423
- case CRYPT_MODE_OFB:
2424
- $encrypt = $init_encrypt . '
2425
- $_ciphertext = "";
2426
- $_plaintext_len = strlen($_text);
2427
- $_xor = $self->encryptIV;
2428
- $_buffer = &$self->enbuffer;
2429
-
2430
- if (strlen($_buffer["xor"])) {
2431
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2432
- $_block = substr($_text, $_i, '.$block_size.');
2433
- if (strlen($_block) > strlen($_buffer["xor"])) {
2434
- $in = $_xor;
2435
- '.$encrypt_block.'
2436
- $_xor = $in;
2437
- $_buffer["xor"].= $_xor;
2438
- }
2439
- $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2440
- $_ciphertext.= $_block ^ $_key;
2441
- }
2442
- } else {
2443
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2444
- $in = $_xor;
2445
- '.$encrypt_block.'
2446
- $_xor = $in;
2447
- $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2448
- }
2449
- $_key = $_xor;
2450
- }
2451
- if ($self->continuousBuffer) {
2452
- $self->encryptIV = $_xor;
2453
- if ($_start = $_plaintext_len % '.$block_size.') {
2454
- $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2455
- }
2456
- }
2457
- return $_ciphertext;
2458
- ';
2459
-
2460
- $decrypt = $init_encrypt . '
2461
- $_plaintext = "";
2462
- $_ciphertext_len = strlen($_text);
2463
- $_xor = $self->decryptIV;
2464
- $_buffer = &$self->debuffer;
2465
-
2466
- if (strlen($_buffer["xor"])) {
2467
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2468
- $_block = substr($_text, $_i, '.$block_size.');
2469
- if (strlen($_block) > strlen($_buffer["xor"])) {
2470
- $in = $_xor;
2471
- '.$encrypt_block.'
2472
- $_xor = $in;
2473
- $_buffer["xor"].= $_xor;
2474
- }
2475
- $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2476
- $_plaintext.= $_block ^ $_key;
2477
- }
2478
- } else {
2479
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2480
- $in = $_xor;
2481
- '.$encrypt_block.'
2482
- $_xor = $in;
2483
- $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2484
- }
2485
- $_key = $_xor;
2486
- }
2487
- if ($self->continuousBuffer) {
2488
- $self->decryptIV = $_xor;
2489
- if ($_start = $_ciphertext_len % '.$block_size.') {
2490
- $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2491
- }
2492
- }
2493
- return $_plaintext;
2494
- ';
2495
- break;
2496
- case CRYPT_MODE_STREAM:
2497
- $encrypt = $init_encrypt . '
2498
- $_ciphertext = "";
2499
- '.$encrypt_block.'
2500
- return $_ciphertext;
2501
- ';
2502
- $decrypt = $init_decrypt . '
2503
- $_plaintext = "";
2504
- '.$decrypt_block.'
2505
- return $_plaintext;
2506
- ';
2507
- break;
2508
- // case CRYPT_MODE_CBC:
2509
- default:
2510
- $encrypt = $init_encrypt . '
2511
- $_ciphertext = "";
2512
- $_plaintext_len = strlen($_text);
2513
-
2514
- $in = $self->encryptIV;
2515
-
2516
- for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2517
- $in = substr($_text, $_i, '.$block_size.') ^ $in;
2518
- '.$encrypt_block.'
2519
- $_ciphertext.= $in;
2520
- }
2521
-
2522
- if ($self->continuousBuffer) {
2523
- $self->encryptIV = $in;
2524
- }
2525
-
2526
- return $_ciphertext;
2527
- ';
2528
-
2529
- $decrypt = $init_decrypt . '
2530
- $_plaintext = "";
2531
- $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2532
- $_ciphertext_len = strlen($_text);
2533
-
2534
- $_iv = $self->decryptIV;
2535
-
2536
- for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2537
- $in = $_block = substr($_text, $_i, '.$block_size.');
2538
- '.$decrypt_block.'
2539
- $_plaintext.= $in ^ $_iv;
2540
- $_iv = $_block;
2541
- }
2542
-
2543
- if ($self->continuousBuffer) {
2544
- $self->decryptIV = $_iv;
2545
- }
2546
-
2547
- return $self->_unpad($_plaintext);
2548
- ';
2549
- break;
2550
- }
2551
-
2552
- // Create the $inline function and return its name as string. Ready to run!
2553
- if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
2554
- eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
2555
- return $func;
2556
- }
2557
-
2558
- return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2559
- }
2560
-
2561
- /**
2562
- * Holds the lambda_functions table (classwide)
2563
- *
2564
- * Each name of the lambda function, created from
2565
- * _setupInlineCrypt() && _createInlineCryptFunction()
2566
- * is stored, classwide (!), here for reusing.
2567
- *
2568
- * The string-based index of $function is a classwide
2569
- * unique value representing, at least, the $mode of
2570
- * operation (or more... depends of the optimizing level)
2571
- * for which $mode the lambda function was created.
2572
- *
2573
- * @access private
2574
- * @return array &$functions
2575
- */
2576
- function &_getLambdaFunctions()
2577
- {
2578
- static $functions = array();
2579
- return $functions;
2580
- }
2581
-
2582
- /**
2583
- * Generates a digest from $bytes
2584
- *
2585
- * @see self::_setupInlineCrypt()
2586
- * @access private
2587
- * @param $bytes
2588
- * @return string
2589
- */
2590
- function _hashInlineCryptFunction($bytes)
2591
- {
2592
- if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) {
2593
- define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
2594
- }
2595
-
2596
- $result = '';
2597
- $hash = $bytes;
2598
-
2599
- switch (true) {
2600
- case CRYPT_BASE_WHIRLPOOL_AVAILABLE:
2601
- foreach (str_split($bytes, 64) as $t) {
2602
- $hash = hash('whirlpool', $hash, true);
2603
- $result .= $t ^ $hash;
2604
- }
2605
- return $result . hash('whirlpool', $hash, true);
2606
- default:
2607
- $len = strlen($bytes);
2608
- for ($i = 0; $i < $len; $i+=20) {
2609
- $t = substr($bytes, $i, 20);
2610
- $hash = pack('H*', sha1($hash));
2611
- $result .= $t ^ $hash;
2612
- }
2613
- return $result . pack('H*', sha1($hash));
2614
- }
2615
- }
2616
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Base Class for all Crypt_* cipher classes
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Internally for phpseclib developers:
9
+ * If you plan to add a new cipher class, please note following rules:
10
+ *
11
+ * - The new Crypt_* cipher class should extend Crypt_Base
12
+ *
13
+ * - Following methods are then required to be overridden/overloaded:
14
+ *
15
+ * - _encryptBlock()
16
+ *
17
+ * - _decryptBlock()
18
+ *
19
+ * - _setupKey()
20
+ *
21
+ * - All other methods are optional to be overridden/overloaded
22
+ *
23
+ * - Look at the source code of the current ciphers how they extend Crypt_Base
24
+ * and take one of them as a start up for the new cipher class.
25
+ *
26
+ * - Please read all the other comments/notes/hints here also for each class var/method
27
+ *
28
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ * of this software and associated documentation files (the "Software"), to deal
30
+ * in the Software without restriction, including without limitation the rights
31
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ * copies of the Software, and to permit persons to whom the Software is
33
+ * furnished to do so, subject to the following conditions:
34
+ *
35
+ * The above copyright notice and this permission notice shall be included in
36
+ * all copies or substantial portions of the Software.
37
+ *
38
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
+ * THE SOFTWARE.
45
+ *
46
+ * @category Crypt
47
+ * @package Crypt_Base
48
+ * @author Jim Wigginton <terrafrost@php.net>
49
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
50
+ * @copyright 2007 Jim Wigginton
51
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
+ * @link http://phpseclib.sourceforge.net
53
+ */
54
+
55
+ /**#@+
56
+ * @access public
57
+ * @see self::encrypt()
58
+ * @see self::decrypt()
59
+ */
60
+ /**
61
+ * Encrypt / decrypt using the Counter mode.
62
+ *
63
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
64
+ *
65
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
66
+ */
67
+ define('CRYPT_MODE_CTR', -1);
68
+ /**
69
+ * Encrypt / decrypt using the Electronic Code Book mode.
70
+ *
71
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
72
+ */
73
+ define('CRYPT_MODE_ECB', 1);
74
+ /**
75
+ * Encrypt / decrypt using the Code Book Chaining mode.
76
+ *
77
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
78
+ */
79
+ define('CRYPT_MODE_CBC', 2);
80
+ /**
81
+ * Encrypt / decrypt using the Cipher Feedback mode.
82
+ *
83
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
84
+ */
85
+ define('CRYPT_MODE_CFB', 3);
86
+ /**
87
+ * Encrypt / decrypt using the Output Feedback mode.
88
+ *
89
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
90
+ */
91
+ define('CRYPT_MODE_OFB', 4);
92
+ /**
93
+ * Encrypt / decrypt using streaming mode.
94
+ */
95
+ define('CRYPT_MODE_STREAM', 5);
96
+ /**#@-*/
97
+
98
+ /**#@+
99
+ * @access private
100
+ * @see self::Crypt_Base()
101
+ * @internal These constants are for internal use only
102
+ */
103
+ /**
104
+ * Base value for the internal implementation $engine switch
105
+ */
106
+ define('CRYPT_ENGINE_INTERNAL', 1);
107
+ /**
108
+ * Base value for the mcrypt implementation $engine switch
109
+ */
110
+ define('CRYPT_ENGINE_MCRYPT', 2);
111
+ /**
112
+ * Base value for the OpenSSL implementation $engine switch
113
+ */
114
+ define('CRYPT_ENGINE_OPENSSL', 3);
115
+ /**#@-*/
116
+
117
+ /**
118
+ * Base Class for all Crypt_* cipher classes
119
+ *
120
+ * @package Crypt_Base
121
+ * @author Jim Wigginton <terrafrost@php.net>
122
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
123
+ * @access public
124
+ */
125
+ class Crypt_Base
126
+ {
127
+ /**
128
+ * The Encryption Mode
129
+ *
130
+ * @see self::Crypt_Base()
131
+ * @var int
132
+ * @access private
133
+ */
134
+ var $mode;
135
+
136
+ /**
137
+ * The Block Length of the block cipher
138
+ *
139
+ * @var int
140
+ * @access private
141
+ */
142
+ var $block_size = 16;
143
+
144
+ /**
145
+ * The Key
146
+ *
147
+ * @see self::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 self::setIV()
157
+ * @var string
158
+ * @access private
159
+ */
160
+ var $iv;
161
+
162
+ /**
163
+ * A "sliding" Initialization Vector
164
+ *
165
+ * @see self::enableContinuousBuffer()
166
+ * @see self::_clearBuffers()
167
+ * @var string
168
+ * @access private
169
+ */
170
+ var $encryptIV;
171
+
172
+ /**
173
+ * A "sliding" Initialization Vector
174
+ *
175
+ * @see self::enableContinuousBuffer()
176
+ * @see self::_clearBuffers()
177
+ * @var string
178
+ * @access private
179
+ */
180
+ var $decryptIV;
181
+
182
+ /**
183
+ * Continuous Buffer status
184
+ *
185
+ * @see self::enableContinuousBuffer()
186
+ * @var bool
187
+ * @access private
188
+ */
189
+ var $continuousBuffer = false;
190
+
191
+ /**
192
+ * Encryption buffer for CTR, OFB and CFB modes
193
+ *
194
+ * @see self::encrypt()
195
+ * @see self::_clearBuffers()
196
+ * @var array
197
+ * @access private
198
+ */
199
+ var $enbuffer;
200
+
201
+ /**
202
+ * Decryption buffer for CTR, OFB and CFB modes
203
+ *
204
+ * @see self::decrypt()
205
+ * @see self::_clearBuffers()
206
+ * @var array
207
+ * @access private
208
+ */
209
+ var $debuffer;
210
+
211
+ /**
212
+ * mcrypt resource for encryption
213
+ *
214
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
215
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
216
+ *
217
+ * @see self::encrypt()
218
+ * @var resource
219
+ * @access private
220
+ */
221
+ var $enmcrypt;
222
+
223
+ /**
224
+ * mcrypt resource for decryption
225
+ *
226
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
227
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
228
+ *
229
+ * @see self::decrypt()
230
+ * @var resource
231
+ * @access private
232
+ */
233
+ var $demcrypt;
234
+
235
+ /**
236
+ * Does the enmcrypt resource need to be (re)initialized?
237
+ *
238
+ * @see Crypt_Twofish::setKey()
239
+ * @see Crypt_Twofish::setIV()
240
+ * @var bool
241
+ * @access private
242
+ */
243
+ var $enchanged = true;
244
+
245
+ /**
246
+ * Does the demcrypt resource need to be (re)initialized?
247
+ *
248
+ * @see Crypt_Twofish::setKey()
249
+ * @see Crypt_Twofish::setIV()
250
+ * @var bool
251
+ * @access private
252
+ */
253
+ var $dechanged = true;
254
+
255
+ /**
256
+ * mcrypt resource for CFB mode
257
+ *
258
+ * mcrypt's CFB mode, in (and only in) buffered context,
259
+ * is broken, so phpseclib implements the CFB mode by it self,
260
+ * even when the mcrypt php extension is available.
261
+ *
262
+ * In order to do the CFB-mode work (fast) phpseclib
263
+ * use a separate ECB-mode mcrypt resource.
264
+ *
265
+ * @link http://phpseclib.sourceforge.net/cfb-demo.phps
266
+ * @see self::encrypt()
267
+ * @see self::decrypt()
268
+ * @see self::_setupMcrypt()
269
+ * @var resource
270
+ * @access private
271
+ */
272
+ var $ecb;
273
+
274
+ /**
275
+ * Optimizing value while CFB-encrypting
276
+ *
277
+ * Only relevant if $continuousBuffer enabled
278
+ * and $engine == CRYPT_ENGINE_MCRYPT
279
+ *
280
+ * It's faster to re-init $enmcrypt if
281
+ * $buffer bytes > $cfb_init_len than
282
+ * using the $ecb resource furthermore.
283
+ *
284
+ * This value depends of the chosen cipher
285
+ * and the time it would be needed for it's
286
+ * initialization [by mcrypt_generic_init()]
287
+ * which, typically, depends on the complexity
288
+ * on its internaly Key-expanding algorithm.
289
+ *
290
+ * @see self::encrypt()
291
+ * @var int
292
+ * @access private
293
+ */
294
+ var $cfb_init_len = 600;
295
+
296
+ /**
297
+ * Does internal cipher state need to be (re)initialized?
298
+ *
299
+ * @see self::setKey()
300
+ * @see self::setIV()
301
+ * @see self::disableContinuousBuffer()
302
+ * @var bool
303
+ * @access private
304
+ */
305
+ var $changed = true;
306
+
307
+ /**
308
+ * Padding status
309
+ *
310
+ * @see self::enablePadding()
311
+ * @var bool
312
+ * @access private
313
+ */
314
+ var $padding = true;
315
+
316
+ /**
317
+ * Is the mode one that is paddable?
318
+ *
319
+ * @see self::Crypt_Base()
320
+ * @var bool
321
+ * @access private
322
+ */
323
+ var $paddable = false;
324
+
325
+ /**
326
+ * Holds which crypt engine internaly should be use,
327
+ * which will be determined automatically on __construct()
328
+ *
329
+ * Currently available $engines are:
330
+ * - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
331
+ * - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
332
+ * - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
333
+ *
334
+ * @see self::_setEngine()
335
+ * @see self::encrypt()
336
+ * @see self::decrypt()
337
+ * @var int
338
+ * @access private
339
+ */
340
+ var $engine;
341
+
342
+ /**
343
+ * Holds the preferred crypt engine
344
+ *
345
+ * @see self::_setEngine()
346
+ * @see self::setPreferredEngine()
347
+ * @var int
348
+ * @access private
349
+ */
350
+ var $preferredEngine;
351
+
352
+ /**
353
+ * The mcrypt specific name of the cipher
354
+ *
355
+ * Only used if $engine == CRYPT_ENGINE_MCRYPT
356
+ *
357
+ * @link http://www.php.net/mcrypt_module_open
358
+ * @link http://www.php.net/mcrypt_list_algorithms
359
+ * @see self::_setupMcrypt()
360
+ * @var string
361
+ * @access private
362
+ */
363
+ var $cipher_name_mcrypt;
364
+
365
+ /**
366
+ * The openssl specific name of the cipher
367
+ *
368
+ * Only used if $engine == CRYPT_ENGINE_OPENSSL
369
+ *
370
+ * @link http://www.php.net/openssl-get-cipher-methods
371
+ * @var string
372
+ * @access private
373
+ */
374
+ var $cipher_name_openssl;
375
+
376
+ /**
377
+ * The openssl specific name of the cipher in ECB mode
378
+ *
379
+ * If OpenSSL does not support the mode we're trying to use (CTR)
380
+ * it can still be emulated with ECB mode.
381
+ *
382
+ * @link http://www.php.net/openssl-get-cipher-methods
383
+ * @var string
384
+ * @access private
385
+ */
386
+ var $cipher_name_openssl_ecb;
387
+
388
+ /**
389
+ * The default salt used by setPassword()
390
+ *
391
+ * @see self::setPassword()
392
+ * @var string
393
+ * @access private
394
+ */
395
+ var $password_default_salt = 'phpseclib/salt';
396
+
397
+ /**
398
+ * The namespace used by the cipher for its constants.
399
+ *
400
+ * ie: AES.php is using CRYPT_AES_MODE_* for its constants
401
+ * so $const_namespace is AES
402
+ *
403
+ * DES.php is using CRYPT_DES_MODE_* for its constants
404
+ * so $const_namespace is DES... and so on
405
+ *
406
+ * All CRYPT_<$const_namespace>_MODE_* are aliases of
407
+ * the generic CRYPT_MODE_* constants, so both could be used
408
+ * for each cipher.
409
+ *
410
+ * Example:
411
+ * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
412
+ * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
413
+ *
414
+ * @see self::Crypt_Base()
415
+ * @var string
416
+ * @access private
417
+ */
418
+ var $const_namespace;
419
+
420
+ /**
421
+ * The name of the performance-optimized callback function
422
+ *
423
+ * Used by encrypt() / decrypt()
424
+ * only if $engine == CRYPT_ENGINE_INTERNAL
425
+ *
426
+ * @see self::encrypt()
427
+ * @see self::decrypt()
428
+ * @see self::_setupInlineCrypt()
429
+ * @see self::$use_inline_crypt
430
+ * @var Callback
431
+ * @access private
432
+ */
433
+ var $inline_crypt;
434
+
435
+ /**
436
+ * Holds whether performance-optimized $inline_crypt() can/should be used.
437
+ *
438
+ * @see self::encrypt()
439
+ * @see self::decrypt()
440
+ * @see self::inline_crypt
441
+ * @var mixed
442
+ * @access private
443
+ */
444
+ var $use_inline_crypt;
445
+
446
+ /**
447
+ * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
448
+ *
449
+ * @see self::_openssl_ctr_process()
450
+ * @var bool
451
+ * @access private
452
+ */
453
+ var $openssl_emulate_ctr = false;
454
+
455
+ /**
456
+ * Determines what options are passed to openssl_encrypt/decrypt
457
+ *
458
+ * @see self::isValidEngine()
459
+ * @var mixed
460
+ * @access private
461
+ */
462
+ var $openssl_options;
463
+
464
+ /**
465
+ * Has the key length explicitly been set or should it be derived from the key, itself?
466
+ *
467
+ * @see self::setKeyLength()
468
+ * @var bool
469
+ * @access private
470
+ */
471
+ var $explicit_key_length = false;
472
+
473
+ /**
474
+ * Don't truncate / null pad key
475
+ *
476
+ * @see self::_clearBuffers()
477
+ * @var bool
478
+ * @access private
479
+ */
480
+ var $skip_key_adjustment = false;
481
+
482
+ /**
483
+ * Default Constructor.
484
+ *
485
+ * Determines whether or not the mcrypt extension should be used.
486
+ *
487
+ * $mode could be:
488
+ *
489
+ * - CRYPT_MODE_ECB
490
+ *
491
+ * - CRYPT_MODE_CBC
492
+ *
493
+ * - CRYPT_MODE_CTR
494
+ *
495
+ * - CRYPT_MODE_CFB
496
+ *
497
+ * - CRYPT_MODE_OFB
498
+ *
499
+ * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
500
+ *
501
+ * If not explicitly set, CRYPT_MODE_CBC will be used.
502
+ *
503
+ * @param int $mode
504
+ * @access public
505
+ */
506
+ function __construct($mode = CRYPT_MODE_CBC)
507
+ {
508
+ // $mode dependent settings
509
+ switch ($mode) {
510
+ case CRYPT_MODE_ECB:
511
+ $this->paddable = true;
512
+ $this->mode = CRYPT_MODE_ECB;
513
+ break;
514
+ case CRYPT_MODE_CTR:
515
+ case CRYPT_MODE_CFB:
516
+ case CRYPT_MODE_OFB:
517
+ case CRYPT_MODE_STREAM:
518
+ $this->mode = $mode;
519
+ break;
520
+ case CRYPT_MODE_CBC:
521
+ default:
522
+ $this->paddable = true;
523
+ $this->mode = CRYPT_MODE_CBC;
524
+ }
525
+
526
+ $this->_setEngine();
527
+
528
+ // Determining whether inline crypting can be used by the cipher
529
+ if ($this->use_inline_crypt !== false) {
530
+ $this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
531
+ }
532
+ }
533
+
534
+ /**
535
+ * PHP4 compatible Default Constructor.
536
+ *
537
+ * @see self::__construct()
538
+ * @param int $mode
539
+ * @access public
540
+ */
541
+ function Crypt_Base($mode = CRYPT_MODE_CBC)
542
+ {
543
+ $this->__construct($mode);
544
+ }
545
+
546
+ /**
547
+ * Sets the initialization vector. (optional)
548
+ *
549
+ * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
550
+ * to be all zero's.
551
+ *
552
+ * @access public
553
+ * @param string $iv
554
+ * @internal Can be overwritten by a sub class, but does not have to be
555
+ */
556
+ function setIV($iv)
557
+ {
558
+ if ($this->mode == CRYPT_MODE_ECB) {
559
+ return;
560
+ }
561
+
562
+ $this->iv = $iv;
563
+ $this->changed = true;
564
+ }
565
+
566
+ /**
567
+ * Sets the key length.
568
+ *
569
+ * Keys with explicitly set lengths need to be treated accordingly
570
+ *
571
+ * @access public
572
+ * @param int $length
573
+ */
574
+ function setKeyLength($length)
575
+ {
576
+ $this->explicit_key_length = true;
577
+ $this->changed = true;
578
+ $this->_setEngine();
579
+ }
580
+
581
+ /**
582
+ * Returns the current key length in bits
583
+ *
584
+ * @access public
585
+ * @return int
586
+ */
587
+ function getKeyLength()
588
+ {
589
+ return $this->key_length << 3;
590
+ }
591
+
592
+ /**
593
+ * Returns the current block length in bits
594
+ *
595
+ * @access public
596
+ * @return int
597
+ */
598
+ function getBlockLength()
599
+ {
600
+ return $this->block_size << 3;
601
+ }
602
+
603
+ /**
604
+ * Sets the key.
605
+ *
606
+ * The min/max length(s) of the key depends on the cipher which is used.
607
+ * If the key not fits the length(s) of the cipher it will paded with null bytes
608
+ * up to the closest valid key length. If the key is more than max length,
609
+ * we trim the excess bits.
610
+ *
611
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
612
+ *
613
+ * @access public
614
+ * @param string $key
615
+ * @internal Could, but not must, extend by the child Crypt_* class
616
+ */
617
+ function setKey($key)
618
+ {
619
+ if (!$this->explicit_key_length) {
620
+ $this->setKeyLength(strlen($key) << 3);
621
+ $this->explicit_key_length = false;
622
+ }
623
+
624
+ $this->key = $key;
625
+ $this->changed = true;
626
+ $this->_setEngine();
627
+ }
628
+
629
+ /**
630
+ * Sets the password.
631
+ *
632
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
633
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
634
+ * $hash, $salt, $count, $dkLen
635
+ *
636
+ * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
637
+ *
638
+ * @see Crypt/Hash.php
639
+ * @param string $password
640
+ * @param string $method
641
+ * @return bool
642
+ * @access public
643
+ * @internal Could, but not must, extend by the child Crypt_* class
644
+ */
645
+ function setPassword($password, $method = 'pbkdf2')
646
+ {
647
+ $key = '';
648
+
649
+ switch ($method) {
650
+ default: // 'pbkdf2' or 'pbkdf1'
651
+ $func_args = func_get_args();
652
+
653
+ // Hash function
654
+ $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
655
+
656
+ // WPA and WPA2 use the SSID as the salt
657
+ $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
658
+
659
+ // RFC2898#section-4.2 uses 1,000 iterations by default
660
+ // WPA and WPA2 use 4,096.
661
+ $count = isset($func_args[4]) ? $func_args[4] : 1000;
662
+
663
+ // Keylength
664
+ if (isset($func_args[5])) {
665
+ $dkLen = $func_args[5];
666
+ } else {
667
+ $dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
668
+ }
669
+
670
+ switch (true) {
671
+ case $method == 'pbkdf1':
672
+ if (!class_exists('Crypt_Hash')) {
673
+ include_once 'Crypt/Hash.php';
674
+ }
675
+ $hashObj = new Crypt_Hash();
676
+ $hashObj->setHash($hash);
677
+ if ($dkLen > $hashObj->getLength()) {
678
+ user_error('Derived key too long');
679
+ return false;
680
+ }
681
+ $t = $password . $salt;
682
+ for ($i = 0; $i < $count; ++$i) {
683
+ $t = $hashObj->hash($t);
684
+ }
685
+ $key = substr($t, 0, $dkLen);
686
+
687
+ $this->setKey(substr($key, 0, $dkLen >> 1));
688
+ $this->setIV(substr($key, $dkLen >> 1));
689
+
690
+ return true;
691
+ // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
692
+ case !function_exists('hash_pbkdf2'):
693
+ case !function_exists('hash_algos'):
694
+ case !in_array($hash, hash_algos()):
695
+ if (!class_exists('Crypt_Hash')) {
696
+ include_once 'Crypt/Hash.php';
697
+ }
698
+ $i = 1;
699
+ while (strlen($key) < $dkLen) {
700
+ $hmac = new Crypt_Hash();
701
+ $hmac->setHash($hash);
702
+ $hmac->setKey($password);
703
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
704
+ for ($j = 2; $j <= $count; ++$j) {
705
+ $u = $hmac->hash($u);
706
+ $f^= $u;
707
+ }
708
+ $key.= $f;
709
+ }
710
+ $key = substr($key, 0, $dkLen);
711
+ break;
712
+ default:
713
+ $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
714
+ }
715
+ }
716
+
717
+ $this->setKey($key);
718
+
719
+ return true;
720
+ }
721
+
722
+ /**
723
+ * Encrypts a message.
724
+ *
725
+ * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
726
+ * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
727
+ * necessary are discussed in the following
728
+ * URL:
729
+ *
730
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
731
+ *
732
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
733
+ * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
734
+ * length.
735
+ *
736
+ * @see self::decrypt()
737
+ * @access public
738
+ * @param string $plaintext
739
+ * @return string $ciphertext
740
+ * @internal Could, but not must, extend by the child Crypt_* class
741
+ */
742
+ function encrypt($plaintext)
743
+ {
744
+ if ($this->paddable) {
745
+ $plaintext = $this->_pad($plaintext);
746
+ }
747
+
748
+ if ($this->engine === CRYPT_ENGINE_OPENSSL) {
749
+ if ($this->changed) {
750
+ $this->_clearBuffers();
751
+ $this->changed = false;
752
+ }
753
+ switch ($this->mode) {
754
+ case CRYPT_MODE_STREAM:
755
+ return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
756
+ case CRYPT_MODE_ECB:
757
+ $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
758
+ return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
759
+ case CRYPT_MODE_CBC:
760
+ $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
761
+ if (!defined('OPENSSL_RAW_DATA')) {
762
+ $result = substr($result, 0, -$this->block_size);
763
+ }
764
+ if ($this->continuousBuffer) {
765
+ $this->encryptIV = substr($result, -$this->block_size);
766
+ }
767
+ return $result;
768
+ case CRYPT_MODE_CTR:
769
+ return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
770
+ case CRYPT_MODE_CFB:
771
+ // cfb loosely routines inspired by openssl's:
772
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
773
+ $ciphertext = '';
774
+ if ($this->continuousBuffer) {
775
+ $iv = &$this->encryptIV;
776
+ $pos = &$this->enbuffer['pos'];
777
+ } else {
778
+ $iv = $this->encryptIV;
779
+ $pos = 0;
780
+ }
781
+ $len = strlen($plaintext);
782
+ $i = 0;
783
+ if ($pos) {
784
+ $orig_pos = $pos;
785
+ $max = $this->block_size - $pos;
786
+ if ($len >= $max) {
787
+ $i = $max;
788
+ $len-= $max;
789
+ $pos = 0;
790
+ } else {
791
+ $i = $len;
792
+ $pos+= $len;
793
+ $len = 0;
794
+ }
795
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
796
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
797
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
798
+ $plaintext = substr($plaintext, $i);
799
+ }
800
+
801
+ $overflow = $len % $this->block_size;
802
+
803
+ if ($overflow) {
804
+ $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
805
+ $iv = $this->_string_pop($ciphertext, $this->block_size);
806
+
807
+ $size = $len - $overflow;
808
+ $block = $iv ^ substr($plaintext, -$overflow);
809
+ $iv = substr_replace($iv, $block, 0, $overflow);
810
+ $ciphertext.= $block;
811
+ $pos = $overflow;
812
+ } elseif ($len) {
813
+ $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
814
+ $iv = substr($ciphertext, -$this->block_size);
815
+ }
816
+
817
+ return $ciphertext;
818
+ case CRYPT_MODE_OFB:
819
+ return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
820
+ }
821
+ }
822
+
823
+ if ($this->engine === CRYPT_ENGINE_MCRYPT) {
824
+ if ($this->changed) {
825
+ $this->_setupMcrypt();
826
+ $this->changed = false;
827
+ }
828
+ if ($this->enchanged) {
829
+ @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
830
+ $this->enchanged = false;
831
+ }
832
+
833
+ // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
834
+ // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
835
+ // rewritten CFB implementation the above outputs the same thing twice.
836
+ if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
837
+ $block_size = $this->block_size;
838
+ $iv = &$this->encryptIV;
839
+ $pos = &$this->enbuffer['pos'];
840
+ $len = strlen($plaintext);
841
+ $ciphertext = '';
842
+ $i = 0;
843
+ if ($pos) {
844
+ $orig_pos = $pos;
845
+ $max = $block_size - $pos;
846
+ if ($len >= $max) {
847
+ $i = $max;
848
+ $len-= $max;
849
+ $pos = 0;
850
+ } else {
851
+ $i = $len;
852
+ $pos+= $len;
853
+ $len = 0;
854
+ }
855
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
856
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
857
+ $this->enbuffer['enmcrypt_init'] = true;
858
+ }
859
+ if ($len >= $block_size) {
860
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
861
+ if ($this->enbuffer['enmcrypt_init'] === true) {
862
+ @mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
863
+ $this->enbuffer['enmcrypt_init'] = false;
864
+ }
865
+ $ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
866
+ $iv = substr($ciphertext, -$block_size);
867
+ $len%= $block_size;
868
+ } else {
869
+ while ($len >= $block_size) {
870
+ $iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
871
+ $ciphertext.= $iv;
872
+ $len-= $block_size;
873
+ $i+= $block_size;
874
+ }
875
+ }
876
+ }
877
+
878
+ if ($len) {
879
+ $iv = @mcrypt_generic($this->ecb, $iv);
880
+ $block = $iv ^ substr($plaintext, -$len);
881
+ $iv = substr_replace($iv, $block, 0, $len);
882
+ $ciphertext.= $block;
883
+ $pos = $len;
884
+ }
885
+
886
+ return $ciphertext;
887
+ }
888
+
889
+ $ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
890
+
891
+ if (!$this->continuousBuffer) {
892
+ @mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
893
+ }
894
+
895
+ return $ciphertext;
896
+ }
897
+
898
+ if ($this->changed) {
899
+ $this->_setup();
900
+ $this->changed = false;
901
+ }
902
+ if ($this->use_inline_crypt) {
903
+ $inline = $this->inline_crypt;
904
+ return $inline('encrypt', $this, $plaintext);
905
+ }
906
+
907
+ $buffer = &$this->enbuffer;
908
+ $block_size = $this->block_size;
909
+ $ciphertext = '';
910
+ switch ($this->mode) {
911
+ case CRYPT_MODE_ECB:
912
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
913
+ $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
914
+ }
915
+ break;
916
+ case CRYPT_MODE_CBC:
917
+ $xor = $this->encryptIV;
918
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
919
+ $block = substr($plaintext, $i, $block_size);
920
+ $block = $this->_encryptBlock($block ^ $xor);
921
+ $xor = $block;
922
+ $ciphertext.= $block;
923
+ }
924
+ if ($this->continuousBuffer) {
925
+ $this->encryptIV = $xor;
926
+ }
927
+ break;
928
+ case CRYPT_MODE_CTR:
929
+ $xor = $this->encryptIV;
930
+ if (strlen($buffer['ciphertext'])) {
931
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
932
+ $block = substr($plaintext, $i, $block_size);
933
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
934
+ $buffer['ciphertext'].= $this->_encryptBlock($xor);
935
+ }
936
+ $this->_increment_str($xor);
937
+ $key = $this->_string_shift($buffer['ciphertext'], $block_size);
938
+ $ciphertext.= $block ^ $key;
939
+ }
940
+ } else {
941
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
942
+ $block = substr($plaintext, $i, $block_size);
943
+ $key = $this->_encryptBlock($xor);
944
+ $this->_increment_str($xor);
945
+ $ciphertext.= $block ^ $key;
946
+ }
947
+ }
948
+ if ($this->continuousBuffer) {
949
+ $this->encryptIV = $xor;
950
+ if ($start = strlen($plaintext) % $block_size) {
951
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
952
+ }
953
+ }
954
+ break;
955
+ case CRYPT_MODE_CFB:
956
+ // cfb loosely routines inspired by openssl's:
957
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
958
+ if ($this->continuousBuffer) {
959
+ $iv = &$this->encryptIV;
960
+ $pos = &$buffer['pos'];
961
+ } else {
962
+ $iv = $this->encryptIV;
963
+ $pos = 0;
964
+ }
965
+ $len = strlen($plaintext);
966
+ $i = 0;
967
+ if ($pos) {
968
+ $orig_pos = $pos;
969
+ $max = $block_size - $pos;
970
+ if ($len >= $max) {
971
+ $i = $max;
972
+ $len-= $max;
973
+ $pos = 0;
974
+ } else {
975
+ $i = $len;
976
+ $pos+= $len;
977
+ $len = 0;
978
+ }
979
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
980
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
981
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
982
+ }
983
+ while ($len >= $block_size) {
984
+ $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
985
+ $ciphertext.= $iv;
986
+ $len-= $block_size;
987
+ $i+= $block_size;
988
+ }
989
+ if ($len) {
990
+ $iv = $this->_encryptBlock($iv);
991
+ $block = $iv ^ substr($plaintext, $i);
992
+ $iv = substr_replace($iv, $block, 0, $len);
993
+ $ciphertext.= $block;
994
+ $pos = $len;
995
+ }
996
+ break;
997
+ case CRYPT_MODE_OFB:
998
+ $xor = $this->encryptIV;
999
+ if (strlen($buffer['xor'])) {
1000
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1001
+ $block = substr($plaintext, $i, $block_size);
1002
+ if (strlen($block) > strlen($buffer['xor'])) {
1003
+ $xor = $this->_encryptBlock($xor);
1004
+ $buffer['xor'].= $xor;
1005
+ }
1006
+ $key = $this->_string_shift($buffer['xor'], $block_size);
1007
+ $ciphertext.= $block ^ $key;
1008
+ }
1009
+ } else {
1010
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1011
+ $xor = $this->_encryptBlock($xor);
1012
+ $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
1013
+ }
1014
+ $key = $xor;
1015
+ }
1016
+ if ($this->continuousBuffer) {
1017
+ $this->encryptIV = $xor;
1018
+ if ($start = strlen($plaintext) % $block_size) {
1019
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1020
+ }
1021
+ }
1022
+ break;
1023
+ case CRYPT_MODE_STREAM:
1024
+ $ciphertext = $this->_encryptBlock($plaintext);
1025
+ break;
1026
+ }
1027
+
1028
+ return $ciphertext;
1029
+ }
1030
+
1031
+ /**
1032
+ * Decrypts a message.
1033
+ *
1034
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
1035
+ * it is.
1036
+ *
1037
+ * @see self::encrypt()
1038
+ * @access public
1039
+ * @param string $ciphertext
1040
+ * @return string $plaintext
1041
+ * @internal Could, but not must, extend by the child Crypt_* class
1042
+ */
1043
+ function decrypt($ciphertext)
1044
+ {
1045
+ if ($this->paddable) {
1046
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
1047
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1048
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
1049
+ }
1050
+
1051
+ if ($this->engine === CRYPT_ENGINE_OPENSSL) {
1052
+ if ($this->changed) {
1053
+ $this->_clearBuffers();
1054
+ $this->changed = false;
1055
+ }
1056
+ switch ($this->mode) {
1057
+ case CRYPT_MODE_STREAM:
1058
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1059
+ break;
1060
+ case CRYPT_MODE_ECB:
1061
+ if (!defined('OPENSSL_RAW_DATA')) {
1062
+ $ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
1063
+ }
1064
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
1065
+ break;
1066
+ case CRYPT_MODE_CBC:
1067
+ if (!defined('OPENSSL_RAW_DATA')) {
1068
+ $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
1069
+ $ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
1070
+ $offset = 2 * $this->block_size;
1071
+ } else {
1072
+ $offset = $this->block_size;
1073
+ }
1074
+ $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
1075
+ if ($this->continuousBuffer) {
1076
+ $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
1077
+ }
1078
+ break;
1079
+ case CRYPT_MODE_CTR:
1080
+ $plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
1081
+ break;
1082
+ case CRYPT_MODE_CFB:
1083
+ // cfb loosely routines inspired by openssl's:
1084
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
1085
+ $plaintext = '';
1086
+ if ($this->continuousBuffer) {
1087
+ $iv = &$this->decryptIV;
1088
+ $pos = &$this->buffer['pos'];
1089
+ } else {
1090
+ $iv = $this->decryptIV;
1091
+ $pos = 0;
1092
+ }
1093
+ $len = strlen($ciphertext);
1094
+ $i = 0;
1095
+ if ($pos) {
1096
+ $orig_pos = $pos;
1097
+ $max = $this->block_size - $pos;
1098
+ if ($len >= $max) {
1099
+ $i = $max;
1100
+ $len-= $max;
1101
+ $pos = 0;
1102
+ } else {
1103
+ $i = $len;
1104
+ $pos+= $len;
1105
+ $len = 0;
1106
+ }
1107
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
1108
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1109
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1110
+ $ciphertext = substr($ciphertext, $i);
1111
+ }
1112
+ $overflow = $len % $this->block_size;
1113
+ if ($overflow) {
1114
+ $plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1115
+ if ($len - $overflow) {
1116
+ $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
1117
+ }
1118
+ $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1119
+ $plaintext.= $iv ^ substr($ciphertext, -$overflow);
1120
+ $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
1121
+ $pos = $overflow;
1122
+ } elseif ($len) {
1123
+ $plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
1124
+ $iv = substr($ciphertext, -$this->block_size);
1125
+ }
1126
+ break;
1127
+ case CRYPT_MODE_OFB:
1128
+ $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
1129
+ }
1130
+
1131
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1132
+ }
1133
+
1134
+ if ($this->engine === CRYPT_ENGINE_MCRYPT) {
1135
+ $block_size = $this->block_size;
1136
+ if ($this->changed) {
1137
+ $this->_setupMcrypt();
1138
+ $this->changed = false;
1139
+ }
1140
+ if ($this->dechanged) {
1141
+ @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1142
+ $this->dechanged = false;
1143
+ }
1144
+
1145
+ if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
1146
+ $iv = &$this->decryptIV;
1147
+ $pos = &$this->debuffer['pos'];
1148
+ $len = strlen($ciphertext);
1149
+ $plaintext = '';
1150
+ $i = 0;
1151
+ if ($pos) {
1152
+ $orig_pos = $pos;
1153
+ $max = $block_size - $pos;
1154
+ if ($len >= $max) {
1155
+ $i = $max;
1156
+ $len-= $max;
1157
+ $pos = 0;
1158
+ } else {
1159
+ $i = $len;
1160
+ $pos+= $len;
1161
+ $len = 0;
1162
+ }
1163
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1164
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1165
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1166
+ }
1167
+ if ($len >= $block_size) {
1168
+ $cb = substr($ciphertext, $i, $len - $len % $block_size);
1169
+ $plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
1170
+ $iv = substr($cb, -$block_size);
1171
+ $len%= $block_size;
1172
+ }
1173
+ if ($len) {
1174
+ $iv = @mcrypt_generic($this->ecb, $iv);
1175
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
1176
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
1177
+ $pos = $len;
1178
+ }
1179
+
1180
+ return $plaintext;
1181
+ }
1182
+
1183
+ $plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
1184
+
1185
+ if (!$this->continuousBuffer) {
1186
+ @mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
1187
+ }
1188
+
1189
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1190
+ }
1191
+
1192
+ if ($this->changed) {
1193
+ $this->_setup();
1194
+ $this->changed = false;
1195
+ }
1196
+ if ($this->use_inline_crypt) {
1197
+ $inline = $this->inline_crypt;
1198
+ return $inline('decrypt', $this, $ciphertext);
1199
+ }
1200
+
1201
+ $block_size = $this->block_size;
1202
+
1203
+ $buffer = &$this->debuffer;
1204
+ $plaintext = '';
1205
+ switch ($this->mode) {
1206
+ case CRYPT_MODE_ECB:
1207
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1208
+ $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
1209
+ }
1210
+ break;
1211
+ case CRYPT_MODE_CBC:
1212
+ $xor = $this->decryptIV;
1213
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1214
+ $block = substr($ciphertext, $i, $block_size);
1215
+ $plaintext.= $this->_decryptBlock($block) ^ $xor;
1216
+ $xor = $block;
1217
+ }
1218
+ if ($this->continuousBuffer) {
1219
+ $this->decryptIV = $xor;
1220
+ }
1221
+ break;
1222
+ case CRYPT_MODE_CTR:
1223
+ $xor = $this->decryptIV;
1224
+ if (strlen($buffer['ciphertext'])) {
1225
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1226
+ $block = substr($ciphertext, $i, $block_size);
1227
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
1228
+ $buffer['ciphertext'].= $this->_encryptBlock($xor);
1229
+ $this->_increment_str($xor);
1230
+ }
1231
+ $key = $this->_string_shift($buffer['ciphertext'], $block_size);
1232
+ $plaintext.= $block ^ $key;
1233
+ }
1234
+ } else {
1235
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1236
+ $block = substr($ciphertext, $i, $block_size);
1237
+ $key = $this->_encryptBlock($xor);
1238
+ $this->_increment_str($xor);
1239
+ $plaintext.= $block ^ $key;
1240
+ }
1241
+ }
1242
+ if ($this->continuousBuffer) {
1243
+ $this->decryptIV = $xor;
1244
+ if ($start = strlen($ciphertext) % $block_size) {
1245
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1246
+ }
1247
+ }
1248
+ break;
1249
+ case CRYPT_MODE_CFB:
1250
+ if ($this->continuousBuffer) {
1251
+ $iv = &$this->decryptIV;
1252
+ $pos = &$buffer['pos'];
1253
+ } else {
1254
+ $iv = $this->decryptIV;
1255
+ $pos = 0;
1256
+ }
1257
+ $len = strlen($ciphertext);
1258
+ $i = 0;
1259
+ if ($pos) {
1260
+ $orig_pos = $pos;
1261
+ $max = $block_size - $pos;
1262
+ if ($len >= $max) {
1263
+ $i = $max;
1264
+ $len-= $max;
1265
+ $pos = 0;
1266
+ } else {
1267
+ $i = $len;
1268
+ $pos+= $len;
1269
+ $len = 0;
1270
+ }
1271
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1272
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1273
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1274
+ }
1275
+ while ($len >= $block_size) {
1276
+ $iv = $this->_encryptBlock($iv);
1277
+ $cb = substr($ciphertext, $i, $block_size);
1278
+ $plaintext.= $iv ^ $cb;
1279
+ $iv = $cb;
1280
+ $len-= $block_size;
1281
+ $i+= $block_size;
1282
+ }
1283
+ if ($len) {
1284
+ $iv = $this->_encryptBlock($iv);
1285
+ $plaintext.= $iv ^ substr($ciphertext, $i);
1286
+ $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1287
+ $pos = $len;
1288
+ }
1289
+ break;
1290
+ case CRYPT_MODE_OFB:
1291
+ $xor = $this->decryptIV;
1292
+ if (strlen($buffer['xor'])) {
1293
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1294
+ $block = substr($ciphertext, $i, $block_size);
1295
+ if (strlen($block) > strlen($buffer['xor'])) {
1296
+ $xor = $this->_encryptBlock($xor);
1297
+ $buffer['xor'].= $xor;
1298
+ }
1299
+ $key = $this->_string_shift($buffer['xor'], $block_size);
1300
+ $plaintext.= $block ^ $key;
1301
+ }
1302
+ } else {
1303
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1304
+ $xor = $this->_encryptBlock($xor);
1305
+ $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1306
+ }
1307
+ $key = $xor;
1308
+ }
1309
+ if ($this->continuousBuffer) {
1310
+ $this->decryptIV = $xor;
1311
+ if ($start = strlen($ciphertext) % $block_size) {
1312
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1313
+ }
1314
+ }
1315
+ break;
1316
+ case CRYPT_MODE_STREAM:
1317
+ $plaintext = $this->_decryptBlock($ciphertext);
1318
+ break;
1319
+ }
1320
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1321
+ }
1322
+
1323
+ /**
1324
+ * OpenSSL CTR Processor
1325
+ *
1326
+ * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1327
+ * for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1328
+ * and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
1329
+ * function will emulate CTR with ECB when necessary.
1330
+ *
1331
+ * @see self::encrypt()
1332
+ * @see self::decrypt()
1333
+ * @param string $plaintext
1334
+ * @param string $encryptIV
1335
+ * @param array $buffer
1336
+ * @return string
1337
+ * @access private
1338
+ */
1339
+ function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
1340
+ {
1341
+ $ciphertext = '';
1342
+
1343
+ $block_size = $this->block_size;
1344
+ $key = $this->key;
1345
+
1346
+ if ($this->openssl_emulate_ctr) {
1347
+ $xor = $encryptIV;
1348
+ if (strlen($buffer['ciphertext'])) {
1349
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1350
+ $block = substr($plaintext, $i, $block_size);
1351
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
1352
+ $result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1353
+ $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
1354
+ $buffer['ciphertext'].= $result;
1355
+ }
1356
+ $this->_increment_str($xor);
1357
+ $otp = $this->_string_shift($buffer['ciphertext'], $block_size);
1358
+ $ciphertext.= $block ^ $otp;
1359
+ }
1360
+ } else {
1361
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
1362
+ $block = substr($plaintext, $i, $block_size);
1363
+ $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1364
+ $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
1365
+ $this->_increment_str($xor);
1366
+ $ciphertext.= $block ^ $otp;
1367
+ }
1368
+ }
1369
+ if ($this->continuousBuffer) {
1370
+ $encryptIV = $xor;
1371
+ if ($start = strlen($plaintext) % $block_size) {
1372
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1373
+ }
1374
+ }
1375
+
1376
+ return $ciphertext;
1377
+ }
1378
+
1379
+ if (strlen($buffer['ciphertext'])) {
1380
+ $ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
1381
+ $plaintext = substr($plaintext, strlen($ciphertext));
1382
+
1383
+ if (!strlen($plaintext)) {
1384
+ return $ciphertext;
1385
+ }
1386
+ }
1387
+
1388
+ $overflow = strlen($plaintext) % $block_size;
1389
+ if ($overflow) {
1390
+ $plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
1391
+ $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1392
+ $temp = $this->_string_pop($encrypted, $block_size);
1393
+ $ciphertext.= $encrypted . ($plaintext2 ^ $temp);
1394
+ if ($this->continuousBuffer) {
1395
+ $buffer['ciphertext'] = substr($temp, $overflow);
1396
+ $encryptIV = $temp;
1397
+ }
1398
+ } elseif (!strlen($buffer['ciphertext'])) {
1399
+ $ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1400
+ $temp = $this->_string_pop($ciphertext, $block_size);
1401
+ if ($this->continuousBuffer) {
1402
+ $encryptIV = $temp;
1403
+ }
1404
+ }
1405
+ if ($this->continuousBuffer) {
1406
+ if (!defined('OPENSSL_RAW_DATA')) {
1407
+ $encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1408
+ }
1409
+ $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
1410
+ if ($overflow) {
1411
+ $this->_increment_str($encryptIV);
1412
+ }
1413
+ }
1414
+
1415
+ return $ciphertext;
1416
+ }
1417
+
1418
+ /**
1419
+ * OpenSSL OFB Processor
1420
+ *
1421
+ * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
1422
+ * for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
1423
+ * and Crypt_Base::decrypt().
1424
+ *
1425
+ * @see self::encrypt()
1426
+ * @see self::decrypt()
1427
+ * @param string $plaintext
1428
+ * @param string $encryptIV
1429
+ * @param array $buffer
1430
+ * @return string
1431
+ * @access private
1432
+ */
1433
+ function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
1434
+ {
1435
+ if (strlen($buffer['xor'])) {
1436
+ $ciphertext = $plaintext ^ $buffer['xor'];
1437
+ $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
1438
+ $plaintext = substr($plaintext, strlen($ciphertext));
1439
+ } else {
1440
+ $ciphertext = '';
1441
+ }
1442
+
1443
+ $block_size = $this->block_size;
1444
+
1445
+ $len = strlen($plaintext);
1446
+ $key = $this->key;
1447
+ $overflow = $len % $block_size;
1448
+
1449
+ if (strlen($plaintext)) {
1450
+ if ($overflow) {
1451
+ $ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1452
+ $xor = $this->_string_pop($ciphertext, $block_size);
1453
+ if ($this->continuousBuffer) {
1454
+ $encryptIV = $xor;
1455
+ }
1456
+ $ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
1457
+ if ($this->continuousBuffer) {
1458
+ $buffer['xor'] = $xor;
1459
+ }
1460
+ } else {
1461
+ $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
1462
+ if ($this->continuousBuffer) {
1463
+ $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
1464
+ }
1465
+ }
1466
+ }
1467
+
1468
+ return $ciphertext;
1469
+ }
1470
+
1471
+ /**
1472
+ * phpseclib <-> OpenSSL Mode Mapper
1473
+ *
1474
+ * May need to be overwritten by classes extending this one in some cases
1475
+ *
1476
+ * @return int
1477
+ * @access private
1478
+ */
1479
+ function _openssl_translate_mode()
1480
+ {
1481
+ switch ($this->mode) {
1482
+ case CRYPT_MODE_ECB:
1483
+ return 'ecb';
1484
+ case CRYPT_MODE_CBC:
1485
+ return 'cbc';
1486
+ case CRYPT_MODE_CTR:
1487
+ return 'ctr';
1488
+ case CRYPT_MODE_CFB:
1489
+ return 'cfb';
1490
+ case CRYPT_MODE_OFB:
1491
+ return 'ofb';
1492
+ }
1493
+ }
1494
+
1495
+ /**
1496
+ * Pad "packets".
1497
+ *
1498
+ * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1499
+ * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1500
+ * pad the input so that it is of the proper length.
1501
+ *
1502
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1503
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1504
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1505
+ * transmitted separately)
1506
+ *
1507
+ * @see self::disablePadding()
1508
+ * @access public
1509
+ */
1510
+ function enablePadding()
1511
+ {
1512
+ $this->padding = true;
1513
+ }
1514
+
1515
+ /**
1516
+ * Do not pad packets.
1517
+ *
1518
+ * @see self::enablePadding()
1519
+ * @access public
1520
+ */
1521
+ function disablePadding()
1522
+ {
1523
+ $this->padding = false;
1524
+ }
1525
+
1526
+ /**
1527
+ * Treat consecutive "packets" as if they are a continuous buffer.
1528
+ *
1529
+ * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1530
+ * will yield different outputs:
1531
+ *
1532
+ * <code>
1533
+ * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1534
+ * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1535
+ * </code>
1536
+ * <code>
1537
+ * echo $rijndael->encrypt($plaintext);
1538
+ * </code>
1539
+ *
1540
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1541
+ * another, as demonstrated with the following:
1542
+ *
1543
+ * <code>
1544
+ * $rijndael->encrypt(substr($plaintext, 0, 16));
1545
+ * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1546
+ * </code>
1547
+ * <code>
1548
+ * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1549
+ * </code>
1550
+ *
1551
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1552
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1553
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1554
+ *
1555
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
1556
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1557
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1558
+ * however, they are also less intuitive and more likely to cause you problems.
1559
+ *
1560
+ * @see self::disableContinuousBuffer()
1561
+ * @access public
1562
+ * @internal Could, but not must, extend by the child Crypt_* class
1563
+ */
1564
+ function enableContinuousBuffer()
1565
+ {
1566
+ if ($this->mode == CRYPT_MODE_ECB) {
1567
+ return;
1568
+ }
1569
+
1570
+ $this->continuousBuffer = true;
1571
+
1572
+ $this->_setEngine();
1573
+ }
1574
+
1575
+ /**
1576
+ * Treat consecutive packets as if they are a discontinuous buffer.
1577
+ *
1578
+ * The default behavior.
1579
+ *
1580
+ * @see self::enableContinuousBuffer()
1581
+ * @access public
1582
+ * @internal Could, but not must, extend by the child Crypt_* class
1583
+ */
1584
+ function disableContinuousBuffer()
1585
+ {
1586
+ if ($this->mode == CRYPT_MODE_ECB) {
1587
+ return;
1588
+ }
1589
+ if (!$this->continuousBuffer) {
1590
+ return;
1591
+ }
1592
+
1593
+ $this->continuousBuffer = false;
1594
+ $this->changed = true;
1595
+
1596
+ $this->_setEngine();
1597
+ }
1598
+
1599
+ /**
1600
+ * Test for engine validity
1601
+ *
1602
+ * @see self::Crypt_Base()
1603
+ * @param int $engine
1604
+ * @access public
1605
+ * @return bool
1606
+ */
1607
+ function isValidEngine($engine)
1608
+ {
1609
+ switch ($engine) {
1610
+ case CRYPT_ENGINE_OPENSSL:
1611
+ if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) {
1612
+ return false;
1613
+ }
1614
+ $this->openssl_emulate_ctr = false;
1615
+ $result = $this->cipher_name_openssl &&
1616
+ extension_loaded('openssl') &&
1617
+ // PHP 5.3.0 - 5.3.2 did not let you set IV's
1618
+ version_compare(PHP_VERSION, '5.3.3', '>=');
1619
+ if (!$result) {
1620
+ return false;
1621
+ }
1622
+
1623
+ // prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
1624
+ // $options openssl_encrypt expected a boolean $raw_data.
1625
+ if (!defined('OPENSSL_RAW_DATA')) {
1626
+ $this->openssl_options = true;
1627
+ } else {
1628
+ $this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
1629
+ }
1630
+
1631
+ $methods = openssl_get_cipher_methods();
1632
+ if (in_array($this->cipher_name_openssl, $methods)) {
1633
+ return true;
1634
+ }
1635
+ // not all of openssl's symmetric cipher's support ctr. for those
1636
+ // that don't we'll emulate it
1637
+ switch ($this->mode) {
1638
+ case CRYPT_MODE_CTR:
1639
+ if (in_array($this->cipher_name_openssl_ecb, $methods)) {
1640
+ $this->openssl_emulate_ctr = true;
1641
+ return true;
1642
+ }
1643
+ }
1644
+ return false;
1645
+ case CRYPT_ENGINE_MCRYPT:
1646
+ return $this->cipher_name_mcrypt &&
1647
+ extension_loaded('mcrypt') &&
1648
+ in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
1649
+ case CRYPT_ENGINE_INTERNAL:
1650
+ return true;
1651
+ }
1652
+
1653
+ return false;
1654
+ }
1655
+
1656
+ /**
1657
+ * Sets the preferred crypt engine
1658
+ *
1659
+ * Currently, $engine could be:
1660
+ *
1661
+ * - CRYPT_ENGINE_OPENSSL [very fast]
1662
+ *
1663
+ * - CRYPT_ENGINE_MCRYPT [fast]
1664
+ *
1665
+ * - CRYPT_ENGINE_INTERNAL [slow]
1666
+ *
1667
+ * If the preferred crypt engine is not available the fastest available one will be used
1668
+ *
1669
+ * @see self::Crypt_Base()
1670
+ * @param int $engine
1671
+ * @access public
1672
+ */
1673
+ function setPreferredEngine($engine)
1674
+ {
1675
+ switch ($engine) {
1676
+ //case CRYPT_ENGINE_OPENSSL:
1677
+ case CRYPT_ENGINE_MCRYPT:
1678
+ case CRYPT_ENGINE_INTERNAL:
1679
+ $this->preferredEngine = $engine;
1680
+ break;
1681
+ default:
1682
+ $this->preferredEngine = CRYPT_ENGINE_OPENSSL;
1683
+ }
1684
+
1685
+ $this->_setEngine();
1686
+ }
1687
+
1688
+ /**
1689
+ * Returns the engine currently being utilized
1690
+ *
1691
+ * @see self::_setEngine()
1692
+ * @access public
1693
+ */
1694
+ function getEngine()
1695
+ {
1696
+ return $this->engine;
1697
+ }
1698
+
1699
+ /**
1700
+ * Sets the engine as appropriate
1701
+ *
1702
+ * @see self::Crypt_Base()
1703
+ * @access private
1704
+ */
1705
+ function _setEngine()
1706
+ {
1707
+ $this->engine = null;
1708
+
1709
+ $candidateEngines = array(
1710
+ $this->preferredEngine,
1711
+ CRYPT_ENGINE_OPENSSL,
1712
+ CRYPT_ENGINE_MCRYPT
1713
+ );
1714
+ foreach ($candidateEngines as $engine) {
1715
+ if ($this->isValidEngine($engine)) {
1716
+ $this->engine = $engine;
1717
+ break;
1718
+ }
1719
+ }
1720
+ if (!$this->engine) {
1721
+ $this->engine = CRYPT_ENGINE_INTERNAL;
1722
+ }
1723
+
1724
+ if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) {
1725
+ // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
1726
+ // (re)open them with the module named in $this->cipher_name_mcrypt
1727
+ @mcrypt_module_close($this->enmcrypt);
1728
+ @mcrypt_module_close($this->demcrypt);
1729
+ $this->enmcrypt = null;
1730
+ $this->demcrypt = null;
1731
+
1732
+ if ($this->ecb) {
1733
+ @mcrypt_module_close($this->ecb);
1734
+ $this->ecb = null;
1735
+ }
1736
+ }
1737
+
1738
+ $this->changed = true;
1739
+ }
1740
+
1741
+ /**
1742
+ * Encrypts a block
1743
+ *
1744
+ * @access private
1745
+ * @param string $in
1746
+ * @return string
1747
+ * @internal Must be extended by the child Crypt_* class
1748
+ */
1749
+ function _encryptBlock($in)
1750
+ {
1751
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1752
+ }
1753
+
1754
+ /**
1755
+ * Decrypts a block
1756
+ *
1757
+ * @access private
1758
+ * @param string $in
1759
+ * @return string
1760
+ * @internal Must be extended by the child Crypt_* class
1761
+ */
1762
+ function _decryptBlock($in)
1763
+ {
1764
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1765
+ }
1766
+
1767
+ /**
1768
+ * Setup the key (expansion)
1769
+ *
1770
+ * Only used if $engine == CRYPT_ENGINE_INTERNAL
1771
+ *
1772
+ * @see self::_setup()
1773
+ * @access private
1774
+ * @internal Must be extended by the child Crypt_* class
1775
+ */
1776
+ function _setupKey()
1777
+ {
1778
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1779
+ }
1780
+
1781
+ /**
1782
+ * Setup the CRYPT_ENGINE_INTERNAL $engine
1783
+ *
1784
+ * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1785
+ * Used (only) if $engine == CRYPT_ENGINE_INTERNAL
1786
+ *
1787
+ * _setup() will be called each time if $changed === true
1788
+ * typically this happens when using one or more of following public methods:
1789
+ *
1790
+ * - setKey()
1791
+ *
1792
+ * - setIV()
1793
+ *
1794
+ * - disableContinuousBuffer()
1795
+ *
1796
+ * - First run of encrypt() / decrypt() with no init-settings
1797
+ *
1798
+ * @see self::setKey()
1799
+ * @see self::setIV()
1800
+ * @see self::disableContinuousBuffer()
1801
+ * @access private
1802
+ * @internal _setup() is always called before en/decryption.
1803
+ * @internal Could, but not must, extend by the child Crypt_* class
1804
+ */
1805
+ function _setup()
1806
+ {
1807
+ $this->_clearBuffers();
1808
+ $this->_setupKey();
1809
+
1810
+ if ($this->use_inline_crypt) {
1811
+ $this->_setupInlineCrypt();
1812
+ }
1813
+ }
1814
+
1815
+ /**
1816
+ * Setup the CRYPT_ENGINE_MCRYPT $engine
1817
+ *
1818
+ * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1819
+ * Used (only) if $engine = CRYPT_ENGINE_MCRYPT
1820
+ *
1821
+ * _setupMcrypt() will be called each time if $changed === true
1822
+ * typically this happens when using one or more of following public methods:
1823
+ *
1824
+ * - setKey()
1825
+ *
1826
+ * - setIV()
1827
+ *
1828
+ * - disableContinuousBuffer()
1829
+ *
1830
+ * - First run of encrypt() / decrypt()
1831
+ *
1832
+ * @see self::setKey()
1833
+ * @see self::setIV()
1834
+ * @see self::disableContinuousBuffer()
1835
+ * @access private
1836
+ * @internal Could, but not must, extend by the child Crypt_* class
1837
+ */
1838
+ function _setupMcrypt()
1839
+ {
1840
+ $this->_clearBuffers();
1841
+ $this->enchanged = $this->dechanged = true;
1842
+
1843
+ if (!isset($this->enmcrypt)) {
1844
+ static $mcrypt_modes = array(
1845
+ CRYPT_MODE_CTR => 'ctr',
1846
+ CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
1847
+ CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
1848
+ CRYPT_MODE_CFB => 'ncfb',
1849
+ CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
1850
+ CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
1851
+ );
1852
+
1853
+ $this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1854
+ $this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1855
+
1856
+ // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1857
+ // to workaround mcrypt's broken ncfb implementation in buffered mode
1858
+ // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1859
+ if ($this->mode == CRYPT_MODE_CFB) {
1860
+ $this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1861
+ }
1862
+ } // else should mcrypt_generic_deinit be called?
1863
+
1864
+ if ($this->mode == CRYPT_MODE_CFB) {
1865
+ @mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1866
+ }
1867
+ }
1868
+
1869
+ /**
1870
+ * Pads a string
1871
+ *
1872
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1873
+ * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1874
+ * chr($this->block_size - (strlen($text) % $this->block_size)
1875
+ *
1876
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1877
+ * and padding will, hence forth, be enabled.
1878
+ *
1879
+ * @see self::_unpad()
1880
+ * @param string $text
1881
+ * @access private
1882
+ * @return string
1883
+ */
1884
+ function _pad($text)
1885
+ {
1886
+ $length = strlen($text);
1887
+
1888
+ if (!$this->padding) {
1889
+ if ($length % $this->block_size == 0) {
1890
+ return $text;
1891
+ } else {
1892
+ user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1893
+ $this->padding = true;
1894
+ }
1895
+ }
1896
+
1897
+ $pad = $this->block_size - ($length % $this->block_size);
1898
+
1899
+ return str_pad($text, $length + $pad, chr($pad));
1900
+ }
1901
+
1902
+ /**
1903
+ * Unpads a string.
1904
+ *
1905
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1906
+ * and false will be returned.
1907
+ *
1908
+ * @see self::_pad()
1909
+ * @param string $text
1910
+ * @access private
1911
+ * @return string
1912
+ */
1913
+ function _unpad($text)
1914
+ {
1915
+ if (!$this->padding) {
1916
+ return $text;
1917
+ }
1918
+
1919
+ $length = ord($text[strlen($text) - 1]);
1920
+
1921
+ if (!$length || $length > $this->block_size) {
1922
+ return false;
1923
+ }
1924
+
1925
+ return substr($text, 0, -$length);
1926
+ }
1927
+
1928
+ /**
1929
+ * Clears internal buffers
1930
+ *
1931
+ * Clearing/resetting the internal buffers is done everytime
1932
+ * after disableContinuousBuffer() or on cipher $engine (re)init
1933
+ * ie after setKey() or setIV()
1934
+ *
1935
+ * @access public
1936
+ * @internal Could, but not must, extend by the child Crypt_* class
1937
+ */
1938
+ function _clearBuffers()
1939
+ {
1940
+ $this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1941
+
1942
+ // mcrypt's handling of invalid's $iv:
1943
+ // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1944
+ $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1945
+
1946
+ if (!$this->skip_key_adjustment) {
1947
+ $this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
1948
+ }
1949
+ }
1950
+
1951
+ /**
1952
+ * String Shift
1953
+ *
1954
+ * Inspired by array_shift
1955
+ *
1956
+ * @param string $string
1957
+ * @param int $index
1958
+ * @access private
1959
+ * @return string
1960
+ */
1961
+ function _string_shift(&$string, $index = 1)
1962
+ {
1963
+ $substr = substr($string, 0, $index);
1964
+ $string = substr($string, $index);
1965
+ return $substr;
1966
+ }
1967
+
1968
+ /**
1969
+ * String Pop
1970
+ *
1971
+ * Inspired by array_pop
1972
+ *
1973
+ * @param string $string
1974
+ * @param int $index
1975
+ * @access private
1976
+ * @return string
1977
+ */
1978
+ function _string_pop(&$string, $index = 1)
1979
+ {
1980
+ $substr = substr($string, -$index);
1981
+ $string = substr($string, 0, -$index);
1982
+ return $substr;
1983
+ }
1984
+
1985
+ /**
1986
+ * Increment the current string
1987
+ *
1988
+ * @see self::decrypt()
1989
+ * @see self::encrypt()
1990
+ * @param string $var
1991
+ * @access private
1992
+ */
1993
+ function _increment_str(&$var)
1994
+ {
1995
+ for ($i = 4; $i <= strlen($var); $i+= 4) {
1996
+ $temp = substr($var, -$i, 4);
1997
+ switch ($temp) {
1998
+ case "\xFF\xFF\xFF\xFF":
1999
+ $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
2000
+ break;
2001
+ case "\x7F\xFF\xFF\xFF":
2002
+ $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
2003
+ return;
2004
+ default:
2005
+ $temp = unpack('Nnum', $temp);
2006
+ $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
2007
+ return;
2008
+ }
2009
+ }
2010
+
2011
+ $remainder = strlen($var) % 4;
2012
+
2013
+ if ($remainder == 0) {
2014
+ return;
2015
+ }
2016
+
2017
+ $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
2018
+ $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
2019
+ $var = substr_replace($var, $temp, 0, $remainder);
2020
+ }
2021
+
2022
+ /**
2023
+ * Setup the performance-optimized function for de/encrypt()
2024
+ *
2025
+ * Stores the created (or existing) callback function-name
2026
+ * in $this->inline_crypt
2027
+ *
2028
+ * Internally for phpseclib developers:
2029
+ *
2030
+ * _setupInlineCrypt() would be called only if:
2031
+ *
2032
+ * - $engine == CRYPT_ENGINE_INTERNAL and
2033
+ *
2034
+ * - $use_inline_crypt === true
2035
+ *
2036
+ * - each time on _setup(), after(!) _setupKey()
2037
+ *
2038
+ *
2039
+ * This ensures that _setupInlineCrypt() has always a
2040
+ * full ready2go initializated internal cipher $engine state
2041
+ * where, for example, the keys allready expanded,
2042
+ * keys/block_size calculated and such.
2043
+ *
2044
+ * It is, each time if called, the responsibility of _setupInlineCrypt():
2045
+ *
2046
+ * - to set $this->inline_crypt to a valid and fully working callback function
2047
+ * as a (faster) replacement for encrypt() / decrypt()
2048
+ *
2049
+ * - NOT to create unlimited callback functions (for memory reasons!)
2050
+ * no matter how often _setupInlineCrypt() would be called. At some
2051
+ * point of amount they must be generic re-useable.
2052
+ *
2053
+ * - the code of _setupInlineCrypt() it self,
2054
+ * and the generated callback code,
2055
+ * must be, in following order:
2056
+ * - 100% safe
2057
+ * - 100% compatible to encrypt()/decrypt()
2058
+ * - using only php5+ features/lang-constructs/php-extensions if
2059
+ * compatibility (down to php4) or fallback is provided
2060
+ * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
2061
+ * - >= 10% faster than encrypt()/decrypt() [which is, by the way,
2062
+ * the reason for the existence of _setupInlineCrypt() :-)]
2063
+ * - memory-nice
2064
+ * - short (as good as possible)
2065
+ *
2066
+ * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
2067
+ * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
2068
+ * - The following variable names are reserved:
2069
+ * - $_* (all variable names prefixed with an underscore)
2070
+ * - $self (object reference to it self. Do not use $this, but $self instead)
2071
+ * - $in (the content of $in has to en/decrypt by the generated code)
2072
+ * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
2073
+ *
2074
+ *
2075
+ * @see self::_setup()
2076
+ * @see self::_createInlineCryptFunction()
2077
+ * @see self::encrypt()
2078
+ * @see self::decrypt()
2079
+ * @access private
2080
+ * @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
2081
+ */
2082
+ function _setupInlineCrypt()
2083
+ {
2084
+ // If, for any reason, an extending Crypt_Base() Crypt_* class
2085
+ // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
2086
+ // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
2087
+ // in the constructor at object instance-time
2088
+ // or, if it's runtime-specific, at runtime
2089
+
2090
+ $this->use_inline_crypt = false;
2091
+ }
2092
+
2093
+ /**
2094
+ * Creates the performance-optimized function for en/decrypt()
2095
+ *
2096
+ * Internally for phpseclib developers:
2097
+ *
2098
+ * _createInlineCryptFunction():
2099
+ *
2100
+ * - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
2101
+ * with the current [$this->]mode of operation code
2102
+ *
2103
+ * - create the $inline function, which called by encrypt() / decrypt()
2104
+ * as its replacement to speed up the en/decryption operations.
2105
+ *
2106
+ * - return the name of the created $inline callback function
2107
+ *
2108
+ * - used to speed up en/decryption
2109
+ *
2110
+ *
2111
+ *
2112
+ * The main reason why can speed up things [up to 50%] this way are:
2113
+ *
2114
+ * - using variables more effective then regular.
2115
+ * (ie no use of expensive arrays but integers $k_0, $k_1 ...
2116
+ * or even, for example, the pure $key[] values hardcoded)
2117
+ *
2118
+ * - avoiding 1000's of function calls of ie _encryptBlock()
2119
+ * but inlining the crypt operations.
2120
+ * in the mode of operation for() loop.
2121
+ *
2122
+ * - full loop unroll the (sometimes key-dependent) rounds
2123
+ * avoiding this way ++$i counters and runtime-if's etc...
2124
+ *
2125
+ * The basic code architectur of the generated $inline en/decrypt()
2126
+ * lambda function, in pseudo php, is:
2127
+ *
2128
+ * <code>
2129
+ * +----------------------------------------------------------------------------------------------+
2130
+ * | callback $inline = create_function: |
2131
+ * | lambda_function_0001_crypt_ECB($action, $text) |
2132
+ * | { |
2133
+ * | INSERT PHP CODE OF: |
2134
+ * | $cipher_code['init_crypt']; // general init code. |
2135
+ * | // ie: $sbox'es declarations used for |
2136
+ * | // encrypt and decrypt'ing. |
2137
+ * | |
2138
+ * | switch ($action) { |
2139
+ * | case 'encrypt': |
2140
+ * | INSERT PHP CODE OF: |
2141
+ * | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
2142
+ * | ie: specified $key or $box |
2143
+ * | declarations for encrypt'ing. |
2144
+ * | |
2145
+ * | foreach ($ciphertext) { |
2146
+ * | $in = $block_size of $ciphertext; |
2147
+ * | |
2148
+ * | INSERT PHP CODE OF: |
2149
+ * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
2150
+ * | // strlen($in) == $this->block_size |
2151
+ * | // here comes the cipher algorithm in action |
2152
+ * | // for encryption. |
2153
+ * | // $cipher_code['encrypt_block'] has to |
2154
+ * | // encrypt the content of the $in variable |
2155
+ * | |
2156
+ * | $plaintext .= $in; |
2157
+ * | } |
2158
+ * | return $plaintext; |
2159
+ * | |
2160
+ * | case 'decrypt': |
2161
+ * | INSERT PHP CODE OF: |
2162
+ * | $cipher_code['init_decrypt']; // decrypt sepcific init code |
2163
+ * | ie: specified $key or $box |
2164
+ * | declarations for decrypt'ing. |
2165
+ * | foreach ($plaintext) { |
2166
+ * | $in = $block_size of $plaintext; |
2167
+ * | |
2168
+ * | INSERT PHP CODE OF: |
2169
+ * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
2170
+ * | // strlen($in) == $this->block_size |
2171
+ * | // here comes the cipher algorithm in action |
2172
+ * | // for decryption. |
2173
+ * | // $cipher_code['decrypt_block'] has to |
2174
+ * | // decrypt the content of the $in variable |
2175
+ * | $ciphertext .= $in; |
2176
+ * | } |
2177
+ * | return $ciphertext; |
2178
+ * | } |
2179
+ * | } |
2180
+ * +----------------------------------------------------------------------------------------------+
2181
+ * </code>
2182
+ *
2183
+ * See also the Crypt_*::_setupInlineCrypt()'s for
2184
+ * productive inline $cipher_code's how they works.
2185
+ *
2186
+ * Structure of:
2187
+ * <code>
2188
+ * $cipher_code = array(
2189
+ * 'init_crypt' => (string) '', // optional
2190
+ * 'init_encrypt' => (string) '', // optional
2191
+ * 'init_decrypt' => (string) '', // optional
2192
+ * 'encrypt_block' => (string) '', // required
2193
+ * 'decrypt_block' => (string) '' // required
2194
+ * );
2195
+ * </code>
2196
+ *
2197
+ * @see self::_setupInlineCrypt()
2198
+ * @see self::encrypt()
2199
+ * @see self::decrypt()
2200
+ * @param array $cipher_code
2201
+ * @access private
2202
+ * @return string (the name of the created callback function)
2203
+ */
2204
+ function _createInlineCryptFunction($cipher_code)
2205
+ {
2206
+ $block_size = $this->block_size;
2207
+
2208
+ // optional
2209
+ $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
2210
+ $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
2211
+ $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
2212
+ // required
2213
+ $encrypt_block = $cipher_code['encrypt_block'];
2214
+ $decrypt_block = $cipher_code['decrypt_block'];
2215
+
2216
+ // Generating mode of operation inline code,
2217
+ // merged with the $cipher_code algorithm
2218
+ // for encrypt- and decryption.
2219
+ switch ($this->mode) {
2220
+ case CRYPT_MODE_ECB:
2221
+ $encrypt = $init_encrypt . '
2222
+ $_ciphertext = "";
2223
+ $_plaintext_len = strlen($_text);
2224
+
2225
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2226
+ $in = substr($_text, $_i, '.$block_size.');
2227
+ '.$encrypt_block.'
2228
+ $_ciphertext.= $in;
2229
+ }
2230
+
2231
+ return $_ciphertext;
2232
+ ';
2233
+
2234
+ $decrypt = $init_decrypt . '
2235
+ $_plaintext = "";
2236
+ $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2237
+ $_ciphertext_len = strlen($_text);
2238
+
2239
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2240
+ $in = substr($_text, $_i, '.$block_size.');
2241
+ '.$decrypt_block.'
2242
+ $_plaintext.= $in;
2243
+ }
2244
+
2245
+ return $self->_unpad($_plaintext);
2246
+ ';
2247
+ break;
2248
+ case CRYPT_MODE_CTR:
2249
+ $encrypt = $init_encrypt . '
2250
+ $_ciphertext = "";
2251
+ $_plaintext_len = strlen($_text);
2252
+ $_xor = $self->encryptIV;
2253
+ $_buffer = &$self->enbuffer;
2254
+ if (strlen($_buffer["ciphertext"])) {
2255
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2256
+ $_block = substr($_text, $_i, '.$block_size.');
2257
+ if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2258
+ $in = $_xor;
2259
+ '.$encrypt_block.'
2260
+ $self->_increment_str($_xor);
2261
+ $_buffer["ciphertext"].= $in;
2262
+ }
2263
+ $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2264
+ $_ciphertext.= $_block ^ $_key;
2265
+ }
2266
+ } else {
2267
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2268
+ $_block = substr($_text, $_i, '.$block_size.');
2269
+ $in = $_xor;
2270
+ '.$encrypt_block.'
2271
+ $self->_increment_str($_xor);
2272
+ $_key = $in;
2273
+ $_ciphertext.= $_block ^ $_key;
2274
+ }
2275
+ }
2276
+ if ($self->continuousBuffer) {
2277
+ $self->encryptIV = $_xor;
2278
+ if ($_start = $_plaintext_len % '.$block_size.') {
2279
+ $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2280
+ }
2281
+ }
2282
+
2283
+ return $_ciphertext;
2284
+ ';
2285
+
2286
+ $decrypt = $init_encrypt . '
2287
+ $_plaintext = "";
2288
+ $_ciphertext_len = strlen($_text);
2289
+ $_xor = $self->decryptIV;
2290
+ $_buffer = &$self->debuffer;
2291
+
2292
+ if (strlen($_buffer["ciphertext"])) {
2293
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2294
+ $_block = substr($_text, $_i, '.$block_size.');
2295
+ if (strlen($_block) > strlen($_buffer["ciphertext"])) {
2296
+ $in = $_xor;
2297
+ '.$encrypt_block.'
2298
+ $self->_increment_str($_xor);
2299
+ $_buffer["ciphertext"].= $in;
2300
+ }
2301
+ $_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
2302
+ $_plaintext.= $_block ^ $_key;
2303
+ }
2304
+ } else {
2305
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2306
+ $_block = substr($_text, $_i, '.$block_size.');
2307
+ $in = $_xor;
2308
+ '.$encrypt_block.'
2309
+ $self->_increment_str($_xor);
2310
+ $_key = $in;
2311
+ $_plaintext.= $_block ^ $_key;
2312
+ }
2313
+ }
2314
+ if ($self->continuousBuffer) {
2315
+ $self->decryptIV = $_xor;
2316
+ if ($_start = $_ciphertext_len % '.$block_size.') {
2317
+ $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
2318
+ }
2319
+ }
2320
+
2321
+ return $_plaintext;
2322
+ ';
2323
+ break;
2324
+ case CRYPT_MODE_CFB:
2325
+ $encrypt = $init_encrypt . '
2326
+ $_ciphertext = "";
2327
+ $_buffer = &$self->enbuffer;
2328
+
2329
+ if ($self->continuousBuffer) {
2330
+ $_iv = &$self->encryptIV;
2331
+ $_pos = &$_buffer["pos"];
2332
+ } else {
2333
+ $_iv = $self->encryptIV;
2334
+ $_pos = 0;
2335
+ }
2336
+ $_len = strlen($_text);
2337
+ $_i = 0;
2338
+ if ($_pos) {
2339
+ $_orig_pos = $_pos;
2340
+ $_max = '.$block_size.' - $_pos;
2341
+ if ($_len >= $_max) {
2342
+ $_i = $_max;
2343
+ $_len-= $_max;
2344
+ $_pos = 0;
2345
+ } else {
2346
+ $_i = $_len;
2347
+ $_pos+= $_len;
2348
+ $_len = 0;
2349
+ }
2350
+ $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
2351
+ $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
2352
+ }
2353
+ while ($_len >= '.$block_size.') {
2354
+ $in = $_iv;
2355
+ '.$encrypt_block.';
2356
+ $_iv = $in ^ substr($_text, $_i, '.$block_size.');
2357
+ $_ciphertext.= $_iv;
2358
+ $_len-= '.$block_size.';
2359
+ $_i+= '.$block_size.';
2360
+ }
2361
+ if ($_len) {
2362
+ $in = $_iv;
2363
+ '.$encrypt_block.'
2364
+ $_iv = $in;
2365
+ $_block = $_iv ^ substr($_text, $_i);
2366
+ $_iv = substr_replace($_iv, $_block, 0, $_len);
2367
+ $_ciphertext.= $_block;
2368
+ $_pos = $_len;
2369
+ }
2370
+ return $_ciphertext;
2371
+ ';
2372
+
2373
+ $decrypt = $init_encrypt . '
2374
+ $_plaintext = "";
2375
+ $_buffer = &$self->debuffer;
2376
+
2377
+ if ($self->continuousBuffer) {
2378
+ $_iv = &$self->decryptIV;
2379
+ $_pos = &$_buffer["pos"];
2380
+ } else {
2381
+ $_iv = $self->decryptIV;
2382
+ $_pos = 0;
2383
+ }
2384
+ $_len = strlen($_text);
2385
+ $_i = 0;
2386
+ if ($_pos) {
2387
+ $_orig_pos = $_pos;
2388
+ $_max = '.$block_size.' - $_pos;
2389
+ if ($_len >= $_max) {
2390
+ $_i = $_max;
2391
+ $_len-= $_max;
2392
+ $_pos = 0;
2393
+ } else {
2394
+ $_i = $_len;
2395
+ $_pos+= $_len;
2396
+ $_len = 0;
2397
+ }
2398
+ $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
2399
+ $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
2400
+ }
2401
+ while ($_len >= '.$block_size.') {
2402
+ $in = $_iv;
2403
+ '.$encrypt_block.'
2404
+ $_iv = $in;
2405
+ $cb = substr($_text, $_i, '.$block_size.');
2406
+ $_plaintext.= $_iv ^ $cb;
2407
+ $_iv = $cb;
2408
+ $_len-= '.$block_size.';
2409
+ $_i+= '.$block_size.';
2410
+ }
2411
+ if ($_len) {
2412
+ $in = $_iv;
2413
+ '.$encrypt_block.'
2414
+ $_iv = $in;
2415
+ $_plaintext.= $_iv ^ substr($_text, $_i);
2416
+ $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
2417
+ $_pos = $_len;
2418
+ }
2419
+
2420
+ return $_plaintext;
2421
+ ';
2422
+ break;
2423
+ case CRYPT_MODE_OFB:
2424
+ $encrypt = $init_encrypt . '
2425
+ $_ciphertext = "";
2426
+ $_plaintext_len = strlen($_text);
2427
+ $_xor = $self->encryptIV;
2428
+ $_buffer = &$self->enbuffer;
2429
+
2430
+ if (strlen($_buffer["xor"])) {
2431
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2432
+ $_block = substr($_text, $_i, '.$block_size.');
2433
+ if (strlen($_block) > strlen($_buffer["xor"])) {
2434
+ $in = $_xor;
2435
+ '.$encrypt_block.'
2436
+ $_xor = $in;
2437
+ $_buffer["xor"].= $_xor;
2438
+ }
2439
+ $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2440
+ $_ciphertext.= $_block ^ $_key;
2441
+ }
2442
+ } else {
2443
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2444
+ $in = $_xor;
2445
+ '.$encrypt_block.'
2446
+ $_xor = $in;
2447
+ $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2448
+ }
2449
+ $_key = $_xor;
2450
+ }
2451
+ if ($self->continuousBuffer) {
2452
+ $self->encryptIV = $_xor;
2453
+ if ($_start = $_plaintext_len % '.$block_size.') {
2454
+ $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2455
+ }
2456
+ }
2457
+ return $_ciphertext;
2458
+ ';
2459
+
2460
+ $decrypt = $init_encrypt . '
2461
+ $_plaintext = "";
2462
+ $_ciphertext_len = strlen($_text);
2463
+ $_xor = $self->decryptIV;
2464
+ $_buffer = &$self->debuffer;
2465
+
2466
+ if (strlen($_buffer["xor"])) {
2467
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2468
+ $_block = substr($_text, $_i, '.$block_size.');
2469
+ if (strlen($_block) > strlen($_buffer["xor"])) {
2470
+ $in = $_xor;
2471
+ '.$encrypt_block.'
2472
+ $_xor = $in;
2473
+ $_buffer["xor"].= $_xor;
2474
+ }
2475
+ $_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
2476
+ $_plaintext.= $_block ^ $_key;
2477
+ }
2478
+ } else {
2479
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2480
+ $in = $_xor;
2481
+ '.$encrypt_block.'
2482
+ $_xor = $in;
2483
+ $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
2484
+ }
2485
+ $_key = $_xor;
2486
+ }
2487
+ if ($self->continuousBuffer) {
2488
+ $self->decryptIV = $_xor;
2489
+ if ($_start = $_ciphertext_len % '.$block_size.') {
2490
+ $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
2491
+ }
2492
+ }
2493
+ return $_plaintext;
2494
+ ';
2495
+ break;
2496
+ case CRYPT_MODE_STREAM:
2497
+ $encrypt = $init_encrypt . '
2498
+ $_ciphertext = "";
2499
+ '.$encrypt_block.'
2500
+ return $_ciphertext;
2501
+ ';
2502
+ $decrypt = $init_decrypt . '
2503
+ $_plaintext = "";
2504
+ '.$decrypt_block.'
2505
+ return $_plaintext;
2506
+ ';
2507
+ break;
2508
+ // case CRYPT_MODE_CBC:
2509
+ default:
2510
+ $encrypt = $init_encrypt . '
2511
+ $_ciphertext = "";
2512
+ $_plaintext_len = strlen($_text);
2513
+
2514
+ $in = $self->encryptIV;
2515
+
2516
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
2517
+ $in = substr($_text, $_i, '.$block_size.') ^ $in;
2518
+ '.$encrypt_block.'
2519
+ $_ciphertext.= $in;
2520
+ }
2521
+
2522
+ if ($self->continuousBuffer) {
2523
+ $self->encryptIV = $in;
2524
+ }
2525
+
2526
+ return $_ciphertext;
2527
+ ';
2528
+
2529
+ $decrypt = $init_decrypt . '
2530
+ $_plaintext = "";
2531
+ $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
2532
+ $_ciphertext_len = strlen($_text);
2533
+
2534
+ $_iv = $self->decryptIV;
2535
+
2536
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
2537
+ $in = $_block = substr($_text, $_i, '.$block_size.');
2538
+ '.$decrypt_block.'
2539
+ $_plaintext.= $in ^ $_iv;
2540
+ $_iv = $_block;
2541
+ }
2542
+
2543
+ if ($self->continuousBuffer) {
2544
+ $self->decryptIV = $_iv;
2545
+ }
2546
+
2547
+ return $self->_unpad($_plaintext);
2548
+ ';
2549
+ break;
2550
+ }
2551
+
2552
+ // Create the $inline function and return its name as string. Ready to run!
2553
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
2554
+ eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
2555
+ return $func;
2556
+ }
2557
+
2558
+ return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
2559
+ }
2560
+
2561
+ /**
2562
+ * Holds the lambda_functions table (classwide)
2563
+ *
2564
+ * Each name of the lambda function, created from
2565
+ * _setupInlineCrypt() && _createInlineCryptFunction()
2566
+ * is stored, classwide (!), here for reusing.
2567
+ *
2568
+ * The string-based index of $function is a classwide
2569
+ * unique value representing, at least, the $mode of
2570
+ * operation (or more... depends of the optimizing level)
2571
+ * for which $mode the lambda function was created.
2572
+ *
2573
+ * @access private
2574
+ * @return array &$functions
2575
+ */
2576
+ function &_getLambdaFunctions()
2577
+ {
2578
+ static $functions = array();
2579
+ return $functions;
2580
+ }
2581
+
2582
+ /**
2583
+ * Generates a digest from $bytes
2584
+ *
2585
+ * @see self::_setupInlineCrypt()
2586
+ * @access private
2587
+ * @param $bytes
2588
+ * @return string
2589
+ */
2590
+ function _hashInlineCryptFunction($bytes)
2591
+ {
2592
+ if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) {
2593
+ define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
2594
+ }
2595
+
2596
+ $result = '';
2597
+ $hash = $bytes;
2598
+
2599
+ switch (true) {
2600
+ case CRYPT_BASE_WHIRLPOOL_AVAILABLE:
2601
+ foreach (str_split($bytes, 64) as $t) {
2602
+ $hash = hash('whirlpool', $hash, true);
2603
+ $result .= $t ^ $hash;
2604
+ }
2605
+ return $result . hash('whirlpool', $hash, true);
2606
+ default:
2607
+ $len = strlen($bytes);
2608
+ for ($i = 0; $i < $len; $i+=20) {
2609
+ $t = substr($bytes, $i, 20);
2610
+ $hash = pack('H*', sha1($hash));
2611
+ $result .= $t ^ $hash;
2612
+ }
2613
+ return $result . pack('H*', sha1($hash));
2614
+ }
2615
+ }
2616
+
2617
+ /**
2618
+ * Convert float to int
2619
+ *
2620
+ * On 32-bit Linux installs running PHP < 5.3 converting floats to ints doesn't always work
2621
+ *
2622
+ * @access private
2623
+ * @param string $x
2624
+ * @return int
2625
+ */
2626
+ function safe_intval($x)
2627
+ {
2628
+ switch (true) {
2629
+ case is_int($x):
2630
+ // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
2631
+ case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
2632
+ // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
2633
+ case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
2634
+ return $x;
2635
+ }
2636
+ return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
2637
+ ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
2638
+ }
2639
+
2640
+ /**
2641
+ * eval()'able string for in-line float to int
2642
+ *
2643
+ * @access private
2644
+ * @return string
2645
+ */
2646
+ function safe_intval_inline()
2647
+ {
2648
+ // on 32-bit linux systems with PHP < 5.3 float to integer conversion is bad
2649
+ switch (true) {
2650
+ case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
2651
+ case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
2652
+ case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
2653
+ return '%s';
2654
+ break;
2655
+ default:
2656
+ $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
2657
+ return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
2658
+ }
2659
+ }
2660
+ }
phpseclib/Crypt/Blowfish.php CHANGED
@@ -1,674 +1,644 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Blowfish.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'Crypt/Blowfish.php';
18
- *
19
- * $blowfish = new Crypt_Blowfish();
20
- *
21
- * $blowfish->setKey('12345678901234567890123456789012');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
- * of this software and associated documentation files (the "Software"), to deal
31
- * in the Software without restriction, including without limitation the rights
32
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
- * copies of the Software, and to permit persons to whom the Software is
34
- * furnished to do so, subject to the following conditions:
35
- *
36
- * The above copyright notice and this permission notice shall be included in
37
- * all copies or substantial portions of the Software.
38
- *
39
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
- * THE SOFTWARE.
46
- *
47
- * @category Crypt
48
- * @package Crypt_Blowfish
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
- * @copyright 2007 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_Base
58
- *
59
- * Base cipher class
60
- */
61
- if (!class_exists('Crypt_Base')) {
62
- include_once 'Base.php';
63
- }
64
-
65
- /**#@+
66
- * @access public
67
- * @see self::encrypt()
68
- * @see self::decrypt()
69
- */
70
- /**
71
- * Encrypt / decrypt using the Counter mode.
72
- *
73
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
- *
75
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
- */
77
- define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR);
78
- /**
79
- * Encrypt / decrypt using the Electronic Code Book mode.
80
- *
81
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
- */
83
- define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB);
84
- /**
85
- * Encrypt / decrypt using the Code Book Chaining mode.
86
- *
87
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
- */
89
- define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC);
90
- /**
91
- * Encrypt / decrypt using the Cipher Feedback mode.
92
- *
93
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
- */
95
- define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
96
- /**
97
- * Encrypt / decrypt using the Cipher Feedback mode.
98
- *
99
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
- */
101
- define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
102
- /**#@-*/
103
-
104
- /**
105
- * Pure-PHP implementation of Blowfish.
106
- *
107
- * @package Crypt_Blowfish
108
- * @author Jim Wigginton <terrafrost@php.net>
109
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
110
- * @access public
111
- */
112
- class Crypt_Blowfish extends Crypt_Base
113
- {
114
- /**
115
- * Block Length of the cipher
116
- *
117
- * @see Crypt_Base::block_size
118
- * @var int
119
- * @access private
120
- */
121
- var $block_size = 8;
122
-
123
- /**
124
- * The namespace used by the cipher for its constants.
125
- *
126
- * @see Crypt_Base::const_namespace
127
- * @var string
128
- * @access private
129
- */
130
- var $const_namespace = 'BLOWFISH';
131
-
132
- /**
133
- * The mcrypt specific name of the cipher
134
- *
135
- * @see Crypt_Base::cipher_name_mcrypt
136
- * @var string
137
- * @access private
138
- */
139
- var $cipher_name_mcrypt = 'blowfish';
140
-
141
- /**
142
- * Optimizing value while CFB-encrypting
143
- *
144
- * @see Crypt_Base::cfb_init_len
145
- * @var int
146
- * @access private
147
- */
148
- var $cfb_init_len = 500;
149
-
150
- /**
151
- * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
152
- *
153
- * S-Box 0
154
- *
155
- * @access private
156
- * @var array
157
- */
158
- var $sbox0 = array(
159
- 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
160
- 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
161
- 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
162
- 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
163
- 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
164
- 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
165
- 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
166
- 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
167
- 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
168
- 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
169
- 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
170
- 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
171
- 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
172
- 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
173
- 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
174
- 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
175
- 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
176
- 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
177
- 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
178
- 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
179
- 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
180
- 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
181
- 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
182
- 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
183
- 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
184
- 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
185
- 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
186
- 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
187
- 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
188
- 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
189
- 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
190
- 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
191
- );
192
-
193
- /**
194
- * S-Box 1
195
- *
196
- * @access private
197
- * @var array
198
- */
199
- var $sbox1 = array(
200
- 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
201
- 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
202
- 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
203
- 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
204
- 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
205
- 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
206
- 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
207
- 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
208
- 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
209
- 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
210
- 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
211
- 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
212
- 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
213
- 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
214
- 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
215
- 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
216
- 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
217
- 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
218
- 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
219
- 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
220
- 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
221
- 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
222
- 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
223
- 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
224
- 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
225
- 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
226
- 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
227
- 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
228
- 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
229
- 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
230
- 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
231
- 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
232
- );
233
-
234
- /**
235
- * S-Box 2
236
- *
237
- * @access private
238
- * @var array
239
- */
240
- var $sbox2 = array(
241
- 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
242
- 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
243
- 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
244
- 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
245
- 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
246
- 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
247
- 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
248
- 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
249
- 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
250
- 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
251
- 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
252
- 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
253
- 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
254
- 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
255
- 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
256
- 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
257
- 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
258
- 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
259
- 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
260
- 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
261
- 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
262
- 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
263
- 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
264
- 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
265
- 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
266
- 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
267
- 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
268
- 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
269
- 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
270
- 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
271
- 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
272
- 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
273
- );
274
-
275
- /**
276
- * S-Box 3
277
- *
278
- * @access private
279
- * @var array
280
- */
281
- var $sbox3 = array(
282
- 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
283
- 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
284
- 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
285
- 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
286
- 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
287
- 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
288
- 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
289
- 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
290
- 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
291
- 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
292
- 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
293
- 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
294
- 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
295
- 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
296
- 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
297
- 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
298
- 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
299
- 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
300
- 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
301
- 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
302
- 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
303
- 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
304
- 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
305
- 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
306
- 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
307
- 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
308
- 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
309
- 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
310
- 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
311
- 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
312
- 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
313
- 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
314
- );
315
-
316
- /**
317
- * P-Array consists of 18 32-bit subkeys
318
- *
319
- * @var array
320
- * @access private
321
- */
322
- var $parray = array(
323
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
324
- 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
325
- 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
326
- );
327
-
328
- /**
329
- * The BCTX-working Array
330
- *
331
- * Holds the expanded key [p] and the key-depended s-boxes [sb]
332
- *
333
- * @var array
334
- * @access private
335
- */
336
- var $bctx;
337
-
338
- /**
339
- * Holds the last used key
340
- *
341
- * @var array
342
- * @access private
343
- */
344
- var $kl;
345
-
346
- /**
347
- * The Key Length (in bytes)
348
- *
349
- * @see Crypt_Base::setKeyLength()
350
- * @var int
351
- * @access private
352
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
353
- * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
354
- * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
355
- * of that, we'll just precompute it once.
356
- */
357
- var $key_length = 16;
358
-
359
- /**
360
- * Sets the key length.
361
- *
362
- * Key lengths can be between 32 and 448 bits.
363
- *
364
- * @access public
365
- * @param int $length
366
- */
367
- function setKeyLength($length)
368
- {
369
- if ($length < 32) {
370
- $this->key_length = 7;
371
- } elseif ($length > 448) {
372
- $this->key_length = 56;
373
- } else {
374
- $this->key_length = $length >> 3;
375
- }
376
-
377
- parent::setKeyLength($length);
378
- }
379
-
380
- /**
381
- * Test for engine validity
382
- *
383
- * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
384
- *
385
- * @see Crypt_Base::isValidEngine()
386
- * @param int $engine
387
- * @access public
388
- * @return bool
389
- */
390
- function isValidEngine($engine)
391
- {
392
- if ($engine == CRYPT_ENGINE_OPENSSL) {
393
- if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
394
- return false;
395
- }
396
- if ($this->key_length < 16) {
397
- return false;
398
- }
399
- $this->cipher_name_openssl_ecb = 'bf-ecb';
400
- $this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
401
- }
402
-
403
- return parent::isValidEngine($engine);
404
- }
405
-
406
- /**
407
- * Setup the key (expansion)
408
- *
409
- * @see Crypt_Base::_setupKey()
410
- * @access private
411
- */
412
- function _setupKey()
413
- {
414
- if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
415
- // already expanded
416
- return;
417
- }
418
- $this->kl = array('key' => $this->key);
419
-
420
- /* key-expanding p[] and S-Box building sb[] */
421
- $this->bctx = array(
422
- 'p' => array(),
423
- 'sb' => array(
424
- $this->sbox0,
425
- $this->sbox1,
426
- $this->sbox2,
427
- $this->sbox3
428
- )
429
- );
430
-
431
- // unpack binary string in unsigned chars
432
- $key = array_values(unpack('C*', $this->key));
433
- $keyl = count($key);
434
- for ($j = 0, $i = 0; $i < 18; ++$i) {
435
- // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
436
- for ($data = 0, $k = 0; $k < 4; ++$k) {
437
- $data = ($data << 8) | $key[$j];
438
- if (++$j >= $keyl) {
439
- $j = 0;
440
- }
441
- }
442
- $this->bctx['p'][] = $this->parray[$i] ^ $data;
443
- }
444
-
445
- // encrypt the zero-string, replace P1 and P2 with the encrypted data,
446
- // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
447
- $data = "\0\0\0\0\0\0\0\0";
448
- for ($i = 0; $i < 18; $i += 2) {
449
- list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
450
- $this->bctx['p'][$i ] = $l;
451
- $this->bctx['p'][$i + 1] = $r;
452
- }
453
- for ($i = 0; $i < 4; ++$i) {
454
- for ($j = 0; $j < 256; $j += 2) {
455
- list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
456
- $this->bctx['sb'][$i][$j ] = $l;
457
- $this->bctx['sb'][$i][$j + 1] = $r;
458
- }
459
- }
460
- }
461
-
462
- /**
463
- * Encrypts a block
464
- *
465
- * @access private
466
- * @param string $in
467
- * @return string
468
- */
469
- function _encryptBlock($in)
470
- {
471
- $p = $this->bctx["p"];
472
- // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
473
- $sb_0 = $this->bctx["sb"][0];
474
- $sb_1 = $this->bctx["sb"][1];
475
- $sb_2 = $this->bctx["sb"][2];
476
- $sb_3 = $this->bctx["sb"][3];
477
-
478
- $in = unpack("N*", $in);
479
- $l = $in[1];
480
- $r = $in[2];
481
-
482
- for ($i = 0; $i < 16; $i+= 2) {
483
- $l^= $p[$i];
484
- $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
485
- $sb_2[$l >> 8 & 0xff]) +
486
- $sb_3[$l & 0xff]);
487
-
488
- $r^= $p[$i + 1];
489
- $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
490
- $sb_2[$r >> 8 & 0xff]) +
491
- $sb_3[$r & 0xff]);
492
- }
493
- return pack("N*", $r ^ $p[17], $l ^ $p[16]);
494
- }
495
-
496
- /**
497
- * Decrypts a block
498
- *
499
- * @access private
500
- * @param string $in
501
- * @return string
502
- */
503
- function _decryptBlock($in)
504
- {
505
- $p = $this->bctx["p"];
506
- $sb_0 = $this->bctx["sb"][0];
507
- $sb_1 = $this->bctx["sb"][1];
508
- $sb_2 = $this->bctx["sb"][2];
509
- $sb_3 = $this->bctx["sb"][3];
510
-
511
- $in = unpack("N*", $in);
512
- $l = $in[1];
513
- $r = $in[2];
514
-
515
- for ($i = 17; $i > 2; $i-= 2) {
516
- $l^= $p[$i];
517
- $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
518
- $sb_2[$l >> 8 & 0xff]) +
519
- $sb_3[$l & 0xff]);
520
-
521
- $r^= $p[$i - 1];
522
- $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
523
- $sb_2[$r >> 8 & 0xff]) +
524
- $sb_3[$r & 0xff]);
525
- }
526
- return pack("N*", $r ^ $p[0], $l ^ $p[1]);
527
- }
528
-
529
- /**
530
- * Setup the performance-optimized function for de/encrypt()
531
- *
532
- * @see Crypt_Base::_setupInlineCrypt()
533
- * @access private
534
- */
535
- function _setupInlineCrypt()
536
- {
537
- $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
538
-
539
- // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
540
- // (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
541
- // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
542
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
543
-
544
- // Generation of a unique hash for our generated code
545
- $code_hash = "Crypt_Blowfish, {$this->mode}";
546
- if ($gen_hi_opt_code) {
547
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
548
- }
549
-
550
- // on 32-bit linux systems with PHP < 5.3 float to integer conversion is bad
551
- switch (true) {
552
- case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
553
- case version_compare(PHP_VERSION, '5.3.0') >= 0:
554
- case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
555
- $safeint = '%s';
556
- break;
557
- default:
558
- $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
559
- $safeint.= '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
560
- }
561
-
562
- if (!isset($lambda_functions[$code_hash])) {
563
- switch (true) {
564
- case $gen_hi_opt_code:
565
- $p = $this->bctx['p'];
566
- $init_crypt = '
567
- static $sb_0, $sb_1, $sb_2, $sb_3;
568
- if (!$sb_0) {
569
- $sb_0 = $self->bctx["sb"][0];
570
- $sb_1 = $self->bctx["sb"][1];
571
- $sb_2 = $self->bctx["sb"][2];
572
- $sb_3 = $self->bctx["sb"][3];
573
- }
574
- ';
575
- break;
576
- default:
577
- $p = array();
578
- for ($i = 0; $i < 18; ++$i) {
579
- $p[] = '$p_' . $i;
580
- }
581
- $init_crypt = '
582
- list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
583
- list(' . implode(',', $p) . ') = $self->bctx["p"];
584
-
585
- ';
586
- }
587
-
588
- // Generating encrypt code:
589
- $encrypt_block = '
590
- $in = unpack("N*", $in);
591
- $l = $in[1];
592
- $r = $in[2];
593
- ';
594
- for ($i = 0; $i < 16; $i+= 2) {
595
- $encrypt_block.= '
596
- $l^= ' . $p[$i] . ';
597
- $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
598
- $sb_2[$l >> 8 & 0xff]) +
599
- $sb_3[$l & 0xff]') . ';
600
-
601
- $r^= ' . $p[$i + 1] . ';
602
- $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
603
- $sb_2[$r >> 8 & 0xff]) +
604
- $sb_3[$r & 0xff]') . ';
605
- ';
606
- }
607
- $encrypt_block.= '
608
- $in = pack("N*",
609
- $r ^ ' . $p[17] . ',
610
- $l ^ ' . $p[16] . '
611
- );
612
- ';
613
-
614
- // Generating decrypt code:
615
- $decrypt_block = '
616
- $in = unpack("N*", $in);
617
- $l = $in[1];
618
- $r = $in[2];
619
- ';
620
-
621
- for ($i = 17; $i > 2; $i-= 2) {
622
- $decrypt_block.= '
623
- $l^= ' . $p[$i] . ';
624
- $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
625
- $sb_2[$l >> 8 & 0xff]) +
626
- $sb_3[$l & 0xff]') . ';
627
-
628
- $r^= ' . $p[$i - 1] . ';
629
- $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
630
- $sb_2[$r >> 8 & 0xff]) +
631
- $sb_3[$r & 0xff]') . ';
632
- ';
633
- }
634
-
635
- $decrypt_block.= '
636
- $in = pack("N*",
637
- $r ^ ' . $p[0] . ',
638
- $l ^ ' . $p[1] . '
639
- );
640
- ';
641
-
642
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
643
- array(
644
- 'init_crypt' => $init_crypt,
645
- 'init_encrypt' => '',
646
- 'init_decrypt' => '',
647
- 'encrypt_block' => $encrypt_block,
648
- 'decrypt_block' => $decrypt_block
649
- )
650
- );
651
- }
652
- $this->inline_crypt = $lambda_functions[$code_hash];
653
- }
654
-
655
- /**
656
- * Convert float to int
657
- *
658
- * On 32-bit Linux installs running PHP < 5.3 converting floats to ints doesn't always work
659
- *
660
- * @access private
661
- * @param string $x
662
- * @return int
663
- */
664
- function safe_intval($x)
665
- {
666
- // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
667
- // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
668
- if (is_int($x) || version_compare(PHP_VERSION, '5.3.0') >= 0 || (PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
669
- return $x;
670
- }
671
- return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
672
- ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
673
- }
674
- }
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of Blowfish.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Useful resources are as follows:
11
+ *
12
+ * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
13
+ *
14
+ * Here's a short example of how to use this library:
15
+ * <code>
16
+ * <?php
17
+ * include 'Crypt/Blowfish.php';
18
+ *
19
+ * $blowfish = new Crypt_Blowfish();
20
+ *
21
+ * $blowfish->setKey('12345678901234567890123456789012');
22
+ *
23
+ * $plaintext = str_repeat('a', 1024);
24
+ *
25
+ * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
26
+ * ?>
27
+ * </code>
28
+ *
29
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ * of this software and associated documentation files (the "Software"), to deal
31
+ * in the Software without restriction, including without limitation the rights
32
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ * copies of the Software, and to permit persons to whom the Software is
34
+ * furnished to do so, subject to the following conditions:
35
+ *
36
+ * The above copyright notice and this permission notice shall be included in
37
+ * all copies or substantial portions of the Software.
38
+ *
39
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ * THE SOFTWARE.
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_Blowfish
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
+ * @copyright 2007 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_Base
58
+ *
59
+ * Base cipher class
60
+ */
61
+ if (!class_exists('Crypt_Base')) {
62
+ include_once 'Base.php';
63
+ }
64
+
65
+ /**#@+
66
+ * @access public
67
+ * @see self::encrypt()
68
+ * @see self::decrypt()
69
+ */
70
+ /**
71
+ * Encrypt / decrypt using the Counter mode.
72
+ *
73
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
+ *
75
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
+ */
77
+ define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR);
78
+ /**
79
+ * Encrypt / decrypt using the Electronic Code Book mode.
80
+ *
81
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
+ */
83
+ define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB);
84
+ /**
85
+ * Encrypt / decrypt using the Code Book Chaining mode.
86
+ *
87
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
+ */
89
+ define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC);
90
+ /**
91
+ * Encrypt / decrypt using the Cipher Feedback mode.
92
+ *
93
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
+ */
95
+ define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
96
+ /**
97
+ * Encrypt / decrypt using the Cipher Feedback mode.
98
+ *
99
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
+ */
101
+ define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
102
+ /**#@-*/
103
+
104
+ /**
105
+ * Pure-PHP implementation of Blowfish.
106
+ *
107
+ * @package Crypt_Blowfish
108
+ * @author Jim Wigginton <terrafrost@php.net>
109
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
110
+ * @access public
111
+ */
112
+ class Crypt_Blowfish extends Crypt_Base
113
+ {
114
+ /**
115
+ * Block Length of the cipher
116
+ *
117
+ * @see Crypt_Base::block_size
118
+ * @var int
119
+ * @access private
120
+ */
121
+ var $block_size = 8;
122
+
123
+ /**
124
+ * The namespace used by the cipher for its constants.
125
+ *
126
+ * @see Crypt_Base::const_namespace
127
+ * @var string
128
+ * @access private
129
+ */
130
+ var $const_namespace = 'BLOWFISH';
131
+
132
+ /**
133
+ * The mcrypt specific name of the cipher
134
+ *
135
+ * @see Crypt_Base::cipher_name_mcrypt
136
+ * @var string
137
+ * @access private
138
+ */
139
+ var $cipher_name_mcrypt = 'blowfish';
140
+
141
+ /**
142
+ * Optimizing value while CFB-encrypting
143
+ *
144
+ * @see Crypt_Base::cfb_init_len
145
+ * @var int
146
+ * @access private
147
+ */
148
+ var $cfb_init_len = 500;
149
+
150
+ /**
151
+ * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
152
+ *
153
+ * S-Box 0
154
+ *
155
+ * @access private
156
+ * @var array
157
+ */
158
+ var $sbox0 = array(
159
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
160
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
161
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
162
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
163
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
164
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
165
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
166
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
167
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
168
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
169
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
170
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
171
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
172
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
173
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
174
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
175
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
176
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
177
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
178
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
179
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
180
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
181
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
182
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
183
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
184
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
185
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
186
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
187
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
188
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
189
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
190
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
191
+ );
192
+
193
+ /**
194
+ * S-Box 1
195
+ *
196
+ * @access private
197
+ * @var array
198
+ */
199
+ var $sbox1 = array(
200
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
201
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
202
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
203
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
204
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
205
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
206
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
207
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
208
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
209
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
210
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
211
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
212
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
213
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
214
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
215
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
216
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
217
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
218
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
219
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
220
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
221
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
222
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
223
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
224
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
225
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
226
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
227
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
228
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
229
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
230
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
231
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
232
+ );
233
+
234
+ /**
235
+ * S-Box 2
236
+ *
237
+ * @access private
238
+ * @var array
239
+ */
240
+ var $sbox2 = array(
241
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
242
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
243
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
244
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
245
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
246
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
247
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
248
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
249
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
250
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
251
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
252
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
253
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
254
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
255
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
256
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
257
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
258
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
259
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
260
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
261
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
262
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
263
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
264
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
265
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
266
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
267
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
268
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
269
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
270
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
271
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
272
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
273
+ );
274
+
275
+ /**
276
+ * S-Box 3
277
+ *
278
+ * @access private
279
+ * @var array
280
+ */
281
+ var $sbox3 = array(
282
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
283
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
284
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
285
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
286
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
287
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
288
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
289
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
290
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
291
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
292
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
293
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
294
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
295
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
296
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
297
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
298
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
299
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
300
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
301
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
302
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
303
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
304
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
305
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
306
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
307
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
308
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
309
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
310
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
311
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
312
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
313
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
314
+ );
315
+
316
+ /**
317
+ * P-Array consists of 18 32-bit subkeys
318
+ *
319
+ * @var array
320
+ * @access private
321
+ */
322
+ var $parray = array(
323
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
324
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
325
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
326
+ );
327
+
328
+ /**
329
+ * The BCTX-working Array
330
+ *
331
+ * Holds the expanded key [p] and the key-depended s-boxes [sb]
332
+ *
333
+ * @var array
334
+ * @access private
335
+ */
336
+ var $bctx;
337
+
338
+ /**
339
+ * Holds the last used key
340
+ *
341
+ * @var array
342
+ * @access private
343
+ */
344
+ var $kl;
345
+
346
+ /**
347
+ * The Key Length (in bytes)
348
+ *
349
+ * @see Crypt_Base::setKeyLength()
350
+ * @var int
351
+ * @access private
352
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
353
+ * because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
354
+ * derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
355
+ * of that, we'll just precompute it once.
356
+ */
357
+ var $key_length = 16;
358
+
359
+ /**
360
+ * Sets the key length.
361
+ *
362
+ * Key lengths can be between 32 and 448 bits.
363
+ *
364
+ * @access public
365
+ * @param int $length
366
+ */
367
+ function setKeyLength($length)
368
+ {
369
+ if ($length < 32) {
370
+ $this->key_length = 4;
371
+ } elseif ($length > 448) {
372
+ $this->key_length = 56;
373
+ } else {
374
+ $this->key_length = $length >> 3;
375
+ }
376
+
377
+ parent::setKeyLength($length);
378
+ }
379
+
380
+ /**
381
+ * Test for engine validity
382
+ *
383
+ * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
384
+ *
385
+ * @see Crypt_Base::isValidEngine()
386
+ * @param int $engine
387
+ * @access public
388
+ * @return bool
389
+ */
390
+ function isValidEngine($engine)
391
+ {
392
+ if ($engine == CRYPT_ENGINE_OPENSSL) {
393
+ if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
394
+ return false;
395
+ }
396
+ if ($this->key_length < 16) {
397
+ return false;
398
+ }
399
+ $this->cipher_name_openssl_ecb = 'bf-ecb';
400
+ $this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
401
+ }
402
+
403
+ return parent::isValidEngine($engine);
404
+ }
405
+
406
+ /**
407
+ * Setup the key (expansion)
408
+ *
409
+ * @see Crypt_Base::_setupKey()
410
+ * @access private
411
+ */
412
+ function _setupKey()
413
+ {
414
+ if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
415
+ // already expanded
416
+ return;
417
+ }
418
+ $this->kl = array('key' => $this->key);
419
+
420
+ /* key-expanding p[] and S-Box building sb[] */
421
+ $this->bctx = array(
422
+ 'p' => array(),
423
+ 'sb' => array(
424
+ $this->sbox0,
425
+ $this->sbox1,
426
+ $this->sbox2,
427
+ $this->sbox3
428
+ )
429
+ );
430
+
431
+ // unpack binary string in unsigned chars
432
+ $key = array_values(unpack('C*', $this->key));
433
+ $keyl = count($key);
434
+ for ($j = 0, $i = 0; $i < 18; ++$i) {
435
+ // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
436
+ for ($data = 0, $k = 0; $k < 4; ++$k) {
437
+ $data = ($data << 8) | $key[$j];
438
+ if (++$j >= $keyl) {
439
+ $j = 0;
440
+ }
441
+ }
442
+ $this->bctx['p'][] = $this->parray[$i] ^ $data;
443
+ }
444
+
445
+ // encrypt the zero-string, replace P1 and P2 with the encrypted data,
446
+ // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
447
+ $data = "\0\0\0\0\0\0\0\0";
448
+ for ($i = 0; $i < 18; $i += 2) {
449
+ list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
450
+ $this->bctx['p'][$i ] = $l;
451
+ $this->bctx['p'][$i + 1] = $r;
452
+ }
453
+ for ($i = 0; $i < 4; ++$i) {
454
+ for ($j = 0; $j < 256; $j += 2) {
455
+ list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
456
+ $this->bctx['sb'][$i][$j ] = $l;
457
+ $this->bctx['sb'][$i][$j + 1] = $r;
458
+ }
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Encrypts a block
464
+ *
465
+ * @access private
466
+ * @param string $in
467
+ * @return string
468
+ */
469
+ function _encryptBlock($in)
470
+ {
471
+ $p = $this->bctx["p"];
472
+ // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
473
+ $sb_0 = $this->bctx["sb"][0];
474
+ $sb_1 = $this->bctx["sb"][1];
475
+ $sb_2 = $this->bctx["sb"][2];
476
+ $sb_3 = $this->bctx["sb"][3];
477
+
478
+ $in = unpack("N*", $in);
479
+ $l = $in[1];
480
+ $r = $in[2];
481
+
482
+ for ($i = 0; $i < 16; $i+= 2) {
483
+ $l^= $p[$i];
484
+ $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
485
+ $sb_2[$l >> 8 & 0xff]) +
486
+ $sb_3[$l & 0xff]);
487
+
488
+ $r^= $p[$i + 1];
489
+ $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
490
+ $sb_2[$r >> 8 & 0xff]) +
491
+ $sb_3[$r & 0xff]);
492
+ }
493
+ return pack("N*", $r ^ $p[17], $l ^ $p[16]);
494
+ }
495
+
496
+ /**
497
+ * Decrypts a block
498
+ *
499
+ * @access private
500
+ * @param string $in
501
+ * @return string
502
+ */
503
+ function _decryptBlock($in)
504
+ {
505
+ $p = $this->bctx["p"];
506
+ $sb_0 = $this->bctx["sb"][0];
507
+ $sb_1 = $this->bctx["sb"][1];
508
+ $sb_2 = $this->bctx["sb"][2];
509
+ $sb_3 = $this->bctx["sb"][3];
510
+
511
+ $in = unpack("N*", $in);
512
+ $l = $in[1];
513
+ $r = $in[2];
514
+
515
+ for ($i = 17; $i > 2; $i-= 2) {
516
+ $l^= $p[$i];
517
+ $r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
518
+ $sb_2[$l >> 8 & 0xff]) +
519
+ $sb_3[$l & 0xff]);
520
+
521
+ $r^= $p[$i - 1];
522
+ $l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
523
+ $sb_2[$r >> 8 & 0xff]) +
524
+ $sb_3[$r & 0xff]);
525
+ }
526
+ return pack("N*", $r ^ $p[0], $l ^ $p[1]);
527
+ }
528
+
529
+ /**
530
+ * Setup the performance-optimized function for de/encrypt()
531
+ *
532
+ * @see Crypt_Base::_setupInlineCrypt()
533
+ * @access private
534
+ */
535
+ function _setupInlineCrypt()
536
+ {
537
+ $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
538
+
539
+ // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
540
+ // (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
541
+ // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
542
+ $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
543
+
544
+ // Generation of a unique hash for our generated code
545
+ $code_hash = "Crypt_Blowfish, {$this->mode}";
546
+ if ($gen_hi_opt_code) {
547
+ $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
548
+ }
549
+
550
+ $safeint = $this->safe_intval_inline();
551
+
552
+ if (!isset($lambda_functions[$code_hash])) {
553
+ switch (true) {
554
+ case $gen_hi_opt_code:
555
+ $p = $this->bctx['p'];
556
+ $init_crypt = '
557
+ static $sb_0, $sb_1, $sb_2, $sb_3;
558
+ if (!$sb_0) {
559
+ $sb_0 = $self->bctx["sb"][0];
560
+ $sb_1 = $self->bctx["sb"][1];
561
+ $sb_2 = $self->bctx["sb"][2];
562
+ $sb_3 = $self->bctx["sb"][3];
563
+ }
564
+ ';
565
+ break;
566
+ default:
567
+ $p = array();
568
+ for ($i = 0; $i < 18; ++$i) {
569
+ $p[] = '$p_' . $i;
570
+ }
571
+ $init_crypt = '
572
+ list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
573
+ list(' . implode(',', $p) . ') = $self->bctx["p"];
574
+
575
+ ';
576
+ }
577
+
578
+ // Generating encrypt code:
579
+ $encrypt_block = '
580
+ $in = unpack("N*", $in);
581
+ $l = $in[1];
582
+ $r = $in[2];
583
+ ';
584
+ for ($i = 0; $i < 16; $i+= 2) {
585
+ $encrypt_block.= '
586
+ $l^= ' . $p[$i] . ';
587
+ $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
588
+ $sb_2[$l >> 8 & 0xff]) +
589
+ $sb_3[$l & 0xff]') . ';
590
+
591
+ $r^= ' . $p[$i + 1] . ';
592
+ $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
593
+ $sb_2[$r >> 8 & 0xff]) +
594
+ $sb_3[$r & 0xff]') . ';
595
+ ';
596
+ }
597
+ $encrypt_block.= '
598
+ $in = pack("N*",
599
+ $r ^ ' . $p[17] . ',
600
+ $l ^ ' . $p[16] . '
601
+ );
602
+ ';
603
+
604
+ // Generating decrypt code:
605
+ $decrypt_block = '
606
+ $in = unpack("N*", $in);
607
+ $l = $in[1];
608
+ $r = $in[2];
609
+ ';
610
+
611
+ for ($i = 17; $i > 2; $i-= 2) {
612
+ $decrypt_block.= '
613
+ $l^= ' . $p[$i] . ';
614
+ $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
615
+ $sb_2[$l >> 8 & 0xff]) +
616
+ $sb_3[$l & 0xff]') . ';
617
+
618
+ $r^= ' . $p[$i - 1] . ';
619
+ $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
620
+ $sb_2[$r >> 8 & 0xff]) +
621
+ $sb_3[$r & 0xff]') . ';
622
+ ';
623
+ }
624
+
625
+ $decrypt_block.= '
626
+ $in = pack("N*",
627
+ $r ^ ' . $p[0] . ',
628
+ $l ^ ' . $p[1] . '
629
+ );
630
+ ';
631
+
632
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
633
+ array(
634
+ 'init_crypt' => $init_crypt,
635
+ 'init_encrypt' => '',
636
+ 'init_decrypt' => '',
637
+ 'encrypt_block' => $encrypt_block,
638
+ 'decrypt_block' => $decrypt_block
639
+ )
640
+ );
641
+ }
642
+ $this->inline_crypt = $lambda_functions[$code_hash];
643
+ }
644
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
phpseclib/Crypt/Hash.php CHANGED
@@ -832,10 +832,13 @@ class Crypt_Hash
832
  $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
833
  }
834
 
835
- // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
836
- // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
837
- if (is_int($result) || version_compare(PHP_VERSION, '5.3.0') >= 0 || (PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
838
- return fmod($result, $mod);
 
 
 
839
  }
840
 
841
  return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
832
  $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
833
  }
834
 
835
+ switch (true) {
836
+ case is_int($result):
837
+ // PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
838
+ case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
839
+ // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
840
+ case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
841
+ return fmod($result, $mod);
842
  }
843
 
844
  return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
phpseclib/Crypt/RC2.php ADDED
@@ -0,0 +1,761 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of RC2.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Useful resources are as follows:
11
+ *
12
+ * - {@link http://tools.ietf.org/html/rfc2268}
13
+ *
14
+ * Here's a short example of how to use this library:
15
+ * <code>
16
+ * <?php
17
+ * include 'Crypt/RC2.php';
18
+ *
19
+ * $rc2 = new Crypt_RC2();
20
+ *
21
+ * $rc2->setKey('abcdefgh');
22
+ *
23
+ * $plaintext = str_repeat('a', 1024);
24
+ *
25
+ * echo $rc2->decrypt($rc2->encrypt($plaintext));
26
+ * ?>
27
+ * </code>
28
+ *
29
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ * of this software and associated documentation files (the "Software"), to deal
31
+ * in the Software without restriction, including without limitation the rights
32
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ * copies of the Software, and to permit persons to whom the Software is
34
+ * furnished to do so, subject to the following conditions:
35
+ *
36
+ * The above copyright notice and this permission notice shall be included in
37
+ * all copies or substantial portions of the Software.
38
+ *
39
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ * THE SOFTWARE.
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_RC2
49
+ * @author Patrick Monnerat <pm@datasphere.ch>
50
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
51
+ * @link http://phpseclib.sourceforge.net
52
+ */
53
+
54
+ /**
55
+ * Include Crypt_Base
56
+ *
57
+ * Base cipher class
58
+ */
59
+ if (!class_exists('Crypt_Base')) {
60
+ include_once 'Base.php';
61
+ }
62
+
63
+ /**#@+
64
+ * @access public
65
+ * @see self::encrypt()
66
+ * @see self::decrypt()
67
+ */
68
+ /**
69
+ * Encrypt / decrypt using the Counter mode.
70
+ *
71
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
72
+ *
73
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
74
+ */
75
+ define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR);
76
+ /**
77
+ * Encrypt / decrypt using the Electronic Code Book mode.
78
+ *
79
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
80
+ */
81
+ define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB);
82
+ /**
83
+ * Encrypt / decrypt using the Code Book Chaining mode.
84
+ *
85
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
86
+ */
87
+ define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC);
88
+ /**
89
+ * Encrypt / decrypt using the Cipher Feedback mode.
90
+ *
91
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
92
+ */
93
+ define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
94
+ /**
95
+ * Encrypt / decrypt using the Cipher Feedback mode.
96
+ *
97
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
98
+ */
99
+ define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
100
+ /**#@-*/
101
+
102
+ /**
103
+ * Pure-PHP implementation of RC2.
104
+ *
105
+ * @package Crypt_RC2
106
+ * @access public
107
+ */
108
+ class Crypt_RC2 extends Crypt_Base
109
+ {
110
+ /**
111
+ * Block Length of the cipher
112
+ *
113
+ * @see Crypt_Base::block_size
114
+ * @var int
115
+ * @access private
116
+ */
117
+ var $block_size = 8;
118
+
119
+ /**
120
+ * The Key
121
+ *
122
+ * @see Crypt_Base::key
123
+ * @see self::setKey()
124
+ * @var string
125
+ * @access private
126
+ */
127
+ var $key;
128
+
129
+ /**
130
+ * The Original (unpadded) Key
131
+ *
132
+ * @see Crypt_Base::key
133
+ * @see self::setKey()
134
+ * @see self::encrypt()
135
+ * @see self::decrypt()
136
+ * @var string
137
+ * @access private
138
+ */
139
+ var $orig_key;
140
+
141
+ /**
142
+ * Don't truncate / null pad key
143
+ *
144
+ * @see Crypt_Base::_clearBuffers()
145
+ * @var bool
146
+ * @access private
147
+ */
148
+ var $skip_key_adjustment = true;
149
+
150
+ /**
151
+ * Key Length (in bytes)
152
+ *
153
+ * @see Crypt_RC2::setKeyLength()
154
+ * @var int
155
+ * @access private
156
+ */
157
+ var $key_length = 16; // = 128 bits
158
+
159
+ /**
160
+ * The namespace used by the cipher for its constants.
161
+ *
162
+ * @see Crypt_Base::const_namespace
163
+ * @var string
164
+ * @access private
165
+ */
166
+ var $const_namespace = 'RC2';
167
+
168
+ /**
169
+ * The mcrypt specific name of the cipher
170
+ *
171
+ * @see Crypt_Base::cipher_name_mcrypt
172
+ * @var string
173
+ * @access private
174
+ */
175
+ var $cipher_name_mcrypt = 'rc2';
176
+
177
+ /**
178
+ * Optimizing value while CFB-encrypting
179
+ *
180
+ * @see Crypt_Base::cfb_init_len
181
+ * @var int
182
+ * @access private
183
+ */
184
+ var $cfb_init_len = 500;
185
+
186
+ /**
187
+ * The key length in bits.
188
+ *
189
+ * @see self::setKeyLength()
190
+ * @see self::setKey()
191
+ * @var int
192
+ * @access private
193
+ * @internal Should be in range [1..1024].
194
+ * @internal Changing this value after setting the key has no effect.
195
+ */
196
+ var $default_key_length = 1024;
197
+
198
+ /**
199
+ * The key length in bits.
200
+ *
201
+ * @see self::isValidEnine()
202
+ * @see self::setKey()
203
+ * @var int
204
+ * @access private
205
+ * @internal Should be in range [1..1024].
206
+ */
207
+ var $current_key_length;
208
+
209
+ /**
210
+ * The Key Schedule
211
+ *
212
+ * @see self::_setupKey()
213
+ * @var array
214
+ * @access private
215
+ */
216
+ var $keys;
217
+
218
+ /**
219
+ * Key expansion randomization table.
220
+ * Twice the same 256-value sequence to save a modulus in key expansion.
221
+ *
222
+ * @see self::setKey()
223
+ * @var array
224
+ * @access private
225
+ */
226
+ var $pitable = array(
227
+ 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
228
+ 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
229
+ 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
230
+ 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
231
+ 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
232
+ 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
233
+ 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
234
+ 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
235
+ 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
236
+ 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
237
+ 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
238
+ 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
239
+ 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
240
+ 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
241
+ 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
242
+ 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
243
+ 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
244
+ 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
245
+ 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
246
+ 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
247
+ 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
248
+ 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
249
+ 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
250
+ 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
251
+ 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
252
+ 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
253
+ 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
254
+ 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
255
+ 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
256
+ 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
257
+ 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
258
+ 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
259
+ 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
260
+ 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
261
+ 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
262
+ 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
263
+ 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
264
+ 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
265
+ 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
266
+ 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
267
+ 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
268
+ 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
269
+ 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
270
+ 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
271
+ 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
272
+ 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
273
+ 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
274
+ 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
275
+ 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
276
+ 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
277
+ 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
278
+ 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
279
+ 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
280
+ 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
281
+ 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
282
+ 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
283
+ 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
284
+ 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
285
+ 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
286
+ 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
287
+ 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
288
+ 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
289
+ 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
290
+ 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
291
+ );
292
+
293
+ /**
294
+ * Inverse key expansion randomization table.
295
+ *
296
+ * @see self::setKey()
297
+ * @var array
298
+ * @access private
299
+ */
300
+ var $invpitable = array(
301
+ 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
302
+ 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
303
+ 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
304
+ 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
305
+ 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
306
+ 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
307
+ 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
308
+ 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
309
+ 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
310
+ 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
311
+ 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
312
+ 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
313
+ 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
314
+ 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
315
+ 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
316
+ 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
317
+ 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
318
+ 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
319
+ 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
320
+ 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
321
+ 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
322
+ 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
323
+ 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
324
+ 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
325
+ 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
326
+ 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
327
+ 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
328
+ 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
329
+ 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
330
+ 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
331
+ 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
332
+ 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
333
+ );
334
+
335
+ /**
336
+ * Test for engine validity
337
+ *
338
+ * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
339
+ *
340
+ * @see Crypt_Base::Crypt_Base()
341
+ * @param int $engine
342
+ * @access public
343
+ * @return bool
344
+ */
345
+ function isValidEngine($engine)
346
+ {
347
+ switch ($engine) {
348
+ case CRYPT_ENGINE_OPENSSL:
349
+ if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
350
+ return false;
351
+ }
352
+ $this->cipher_name_openssl_ecb = 'rc2-ecb';
353
+ $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
354
+ }
355
+
356
+ return parent::isValidEngine($engine);
357
+ }
358
+
359
+ /**
360
+ * Sets the key length.
361
+ *
362
+ * Valid key lengths are 8 to 1024.
363
+ * Calling this function after setting the key has no effect until the next
364
+ * Crypt_RC2::setKey() call.
365
+ *
366
+ * @access public
367
+ * @param int $length in bits
368
+ */
369
+ function setKeyLength($length)
370
+ {
371
+ if ($length < 8) {
372
+ $this->default_key_length = 1;
373
+ } elseif ($length > 1024) {
374
+ $this->default_key_length = 128;
375
+ } else {
376
+ $this->default_key_length = $length;
377
+ }
378
+ $this->current_key_length = $this->default_key_length;
379
+
380
+ parent::setKeyLength($length);
381
+ }
382
+
383
+ /**
384
+ * Returns the current key length
385
+ *
386
+ * @access public
387
+ * @return int
388
+ */
389
+ function getKeyLength()
390
+ {
391
+ return $this->current_key_length;
392
+ }
393
+
394
+ /**
395
+ * Sets the key.
396
+ *
397
+ * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
398
+ * strlen($key) <= 128), however, we only use the first 128 bytes if $key
399
+ * has more then 128 bytes in it, and set $key to a single null byte if
400
+ * it is empty.
401
+ *
402
+ * If the key is not explicitly set, it'll be assumed to be a single
403
+ * null byte.
404
+ *
405
+ * @see Crypt_Base::setKey()
406
+ * @access public
407
+ * @param string $key
408
+ * @param int $t1 optional Effective key length in bits.
409
+ */
410
+ function setKey($key, $t1 = 0)
411
+ {
412
+ $this->orig_key = $key;
413
+
414
+ if ($t1 <= 0) {
415
+ $t1 = $this->default_key_length;
416
+ } elseif ($t1 > 1024) {
417
+ $t1 = 1024;
418
+ }
419
+ $this->current_key_length = $t1;
420
+ // Key byte count should be 1..128.
421
+ $key = strlen($key) ? substr($key, 0, 128) : "\x00";
422
+ $t = strlen($key);
423
+
424
+ // The mcrypt RC2 implementation only supports effective key length
425
+ // of 1024 bits. It is however possible to handle effective key
426
+ // lengths in range 1..1024 by expanding the key and applying
427
+ // inverse pitable mapping to the first byte before submitting it
428
+ // to mcrypt.
429
+
430
+ // Key expansion.
431
+ $l = array_values(unpack('C*', $key));
432
+ $t8 = ($t1 + 7) >> 3;
433
+ $tm = 0xFF >> (8 * $t8 - $t1);
434
+
435
+ // Expand key.
436
+ $pitable = $this->pitable;
437
+ for ($i = $t; $i < 128; $i++) {
438
+ $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
439
+ }
440
+ $i = 128 - $t8;
441
+ $l[$i] = $pitable[$l[$i] & $tm];
442
+ while ($i--) {
443
+ $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
444
+ }
445
+
446
+ // Prepare the key for mcrypt.
447
+ $l[0] = $this->invpitable[$l[0]];
448
+ array_unshift($l, 'C*');
449
+
450
+ parent::setKey(call_user_func_array('pack', $l));
451
+ }
452
+
453
+ /**
454
+ * Encrypts a message.
455
+ *
456
+ * Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code
457
+ *
458
+ * @see self::decrypt()
459
+ * @access public
460
+ * @param string $plaintext
461
+ * @return string $ciphertext
462
+ */
463
+ function encrypt($plaintext)
464
+ {
465
+ if ($this->engine == CRYPT_ENGINE_OPENSSL) {
466
+ $temp = $this->key;
467
+ $this->key = $this->orig_key;
468
+ $result = parent::encrypt($plaintext);
469
+ $this->key = $temp;
470
+ return $result;
471
+ }
472
+
473
+ return parent::encrypt($plaintext);
474
+ }
475
+
476
+ /**
477
+ * Decrypts a message.
478
+ *
479
+ * Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code
480
+ *
481
+ * @see self::encrypt()
482
+ * @access public
483
+ * @param string $ciphertext
484
+ * @return string $plaintext
485
+ */
486
+ function decrypt($ciphertext)
487
+ {
488
+ if ($this->engine == CRYPT_ENGINE_OPENSSL) {
489
+ $temp = $this->key;
490
+ $this->key = $this->orig_key;
491
+ $result = parent::decrypt($ciphertext);
492
+ $this->key = $temp;
493
+ return $result;
494
+ }
495
+
496
+ return parent::decrypt($ciphertext);
497
+ }
498
+
499
+ /**
500
+ * Encrypts a block
501
+ *
502
+ * @see Crypt_Base::_encryptBlock()
503
+ * @see Crypt_Base::encrypt()
504
+ * @access private
505
+ * @param string $in
506
+ * @return string
507
+ */
508
+ function _encryptBlock($in)
509
+ {
510
+ list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
511
+ $keys = $this->keys;
512
+ $limit = 20;
513
+ $actions = array($limit => 44, 44 => 64);
514
+ $j = 0;
515
+
516
+ for (;;) {
517
+ // Mixing round.
518
+ $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
519
+ $r0 |= $r0 >> 16;
520
+ $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
521
+ $r1 |= $r1 >> 16;
522
+ $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
523
+ $r2 |= $r2 >> 16;
524
+ $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
525
+ $r3 |= $r3 >> 16;
526
+
527
+ if ($j === $limit) {
528
+ if ($limit === 64) {
529
+ break;
530
+ }
531
+
532
+ // Mashing round.
533
+ $r0 += $keys[$r3 & 0x3F];
534
+ $r1 += $keys[$r0 & 0x3F];
535
+ $r2 += $keys[$r1 & 0x3F];
536
+ $r3 += $keys[$r2 & 0x3F];
537
+ $limit = $actions[$limit];
538
+ }
539
+ }
540
+
541
+ return pack('vvvv', $r0, $r1, $r2, $r3);
542
+ }
543
+
544
+ /**
545
+ * Decrypts a block
546
+ *
547
+ * @see Crypt_Base::_decryptBlock()
548
+ * @see Crypt_Base::decrypt()
549
+ * @access private
550
+ * @param string $in
551
+ * @return string
552
+ */
553
+ function _decryptBlock($in)
554
+ {
555
+ list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
556
+ $keys = $this->keys;
557
+ $limit = 44;
558
+ $actions = array($limit => 20, 20 => 0);
559
+ $j = 64;
560
+
561
+ for (;;) {
562
+ // R-mixing round.
563
+ $r3 = ($r3 | ($r3 << 16)) >> 5;
564
+ $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
565
+ $r2 = ($r2 | ($r2 << 16)) >> 3;
566
+ $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
567
+ $r1 = ($r1 | ($r1 << 16)) >> 2;
568
+ $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
569
+ $r0 = ($r0 | ($r0 << 16)) >> 1;
570
+ $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
571
+
572
+ if ($j === $limit) {
573
+ if ($limit === 0) {
574
+ break;
575
+ }
576
+
577
+ // R-mashing round.
578
+ $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
579
+ $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
580
+ $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
581
+ $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
582
+ $limit = $actions[$limit];
583
+ }
584
+ }
585
+
586
+ return pack('vvvv', $r0, $r1, $r2, $r3);
587
+ }
588
+
589
+ /**
590
+ * Setup the CRYPT_ENGINE_MCRYPT $engine
591
+ *
592
+ * @see Crypt_Base::_setupMcrypt()
593
+ * @access private
594
+ */
595
+ function _setupMcrypt()
596
+ {
597
+ if (!isset($this->key)) {
598
+ $this->setKey('');
599
+ }
600
+
601
+ parent::_setupMcrypt();
602
+ }
603
+
604
+ /**
605
+ * Creates the key schedule
606
+ *
607
+ * @see Crypt_Base::_setupKey()
608
+ * @access private
609
+ */
610
+ function _setupKey()
611
+ {
612
+ if (!isset($this->key)) {
613
+ $this->setKey('');
614
+ }
615
+
616
+ // Key has already been expanded in Crypt_RC2::setKey():
617
+ // Only the first value must be altered.
618
+ $l = unpack('Ca/Cb/v*', $this->key);
619
+ array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
620
+ unset($l['a']);
621
+ unset($l['b']);
622
+ $this->keys = $l;
623
+ }
624
+
625
+ /**
626
+ * Setup the performance-optimized function for de/encrypt()
627
+ *
628
+ * @see Crypt_Base::_setupInlineCrypt()
629
+ * @access private
630
+ */
631
+ function _setupInlineCrypt()
632
+ {
633
+ $lambda_functions = &Crypt_RC2::_getLambdaFunctions();
634
+
635
+ // The first 10 generated $lambda_functions will use the $keys hardcoded as integers
636
+ // for the mixing rounds, for better inline crypt performance [~20% faster].
637
+ // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
638
+ // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
639
+ $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
640
+
641
+ // Generation of a unique hash for our generated code
642
+ $code_hash = "Crypt_RC2, {$this->mode}";
643
+ if ($gen_hi_opt_code) {
644
+ $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
645
+ }
646
+
647
+ // Is there a re-usable $lambda_functions in there?
648
+ // If not, we have to create it.
649
+ if (!isset($lambda_functions[$code_hash])) {
650
+ // Init code for both, encrypt and decrypt.
651
+ $init_crypt = '$keys = $self->keys;';
652
+
653
+ switch (true) {
654
+ case $gen_hi_opt_code:
655
+ $keys = $this->keys;
656
+ default:
657
+ $keys = array();
658
+ foreach ($this->keys as $k => $v) {
659
+ $keys[$k] = '$keys[' . $k . ']';
660
+ }
661
+ }
662
+
663
+ // $in is the current 8 bytes block which has to be en/decrypt
664
+ $encrypt_block = $decrypt_block = '
665
+ $in = unpack("v4", $in);
666
+ $r0 = $in[1];
667
+ $r1 = $in[2];
668
+ $r2 = $in[3];
669
+ $r3 = $in[4];
670
+ ';
671
+
672
+ // Create code for encryption.
673
+ $limit = 20;
674
+ $actions = array($limit => 44, 44 => 64);
675
+ $j = 0;
676
+
677
+ for (;;) {
678
+ // Mixing round.
679
+ $encrypt_block .= '
680
+ $r0 = (($r0 + ' . $keys[$j++] . ' +
681
+ ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
682
+ $r0 |= $r0 >> 16;
683
+ $r1 = (($r1 + ' . $keys[$j++] . ' +
684
+ ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
685
+ $r1 |= $r1 >> 16;
686
+ $r2 = (($r2 + ' . $keys[$j++] . ' +
687
+ ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
688
+ $r2 |= $r2 >> 16;
689
+ $r3 = (($r3 + ' . $keys[$j++] . ' +
690
+ ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
691
+ $r3 |= $r3 >> 16;';
692
+
693
+ if ($j === $limit) {
694
+ if ($limit === 64) {
695
+ break;
696
+ }
697
+
698
+ // Mashing round.
699
+ $encrypt_block .= '
700
+ $r0 += $keys[$r3 & 0x3F];
701
+ $r1 += $keys[$r0 & 0x3F];
702
+ $r2 += $keys[$r1 & 0x3F];
703
+ $r3 += $keys[$r2 & 0x3F];';
704
+ $limit = $actions[$limit];
705
+ }
706
+ }
707
+
708
+ $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
709
+
710
+ // Create code for decryption.
711
+ $limit = 44;
712
+ $actions = array($limit => 20, 20 => 0);
713
+ $j = 64;
714
+
715
+ for (;;) {
716
+ // R-mixing round.
717
+ $decrypt_block .= '
718
+ $r3 = ($r3 | ($r3 << 16)) >> 5;
719
+ $r3 = ($r3 - ' . $keys[--$j] . ' -
720
+ ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
721
+ $r2 = ($r2 | ($r2 << 16)) >> 3;
722
+ $r2 = ($r2 - ' . $keys[--$j] . ' -
723
+ ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
724
+ $r1 = ($r1 | ($r1 << 16)) >> 2;
725
+ $r1 = ($r1 - ' . $keys[--$j] . ' -
726
+ ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
727
+ $r0 = ($r0 | ($r0 << 16)) >> 1;
728
+ $r0 = ($r0 - ' . $keys[--$j] . ' -
729
+ ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
730
+
731
+ if ($j === $limit) {
732
+ if ($limit === 0) {
733
+ break;
734
+ }
735
+
736
+ // R-mashing round.
737
+ $decrypt_block .= '
738
+ $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
739
+ $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
740
+ $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
741
+ $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
742
+ $limit = $actions[$limit];
743
+ }
744
+ }
745
+
746
+ $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
747
+
748
+ // Creates the inline-crypt function
749
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
750
+ array(
751
+ 'init_crypt' => $init_crypt,
752
+ 'encrypt_block' => $encrypt_block,
753
+ 'decrypt_block' => $decrypt_block
754
+ )
755
+ );
756
+ }
757
+
758
+ // Set the inline-crypt function as callback in: $this->inline_crypt
759
+ $this->inline_crypt = $lambda_functions[$code_hash];
760
+ }
761
+ }
phpseclib/Crypt/Random.php CHANGED
@@ -67,6 +67,10 @@ if (!function_exists('crypt_random_string')) {
67
  */
68
  function crypt_random_string($length)
69
  {
 
 
 
 
70
  if (CRYPT_RANDOM_IS_WINDOWS) {
71
  // method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows
72
  if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
67
  */
68
  function crypt_random_string($length)
69
  {
70
+ if (!$length) {
71
+ return '';
72
+ }
73
+
74
  if (CRYPT_RANDOM_IS_WINDOWS) {
75
  // method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows
76
  if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
phpseclib/Crypt/Twofish.php CHANGED
@@ -1,881 +1,889 @@
1
- <?php
2
-
3
- /**
4
- * Pure-PHP implementation of Twofish.
5
- *
6
- * Uses mcrypt, if available, and an internal implementation, otherwise.
7
- *
8
- * PHP versions 4 and 5
9
- *
10
- * Useful resources are as follows:
11
- *
12
- * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
13
- *
14
- * Here's a short example of how to use this library:
15
- * <code>
16
- * <?php
17
- * include 'Crypt/Twofish.php';
18
- *
19
- * $twofish = new Crypt_Twofish();
20
- *
21
- * $twofish->setKey('12345678901234567890123456789012');
22
- *
23
- * $plaintext = str_repeat('a', 1024);
24
- *
25
- * echo $twofish->decrypt($twofish->encrypt($plaintext));
26
- * ?>
27
- * </code>
28
- *
29
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
- * of this software and associated documentation files (the "Software"), to deal
31
- * in the Software without restriction, including without limitation the rights
32
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
- * copies of the Software, and to permit persons to whom the Software is
34
- * furnished to do so, subject to the following conditions:
35
- *
36
- * The above copyright notice and this permission notice shall be included in
37
- * all copies or substantial portions of the Software.
38
- *
39
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
- * THE SOFTWARE.
46
- *
47
- * @category Crypt
48
- * @package Crypt_Twofish
49
- * @author Jim Wigginton <terrafrost@php.net>
50
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
- * @copyright 2007 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_Base
58
- *
59
- * Base cipher class
60
- */
61
- if (!class_exists('Crypt_Base')) {
62
- include_once 'Base.php';
63
- }
64
-
65
- /**#@+
66
- * @access public
67
- * @see self::encrypt()
68
- * @see self::decrypt()
69
- */
70
- /**
71
- * Encrypt / decrypt using the Counter mode.
72
- *
73
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
- *
75
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
- */
77
- define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR);
78
- /**
79
- * Encrypt / decrypt using the Electronic Code Book mode.
80
- *
81
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
- */
83
- define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB);
84
- /**
85
- * Encrypt / decrypt using the Code Book Chaining mode.
86
- *
87
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
- */
89
- define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC);
90
- /**
91
- * Encrypt / decrypt using the Cipher Feedback mode.
92
- *
93
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
- */
95
- define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
96
- /**
97
- * Encrypt / decrypt using the Cipher Feedback mode.
98
- *
99
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
- */
101
- define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
102
- /**#@-*/
103
-
104
- /**
105
- * Pure-PHP implementation of Twofish.
106
- *
107
- * @package Crypt_Twofish
108
- * @author Jim Wigginton <terrafrost@php.net>
109
- * @author Hans-Juergen Petrich <petrich@tronic-media.com>
110
- * @access public
111
- */
112
- class Crypt_Twofish extends Crypt_Base
113
- {
114
- /**
115
- * The namespace used by the cipher for its constants.
116
- *
117
- * @see Crypt_Base::const_namespace
118
- * @var string
119
- * @access private
120
- */
121
- var $const_namespace = 'TWOFISH';
122
-
123
- /**
124
- * The mcrypt specific name of the cipher
125
- *
126
- * @see Crypt_Base::cipher_name_mcrypt
127
- * @var string
128
- * @access private
129
- */
130
- var $cipher_name_mcrypt = 'twofish';
131
-
132
- /**
133
- * Optimizing value while CFB-encrypting
134
- *
135
- * @see Crypt_Base::cfb_init_len
136
- * @var int
137
- * @access private
138
- */
139
- var $cfb_init_len = 800;
140
-
141
- /**
142
- * Q-Table
143
- *
144
- * @var array
145
- * @access private
146
- */
147
- var $q0 = array(
148
- 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
149
- 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
150
- 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
151
- 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
152
- 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
153
- 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
154
- 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
155
- 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
156
- 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
157
- 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
158
- 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
159
- 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
160
- 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
161
- 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
162
- 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
163
- 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
164
- 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
165
- 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
166
- 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
167
- 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
168
- 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
169
- 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
170
- 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
171
- 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
172
- 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
173
- 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
174
- 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
175
- 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
176
- 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
177
- 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
178
- 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
179
- 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
180
- );
181
-
182
- /**
183
- * Q-Table
184
- *
185
- * @var array
186
- * @access private
187
- */
188
- var $q1 = array(
189
- 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
190
- 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
191
- 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
192
- 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
193
- 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
194
- 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
195
- 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
196
- 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
197
- 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
198
- 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
199
- 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
200
- 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
201
- 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
202
- 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
203
- 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
204
- 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
205
- 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
206
- 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
207
- 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
208
- 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
209
- 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
210
- 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
211
- 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
212
- 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
213
- 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
214
- 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
215
- 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
216
- 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
217
- 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
218
- 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
219
- 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
220
- 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
221
- );
222
-
223
- /**
224
- * M-Table
225
- *
226
- * @var array
227
- * @access private
228
- */
229
- var $m0 = array(
230
- 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
231
- 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
232
- 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
233
- 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
234
- 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
235
- 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
236
- 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
237
- 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
238
- 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
239
- 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
240
- 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
241
- 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
242
- 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
243
- 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
244
- 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
245
- 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
246
- 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
247
- 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
248
- 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
249
- 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
250
- 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
251
- 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
252
- 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
253
- 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
254
- 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
255
- 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
256
- 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
257
- 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
258
- 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
259
- 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
260
- 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
261
- 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
262
- );
263
-
264
- /**
265
- * M-Table
266
- *
267
- * @var array
268
- * @access private
269
- */
270
- var $m1 = array(
271
- 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
272
- 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
273
- 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
274
- 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
275
- 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
276
- 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
277
- 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
278
- 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
279
- 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
280
- 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
281
- 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
282
- 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
283
- 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
284
- 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
285
- 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
286
- 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
287
- 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
288
- 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
289
- 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
290
- 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
291
- 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
292
- 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
293
- 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
294
- 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
295
- 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
296
- 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
297
- 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
298
- 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
299
- 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
300
- 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
301
- 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
302
- 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
303
- );
304
-
305
- /**
306
- * M-Table
307
- *
308
- * @var array
309
- * @access private
310
- */
311
- var $m2 = array(
312
- 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
313
- 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
314
- 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
315
- 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
316
- 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
317
- 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
318
- 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
319
- 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
320
- 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
321
- 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
322
- 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
323
- 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
324
- 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
325
- 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
326
- 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
327
- 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
328
- 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
329
- 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
330
- 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
331
- 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
332
- 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
333
- 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
334
- 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
335
- 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
336
- 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
337
- 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
338
- 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
339
- 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
340
- 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
341
- 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
342
- 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
343
- 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
344
- );
345
-
346
- /**
347
- * M-Table
348
- *
349
- * @var array
350
- * @access private
351
- */
352
- var $m3 = array(
353
- 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
354
- 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
355
- 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
356
- 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
357
- 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
358
- 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
359
- 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
360
- 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
361
- 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
362
- 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
363
- 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
364
- 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
365
- 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
366
- 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
367
- 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
368
- 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
369
- 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
370
- 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
371
- 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
372
- 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
373
- 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
374
- 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
375
- 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
376
- 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
377
- 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
378
- 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
379
- 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
380
- 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
381
- 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
382
- 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
383
- 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
384
- 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
385
- );
386
-
387
- /**
388
- * The Key Schedule Array
389
- *
390
- * @var array
391
- * @access private
392
- */
393
- var $K = array();
394
-
395
- /**
396
- * The Key depended S-Table 0
397
- *
398
- * @var array
399
- * @access private
400
- */
401
- var $S0 = array();
402
-
403
- /**
404
- * The Key depended S-Table 1
405
- *
406
- * @var array
407
- * @access private
408
- */
409
- var $S1 = array();
410
-
411
- /**
412
- * The Key depended S-Table 2
413
- *
414
- * @var array
415
- * @access private
416
- */
417
- var $S2 = array();
418
-
419
- /**
420
- * The Key depended S-Table 3
421
- *
422
- * @var array
423
- * @access private
424
- */
425
- var $S3 = array();
426
-
427
- /**
428
- * Holds the last used key
429
- *
430
- * @var array
431
- * @access private
432
- */
433
- var $kl;
434
-
435
- /**
436
- * The Key Length (in bytes)
437
- *
438
- * @see Crypt_Twofish::setKeyLength()
439
- * @var int
440
- * @access private
441
- */
442
- var $key_length = 16;
443
-
444
- /**
445
- * Sets the key length.
446
- *
447
- * Valid key lengths are 128, 192 or 256 bits
448
- *
449
- * @access public
450
- * @param int $length
451
- */
452
- function setKeyLength($length)
453
- {
454
- switch (true) {
455
- case $length <= 128:
456
- $this->key_length = 16;
457
- break;
458
- case $length <= 192:
459
- $this->key_length = 24;
460
- break;
461
- default:
462
- $this->key_length = 32;
463
- }
464
-
465
- parent::setKeyLength($length);
466
- }
467
-
468
- /**
469
- * Setup the key (expansion)
470
- *
471
- * @see Crypt_Base::_setupKey()
472
- * @access private
473
- */
474
- function _setupKey()
475
- {
476
- if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
477
- // already expanded
478
- return;
479
- }
480
- $this->kl = array('key' => $this->key);
481
-
482
- /* Key expanding and generating the key-depended s-boxes */
483
- $le_longs = unpack('V*', $this->key);
484
- $key = unpack('C*', $this->key);
485
- $m0 = $this->m0;
486
- $m1 = $this->m1;
487
- $m2 = $this->m2;
488
- $m3 = $this->m3;
489
- $q0 = $this->q0;
490
- $q1 = $this->q1;
491
-
492
- $K = $S0 = $S1 = $S2 = $S3 = array();
493
-
494
- switch (strlen($this->key)) {
495
- case 16:
496
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
497
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
498
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
499
- $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
500
- $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
501
- $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
502
- $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
503
- $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
504
- $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
505
- $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
506
- $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
507
- $B = ($B << 8) | ($B >> 24 & 0xff);
508
- $K[] = $A+= $B;
509
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
510
- }
511
- for ($i = 0; $i < 256; ++$i) {
512
- $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
513
- $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
514
- $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
515
- $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
516
- }
517
- break;
518
- case 24:
519
- list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
520
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
521
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
522
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
523
- $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
524
- $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
525
- $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
526
- $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
527
- $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
528
- $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
529
- $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
530
- $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
531
- $B = ($B << 8) | ($B >> 24 & 0xff);
532
- $K[] = $A+= $B;
533
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
534
- }
535
- for ($i = 0; $i < 256; ++$i) {
536
- $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
537
- $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
538
- $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
539
- $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
540
- }
541
- break;
542
- default: // 32
543
- list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
544
- list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
545
- list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
546
- list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
547
- for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
548
- $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
549
- $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
550
- $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
551
- $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
552
- $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
553
- $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
554
- $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
555
- $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
556
- $B = ($B << 8) | ($B >> 24 & 0xff);
557
- $K[] = $A+= $B;
558
- $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
559
- }
560
- for ($i = 0; $i < 256; ++$i) {
561
- $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
562
- $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
563
- $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
564
- $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
565
- }
566
- }
567
-
568
- $this->K = $K;
569
- $this->S0 = $S0;
570
- $this->S1 = $S1;
571
- $this->S2 = $S2;
572
- $this->S3 = $S3;
573
- }
574
-
575
- /**
576
- * _mdsrem function using by the twofish cipher algorithm
577
- *
578
- * @access private
579
- * @param string $A
580
- * @param string $B
581
- * @return array
582
- */
583
- function _mdsrem($A, $B)
584
- {
585
- // No gain by unrolling this loop.
586
- for ($i = 0; $i < 8; ++$i) {
587
- // Get most significant coefficient.
588
- $t = 0xff & ($B >> 24);
589
-
590
- // Shift the others up.
591
- $B = ($B << 8) | (0xff & ($A >> 24));
592
- $A<<= 8;
593
-
594
- $u = $t << 1;
595
-
596
- // Subtract the modular polynomial on overflow.
597
- if ($t & 0x80) {
598
- $u^= 0x14d;
599
- }
600
-
601
- // Remove t * (a * x^2 + 1).
602
- $B ^= $t ^ ($u << 16);
603
-
604
- // Form u = a*t + t/a = t*(a + 1/a).
605
- $u^= 0x7fffffff & ($t >> 1);
606
-
607
- // Add the modular polynomial on underflow.
608
- if ($t & 0x01) {
609
- $u^= 0xa6 ;
610
- }
611
-
612
- // Remove t * (a + 1/a) * (x^3 + x).
613
- $B^= ($u << 24) | ($u << 8);
614
- }
615
-
616
- return array(
617
- 0xff & $B >> 24,
618
- 0xff & $B >> 16,
619
- 0xff & $B >> 8,
620
- 0xff & $B);
621
- }
622
-
623
- /**
624
- * Encrypts a block
625
- *
626
- * @access private
627
- * @param string $in
628
- * @return string
629
- */
630
- function _encryptBlock($in)
631
- {
632
- $S0 = $this->S0;
633
- $S1 = $this->S1;
634
- $S2 = $this->S2;
635
- $S3 = $this->S3;
636
- $K = $this->K;
637
-
638
- $in = unpack("V4", $in);
639
- $R0 = $K[0] ^ $in[1];
640
- $R1 = $K[1] ^ $in[2];
641
- $R2 = $K[2] ^ $in[3];
642
- $R3 = $K[3] ^ $in[4];
643
-
644
- $ki = 7;
645
- while ($ki < 39) {
646
- $t0 = $S0[ $R0 & 0xff] ^
647
- $S1[($R0 >> 8) & 0xff] ^
648
- $S2[($R0 >> 16) & 0xff] ^
649
- $S3[($R0 >> 24) & 0xff];
650
- $t1 = $S0[($R1 >> 24) & 0xff] ^
651
- $S1[ $R1 & 0xff] ^
652
- $S2[($R1 >> 8) & 0xff] ^
653
- $S3[($R1 >> 16) & 0xff];
654
- $R2^= $t0 + $t1 + $K[++$ki];
655
- $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
656
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
657
-
658
- $t0 = $S0[ $R2 & 0xff] ^
659
- $S1[($R2 >> 8) & 0xff] ^
660
- $S2[($R2 >> 16) & 0xff] ^
661
- $S3[($R2 >> 24) & 0xff];
662
- $t1 = $S0[($R3 >> 24) & 0xff] ^
663
- $S1[ $R3 & 0xff] ^
664
- $S2[($R3 >> 8) & 0xff] ^
665
- $S3[($R3 >> 16) & 0xff];
666
- $R0^= ($t0 + $t1 + $K[++$ki]);
667
- $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
668
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
669
- }
670
-
671
- // @codingStandardsIgnoreStart
672
- return pack("V4", $K[4] ^ $R2,
673
- $K[5] ^ $R3,
674
- $K[6] ^ $R0,
675
- $K[7] ^ $R1);
676
- // @codingStandardsIgnoreEnd
677
- }
678
-
679
- /**
680
- * Decrypts a block
681
- *
682
- * @access private
683
- * @param string $in
684
- * @return string
685
- */
686
- function _decryptBlock($in)
687
- {
688
- $S0 = $this->S0;
689
- $S1 = $this->S1;
690
- $S2 = $this->S2;
691
- $S3 = $this->S3;
692
- $K = $this->K;
693
-
694
- $in = unpack("V4", $in);
695
- $R0 = $K[4] ^ $in[1];
696
- $R1 = $K[5] ^ $in[2];
697
- $R2 = $K[6] ^ $in[3];
698
- $R3 = $K[7] ^ $in[4];
699
-
700
- $ki = 40;
701
- while ($ki > 8) {
702
- $t0 = $S0[$R0 & 0xff] ^
703
- $S1[$R0 >> 8 & 0xff] ^
704
- $S2[$R0 >> 16 & 0xff] ^
705
- $S3[$R0 >> 24 & 0xff];
706
- $t1 = $S0[$R1 >> 24 & 0xff] ^
707
- $S1[$R1 & 0xff] ^
708
- $S2[$R1 >> 8 & 0xff] ^
709
- $S3[$R1 >> 16 & 0xff];
710
- $R3^= $t0 + ($t1 << 1) + $K[--$ki];
711
- $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
712
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
713
-
714
- $t0 = $S0[$R2 & 0xff] ^
715
- $S1[$R2 >> 8 & 0xff] ^
716
- $S2[$R2 >> 16 & 0xff] ^
717
- $S3[$R2 >> 24 & 0xff];
718
- $t1 = $S0[$R3 >> 24 & 0xff] ^
719
- $S1[$R3 & 0xff] ^
720
- $S2[$R3 >> 8 & 0xff] ^
721
- $S3[$R3 >> 16 & 0xff];
722
- $R1^= $t0 + ($t1 << 1) + $K[--$ki];
723
- $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
724
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
725
- }
726
-
727
- // @codingStandardsIgnoreStart
728
- return pack("V4", $K[0] ^ $R2,
729
- $K[1] ^ $R3,
730
- $K[2] ^ $R0,
731
- $K[3] ^ $R1);
732
- // @codingStandardsIgnoreEnd
733
- }
734
-
735
- /**
736
- * Setup the performance-optimized function for de/encrypt()
737
- *
738
- * @see Crypt_Base::_setupInlineCrypt()
739
- * @access private
740
- */
741
- function _setupInlineCrypt()
742
- {
743
- $lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
744
-
745
- // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
746
- // (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
747
- $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
748
-
749
- // Generation of a unique hash for our generated code
750
- $code_hash = "Crypt_Twofish, {$this->mode}";
751
- if ($gen_hi_opt_code) {
752
- $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
753
- }
754
-
755
- if (!isset($lambda_functions[$code_hash])) {
756
- switch (true) {
757
- case $gen_hi_opt_code:
758
- $K = $this->K;
759
- $init_crypt = '
760
- static $S0, $S1, $S2, $S3;
761
- if (!$S0) {
762
- for ($i = 0; $i < 256; ++$i) {
763
- $S0[] = (int)$self->S0[$i];
764
- $S1[] = (int)$self->S1[$i];
765
- $S2[] = (int)$self->S2[$i];
766
- $S3[] = (int)$self->S3[$i];
767
- }
768
- }
769
- ';
770
- break;
771
- default:
772
- $K = array();
773
- for ($i = 0; $i < 40; ++$i) {
774
- $K[] = '$K_' . $i;
775
- }
776
- $init_crypt = '
777
- $S0 = $self->S0;
778
- $S1 = $self->S1;
779
- $S2 = $self->S2;
780
- $S3 = $self->S3;
781
- list(' . implode(',', $K) . ') = $self->K;
782
- ';
783
- }
784
-
785
- // Generating encrypt code:
786
- $encrypt_block = '
787
- $in = unpack("V4", $in);
788
- $R0 = '.$K[0].' ^ $in[1];
789
- $R1 = '.$K[1].' ^ $in[2];
790
- $R2 = '.$K[2].' ^ $in[3];
791
- $R3 = '.$K[3].' ^ $in[4];
792
- ';
793
- for ($ki = 7, $i = 0; $i < 8; ++$i) {
794
- $encrypt_block.= '
795
- $t0 = $S0[ $R0 & 0xff] ^
796
- $S1[($R0 >> 8) & 0xff] ^
797
- $S2[($R0 >> 16) & 0xff] ^
798
- $S3[($R0 >> 24) & 0xff];
799
- $t1 = $S0[($R1 >> 24) & 0xff] ^
800
- $S1[ $R1 & 0xff] ^
801
- $S2[($R1 >> 8) & 0xff] ^
802
- $S3[($R1 >> 16) & 0xff];
803
- $R2^= ($t0 + $t1 + '.$K[++$ki].');
804
- $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
805
- $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
806
-
807
- $t0 = $S0[ $R2 & 0xff] ^
808
- $S1[($R2 >> 8) & 0xff] ^
809
- $S2[($R2 >> 16) & 0xff] ^
810
- $S3[($R2 >> 24) & 0xff];
811
- $t1 = $S0[($R3 >> 24) & 0xff] ^
812
- $S1[ $R3 & 0xff] ^
813
- $S2[($R3 >> 8) & 0xff] ^
814
- $S3[($R3 >> 16) & 0xff];
815
- $R0^= ($t0 + $t1 + '.$K[++$ki].');
816
- $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
817
- $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
818
- ';
819
- }
820
- $encrypt_block.= '
821
- $in = pack("V4", '.$K[4].' ^ $R2,
822
- '.$K[5].' ^ $R3,
823
- '.$K[6].' ^ $R0,
824
- '.$K[7].' ^ $R1);
825
- ';
826
-
827
- // Generating decrypt code:
828
- $decrypt_block = '
829
- $in = unpack("V4", $in);
830
- $R0 = '.$K[4].' ^ $in[1];
831
- $R1 = '.$K[5].' ^ $in[2];
832
- $R2 = '.$K[6].' ^ $in[3];
833
- $R3 = '.$K[7].' ^ $in[4];
834
- ';
835
- for ($ki = 40, $i = 0; $i < 8; ++$i) {
836
- $decrypt_block.= '
837
- $t0 = $S0[$R0 & 0xff] ^
838
- $S1[$R0 >> 8 & 0xff] ^
839
- $S2[$R0 >> 16 & 0xff] ^
840
- $S3[$R0 >> 24 & 0xff];
841
- $t1 = $S0[$R1 >> 24 & 0xff] ^
842
- $S1[$R1 & 0xff] ^
843
- $S2[$R1 >> 8 & 0xff] ^
844
- $S3[$R1 >> 16 & 0xff];
845
- $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
846
- $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
847
- $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
848
-
849
- $t0 = $S0[$R2 & 0xff] ^
850
- $S1[$R2 >> 8 & 0xff] ^
851
- $S2[$R2 >> 16 & 0xff] ^
852
- $S3[$R2 >> 24 & 0xff];
853
- $t1 = $S0[$R3 >> 24 & 0xff] ^
854
- $S1[$R3 & 0xff] ^
855
- $S2[$R3 >> 8 & 0xff] ^
856
- $S3[$R3 >> 16 & 0xff];
857
- $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
858
- $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
859
- $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
860
- ';
861
- }
862
- $decrypt_block.= '
863
- $in = pack("V4", '.$K[0].' ^ $R2,
864
- '.$K[1].' ^ $R3,
865
- '.$K[2].' ^ $R0,
866
- '.$K[3].' ^ $R1);
867
- ';
868
-
869
- $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
870
- array(
871
- 'init_crypt' => $init_crypt,
872
- 'init_encrypt' => '',
873
- 'init_decrypt' => '',
874
- 'encrypt_block' => $encrypt_block,
875
- 'decrypt_block' => $decrypt_block
876
- )
877
- );
878
- }
879
- $this->inline_crypt = $lambda_functions[$code_hash];
880
- }
881
- }
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of Twofish.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Useful resources are as follows:
11
+ *
12
+ * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
13
+ *
14
+ * Here's a short example of how to use this library:
15
+ * <code>
16
+ * <?php
17
+ * include 'Crypt/Twofish.php';
18
+ *
19
+ * $twofish = new Crypt_Twofish();
20
+ *
21
+ * $twofish->setKey('12345678901234567890123456789012');
22
+ *
23
+ * $plaintext = str_repeat('a', 1024);
24
+ *
25
+ * echo $twofish->decrypt($twofish->encrypt($plaintext));
26
+ * ?>
27
+ * </code>
28
+ *
29
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ * of this software and associated documentation files (the "Software"), to deal
31
+ * in the Software without restriction, including without limitation the rights
32
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ * copies of the Software, and to permit persons to whom the Software is
34
+ * furnished to do so, subject to the following conditions:
35
+ *
36
+ * The above copyright notice and this permission notice shall be included in
37
+ * all copies or substantial portions of the Software.
38
+ *
39
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ * THE SOFTWARE.
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_Twofish
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
+ * @copyright 2007 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_Base
58
+ *
59
+ * Base cipher class
60
+ */
61
+ if (!class_exists('Crypt_Base')) {
62
+ include_once 'Base.php';
63
+ }
64
+
65
+ /**#@+
66
+ * @access public
67
+ * @see self::encrypt()
68
+ * @see self::decrypt()
69
+ */
70
+ /**
71
+ * Encrypt / decrypt using the Counter mode.
72
+ *
73
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
+ *
75
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
+ */
77
+ define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR);
78
+ /**
79
+ * Encrypt / decrypt using the Electronic Code Book mode.
80
+ *
81
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
+ */
83
+ define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB);
84
+ /**
85
+ * Encrypt / decrypt using the Code Book Chaining mode.
86
+ *
87
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
+ */
89
+ define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC);
90
+ /**
91
+ * Encrypt / decrypt using the Cipher Feedback mode.
92
+ *
93
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
+ */
95
+ define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
96
+ /**
97
+ * Encrypt / decrypt using the Cipher Feedback mode.
98
+ *
99
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
+ */
101
+ define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
102
+ /**#@-*/
103
+
104
+ /**
105
+ * Pure-PHP implementation of Twofish.
106
+ *
107
+ * @package Crypt_Twofish
108
+ * @author Jim Wigginton <terrafrost@php.net>
109
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
110
+ * @access public
111
+ */
112
+ class Crypt_Twofish extends Crypt_Base
113
+ {
114
+ /**
115
+ * The namespace used by the cipher for its constants.
116
+ *
117
+ * @see Crypt_Base::const_namespace
118
+ * @var string
119
+ * @access private
120
+ */
121
+ var $const_namespace = 'TWOFISH';
122
+
123
+ /**
124
+ * The mcrypt specific name of the cipher
125
+ *
126
+ * @see Crypt_Base::cipher_name_mcrypt
127
+ * @var string
128
+ * @access private
129
+ */
130
+ var $cipher_name_mcrypt = 'twofish';
131
+
132
+ /**
133
+ * Optimizing value while CFB-encrypting
134
+ *
135
+ * @see Crypt_Base::cfb_init_len
136
+ * @var int
137
+ * @access private
138
+ */
139
+ var $cfb_init_len = 800;
140
+
141
+ /**
142
+ * Q-Table
143
+ *
144
+ * @var array
145
+ * @access private
146
+ */
147
+ var $q0 = array(
148
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
149
+ 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
150
+ 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
151
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
152
+ 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
153
+ 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
154
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
155
+ 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
156
+ 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
157
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
158
+ 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
159
+ 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
160
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
161
+ 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
162
+ 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
163
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
164
+ 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
165
+ 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
166
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
167
+ 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
168
+ 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
169
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
170
+ 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
171
+ 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
172
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
173
+ 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
174
+ 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
175
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
176
+ 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
177
+ 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
178
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
179
+ 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
180
+ );
181
+
182
+ /**
183
+ * Q-Table
184
+ *
185
+ * @var array
186
+ * @access private
187
+ */
188
+ var $q1 = array(
189
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
190
+ 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
191
+ 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
192
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
193
+ 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
194
+ 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
195
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
196
+ 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
197
+ 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
198
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
199
+ 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
200
+ 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
201
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
202
+ 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
203
+ 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
204
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
205
+ 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
206
+ 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
207
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
208
+ 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
209
+ 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
210
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
211
+ 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
212
+ 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
213
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
214
+ 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
215
+ 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
216
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
217
+ 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
218
+ 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
219
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
220
+ 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
221
+ );
222
+
223
+ /**
224
+ * M-Table
225
+ *
226
+ * @var array
227
+ * @access private
228
+ */
229
+ var $m0 = array(
230
+ 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
231
+ 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
232
+ 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
233
+ 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
234
+ 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
235
+ 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
236
+ 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
237
+ 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
238
+ 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
239
+ 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
240
+ 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
241
+ 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
242
+ 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
243
+ 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
244
+ 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
245
+ 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
246
+ 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
247
+ 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
248
+ 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
249
+ 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
250
+ 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
251
+ 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
252
+ 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
253
+ 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
254
+ 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
255
+ 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
256
+ 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
257
+ 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
258
+ 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
259
+ 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
260
+ 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
261
+ 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
262
+ );
263
+
264
+ /**
265
+ * M-Table
266
+ *
267
+ * @var array
268
+ * @access private
269
+ */
270
+ var $m1 = array(
271
+ 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
272
+ 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
273
+ 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
274
+ 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
275
+ 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
276
+ 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
277
+ 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
278
+ 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
279
+ 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
280
+ 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
281
+ 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
282
+ 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
283
+ 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
284
+ 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
285
+ 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
286
+ 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
287
+ 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
288
+ 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
289
+ 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
290
+ 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
291
+ 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
292
+ 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
293
+ 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
294
+ 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
295
+ 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
296
+ 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
297
+ 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
298
+ 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
299
+ 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
300
+ 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
301
+ 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
302
+ 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
303
+ );
304
+
305
+ /**
306
+ * M-Table
307
+ *
308
+ * @var array
309
+ * @access private
310
+ */
311
+ var $m2 = array(
312
+ 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
313
+ 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
314
+ 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
315
+ 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
316
+ 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
317
+ 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
318
+ 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
319
+ 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
320
+ 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
321
+ 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
322
+ 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
323
+ 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
324
+ 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
325
+ 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
326
+ 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
327
+ 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
328
+ 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
329
+ 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
330
+ 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
331
+ 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
332
+ 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
333
+ 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
334
+ 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
335
+ 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
336
+ 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
337
+ 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
338
+ 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
339
+ 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
340
+ 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
341
+ 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
342
+ 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
343
+ 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
344
+ );
345
+
346
+ /**
347
+ * M-Table
348
+ *
349
+ * @var array
350
+ * @access private
351
+ */
352
+ var $m3 = array(
353
+ 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
354
+ 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
355
+ 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
356
+ 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
357
+ 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
358
+ 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
359
+ 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
360
+ 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
361
+ 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
362
+ 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
363
+ 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
364
+ 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
365
+ 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
366
+ 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
367
+ 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
368
+ 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
369
+ 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
370
+ 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
371
+ 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
372
+ 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
373
+ 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
374
+ 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
375
+ 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
376
+ 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
377
+ 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
378
+ 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
379
+ 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
380
+ 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
381
+ 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
382
+ 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
383
+ 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
384
+ 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
385
+ );
386
+
387
+ /**
388
+ * The Key Schedule Array
389
+ *
390
+ * @var array
391
+ * @access private
392
+ */
393
+ var $K = array();
394
+
395
+ /**
396
+ * The Key depended S-Table 0
397
+ *
398
+ * @var array
399
+ * @access private
400
+ */
401
+ var $S0 = array();
402
+
403
+ /**
404
+ * The Key depended S-Table 1
405
+ *
406
+ * @var array
407
+ * @access private
408
+ */
409
+ var $S1 = array();
410
+
411
+ /**
412
+ * The Key depended S-Table 2
413
+ *
414
+ * @var array
415
+ * @access private
416
+ */
417
+ var $S2 = array();
418
+
419
+ /**
420
+ * The Key depended S-Table 3
421
+ *
422
+ * @var array
423
+ * @access private
424
+ */
425
+ var $S3 = array();
426
+
427
+ /**
428
+ * Holds the last used key
429
+ *
430
+ * @var array
431
+ * @access private
432
+ */
433
+ var $kl;
434
+
435
+ /**
436
+ * The Key Length (in bytes)
437
+ *
438
+ * @see Crypt_Twofish::setKeyLength()
439
+ * @var int
440
+ * @access private
441
+ */
442
+ var $key_length = 16;
443
+
444
+ /**
445
+ * Sets the key length.
446
+ *
447
+ * Valid key lengths are 128, 192 or 256 bits
448
+ *
449
+ * @access public
450
+ * @param int $length
451
+ */
452
+ function setKeyLength($length)
453
+ {
454
+ switch (true) {
455
+ case $length <= 128:
456
+ $this->key_length = 16;
457
+ break;
458
+ case $length <= 192:
459
+ $this->key_length = 24;
460
+ break;
461
+ default:
462
+ $this->key_length = 32;
463
+ }
464
+
465
+ parent::setKeyLength($length);
466
+ }
467
+
468
+ /**
469
+ * Setup the key (expansion)
470
+ *
471
+ * @see Crypt_Base::_setupKey()
472
+ * @access private
473
+ */
474
+ function _setupKey()
475
+ {
476
+ if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
477
+ // already expanded
478
+ return;
479
+ }
480
+ $this->kl = array('key' => $this->key);
481
+
482
+ /* Key expanding and generating the key-depended s-boxes */
483
+ $le_longs = unpack('V*', $this->key);
484
+ $key = unpack('C*', $this->key);
485
+ $m0 = $this->m0;
486
+ $m1 = $this->m1;
487
+ $m2 = $this->m2;
488
+ $m3 = $this->m3;
489
+ $q0 = $this->q0;
490
+ $q1 = $this->q1;
491
+
492
+ $K = $S0 = $S1 = $S2 = $S3 = array();
493
+
494
+ switch (strlen($this->key)) {
495
+ case 16:
496
+ list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
497
+ list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
498
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
499
+ $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
500
+ $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
501
+ $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
502
+ $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
503
+ $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
504
+ $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
505
+ $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
506
+ $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
507
+ $B = ($B << 8) | ($B >> 24 & 0xff);
508
+ $A = $this->safe_intval($A + $B);
509
+ $K[] = $A;
510
+ $A = $this->safe_intval($A + $B);
511
+ $K[] = ($A << 9 | $A >> 23 & 0x1ff);
512
+ }
513
+ for ($i = 0; $i < 256; ++$i) {
514
+ $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
515
+ $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
516
+ $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
517
+ $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
518
+ }
519
+ break;
520
+ case 24:
521
+ list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
522
+ list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
523
+ list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
524
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
525
+ $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
526
+ $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
527
+ $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
528
+ $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
529
+ $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
530
+ $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
531
+ $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
532
+ $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
533
+ $B = ($B << 8) | ($B >> 24 & 0xff);
534
+ $A = $this->safe_intval($A + $B);
535
+ $K[] = $A;
536
+ $A = $this->safe_intval($A + $B);
537
+ $K[] = ($A << 9 | $A >> 23 & 0x1ff);
538
+ }
539
+ for ($i = 0; $i < 256; ++$i) {
540
+ $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
541
+ $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
542
+ $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
543
+ $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
544
+ }
545
+ break;
546
+ default: // 32
547
+ list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
548
+ list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
549
+ list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
550
+ list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
551
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
552
+ $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
553
+ $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
554
+ $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
555
+ $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
556
+ $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
557
+ $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
558
+ $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
559
+ $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
560
+ $B = ($B << 8) | ($B >> 24 & 0xff);
561
+ $A = $this->safe_intval($A + $B);
562
+ $K[] = $A;
563
+ $A = $this->safe_intval($A + $B);
564
+ $K[] = ($A << 9 | $A >> 23 & 0x1ff);
565
+ }
566
+ for ($i = 0; $i < 256; ++$i) {
567
+ $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
568
+ $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
569
+ $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
570
+ $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
571
+ }
572
+ }
573
+
574
+ $this->K = $K;
575
+ $this->S0 = $S0;
576
+ $this->S1 = $S1;
577
+ $this->S2 = $S2;
578
+ $this->S3 = $S3;
579
+ }
580
+
581
+ /**
582
+ * _mdsrem function using by the twofish cipher algorithm
583
+ *
584
+ * @access private
585
+ * @param string $A
586
+ * @param string $B
587
+ * @return array
588
+ */
589
+ function _mdsrem($A, $B)
590
+ {
591
+ // No gain by unrolling this loop.
592
+ for ($i = 0; $i < 8; ++$i) {
593
+ // Get most significant coefficient.
594
+ $t = 0xff & ($B >> 24);
595
+
596
+ // Shift the others up.
597
+ $B = ($B << 8) | (0xff & ($A >> 24));
598
+ $A<<= 8;
599
+
600
+ $u = $t << 1;
601
+
602
+ // Subtract the modular polynomial on overflow.
603
+ if ($t & 0x80) {
604
+ $u^= 0x14d;
605
+ }
606
+
607
+ // Remove t * (a * x^2 + 1).
608
+ $B ^= $t ^ ($u << 16);
609
+
610
+ // Form u = a*t + t/a = t*(a + 1/a).
611
+ $u^= 0x7fffffff & ($t >> 1);
612
+
613
+ // Add the modular polynomial on underflow.
614
+ if ($t & 0x01) {
615
+ $u^= 0xa6 ;
616
+ }
617
+
618
+ // Remove t * (a + 1/a) * (x^3 + x).
619
+ $B^= ($u << 24) | ($u << 8);
620
+ }
621
+
622
+ return array(
623
+ 0xff & $B >> 24,
624
+ 0xff & $B >> 16,
625
+ 0xff & $B >> 8,
626
+ 0xff & $B);
627
+ }
628
+
629
+ /**
630
+ * Encrypts a block
631
+ *
632
+ * @access private
633
+ * @param string $in
634
+ * @return string
635
+ */
636
+ function _encryptBlock($in)
637
+ {
638
+ $S0 = $this->S0;
639
+ $S1 = $this->S1;
640
+ $S2 = $this->S2;
641
+ $S3 = $this->S3;
642
+ $K = $this->K;
643
+
644
+ $in = unpack("V4", $in);
645
+ $R0 = $K[0] ^ $in[1];
646
+ $R1 = $K[1] ^ $in[2];
647
+ $R2 = $K[2] ^ $in[3];
648
+ $R3 = $K[3] ^ $in[4];
649
+
650
+ $ki = 7;
651
+ while ($ki < 39) {
652
+ $t0 = $S0[ $R0 & 0xff] ^
653
+ $S1[($R0 >> 8) & 0xff] ^
654
+ $S2[($R0 >> 16) & 0xff] ^
655
+ $S3[($R0 >> 24) & 0xff];
656
+ $t1 = $S0[($R1 >> 24) & 0xff] ^
657
+ $S1[ $R1 & 0xff] ^
658
+ $S2[($R1 >> 8) & 0xff] ^
659
+ $S3[($R1 >> 16) & 0xff];
660
+ $R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
661
+ $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
662
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
663
+
664
+ $t0 = $S0[ $R2 & 0xff] ^
665
+ $S1[($R2 >> 8) & 0xff] ^
666
+ $S2[($R2 >> 16) & 0xff] ^
667
+ $S3[($R2 >> 24) & 0xff];
668
+ $t1 = $S0[($R3 >> 24) & 0xff] ^
669
+ $S1[ $R3 & 0xff] ^
670
+ $S2[($R3 >> 8) & 0xff] ^
671
+ $S3[($R3 >> 16) & 0xff];
672
+ $R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
673
+ $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
674
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
675
+ }
676
+
677
+ // @codingStandardsIgnoreStart
678
+ return pack("V4", $K[4] ^ $R2,
679
+ $K[5] ^ $R3,
680
+ $K[6] ^ $R0,
681
+ $K[7] ^ $R1);
682
+ // @codingStandardsIgnoreEnd
683
+ }
684
+
685
+ /**
686
+ * Decrypts a block
687
+ *
688
+ * @access private
689
+ * @param string $in
690
+ * @return string
691
+ */
692
+ function _decryptBlock($in)
693
+ {
694
+ $S0 = $this->S0;
695
+ $S1 = $this->S1;
696
+ $S2 = $this->S2;
697
+ $S3 = $this->S3;
698
+ $K = $this->K;
699
+
700
+ $in = unpack("V4", $in);
701
+ $R0 = $K[4] ^ $in[1];
702
+ $R1 = $K[5] ^ $in[2];
703
+ $R2 = $K[6] ^ $in[3];
704
+ $R3 = $K[7] ^ $in[4];
705
+
706
+ $ki = 40;
707
+ while ($ki > 8) {
708
+ $t0 = $S0[$R0 & 0xff] ^
709
+ $S1[$R0 >> 8 & 0xff] ^
710
+ $S2[$R0 >> 16 & 0xff] ^
711
+ $S3[$R0 >> 24 & 0xff];
712
+ $t1 = $S0[$R1 >> 24 & 0xff] ^
713
+ $S1[$R1 & 0xff] ^
714
+ $S2[$R1 >> 8 & 0xff] ^
715
+ $S3[$R1 >> 16 & 0xff];
716
+ $R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
717
+ $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
718
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
719
+
720
+ $t0 = $S0[$R2 & 0xff] ^
721
+ $S1[$R2 >> 8 & 0xff] ^
722
+ $S2[$R2 >> 16 & 0xff] ^
723
+ $S3[$R2 >> 24 & 0xff];
724
+ $t1 = $S0[$R3 >> 24 & 0xff] ^
725
+ $S1[$R3 & 0xff] ^
726
+ $S2[$R3 >> 8 & 0xff] ^
727
+ $S3[$R3 >> 16 & 0xff];
728
+ $R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
729
+ $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
730
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
731
+ }
732
+
733
+ // @codingStandardsIgnoreStart
734
+ return pack("V4", $K[0] ^ $R2,
735
+ $K[1] ^ $R3,
736
+ $K[2] ^ $R0,
737
+ $K[3] ^ $R1);
738
+ // @codingStandardsIgnoreEnd
739
+ }
740
+
741
+ /**
742
+ * Setup the performance-optimized function for de/encrypt()
743
+ *
744
+ * @see Crypt_Base::_setupInlineCrypt()
745
+ * @access private
746
+ */
747
+ function _setupInlineCrypt()
748
+ {
749
+ $lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
750
+
751
+ // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
752
+ // (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
753
+ $gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
754
+
755
+ // Generation of a unique hash for our generated code
756
+ $code_hash = "Crypt_Twofish, {$this->mode}";
757
+ if ($gen_hi_opt_code) {
758
+ $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
759
+ }
760
+
761
+ $safeint = $this->safe_intval_inline();
762
+
763
+ if (!isset($lambda_functions[$code_hash])) {
764
+ switch (true) {
765
+ case $gen_hi_opt_code:
766
+ $K = $this->K;
767
+ $init_crypt = '
768
+ static $S0, $S1, $S2, $S3;
769
+ if (!$S0) {
770
+ for ($i = 0; $i < 256; ++$i) {
771
+ $S0[] = (int)$self->S0[$i];
772
+ $S1[] = (int)$self->S1[$i];
773
+ $S2[] = (int)$self->S2[$i];
774
+ $S3[] = (int)$self->S3[$i];
775
+ }
776
+ }
777
+ ';
778
+ break;
779
+ default:
780
+ $K = array();
781
+ for ($i = 0; $i < 40; ++$i) {
782
+ $K[] = '$K_' . $i;
783
+ }
784
+ $init_crypt = '
785
+ $S0 = $self->S0;
786
+ $S1 = $self->S1;
787
+ $S2 = $self->S2;
788
+ $S3 = $self->S3;
789
+ list(' . implode(',', $K) . ') = $self->K;
790
+ ';
791
+ }
792
+
793
+ // Generating encrypt code:
794
+ $encrypt_block = '
795
+ $in = unpack("V4", $in);
796
+ $R0 = '.$K[0].' ^ $in[1];
797
+ $R1 = '.$K[1].' ^ $in[2];
798
+ $R2 = '.$K[2].' ^ $in[3];
799
+ $R3 = '.$K[3].' ^ $in[4];
800
+ ';
801
+ for ($ki = 7, $i = 0; $i < 8; ++$i) {
802
+ $encrypt_block.= '
803
+ $t0 = $S0[ $R0 & 0xff] ^
804
+ $S1[($R0 >> 8) & 0xff] ^
805
+ $S2[($R0 >> 16) & 0xff] ^
806
+ $S3[($R0 >> 24) & 0xff];
807
+ $t1 = $S0[($R1 >> 24) & 0xff] ^
808
+ $S1[ $R1 & 0xff] ^
809
+ $S2[($R1 >> 8) & 0xff] ^
810
+ $S3[($R1 >> 16) & 0xff];
811
+ $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
812
+ $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
813
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
814
+
815
+ $t0 = $S0[ $R2 & 0xff] ^
816
+ $S1[($R2 >> 8) & 0xff] ^
817
+ $S2[($R2 >> 16) & 0xff] ^
818
+ $S3[($R2 >> 24) & 0xff];
819
+ $t1 = $S0[($R3 >> 24) & 0xff] ^
820
+ $S1[ $R3 & 0xff] ^
821
+ $S2[($R3 >> 8) & 0xff] ^
822
+ $S3[($R3 >> 16) & 0xff];
823
+ $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
824
+ $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
825
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
826
+ ';
827
+ }
828
+ $encrypt_block.= '
829
+ $in = pack("V4", ' . $K[4] . ' ^ $R2,
830
+ ' . $K[5] . ' ^ $R3,
831
+ ' . $K[6] . ' ^ $R0,
832
+ ' . $K[7] . ' ^ $R1);
833
+ ';
834
+
835
+ // Generating decrypt code:
836
+ $decrypt_block = '
837
+ $in = unpack("V4", $in);
838
+ $R0 = '.$K[4].' ^ $in[1];
839
+ $R1 = '.$K[5].' ^ $in[2];
840
+ $R2 = '.$K[6].' ^ $in[3];
841
+ $R3 = '.$K[7].' ^ $in[4];
842
+ ';
843
+ for ($ki = 40, $i = 0; $i < 8; ++$i) {
844
+ $decrypt_block.= '
845
+ $t0 = $S0[$R0 & 0xff] ^
846
+ $S1[$R0 >> 8 & 0xff] ^
847
+ $S2[$R0 >> 16 & 0xff] ^
848
+ $S3[$R0 >> 24 & 0xff];
849
+ $t1 = $S0[$R1 >> 24 & 0xff] ^
850
+ $S1[$R1 & 0xff] ^
851
+ $S2[$R1 >> 8 & 0xff] ^
852
+ $S3[$R1 >> 16 & 0xff];
853
+ $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
854
+ $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
855
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
856
+
857
+ $t0 = $S0[$R2 & 0xff] ^
858
+ $S1[$R2 >> 8 & 0xff] ^
859
+ $S2[$R2 >> 16 & 0xff] ^
860
+ $S3[$R2 >> 24 & 0xff];
861
+ $t1 = $S0[$R3 >> 24 & 0xff] ^
862
+ $S1[$R3 & 0xff] ^
863
+ $S2[$R3 >> 8 & 0xff] ^
864
+ $S3[$R3 >> 16 & 0xff];
865
+ $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
866
+ $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
867
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
868
+ ';
869
+ }
870
+ $decrypt_block.= '
871
+ $in = pack("V4", ' . $K[0] . ' ^ $R2,
872
+ ' . $K[1] . ' ^ $R3,
873
+ ' . $K[2] . ' ^ $R0,
874
+ ' . $K[3] . ' ^ $R1);
875
+ ';
876
+
877
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
878
+ array(
879
+ 'init_crypt' => $init_crypt,
880
+ 'init_encrypt' => '',
881
+ 'init_decrypt' => '',
882
+ 'encrypt_block' => $encrypt_block,
883
+ 'decrypt_block' => $decrypt_block
884
+ )
885
+ );
886
+ }
887
+ $this->inline_crypt = $lambda_functions[$code_hash];
888
+ }
889
+ }
phpseclib/File/ANSI.php ADDED
@@ -0,0 +1,604 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP ANSI Decoder
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * If you call read() in Net_SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
9
+ * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a
10
+ * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
11
+ * color to display them in, etc. File_ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
12
+ *
13
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ * of this software and associated documentation files (the "Software"), to deal
15
+ * in the Software without restriction, including without limitation the rights
16
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ * copies of the Software, and to permit persons to whom the Software is
18
+ * furnished to do so, subject to the following conditions:
19
+ *
20
+ * The above copyright notice and this permission notice shall be included in
21
+ * all copies or substantial portions of the Software.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
+ * THE SOFTWARE.
30
+ *
31
+ * @category File
32
+ * @package File_ANSI
33
+ * @author Jim Wigginton <terrafrost@php.net>
34
+ * @copyright 2012 Jim Wigginton
35
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
36
+ * @link http://phpseclib.sourceforge.net
37
+ */
38
+
39
+ /**
40
+ * Pure-PHP ANSI Decoder
41
+ *
42
+ * @package File_ANSI
43
+ * @author Jim Wigginton <terrafrost@php.net>
44
+ * @access public
45
+ */
46
+ class File_ANSI
47
+ {
48
+ /**
49
+ * Max Width
50
+ *
51
+ * @var int
52
+ * @access private
53
+ */
54
+ var $max_x;
55
+
56
+ /**
57
+ * Max Height
58
+ *
59
+ * @var int
60
+ * @access private
61
+ */
62
+ var $max_y;
63
+
64
+ /**
65
+ * Max History
66
+ *
67
+ * @var int
68
+ * @access private
69
+ */
70
+ var $max_history;
71
+
72
+ /**
73
+ * History
74
+ *
75
+ * @var array
76
+ * @access private
77
+ */
78
+ var $history;
79
+
80
+ /**
81
+ * History Attributes
82
+ *
83
+ * @var array
84
+ * @access private
85
+ */
86
+ var $history_attrs;
87
+
88
+ /**
89
+ * Current Column
90
+ *
91
+ * @var int
92
+ * @access private
93
+ */
94
+ var $x;
95
+
96
+ /**
97
+ * Current Row
98
+ *
99
+ * @var int
100
+ * @access private
101
+ */
102
+ var $y;
103
+
104
+ /**
105
+ * Old Column
106
+ *
107
+ * @var int
108
+ * @access private
109
+ */
110
+ var $old_x;
111
+
112
+ /**
113
+ * Old Row
114
+ *
115
+ * @var int
116
+ * @access private
117
+ */
118
+ var $old_y;
119
+
120
+ /**
121
+ * An empty attribute cell
122
+ *
123
+ * @var object
124
+ * @access private
125
+ */
126
+ var $base_attr_cell;
127
+
128
+ /**
129
+ * The current attribute cell
130
+ *
131
+ * @var object
132
+ * @access private
133
+ */
134
+ var $attr_cell;
135
+
136
+ /**
137
+ * An empty attribute row
138
+ *
139
+ * @var array
140
+ * @access private
141
+ */
142
+ var $attr_row;
143
+
144
+ /**
145
+ * The current screen text
146
+ *
147
+ * @var array
148
+ * @access private
149
+ */
150
+ var $screen;
151
+
152
+ /**
153
+ * The current screen attributes
154
+ *
155
+ * @var array
156
+ * @access private
157
+ */
158
+ var $attrs;
159
+
160
+ /**
161
+ * Current ANSI code
162
+ *
163
+ * @var string
164
+ * @access private
165
+ */
166
+ var $ansi;
167
+
168
+ /**
169
+ * Tokenization
170
+ *
171
+ * @var array
172
+ * @access private
173
+ */
174
+ var $tokenization;
175
+
176
+ /**
177
+ * Default Constructor.
178
+ *
179
+ * @return File_ANSI
180
+ * @access public
181
+ */
182
+ function __construct()
183
+ {
184
+ $attr_cell = new stdClass();
185
+ $attr_cell->bold = false;
186
+ $attr_cell->underline = false;
187
+ $attr_cell->blink = false;
188
+ $attr_cell->background = 'black';
189
+ $attr_cell->foreground = 'white';
190
+ $attr_cell->reverse = false;
191
+ $this->base_attr_cell = clone($attr_cell);
192
+ $this->attr_cell = clone($attr_cell);
193
+
194
+ $this->setHistory(200);
195
+ $this->setDimensions(80, 24);
196
+ }
197
+
198
+ /**
199
+ * PHP4 compatible Default Constructor.
200
+ *
201
+ * @see self::__construct()
202
+ * @access public
203
+ */
204
+ function File_ANSI()
205
+ {
206
+ $this->__construct($mode);
207
+ }
208
+
209
+ /**
210
+ * Set terminal width and height
211
+ *
212
+ * Resets the screen as well
213
+ *
214
+ * @param int $x
215
+ * @param int $y
216
+ * @access public
217
+ */
218
+ function setDimensions($x, $y)
219
+ {
220
+ $this->max_x = $x - 1;
221
+ $this->max_y = $y - 1;
222
+ $this->x = $this->y = 0;
223
+ $this->history = $this->history_attrs = array();
224
+ $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
225
+ $this->screen = array_fill(0, $this->max_y + 1, '');
226
+ $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
227
+ $this->ansi = '';
228
+ }
229
+
230
+ /**
231
+ * Set the number of lines that should be logged past the terminal height
232
+ *
233
+ * @param int $x
234
+ * @param int $y
235
+ * @access public
236
+ */
237
+ function setHistory($history)
238
+ {
239
+ $this->max_history = $history;
240
+ }
241
+
242
+ /**
243
+ * Load a string
244
+ *
245
+ * @param string $source
246
+ * @access public
247
+ */
248
+ function loadString($source)
249
+ {
250
+ $this->setDimensions($this->max_x + 1, $this->max_y + 1);
251
+ $this->appendString($source);
252
+ }
253
+
254
+ /**
255
+ * Appdend a string
256
+ *
257
+ * @param string $source
258
+ * @access public
259
+ */
260
+ function appendString($source)
261
+ {
262
+ $this->tokenization = array('');
263
+ for ($i = 0; $i < strlen($source); $i++) {
264
+ if (strlen($this->ansi)) {
265
+ $this->ansi.= $source[$i];
266
+ $chr = ord($source[$i]);
267
+ // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
268
+ // single character CSI's not currently supported
269
+ switch (true) {
270
+ case $this->ansi == "\x1B=":
271
+ $this->ansi = '';
272
+ continue 2;
273
+ case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
274
+ case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
275
+ break;
276
+ default:
277
+ continue 2;
278
+ }
279
+ $this->tokenization[] = $this->ansi;
280
+ $this->tokenization[] = '';
281
+ // http://ascii-table.com/ansi-escape-sequences-vt-100.php
282
+ switch ($this->ansi) {
283
+ case "\x1B[H": // Move cursor to upper left corner
284
+ $this->old_x = $this->x;
285
+ $this->old_y = $this->y;
286
+ $this->x = $this->y = 0;
287
+ break;
288
+ case "\x1B[J": // Clear screen from cursor down
289
+ $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
290
+ $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
291
+
292
+ $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
293
+ $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
294
+
295
+ if (count($this->history) == $this->max_history) {
296
+ array_shift($this->history);
297
+ array_shift($this->history_attrs);
298
+ }
299
+ case "\x1B[K": // Clear screen from cursor right
300
+ $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
301
+
302
+ array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
303
+ break;
304
+ case "\x1B[2K": // Clear entire line
305
+ $this->screen[$this->y] = str_repeat(' ', $this->x);
306
+ $this->attrs[$this->y] = $this->attr_row;
307
+ break;
308
+ case "\x1B[?1h": // set cursor key to application
309
+ case "\x1B[?25h": // show the cursor
310
+ case "\x1B(B": // set united states g0 character set
311
+ break;
312
+ case "\x1BE": // Move to next line
313
+ $this->_newLine();
314
+ $this->x = 0;
315
+ break;
316
+ default:
317
+ switch (true) {
318
+ case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
319
+ $this->old_y = $this->y;
320
+ $this->y+= $match[1];
321
+ break;
322
+ case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
323
+ $this->old_x = $this->x;
324
+ $this->old_y = $this->y;
325
+ $this->x = $match[2] - 1;
326
+ $this->y = $match[1] - 1;
327
+ break;
328
+ case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
329
+ $this->old_x = $this->x;
330
+ $this->x+= $match[1];
331
+ break;
332
+ case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
333
+ $this->old_x = $this->x;
334
+ $this->x-= $match[1];
335
+ if ($this->x < 0) {
336
+ $this->x = 0;
337
+ }
338
+ break;
339
+ case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
340
+ break;
341
+ case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
342
+ $attr_cell = &$this->attr_cell;
343
+ $mods = explode(';', $match[1]);
344
+ foreach ($mods as $mod) {
345
+ switch ($mod) {
346
+ case 0: // Turn off character attributes
347
+ $attr_cell = clone($this->base_attr_cell);
348
+ break;
349
+ case 1: // Turn bold mode on
350
+ $attr_cell->bold = true;
351
+ break;
352
+ case 4: // Turn underline mode on
353
+ $attr_cell->underline = true;
354
+ break;
355
+ case 5: // Turn blinking mode on
356
+ $attr_cell->blink = true;
357
+ break;
358
+ case 7: // Turn reverse video on
359
+ $attr_cell->reverse = !$attr_cell->reverse;
360
+ $temp = $attr_cell->background;
361
+ $attr_cell->background = $attr_cell->foreground;
362
+ $attr_cell->foreground = $temp;
363
+ break;
364
+ default: // set colors
365
+ //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
366
+ $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
367
+ //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
368
+ $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
369
+ switch ($mod) {
370
+ // @codingStandardsIgnoreStart
371
+ case 30: $front = 'black'; break;
372
+ case 31: $front = 'red'; break;
373
+ case 32: $front = 'green'; break;
374
+ case 33: $front = 'yellow'; break;
375
+ case 34: $front = 'blue'; break;
376
+ case 35: $front = 'magenta'; break;
377
+ case 36: $front = 'cyan'; break;
378
+ case 37: $front = 'white'; break;
379
+
380
+ case 40: $back = 'black'; break;
381
+ case 41: $back = 'red'; break;
382
+ case 42: $back = 'green'; break;
383
+ case 43: $back = 'yellow'; break;
384
+ case 44: $back = 'blue'; break;
385
+ case 45: $back = 'magenta'; break;
386
+ case 46: $back = 'cyan'; break;
387
+ case 47: $back = 'white'; break;
388
+ // @codingStandardsIgnoreEnd
389
+
390
+ default:
391
+ //user_error('Unsupported attribute: ' . $mod);
392
+ $this->ansi = '';
393
+ break 2;
394
+ }
395
+ }
396
+ }
397
+ break;
398
+ default:
399
+ //user_error("{$this->ansi} is unsupported\r\n");
400
+ }
401
+ }
402
+ $this->ansi = '';
403
+ continue;
404
+ }
405
+
406
+ $this->tokenization[count($this->tokenization) - 1].= $source[$i];
407
+ switch ($source[$i]) {
408
+ case "\r":
409
+ $this->x = 0;
410
+ break;
411
+ case "\n":
412
+ $this->_newLine();
413
+ break;
414
+ case "\x08": // backspace
415
+ if ($this->x) {
416
+ $this->x--;
417
+ $this->attrs[$this->y][$this->x] = clone($this->base_attr_cell);
418
+ $this->screen[$this->y] = substr_replace(
419
+ $this->screen[$this->y],
420
+ $source[$i],
421
+ $this->x,
422
+ 1
423
+ );
424
+ }
425
+ break;
426
+ case "\x0F": // shift
427
+ break;
428
+ case "\x1B": // start ANSI escape code
429
+ $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
430
+ //if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
431
+ // array_pop($this->tokenization);
432
+ //}
433
+ $this->ansi.= "\x1B";
434
+ break;
435
+ default:
436
+ $this->attrs[$this->y][$this->x] = clone($this->attr_cell);
437
+ if ($this->x > strlen($this->screen[$this->y])) {
438
+ $this->screen[$this->y] = str_repeat(' ', $this->x);
439
+ }
440
+ $this->screen[$this->y] = substr_replace(
441
+ $this->screen[$this->y],
442
+ $source[$i],
443
+ $this->x,
444
+ 1
445
+ );
446
+
447
+ if ($this->x > $this->max_x) {
448
+ $this->x = 0;
449
+ $this->_newLine();
450
+ } else {
451
+ $this->x++;
452
+ }
453
+ }
454
+ }
455
+ }
456
+
457
+ /**
458
+ * Add a new line
459
+ *
460
+ * Also update the $this->screen and $this->history buffers
461
+ *
462
+ * @access private
463
+ */
464
+ function _newLine()
465
+ {
466
+ //if ($this->y < $this->max_y) {
467
+ // $this->y++;
468
+ //}
469
+
470
+ while ($this->y >= $this->max_y) {
471
+ $this->history = array_merge($this->history, array(array_shift($this->screen)));
472
+ $this->screen[] = '';
473
+
474
+ $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
475
+ $this->attrs[] = $this->attr_row;
476
+
477
+ if (count($this->history) >= $this->max_history) {
478
+ array_shift($this->history);
479
+ array_shift($this->history_attrs);
480
+ }
481
+
482
+ $this->y--;
483
+ }
484
+ $this->y++;
485
+ }
486
+
487
+ /**
488
+ * Returns the current coordinate without preformating
489
+ *
490
+ * @access private
491
+ * @return string
492
+ */
493
+ function _processCoordinate($last_attr, $cur_attr, $char)
494
+ {
495
+ $output = '';
496
+
497
+ if ($last_attr != $cur_attr) {
498
+ $close = $open = '';
499
+ if ($last_attr->foreground != $cur_attr->foreground) {
500
+ if ($cur_attr->foreground != 'white') {
501
+ $open.= '<span style="color: ' . $cur_attr->foreground . '">';
502
+ }
503
+ if ($last_attr->foreground != 'white') {
504
+ $close = '</span>' . $close;
505
+ }
506
+ }
507
+ if ($last_attr->background != $cur_attr->background) {
508
+ if ($cur_attr->background != 'black') {
509
+ $open.= '<span style="background: ' . $cur_attr->background . '">';
510
+ }
511
+ if ($last_attr->background != 'black') {
512
+ $close = '</span>' . $close;
513
+ }
514
+ }
515
+ if ($last_attr->bold != $cur_attr->bold) {
516
+ if ($cur_attr->bold) {
517
+ $open.= '<b>';
518
+ } else {
519
+ $close = '</b>' . $close;
520
+ }
521
+ }
522
+ if ($last_attr->underline != $cur_attr->underline) {
523
+ if ($cur_attr->underline) {
524
+ $open.= '<u>';
525
+ } else {
526
+ $close = '</u>' . $close;
527
+ }
528
+ }
529
+ if ($last_attr->blink != $cur_attr->blink) {
530
+ if ($cur_attr->blink) {
531
+ $open.= '<blink>';
532
+ } else {
533
+ $close = '</blink>' . $close;
534
+ }
535
+ }
536
+ $output.= $close . $open;
537
+ }
538
+
539
+ $output.= htmlspecialchars($char);
540
+
541
+ return $output;
542
+ }
543
+
544
+ /**
545
+ * Returns the current screen without preformating
546
+ *
547
+ * @access private
548
+ * @return string
549
+ */
550
+ function _getScreen()
551
+ {
552
+ $output = '';
553
+ $last_attr = $this->base_attr_cell;
554
+ for ($i = 0; $i <= $this->max_y; $i++) {
555
+ for ($j = 0; $j <= $this->max_x; $j++) {
556
+ $cur_attr = $this->attrs[$i][$j];
557
+ $output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
558
+ $last_attr = $this->attrs[$i][$j];
559
+ }
560
+ $output.= "\r\n";
561
+ }
562
+ $output = substr($output, 0, -2);
563
+ // close any remaining open tags
564
+ $output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
565
+ return rtrim($output);
566
+ }
567
+
568
+ /**
569
+ * Returns the current screen
570
+ *
571
+ * @access public
572
+ * @return string
573
+ */
574
+ function getScreen()
575
+ {
576
+ return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->_getScreen() . '</pre>';
577
+ }
578
+
579
+ /**
580
+ * Returns the current screen and the x previous lines
581
+ *
582
+ * @access public
583
+ * @return string
584
+ */
585
+ function getHistory()
586
+ {
587
+ $scrollback = '';
588
+ $last_attr = $this->base_attr_cell;
589
+ for ($i = 0; $i < count($this->history); $i++) {
590
+ for ($j = 0; $j <= $this->max_x + 1; $j++) {
591
+ $cur_attr = $this->history_attrs[$i][$j];
592
+ $scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
593
+ $last_attr = $this->history_attrs[$i][$j];
594
+ }
595
+ $scrollback.= "\r\n";
596
+ }
597
+ $base_attr_cell = $this->base_attr_cell;
598
+ $this->base_attr_cell = $last_attr;
599
+ $scrollback.= $this->_getScreen();
600
+ $this->base_attr_cell = $base_attr_cell;
601
+
602
+ return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
603
+ }
604
+ }
phpseclib/File/ASN1.php ADDED
@@ -0,0 +1,1473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP ASN.1 Parser
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * ASN.1 provides the semantics for data encoded using various schemes. The most commonly
9
+ * utilized scheme is DER or the "Distinguished Encoding Rules". PEM's are base64 encoded
10
+ * DER blobs.
11
+ *
12
+ * File_ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
13
+ *
14
+ * Uses the 1988 ASN.1 syntax.
15
+ *
16
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ * of this software and associated documentation files (the "Software"), to deal
18
+ * in the Software without restriction, including without limitation the rights
19
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ * copies of the Software, and to permit persons to whom the Software is
21
+ * furnished to do so, subject to the following conditions:
22
+ *
23
+ * The above copyright notice and this permission notice shall be included in
24
+ * all copies or substantial portions of the Software.
25
+ *
26
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
+ * THE SOFTWARE.
33
+ *
34
+ * @category File
35
+ * @package File_ASN1
36
+ * @author Jim Wigginton <terrafrost@php.net>
37
+ * @copyright 2012 Jim Wigginton
38
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
39
+ * @link http://phpseclib.sourceforge.net
40
+ */
41
+
42
+ /**#@+
43
+ * Tag Classes
44
+ *
45
+ * @access private
46
+ * @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
47
+ */
48
+ define('FILE_ASN1_CLASS_UNIVERSAL', 0);
49
+ define('FILE_ASN1_CLASS_APPLICATION', 1);
50
+ define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
51
+ define('FILE_ASN1_CLASS_PRIVATE', 3);
52
+ /**#@-*/
53
+
54
+ /**#@+
55
+ * Tag Classes
56
+ *
57
+ * @access private
58
+ * @link http://www.obj-sys.com/asn1tutorial/node124.html
59
+ */
60
+ define('FILE_ASN1_TYPE_BOOLEAN', 1);
61
+ define('FILE_ASN1_TYPE_INTEGER', 2);
62
+ define('FILE_ASN1_TYPE_BIT_STRING', 3);
63
+ define('FILE_ASN1_TYPE_OCTET_STRING', 4);
64
+ define('FILE_ASN1_TYPE_NULL', 5);
65
+ define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
66
+ //define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
67
+ //define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
68
+ define('FILE_ASN1_TYPE_REAL', 9);
69
+ define('FILE_ASN1_TYPE_ENUMERATED', 10);
70
+ //define('FILE_ASN1_TYPE_EMBEDDED', 11);
71
+ define('FILE_ASN1_TYPE_UTF8_STRING', 12);
72
+ //define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
73
+ define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
74
+ define('FILE_ASN1_TYPE_SET', 17); // SET OF
75
+ /**#@-*/
76
+ /**#@+
77
+ * More Tag Classes
78
+ *
79
+ * @access private
80
+ * @link http://www.obj-sys.com/asn1tutorial/node10.html
81
+ */
82
+ define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
83
+ define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
84
+ define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
85
+ define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
86
+ define('FILE_ASN1_TYPE_IA5_STRING', 22);
87
+ define('FILE_ASN1_TYPE_UTC_TIME', 23);
88
+ define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
89
+ define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
90
+ define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
91
+ define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
92
+ define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
93
+ //define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
94
+ define('FILE_ASN1_TYPE_BMP_STRING', 30);
95
+ /**#@-*/
96
+
97
+ /**#@+
98
+ * Tag Aliases
99
+ *
100
+ * These tags are kinda place holders for other tags.
101
+ *
102
+ * @access private
103
+ */
104
+ define('FILE_ASN1_TYPE_CHOICE', -1);
105
+ define('FILE_ASN1_TYPE_ANY', -2);
106
+ /**#@-*/
107
+
108
+ /**
109
+ * ASN.1 Element
110
+ *
111
+ * Bypass normal encoding rules in File_ASN1::encodeDER()
112
+ *
113
+ * @package File_ASN1
114
+ * @author Jim Wigginton <terrafrost@php.net>
115
+ * @access public
116
+ */
117
+ class File_ASN1_Element
118
+ {
119
+ /**
120
+ * Raw element value
121
+ *
122
+ * @var string
123
+ * @access private
124
+ */
125
+ var $element;
126
+
127
+ /**
128
+ * Constructor
129
+ *
130
+ * @param string $encoded
131
+ * @return File_ASN1_Element
132
+ * @access public
133
+ */
134
+ function __construct($encoded)
135
+ {
136
+ $this->element = $encoded;
137
+ }
138
+
139
+ /**
140
+ * PHP4 compatible Default Constructor.
141
+ *
142
+ * @see self::__construct()
143
+ * @param int $mode
144
+ * @access public
145
+ */
146
+ function File_ASN1_Element($encoded)
147
+ {
148
+ $this->__construct($encoded);
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Pure-PHP ASN.1 Parser
154
+ *
155
+ * @package File_ASN1
156
+ * @author Jim Wigginton <terrafrost@php.net>
157
+ * @access public
158
+ */
159
+ class File_ASN1
160
+ {
161
+ /**
162
+ * ASN.1 object identifier
163
+ *
164
+ * @var array
165
+ * @access private
166
+ * @link http://en.wikipedia.org/wiki/Object_identifier
167
+ */
168
+ var $oids = array();
169
+
170
+ /**
171
+ * Default date format
172
+ *
173
+ * @var string
174
+ * @access private
175
+ * @link http://php.net/class.datetime
176
+ */
177
+ var $format = 'D, d M Y H:i:s O';
178
+
179
+ /**
180
+ * Default date format
181
+ *
182
+ * @var array
183
+ * @access private
184
+ * @see self::setTimeFormat()
185
+ * @see self::asn1map()
186
+ * @link http://php.net/class.datetime
187
+ */
188
+ var $encoded;
189
+
190
+ /**
191
+ * Filters
192
+ *
193
+ * If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
194
+ *
195
+ * @var array
196
+ * @access private
197
+ * @see self::_encode_der()
198
+ */
199
+ var $filters;
200
+
201
+ /**
202
+ * Type mapping table for the ANY type.
203
+ *
204
+ * Structured or unknown types are mapped to a FILE_ASN1_Element.
205
+ * Unambiguous types get the direct mapping (int/real/bool).
206
+ * Others are mapped as a choice, with an extra indexing level.
207
+ *
208
+ * @var array
209
+ * @access public
210
+ */
211
+ var $ANYmap = array(
212
+ FILE_ASN1_TYPE_BOOLEAN => true,
213
+ FILE_ASN1_TYPE_INTEGER => true,
214
+ FILE_ASN1_TYPE_BIT_STRING => 'bitString',
215
+ FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
216
+ FILE_ASN1_TYPE_NULL => 'null',
217
+ FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
218
+ FILE_ASN1_TYPE_REAL => true,
219
+ FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
220
+ FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
221
+ FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
222
+ FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
223
+ FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
224
+ FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
225
+ FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
226
+ FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
227
+ FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
228
+ FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
229
+ FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
230
+ FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
231
+ FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
232
+ //FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
233
+ FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
234
+ );
235
+
236
+ /**
237
+ * String type to character size mapping table.
238
+ *
239
+ * Non-convertable types are absent from this table.
240
+ * size == 0 indicates variable length encoding.
241
+ *
242
+ * @var array
243
+ * @access public
244
+ */
245
+ var $stringTypeSize = array(
246
+ FILE_ASN1_TYPE_UTF8_STRING => 0,
247
+ FILE_ASN1_TYPE_BMP_STRING => 2,
248
+ FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
249
+ FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
250
+ FILE_ASN1_TYPE_TELETEX_STRING => 1,
251
+ FILE_ASN1_TYPE_IA5_STRING => 1,
252
+ FILE_ASN1_TYPE_VISIBLE_STRING => 1,
253
+ );
254
+
255
+ /**
256
+ * Default Constructor.
257
+ *
258
+ * @access public
259
+ */
260
+ function __construct()
261
+ {
262
+ static $static_init = null;
263
+ if (!$static_init) {
264
+ $static_init = true;
265
+ if (!class_exists('Math_BigInteger')) {
266
+ include_once 'Math/BigInteger.php';
267
+ }
268
+ }
269
+ }
270
+
271
+ /**
272
+ * PHP4 compatible Default Constructor.
273
+ *
274
+ * @see self::__construct()
275
+ * @access public
276
+ */
277
+ function File_ASN1()
278
+ {
279
+ $this->__construct($mode);
280
+ }
281
+
282
+ /**
283
+ * Parse BER-encoding
284
+ *
285
+ * Serves a similar purpose to openssl's asn1parse
286
+ *
287
+ * @param string $encoded
288
+ * @return array
289
+ * @access public
290
+ */
291
+ function decodeBER($encoded)
292
+ {
293
+ if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
294
+ $encoded = $encoded->element;
295
+ }
296
+
297
+ $this->encoded = $encoded;
298
+ // encapsulate in an array for BC with the old decodeBER
299
+ return array($this->_decode_ber($encoded));
300
+ }
301
+
302
+ /**
303
+ * Parse BER-encoding (Helper function)
304
+ *
305
+ * Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
306
+ * $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
307
+ * FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
308
+ *
309
+ * @param string $encoded
310
+ * @param int $start
311
+ * @param int $encoded_pos
312
+ * @return array
313
+ * @access private
314
+ */
315
+ function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
316
+ {
317
+ $current = array('start' => $start);
318
+
319
+ $type = ord($encoded[$encoded_pos++]);
320
+ $start++;
321
+
322
+ $constructed = ($type >> 5) & 1;
323
+
324
+ $tag = $type & 0x1F;
325
+ if ($tag == 0x1F) {
326
+ $tag = 0;
327
+ // process septets (since the eighth bit is ignored, it's not an octet)
328
+ do {
329
+ $loop = ord($encoded[0]) >> 7;
330
+ $tag <<= 7;
331
+ $tag |= ord($encoded[$encoded_pos++]) & 0x7F;
332
+ $start++;
333
+ } while ($loop);
334
+ }
335
+
336
+ // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
337
+ $length = ord($encoded[$encoded_pos++]);
338
+ $start++;
339
+ if ($length == 0x80) { // indefinite length
340
+ // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
341
+ // immediately available." -- paragraph 8.1.3.2.c
342
+ $length = strlen($encoded) - $encoded_pos;
343
+ } elseif ($length & 0x80) { // definite length, long form
344
+ // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
345
+ // support it up to four.
346
+ $length&= 0x7F;
347
+ $temp = substr($encoded, $encoded_pos, $length);
348
+ $encoded_pos += $length;
349
+ // tags of indefinte length don't really have a header length; this length includes the tag
350
+ $current+= array('headerlength' => $length + 2);
351
+ $start+= $length;
352
+ extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
353
+ } else {
354
+ $current+= array('headerlength' => 2);
355
+ }
356
+
357
+ if ($length > (strlen($encoded) - $encoded_pos)) {
358
+ return false;
359
+ }
360
+
361
+ $content = substr($encoded, $encoded_pos, $length);
362
+ $content_pos = 0;
363
+
364
+ // at this point $length can be overwritten. it's only accurate for definite length things as is
365
+
366
+ /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
367
+ built-in types. It defines an application-independent data type that must be distinguishable from all other
368
+ data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
369
+ have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
370
+ a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
371
+ alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
372
+ data type; the term CONTEXT-SPECIFIC does not appear.
373
+
374
+ -- http://www.obj-sys.com/asn1tutorial/node12.html */
375
+ $class = ($type >> 6) & 3;
376
+ switch ($class) {
377
+ case FILE_ASN1_CLASS_APPLICATION:
378
+ case FILE_ASN1_CLASS_PRIVATE:
379
+ case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
380
+ if (!$constructed) {
381
+ return array(
382
+ 'type' => $class,
383
+ 'constant' => $tag,
384
+ 'content' => $content,
385
+ 'length' => $length + $start - $current['start']
386
+ );
387
+ }
388
+
389
+ $newcontent = array();
390
+ $remainingLength = $length;
391
+ while ($remainingLength > 0) {
392
+ $temp = $this->_decode_ber($content, $start, $content_pos);
393
+ $length = $temp['length'];
394
+ // end-of-content octets - see paragraph 8.1.5
395
+ if (substr($content, $content_pos + $length, 2) == "\0\0") {
396
+ $length+= 2;
397
+ $start+= $length;
398
+ $newcontent[] = $temp;
399
+ break;
400
+ }
401
+ $start+= $length;
402
+ $remainingLength-= $length;
403
+ $newcontent[] = $temp;
404
+ $content_pos += $length;
405
+ }
406
+
407
+ return array(
408
+ 'type' => $class,
409
+ 'constant' => $tag,
410
+ // the array encapsulation is for BC with the old format
411
+ 'content' => $newcontent,
412
+ // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
413
+ // the absence of $content['headerlength'] is how we know if something is indefinite or not.
414
+ // technically, it could be defined to be 2 and then another indicator could be used but whatever.
415
+ 'length' => $start - $current['start']
416
+ ) + $current;
417
+ }
418
+
419
+ $current+= array('type' => $tag);
420
+
421
+ // decode UNIVERSAL tags
422
+ switch ($tag) {
423
+ case FILE_ASN1_TYPE_BOOLEAN:
424
+ // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
425
+ //if (strlen($content) != 1) {
426
+ // return false;
427
+ //}
428
+ $current['content'] = (bool) ord($content[$content_pos]);
429
+ break;
430
+ case FILE_ASN1_TYPE_INTEGER:
431
+ case FILE_ASN1_TYPE_ENUMERATED:
432
+ $current['content'] = new Math_BigInteger(substr($content, $content_pos), -256);
433
+ break;
434
+ case FILE_ASN1_TYPE_REAL: // not currently supported
435
+ return false;
436
+ case FILE_ASN1_TYPE_BIT_STRING:
437
+ // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
438
+ // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
439
+ // seven.
440
+ if (!$constructed) {
441
+ $current['content'] = substr($content, $content_pos);
442
+ } else {
443
+ $temp = $this->_decode_ber($content, $start, $content_pos);
444
+ $length-= (strlen($content) - $content_pos);
445
+ $last = count($temp) - 1;
446
+ for ($i = 0; $i < $last; $i++) {
447
+ // all subtags should be bit strings
448
+ //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
449
+ // return false;
450
+ //}
451
+ $current['content'].= substr($temp[$i]['content'], 1);
452
+ }
453
+ // all subtags should be bit strings
454
+ //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
455
+ // return false;
456
+ //}
457
+ $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
458
+ }
459
+ break;
460
+ case FILE_ASN1_TYPE_OCTET_STRING:
461
+ if (!$constructed) {
462
+ $current['content'] = substr($content, $content_pos);
463
+ } else {
464
+ $current['content'] = '';
465
+ $length = 0;
466
+ while (substr($content, $content_pos, 2) != "\0\0") {
467
+ $temp = $this->_decode_ber($content, $length + $start, $content_pos);
468
+ $content_pos += $temp['length'];
469
+ // all subtags should be octet strings
470
+ //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
471
+ // return false;
472
+ //}
473
+ $current['content'].= $temp['content'];
474
+ $length+= $temp['length'];
475
+ }
476
+ if (substr($content, $content_pos, 2) == "\0\0") {
477
+ $length+= 2; // +2 for the EOC
478
+ }
479
+ }
480
+ break;
481
+ case FILE_ASN1_TYPE_NULL:
482
+ // "The contents octets shall not contain any octets." -- paragraph 8.8.2
483
+ //if (strlen($content)) {
484
+ // return false;
485
+ //}
486
+ break;
487
+ case FILE_ASN1_TYPE_SEQUENCE:
488
+ case FILE_ASN1_TYPE_SET:
489
+ $offset = 0;
490
+ $current['content'] = array();
491
+ $content_len = strlen($content);
492
+ while ($content_pos < $content_len) {
493
+ // if indefinite length construction was used and we have an end-of-content string next
494
+ // 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
495
+ if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
496
+ $length = $offset + 2; // +2 for the EOC
497
+ break 2;
498
+ }
499
+ $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
500
+ $content_pos += $temp['length'];
501
+ $current['content'][] = $temp;
502
+ $offset+= $temp['length'];
503
+ }
504
+ break;
505
+ case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
506
+ $temp = ord($content[$content_pos++]);
507
+ $current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
508
+ $valuen = 0;
509
+ // process septets
510
+ $content_len = strlen($content);
511
+ while ($content_pos < $content_len) {
512
+ $temp = ord($content[$content_pos++]);
513
+ $valuen <<= 7;
514
+ $valuen |= $temp & 0x7F;
515
+ if (~$temp & 0x80) {
516
+ $current['content'].= ".$valuen";
517
+ $valuen = 0;
518
+ }
519
+ }
520
+ // the eighth bit of the last byte should not be 1
521
+ //if ($temp >> 7) {
522
+ // return false;
523
+ //}
524
+ break;
525
+ /* Each character string type shall be encoded as if it had been declared:
526
+ [UNIVERSAL x] IMPLICIT OCTET STRING
527
+
528
+ -- X.690-0207.pdf#page=23 (paragraph 8.21.3)
529
+
530
+ Per that, we're not going to do any validation. If there are any illegal characters in the string,
531
+ we don't really care */
532
+ case FILE_ASN1_TYPE_NUMERIC_STRING:
533
+ // 0,1,2,3,4,5,6,7,8,9, and space
534
+ case FILE_ASN1_TYPE_PRINTABLE_STRING:
535
+ // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
536
+ // hyphen, full stop, solidus, colon, equal sign, question mark
537
+ case FILE_ASN1_TYPE_TELETEX_STRING:
538
+ // The Teletex character set in CCITT's T61, space, and delete
539
+ // see http://en.wikipedia.org/wiki/Teletex#Character_sets
540
+ case FILE_ASN1_TYPE_VIDEOTEX_STRING:
541
+ // The Videotex character set in CCITT's T.100 and T.101, space, and delete
542
+ case FILE_ASN1_TYPE_VISIBLE_STRING:
543
+ // Printing character sets of international ASCII, and space
544
+ case FILE_ASN1_TYPE_IA5_STRING:
545
+ // International Alphabet 5 (International ASCII)
546
+ case FILE_ASN1_TYPE_GRAPHIC_STRING:
547
+ // All registered G sets, and space
548
+ case FILE_ASN1_TYPE_GENERAL_STRING:
549
+ // All registered C and G sets, space and delete
550
+ case FILE_ASN1_TYPE_UTF8_STRING:
551
+ // ????
552
+ case FILE_ASN1_TYPE_BMP_STRING:
553
+ $current['content'] = substr($content, $content_pos);
554
+ break;
555
+ case FILE_ASN1_TYPE_UTC_TIME:
556
+ case FILE_ASN1_TYPE_GENERALIZED_TIME:
557
+ $current['content'] = class_exists('DateTime') ?
558
+ $this->_decodeDateTime(substr($content, $content_pos), $tag) :
559
+ $this->_decodeUnixTime(substr($content, $content_pos), $tag);
560
+ default:
561
+ }
562
+
563
+ $start+= $length;
564
+
565
+ // ie. length is the length of the full TLV encoding - it's not just the length of the value
566
+ return $current + array('length' => $start - $current['start']);
567
+ }
568
+
569
+ /**
570
+ * ASN.1 Map
571
+ *
572
+ * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
573
+ *
574
+ * "Special" mappings may be applied on a per tag-name basis via $special.
575
+ *
576
+ * @param array $decoded
577
+ * @param array $mapping
578
+ * @param array $special
579
+ * @return array
580
+ * @access public
581
+ */
582
+ function asn1map($decoded, $mapping, $special = array())
583
+ {
584
+ if (isset($mapping['explicit']) && is_array($decoded['content'])) {
585
+ $decoded = $decoded['content'][0];
586
+ }
587
+
588
+ switch (true) {
589
+ case $mapping['type'] == FILE_ASN1_TYPE_ANY:
590
+ $intype = $decoded['type'];
591
+ if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
592
+ return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
593
+ }
594
+ $inmap = $this->ANYmap[$intype];
595
+ if (is_string($inmap)) {
596
+ return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
597
+ }
598
+ break;
599
+ case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
600
+ foreach ($mapping['children'] as $key => $option) {
601
+ switch (true) {
602
+ case isset($option['constant']) && $option['constant'] == $decoded['constant']:
603
+ case !isset($option['constant']) && $option['type'] == $decoded['type']:
604
+ $value = $this->asn1map($decoded, $option, $special);
605
+ break;
606
+ case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
607
+ $v = $this->asn1map($decoded, $option, $special);
608
+ if (isset($v)) {
609
+ $value = $v;
610
+ }
611
+ }
612
+ if (isset($value)) {
613
+ if (isset($special[$key])) {
614
+ $value = call_user_func($special[$key], $value);
615
+ }
616
+ return array($key => $value);
617
+ }
618
+ }
619
+ return null;
620
+ case isset($mapping['implicit']):
621
+ case isset($mapping['explicit']):
622
+ case $decoded['type'] == $mapping['type']:
623
+ break;
624
+ default:
625
+ // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
626
+ // let it through
627
+ switch (true) {
628
+ case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
629
+ case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
630
+ case $mapping['type'] < 18:
631
+ case $mapping['type'] > 30:
632
+ return null;
633
+ }
634
+ }
635
+
636
+ if (isset($mapping['implicit'])) {
637
+ $decoded['type'] = $mapping['type'];
638
+ }
639
+
640
+ switch ($decoded['type']) {
641
+ case FILE_ASN1_TYPE_SEQUENCE:
642
+ $map = array();
643
+
644
+ // ignore the min and max
645
+ if (isset($mapping['min']) && isset($mapping['max'])) {
646
+ $child = $mapping['children'];
647
+ foreach ($decoded['content'] as $content) {
648
+ if (($map[] = $this->asn1map($content, $child, $special)) === null) {
649
+ return null;
650
+ }
651
+ }
652
+
653
+ return $map;
654
+ }
655
+
656
+ $n = count($decoded['content']);
657
+ $i = 0;
658
+
659
+ foreach ($mapping['children'] as $key => $child) {
660
+ $maymatch = $i < $n; // Match only existing input.
661
+ if ($maymatch) {
662
+ $temp = $decoded['content'][$i];
663
+
664
+ if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
665
+ // Get the mapping and input class & constant.
666
+ $childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
667
+ $constant = null;
668
+ if (isset($temp['constant'])) {
669
+ $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
670
+ }
671
+ if (isset($child['class'])) {
672
+ $childClass = $child['class'];
673
+ $constant = $child['cast'];
674
+ } elseif (isset($child['constant'])) {
675
+ $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
676
+ $constant = $child['constant'];
677
+ }
678
+
679
+ if (isset($constant) && isset($temp['constant'])) {
680
+ // Can only match if constants and class match.
681
+ $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
682
+ } else {
683
+ // Can only match if no constant expected and type matches or is generic.
684
+ $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
685
+ }
686
+ }
687
+ }
688
+
689
+ if ($maymatch) {
690
+ // Attempt submapping.
691
+ $candidate = $this->asn1map($temp, $child, $special);
692
+ $maymatch = $candidate !== null;
693
+ }
694
+
695
+ if ($maymatch) {
696
+ // Got the match: use it.
697
+ if (isset($special[$key])) {
698
+ $candidate = call_user_func($special[$key], $candidate);
699
+ }
700
+ $map[$key] = $candidate;
701
+ $i++;
702
+ } elseif (isset($child['default'])) {
703
+ $map[$key] = $child['default']; // Use default.
704
+ } elseif (!isset($child['optional'])) {
705
+ return null; // Syntax error.
706
+ }
707
+ }
708
+
709
+ // Fail mapping if all input items have not been consumed.
710
+ return $i < $n ? null: $map;
711
+
712
+ // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
713
+ case FILE_ASN1_TYPE_SET:
714
+ $map = array();
715
+
716
+ // ignore the min and max
717
+ if (isset($mapping['min']) && isset($mapping['max'])) {
718
+ $child = $mapping['children'];
719
+ foreach ($decoded['content'] as $content) {
720
+ if (($map[] = $this->asn1map($content, $child, $special)) === null) {
721
+ return null;
722
+ }
723
+ }
724
+
725
+ return $map;
726
+ }
727
+
728
+ for ($i = 0; $i < count($decoded['content']); $i++) {
729
+ $temp = $decoded['content'][$i];
730
+ $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
731
+ if (isset($temp['constant'])) {
732
+ $tempClass = isset($temp['class']) ? $temp['class'] : FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
733
+ }
734
+
735
+ foreach ($mapping['children'] as $key => $child) {
736
+ if (isset($map[$key])) {
737
+ continue;
738
+ }
739
+ $maymatch = true;
740
+ if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
741
+ $childClass = FILE_ASN1_CLASS_UNIVERSAL;
742
+ $constant = null;
743
+ if (isset($child['class'])) {
744
+ $childClass = $child['class'];
745
+ $constant = $child['cast'];
746
+ } elseif (isset($child['constant'])) {
747
+ $childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
748
+ $constant = $child['constant'];
749
+ }
750
+
751
+ if (isset($constant) && isset($temp['constant'])) {
752
+ // Can only match if constants and class match.
753
+ $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
754
+ } else {
755
+ // Can only match if no constant expected and type matches or is generic.
756
+ $maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
757
+ }
758
+ }
759
+
760
+ if ($maymatch) {
761
+ // Attempt submapping.
762
+ $candidate = $this->asn1map($temp, $child, $special);
763
+ $maymatch = $candidate !== null;
764
+ }
765
+
766
+ if (!$maymatch) {
767
+ break;
768
+ }
769
+
770
+ // Got the match: use it.
771
+ if (isset($special[$key])) {
772
+ $candidate = call_user_func($special[$key], $candidate);
773
+ }
774
+ $map[$key] = $candidate;
775
+ break;
776
+ }
777
+ }
778
+
779
+ foreach ($mapping['children'] as $key => $child) {
780
+ if (!isset($map[$key])) {
781
+ if (isset($child['default'])) {
782
+ $map[$key] = $child['default'];
783
+ } elseif (!isset($child['optional'])) {
784
+ return null;
785
+ }
786
+ }
787
+ }
788
+ return $map;
789
+ case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
790
+ return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
791
+ case FILE_ASN1_TYPE_UTC_TIME:
792
+ case FILE_ASN1_TYPE_GENERALIZED_TIME:
793
+ if (class_exists('DateTime')) {
794
+ if (isset($mapping['implicit'])) {
795
+ $decoded['content'] = $this->_decodeDateTime($decoded['content'], $decoded['type']);
796
+ }
797
+ if (!$decoded['content']) {
798
+ return false;
799
+ }
800
+ return $decoded['content']->format($this->format);
801
+ } else {
802
+ if (isset($mapping['implicit'])) {
803
+ $decoded['content'] = $this->_decodeUnixTime($decoded['content'], $decoded['type']);
804
+ }
805
+ return @date($this->format, $decoded['content']);
806
+ }
807
+ case FILE_ASN1_TYPE_BIT_STRING:
808
+ if (isset($mapping['mapping'])) {
809
+ $offset = ord($decoded['content'][0]);
810
+ $size = (strlen($decoded['content']) - 1) * 8 - $offset;
811
+ /*
812
+ From X.680-0207.pdf#page=46 (21.7):
813
+
814
+ "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
815
+ arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
816
+ therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
817
+ 0 bits."
818
+ */
819
+ $bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
820
+ for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
821
+ $current = ord($decoded['content'][$i]);
822
+ for ($j = $offset; $j < 8; $j++) {
823
+ $bits[] = (bool) ($current & (1 << $j));
824
+ }
825
+ $offset = 0;
826
+ }
827
+ $values = array();
828
+ $map = array_reverse($mapping['mapping']);
829
+ foreach ($map as $i => $value) {
830
+ if ($bits[$i]) {
831
+ $values[] = $value;
832
+ }
833
+ }
834
+ return $values;
835
+ }
836
+ case FILE_ASN1_TYPE_OCTET_STRING:
837
+ return base64_encode($decoded['content']);
838
+ case FILE_ASN1_TYPE_NULL:
839
+ return '';
840
+ case FILE_ASN1_TYPE_BOOLEAN:
841
+ return $decoded['content'];
842
+ case FILE_ASN1_TYPE_NUMERIC_STRING:
843
+ case FILE_ASN1_TYPE_PRINTABLE_STRING:
844
+ case FILE_ASN1_TYPE_TELETEX_STRING:
845
+ case FILE_ASN1_TYPE_VIDEOTEX_STRING:
846
+ case FILE_ASN1_TYPE_IA5_STRING:
847
+ case FILE_ASN1_TYPE_GRAPHIC_STRING:
848
+ case FILE_ASN1_TYPE_VISIBLE_STRING:
849
+ case FILE_ASN1_TYPE_GENERAL_STRING:
850
+ case FILE_ASN1_TYPE_UNIVERSAL_STRING:
851
+ case FILE_ASN1_TYPE_UTF8_STRING:
852
+ case FILE_ASN1_TYPE_BMP_STRING:
853
+ return $decoded['content'];
854
+ case FILE_ASN1_TYPE_INTEGER:
855
+ case FILE_ASN1_TYPE_ENUMERATED:
856
+ $temp = $decoded['content'];
857
+ if (isset($mapping['implicit'])) {
858
+ $temp = new Math_BigInteger($decoded['content'], -256);
859
+ }
860
+ if (isset($mapping['mapping'])) {
861
+ $temp = (int) $temp->toString();
862
+ return isset($mapping['mapping'][$temp]) ?
863
+ $mapping['mapping'][$temp] :
864
+ false;
865
+ }
866
+ return $temp;
867
+ }
868
+ }
869
+
870
+ /**
871
+ * ASN.1 Encode
872
+ *
873
+ * DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
874
+ * an ASN.1 compiler.
875
+ *
876
+ * "Special" mappings can be applied via $special.
877
+ *
878
+ * @param string $source
879
+ * @param string $mapping
880
+ * @param int $idx
881
+ * @return string
882
+ * @access public
883
+ */
884
+ function encodeDER($source, $mapping, $special = array())
885
+ {
886
+ $this->location = array();
887
+ return $this->_encode_der($source, $mapping, null, $special);
888
+ }
889
+
890
+ /**
891
+ * ASN.1 Encode (Helper function)
892
+ *
893
+ * @param string $source
894
+ * @param string $mapping
895
+ * @param int $idx
896
+ * @return string
897
+ * @access private
898
+ */
899
+ function _encode_der($source, $mapping, $idx = null, $special = array())
900
+ {
901
+ if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
902
+ return $source->element;
903
+ }
904
+
905
+ // do not encode (implicitly optional) fields with value set to default
906
+ if (isset($mapping['default']) && $source === $mapping['default']) {
907
+ return '';
908
+ }
909
+
910
+ if (isset($idx)) {
911
+ if (isset($special[$idx])) {
912
+ $source = call_user_func($special[$idx], $source);
913
+ }
914
+ $this->location[] = $idx;
915
+ }
916
+
917
+ $tag = $mapping['type'];
918
+
919
+ switch ($tag) {
920
+ case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
921
+ case FILE_ASN1_TYPE_SEQUENCE:
922
+ $tag|= 0x20; // set the constructed bit
923
+
924
+ // ignore the min and max
925
+ if (isset($mapping['min']) && isset($mapping['max'])) {
926
+ $value = array();
927
+ $child = $mapping['children'];
928
+
929
+ foreach ($source as $content) {
930
+ $temp = $this->_encode_der($content, $child, null, $special);
931
+ if ($temp === false) {
932
+ return false;
933
+ }
934
+ $value[]= $temp;
935
+ }
936
+ /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
937
+ as octet strings with the shorter components being padded at their trailing end with 0-octets.
938
+ NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
939
+
940
+ -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
941
+ if ($mapping['type'] == FILE_ASN1_TYPE_SET) {
942
+ sort($value);
943
+ }
944
+ $value = implode($value, '');
945
+ break;
946
+ }
947
+
948
+ $value = '';
949
+ foreach ($mapping['children'] as $key => $child) {
950
+ if (!array_key_exists($key, $source)) {
951
+ if (!isset($child['optional'])) {
952
+ return false;
953
+ }
954
+ continue;
955
+ }
956
+
957
+ $temp = $this->_encode_der($source[$key], $child, $key, $special);
958
+ if ($temp === false) {
959
+ return false;
960
+ }
961
+
962
+ // An empty child encoding means it has been optimized out.
963
+ // Else we should have at least one tag byte.
964
+ if ($temp === '') {
965
+ continue;
966
+ }
967
+
968
+ // if isset($child['constant']) is true then isset($child['optional']) should be true as well
969
+ if (isset($child['constant'])) {
970
+ /*
971
+ From X.680-0207.pdf#page=58 (30.6):
972
+
973
+ "The tagging construction specifies explicit tagging if any of the following holds:
974
+ ...
975
+ c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
976
+ AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
977
+ an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
978
+ */
979
+ if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
980
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
981
+ $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
982
+ } else {
983
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
984
+ $temp = $subtag . substr($temp, 1);
985
+ }
986
+ }
987
+ $value.= $temp;
988
+ }
989
+ break;
990
+ case FILE_ASN1_TYPE_CHOICE:
991
+ $temp = false;
992
+
993
+ foreach ($mapping['children'] as $key => $child) {
994
+ if (!isset($source[$key])) {
995
+ continue;
996
+ }
997
+
998
+ $temp = $this->_encode_der($source[$key], $child, $key, $special);
999
+ if ($temp === false) {
1000
+ return false;
1001
+ }
1002
+
1003
+ // An empty child encoding means it has been optimized out.
1004
+ // Else we should have at least one tag byte.
1005
+ if ($temp === '') {
1006
+ continue;
1007
+ }
1008
+
1009
+ $tag = ord($temp[0]);
1010
+
1011
+ // if isset($child['constant']) is true then isset($child['optional']) should be true as well
1012
+ if (isset($child['constant'])) {
1013
+ if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
1014
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
1015
+ $temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
1016
+ } else {
1017
+ $subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
1018
+ $temp = $subtag . substr($temp, 1);
1019
+ }
1020
+ }
1021
+ }
1022
+
1023
+ if (isset($idx)) {
1024
+ array_pop($this->location);
1025
+ }
1026
+
1027
+ if ($temp && isset($mapping['cast'])) {
1028
+ $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
1029
+ }
1030
+
1031
+ return $temp;
1032
+ case FILE_ASN1_TYPE_INTEGER:
1033
+ case FILE_ASN1_TYPE_ENUMERATED:
1034
+ if (!isset($mapping['mapping'])) {
1035
+ if (is_numeric($source)) {
1036
+ $source = new Math_BigInteger($source);
1037
+ }
1038
+ $value = $source->toBytes(true);
1039
+ } else {
1040
+ $value = array_search($source, $mapping['mapping']);
1041
+ if ($value === false) {
1042
+ return false;
1043
+ }
1044
+ $value = new Math_BigInteger($value);
1045
+ $value = $value->toBytes(true);
1046
+ }
1047
+ if (!strlen($value)) {
1048
+ $value = chr(0);
1049
+ }
1050
+ break;
1051
+ case FILE_ASN1_TYPE_UTC_TIME:
1052
+ case FILE_ASN1_TYPE_GENERALIZED_TIME:
1053
+ $format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
1054
+ $format.= 'mdHis';
1055
+ if (!class_exists('DateTime')) {
1056
+ $value = @gmdate($format, strtotime($source)) . 'Z';
1057
+ } else {
1058
+ $date = new DateTime($source, new DateTimeZone('GMT'));
1059
+ $value = $date->format($format) . 'Z';
1060
+ }
1061
+ break;
1062
+ case FILE_ASN1_TYPE_BIT_STRING:
1063
+ if (isset($mapping['mapping'])) {
1064
+ $bits = array_fill(0, count($mapping['mapping']), 0);
1065
+ $size = 0;
1066
+ for ($i = 0; $i < count($mapping['mapping']); $i++) {
1067
+ if (in_array($mapping['mapping'][$i], $source)) {
1068
+ $bits[$i] = 1;
1069
+ $size = $i;
1070
+ }
1071
+ }
1072
+
1073
+ if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
1074
+ $size = $mapping['min'] - 1;
1075
+ }
1076
+
1077
+ $offset = 8 - (($size + 1) & 7);
1078
+ $offset = $offset !== 8 ? $offset : 0;
1079
+
1080
+ $value = chr($offset);
1081
+
1082
+ for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
1083
+ unset($bits[$i]);
1084
+ }
1085
+
1086
+ $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
1087
+ $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
1088
+ foreach ($bytes as $byte) {
1089
+ $value.= chr(bindec($byte));
1090
+ }
1091
+
1092
+ break;
1093
+ }
1094
+ case FILE_ASN1_TYPE_OCTET_STRING:
1095
+ /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
1096
+ the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
1097
+
1098
+ -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
1099
+ $value = base64_decode($source);
1100
+ break;
1101
+ case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
1102
+ $oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
1103
+ if ($oid === false) {
1104
+ user_error('Invalid OID');
1105
+ return false;
1106
+ }
1107
+ $value = '';
1108
+ $parts = explode('.', $oid);
1109
+ $value = chr(40 * $parts[0] + $parts[1]);
1110
+ for ($i = 2; $i < count($parts); $i++) {
1111
+ $temp = '';
1112
+ if (!$parts[$i]) {
1113
+ $temp = "\0";
1114
+ } else {
1115
+ while ($parts[$i]) {
1116
+ $temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
1117
+ $parts[$i] >>= 7;
1118
+ }
1119
+ $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
1120
+ }
1121
+ $value.= $temp;
1122
+ }
1123
+ break;
1124
+ case FILE_ASN1_TYPE_ANY:
1125
+ $loc = $this->location;
1126
+ if (isset($idx)) {
1127
+ array_pop($this->location);
1128
+ }
1129
+
1130
+ switch (true) {
1131
+ case !isset($source):
1132
+ return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
1133
+ case is_int($source):
1134
+ case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
1135
+ return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
1136
+ case is_float($source):
1137
+ return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
1138
+ case is_bool($source):
1139
+ return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
1140
+ case is_array($source) && count($source) == 1:
1141
+ $typename = implode('', array_keys($source));
1142
+ $outtype = array_search($typename, $this->ANYmap, true);
1143
+ if ($outtype !== false) {
1144
+ return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
1145
+ }
1146
+ }
1147
+
1148
+ $filters = $this->filters;
1149
+ foreach ($loc as $part) {
1150
+ if (!isset($filters[$part])) {
1151
+ $filters = false;
1152
+ break;
1153
+ }
1154
+ $filters = $filters[$part];
1155
+ }
1156
+ if ($filters === false) {
1157
+ user_error('No filters defined for ' . implode('/', $loc));
1158
+ return false;
1159
+ }
1160
+ return $this->_encode_der($source, $filters + $mapping, null, $special);
1161
+ case FILE_ASN1_TYPE_NULL:
1162
+ $value = '';
1163
+ break;
1164
+ case FILE_ASN1_TYPE_NUMERIC_STRING:
1165
+ case FILE_ASN1_TYPE_TELETEX_STRING:
1166
+ case FILE_ASN1_TYPE_PRINTABLE_STRING:
1167
+ case FILE_ASN1_TYPE_UNIVERSAL_STRING:
1168
+ case FILE_ASN1_TYPE_UTF8_STRING:
1169
+ case FILE_ASN1_TYPE_BMP_STRING:
1170
+ case FILE_ASN1_TYPE_IA5_STRING:
1171
+ case FILE_ASN1_TYPE_VISIBLE_STRING:
1172
+ case FILE_ASN1_TYPE_VIDEOTEX_STRING:
1173
+ case FILE_ASN1_TYPE_GRAPHIC_STRING:
1174
+ case FILE_ASN1_TYPE_GENERAL_STRING:
1175
+ $value = $source;
1176
+ break;
1177
+ case FILE_ASN1_TYPE_BOOLEAN:
1178
+ $value = $source ? "\xFF" : "\x00";
1179
+ break;
1180
+ default:
1181
+ user_error('Mapping provides no type definition for ' . implode('/', $this->location));
1182
+ return false;
1183
+ }
1184
+
1185
+ if (isset($idx)) {
1186
+ array_pop($this->location);
1187
+ }
1188
+
1189
+ if (isset($mapping['cast'])) {
1190
+ if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
1191
+ $value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1192
+ $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
1193
+ } else {
1194
+ $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
1195
+ }
1196
+ }
1197
+
1198
+ return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
1199
+ }
1200
+
1201
+ /**
1202
+ * DER-encode the length
1203
+ *
1204
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1205
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1206
+ *
1207
+ * @access private
1208
+ * @param int $length
1209
+ * @return string
1210
+ */
1211
+ function _encodeLength($length)
1212
+ {
1213
+ if ($length <= 0x7F) {
1214
+ return chr($length);
1215
+ }
1216
+
1217
+ $temp = ltrim(pack('N', $length), chr(0));
1218
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
1219
+ }
1220
+
1221
+ /**
1222
+ * BER-decode the time (using UNIX time)
1223
+ *
1224
+ * Called by _decode_ber() and in the case of implicit tags asn1map().
1225
+ *
1226
+ * @access private
1227
+ * @param string $content
1228
+ * @param int $tag
1229
+ * @return string
1230
+ */
1231
+ function _decodeUnixTime($content, $tag)
1232
+ {
1233
+ /* UTCTime:
1234
+ http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
1235
+ http://www.obj-sys.com/asn1tutorial/node15.html
1236
+
1237
+ GeneralizedTime:
1238
+ http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
1239
+ http://www.obj-sys.com/asn1tutorial/node14.html */
1240
+
1241
+ $pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
1242
+ '#^(..)(..)(..)(..)(..)(..)?(.*)$#' :
1243
+ '#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
1244
+
1245
+ preg_match($pattern, $content, $matches);
1246
+
1247
+ list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
1248
+
1249
+ if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
1250
+ $year = $year >= 50 ? "19$year" : "20$year";
1251
+ }
1252
+
1253
+ if ($timezone == 'Z') {
1254
+ $mktime = 'gmmktime';
1255
+ $timezone = 0;
1256
+ } elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
1257
+ $mktime = 'gmmktime';
1258
+ $timezone = 60 * $matches[3] + 3600 * $matches[2];
1259
+ if ($matches[1] == '-') {
1260
+ $timezone = -$timezone;
1261
+ }
1262
+ } else {
1263
+ $mktime = 'mktime';
1264
+ $timezone = 0;
1265
+ }
1266
+
1267
+ return @$mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year) + $timezone;
1268
+ }
1269
+
1270
+
1271
+ /**
1272
+ * BER-decode the time (using DateTime)
1273
+ *
1274
+ * Called by _decode_ber() and in the case of implicit tags asn1map().
1275
+ *
1276
+ * @access private
1277
+ * @param string $content
1278
+ * @param int $tag
1279
+ * @return string
1280
+ */
1281
+ function _decodeDateTime($content, $tag)
1282
+ {
1283
+ /* UTCTime:
1284
+ http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
1285
+ http://www.obj-sys.com/asn1tutorial/node15.html
1286
+
1287
+ GeneralizedTime:
1288
+ http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
1289
+ http://www.obj-sys.com/asn1tutorial/node14.html */
1290
+
1291
+ $format = 'YmdHis';
1292
+
1293
+ if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
1294
+ // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
1295
+ // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
1296
+ // browsers parse it phpseclib ought to too
1297
+ if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
1298
+ $content = $matches[1] . '00' . $matches[2];
1299
+ }
1300
+ $prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
1301
+ $content = $prefix . $content;
1302
+ } elseif (strpos($content, '.') !== false) {
1303
+ $format.= '.u';
1304
+ }
1305
+
1306
+ if ($content[strlen($content) - 1] == 'Z') {
1307
+ $content = substr($content, 0, -1) . '+0000';
1308
+ }
1309
+
1310
+ if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
1311
+ $format.= 'O';
1312
+ }
1313
+
1314
+ // error supression isn't necessary as of PHP 7.0:
1315
+ // http://php.net/manual/en/migration70.other-changes.php
1316
+ return @DateTime::createFromFormat($format, $content);
1317
+ }
1318
+
1319
+ /**
1320
+ * Set the time format
1321
+ *
1322
+ * Sets the time / date format for asn1map().
1323
+ *
1324
+ * @access public
1325
+ * @param string $format
1326
+ */
1327
+ function setTimeFormat($format)
1328
+ {
1329
+ $this->format = $format;
1330
+ }
1331
+
1332
+ /**
1333
+ * Load OIDs
1334
+ *
1335
+ * Load the relevant OIDs for a particular ASN.1 semantic mapping.
1336
+ *
1337
+ * @access public
1338
+ * @param array $oids
1339
+ */
1340
+ function loadOIDs($oids)
1341
+ {
1342
+ $this->oids = $oids;
1343
+ }
1344
+
1345
+ /**
1346
+ * Load filters
1347
+ *
1348
+ * See File_X509, etc, for an example.
1349
+ *
1350
+ * @access public
1351
+ * @param array $filters
1352
+ */
1353
+ function loadFilters($filters)
1354
+ {
1355
+ $this->filters = $filters;
1356
+ }
1357
+
1358
+ /**
1359
+ * String Shift
1360
+ *
1361
+ * Inspired by array_shift
1362
+ *
1363
+ * @param string $string
1364
+ * @param int $index
1365
+ * @return string
1366
+ * @access private
1367
+ */
1368
+ function _string_shift(&$string, $index = 1)
1369
+ {
1370
+ $substr = substr($string, 0, $index);
1371
+ $string = substr($string, $index);
1372
+ return $substr;
1373
+ }
1374
+
1375
+ /**
1376
+ * String type conversion
1377
+ *
1378
+ * This is a lazy conversion, dealing only with character size.
1379
+ * No real conversion table is used.
1380
+ *
1381
+ * @param string $in
1382
+ * @param int $from
1383
+ * @param int $to
1384
+ * @return string
1385
+ * @access public
1386
+ */
1387
+ function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
1388
+ {
1389
+ if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
1390
+ return false;
1391
+ }
1392
+ $insize = $this->stringTypeSize[$from];
1393
+ $outsize = $this->stringTypeSize[$to];
1394
+ $inlength = strlen($in);
1395
+ $out = '';
1396
+
1397
+ for ($i = 0; $i < $inlength;) {
1398
+ if ($inlength - $i < $insize) {
1399
+ return false;
1400
+ }
1401
+
1402
+ // Get an input character as a 32-bit value.
1403
+ $c = ord($in[$i++]);
1404
+ switch (true) {
1405
+ case $insize == 4:
1406
+ $c = ($c << 8) | ord($in[$i++]);
1407
+ $c = ($c << 8) | ord($in[$i++]);
1408
+ case $insize == 2:
1409
+ $c = ($c << 8) | ord($in[$i++]);
1410
+ case $insize == 1:
1411
+ break;
1412
+ case ($c & 0x80) == 0x00:
1413
+ break;
1414
+ case ($c & 0x40) == 0x00:
1415
+ return false;
1416
+ default:
1417
+ $bit = 6;
1418
+ do {
1419
+ if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
1420
+ return false;
1421
+ }
1422
+ $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
1423
+ $bit += 5;
1424
+ $mask = 1 << $bit;
1425
+ } while ($c & $bit);
1426
+ $c &= $mask - 1;
1427
+ break;
1428
+ }
1429
+
1430
+ // Convert and append the character to output string.
1431
+ $v = '';
1432
+ switch (true) {
1433
+ case $outsize == 4:
1434
+ $v .= chr($c & 0xFF);
1435
+ $c >>= 8;
1436
+ $v .= chr($c & 0xFF);
1437
+ $c >>= 8;
1438
+ case $outsize == 2:
1439
+ $v .= chr($c & 0xFF);
1440
+ $c >>= 8;
1441
+ case $outsize == 1:
1442
+ $v .= chr($c & 0xFF);
1443
+ $c >>= 8;
1444
+ if ($c) {
1445
+ return false;
1446
+ }
1447
+ break;
1448
+ case ($c & 0x80000000) != 0:
1449
+ return false;
1450
+ case $c >= 0x04000000:
1451
+ $v .= chr(0x80 | ($c & 0x3F));
1452
+ $c = ($c >> 6) | 0x04000000;
1453
+ case $c >= 0x00200000:
1454
+ $v .= chr(0x80 | ($c & 0x3F));
1455
+ $c = ($c >> 6) | 0x00200000;
1456
+ case $c >= 0x00010000:
1457
+ $v .= chr(0x80 | ($c & 0x3F));
1458
+ $c = ($c >> 6) | 0x00010000;
1459
+ case $c >= 0x00000800:
1460
+ $v .= chr(0x80 | ($c & 0x3F));
1461
+ $c = ($c >> 6) | 0x00000800;
1462
+ case $c >= 0x00000080:
1463
+ $v .= chr(0x80 | ($c & 0x3F));
1464
+ $c = ($c >> 6) | 0x000000C0;
1465
+ default:
1466
+ $v .= chr($c);
1467
+ break;
1468
+ }
1469
+ $out .= strrev($v);
1470
+ }
1471
+ return $out;
1472
+ }
1473
+ }
phpseclib/File/X509.php ADDED
@@ -0,0 +1,4958 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP X.509 Parser
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Encode and decode X.509 certificates.
9
+ *
10
+ * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and
11
+ * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}.
12
+ *
13
+ * Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a
14
+ * portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is
15
+ * 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
16
+ * be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the
17
+ * the certificate all together unless the certificate is re-signed.
18
+ *
19
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
20
+ * of this software and associated documentation files (the "Software"), to deal
21
+ * in the Software without restriction, including without limitation the rights
22
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23
+ * copies of the Software, and to permit persons to whom the Software is
24
+ * furnished to do so, subject to the following conditions:
25
+ *
26
+ * The above copyright notice and this permission notice shall be included in
27
+ * all copies or substantial portions of the Software.
28
+ *
29
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35
+ * THE SOFTWARE.
36
+ *
37
+ * @category File
38
+ * @package File_X509
39
+ * @author Jim Wigginton <terrafrost@php.net>
40
+ * @copyright 2012 Jim Wigginton
41
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
42
+ * @link http://phpseclib.sourceforge.net
43
+ */
44
+
45
+ /**
46
+ * Include File_ASN1
47
+ */
48
+ if (!class_exists('File_ASN1')) {
49
+ include_once 'ASN1.php';
50
+ }
51
+
52
+ /**
53
+ * Flag to only accept signatures signed by certificate authorities
54
+ *
55
+ * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
56
+ *
57
+ * @access public
58
+ */
59
+ define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1);
60
+
61
+ /**#@+
62
+ * @access public
63
+ * @see self::getDN()
64
+ */
65
+ /**
66
+ * Return internal array representation
67
+ */
68
+ define('FILE_X509_DN_ARRAY', 0);
69
+ /**
70
+ * Return string
71
+ */
72
+ define('FILE_X509_DN_STRING', 1);
73
+ /**
74
+ * Return ASN.1 name string
75
+ */
76
+ define('FILE_X509_DN_ASN1', 2);
77
+ /**
78
+ * Return OpenSSL compatible array
79
+ */
80
+ define('FILE_X509_DN_OPENSSL', 3);
81
+ /**
82
+ * Return canonical ASN.1 RDNs string
83
+ */
84
+ define('FILE_X509_DN_CANON', 4);
85
+ /**
86
+ * Return name hash for file indexing
87
+ */
88
+ define('FILE_X509_DN_HASH', 5);
89
+ /**#@-*/
90
+
91
+ /**#@+
92
+ * @access public
93
+ * @see self::saveX509()
94
+ * @see self::saveCSR()
95
+ * @see self::saveCRL()
96
+ */
97
+ /**
98
+ * Save as PEM
99
+ *
100
+ * ie. a base64-encoded PEM with a header and a footer
101
+ */
102
+ define('FILE_X509_FORMAT_PEM', 0);
103
+ /**
104
+ * Save as DER
105
+ */
106
+ define('FILE_X509_FORMAT_DER', 1);
107
+ /**
108
+ * Save as a SPKAC
109
+ *
110
+ * Only works on CSRs. Not currently supported.
111
+ */
112
+ define('FILE_X509_FORMAT_SPKAC', 2);
113
+ /**
114
+ * Auto-detect the format
115
+ *
116
+ * Used only by the load*() functions
117
+ */
118
+ define('FILE_X509_FORMAT_AUTO_DETECT', 3);
119
+ /**#@-*/
120
+
121
+ /**
122
+ * Attribute value disposition.
123
+ * If disposition is >= 0, this is the index of the target value.
124
+ */
125
+ define('FILE_X509_ATTR_ALL', -1); // All attribute values (array).
126
+ define('FILE_X509_ATTR_APPEND', -2); // Add a value.
127
+ define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
128
+
129
+ /**
130
+ * Pure-PHP X.509 Parser
131
+ *
132
+ * @package File_X509
133
+ * @author Jim Wigginton <terrafrost@php.net>
134
+ * @access public
135
+ */
136
+ class File_X509
137
+ {
138
+ /**
139
+ * ASN.1 syntax for X.509 certificates
140
+ *
141
+ * @var array
142
+ * @access private
143
+ */
144
+ var $Certificate;
145
+
146
+ /**#@+
147
+ * ASN.1 syntax for various extensions
148
+ *
149
+ * @access private
150
+ */
151
+ var $DirectoryString;
152
+ var $PKCS9String;
153
+ var $AttributeValue;
154
+ var $Extensions;
155
+ var $KeyUsage;
156
+ var $ExtKeyUsageSyntax;
157
+ var $BasicConstraints;
158
+ var $KeyIdentifier;
159
+ var $CRLDistributionPoints;
160
+ var $AuthorityKeyIdentifier;
161
+ var $CertificatePolicies;
162
+ var $AuthorityInfoAccessSyntax;
163
+ var $SubjectAltName;
164
+ var $SubjectDirectoryAttributes;
165
+ var $PrivateKeyUsagePeriod;
166
+ var $IssuerAltName;
167
+ var $PolicyMappings;
168
+ var $NameConstraints;
169
+
170
+ var $CPSuri;
171
+ var $UserNotice;
172
+
173
+ var $netscape_cert_type;
174
+ var $netscape_comment;
175
+ var $netscape_ca_policy_url;
176
+
177
+ var $Name;
178
+ var $RelativeDistinguishedName;
179
+ var $CRLNumber;
180
+ var $CRLReason;
181
+ var $IssuingDistributionPoint;
182
+ var $InvalidityDate;
183
+ var $CertificateIssuer;
184
+ var $HoldInstructionCode;
185
+ var $SignedPublicKeyAndChallenge;
186
+ /**#@-*/
187
+
188
+ /**#@+
189
+ * ASN.1 syntax for various DN attributes
190
+ *
191
+ * @access private
192
+ */
193
+ var $PostalAddress;
194
+ /**#@-*/
195
+
196
+ /**
197
+ * ASN.1 syntax for Certificate Signing Requests (RFC2986)
198
+ *
199
+ * @var array
200
+ * @access private
201
+ */
202
+ var $CertificationRequest;
203
+
204
+ /**
205
+ * ASN.1 syntax for Certificate Revocation Lists (RFC5280)
206
+ *
207
+ * @var array
208
+ * @access private
209
+ */
210
+ var $CertificateList;
211
+
212
+ /**
213
+ * Distinguished Name
214
+ *
215
+ * @var array
216
+ * @access private
217
+ */
218
+ var $dn;
219
+
220
+ /**
221
+ * Public key
222
+ *
223
+ * @var string
224
+ * @access private
225
+ */
226
+ var $publicKey;
227
+
228
+ /**
229
+ * Private key
230
+ *
231
+ * @var string
232
+ * @access private
233
+ */
234
+ var $privateKey;
235
+
236
+ /**
237
+ * Object identifiers for X.509 certificates
238
+ *
239
+ * @var array
240
+ * @access private
241
+ * @link http://en.wikipedia.org/wiki/Object_identifier
242
+ */
243
+ var $oids;
244
+
245
+ /**
246
+ * The certificate authorities
247
+ *
248
+ * @var array
249
+ * @access private
250
+ */
251
+ var $CAs;
252
+
253
+ /**
254
+ * The currently loaded certificate
255
+ *
256
+ * @var array
257
+ * @access private
258
+ */
259
+ var $currentCert;
260
+
261
+ /**
262
+ * The signature subject
263
+ *
264
+ * There's no guarantee File_X509 is going to re-encode an X.509 cert in the same way it was originally
265
+ * encoded so we take save the portion of the original cert that the signature would have made for.
266
+ *
267
+ * @var string
268
+ * @access private
269
+ */
270
+ var $signatureSubject;
271
+
272
+ /**
273
+ * Certificate Start Date
274
+ *
275
+ * @var string
276
+ * @access private
277
+ */
278
+ var $startDate;
279
+
280
+ /**
281
+ * Certificate End Date
282
+ *
283
+ * @var string
284
+ * @access private
285
+ */
286
+ var $endDate;
287
+
288
+ /**
289
+ * Serial Number
290
+ *
291
+ * @var string
292
+ * @access private
293
+ */
294
+ var $serialNumber;
295
+
296
+ /**
297
+ * Key Identifier
298
+ *
299
+ * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
300
+ * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
301
+ *
302
+ * @var string
303
+ * @access private
304
+ */
305
+ var $currentKeyIdentifier;
306
+
307
+ /**
308
+ * CA Flag
309
+ *
310
+ * @var bool
311
+ * @access private
312
+ */
313
+ var $caFlag = false;
314
+
315
+ /**
316
+ * SPKAC Challenge
317
+ *
318
+ * @var string
319
+ * @access private
320
+ */
321
+ var $challenge;
322
+
323
+ /**
324
+ * Default Constructor.
325
+ *
326
+ * @return File_X509
327
+ * @access public
328
+ */
329
+ function __construct()
330
+ {
331
+ if (!class_exists('Math_BigInteger')) {
332
+ include_once 'Math/BigInteger.php';
333
+ }
334
+
335
+ // Explicitly Tagged Module, 1988 Syntax
336
+ // http://tools.ietf.org/html/rfc5280#appendix-A.1
337
+
338
+ $this->DirectoryString = array(
339
+ 'type' => FILE_ASN1_TYPE_CHOICE,
340
+ 'children' => array(
341
+ 'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING),
342
+ 'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
343
+ 'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING),
344
+ 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING),
345
+ 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING)
346
+ )
347
+ );
348
+
349
+ $this->PKCS9String = array(
350
+ 'type' => FILE_ASN1_TYPE_CHOICE,
351
+ 'children' => array(
352
+ 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
353
+ 'directoryString' => $this->DirectoryString
354
+ )
355
+ );
356
+
357
+ $this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY);
358
+
359
+ $AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
360
+
361
+ $AttributeTypeAndValue = array(
362
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
363
+ 'children' => array(
364
+ 'type' => $AttributeType,
365
+ 'value'=> $this->AttributeValue
366
+ )
367
+ );
368
+
369
+ /*
370
+ In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
371
+ but they can be useful at times when either there is no unique attribute in the entry or you
372
+ want to ensure that the entry's DN contains some useful identifying information.
373
+
374
+ - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
375
+ */
376
+ $this->RelativeDistinguishedName = array(
377
+ 'type' => FILE_ASN1_TYPE_SET,
378
+ 'min' => 1,
379
+ 'max' => -1,
380
+ 'children' => $AttributeTypeAndValue
381
+ );
382
+
383
+ // http://tools.ietf.org/html/rfc5280#section-4.1.2.4
384
+ $RDNSequence = array(
385
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
386
+ // RDNSequence does not define a min or a max, which means it doesn't have one
387
+ 'min' => 0,
388
+ 'max' => -1,
389
+ 'children' => $this->RelativeDistinguishedName
390
+ );
391
+
392
+ $this->Name = array(
393
+ 'type' => FILE_ASN1_TYPE_CHOICE,
394
+ 'children' => array(
395
+ 'rdnSequence' => $RDNSequence
396
+ )
397
+ );
398
+
399
+ // http://tools.ietf.org/html/rfc5280#section-4.1.1.2
400
+ $AlgorithmIdentifier = array(
401
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
402
+ 'children' => array(
403
+ 'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
404
+ 'parameters' => array(
405
+ 'type' => FILE_ASN1_TYPE_ANY,
406
+ 'optional' => true
407
+ )
408
+ )
409
+ );
410
+
411
+ /*
412
+ A certificate using system MUST reject the certificate if it encounters
413
+ a critical extension it does not recognize; however, a non-critical
414
+ extension may be ignored if it is not recognized.
415
+
416
+ http://tools.ietf.org/html/rfc5280#section-4.2
417
+ */
418
+ $Extension = array(
419
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
420
+ 'children' => array(
421
+ 'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
422
+ 'critical' => array(
423
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
424
+ 'optional' => true,
425
+ 'default' => false
426
+ ),
427
+ 'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING)
428
+ )
429
+ );
430
+
431
+ $this->Extensions = array(
432
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
433
+ 'min' => 1,
434
+ // technically, it's MAX, but we'll assume anything < 0 is MAX
435
+ 'max' => -1,
436
+ // if 'children' isn't an array then 'min' and 'max' must be defined
437
+ 'children' => $Extension
438
+ );
439
+
440
+ $SubjectPublicKeyInfo = array(
441
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
442
+ 'children' => array(
443
+ 'algorithm' => $AlgorithmIdentifier,
444
+ 'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
445
+ )
446
+ );
447
+
448
+ $UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING);
449
+
450
+ $Time = array(
451
+ 'type' => FILE_ASN1_TYPE_CHOICE,
452
+ 'children' => array(
453
+ 'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME),
454
+ 'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
455
+ )
456
+ );
457
+
458
+ // http://tools.ietf.org/html/rfc5280#section-4.1.2.5
459
+ $Validity = array(
460
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
461
+ 'children' => array(
462
+ 'notBefore' => $Time,
463
+ 'notAfter' => $Time
464
+ )
465
+ );
466
+
467
+ $CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
468
+
469
+ $Version = array(
470
+ 'type' => FILE_ASN1_TYPE_INTEGER,
471
+ 'mapping' => array('v1', 'v2', 'v3')
472
+ );
473
+
474
+ // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
475
+ $TBSCertificate = array(
476
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
477
+ 'children' => array(
478
+ // technically, default implies optional, but we'll define it as being optional, none-the-less, just to
479
+ // reenforce that fact
480
+ 'version' => array(
481
+ 'constant' => 0,
482
+ 'optional' => true,
483
+ 'explicit' => true,
484
+ 'default' => 'v1'
485
+ ) + $Version,
486
+ 'serialNumber' => $CertificateSerialNumber,
487
+ 'signature' => $AlgorithmIdentifier,
488
+ 'issuer' => $this->Name,
489
+ 'validity' => $Validity,
490
+ 'subject' => $this->Name,
491
+ 'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
492
+ // implicit means that the T in the TLV structure is to be rewritten, regardless of the type
493
+ 'issuerUniqueID' => array(
494
+ 'constant' => 1,
495
+ 'optional' => true,
496
+ 'implicit' => true
497
+ ) + $UniqueIdentifier,
498
+ 'subjectUniqueID' => array(
499
+ 'constant' => 2,
500
+ 'optional' => true,
501
+ 'implicit' => true
502
+ ) + $UniqueIdentifier,
503
+ // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
504
+ // it's not IMPLICIT, it's EXPLICIT
505
+ 'extensions' => array(
506
+ 'constant' => 3,
507
+ 'optional' => true,
508
+ 'explicit' => true
509
+ ) + $this->Extensions
510
+ )
511
+ );
512
+
513
+ $this->Certificate = array(
514
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
515
+ 'children' => array(
516
+ 'tbsCertificate' => $TBSCertificate,
517
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
518
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
519
+ )
520
+ );
521
+
522
+ $this->KeyUsage = array(
523
+ 'type' => FILE_ASN1_TYPE_BIT_STRING,
524
+ 'mapping' => array(
525
+ 'digitalSignature',
526
+ 'nonRepudiation',
527
+ 'keyEncipherment',
528
+ 'dataEncipherment',
529
+ 'keyAgreement',
530
+ 'keyCertSign',
531
+ 'cRLSign',
532
+ 'encipherOnly',
533
+ 'decipherOnly'
534
+ )
535
+ );
536
+
537
+ $this->BasicConstraints = array(
538
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
539
+ 'children' => array(
540
+ 'cA' => array(
541
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
542
+ 'optional' => true,
543
+ 'default' => false
544
+ ),
545
+ 'pathLenConstraint' => array(
546
+ 'type' => FILE_ASN1_TYPE_INTEGER,
547
+ 'optional' => true
548
+ )
549
+ )
550
+ );
551
+
552
+ $this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING);
553
+
554
+ $OrganizationalUnitNames = array(
555
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
556
+ 'min' => 1,
557
+ 'max' => 4, // ub-organizational-units
558
+ 'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
559
+ );
560
+
561
+ $PersonalName = array(
562
+ 'type' => FILE_ASN1_TYPE_SET,
563
+ 'children' => array(
564
+ 'surname' => array(
565
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
566
+ 'constant' => 0,
567
+ 'optional' => true,
568
+ 'implicit' => true
569
+ ),
570
+ 'given-name' => array(
571
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
572
+ 'constant' => 1,
573
+ 'optional' => true,
574
+ 'implicit' => true
575
+ ),
576
+ 'initials' => array(
577
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
578
+ 'constant' => 2,
579
+ 'optional' => true,
580
+ 'implicit' => true
581
+ ),
582
+ 'generation-qualifier' => array(
583
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
584
+ 'constant' => 3,
585
+ 'optional' => true,
586
+ 'implicit' => true
587
+ )
588
+ )
589
+ );
590
+
591
+ $NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
592
+
593
+ $OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
594
+
595
+ $PrivateDomainName = array(
596
+ 'type' => FILE_ASN1_TYPE_CHOICE,
597
+ 'children' => array(
598
+ 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
599
+ 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
600
+ )
601
+ );
602
+
603
+ $TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
604
+
605
+ $NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
606
+
607
+ $AdministrationDomainName = array(
608
+ 'type' => FILE_ASN1_TYPE_CHOICE,
609
+ // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
610
+ // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
611
+ 'class' => FILE_ASN1_CLASS_APPLICATION,
612
+ 'cast' => 2,
613
+ 'children' => array(
614
+ 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
615
+ 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
616
+ )
617
+ );
618
+
619
+ $CountryName = array(
620
+ 'type' => FILE_ASN1_TYPE_CHOICE,
621
+ // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
622
+ // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
623
+ 'class' => FILE_ASN1_CLASS_APPLICATION,
624
+ 'cast' => 1,
625
+ 'children' => array(
626
+ 'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
627
+ 'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
628
+ )
629
+ );
630
+
631
+ $AnotherName = array(
632
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
633
+ 'children' => array(
634
+ 'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
635
+ 'value' => array(
636
+ 'type' => FILE_ASN1_TYPE_ANY,
637
+ 'constant' => 0,
638
+ 'optional' => true,
639
+ 'explicit' => true
640
+ )
641
+ )
642
+ );
643
+
644
+ $ExtensionAttribute = array(
645
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
646
+ 'children' => array(
647
+ 'extension-attribute-type' => array(
648
+ 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
649
+ 'constant' => 0,
650
+ 'optional' => true,
651
+ 'implicit' => true
652
+ ),
653
+ 'extension-attribute-value' => array(
654
+ 'type' => FILE_ASN1_TYPE_ANY,
655
+ 'constant' => 1,
656
+ 'optional' => true,
657
+ 'explicit' => true
658
+ )
659
+ )
660
+ );
661
+
662
+ $ExtensionAttributes = array(
663
+ 'type' => FILE_ASN1_TYPE_SET,
664
+ 'min' => 1,
665
+ 'max' => 256, // ub-extension-attributes
666
+ 'children' => $ExtensionAttribute
667
+ );
668
+
669
+ $BuiltInDomainDefinedAttribute = array(
670
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
671
+ 'children' => array(
672
+ 'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
673
+ 'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
674
+ )
675
+ );
676
+
677
+ $BuiltInDomainDefinedAttributes = array(
678
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
679
+ 'min' => 1,
680
+ 'max' => 4, // ub-domain-defined-attributes
681
+ 'children' => $BuiltInDomainDefinedAttribute
682
+ );
683
+
684
+ $BuiltInStandardAttributes = array(
685
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
686
+ 'children' => array(
687
+ 'country-name' => array('optional' => true) + $CountryName,
688
+ 'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
689
+ 'network-address' => array(
690
+ 'constant' => 0,
691
+ 'optional' => true,
692
+ 'implicit' => true
693
+ ) + $NetworkAddress,
694
+ 'terminal-identifier' => array(
695
+ 'constant' => 1,
696
+ 'optional' => true,
697
+ 'implicit' => true
698
+ ) + $TerminalIdentifier,
699
+ 'private-domain-name' => array(
700
+ 'constant' => 2,
701
+ 'optional' => true,
702
+ 'explicit' => true
703
+ ) + $PrivateDomainName,
704
+ 'organization-name' => array(
705
+ 'constant' => 3,
706
+ 'optional' => true,
707
+ 'implicit' => true
708
+ ) + $OrganizationName,
709
+ 'numeric-user-identifier' => array(
710
+ 'constant' => 4,
711
+ 'optional' => true,
712
+ 'implicit' => true
713
+ ) + $NumericUserIdentifier,
714
+ 'personal-name' => array(
715
+ 'constant' => 5,
716
+ 'optional' => true,
717
+ 'implicit' => true
718
+ ) + $PersonalName,
719
+ 'organizational-unit-names' => array(
720
+ 'constant' => 6,
721
+ 'optional' => true,
722
+ 'implicit' => true
723
+ ) + $OrganizationalUnitNames
724
+ )
725
+ );
726
+
727
+ $ORAddress = array(
728
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
729
+ 'children' => array(
730
+ 'built-in-standard-attributes' => $BuiltInStandardAttributes,
731
+ 'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
732
+ 'extension-attributes' => array('optional' => true) + $ExtensionAttributes
733
+ )
734
+ );
735
+
736
+ $EDIPartyName = array(
737
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
738
+ 'children' => array(
739
+ 'nameAssigner' => array(
740
+ 'constant' => 0,
741
+ 'optional' => true,
742
+ 'implicit' => true
743
+ ) + $this->DirectoryString,
744
+ // partyName is technically required but File_ASN1 doesn't currently support non-optional constants and
745
+ // setting it to optional gets the job done in any event.
746
+ 'partyName' => array(
747
+ 'constant' => 1,
748
+ 'optional' => true,
749
+ 'implicit' => true
750
+ ) + $this->DirectoryString
751
+ )
752
+ );
753
+
754
+ $GeneralName = array(
755
+ 'type' => FILE_ASN1_TYPE_CHOICE,
756
+ 'children' => array(
757
+ 'otherName' => array(
758
+ 'constant' => 0,
759
+ 'optional' => true,
760
+ 'implicit' => true
761
+ ) + $AnotherName,
762
+ 'rfc822Name' => array(
763
+ 'type' => FILE_ASN1_TYPE_IA5_STRING,
764
+ 'constant' => 1,
765
+ 'optional' => true,
766
+ 'implicit' => true
767
+ ),
768
+ 'dNSName' => array(
769
+ 'type' => FILE_ASN1_TYPE_IA5_STRING,
770
+ 'constant' => 2,
771
+ 'optional' => true,
772
+ 'implicit' => true
773
+ ),
774
+ 'x400Address' => array(
775
+ 'constant' => 3,
776
+ 'optional' => true,
777
+ 'implicit' => true
778
+ ) + $ORAddress,
779
+ 'directoryName' => array(
780
+ 'constant' => 4,
781
+ 'optional' => true,
782
+ 'explicit' => true
783
+ ) + $this->Name,
784
+ 'ediPartyName' => array(
785
+ 'constant' => 5,
786
+ 'optional' => true,
787
+ 'implicit' => true
788
+ ) + $EDIPartyName,
789
+ 'uniformResourceIdentifier' => array(
790
+ 'type' => FILE_ASN1_TYPE_IA5_STRING,
791
+ 'constant' => 6,
792
+ 'optional' => true,
793
+ 'implicit' => true
794
+ ),
795
+ 'iPAddress' => array(
796
+ 'type' => FILE_ASN1_TYPE_OCTET_STRING,
797
+ 'constant' => 7,
798
+ 'optional' => true,
799
+ 'implicit' => true
800
+ ),
801
+ 'registeredID' => array(
802
+ 'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER,
803
+ 'constant' => 8,
804
+ 'optional' => true,
805
+ 'implicit' => true
806
+ )
807
+ )
808
+ );
809
+
810
+ $GeneralNames = array(
811
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
812
+ 'min' => 1,
813
+ 'max' => -1,
814
+ 'children' => $GeneralName
815
+ );
816
+
817
+ $this->IssuerAltName = $GeneralNames;
818
+
819
+ $ReasonFlags = array(
820
+ 'type' => FILE_ASN1_TYPE_BIT_STRING,
821
+ 'mapping' => array(
822
+ 'unused',
823
+ 'keyCompromise',
824
+ 'cACompromise',
825
+ 'affiliationChanged',
826
+ 'superseded',
827
+ 'cessationOfOperation',
828
+ 'certificateHold',
829
+ 'privilegeWithdrawn',
830
+ 'aACompromise'
831
+ )
832
+ );
833
+
834
+ $DistributionPointName = array(
835
+ 'type' => FILE_ASN1_TYPE_CHOICE,
836
+ 'children' => array(
837
+ 'fullName' => array(
838
+ 'constant' => 0,
839
+ 'optional' => true,
840
+ 'implicit' => true
841
+ ) + $GeneralNames,
842
+ 'nameRelativeToCRLIssuer' => array(
843
+ 'constant' => 1,
844
+ 'optional' => true,
845
+ 'implicit' => true
846
+ ) + $this->RelativeDistinguishedName
847
+ )
848
+ );
849
+
850
+ $DistributionPoint = array(
851
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
852
+ 'children' => array(
853
+ 'distributionPoint' => array(
854
+ 'constant' => 0,
855
+ 'optional' => true,
856
+ 'explicit' => true
857
+ ) + $DistributionPointName,
858
+ 'reasons' => array(
859
+ 'constant' => 1,
860
+ 'optional' => true,
861
+ 'implicit' => true
862
+ ) + $ReasonFlags,
863
+ 'cRLIssuer' => array(
864
+ 'constant' => 2,
865
+ 'optional' => true,
866
+ 'implicit' => true
867
+ ) + $GeneralNames
868
+ )
869
+ );
870
+
871
+ $this->CRLDistributionPoints = array(
872
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
873
+ 'min' => 1,
874
+ 'max' => -1,
875
+ 'children' => $DistributionPoint
876
+ );
877
+
878
+ $this->AuthorityKeyIdentifier = array(
879
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
880
+ 'children' => array(
881
+ 'keyIdentifier' => array(
882
+ 'constant' => 0,
883
+ 'optional' => true,
884
+ 'implicit' => true
885
+ ) + $this->KeyIdentifier,
886
+ 'authorityCertIssuer' => array(
887
+ 'constant' => 1,
888
+ 'optional' => true,
889
+ 'implicit' => true
890
+ ) + $GeneralNames,
891
+ 'authorityCertSerialNumber' => array(
892
+ 'constant' => 2,
893
+ 'optional' => true,
894
+ 'implicit' => true
895
+ ) + $CertificateSerialNumber
896
+ )
897
+ );
898
+
899
+ $PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
900
+
901
+ $PolicyQualifierInfo = array(
902
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
903
+ 'children' => array(
904
+ 'policyQualifierId' => $PolicyQualifierId,
905
+ 'qualifier' => array('type' => FILE_ASN1_TYPE_ANY)
906
+ )
907
+ );
908
+
909
+ $CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
910
+
911
+ $PolicyInformation = array(
912
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
913
+ 'children' => array(
914
+ 'policyIdentifier' => $CertPolicyId,
915
+ 'policyQualifiers' => array(
916
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
917
+ 'min' => 0,
918
+ 'max' => -1,
919
+ 'optional' => true,
920
+ 'children' => $PolicyQualifierInfo
921
+ )
922
+ )
923
+ );
924
+
925
+ $this->CertificatePolicies = array(
926
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
927
+ 'min' => 1,
928
+ 'max' => -1,
929
+ 'children' => $PolicyInformation
930
+ );
931
+
932
+ $this->PolicyMappings = array(
933
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
934
+ 'min' => 1,
935
+ 'max' => -1,
936
+ 'children' => array(
937
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
938
+ 'children' => array(
939
+ 'issuerDomainPolicy' => $CertPolicyId,
940
+ 'subjectDomainPolicy' => $CertPolicyId
941
+ )
942
+ )
943
+ );
944
+
945
+ $KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
946
+
947
+ $this->ExtKeyUsageSyntax = array(
948
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
949
+ 'min' => 1,
950
+ 'max' => -1,
951
+ 'children' => $KeyPurposeId
952
+ );
953
+
954
+ $AccessDescription = array(
955
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
956
+ 'children' => array(
957
+ 'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
958
+ 'accessLocation' => $GeneralName
959
+ )
960
+ );
961
+
962
+ $this->AuthorityInfoAccessSyntax = array(
963
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
964
+ 'min' => 1,
965
+ 'max' => -1,
966
+ 'children' => $AccessDescription
967
+ );
968
+
969
+ $this->SubjectAltName = $GeneralNames;
970
+
971
+ $this->PrivateKeyUsagePeriod = array(
972
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
973
+ 'children' => array(
974
+ 'notBefore' => array(
975
+ 'constant' => 0,
976
+ 'optional' => true,
977
+ 'implicit' => true,
978
+ 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME),
979
+ 'notAfter' => array(
980
+ 'constant' => 1,
981
+ 'optional' => true,
982
+ 'implicit' => true,
983
+ 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
984
+ )
985
+ );
986
+
987
+ $BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER);
988
+
989
+ $GeneralSubtree = array(
990
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
991
+ 'children' => array(
992
+ 'base' => $GeneralName,
993
+ 'minimum' => array(
994
+ 'constant' => 0,
995
+ 'optional' => true,
996
+ 'implicit' => true,
997
+ 'default' => new Math_BigInteger(0)
998
+ ) + $BaseDistance,
999
+ 'maximum' => array(
1000
+ 'constant' => 1,
1001
+ 'optional' => true,
1002
+ 'implicit' => true,
1003
+ ) + $BaseDistance
1004
+ )
1005
+ );
1006
+
1007
+ $GeneralSubtrees = array(
1008
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1009
+ 'min' => 1,
1010
+ 'max' => -1,
1011
+ 'children' => $GeneralSubtree
1012
+ );
1013
+
1014
+ $this->NameConstraints = array(
1015
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1016
+ 'children' => array(
1017
+ 'permittedSubtrees' => array(
1018
+ 'constant' => 0,
1019
+ 'optional' => true,
1020
+ 'implicit' => true
1021
+ ) + $GeneralSubtrees,
1022
+ 'excludedSubtrees' => array(
1023
+ 'constant' => 1,
1024
+ 'optional' => true,
1025
+ 'implicit' => true
1026
+ ) + $GeneralSubtrees
1027
+ )
1028
+ );
1029
+
1030
+ $this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1031
+
1032
+ $DisplayText = array(
1033
+ 'type' => FILE_ASN1_TYPE_CHOICE,
1034
+ 'children' => array(
1035
+ 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
1036
+ 'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING),
1037
+ 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING),
1038
+ 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING)
1039
+ )
1040
+ );
1041
+
1042
+ $NoticeReference = array(
1043
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1044
+ 'children' => array(
1045
+ 'organization' => $DisplayText,
1046
+ 'noticeNumbers' => array(
1047
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1048
+ 'min' => 1,
1049
+ 'max' => 200,
1050
+ 'children' => array('type' => FILE_ASN1_TYPE_INTEGER)
1051
+ )
1052
+ )
1053
+ );
1054
+
1055
+ $this->UserNotice = array(
1056
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1057
+ 'children' => array(
1058
+ 'noticeRef' => array(
1059
+ 'optional' => true,
1060
+ 'implicit' => true
1061
+ ) + $NoticeReference,
1062
+ 'explicitText' => array(
1063
+ 'optional' => true,
1064
+ 'implicit' => true
1065
+ ) + $DisplayText
1066
+ )
1067
+ );
1068
+
1069
+ // mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
1070
+ $this->netscape_cert_type = array(
1071
+ 'type' => FILE_ASN1_TYPE_BIT_STRING,
1072
+ 'mapping' => array(
1073
+ 'SSLClient',
1074
+ 'SSLServer',
1075
+ 'Email',
1076
+ 'ObjectSigning',
1077
+ 'Reserved',
1078
+ 'SSLCA',
1079
+ 'EmailCA',
1080
+ 'ObjectSigningCA'
1081
+ )
1082
+ );
1083
+
1084
+ $this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1085
+ $this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1086
+
1087
+ // attribute is used in RFC2986 but we're using the RFC5280 definition
1088
+
1089
+ $Attribute = array(
1090
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1091
+ 'children' => array(
1092
+ 'type' => $AttributeType,
1093
+ 'value'=> array(
1094
+ 'type' => FILE_ASN1_TYPE_SET,
1095
+ 'min' => 1,
1096
+ 'max' => -1,
1097
+ 'children' => $this->AttributeValue
1098
+ )
1099
+ )
1100
+ );
1101
+
1102
+ $this->SubjectDirectoryAttributes = array(
1103
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1104
+ 'min' => 1,
1105
+ 'max' => -1,
1106
+ 'children' => $Attribute
1107
+ );
1108
+
1109
+ // adapted from <http://tools.ietf.org/html/rfc2986>
1110
+
1111
+ $Attributes = array(
1112
+ 'type' => FILE_ASN1_TYPE_SET,
1113
+ 'min' => 1,
1114
+ 'max' => -1,
1115
+ 'children' => $Attribute
1116
+ );
1117
+
1118
+ $CertificationRequestInfo = array(
1119
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1120
+ 'children' => array(
1121
+ 'version' => array(
1122
+ 'type' => FILE_ASN1_TYPE_INTEGER,
1123
+ 'mapping' => array('v1')
1124
+ ),
1125
+ 'subject' => $this->Name,
1126
+ 'subjectPKInfo' => $SubjectPublicKeyInfo,
1127
+ 'attributes' => array(
1128
+ 'constant' => 0,
1129
+ 'optional' => true,
1130
+ 'implicit' => true
1131
+ ) + $Attributes,
1132
+ )
1133
+ );
1134
+
1135
+ $this->CertificationRequest = array(
1136
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1137
+ 'children' => array(
1138
+ 'certificationRequestInfo' => $CertificationRequestInfo,
1139
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
1140
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1141
+ )
1142
+ );
1143
+
1144
+ $RevokedCertificate = array(
1145
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1146
+ 'children' => array(
1147
+ 'userCertificate' => $CertificateSerialNumber,
1148
+ 'revocationDate' => $Time,
1149
+ 'crlEntryExtensions' => array(
1150
+ 'optional' => true
1151
+ ) + $this->Extensions
1152
+ )
1153
+ );
1154
+
1155
+ $TBSCertList = array(
1156
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1157
+ 'children' => array(
1158
+ 'version' => array(
1159
+ 'optional' => true,
1160
+ 'default' => 'v1'
1161
+ ) + $Version,
1162
+ 'signature' => $AlgorithmIdentifier,
1163
+ 'issuer' => $this->Name,
1164
+ 'thisUpdate' => $Time,
1165
+ 'nextUpdate' => array(
1166
+ 'optional' => true
1167
+ ) + $Time,
1168
+ 'revokedCertificates' => array(
1169
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1170
+ 'optional' => true,
1171
+ 'min' => 0,
1172
+ 'max' => -1,
1173
+ 'children' => $RevokedCertificate
1174
+ ),
1175
+ 'crlExtensions' => array(
1176
+ 'constant' => 0,
1177
+ 'optional' => true,
1178
+ 'explicit' => true
1179
+ ) + $this->Extensions
1180
+ )
1181
+ );
1182
+
1183
+ $this->CertificateList = array(
1184
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1185
+ 'children' => array(
1186
+ 'tbsCertList' => $TBSCertList,
1187
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
1188
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1189
+ )
1190
+ );
1191
+
1192
+ $this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
1193
+
1194
+ $this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED,
1195
+ 'mapping' => array(
1196
+ 'unspecified',
1197
+ 'keyCompromise',
1198
+ 'cACompromise',
1199
+ 'affiliationChanged',
1200
+ 'superseded',
1201
+ 'cessationOfOperation',
1202
+ 'certificateHold',
1203
+ // Value 7 is not used.
1204
+ 8 => 'removeFromCRL',
1205
+ 'privilegeWithdrawn',
1206
+ 'aACompromise'
1207
+ )
1208
+ );
1209
+
1210
+ $this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE,
1211
+ 'children' => array(
1212
+ 'distributionPoint' => array(
1213
+ 'constant' => 0,
1214
+ 'optional' => true,
1215
+ 'explicit' => true
1216
+ ) + $DistributionPointName,
1217
+ 'onlyContainsUserCerts' => array(
1218
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1219
+ 'constant' => 1,
1220
+ 'optional' => true,
1221
+ 'default' => false,
1222
+ 'implicit' => true
1223
+ ),
1224
+ 'onlyContainsCACerts' => array(
1225
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1226
+ 'constant' => 2,
1227
+ 'optional' => true,
1228
+ 'default' => false,
1229
+ 'implicit' => true
1230
+ ),
1231
+ 'onlySomeReasons' => array(
1232
+ 'constant' => 3,
1233
+ 'optional' => true,
1234
+ 'implicit' => true
1235
+ ) + $ReasonFlags,
1236
+ 'indirectCRL' => array(
1237
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1238
+ 'constant' => 4,
1239
+ 'optional' => true,
1240
+ 'default' => false,
1241
+ 'implicit' => true
1242
+ ),
1243
+ 'onlyContainsAttributeCerts' => array(
1244
+ 'type' => FILE_ASN1_TYPE_BOOLEAN,
1245
+ 'constant' => 5,
1246
+ 'optional' => true,
1247
+ 'default' => false,
1248
+ 'implicit' => true
1249
+ )
1250
+ )
1251
+ );
1252
+
1253
+ $this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME);
1254
+
1255
+ $this->CertificateIssuer = $GeneralNames;
1256
+
1257
+ $this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
1258
+
1259
+ $PublicKeyAndChallenge = array(
1260
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1261
+ 'children' => array(
1262
+ 'spki' => $SubjectPublicKeyInfo,
1263
+ 'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING)
1264
+ )
1265
+ );
1266
+
1267
+ $this->SignedPublicKeyAndChallenge = array(
1268
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1269
+ 'children' => array(
1270
+ 'publicKeyAndChallenge' => $PublicKeyAndChallenge,
1271
+ 'signatureAlgorithm' => $AlgorithmIdentifier,
1272
+ 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
1273
+ )
1274
+ );
1275
+
1276
+ $this->PostalAddress = array(
1277
+ 'type' => FILE_ASN1_TYPE_SEQUENCE,
1278
+ 'optional' => true,
1279
+ 'min' => 1,
1280
+ 'max' => -1,
1281
+ 'children' => $this->DirectoryString
1282
+ );
1283
+
1284
+ // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
1285
+ $this->oids = array(
1286
+ '1.3.6.1.5.5.7' => 'id-pkix',
1287
+ '1.3.6.1.5.5.7.1' => 'id-pe',
1288
+ '1.3.6.1.5.5.7.2' => 'id-qt',
1289
+ '1.3.6.1.5.5.7.3' => 'id-kp',
1290
+ '1.3.6.1.5.5.7.48' => 'id-ad',
1291
+ '1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
1292
+ '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
1293
+ '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
1294
+ '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
1295
+ '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
1296
+ '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
1297
+ '2.5.4' => 'id-at',
1298
+ '2.5.4.41' => 'id-at-name',
1299
+ '2.5.4.4' => 'id-at-surname',
1300
+ '2.5.4.42' => 'id-at-givenName',
1301
+ '2.5.4.43' => 'id-at-initials',
1302
+ '2.5.4.44' => 'id-at-generationQualifier',
1303
+ '2.5.4.3' => 'id-at-commonName',
1304
+ '2.5.4.7' => 'id-at-localityName',
1305
+ '2.5.4.8' => 'id-at-stateOrProvinceName',
1306
+ '2.5.4.10' => 'id-at-organizationName',
1307
+ '2.5.4.11' => 'id-at-organizationalUnitName',
1308
+ '2.5.4.12' => 'id-at-title',
1309
+ '2.5.4.13' => 'id-at-description',
1310
+ '2.5.4.46' => 'id-at-dnQualifier',
1311
+ '2.5.4.6' => 'id-at-countryName',
1312
+ '2.5.4.5' => 'id-at-serialNumber',
1313
+ '2.5.4.65' => 'id-at-pseudonym',
1314
+ '2.5.4.17' => 'id-at-postalCode',
1315
+ '2.5.4.9' => 'id-at-streetAddress',
1316
+ '2.5.4.45' => 'id-at-uniqueIdentifier',
1317
+ '2.5.4.72' => 'id-at-role',
1318
+ '2.5.4.16' => 'id-at-postalAddress',
1319
+
1320
+ '0.9.2342.19200300.100.1.25' => 'id-domainComponent',
1321
+ '1.2.840.113549.1.9' => 'pkcs-9',
1322
+ '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
1323
+ '2.5.29' => 'id-ce',
1324
+ '2.5.29.35' => 'id-ce-authorityKeyIdentifier',
1325
+ '2.5.29.14' => 'id-ce-subjectKeyIdentifier',
1326
+ '2.5.29.15' => 'id-ce-keyUsage',
1327
+ '2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
1328
+ '2.5.29.32' => 'id-ce-certificatePolicies',
1329
+ '2.5.29.32.0' => 'anyPolicy',
1330
+
1331
+ '2.5.29.33' => 'id-ce-policyMappings',
1332
+ '2.5.29.17' => 'id-ce-subjectAltName',
1333
+ '2.5.29.18' => 'id-ce-issuerAltName',
1334
+ '2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
1335
+ '2.5.29.19' => 'id-ce-basicConstraints',
1336
+ '2.5.29.30' => 'id-ce-nameConstraints',
1337
+ '2.5.29.36' => 'id-ce-policyConstraints',
1338
+ '2.5.29.31' => 'id-ce-cRLDistributionPoints',
1339
+ '2.5.29.37' => 'id-ce-extKeyUsage',
1340
+ '2.5.29.37.0' => 'anyExtendedKeyUsage',
1341
+ '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
1342
+ '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
1343
+ '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
1344
+ '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
1345
+ '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
1346
+ '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
1347
+ '2.5.29.54' => 'id-ce-inhibitAnyPolicy',
1348
+ '2.5.29.46' => 'id-ce-freshestCRL',
1349
+ '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
1350
+ '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
1351
+ '2.5.29.20' => 'id-ce-cRLNumber',
1352
+ '2.5.29.28' => 'id-ce-issuingDistributionPoint',
1353
+ '2.5.29.27' => 'id-ce-deltaCRLIndicator',
1354
+ '2.5.29.21' => 'id-ce-cRLReasons',
1355
+ '2.5.29.29' => 'id-ce-certificateIssuer',
1356
+ '2.5.29.23' => 'id-ce-holdInstructionCode',
1357
+ '1.2.840.10040.2' => 'holdInstruction',
1358
+ '1.2.840.10040.2.1' => 'id-holdinstruction-none',
1359
+ '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
1360
+ '1.2.840.10040.2.3' => 'id-holdinstruction-reject',
1361
+ '2.5.29.24' => 'id-ce-invalidityDate',
1362
+
1363
+ '1.2.840.113549.2.2' => 'md2',
1364
+ '1.2.840.113549.2.5' => 'md5',
1365
+ '1.3.14.3.2.26' => 'id-sha1',
1366
+ '1.2.840.10040.4.1' => 'id-dsa',
1367
+ '1.2.840.10040.4.3' => 'id-dsa-with-sha1',
1368
+ '1.2.840.113549.1.1' => 'pkcs-1',
1369
+ '1.2.840.113549.1.1.1' => 'rsaEncryption',
1370
+ '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
1371
+ '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
1372
+ '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
1373
+ '1.2.840.10046.2.1' => 'dhpublicnumber',
1374
+ '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
1375
+ '1.2.840.10045' => 'ansi-X9-62',
1376
+ '1.2.840.10045.4' => 'id-ecSigType',
1377
+ '1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
1378
+ '1.2.840.10045.1' => 'id-fieldType',
1379
+ '1.2.840.10045.1.1' => 'prime-field',
1380
+ '1.2.840.10045.1.2' => 'characteristic-two-field',
1381
+ '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
1382
+ '1.2.840.10045.1.2.3.1' => 'gnBasis',
1383
+ '1.2.840.10045.1.2.3.2' => 'tpBasis',
1384
+ '1.2.840.10045.1.2.3.3' => 'ppBasis',
1385
+ '1.2.840.10045.2' => 'id-publicKeyType',
1386
+ '1.2.840.10045.2.1' => 'id-ecPublicKey',
1387
+ '1.2.840.10045.3' => 'ellipticCurve',
1388
+ '1.2.840.10045.3.0' => 'c-TwoCurve',
1389
+ '1.2.840.10045.3.0.1' => 'c2pnb163v1',
1390
+ '1.2.840.10045.3.0.2' => 'c2pnb163v2',
1391
+ '1.2.840.10045.3.0.3' => 'c2pnb163v3',
1392
+ '1.2.840.10045.3.0.4' => 'c2pnb176w1',
1393
+ '1.2.840.10045.3.0.5' => 'c2pnb191v1',
1394
+ '1.2.840.10045.3.0.6' => 'c2pnb191v2',
1395
+ '1.2.840.10045.3.0.7' => 'c2pnb191v3',
1396
+ '1.2.840.10045.3.0.8' => 'c2pnb191v4',
1397
+ '1.2.840.10045.3.0.9' => 'c2pnb191v5',
1398
+ '1.2.840.10045.3.0.10' => 'c2pnb208w1',
1399
+ '1.2.840.10045.3.0.11' => 'c2pnb239v1',
1400
+ '1.2.840.10045.3.0.12' => 'c2pnb239v2',
1401
+ '1.2.840.10045.3.0.13' => 'c2pnb239v3',
1402
+ '1.2.840.10045.3.0.14' => 'c2pnb239v4',
1403
+ '1.2.840.10045.3.0.15' => 'c2pnb239v5',
1404
+ '1.2.840.10045.3.0.16' => 'c2pnb272w1',
1405
+ '1.2.840.10045.3.0.17' => 'c2pnb304w1',
1406
+ '1.2.840.10045.3.0.18' => 'c2pnb359v1',
1407
+ '1.2.840.10045.3.0.19' => 'c2pnb368w1',
1408
+ '1.2.840.10045.3.0.20' => 'c2pnb431r1',
1409
+ '1.2.840.10045.3.1' => 'primeCurve',
1410
+ '1.2.840.10045.3.1.1' => 'prime192v1',
1411
+ '1.2.840.10045.3.1.2' => 'prime192v2',
1412
+ '1.2.840.10045.3.1.3' => 'prime192v3',
1413
+ '1.2.840.10045.3.1.4' => 'prime239v1',
1414
+ '1.2.840.10045.3.1.5' => 'prime239v2',
1415
+ '1.2.840.10045.3.1.6' => 'prime239v3',
1416
+ '1.2.840.10045.3.1.7' => 'prime256v1',
1417
+ '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
1418
+ '1.2.840.113549.1.1.9' => 'id-pSpecified',
1419
+ '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
1420
+ '1.2.840.113549.1.1.8' => 'id-mgf1',
1421
+ '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
1422
+ '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
1423
+ '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
1424
+ '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
1425
+ '2.16.840.1.101.3.4.2.4' => 'id-sha224',
1426
+ '2.16.840.1.101.3.4.2.1' => 'id-sha256',
1427
+ '2.16.840.1.101.3.4.2.2' => 'id-sha384',
1428
+ '2.16.840.1.101.3.4.2.3' => 'id-sha512',
1429
+ '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
1430
+ '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
1431
+ '1.2.643.2.2.20' => 'id-GostR3410-2001',
1432
+ '1.2.643.2.2.19' => 'id-GostR3410-94',
1433
+ // Netscape Object Identifiers from "Netscape Certificate Extensions"
1434
+ '2.16.840.1.113730' => 'netscape',
1435
+ '2.16.840.1.113730.1' => 'netscape-cert-extension',
1436
+ '2.16.840.1.113730.1.1' => 'netscape-cert-type',
1437
+ '2.16.840.1.113730.1.13' => 'netscape-comment',
1438
+ '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
1439
+ // the following are X.509 extensions not supported by phpseclib
1440
+ '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
1441
+ '1.2.840.113533.7.65.0' => 'entrustVersInfo',
1442
+ '2.16.840.1.113733.1.6.9' => 'verisignPrivate',
1443
+ // for Certificate Signing Requests
1444
+ // see http://tools.ietf.org/html/rfc2985
1445
+ '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
1446
+ '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
1447
+ '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
1448
+ );
1449
+ }
1450
+
1451
+ /**
1452
+ * PHP4 compatible Default Constructor.
1453
+ *
1454
+ * @see self::__construct()
1455
+ * @access public
1456
+ */
1457
+ function File_X509()
1458
+ {
1459
+ $this->__construct();
1460
+ }
1461
+
1462
+ /**
1463
+ * Load X.509 certificate
1464
+ *
1465
+ * Returns an associative array describing the X.509 cert or a false if the cert failed to load
1466
+ *
1467
+ * @param string $cert
1468
+ * @param int $mode
1469
+ * @access public
1470
+ * @return mixed
1471
+ */
1472
+ function loadX509($cert, $mode = FILE_X509_FORMAT_AUTO_DETECT)
1473
+ {
1474
+ if (is_array($cert) && isset($cert['tbsCertificate'])) {
1475
+ unset($this->currentCert);
1476
+ unset($this->currentKeyIdentifier);
1477
+ $this->dn = $cert['tbsCertificate']['subject'];
1478
+ if (!isset($this->dn)) {
1479
+ return false;
1480
+ }
1481
+ $this->currentCert = $cert;
1482
+
1483
+ $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1484
+ $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1485
+
1486
+ unset($this->signatureSubject);
1487
+
1488
+ return $cert;
1489
+ }
1490
+
1491
+ $asn1 = new File_ASN1();
1492
+
1493
+ if ($mode != FILE_X509_FORMAT_DER) {
1494
+ $newcert = $this->_extractBER($cert);
1495
+ if ($mode == FILE_X509_FORMAT_PEM && $cert == $newcert) {
1496
+ return false;
1497
+ }
1498
+ $cert = $newcert;
1499
+ }
1500
+
1501
+ if ($cert === false) {
1502
+ $this->currentCert = false;
1503
+ return false;
1504
+ }
1505
+
1506
+ $asn1->loadOIDs($this->oids);
1507
+ $decoded = $asn1->decodeBER($cert);
1508
+
1509
+ if (!empty($decoded)) {
1510
+ $x509 = $asn1->asn1map($decoded[0], $this->Certificate);
1511
+ }
1512
+ if (!isset($x509) || $x509 === false) {
1513
+ $this->currentCert = false;
1514
+ return false;
1515
+ }
1516
+
1517
+ $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
1518
+
1519
+ if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
1520
+ $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
1521
+ }
1522
+ $this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
1523
+ $this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);
1524
+
1525
+ $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
1526
+ $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
1527
+
1528
+ $this->currentCert = $x509;
1529
+ $this->dn = $x509['tbsCertificate']['subject'];
1530
+
1531
+ $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1532
+ $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1533
+
1534
+ return $x509;
1535
+ }
1536
+
1537
+ /**
1538
+ * Save X.509 certificate
1539
+ *
1540
+ * @param array $cert
1541
+ * @param int $format optional
1542
+ * @access public
1543
+ * @return string
1544
+ */
1545
+ function saveX509($cert, $format = FILE_X509_FORMAT_PEM)
1546
+ {
1547
+ if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
1548
+ return false;
1549
+ }
1550
+
1551
+ switch (true) {
1552
+ // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
1553
+ case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
1554
+ case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
1555
+ break;
1556
+ default:
1557
+ switch ($algorithm) {
1558
+ case 'rsaEncryption':
1559
+ $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
1560
+ = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
1561
+ /* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
1562
+ -- https://tools.ietf.org/html/rfc3279#section-2.3.1
1563
+
1564
+ given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank,
1565
+ it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
1566
+ */
1567
+ $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
1568
+ // https://tools.ietf.org/html/rfc3279#section-2.2.1
1569
+ $cert['signatureAlgorithm']['parameters'] = null;
1570
+ $cert['tbsCertificate']['signature']['parameters'] = null;
1571
+ }
1572
+ }
1573
+
1574
+ $asn1 = new File_ASN1();
1575
+ $asn1->loadOIDs($this->oids);
1576
+
1577
+ $filters = array();
1578
+ $type_utf8_string = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
1579
+ $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
1580
+ $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1581
+ $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1582
+ $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
1583
+ $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
1584
+ $filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
1585
+ $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1586
+ //$filters['policyQualifiers']['qualifier'] = $type_utf8_string;
1587
+ $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1588
+ $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1589
+
1590
+ /* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING.
1591
+ FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
1592
+ characters.
1593
+ */
1594
+ $filters['policyQualifiers']['qualifier']
1595
+ = array('type' => FILE_ASN1_TYPE_IA5_STRING);
1596
+
1597
+ $asn1->loadFilters($filters);
1598
+
1599
+ $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
1600
+ $this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
1601
+ $this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);
1602
+
1603
+ $cert = $asn1->encodeDER($cert, $this->Certificate);
1604
+
1605
+ switch ($format) {
1606
+ case FILE_X509_FORMAT_DER:
1607
+ return $cert;
1608
+ // case FILE_X509_FORMAT_PEM:
1609
+ default:
1610
+ return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
1611
+ }
1612
+ }
1613
+
1614
+ /**
1615
+ * Map extension values from octet string to extension-specific internal
1616
+ * format.
1617
+ *
1618
+ * @param array ref $root
1619
+ * @param string $path
1620
+ * @param object $asn1
1621
+ * @access private
1622
+ */
1623
+ function _mapInExtensions(&$root, $path, $asn1)
1624
+ {
1625
+ $extensions = &$this->_subArrayUnchecked($root, $path);
1626
+
1627
+ if ($extensions) {
1628
+ for ($i = 0; $i < count($extensions); $i++) {
1629
+ $id = $extensions[$i]['extnId'];
1630
+ $value = &$extensions[$i]['extnValue'];
1631
+ $value = base64_decode($value);
1632
+ $decoded = $asn1->decodeBER($value);
1633
+ /* [extnValue] contains the DER encoding of an ASN.1 value
1634
+ corresponding to the extension type identified by extnID */
1635
+ $map = $this->_getMapping($id);
1636
+ if (!is_bool($map)) {
1637
+ $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP')));
1638
+ $value = $mapped === false ? $decoded[0] : $mapped;
1639
+
1640
+ if ($id == 'id-ce-certificatePolicies') {
1641
+ for ($j = 0; $j < count($value); $j++) {
1642
+ if (!isset($value[$j]['policyQualifiers'])) {
1643
+ continue;
1644
+ }
1645
+ for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1646
+ $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1647
+ $map = $this->_getMapping($subid);
1648
+ $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1649
+ if ($map !== false) {
1650
+ $decoded = $asn1->decodeBER($subvalue);
1651
+ $mapped = $asn1->asn1map($decoded[0], $map);
1652
+ $subvalue = $mapped === false ? $decoded[0] : $mapped;
1653
+ }
1654
+ }
1655
+ }
1656
+ }
1657
+ } else {
1658
+ $value = base64_encode($value);
1659
+ }
1660
+ }
1661
+ }
1662
+ }
1663
+
1664
+ /**
1665
+ * Map extension values from extension-specific internal format to
1666
+ * octet string.
1667
+ *
1668
+ * @param array ref $root
1669
+ * @param string $path
1670
+ * @param object $asn1
1671
+ * @access private
1672
+ */
1673
+ function _mapOutExtensions(&$root, $path, $asn1)
1674
+ {
1675
+ $extensions = &$this->_subArray($root, $path);
1676
+
1677
+ if (is_array($extensions)) {
1678
+ $size = count($extensions);
1679
+ for ($i = 0; $i < $size; $i++) {
1680
+ if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') {
1681
+ continue;
1682
+ }
1683
+
1684
+ $id = $extensions[$i]['extnId'];
1685
+ $value = &$extensions[$i]['extnValue'];
1686
+
1687
+ switch ($id) {
1688
+ case 'id-ce-certificatePolicies':
1689
+ for ($j = 0; $j < count($value); $j++) {
1690
+ if (!isset($value[$j]['policyQualifiers'])) {
1691
+ continue;
1692
+ }
1693
+ for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1694
+ $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1695
+ $map = $this->_getMapping($subid);
1696
+ $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1697
+ if ($map !== false) {
1698
+ // by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's
1699
+ // actual type is FILE_ASN1_TYPE_ANY
1700
+ $subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map));
1701
+ }
1702
+ }
1703
+ }
1704
+ break;
1705
+ case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
1706
+ if (isset($value['authorityCertSerialNumber'])) {
1707
+ if ($value['authorityCertSerialNumber']->toBytes() == '') {
1708
+ $temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
1709
+ $value['authorityCertSerialNumber'] = new File_ASN1_Element($temp);
1710
+ }
1711
+ }
1712
+ }
1713
+
1714
+ /* [extnValue] contains the DER encoding of an ASN.1 value
1715
+ corresponding to the extension type identified by extnID */
1716
+ $map = $this->_getMapping($id);
1717
+ if (is_bool($map)) {
1718
+ if (!$map) {
1719
+ user_error($id . ' is not a currently supported extension');
1720
+ unset($extensions[$i]);
1721
+ }
1722
+ } else {
1723
+ $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
1724
+ $value = base64_encode($temp);
1725
+ }
1726
+ }
1727
+ }
1728
+ }
1729
+
1730
+ /**
1731
+ * Map attribute values from ANY type to attribute-specific internal
1732
+ * format.
1733
+ *
1734
+ * @param array ref $root
1735
+ * @param string $path
1736
+ * @param object $asn1
1737
+ * @access private
1738
+ */
1739
+ function _mapInAttributes(&$root, $path, $asn1)
1740
+ {
1741
+ $attributes = &$this->_subArray($root, $path);
1742
+
1743
+ if (is_array($attributes)) {
1744
+ for ($i = 0; $i < count($attributes); $i++) {
1745
+ $id = $attributes[$i]['type'];
1746
+ /* $value contains the DER encoding of an ASN.1 value
1747
+ corresponding to the attribute type identified by type */
1748
+ $map = $this->_getMapping($id);
1749
+ if (is_array($attributes[$i]['value'])) {
1750
+ $values = &$attributes[$i]['value'];
1751
+ for ($j = 0; $j < count($values); $j++) {
1752
+ $value = $asn1->encodeDER($values[$j], $this->AttributeValue);
1753
+ $decoded = $asn1->decodeBER($value);
1754
+ if (!is_bool($map)) {
1755
+ $mapped = $asn1->asn1map($decoded[0], $map);
1756
+ if ($mapped !== false) {
1757
+ $values[$j] = $mapped;
1758
+ }
1759
+ if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
1760
+ $this->_mapInExtensions($values, $j, $asn1);
1761
+ }
1762
+ } elseif ($map) {
1763
+ $values[$j] = base64_encode($value);
1764
+ }
1765
+ }
1766
+ }
1767
+ }
1768
+ }
1769
+ }
1770
+
1771
+ /**
1772
+ * Map attribute values from attribute-specific internal format to
1773
+ * ANY type.
1774
+ *
1775
+ * @param array ref $root
1776
+ * @param string $path
1777
+ * @param object $asn1
1778
+ * @access private
1779
+ */
1780
+ function _mapOutAttributes(&$root, $path, $asn1)
1781
+ {
1782
+ $attributes = &$this->_subArray($root, $path);
1783
+
1784
+ if (is_array($attributes)) {
1785
+ $size = count($attributes);
1786
+ for ($i = 0; $i < $size; $i++) {
1787
+ /* [value] contains the DER encoding of an ASN.1 value
1788
+ corresponding to the attribute type identified by type */
1789
+ $id = $attributes[$i]['type'];
1790
+ $map = $this->_getMapping($id);
1791
+ if ($map === false) {
1792
+ user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
1793
+ unset($attributes[$i]);
1794
+ } elseif (is_array($attributes[$i]['value'])) {
1795
+ $values = &$attributes[$i]['value'];
1796
+ for ($j = 0; $j < count($values); $j++) {
1797
+ switch ($id) {
1798
+ case 'pkcs-9-at-extensionRequest':
1799
+ $this->_mapOutExtensions($values, $j, $asn1);
1800
+ break;
1801
+ }
1802
+
1803
+ if (!is_bool($map)) {
1804
+ $temp = $asn1->encodeDER($values[$j], $map);
1805
+ $decoded = $asn1->decodeBER($temp);
1806
+ $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
1807
+ }
1808
+ }
1809
+ }
1810
+ }
1811
+ }
1812
+ }
1813
+
1814
+ /**
1815
+ * Map DN values from ANY type to DN-specific internal
1816
+ * format.
1817
+ *
1818
+ * @param array ref $root
1819
+ * @param string $path
1820
+ * @param object $asn1
1821
+ * @access private
1822
+ */
1823
+ function _mapInDNs(&$root, $path, $asn1)
1824
+ {
1825
+ $dns = &$this->_subArray($root, $path);
1826
+
1827
+ if (is_array($dns)) {
1828
+ for ($i = 0; $i < count($dns); $i++) {
1829
+ for ($j = 0; $j < count($dns[$i]); $j++) {
1830
+ $type = $dns[$i][$j]['type'];
1831
+ $value = &$dns[$i][$j]['value'];
1832
+ if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
1833
+ $map = $this->_getMapping($type);
1834
+ if (!is_bool($map)) {
1835
+ $decoded = $asn1->decodeBER($value);
1836
+ $value = $asn1->asn1map($decoded[0], $map);
1837
+ }
1838
+ }
1839
+ }
1840
+ }
1841
+ }
1842
+ }
1843
+
1844
+ /**
1845
+ * Map DN values from DN-specific internal format to
1846
+ * ANY type.
1847
+ *
1848
+ * @param array ref $root
1849
+ * @param string $path
1850
+ * @param object $asn1
1851
+ * @access private
1852
+ */
1853
+ function _mapOutDNs(&$root, $path, $asn1)
1854
+ {
1855
+ $dns = &$this->_subArray($root, $path);
1856
+
1857
+ if (is_array($dns)) {
1858
+ $size = count($dns);
1859
+ for ($i = 0; $i < $size; $i++) {
1860
+ for ($j = 0; $j < count($dns[$i]); $j++) {
1861
+ $type = $dns[$i][$j]['type'];
1862
+ $value = &$dns[$i][$j]['value'];
1863
+ if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
1864
+ continue;
1865
+ }
1866
+
1867
+ $map = $this->_getMapping($type);
1868
+ if (!is_bool($map)) {
1869
+ $value = new File_ASN1_Element($asn1->encodeDER($value, $map));
1870
+ }
1871
+ }
1872
+ }
1873
+ }
1874
+ }
1875
+
1876
+ /**
1877
+ * Associate an extension ID to an extension mapping
1878
+ *
1879
+ * @param string $extnId
1880
+ * @access private
1881
+ * @return mixed
1882
+ */
1883
+ function _getMapping($extnId)
1884
+ {
1885
+ if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object
1886
+ return true;
1887
+ }
1888
+
1889
+ switch ($extnId) {
1890
+ case 'id-ce-keyUsage':
1891
+ return $this->KeyUsage;
1892
+ case 'id-ce-basicConstraints':
1893
+ return $this->BasicConstraints;
1894
+ case 'id-ce-subjectKeyIdentifier':
1895
+ return $this->KeyIdentifier;
1896
+ case 'id-ce-cRLDistributionPoints':
1897
+ return $this->CRLDistributionPoints;
1898
+ case 'id-ce-authorityKeyIdentifier':
1899
+ return $this->AuthorityKeyIdentifier;
1900
+ case 'id-ce-certificatePolicies':
1901
+ return $this->CertificatePolicies;
1902
+ case 'id-ce-extKeyUsage':
1903
+ return $this->ExtKeyUsageSyntax;
1904
+ case 'id-pe-authorityInfoAccess':
1905
+ return $this->AuthorityInfoAccessSyntax;
1906
+ case 'id-ce-subjectAltName':
1907
+ return $this->SubjectAltName;
1908
+ case 'id-ce-subjectDirectoryAttributes':
1909
+ return $this->SubjectDirectoryAttributes;
1910
+ case 'id-ce-privateKeyUsagePeriod':
1911
+ return $this->PrivateKeyUsagePeriod;
1912
+ case 'id-ce-issuerAltName':
1913
+ return $this->IssuerAltName;
1914
+ case 'id-ce-policyMappings':
1915
+ return $this->PolicyMappings;
1916
+ case 'id-ce-nameConstraints':
1917
+ return $this->NameConstraints;
1918
+
1919
+ case 'netscape-cert-type':
1920
+ return $this->netscape_cert_type;
1921
+ case 'netscape-comment':
1922
+ return $this->netscape_comment;
1923
+ case 'netscape-ca-policy-url':
1924
+ return $this->netscape_ca_policy_url;
1925
+
1926
+ // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
1927
+ // back around to asn1map() and we don't want it decoded again.
1928
+ //case 'id-qt-cps':
1929
+ // return $this->CPSuri;
1930
+ case 'id-qt-unotice':
1931
+ return $this->UserNotice;
1932
+
1933
+ // the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
1934
+ case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
1935
+ case 'entrustVersInfo':
1936
+ // http://support.microsoft.com/kb/287547
1937
+ case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
1938
+ case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
1939
+ // "SET Secure Electronic Transaction Specification"
1940
+ // http://www.maithean.com/docs/set_bk3.pdf
1941
+ case '2.23.42.7.0': // id-set-hashedRootKey
1942
+ // "Certificate Transparency"
1943
+ // https://tools.ietf.org/html/rfc6962
1944
+ case '1.3.6.1.4.1.11129.2.4.2':
1945
+ return true;
1946
+
1947
+ // CSR attributes
1948
+ case 'pkcs-9-at-unstructuredName':
1949
+ return $this->PKCS9String;
1950
+ case 'pkcs-9-at-challengePassword':
1951
+ return $this->DirectoryString;
1952
+ case 'pkcs-9-at-extensionRequest':
1953
+ return $this->Extensions;
1954
+
1955
+ // CRL extensions.
1956
+ case 'id-ce-cRLNumber':
1957
+ return $this->CRLNumber;
1958
+ case 'id-ce-deltaCRLIndicator':
1959
+ return $this->CRLNumber;
1960
+ case 'id-ce-issuingDistributionPoint':
1961
+ return $this->IssuingDistributionPoint;
1962
+ case 'id-ce-freshestCRL':
1963
+ return $this->CRLDistributionPoints;
1964
+ case 'id-ce-cRLReasons':
1965
+ return $this->CRLReason;
1966
+ case 'id-ce-invalidityDate':
1967
+ return $this->InvalidityDate;
1968
+ case 'id-ce-certificateIssuer':
1969
+ return $this->CertificateIssuer;
1970
+ case 'id-ce-holdInstructionCode':
1971
+ return $this->HoldInstructionCode;
1972
+ case 'id-at-postalAddress':
1973
+ return $this->PostalAddress;
1974
+ }
1975
+
1976
+ return false;
1977
+ }
1978
+
1979
+ /**
1980
+ * Load an X.509 certificate as a certificate authority
1981
+ *
1982
+ * @param string $cert
1983
+ * @access public
1984
+ * @return bool
1985
+ */
1986
+ function loadCA($cert)
1987
+ {
1988
+ $olddn = $this->dn;
1989
+ $oldcert = $this->currentCert;
1990
+ $oldsigsubj = $this->signatureSubject;
1991
+ $oldkeyid = $this->currentKeyIdentifier;
1992
+
1993
+ $cert = $this->loadX509($cert);
1994
+ if (!$cert) {
1995
+ $this->dn = $olddn;
1996
+ $this->currentCert = $oldcert;
1997
+ $this->signatureSubject = $oldsigsubj;
1998
+ $this->currentKeyIdentifier = $oldkeyid;
1999
+
2000
+ return false;
2001
+ }
2002
+
2003
+ /* From RFC5280 "PKIX Certificate and CRL Profile":
2004
+
2005
+ If the keyUsage extension is present, then the subject public key
2006
+ MUST NOT be used to verify signatures on certificates or CRLs unless
2007
+ the corresponding keyCertSign or cRLSign bit is set. */
2008
+ //$keyUsage = $this->getExtension('id-ce-keyUsage');
2009
+ //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
2010
+ // return false;
2011
+ //}
2012
+
2013
+ /* From RFC5280 "PKIX Certificate and CRL Profile":
2014
+
2015
+ The cA boolean indicates whether the certified public key may be used
2016
+ to verify certificate signatures. If the cA boolean is not asserted,
2017
+ then the keyCertSign bit in the key usage extension MUST NOT be
2018
+ asserted. If the basic constraints extension is not present in a
2019
+ version 3 certificate, or the extension is present but the cA boolean
2020
+ is not asserted, then the certified public key MUST NOT be used to
2021
+ verify certificate signatures. */
2022
+ //$basicConstraints = $this->getExtension('id-ce-basicConstraints');
2023
+ //if (!$basicConstraints || !$basicConstraints['cA']) {
2024
+ // return false;
2025
+ //}
2026
+
2027
+ $this->CAs[] = $cert;
2028
+
2029
+ $this->dn = $olddn;
2030
+ $this->currentCert = $oldcert;
2031
+ $this->signatureSubject = $oldsigsubj;
2032
+
2033
+ return true;
2034
+ }
2035
+
2036
+ /**
2037
+ * Validate an X.509 certificate against a URL
2038
+ *
2039
+ * From RFC2818 "HTTP over TLS":
2040
+ *
2041
+ * Matching is performed using the matching rules specified by
2042
+ * [RFC2459]. If more than one identity of a given type is present in
2043
+ * the certificate (e.g., more than one dNSName name, a match in any one
2044
+ * of the set is considered acceptable.) Names may contain the wildcard
2045
+ * character * which is considered to match any single domain name
2046
+ * component or component fragment. E.g., *.a.com matches foo.a.com but
2047
+ * not bar.foo.a.com. f*.com matches foo.com but not bar.com.
2048
+ *
2049
+ * @param string $url
2050
+ * @access public
2051
+ * @return bool
2052
+ */
2053
+ function validateURL($url)
2054
+ {
2055
+ if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2056
+ return false;
2057
+ }
2058
+
2059
+ $components = parse_url($url);
2060
+ if (!isset($components['host'])) {
2061
+ return false;
2062
+ }
2063
+
2064
+ if ($names = $this->getExtension('id-ce-subjectAltName')) {
2065
+ foreach ($names as $name) {
2066
+ foreach ($name as $key => $value) {
2067
+ $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
2068
+ switch ($key) {
2069
+ case 'dNSName':
2070
+ /* From RFC2818 "HTTP over TLS":
2071
+
2072
+ If a subjectAltName extension of type dNSName is present, that MUST
2073
+ be used as the identity. Otherwise, the (most specific) Common Name
2074
+ field in the Subject field of the certificate MUST be used. Although
2075
+ the use of the Common Name is existing practice, it is deprecated and
2076
+ Certification Authorities are encouraged to use the dNSName instead. */
2077
+ if (preg_match('#^' . $value . '$#', $components['host'])) {
2078
+ return true;
2079
+ }
2080
+ break;
2081
+ case 'iPAddress':
2082
+ /* From RFC2818 "HTTP over TLS":
2083
+
2084
+ In some cases, the URI is specified as an IP address rather than a
2085
+ hostname. In this case, the iPAddress subjectAltName must be present
2086
+ in the certificate and must exactly match the IP in the URI. */
2087
+ if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
2088
+ return true;
2089
+ }
2090
+ }
2091
+ }
2092
+ }
2093
+ return false;
2094
+ }
2095
+
2096
+ if ($value = $this->getDNProp('id-at-commonName')) {
2097
+ $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
2098
+ return preg_match('#^' . $value . '$#', $components['host']);
2099
+ }
2100
+
2101
+ return false;
2102
+ }
2103
+
2104
+ /**
2105
+ * Validate a date
2106
+ *
2107
+ * If $date isn't defined it is assumed to be the current date.
2108
+ *
2109
+ * @param int $date optional
2110
+ * @access public
2111
+ */
2112
+ function validateDate($date = null)
2113
+ {
2114
+ if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2115
+ return false;
2116
+ }
2117
+
2118
+ if (!isset($date)) {
2119
+ $date = class_exists('DateTime') ?
2120
+ new DateTime($date, new DateTimeZone(@date_default_timezone_get())) :
2121
+ time();
2122
+ }
2123
+
2124
+ $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
2125
+ $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
2126
+
2127
+ $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
2128
+ $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
2129
+
2130
+ if (class_exists('DateTime')) {
2131
+ $notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
2132
+ $notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));
2133
+ } else {
2134
+ $notBefore = @strtotime($notBefore);
2135
+ $notAfter = @strtotime($notAfter);
2136
+ }
2137
+
2138
+ switch (true) {
2139
+ case $date < $notBefore:
2140
+ case $date > $notAfter:
2141
+ return false;
2142
+ }
2143
+
2144
+ return true;
2145
+ }
2146
+
2147
+ /**
2148
+ * Validate a signature
2149
+ *
2150
+ * Works on X.509 certs, CSR's and CRL's.
2151
+ * Returns true if the signature is verified, false if it is not correct or null on error
2152
+ *
2153
+ * By default returns false for self-signed certs. Call validateSignature(false) to make this support
2154
+ * self-signed.
2155
+ *
2156
+ * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
2157
+ *
2158
+ * @param bool $caonly optional
2159
+ * @access public
2160
+ * @return mixed
2161
+ */
2162
+ function validateSignature($caonly = true)
2163
+ {
2164
+ if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
2165
+ return null;
2166
+ }
2167
+
2168
+ /* TODO:
2169
+ "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
2170
+ -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
2171
+
2172
+ implement pathLenConstraint in the id-ce-basicConstraints extension */
2173
+
2174
+ switch (true) {
2175
+ case isset($this->currentCert['tbsCertificate']):
2176
+ // self-signed cert
2177
+ switch (true) {
2178
+ case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
2179
+ case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(FILE_X509_DN_STRING) === $this->getDN(FILE_X509_DN_STRING):
2180
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2181
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
2182
+ switch (true) {
2183
+ case !is_array($authorityKey):
2184
+ case !$subjectKeyID:
2185
+ case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2186
+ $signingCert = $this->currentCert; // working cert
2187
+ }
2188
+ }
2189
+
2190
+ if (!empty($this->CAs)) {
2191
+ for ($i = 0; $i < count($this->CAs); $i++) {
2192
+ // even if the cert is a self-signed one we still want to see if it's a CA;
2193
+ // if not, we'll conditionally return an error
2194
+ $ca = $this->CAs[$i];
2195
+ switch (true) {
2196
+ case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
2197
+ case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']):
2198
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2199
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2200
+ switch (true) {
2201
+ case !is_array($authorityKey):
2202
+ case !$subjectKeyID:
2203
+ case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2204
+ if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
2205
+ break 2; // serial mismatch - check other ca
2206
+ }
2207
+ $signingCert = $ca; // working cert
2208
+ break 3;
2209
+ }
2210
+ }
2211
+ }
2212
+ if (count($this->CAs) == $i && $caonly) {
2213
+ return false;
2214
+ }
2215
+ } elseif (!isset($signingCert) || $caonly) {
2216
+ return false;
2217
+ }
2218
+ return $this->_validateSignature(
2219
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2220
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2221
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2222
+ substr(base64_decode($this->currentCert['signature']), 1),
2223
+ $this->signatureSubject
2224
+ );
2225
+ case isset($this->currentCert['certificationRequestInfo']):
2226
+ return $this->_validateSignature(
2227
+ $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
2228
+ $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
2229
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2230
+ substr(base64_decode($this->currentCert['signature']), 1),
2231
+ $this->signatureSubject
2232
+ );
2233
+ case isset($this->currentCert['publicKeyAndChallenge']):
2234
+ return $this->_validateSignature(
2235
+ $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
2236
+ $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
2237
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2238
+ substr(base64_decode($this->currentCert['signature']), 1),
2239
+ $this->signatureSubject
2240
+ );
2241
+ case isset($this->currentCert['tbsCertList']):
2242
+ if (!empty($this->CAs)) {
2243
+ for ($i = 0; $i < count($this->CAs); $i++) {
2244
+ $ca = $this->CAs[$i];
2245
+ switch (true) {
2246
+ case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
2247
+ case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']):
2248
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2249
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2250
+ switch (true) {
2251
+ case !is_array($authorityKey):
2252
+ case !$subjectKeyID:
2253
+ case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2254
+ if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
2255
+ break 2; // serial mismatch - check other ca
2256
+ }
2257
+ $signingCert = $ca; // working cert
2258
+ break 3;
2259
+ }
2260
+ }
2261
+ }
2262
+ }
2263
+ if (!isset($signingCert)) {
2264
+ return false;
2265
+ }
2266
+ return $this->_validateSignature(
2267
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2268
+ $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2269
+ $this->currentCert['signatureAlgorithm']['algorithm'],
2270
+ substr(base64_decode($this->currentCert['signature']), 1),
2271
+ $this->signatureSubject
2272
+ );
2273
+ default:
2274
+ return false;
2275
+ }
2276
+ }
2277
+
2278
+ /**
2279
+ * Validates a signature
2280
+ *
2281
+ * Returns true if the signature is verified, false if it is not correct or null on error
2282
+ *
2283
+ * @param string $publicKeyAlgorithm
2284
+ * @param string $publicKey
2285
+ * @param string $signatureAlgorithm
2286
+ * @param string $signature
2287
+ * @param string $signatureSubject
2288
+ * @access private
2289
+ * @return int
2290
+ */
2291
+ function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
2292
+ {
2293
+ switch ($publicKeyAlgorithm) {
2294
+ case 'rsaEncryption':
2295
+ if (!class_exists('Crypt_RSA')) {
2296
+ include_once 'Crypt/RSA.php';
2297
+ }
2298
+ $rsa = new Crypt_RSA();
2299
+ $rsa->loadKey($publicKey);
2300
+
2301
+ switch ($signatureAlgorithm) {
2302
+ case 'md2WithRSAEncryption':
2303
+ case 'md5WithRSAEncryption':
2304
+ case 'sha1WithRSAEncryption':
2305
+ case 'sha224WithRSAEncryption':
2306
+ case 'sha256WithRSAEncryption':
2307
+ case 'sha384WithRSAEncryption':
2308
+ case 'sha512WithRSAEncryption':
2309
+ $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
2310
+ $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2311
+ if (!@$rsa->verify($signatureSubject, $signature)) {
2312
+ return false;
2313
+ }
2314
+ break;
2315
+ default:
2316
+ return null;
2317
+ }
2318
+ break;
2319
+ default:
2320
+ return null;
2321
+ }
2322
+
2323
+ return true;
2324
+ }
2325
+
2326
+ /**
2327
+ * Reformat public keys
2328
+ *
2329
+ * Reformats a public key to a format supported by phpseclib (if applicable)
2330
+ *
2331
+ * @param string $algorithm
2332
+ * @param string $key
2333
+ * @access private
2334
+ * @return string
2335
+ */
2336
+ function _reformatKey($algorithm, $key)
2337
+ {
2338
+ switch ($algorithm) {
2339
+ case 'rsaEncryption':
2340
+ return
2341
+ "-----BEGIN RSA PUBLIC KEY-----\r\n" .
2342
+ // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
2343
+ // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
2344
+ // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
2345
+ chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
2346
+ '-----END RSA PUBLIC KEY-----';
2347
+ default:
2348
+ return $key;
2349
+ }
2350
+ }
2351
+
2352
+ /**
2353
+ * Decodes an IP address
2354
+ *
2355
+ * Takes in a base64 encoded "blob" and returns a human readable IP address
2356
+ *
2357
+ * @param string $ip
2358
+ * @access private
2359
+ * @return string
2360
+ */
2361
+ function _decodeIP($ip)
2362
+ {
2363
+ $ip = base64_decode($ip);
2364
+ list(, $ip) = unpack('N', $ip);
2365
+ return long2ip($ip);
2366
+ }
2367
+
2368
+ /**
2369
+ * Encodes an IP address
2370
+ *
2371
+ * Takes a human readable IP address into a base64-encoded "blob"
2372
+ *
2373
+ * @param string $ip
2374
+ * @access private
2375
+ * @return string
2376
+ */
2377
+ function _encodeIP($ip)
2378
+ {
2379
+ return base64_encode(pack('N', ip2long($ip)));
2380
+ }
2381
+
2382
+ /**
2383
+ * "Normalizes" a Distinguished Name property
2384
+ *
2385
+ * @param string $propName
2386
+ * @access private
2387
+ * @return mixed
2388
+ */
2389
+ function _translateDNProp($propName)
2390
+ {
2391
+ switch (strtolower($propName)) {
2392
+ case 'id-at-countryname':
2393
+ case 'countryname':
2394
+ case 'c':
2395
+ return 'id-at-countryName';
2396
+ case 'id-at-organizationname':
2397
+ case 'organizationname':
2398
+ case 'o':
2399
+ return 'id-at-organizationName';
2400
+ case 'id-at-dnqualifier':
2401
+ case 'dnqualifier':
2402
+ return 'id-at-dnQualifier';
2403
+ case 'id-at-commonname':
2404
+ case 'commonname':
2405
+ case 'cn':
2406
+ return 'id-at-commonName';
2407
+ case 'id-at-stateorprovincename':
2408
+ case 'stateorprovincename':
2409
+ case 'state':
2410
+ case 'province':
2411
+ case 'provincename':
2412
+ case 'st':
2413
+ return 'id-at-stateOrProvinceName';
2414
+ case 'id-at-localityname':
2415
+ case 'localityname':
2416
+ case 'l':
2417
+ return 'id-at-localityName';
2418
+ case 'id-emailaddress':
2419
+ case 'emailaddress':
2420
+ return 'pkcs-9-at-emailAddress';
2421
+ case 'id-at-serialnumber':
2422
+ case 'serialnumber':
2423
+ return 'id-at-serialNumber';
2424
+ case 'id-at-postalcode':
2425
+ case 'postalcode':
2426
+ return 'id-at-postalCode';
2427
+ case 'id-at-streetaddress':
2428
+ case 'streetaddress':
2429
+ return 'id-at-streetAddress';
2430
+ case 'id-at-name':
2431
+ case 'name':
2432
+ return 'id-at-name';
2433
+ case 'id-at-givenname':
2434
+ case 'givenname':
2435
+ return 'id-at-givenName';
2436
+ case 'id-at-surname':
2437
+ case 'surname':
2438
+ case 'sn':
2439
+ return 'id-at-surname';
2440
+ case 'id-at-initials':
2441
+ case 'initials':
2442
+ return 'id-at-initials';
2443
+ case 'id-at-generationqualifier':
2444
+ case 'generationqualifier':
2445
+ return 'id-at-generationQualifier';
2446
+ case 'id-at-organizationalunitname':
2447
+ case 'organizationalunitname':
2448
+ case 'ou':
2449
+ return 'id-at-organizationalUnitName';
2450
+ case 'id-at-pseudonym':
2451
+ case 'pseudonym':
2452
+ return 'id-at-pseudonym';
2453
+ case 'id-at-title':
2454
+ case 'title':
2455
+ return 'id-at-title';
2456
+ case 'id-at-description':
2457
+ case 'description':
2458
+ return 'id-at-description';
2459
+ case 'id-at-role':
2460
+ case 'role':
2461
+ return 'id-at-role';
2462
+ case 'id-at-uniqueidentifier':
2463
+ case 'uniqueidentifier':
2464
+ case 'x500uniqueidentifier':
2465
+ return 'id-at-uniqueIdentifier';
2466
+ case 'postaladdress':
2467
+ case 'id-at-postaladdress':
2468
+ return 'id-at-postalAddress';
2469
+ default:
2470
+ return false;
2471
+ }
2472
+ }
2473
+
2474
+ /**
2475
+ * Set a Distinguished Name property
2476
+ *
2477
+ * @param string $propName
2478
+ * @param mixed $propValue
2479
+ * @param string $type optional
2480
+ * @access public
2481
+ * @return bool
2482
+ */
2483
+ function setDNProp($propName, $propValue, $type = 'utf8String')
2484
+ {
2485
+ if (empty($this->dn)) {
2486
+ $this->dn = array('rdnSequence' => array());
2487
+ }
2488
+
2489
+ if (($propName = $this->_translateDNProp($propName)) === false) {
2490
+ return false;
2491
+ }
2492
+
2493
+ foreach ((array) $propValue as $v) {
2494
+ if (!is_array($v) && isset($type)) {
2495
+ $v = array($type => $v);
2496
+ }
2497
+ $this->dn['rdnSequence'][] = array(
2498
+ array(
2499
+ 'type' => $propName,
2500
+ 'value'=> $v
2501
+ )
2502
+ );
2503
+ }
2504
+
2505
+ return true;
2506
+ }
2507
+
2508
+ /**
2509
+ * Remove Distinguished Name properties
2510
+ *
2511
+ * @param string $propName
2512
+ * @access public
2513
+ */
2514
+ function removeDNProp($propName)
2515
+ {
2516
+ if (empty($this->dn)) {
2517
+ return;
2518
+ }
2519
+
2520
+ if (($propName = $this->_translateDNProp($propName)) === false) {
2521
+ return;
2522
+ }
2523
+
2524
+ $dn = &$this->dn['rdnSequence'];
2525
+ $size = count($dn);
2526
+ for ($i = 0; $i < $size; $i++) {
2527
+ if ($dn[$i][0]['type'] == $propName) {
2528
+ unset($dn[$i]);
2529
+ }
2530
+ }
2531
+
2532
+ $dn = array_values($dn);
2533
+ // fix for https://bugs.php.net/75433 affecting PHP 7.2
2534
+ if (!isset($dn[0])) {
2535
+ $dn = array_splice($dn, 0, 0);
2536
+ }
2537
+ }
2538
+
2539
+ /**
2540
+ * Get Distinguished Name properties
2541
+ *
2542
+ * @param string $propName
2543
+ * @param array $dn optional
2544
+ * @param bool $withType optional
2545
+ * @return mixed
2546
+ * @access public
2547
+ */
2548
+ function getDNProp($propName, $dn = null, $withType = false)
2549
+ {
2550
+ if (!isset($dn)) {
2551
+ $dn = $this->dn;
2552
+ }
2553
+
2554
+ if (empty($dn)) {
2555
+ return false;
2556
+ }
2557
+
2558
+ if (($propName = $this->_translateDNProp($propName)) === false) {
2559
+ return false;
2560
+ }
2561
+
2562
+ $asn1 = new File_ASN1();
2563
+ $asn1->loadOIDs($this->oids);
2564
+ $filters = array();
2565
+ $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2566
+ $asn1->loadFilters($filters);
2567
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2568
+ $dn = $dn['rdnSequence'];
2569
+ $result = array();
2570
+ for ($i = 0; $i < count($dn); $i++) {
2571
+ if ($dn[$i][0]['type'] == $propName) {
2572
+ $v = $dn[$i][0]['value'];
2573
+ if (!$withType) {
2574
+ if (is_array($v)) {
2575
+ foreach ($v as $type => $s) {
2576
+ $type = array_search($type, $asn1->ANYmap, true);
2577
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2578
+ $s = $asn1->convert($s, $type);
2579
+ if ($s !== false) {
2580
+ $v = $s;
2581
+ break;
2582
+ }
2583
+ }
2584
+ }
2585
+ if (is_array($v)) {
2586
+ $v = array_pop($v); // Always strip data type.
2587
+ }
2588
+ } elseif (is_object($v) && strtolower(get_class($v)) == 'file_asn1_element') {
2589
+ $map = $this->_getMapping($propName);
2590
+ if (!is_bool($map)) {
2591
+ $decoded = $asn1->decodeBER($v);
2592
+ $v = $asn1->asn1map($decoded[0], $map);
2593
+ }
2594
+ }
2595
+ }
2596
+ $result[] = $v;
2597
+ }
2598
+ }
2599
+
2600
+ return $result;
2601
+ }
2602
+
2603
+ /**
2604
+ * Set a Distinguished Name
2605
+ *
2606
+ * @param mixed $dn
2607
+ * @param bool $merge optional
2608
+ * @param string $type optional
2609
+ * @access public
2610
+ * @return bool
2611
+ */
2612
+ function setDN($dn, $merge = false, $type = 'utf8String')
2613
+ {
2614
+ if (!$merge) {
2615
+ $this->dn = null;
2616
+ }
2617
+
2618
+ if (is_array($dn)) {
2619
+ if (isset($dn['rdnSequence'])) {
2620
+ $this->dn = $dn; // No merge here.
2621
+ return true;
2622
+ }
2623
+
2624
+ // handles stuff generated by openssl_x509_parse()
2625
+ foreach ($dn as $prop => $value) {
2626
+ if (!$this->setDNProp($prop, $value, $type)) {
2627
+ return false;
2628
+ }
2629
+ }
2630
+ return true;
2631
+ }
2632
+
2633
+ // handles everything else
2634
+ $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2635
+ for ($i = 1; $i < count($results); $i+=2) {
2636
+ $prop = trim($results[$i], ', =/');
2637
+ $value = $results[$i + 1];
2638
+ if (!$this->setDNProp($prop, $value, $type)) {
2639
+ return false;
2640
+ }
2641
+ }
2642
+
2643
+ return true;
2644
+ }
2645
+
2646
+ /**
2647
+ * Get the Distinguished Name for a certificates subject
2648
+ *
2649
+ * @param mixed $format optional
2650
+ * @param array $dn optional
2651
+ * @access public
2652
+ * @return bool
2653
+ */
2654
+ function getDN($format = FILE_X509_DN_ARRAY, $dn = null)
2655
+ {
2656
+ if (!isset($dn)) {
2657
+ $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
2658
+ }
2659
+
2660
+ switch ((int) $format) {
2661
+ case FILE_X509_DN_ARRAY:
2662
+ return $dn;
2663
+ case FILE_X509_DN_ASN1:
2664
+ $asn1 = new File_ASN1();
2665
+ $asn1->loadOIDs($this->oids);
2666
+ $filters = array();
2667
+ $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2668
+ $asn1->loadFilters($filters);
2669
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2670
+ return $asn1->encodeDER($dn, $this->Name);
2671
+ case FILE_X509_DN_CANON:
2672
+ // No SEQUENCE around RDNs and all string values normalized as
2673
+ // trimmed lowercase UTF-8 with all spacing as one blank.
2674
+ // constructed RDNs will not be canonicalized
2675
+ $asn1 = new File_ASN1();
2676
+ $asn1->loadOIDs($this->oids);
2677
+ $filters = array();
2678
+ $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2679
+ $asn1->loadFilters($filters);
2680
+ $result = '';
2681
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2682
+ foreach ($dn['rdnSequence'] as $rdn) {
2683
+ foreach ($rdn as $i => $attr) {
2684
+ $attr = &$rdn[$i];
2685
+ if (is_array($attr['value'])) {
2686
+ foreach ($attr['value'] as $type => $v) {
2687
+ $type = array_search($type, $asn1->ANYmap, true);
2688
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2689
+ $v = $asn1->convert($v, $type);
2690
+ if ($v !== false) {
2691
+ $v = preg_replace('/\s+/', ' ', $v);
2692
+ $attr['value'] = strtolower(trim($v));
2693
+ break;
2694
+ }
2695
+ }
2696
+ }
2697
+ }
2698
+ }
2699
+ $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
2700
+ }
2701
+ return $result;
2702
+ case FILE_X509_DN_HASH:
2703
+ $dn = $this->getDN(FILE_X509_DN_CANON, $dn);
2704
+ if (!class_exists('Crypt_Hash')) {
2705
+ include_once 'Crypt/Hash.php';
2706
+ }
2707
+ $hash = new Crypt_Hash('sha1');
2708
+ $hash = $hash->hash($dn);
2709
+ extract(unpack('Vhash', $hash));
2710
+ return strtolower(bin2hex(pack('N', $hash)));
2711
+ }
2712
+
2713
+ // Default is to return a string.
2714
+ $start = true;
2715
+ $output = '';
2716
+ $result = array();
2717
+ $asn1 = new File_ASN1();
2718
+ $asn1->loadOIDs($this->oids);
2719
+ $filters = array();
2720
+ $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
2721
+ $asn1->loadFilters($filters);
2722
+ $this->_mapOutDNs($dn, 'rdnSequence', $asn1);
2723
+ foreach ($dn['rdnSequence'] as $field) {
2724
+ $prop = $field[0]['type'];
2725
+ $value = $field[0]['value'];
2726
+
2727
+ $delim = ', ';
2728
+ switch ($prop) {
2729
+ case 'id-at-countryName':
2730
+ $desc = 'C';
2731
+ break;
2732
+ case 'id-at-stateOrProvinceName':
2733
+ $desc = 'ST';
2734
+ break;
2735
+ case 'id-at-organizationName':
2736
+ $desc = 'O';
2737
+ break;
2738
+ case 'id-at-organizationalUnitName':
2739
+ $desc = 'OU';
2740
+ break;
2741
+ case 'id-at-commonName':
2742
+ $desc = 'CN';
2743
+ break;
2744
+ case 'id-at-localityName':
2745
+ $desc = 'L';
2746
+ break;
2747
+ case 'id-at-surname':
2748
+ $desc = 'SN';
2749
+ break;
2750
+ case 'id-at-uniqueIdentifier':
2751
+ $delim = '/';
2752
+ $desc = 'x500UniqueIdentifier';
2753
+ break;
2754
+ case 'id-at-postalAddress':
2755
+ $delim = '/';
2756
+ $desc = 'postalAddress';
2757
+ break;
2758
+ default:
2759
+ $delim = '/';
2760
+ $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
2761
+ }
2762
+
2763
+ if (!$start) {
2764
+ $output.= $delim;
2765
+ }
2766
+ if (is_array($value)) {
2767
+ foreach ($value as $type => $v) {
2768
+ $type = array_search($type, $asn1->ANYmap, true);
2769
+ if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2770
+ $v = $asn1->convert($v, $type);
2771
+ if ($v !== false) {
2772
+ $value = $v;
2773
+ break;
2774
+ }
2775
+ }
2776
+ }
2777
+ if (is_array($value)) {
2778
+ $value = array_pop($value); // Always strip data type.
2779
+ }
2780
+ } elseif (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
2781
+ // @codingStandardsIgnoreStart
2782
+ $callback = version_compare(PHP_VERSION, '5.3.0') >= 0 ?
2783
+ function ($x) { return "\x" . bin2hex($x[0]); } :
2784
+ create_function('$x', 'return "\x" . bin2hex($x[0]);');
2785
+ // @codingStandardsIgnoreEnd
2786
+ $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
2787
+ }
2788
+ $output.= $desc . '=' . $value;
2789
+ $result[$desc] = isset($result[$desc]) ?
2790
+ array_merge((array) $dn[$prop], array($value)) :
2791
+ $value;
2792
+ $start = false;
2793
+ }
2794
+
2795
+ return $format == FILE_X509_DN_OPENSSL ? $result : $output;
2796
+ }
2797
+
2798
+ /**
2799
+ * Get the Distinguished Name for a certificate/crl issuer
2800
+ *
2801
+ * @param int $format optional
2802
+ * @access public
2803
+ * @return mixed
2804
+ */
2805
+ function getIssuerDN($format = FILE_X509_DN_ARRAY)
2806
+ {
2807
+ switch (true) {
2808
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2809
+ break;
2810
+ case isset($this->currentCert['tbsCertificate']):
2811
+ return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
2812
+ case isset($this->currentCert['tbsCertList']):
2813
+ return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
2814
+ }
2815
+
2816
+ return false;
2817
+ }
2818
+
2819
+ /**
2820
+ * Get the Distinguished Name for a certificate/csr subject
2821
+ * Alias of getDN()
2822
+ *
2823
+ * @param int $format optional
2824
+ * @access public
2825
+ * @return mixed
2826
+ */
2827
+ function getSubjectDN($format = FILE_X509_DN_ARRAY)
2828
+ {
2829
+ switch (true) {
2830
+ case !empty($this->dn):
2831
+ return $this->getDN($format);
2832
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2833
+ break;
2834
+ case isset($this->currentCert['tbsCertificate']):
2835
+ return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
2836
+ case isset($this->currentCert['certificationRequestInfo']):
2837
+ return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
2838
+ }
2839
+
2840
+ return false;
2841
+ }
2842
+
2843
+ /**
2844
+ * Get an individual Distinguished Name property for a certificate/crl issuer
2845
+ *
2846
+ * @param string $propName
2847
+ * @param bool $withType optional
2848
+ * @access public
2849
+ * @return mixed
2850
+ */
2851
+ function getIssuerDNProp($propName, $withType = false)
2852
+ {
2853
+ switch (true) {
2854
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2855
+ break;
2856
+ case isset($this->currentCert['tbsCertificate']):
2857
+ return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
2858
+ case isset($this->currentCert['tbsCertList']):
2859
+ return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
2860
+ }
2861
+
2862
+ return false;
2863
+ }
2864
+
2865
+ /**
2866
+ * Get an individual Distinguished Name property for a certificate/csr subject
2867
+ *
2868
+ * @param string $propName
2869
+ * @param bool $withType optional
2870
+ * @access public
2871
+ * @return mixed
2872
+ */
2873
+ function getSubjectDNProp($propName, $withType = false)
2874
+ {
2875
+ switch (true) {
2876
+ case !empty($this->dn):
2877
+ return $this->getDNProp($propName, null, $withType);
2878
+ case !isset($this->currentCert) || !is_array($this->currentCert):
2879
+ break;
2880
+ case isset($this->currentCert['tbsCertificate']):
2881
+ return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
2882
+ case isset($this->currentCert['certificationRequestInfo']):
2883
+ return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
2884
+ }
2885
+
2886
+ return false;
2887
+ }
2888
+
2889
+ /**
2890
+ * Get the certificate chain for the current cert
2891
+ *
2892
+ * @access public
2893
+ * @return mixed
2894
+ */
2895
+ function getChain()
2896
+ {
2897
+ $chain = array($this->currentCert);
2898
+
2899
+ if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2900
+ return false;
2901
+ }
2902
+ if (empty($this->CAs)) {
2903
+ return $chain;
2904
+ }
2905
+ while (true) {
2906
+ $currentCert = $chain[count($chain) - 1];
2907
+ for ($i = 0; $i < count($this->CAs); $i++) {
2908
+ $ca = $this->CAs[$i];
2909
+ if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2910
+ $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
2911
+ $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2912
+ switch (true) {
2913
+ case !is_array($authorityKey):
2914
+ case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2915
+ if ($currentCert === $ca) {
2916
+ break 3;
2917
+ }
2918
+ $chain[] = $ca;
2919
+ break 2;
2920
+ }
2921
+ }
2922
+ }
2923
+ if ($i == count($this->CAs)) {
2924
+ break;
2925
+ }
2926
+ }
2927
+ foreach ($chain as $key => $value) {
2928
+ $chain[$key] = new File_X509();
2929
+ $chain[$key]->loadX509($value);
2930
+ }
2931
+ return $chain;
2932
+ }
2933
+
2934
+ /**
2935
+ * Set public key
2936
+ *
2937
+ * Key needs to be a Crypt_RSA object
2938
+ *
2939
+ * @param object $key
2940
+ * @access public
2941
+ * @return bool
2942
+ */
2943
+ function setPublicKey($key)
2944
+ {
2945
+ $key->setPublicKey();
2946
+ $this->publicKey = $key;
2947
+ }
2948
+
2949
+ /**
2950
+ * Set private key
2951
+ *
2952
+ * Key needs to be a Crypt_RSA object
2953
+ *
2954
+ * @param object $key
2955
+ * @access public
2956
+ */
2957
+ function setPrivateKey($key)
2958
+ {
2959
+ $this->privateKey = $key;
2960
+ }
2961
+
2962
+ /**
2963
+ * Set challenge
2964
+ *
2965
+ * Used for SPKAC CSR's
2966
+ *
2967
+ * @param string $challenge
2968
+ * @access public
2969
+ */
2970
+ function setChallenge($challenge)
2971
+ {
2972
+ $this->challenge = $challenge;
2973
+ }
2974
+
2975
+ /**
2976
+ * Gets the public key
2977
+ *
2978
+ * Returns a Crypt_RSA object or a false.
2979
+ *
2980
+ * @access public
2981
+ * @return mixed
2982
+ */
2983
+ function getPublicKey()
2984
+ {
2985
+ if (isset($this->publicKey)) {
2986
+ return $this->publicKey;
2987
+ }
2988
+
2989
+ if (isset($this->currentCert) && is_array($this->currentCert)) {
2990
+ foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
2991
+ $keyinfo = $this->_subArray($this->currentCert, $path);
2992
+ if (!empty($keyinfo)) {
2993
+ break;
2994
+ }
2995
+ }
2996
+ }
2997
+ if (empty($keyinfo)) {
2998
+ return false;
2999
+ }
3000
+
3001
+ $key = $keyinfo['subjectPublicKey'];
3002
+
3003
+ switch ($keyinfo['algorithm']['algorithm']) {
3004
+ case 'rsaEncryption':
3005
+ if (!class_exists('Crypt_RSA')) {
3006
+ include_once 'Crypt/RSA.php';
3007
+ }
3008
+ $publicKey = new Crypt_RSA();
3009
+ $publicKey->loadKey($key);
3010
+ $publicKey->setPublicKey();
3011
+ break;
3012
+ default:
3013
+ return false;
3014
+ }
3015
+
3016
+ return $publicKey;
3017
+ }
3018
+
3019
+ /**
3020
+ * Load a Certificate Signing Request
3021
+ *
3022
+ * @param string $csr
3023
+ * @access public
3024
+ * @return mixed
3025
+ */
3026
+ function loadCSR($csr, $mode = FILE_X509_FORMAT_AUTO_DETECT)
3027
+ {
3028
+ if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
3029
+ unset($this->currentCert);
3030
+ unset($this->currentKeyIdentifier);
3031
+ unset($this->signatureSubject);
3032
+ $this->dn = $csr['certificationRequestInfo']['subject'];
3033
+ if (!isset($this->dn)) {
3034
+ return false;
3035
+ }
3036
+
3037
+ $this->currentCert = $csr;
3038
+ return $csr;
3039
+ }
3040
+
3041
+ // see http://tools.ietf.org/html/rfc2986
3042
+
3043
+ $asn1 = new File_ASN1();
3044
+
3045
+ if ($mode != FILE_X509_FORMAT_DER) {
3046
+ $newcsr = $this->_extractBER($csr);
3047
+ if ($mode == FILE_X509_FORMAT_PEM && $csr == $newcsr) {
3048
+ return false;
3049
+ }
3050
+ $csr = $newcsr;
3051
+ }
3052
+ $orig = $csr;
3053
+
3054
+ if ($csr === false) {
3055
+ $this->currentCert = false;
3056
+ return false;
3057
+ }
3058
+
3059
+ $asn1->loadOIDs($this->oids);
3060
+ $decoded = $asn1->decodeBER($csr);
3061
+
3062
+ if (empty($decoded)) {
3063
+ $this->currentCert = false;
3064
+ return false;
3065
+ }
3066
+
3067
+ $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
3068
+ if (!isset($csr) || $csr === false) {
3069
+ $this->currentCert = false;
3070
+ return false;
3071
+ }
3072
+
3073
+ $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
3074
+ $this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
3075
+
3076
+ $this->dn = $csr['certificationRequestInfo']['subject'];
3077
+
3078
+ $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3079
+
3080
+ $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
3081
+ $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
3082
+ $key = $this->_reformatKey($algorithm, $key);
3083
+
3084
+ switch ($algorithm) {
3085
+ case 'rsaEncryption':
3086
+ if (!class_exists('Crypt_RSA')) {
3087
+ include_once 'Crypt/RSA.php';
3088
+ }
3089
+ $this->publicKey = new Crypt_RSA();
3090
+ $this->publicKey->loadKey($key);
3091
+ $this->publicKey->setPublicKey();
3092
+ break;
3093
+ default:
3094
+ $this->publicKey = null;
3095
+ }
3096
+
3097
+ $this->currentKeyIdentifier = null;
3098
+ $this->currentCert = $csr;
3099
+
3100
+ return $csr;
3101
+ }
3102
+
3103
+ /**
3104
+ * Save CSR request
3105
+ *
3106
+ * @param array $csr
3107
+ * @param int $format optional
3108
+ * @access public
3109
+ * @return string
3110
+ */
3111
+ function saveCSR($csr, $format = FILE_X509_FORMAT_PEM)
3112
+ {
3113
+ if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
3114
+ return false;
3115
+ }
3116
+
3117
+ switch (true) {
3118
+ case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
3119
+ case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
3120
+ break;
3121
+ default:
3122
+ switch ($algorithm) {
3123
+ case 'rsaEncryption':
3124
+ $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
3125
+ = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
3126
+ $csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
3127
+ $csr['signatureAlgorithm']['parameters'] = null;
3128
+ $csr['certificationRequestInfo']['signature']['parameters'] = null;
3129
+ }
3130
+ }
3131
+
3132
+ $asn1 = new File_ASN1();
3133
+
3134
+ $asn1->loadOIDs($this->oids);
3135
+
3136
+ $filters = array();
3137
+ $filters['certificationRequestInfo']['subject']['rdnSequence']['value']
3138
+ = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3139
+
3140
+ $asn1->loadFilters($filters);
3141
+
3142
+ $this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
3143
+ $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
3144
+ $csr = $asn1->encodeDER($csr, $this->CertificationRequest);
3145
+
3146
+ switch ($format) {
3147
+ case FILE_X509_FORMAT_DER:
3148
+ return $csr;
3149
+ // case FILE_X509_FORMAT_PEM:
3150
+ default:
3151
+ return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
3152
+ }
3153
+ }
3154
+
3155
+ /**
3156
+ * Load a SPKAC CSR
3157
+ *
3158
+ * SPKAC's are produced by the HTML5 keygen element:
3159
+ *
3160
+ * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
3161
+ *
3162
+ * @param string $csr
3163
+ * @access public
3164
+ * @return mixed
3165
+ */
3166
+ function loadSPKAC($spkac)
3167
+ {
3168
+ if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
3169
+ unset($this->currentCert);
3170
+ unset($this->currentKeyIdentifier);
3171
+ unset($this->signatureSubject);
3172
+ $this->currentCert = $spkac;
3173
+ return $spkac;
3174
+ }
3175
+
3176
+ // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
3177
+
3178
+ $asn1 = new File_ASN1();
3179
+
3180
+ // OpenSSL produces SPKAC's that are preceded by the string SPKAC=
3181
+ $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
3182
+ $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
3183
+ if ($temp != false) {
3184
+ $spkac = $temp;
3185
+ }
3186
+ $orig = $spkac;
3187
+
3188
+ if ($spkac === false) {
3189
+ $this->currentCert = false;
3190
+ return false;
3191
+ }
3192
+
3193
+ $asn1->loadOIDs($this->oids);
3194
+ $decoded = $asn1->decodeBER($spkac);
3195
+
3196
+ if (empty($decoded)) {
3197
+ $this->currentCert = false;
3198
+ return false;
3199
+ }
3200
+
3201
+ $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
3202
+
3203
+ if (!isset($spkac) || $spkac === false) {
3204
+ $this->currentCert = false;
3205
+ return false;
3206
+ }
3207
+
3208
+ $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3209
+
3210
+ $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
3211
+ $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
3212
+ $key = $this->_reformatKey($algorithm, $key);
3213
+
3214
+ switch ($algorithm) {
3215
+ case 'rsaEncryption':
3216
+ if (!class_exists('Crypt_RSA')) {
3217
+ include_once 'Crypt/RSA.php';
3218
+ }
3219
+ $this->publicKey = new Crypt_RSA();
3220
+ $this->publicKey->loadKey($key);
3221
+ $this->publicKey->setPublicKey();
3222
+ break;
3223
+ default:
3224
+ $this->publicKey = null;
3225
+ }
3226
+
3227
+ $this->currentKeyIdentifier = null;
3228
+ $this->currentCert = $spkac;
3229
+
3230
+ return $spkac;
3231
+ }
3232
+
3233
+ /**
3234
+ * Save a SPKAC CSR request
3235
+ *
3236
+ * @param array $csr
3237
+ * @param int $format optional
3238
+ * @access public
3239
+ * @return string
3240
+ */
3241
+ function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM)
3242
+ {
3243
+ if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
3244
+ return false;
3245
+ }
3246
+
3247
+ $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
3248
+ switch (true) {
3249
+ case !$algorithm:
3250
+ case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
3251
+ break;
3252
+ default:
3253
+ switch ($algorithm) {
3254
+ case 'rsaEncryption':
3255
+ $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
3256
+ = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
3257
+ }
3258
+ }
3259
+
3260
+ $asn1 = new File_ASN1();
3261
+
3262
+ $asn1->loadOIDs($this->oids);
3263
+ $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);
3264
+
3265
+ switch ($format) {
3266
+ case FILE_X509_FORMAT_DER:
3267
+ return $spkac;
3268
+ // case FILE_X509_FORMAT_PEM:
3269
+ default:
3270
+ // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much
3271
+ // no other SPKAC decoders phpseclib will use that same format
3272
+ return 'SPKAC=' . base64_encode($spkac);
3273
+ }
3274
+ }
3275
+
3276
+ /**
3277
+ * Load a Certificate Revocation List
3278
+ *
3279
+ * @param string $crl
3280
+ * @access public
3281
+ * @return mixed
3282
+ */
3283
+ function loadCRL($crl, $mode = FILE_X509_FORMAT_AUTO_DETECT)
3284
+ {
3285
+ if (is_array($crl) && isset($crl['tbsCertList'])) {
3286
+ $this->currentCert = $crl;
3287
+ unset($this->signatureSubject);
3288
+ return $crl;
3289
+ }
3290
+
3291
+ $asn1 = new File_ASN1();
3292
+
3293
+ if ($mode != FILE_X509_FORMAT_DER) {
3294
+ $newcrl = $this->_extractBER($crl);
3295
+ if ($mode == FILE_X509_FORMAT_PEM && $crl == $newcrl) {
3296
+ return false;
3297
+ }
3298
+ $crl = $newcrl;
3299
+ }
3300
+ $orig = $crl;
3301
+
3302
+ if ($crl === false) {
3303
+ $this->currentCert = false;
3304
+ return false;
3305
+ }
3306
+
3307
+ $asn1->loadOIDs($this->oids);
3308
+ $decoded = $asn1->decodeBER($crl);
3309
+
3310
+ if (empty($decoded)) {
3311
+ $this->currentCert = false;
3312
+ return false;
3313
+ }
3314
+
3315
+ $crl = $asn1->asn1map($decoded[0], $this->CertificateList);
3316
+ if (!isset($crl) || $crl === false) {
3317
+ $this->currentCert = false;
3318
+ return false;
3319
+ }
3320
+
3321
+ $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3322
+
3323
+ $this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
3324
+ if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
3325
+ $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3326
+ }
3327
+ if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
3328
+ $rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
3329
+ if ($rclist_ref) {
3330
+ $rclist = $crl['tbsCertList']['revokedCertificates'];
3331
+ foreach ($rclist as $i => $extension) {
3332
+ if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
3333
+ $this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
3334
+ }
3335
+ }
3336
+ }
3337
+ }
3338
+
3339
+ $this->currentKeyIdentifier = null;
3340
+ $this->currentCert = $crl;
3341
+
3342
+ return $crl;
3343
+ }
3344
+
3345
+ /**
3346
+ * Save Certificate Revocation List.
3347
+ *
3348
+ * @param array $crl
3349
+ * @param int $format optional
3350
+ * @access public
3351
+ * @return string
3352
+ */
3353
+ function saveCRL($crl, $format = FILE_X509_FORMAT_PEM)
3354
+ {
3355
+ if (!is_array($crl) || !isset($crl['tbsCertList'])) {
3356
+ return false;
3357
+ }
3358
+
3359
+ $asn1 = new File_ASN1();
3360
+
3361
+ $asn1->loadOIDs($this->oids);
3362
+
3363
+ $filters = array();
3364
+ $filters['tbsCertList']['issuer']['rdnSequence']['value']
3365
+ = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3366
+ $filters['tbsCertList']['signature']['parameters']
3367
+ = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3368
+ $filters['signatureAlgorithm']['parameters']
3369
+ = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
3370
+
3371
+ if (empty($crl['tbsCertList']['signature']['parameters'])) {
3372
+ $filters['tbsCertList']['signature']['parameters']
3373
+ = array('type' => FILE_ASN1_TYPE_NULL);
3374
+ }
3375
+
3376
+ if (empty($crl['signatureAlgorithm']['parameters'])) {
3377
+ $filters['signatureAlgorithm']['parameters']
3378
+ = array('type' => FILE_ASN1_TYPE_NULL);
3379
+ }
3380
+
3381
+ $asn1->loadFilters($filters);
3382
+
3383
+ $this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
3384
+ $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3385
+ $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
3386
+ if (is_array($rclist)) {
3387
+ foreach ($rclist as $i => $extension) {
3388
+ $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3389
+ }
3390
+ }
3391
+
3392
+ $crl = $asn1->encodeDER($crl, $this->CertificateList);
3393
+
3394
+ switch ($format) {
3395
+ case FILE_X509_FORMAT_DER:
3396
+ return $crl;
3397
+ // case FILE_X509_FORMAT_PEM:
3398
+ default:
3399
+ return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
3400
+ }
3401
+ }
3402
+
3403
+ /**
3404
+ * Helper function to build a time field according to RFC 3280 section
3405
+ * - 4.1.2.5 Validity
3406
+ * - 5.1.2.4 This Update
3407
+ * - 5.1.2.5 Next Update
3408
+ * - 5.1.2.6 Revoked Certificates
3409
+ * by choosing utcTime iff year of date given is before 2050 and generalTime else.
3410
+ *
3411
+ * @param string $date in format date('D, d M Y H:i:s O')
3412
+ * @access private
3413
+ * @return array
3414
+ */
3415
+ function _timeField($date)
3416
+ {
3417
+ if (is_object($date) && strtolower(get_class($date)) == 'file_asn1_element') {
3418
+ return $date;
3419
+ }
3420
+ if (!class_exists('DateTime')) {
3421
+ $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
3422
+ } else {
3423
+ $dateObj = new DateTime($date, new DateTimeZone('GMT'));
3424
+ $year = $dateObj->format('Y');
3425
+ }
3426
+ if ($year < 2050) {
3427
+ return array('utcTime' => $date);
3428
+ } else {
3429
+ return array('generalTime' => $date);
3430
+ }
3431
+ }
3432
+
3433
+ /**
3434
+ * Sign an X.509 certificate
3435
+ *
3436
+ * $issuer's private key needs to be loaded.
3437
+ * $subject can be either an existing X.509 cert (if you want to resign it),
3438
+ * a CSR or something with the DN and public key explicitly set.
3439
+ *
3440
+ * @param File_X509 $issuer
3441
+ * @param File_X509 $subject
3442
+ * @param string $signatureAlgorithm optional
3443
+ * @access public
3444
+ * @return mixed
3445
+ */
3446
+ function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
3447
+ {
3448
+ if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3449
+ return false;
3450
+ }
3451
+
3452
+ if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
3453
+ return false;
3454
+ }
3455
+
3456
+ $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3457
+ $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3458
+
3459
+ if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
3460
+ $this->currentCert = $subject->currentCert;
3461
+ $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
3462
+ $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3463
+
3464
+ if (!empty($this->startDate)) {
3465
+ $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
3466
+ }
3467
+ if (!empty($this->endDate)) {
3468
+ $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
3469
+ }
3470
+ if (!empty($this->serialNumber)) {
3471
+ $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
3472
+ }
3473
+ if (!empty($subject->dn)) {
3474
+ $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
3475
+ }
3476
+ if (!empty($subject->publicKey)) {
3477
+ $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
3478
+ }
3479
+ $this->removeExtension('id-ce-authorityKeyIdentifier');
3480
+ if (isset($subject->domains)) {
3481
+ $this->removeExtension('id-ce-subjectAltName');
3482
+ }
3483
+ } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
3484
+ return false;
3485
+ } else {
3486
+ if (!isset($subject->publicKey)) {
3487
+ return false;
3488
+ }
3489
+
3490
+ if (!class_exists('DateTime')) {
3491
+ $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
3492
+ $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
3493
+ } else {
3494
+ $startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
3495
+ $startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
3496
+
3497
+ $endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
3498
+ $endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
3499
+ }
3500
+ if (!empty($this->serialNumber)) {
3501
+ $serialNumber = $this->serialNumber;
3502
+ } else {
3503
+ if (!function_exists('crypt_random_string')) {
3504
+ include_once 'Crypt/Random.php';
3505
+ }
3506
+ /* "The serial number MUST be a positive integer"
3507
+ "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
3508
+ -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
3509
+
3510
+ for the integer to be positive the leading bit needs to be 0 hence the
3511
+ application of a bitmap
3512
+ */
3513
+ $serialNumber = new Math_BigInteger(crypt_random_string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);
3514
+ }
3515
+
3516
+ $this->currentCert = array(
3517
+ 'tbsCertificate' =>
3518
+ array(
3519
+ 'version' => 'v3',
3520
+ 'serialNumber' => $serialNumber, // $this->setserialNumber()
3521
+ 'signature' => array('algorithm' => $signatureAlgorithm),
3522
+ 'issuer' => false, // this is going to be overwritten later
3523
+ 'validity' => array(
3524
+ 'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
3525
+ 'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
3526
+ ),
3527
+ 'subject' => $subject->dn,
3528
+ 'subjectPublicKeyInfo' => $subjectPublicKey
3529
+ ),
3530
+ 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3531
+ 'signature' => false // this is going to be overwritten later
3532
+ );
3533
+
3534
+ // Copy extensions from CSR.
3535
+ $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
3536
+
3537
+ if (!empty($csrexts)) {
3538
+ $this->currentCert['tbsCertificate']['extensions'] = $csrexts;
3539
+ }
3540
+ }
3541
+
3542
+ $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
3543
+
3544
+ if (isset($issuer->currentKeyIdentifier)) {
3545
+ $this->setExtension('id-ce-authorityKeyIdentifier', array(
3546
+ //'authorityCertIssuer' => array(
3547
+ // array(
3548
+ // 'directoryName' => $issuer->dn
3549
+ // )
3550
+ //),
3551
+ 'keyIdentifier' => $issuer->currentKeyIdentifier
3552
+ ));
3553
+ //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
3554
+ //if (isset($issuer->serialNumber)) {
3555
+ // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3556
+ //}
3557
+ //unset($extensions);
3558
+ }
3559
+
3560
+ if (isset($subject->currentKeyIdentifier)) {
3561
+ $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
3562
+ }
3563
+
3564
+ $altName = array();
3565
+
3566
+ if (isset($subject->domains) && count($subject->domains)) {
3567
+ $altName = array_map(array('File_X509', '_dnsName'), $subject->domains);
3568
+ }
3569
+
3570
+ if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
3571
+ // should an IP address appear as the CN if no domain name is specified? idk
3572
+ //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
3573
+ $ipAddresses = array();
3574
+ foreach ($subject->ipAddresses as $ipAddress) {
3575
+ $encoded = $subject->_ipAddress($ipAddress);
3576
+ if ($encoded !== false) {
3577
+ $ipAddresses[] = $encoded;
3578
+ }
3579
+ }
3580
+ if (count($ipAddresses)) {
3581
+ $altName = array_merge($altName, $ipAddresses);
3582
+ }
3583
+ }
3584
+
3585
+ if (!empty($altName)) {
3586
+ $this->setExtension('id-ce-subjectAltName', $altName);
3587
+ }
3588
+
3589
+ if ($this->caFlag) {
3590
+ $keyUsage = $this->getExtension('id-ce-keyUsage');
3591
+ if (!$keyUsage) {
3592
+ $keyUsage = array();
3593
+ }
3594
+
3595
+ $this->setExtension(
3596
+ 'id-ce-keyUsage',
3597
+ array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
3598
+ );
3599
+
3600
+ $basicConstraints = $this->getExtension('id-ce-basicConstraints');
3601
+ if (!$basicConstraints) {
3602
+ $basicConstraints = array();
3603
+ }
3604
+
3605
+ $this->setExtension(
3606
+ 'id-ce-basicConstraints',
3607
+ array_unique(array_merge(array('cA' => true), $basicConstraints)),
3608
+ true
3609
+ );
3610
+
3611
+ if (!isset($subject->currentKeyIdentifier)) {
3612
+ $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
3613
+ }
3614
+ }
3615
+
3616
+ // resync $this->signatureSubject
3617
+ // save $tbsCertificate in case there are any File_ASN1_Element objects in it
3618
+ $tbsCertificate = $this->currentCert['tbsCertificate'];
3619
+ $this->loadX509($this->saveX509($this->currentCert));
3620
+
3621
+ $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3622
+ $result['tbsCertificate'] = $tbsCertificate;
3623
+
3624
+ $this->currentCert = $currentCert;
3625
+ $this->signatureSubject = $signatureSubject;
3626
+
3627
+ return $result;
3628
+ }
3629
+
3630
+ /**
3631
+ * Sign a CSR
3632
+ *
3633
+ * @access public
3634
+ * @return mixed
3635
+ */
3636
+ function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
3637
+ {
3638
+ if (!is_object($this->privateKey) || empty($this->dn)) {
3639
+ return false;
3640
+ }
3641
+
3642
+ $origPublicKey = $this->publicKey;
3643
+ $class = get_class($this->privateKey);
3644
+ $this->publicKey = new $class();
3645
+ $this->publicKey->loadKey($this->privateKey->getPublicKey());
3646
+ $this->publicKey->setPublicKey();
3647
+ if (!($publicKey = $this->_formatSubjectPublicKey())) {
3648
+ return false;
3649
+ }
3650
+ $this->publicKey = $origPublicKey;
3651
+
3652
+ $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3653
+ $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3654
+
3655
+ if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
3656
+ $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3657
+ if (!empty($this->dn)) {
3658
+ $this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
3659
+ }
3660
+ $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
3661
+ } else {
3662
+ $this->currentCert = array(
3663
+ 'certificationRequestInfo' =>
3664
+ array(
3665
+ 'version' => 'v1',
3666
+ 'subject' => $this->dn,
3667
+ 'subjectPKInfo' => $publicKey
3668
+ ),
3669
+ 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3670
+ 'signature' => false // this is going to be overwritten later
3671
+ );
3672
+ }
3673
+
3674
+ // resync $this->signatureSubject
3675
+ // save $certificationRequestInfo in case there are any File_ASN1_Element objects in it
3676
+ $certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
3677
+ $this->loadCSR($this->saveCSR($this->currentCert));
3678
+
3679
+ $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3680
+ $result['certificationRequestInfo'] = $certificationRequestInfo;
3681
+
3682
+ $this->currentCert = $currentCert;
3683
+ $this->signatureSubject = $signatureSubject;
3684
+
3685
+ return $result;
3686
+ }
3687
+
3688
+ /**
3689
+ * Sign a SPKAC
3690
+ *
3691
+ * @access public
3692
+ * @return mixed
3693
+ */
3694
+ function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
3695
+ {
3696
+ if (!is_object($this->privateKey)) {
3697
+ return false;
3698
+ }
3699
+
3700
+ $origPublicKey = $this->publicKey;
3701
+ $class = get_class($this->privateKey);
3702
+ $this->publicKey = new $class();
3703
+ $this->publicKey->loadKey($this->privateKey->getPublicKey());
3704
+ $this->publicKey->setPublicKey();
3705
+ $publicKey = $this->_formatSubjectPublicKey();
3706
+ if (!$publicKey) {
3707
+ return false;
3708
+ }
3709
+ $this->publicKey = $origPublicKey;
3710
+
3711
+ $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3712
+ $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3713
+
3714
+ // re-signing a SPKAC seems silly but since everything else supports re-signing why not?
3715
+ if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
3716
+ $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3717
+ $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
3718
+ if (!empty($this->challenge)) {
3719
+ // the bitwise AND ensures that the output is a valid IA5String
3720
+ $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
3721
+ }
3722
+ } else {
3723
+ $this->currentCert = array(
3724
+ 'publicKeyAndChallenge' =>
3725
+ array(
3726
+ 'spki' => $publicKey,
3727
+ // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>,
3728
+ // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
3729
+ // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
3730
+ // we could alternatively do this instead if we ignored the specs:
3731
+ // crypt_random_string(8) & str_repeat("\x7F", 8)
3732
+ 'challenge' => !empty($this->challenge) ? $this->challenge : ''
3733
+ ),
3734
+ 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3735
+ 'signature' => false // this is going to be overwritten later
3736
+ );
3737
+ }
3738
+
3739
+ // resync $this->signatureSubject
3740
+ // save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it
3741
+ $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
3742
+ $this->loadSPKAC($this->saveSPKAC($this->currentCert));
3743
+
3744
+ $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3745
+ $result['publicKeyAndChallenge'] = $publicKeyAndChallenge;
3746
+
3747
+ $this->currentCert = $currentCert;
3748
+ $this->signatureSubject = $signatureSubject;
3749
+
3750
+ return $result;
3751
+ }
3752
+
3753
+ /**
3754
+ * Sign a CRL
3755
+ *
3756
+ * $issuer's private key needs to be loaded.
3757
+ *
3758
+ * @param File_X509 $issuer
3759
+ * @param File_X509 $crl
3760
+ * @param string $signatureAlgorithm optional
3761
+ * @access public
3762
+ * @return mixed
3763
+ */
3764
+ function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
3765
+ {
3766
+ if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3767
+ return false;
3768
+ }
3769
+
3770
+ $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3771
+ $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
3772
+ if (!class_exists('DateTime')) {
3773
+ $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
3774
+ } else {
3775
+ $thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
3776
+ $thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
3777
+ }
3778
+
3779
+ if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
3780
+ $this->currentCert = $crl->currentCert;
3781
+ $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
3782
+ $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3783
+ } else {
3784
+ $this->currentCert = array(
3785
+ 'tbsCertList' =>
3786
+ array(
3787
+ 'version' => 'v2',
3788
+ 'signature' => array('algorithm' => $signatureAlgorithm),
3789
+ 'issuer' => false, // this is going to be overwritten later
3790
+ 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate()
3791
+ ),
3792
+ 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3793
+ 'signature' => false // this is going to be overwritten later
3794
+ );
3795
+ }
3796
+
3797
+ $tbsCertList = &$this->currentCert['tbsCertList'];
3798
+ $tbsCertList['issuer'] = $issuer->dn;
3799
+ $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
3800
+
3801
+ if (!empty($this->endDate)) {
3802
+ $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
3803
+ } else {
3804
+ unset($tbsCertList['nextUpdate']);
3805
+ }
3806
+
3807
+ if (!empty($this->serialNumber)) {
3808
+ $crlNumber = $this->serialNumber;
3809
+ } else {
3810
+ $crlNumber = $this->getExtension('id-ce-cRLNumber');
3811
+ // "The CRL number is a non-critical CRL extension that conveys a
3812
+ // monotonically increasing sequence number for a given CRL scope and
3813
+ // CRL issuer. This extension allows users to easily determine when a
3814
+ // particular CRL supersedes another CRL."
3815
+ // -- https://tools.ietf.org/html/rfc5280#section-5.2.3
3816
+ $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null;
3817
+ }
3818
+
3819
+ $this->removeExtension('id-ce-authorityKeyIdentifier');
3820
+ $this->removeExtension('id-ce-issuerAltName');
3821
+
3822
+ // Be sure version >= v2 if some extension found.
3823
+ $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
3824
+ if (!$version) {
3825
+ if (!empty($tbsCertList['crlExtensions'])) {
3826
+ $version = 1; // v2.
3827
+ } elseif (!empty($tbsCertList['revokedCertificates'])) {
3828
+ foreach ($tbsCertList['revokedCertificates'] as $cert) {
3829
+ if (!empty($cert['crlEntryExtensions'])) {
3830
+ $version = 1; // v2.
3831
+ }
3832
+ }
3833
+ }
3834
+
3835
+ if ($version) {
3836
+ $tbsCertList['version'] = $version;
3837
+ }
3838
+ }
3839
+
3840
+ // Store additional extensions.
3841
+ if (!empty($tbsCertList['version'])) { // At least v2.
3842
+ if (!empty($crlNumber)) {
3843
+ $this->setExtension('id-ce-cRLNumber', $crlNumber);
3844
+ }
3845
+
3846
+ if (isset($issuer->currentKeyIdentifier)) {
3847
+ $this->setExtension('id-ce-authorityKeyIdentifier', array(
3848
+ //'authorityCertIssuer' => array(
3849
+ // array(
3850
+ // 'directoryName' => $issuer->dn
3851
+ // )
3852
+ //),
3853
+ 'keyIdentifier' => $issuer->currentKeyIdentifier
3854
+ ));
3855
+ //$extensions = &$tbsCertList['crlExtensions'];
3856
+ //if (isset($issuer->serialNumber)) {
3857
+ // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3858
+ //}
3859
+ //unset($extensions);
3860
+ }
3861
+
3862
+ $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);
3863
+
3864
+ if ($issuerAltName !== false) {
3865
+ $this->setExtension('id-ce-issuerAltName', $issuerAltName);
3866
+ }
3867
+ }
3868
+
3869
+ if (empty($tbsCertList['revokedCertificates'])) {
3870
+ unset($tbsCertList['revokedCertificates']);
3871
+ }
3872
+
3873
+ unset($tbsCertList);
3874
+
3875
+ // resync $this->signatureSubject
3876
+ // save $tbsCertList in case there are any File_ASN1_Element objects in it
3877
+ $tbsCertList = $this->currentCert['tbsCertList'];
3878
+ $this->loadCRL($this->saveCRL($this->currentCert));
3879
+
3880
+ $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3881
+ $result['tbsCertList'] = $tbsCertList;
3882
+
3883
+ $this->currentCert = $currentCert;
3884
+ $this->signatureSubject = $signatureSubject;
3885
+
3886
+ return $result;
3887
+ }
3888
+
3889
+ /**
3890
+ * X.509 certificate signing helper function.
3891
+ *
3892
+ * @param object $key
3893
+ * @param File_X509 $subject
3894
+ * @param string $signatureAlgorithm
3895
+ * @access public
3896
+ * @return mixed
3897
+ */
3898
+ function _sign($key, $signatureAlgorithm)
3899
+ {
3900
+ switch (strtolower(get_class($key))) {
3901
+ case 'crypt_rsa':
3902
+ switch ($signatureAlgorithm) {
3903
+ case 'md2WithRSAEncryption':
3904
+ case 'md5WithRSAEncryption':
3905
+ case 'sha1WithRSAEncryption':
3906
+ case 'sha224WithRSAEncryption':
3907
+ case 'sha256WithRSAEncryption':
3908
+ case 'sha384WithRSAEncryption':
3909
+ case 'sha512WithRSAEncryption':
3910
+ $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
3911
+ $key->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
3912
+
3913
+ $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
3914
+ return $this->currentCert;
3915
+ }
3916
+ default:
3917
+ return false;
3918
+ }
3919
+ }
3920
+
3921
+ /**
3922
+ * Set certificate start date
3923
+ *
3924
+ * @param string $date
3925
+ * @access public
3926
+ */
3927
+ function setStartDate($date)
3928
+ {
3929
+ if (class_exists('DateTime')) {
3930
+ $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
3931
+ $this->startDate = $date->format('D, d M Y H:i:s O');
3932
+ } else {
3933
+ $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
3934
+ }
3935
+ }
3936
+
3937
+ /**
3938
+ * Set certificate end date
3939
+ *
3940
+ * @param string $date
3941
+ * @access public
3942
+ */
3943
+ function setEndDate($date)
3944
+ {
3945
+ /*
3946
+ To indicate that a certificate has no well-defined expiration date,
3947
+ the notAfter SHOULD be assigned the GeneralizedTime value of
3948
+ 99991231235959Z.
3949
+
3950
+ -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
3951
+ */
3952
+ if (strtolower($date) == 'lifetime') {
3953
+ $temp = '99991231235959Z';
3954
+ $asn1 = new File_ASN1();
3955
+ $temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
3956
+ $this->endDate = new File_ASN1_Element($temp);
3957
+ } else {
3958
+ if (class_exists('DateTime')) {
3959
+ $date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
3960
+ $this->endDate = $date->format('D, d M Y H:i:s O');
3961
+ } else {
3962
+ $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
3963
+ }
3964
+ }
3965
+ }
3966
+
3967
+ /**
3968
+ * Set Serial Number
3969
+ *
3970
+ * @param string $serial
3971
+ * @param $base optional
3972
+ * @access public
3973
+ */
3974
+ function setSerialNumber($serial, $base = -256)
3975
+ {
3976
+ $this->serialNumber = new Math_BigInteger($serial, $base);
3977
+ }
3978
+
3979
+ /**
3980
+ * Turns the certificate into a certificate authority
3981
+ *
3982
+ * @access public
3983
+ */
3984
+ function makeCA()
3985
+ {
3986
+ $this->caFlag = true;
3987
+ }
3988
+
3989
+ /**
3990
+ * Check for validity of subarray
3991
+ *
3992
+ * This is intended for use in conjunction with _subArrayUnchecked(),
3993
+ * implementing the checks included in _subArray() but without copying
3994
+ * a potentially large array by passing its reference by-value to is_array().
3995
+ *
3996
+ * @param array $root
3997
+ * @param string $path
3998
+ * @return boolean
3999
+ * @access private
4000
+ */
4001
+ function _isSubArrayValid($root, $path)
4002
+ {
4003
+ if (!is_array($root)) {
4004
+ return false;
4005
+ }
4006
+
4007
+ foreach (explode('/', $path) as $i) {
4008
+ if (!is_array($root)) {
4009
+ return false;
4010
+ }
4011
+
4012
+ if (!isset($root[$i])) {
4013
+ return true;
4014
+ }
4015
+
4016
+ $root = $root[$i];
4017
+ }
4018
+
4019
+ return true;
4020
+ }
4021
+
4022
+ /**
4023
+ * Get a reference to a subarray
4024
+ *
4025
+ * This variant of _subArray() does no is_array() checking,
4026
+ * so $root should be checked with _isSubArrayValid() first.
4027
+ *
4028
+ * This is here for performance reasons:
4029
+ * Passing a reference (i.e. $root) by-value (i.e. to is_array())
4030
+ * creates a copy. If $root is an especially large array, this is expensive.
4031
+ *
4032
+ * @param array $root
4033
+ * @param string $path absolute path with / as component separator
4034
+ * @param bool $create optional
4035
+ * @access private
4036
+ * @return array|false
4037
+ */
4038
+ function &_subArrayUnchecked(&$root, $path, $create = false)
4039
+ {
4040
+ $false = false;
4041
+
4042
+ foreach (explode('/', $path) as $i) {
4043
+ if (!isset($root[$i])) {
4044
+ if (!$create) {
4045
+ return $false;
4046
+ }
4047
+
4048
+ $root[$i] = array();
4049
+ }
4050
+
4051
+ $root = &$root[$i];
4052
+ }
4053
+
4054
+ return $root;
4055
+ }
4056
+
4057
+ /**
4058
+ * Get a reference to a subarray
4059
+ *
4060
+ * @param array $root
4061
+ * @param string $path absolute path with / as component separator
4062
+ * @param bool $create optional
4063
+ * @access private
4064
+ * @return array|false
4065
+ */
4066
+ function &_subArray(&$root, $path, $create = false)
4067
+ {
4068
+ $false = false;
4069
+
4070
+ if (!is_array($root)) {
4071
+ return $false;
4072
+ }
4073
+
4074
+ foreach (explode('/', $path) as $i) {
4075
+ if (!is_array($root)) {
4076
+ return $false;
4077
+ }
4078
+
4079
+ if (!isset($root[$i])) {
4080
+ if (!$create) {
4081
+ return $false;
4082
+ }
4083
+
4084
+ $root[$i] = array();
4085
+ }
4086
+
4087
+ $root = &$root[$i];
4088
+ }
4089
+
4090
+ return $root;
4091
+ }
4092
+
4093
+ /**
4094
+ * Get a reference to an extension subarray
4095
+ *
4096
+ * @param array $root
4097
+ * @param string $path optional absolute path with / as component separator
4098
+ * @param bool $create optional
4099
+ * @access private
4100
+ * @return array|false
4101
+ */
4102
+ function &_extensions(&$root, $path = null, $create = false)
4103
+ {
4104
+ if (!isset($root)) {
4105
+ $root = $this->currentCert;
4106
+ }
4107
+
4108
+ switch (true) {
4109
+ case !empty($path):
4110
+ case !is_array($root):
4111
+ break;
4112
+ case isset($root['tbsCertificate']):
4113
+ $path = 'tbsCertificate/extensions';
4114
+ break;
4115
+ case isset($root['tbsCertList']):
4116
+ $path = 'tbsCertList/crlExtensions';
4117
+ break;
4118
+ case isset($root['certificationRequestInfo']):
4119
+ $pth = 'certificationRequestInfo/attributes';
4120
+ $attributes = &$this->_subArray($root, $pth, $create);
4121
+
4122
+ if (is_array($attributes)) {
4123
+ foreach ($attributes as $key => $value) {
4124
+ if ($value['type'] == 'pkcs-9-at-extensionRequest') {
4125
+ $path = "$pth/$key/value/0";
4126
+ break 2;
4127
+ }
4128
+ }
4129
+ if ($create) {
4130
+ $key = count($attributes);
4131
+ $attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
4132
+ $path = "$pth/$key/value/0";
4133
+ }
4134
+ }
4135
+ break;
4136
+ }
4137
+
4138
+ $extensions = &$this->_subArray($root, $path, $create);
4139
+
4140
+ if (!is_array($extensions)) {
4141
+ $false = false;
4142
+ return $false;
4143
+ }
4144
+
4145
+ return $extensions;
4146
+ }
4147
+
4148
+ /**
4149
+ * Remove an Extension
4150
+ *
4151
+ * @param string $id
4152
+ * @param string $path optional
4153
+ * @access private
4154
+ * @return bool
4155
+ */
4156
+ function _removeExtension($id, $path = null)
4157
+ {
4158
+ $extensions = &$this->_extensions($this->currentCert, $path);
4159
+
4160
+ if (!is_array($extensions)) {
4161
+ return false;
4162
+ }
4163
+
4164
+ $result = false;
4165
+ foreach ($extensions as $key => $value) {
4166
+ if ($value['extnId'] == $id) {
4167
+ unset($extensions[$key]);
4168
+ $result = true;
4169
+ }
4170
+ }
4171
+
4172
+ $extensions = array_values($extensions);
4173
+ // fix for https://bugs.php.net/75433 affecting PHP 7.2
4174
+ if (!isset($extensions[0])) {
4175
+ $extensions = array_splice($extensions, 0, 0);
4176
+ }
4177
+ return $result;
4178
+ }
4179
+
4180
+ /**
4181
+ * Get an Extension
4182
+ *
4183
+ * Returns the extension if it exists and false if not
4184
+ *
4185
+ * @param string $id
4186
+ * @param array $cert optional
4187
+ * @param string $path optional
4188
+ * @access private
4189
+ * @return mixed
4190
+ */
4191
+ function _getExtension($id, $cert = null, $path = null)
4192
+ {
4193
+ $extensions = $this->_extensions($cert, $path);
4194
+
4195
+ if (!is_array($extensions)) {
4196
+ return false;
4197
+ }
4198
+
4199
+ foreach ($extensions as $key => $value) {
4200
+ if ($value['extnId'] == $id) {
4201
+ return $value['extnValue'];
4202
+ }
4203
+ }
4204
+
4205
+ return false;
4206
+ }
4207
+
4208
+ /**
4209
+ * Returns a list of all extensions in use
4210
+ *
4211
+ * @param array $cert optional
4212
+ * @param string $path optional
4213
+ * @access private
4214
+ * @return array
4215
+ */
4216
+ function _getExtensions($cert = null, $path = null)
4217
+ {
4218
+ $exts = $this->_extensions($cert, $path);
4219
+ $extensions = array();
4220
+
4221
+ if (is_array($exts)) {
4222
+ foreach ($exts as $extension) {
4223
+ $extensions[] = $extension['extnId'];
4224
+ }
4225
+ }
4226
+
4227
+ return $extensions;
4228
+ }
4229
+
4230
+ /**
4231
+ * Set an Extension
4232
+ *
4233
+ * @param string $id
4234
+ * @param mixed $value
4235
+ * @param bool $critical optional
4236
+ * @param bool $replace optional
4237
+ * @param string $path optional
4238
+ * @access private
4239
+ * @return bool
4240
+ */
4241
+ function _setExtension($id, $value, $critical = false, $replace = true, $path = null)
4242
+ {
4243
+ $extensions = &$this->_extensions($this->currentCert, $path, true);
4244
+
4245
+ if (!is_array($extensions)) {
4246
+ return false;
4247
+ }
4248
+
4249
+ $newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);
4250
+
4251
+ foreach ($extensions as $key => $value) {
4252
+ if ($value['extnId'] == $id) {
4253
+ if (!$replace) {
4254
+ return false;
4255
+ }
4256
+
4257
+ $extensions[$key] = $newext;
4258
+ return true;
4259
+ }
4260
+ }
4261
+
4262
+ $extensions[] = $newext;
4263
+ return true;
4264
+ }
4265
+
4266
+ /**
4267
+ * Remove a certificate, CSR or CRL Extension
4268
+ *
4269
+ * @param string $id
4270
+ * @access public
4271
+ * @return bool
4272
+ */
4273
+ function removeExtension($id)
4274
+ {
4275
+ return $this->_removeExtension($id);
4276
+ }
4277
+
4278
+ /**
4279
+ * Get a certificate, CSR or CRL Extension
4280
+ *
4281
+ * Returns the extension if it exists and false if not
4282
+ *
4283
+ * @param string $id
4284
+ * @param array $cert optional
4285
+ * @access public
4286
+ * @return mixed
4287
+ */
4288
+ function getExtension($id, $cert = null)
4289
+ {
4290
+ return $this->_getExtension($id, $cert);
4291
+ }
4292
+
4293
+ /**
4294
+ * Returns a list of all extensions in use in certificate, CSR or CRL
4295
+ *
4296
+ * @param array $cert optional
4297
+ * @access public
4298
+ * @return array
4299
+ */
4300
+ function getExtensions($cert = null)
4301
+ {
4302
+ return $this->_getExtensions($cert);
4303
+ }
4304
+
4305
+ /**
4306
+ * Set a certificate, CSR or CRL Extension
4307
+ *
4308
+ * @param string $id
4309
+ * @param mixed $value
4310
+ * @param bool $critical optional
4311
+ * @param bool $replace optional
4312
+ * @access public
4313
+ * @return bool
4314
+ */
4315
+ function setExtension($id, $value, $critical = false, $replace = true)
4316
+ {
4317
+ return $this->_setExtension($id, $value, $critical, $replace);
4318
+ }
4319
+
4320
+ /**
4321
+ * Remove a CSR attribute.
4322
+ *
4323
+ * @param string $id
4324
+ * @param int $disposition optional
4325
+ * @access public
4326
+ * @return bool
4327
+ */
4328
+ function removeAttribute($id, $disposition = FILE_X509_ATTR_ALL)
4329
+ {
4330
+ $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');
4331
+
4332
+ if (!is_array($attributes)) {
4333
+ return false;
4334
+ }
4335
+
4336
+ $result = false;
4337
+ foreach ($attributes as $key => $attribute) {
4338
+ if ($attribute['type'] == $id) {
4339
+ $n = count($attribute['value']);
4340
+ switch (true) {
4341
+ case $disposition == FILE_X509_ATTR_APPEND:
4342
+ case $disposition == FILE_X509_ATTR_REPLACE:
4343
+ return false;
4344
+ case $disposition >= $n:
4345
+ $disposition -= $n;
4346
+ break;
4347
+ case $disposition == FILE_X509_ATTR_ALL:
4348
+ case $n == 1:
4349
+ unset($attributes[$key]);
4350
+ $result = true;
4351
+ break;
4352
+ default:
4353
+ unset($attributes[$key]['value'][$disposition]);
4354
+ $attributes[$key]['value'] = array_values($attributes[$key]['value']);
4355
+ $result = true;
4356
+ break;
4357
+ }
4358
+ if ($result && $disposition != FILE_X509_ATTR_ALL) {
4359
+ break;
4360
+ }
4361
+ }
4362
+ }
4363
+
4364
+ $attributes = array_values($attributes);
4365
+ return $result;
4366
+ }
4367
+
4368
+ /**
4369
+ * Get a CSR attribute
4370
+ *
4371
+ * Returns the attribute if it exists and false if not
4372
+ *
4373
+ * @param string $id
4374
+ * @param int $disposition optional
4375
+ * @param array $csr optional
4376
+ * @access public
4377
+ * @return mixed
4378
+ */
4379
+ function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = null)
4380
+ {
4381
+ if (empty($csr)) {
4382
+ $csr = $this->currentCert;
4383
+ }
4384
+
4385
+ $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4386
+
4387
+ if (!is_array($attributes)) {
4388
+ return false;
4389
+ }
4390
+
4391
+ foreach ($attributes as $key => $attribute) {
4392
+ if ($attribute['type'] == $id) {
4393
+ $n = count($attribute['value']);
4394
+ switch (true) {
4395
+ case $disposition == FILE_X509_ATTR_APPEND:
4396
+ case $disposition == FILE_X509_ATTR_REPLACE:
4397
+ return false;
4398
+ case $disposition == FILE_X509_ATTR_ALL:
4399
+ return $attribute['value'];
4400
+ case $disposition >= $n:
4401
+ $disposition -= $n;
4402
+ break;
4403
+ default:
4404
+ return $attribute['value'][$disposition];
4405
+ }
4406
+ }
4407
+ }
4408
+
4409
+ return false;
4410
+ }
4411
+
4412
+ /**
4413
+ * Returns a list of all CSR attributes in use
4414
+ *
4415
+ * @param array $csr optional
4416
+ * @access public
4417
+ * @return array
4418
+ */
4419
+ function getAttributes($csr = null)
4420
+ {
4421
+ if (empty($csr)) {
4422
+ $csr = $this->currentCert;
4423
+ }
4424
+
4425
+ $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4426
+ $attrs = array();
4427
+
4428
+ if (is_array($attributes)) {
4429
+ foreach ($attributes as $attribute) {
4430
+ $attrs[] = $attribute['type'];
4431
+ }
4432
+ }
4433
+
4434
+ return $attrs;
4435
+ }
4436
+
4437
+ /**
4438
+ * Set a CSR attribute
4439
+ *
4440
+ * @param string $id
4441
+ * @param mixed $value
4442
+ * @param bool $disposition optional
4443
+ * @access public
4444
+ * @return bool
4445
+ */
4446
+ function setAttribute($id, $value, $disposition = FILE_X509_ATTR_ALL)
4447
+ {
4448
+ $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);
4449
+
4450
+ if (!is_array($attributes)) {
4451
+ return false;
4452
+ }
4453
+
4454
+ switch ($disposition) {
4455
+ case FILE_X509_ATTR_REPLACE:
4456
+ $disposition = FILE_X509_ATTR_APPEND;
4457
+ case FILE_X509_ATTR_ALL:
4458
+ $this->removeAttribute($id);
4459
+ break;
4460
+ }
4461
+
4462
+ foreach ($attributes as $key => $attribute) {
4463
+ if ($attribute['type'] == $id) {
4464
+ $n = count($attribute['value']);
4465
+ switch (true) {
4466
+ case $disposition == FILE_X509_ATTR_APPEND:
4467
+ $last = $key;
4468
+ break;
4469
+ case $disposition >= $n:
4470
+ $disposition -= $n;
4471
+ break;
4472
+ default:
4473
+ $attributes[$key]['value'][$disposition] = $value;
4474
+ return true;
4475
+ }
4476
+ }
4477
+ }
4478
+
4479
+ switch (true) {
4480
+ case $disposition >= 0:
4481
+ return false;
4482
+ case isset($last):
4483
+ $attributes[$last]['value'][] = $value;
4484
+ break;
4485
+ default:
4486
+ $attributes[] = array('type' => $id, 'value' => $disposition == FILE_X509_ATTR_ALL ? $value: array($value));
4487
+ break;
4488
+ }
4489
+
4490
+ return true;
4491
+ }
4492
+
4493
+ /**
4494
+ * Sets the subject key identifier
4495
+ *
4496
+ * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions.
4497
+ *
4498
+ * @param string $value
4499
+ * @access public
4500
+ */
4501
+ function setKeyIdentifier($value)
4502
+ {
4503
+ if (empty($value)) {
4504
+ unset($this->currentKeyIdentifier);
4505
+ } else {
4506
+ $this->currentKeyIdentifier = base64_encode($value);
4507
+ }
4508
+ }
4509
+
4510
+ /**
4511
+ * Compute a public key identifier.
4512
+ *
4513
+ * Although key identifiers may be set to any unique value, this function
4514
+ * computes key identifiers from public key according to the two
4515
+ * recommended methods (4.2.1.2 RFC 3280).
4516
+ * Highly polymorphic: try to accept all possible forms of key:
4517
+ * - Key object
4518
+ * - File_X509 object with public or private key defined
4519
+ * - Certificate or CSR array
4520
+ * - File_ASN1_Element object
4521
+ * - PEM or DER string
4522
+ *
4523
+ * @param mixed $key optional
4524
+ * @param int $method optional
4525
+ * @access public
4526
+ * @return string binary key identifier
4527
+ */
4528
+ function computeKeyIdentifier($key = null, $method = 1)
4529
+ {
4530
+ if (is_null($key)) {
4531
+ $key = $this;
4532
+ }
4533
+
4534
+ switch (true) {
4535
+ case is_string($key):
4536
+ break;
4537
+ case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
4538
+ return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
4539
+ case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
4540
+ return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
4541
+ case !is_object($key):
4542
+ return false;
4543
+ case strtolower(get_class($key)) == 'file_asn1_element':
4544
+ // Assume the element is a bitstring-packed key.
4545
+ $asn1 = new File_ASN1();
4546
+ $decoded = $asn1->decodeBER($key->element);
4547
+ if (empty($decoded)) {
4548
+ return false;
4549
+ }
4550
+ $raw = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING));
4551
+ if (empty($raw)) {
4552
+ return false;
4553
+ }
4554
+ $raw = base64_decode($raw);
4555
+ // If the key is private, compute identifier from its corresponding public key.
4556
+ if (!class_exists('Crypt_RSA')) {
4557
+ include_once 'Crypt/RSA.php';
4558
+ }
4559
+ $key = new Crypt_RSA();
4560
+ if (!$key->loadKey($raw)) {
4561
+ return false; // Not an unencrypted RSA key.
4562
+ }
4563
+ if ($key->getPrivateKey() !== false) { // If private.
4564
+ return $this->computeKeyIdentifier($key, $method);
4565
+ }
4566
+ $key = $raw; // Is a public key.
4567
+ break;
4568
+ case strtolower(get_class($key)) == 'file_x509':
4569
+ if (isset($key->publicKey)) {
4570
+ return $this->computeKeyIdentifier($key->publicKey, $method);
4571
+ }
4572
+ if (isset($key->privateKey)) {
4573
+ return $this->computeKeyIdentifier($key->privateKey, $method);
4574
+ }
4575
+ if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
4576
+ return $this->computeKeyIdentifier($key->currentCert, $method);
4577
+ }
4578
+ return false;
4579
+ default: // Should be a key object (i.e.: Crypt_RSA).
4580
+ $key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
4581
+ break;
4582
+ }
4583
+
4584
+ // If in PEM format, convert to binary.
4585
+ $key = $this->_extractBER($key);
4586
+
4587
+ // Now we have the key string: compute its sha-1 sum.
4588
+ if (!class_exists('Crypt_Hash')) {
4589
+ include_once 'Crypt/Hash.php';
4590
+ }
4591
+ $hash = new Crypt_Hash('sha1');
4592
+ $hash = $hash->hash($key);
4593
+
4594
+ if ($method == 2) {
4595
+ $hash = substr($hash, -8);
4596
+ $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
4597
+ }
4598
+
4599
+ return $hash;
4600
+ }
4601
+
4602
+ /**
4603
+ * Format a public key as appropriate
4604
+ *
4605
+ * @access private
4606
+ * @return array
4607
+ */
4608
+ function _formatSubjectPublicKey()
4609
+ {
4610
+ if (!isset($this->publicKey) || !is_object($this->publicKey)) {
4611
+ return false;
4612
+ }
4613
+
4614
+ switch (strtolower(get_class($this->publicKey))) {
4615
+ case 'crypt_rsa':
4616
+ // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
4617
+ // the former is a good example of how to do fuzzing on the public key
4618
+ //return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
4619
+ return array(
4620
+ 'algorithm' => array('algorithm' => 'rsaEncryption'),
4621
+ 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
4622
+ );
4623
+ default:
4624
+ return false;
4625
+ }
4626
+ }
4627
+
4628
+ /**
4629
+ * Set the domain name's which the cert is to be valid for
4630
+ *
4631
+ * @access public
4632
+ * @return array
4633
+ */
4634
+ function setDomain()
4635
+ {
4636
+ $this->domains = func_get_args();
4637
+ $this->removeDNProp('id-at-commonName');
4638
+ $this->setDNProp('id-at-commonName', $this->domains[0]);
4639
+ }
4640
+
4641
+ /**
4642
+ * Set the IP Addresses's which the cert is to be valid for
4643
+ *
4644
+ * @access public
4645
+ * @param string $ipAddress optional
4646
+ */
4647
+ function setIPAddress()
4648
+ {
4649
+ $this->ipAddresses = func_get_args();
4650
+ /*
4651
+ if (!isset($this->domains)) {
4652
+ $this->removeDNProp('id-at-commonName');
4653
+ $this->setDNProp('id-at-commonName', $this->ipAddresses[0]);
4654
+ }
4655
+ */
4656
+ }
4657
+
4658
+ /**
4659
+ * Helper function to build domain array
4660
+ *
4661
+ * @access private
4662
+ * @param string $domain
4663
+ * @return array
4664
+ */
4665
+ function _dnsName($domain)
4666
+ {
4667
+ return array('dNSName' => $domain);
4668
+ }
4669
+
4670
+ /**
4671
+ * Helper function to build IP Address array
4672
+ *
4673
+ * (IPv6 is not currently supported)
4674
+ *
4675
+ * @access private
4676
+ * @param string $address
4677
+ * @return array
4678
+ */
4679
+ function _iPAddress($address)
4680
+ {
4681
+ return array('iPAddress' => $address);
4682
+ }
4683
+
4684
+ /**
4685
+ * Get the index of a revoked certificate.
4686
+ *
4687
+ * @param array $rclist
4688
+ * @param string $serial
4689
+ * @param bool $create optional
4690
+ * @access private
4691
+ * @return int|false
4692
+ */
4693
+ function _revokedCertificate(&$rclist, $serial, $create = false)
4694
+ {
4695
+ $serial = new Math_BigInteger($serial);
4696
+
4697
+ foreach ($rclist as $i => $rc) {
4698
+ if (!($serial->compare($rc['userCertificate']))) {
4699
+ return $i;
4700
+ }
4701
+ }
4702
+
4703
+ if (!$create) {
4704
+ return false;
4705
+ }
4706
+
4707
+ if (!class_exists('DateTime')) {
4708
+ $revocationDate = @date('D, d M Y H:i:s O');
4709
+ } else {
4710
+ $revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
4711
+ $revocationDate = $revocationDate->format('D, d M Y H:i:s O');
4712
+ }
4713
+
4714
+ $i = count($rclist);
4715
+ $rclist[] = array('userCertificate' => $serial,
4716
+ 'revocationDate' => $this->_timeField($revocationDate));
4717
+ return $i;
4718
+ }
4719
+
4720
+ /**
4721
+ * Revoke a certificate.
4722
+ *
4723
+ * @param string $serial
4724
+ * @param string $date optional
4725
+ * @access public
4726
+ * @return bool
4727
+ */
4728
+ function revoke($serial, $date = null)
4729
+ {
4730
+ if (isset($this->currentCert['tbsCertList'])) {
4731
+ if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4732
+ if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
4733
+ if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4734
+ if (!empty($date)) {
4735
+ $rclist[$i]['revocationDate'] = $this->_timeField($date);
4736
+ }
4737
+
4738
+ return true;
4739
+ }
4740
+ }
4741
+ }
4742
+ }
4743
+
4744
+ return false;
4745
+ }
4746
+
4747
+ /**
4748
+ * Unrevoke a certificate.
4749
+ *
4750
+ * @param string $serial
4751
+ * @access public
4752
+ * @return bool
4753
+ */
4754
+ function unrevoke($serial)
4755
+ {
4756
+ if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4757
+ if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4758
+ unset($rclist[$i]);
4759
+ $rclist = array_values($rclist);
4760
+ return true;
4761
+ }
4762
+ }
4763
+
4764
+ return false;
4765
+ }
4766
+
4767
+ /**
4768
+ * Get a revoked certificate.
4769
+ *
4770
+ * @param string $serial
4771
+ * @access public
4772
+ * @return mixed
4773
+ */
4774
+ function getRevoked($serial)
4775
+ {
4776
+ if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4777
+ if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4778
+ return $rclist[$i];
4779
+ }
4780
+ }
4781
+
4782
+ return false;
4783
+ }
4784
+
4785
+ /**
4786
+ * List revoked certificates
4787
+ *
4788
+ * @param array $crl optional
4789
+ * @access public
4790
+ * @return array
4791
+ */
4792
+ function listRevoked($crl = null)
4793
+ {
4794
+ if (!isset($crl)) {
4795
+ $crl = $this->currentCert;
4796
+ }
4797
+
4798
+ if (!isset($crl['tbsCertList'])) {
4799
+ return false;
4800
+ }
4801
+
4802
+ $result = array();
4803
+
4804
+ if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4805
+ foreach ($rclist as $rc) {
4806
+ $result[] = $rc['userCertificate']->toString();
4807
+ }
4808
+ }
4809
+
4810
+ return $result;
4811
+ }
4812
+
4813
+ /**
4814
+ * Remove a Revoked Certificate Extension
4815
+ *
4816
+ * @param string $serial
4817
+ * @param string $id
4818
+ * @access public
4819
+ * @return bool
4820
+ */
4821
+ function removeRevokedCertificateExtension($serial, $id)
4822
+ {
4823
+ if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4824
+ if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4825
+ return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4826
+ }
4827
+ }
4828
+
4829
+ return false;
4830
+ }
4831
+
4832
+ /**
4833
+ * Get a Revoked Certificate Extension
4834
+ *
4835
+ * Returns the extension if it exists and false if not
4836
+ *
4837
+ * @param string $serial
4838
+ * @param string $id
4839
+ * @param array $crl optional
4840
+ * @access public
4841
+ * @return mixed
4842
+ */
4843
+ function getRevokedCertificateExtension($serial, $id, $crl = null)
4844
+ {
4845
+ if (!isset($crl)) {
4846
+ $crl = $this->currentCert;
4847
+ }
4848
+
4849
+ if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4850
+ if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4851
+ return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4852
+ }
4853
+ }
4854
+
4855
+ return false;
4856
+ }
4857
+
4858
+ /**
4859
+ * Returns a list of all extensions in use for a given revoked certificate
4860
+ *
4861
+ * @param string $serial
4862
+ * @param array $crl optional
4863
+ * @access public
4864
+ * @return array
4865
+ */
4866
+ function getRevokedCertificateExtensions($serial, $crl = null)
4867
+ {
4868
+ if (!isset($crl)) {
4869
+ $crl = $this->currentCert;
4870
+ }
4871
+
4872
+ if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4873
+ if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4874
+ return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4875
+ }
4876
+ }
4877
+
4878
+ return false;
4879
+ }
4880
+
4881
+ /**
4882
+ * Set a Revoked Certificate Extension
4883
+ *
4884
+ * @param string $serial
4885
+ * @param string $id
4886
+ * @param mixed $value
4887
+ * @param bool $critical optional
4888
+ * @param bool $replace optional
4889
+ * @access public
4890
+ * @return bool
4891
+ */
4892
+ function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
4893
+ {
4894
+ if (isset($this->currentCert['tbsCertList'])) {
4895
+ if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4896
+ if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4897
+ return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4898
+ }
4899
+ }
4900
+ }
4901
+
4902
+ return false;
4903
+ }
4904
+
4905
+ /**
4906
+ * Extract raw BER from Base64 encoding
4907
+ *
4908
+ * @access private
4909
+ * @param string $str
4910
+ * @return string
4911
+ */
4912
+ function _extractBER($str)
4913
+ {
4914
+ /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
4915
+ * above and beyond the ceritificate.
4916
+ * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
4917
+ *
4918
+ * Bag Attributes
4919
+ * localKeyID: 01 00 00 00
4920
+ * subject=/O=organization/OU=org unit/CN=common name
4921
+ * issuer=/O=organization/CN=common name
4922
+ */
4923
+ $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
4924
+ // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
4925
+ $temp = preg_replace('#-+[^-]+-+#', '', $temp);
4926
+ // remove new lines
4927
+ $temp = str_replace(array("\r", "\n", ' '), '', $temp);
4928
+ $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
4929
+ return $temp != false ? $temp : $str;
4930
+ }
4931
+
4932
+ /**
4933
+ * Returns the OID corresponding to a name
4934
+ *
4935
+ * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if
4936
+ * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version
4937
+ * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able
4938
+ * to work from version to version.
4939
+ *
4940
+ * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that
4941
+ * what's being passed to it already is an OID and return that instead. A few examples.
4942
+ *
4943
+ * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1'
4944
+ * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1'
4945
+ * getOID('zzz') == 'zzz'
4946
+ *
4947
+ * @access public
4948
+ * @return string
4949
+ */
4950
+ function getOID($name)
4951
+ {
4952
+ static $reverseMap;
4953
+ if (!isset($reverseMap)) {
4954
+ $reverseMap = array_flip($this->oids);
4955
+ }
4956
+ return isset($reverseMap[$name]) ? $reverseMap[$name] : $name;
4957
+ }
4958
+ }
phpseclib/Math/BigInteger.php CHANGED
@@ -2905,7 +2905,7 @@ class Math_BigInteger
2905
  switch (MATH_BIGINTEGER_MODE) {
2906
  case MATH_BIGINTEGER_MODE_GMP:
2907
  $temp = new Math_BigInteger();
2908
- $temp->value = gmp_xor($this->value, $x->value);
2909
 
2910
  return $this->_normalize($temp);
2911
  case MATH_BIGINTEGER_MODE_BCMATH:
@@ -2922,6 +2922,7 @@ class Math_BigInteger
2922
 
2923
  $length = max(count($this->value), count($x->value));
2924
  $result = $this->copy();
 
2925
  $result->value = array_pad($result->value, $length, 0);
2926
  $x->value = array_pad($x->value, $length, 0);
2927
 
2905
  switch (MATH_BIGINTEGER_MODE) {
2906
  case MATH_BIGINTEGER_MODE_GMP:
2907
  $temp = new Math_BigInteger();
2908
+ $temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
2909
 
2910
  return $this->_normalize($temp);
2911
  case MATH_BIGINTEGER_MODE_BCMATH:
2922
 
2923
  $length = max(count($this->value), count($x->value));
2924
  $result = $this->copy();
2925
+ $result->is_negative = false;
2926
  $result->value = array_pad($result->value, $length, 0);
2927
  $x->value = array_pad($x->value, $length, 0);
2928
 
phpseclib/Net/SCP.php ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of SCP.
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
9
+ *
10
+ * Here's a short example of how to use this library:
11
+ * <code>
12
+ * <?php
13
+ * include 'Net/SCP.php';
14
+ * include 'Net/SSH2.php';
15
+ *
16
+ * $ssh = new Net_SSH2('www.domain.tld');
17
+ * if (!$ssh->login('username', 'password')) {
18
+ * exit('bad login');
19
+ * }
20
+ *
21
+ * $scp = new Net_SCP($ssh);
22
+ * $scp->put('abcd', str_repeat('x', 1024*1024));
23
+ * ?>
24
+ * </code>
25
+ *
26
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
27
+ * of this software and associated documentation files (the "Software"), to deal
28
+ * in the Software without restriction, including without limitation the rights
29
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30
+ * copies of the Software, and to permit persons to whom the Software is
31
+ * furnished to do so, subject to the following conditions:
32
+ *
33
+ * The above copyright notice and this permission notice shall be included in
34
+ * all copies or substantial portions of the Software.
35
+ *
36
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42
+ * THE SOFTWARE.
43
+ *
44
+ * @category Net
45
+ * @package Net_SCP
46
+ * @author Jim Wigginton <terrafrost@php.net>
47
+ * @copyright 2010 Jim Wigginton
48
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
49
+ * @link http://phpseclib.sourceforge.net
50
+ */
51
+
52
+ /**#@+
53
+ * @access public
54
+ * @see self::put()
55
+ */
56
+ /**
57
+ * Reads data from a local file.
58
+ */
59
+ define('NET_SCP_LOCAL_FILE', 1);
60
+ /**
61
+ * Reads data from a string.
62
+ */
63
+ define('NET_SCP_STRING', 2);
64
+ /**#@-*/
65
+
66
+ /**#@+
67
+ * @access private
68
+ * @see self::_send()
69
+ * @see self::_receive()
70
+ */
71
+ /**
72
+ * SSH1 is being used.
73
+ */
74
+ define('NET_SCP_SSH1', 1);
75
+ /**
76
+ * SSH2 is being used.
77
+ */
78
+ define('NET_SCP_SSH2', 2);
79
+ /**#@-*/
80
+
81
+ /**
82
+ * Pure-PHP implementations of SCP.
83
+ *
84
+ * @package Net_SCP
85
+ * @author Jim Wigginton <terrafrost@php.net>
86
+ * @access public
87
+ */
88
+ class Net_SCP
89
+ {
90
+ /**
91
+ * SSH Object
92
+ *
93
+ * @var object
94
+ * @access private
95
+ */
96
+ var $ssh;
97
+
98
+ /**
99
+ * Packet Size
100
+ *
101
+ * @var int
102
+ * @access private
103
+ */
104
+ var $packet_size;
105
+
106
+ /**
107
+ * Mode
108
+ *
109
+ * @var int
110
+ * @access private
111
+ */
112
+ var $mode;
113
+
114
+ /**
115
+ * Default Constructor.
116
+ *
117
+ * Connects to an SSH server
118
+ *
119
+ * @param Net_SSH1|Net_SSH2 $ssh
120
+ * @return Net_SCP
121
+ * @access public
122
+ */
123
+ function __construct($ssh)
124
+ {
125
+ if (!is_object($ssh)) {
126
+ return;
127
+ }
128
+
129
+ switch (strtolower(get_class($ssh))) {
130
+ case 'net_ssh2':
131
+ $this->mode = NET_SCP_SSH2;
132
+ break;
133
+ case 'net_ssh1':
134
+ $this->packet_size = 50000;
135
+ $this->mode = NET_SCP_SSH1;
136
+ break;
137
+ default:
138
+ return;
139
+ }
140
+
141
+ $this->ssh = $ssh;
142
+ }
143
+
144
+ /**
145
+ * PHP4 compatible Default Constructor.
146
+ *
147
+ * @see self::__construct()
148
+ * @param Net_SSH1|Net_SSH2 $ssh
149
+ * @access public
150
+ */
151
+ function Net_SCP($ssh)
152
+ {
153
+ $this->__construct($ssh);
154
+ }
155
+
156
+ /**
157
+ * Uploads a file to the SCP server.
158
+ *
159
+ * By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
160
+ * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes
161
+ * long, containing 'filename.ext' as its contents.
162
+ *
163
+ * Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will
164
+ * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
165
+ * large $remote_file will be, as well.
166
+ *
167
+ * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
168
+ * care of that, yourself.
169
+ *
170
+ * @param string $remote_file
171
+ * @param string $data
172
+ * @param int $mode
173
+ * @param callable $callback
174
+ * @return bool
175
+ * @access public
176
+ */
177
+ function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null)
178
+ {
179
+ if (!isset($this->ssh)) {
180
+ return false;
181
+ }
182
+
183
+ if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
184
+ return false;
185
+ }
186
+
187
+ $temp = $this->_receive();
188
+ if ($temp !== chr(0)) {
189
+ return false;
190
+ }
191
+
192
+ if ($this->mode == NET_SCP_SSH2) {
193
+ $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4;
194
+ }
195
+
196
+ $remote_file = basename($remote_file);
197
+
198
+ if ($mode == NET_SCP_STRING) {
199
+ $size = strlen($data);
200
+ } else {
201
+ if (!is_file($data)) {
202
+ user_error("$data is not a valid file", E_USER_NOTICE);
203
+ return false;
204
+ }
205
+
206
+ $fp = @fopen($data, 'rb');
207
+ if (!$fp) {
208
+ return false;
209
+ }
210
+ $size = filesize($data);
211
+ }
212
+
213
+ $this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");
214
+
215
+ $temp = $this->_receive();
216
+ if ($temp !== chr(0)) {
217
+ return false;
218
+ }
219
+
220
+ $sent = 0;
221
+ while ($sent < $size) {
222
+ $temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size);
223
+ $this->_send($temp);
224
+ $sent+= strlen($temp);
225
+
226
+ if (is_callable($callback)) {
227
+ call_user_func($callback, $sent);
228
+ }
229
+ }
230
+ $this->_close();
231
+
232
+ if ($mode != NET_SCP_STRING) {
233
+ fclose($fp);
234
+ }
235
+
236
+ return true;
237
+ }
238
+
239
+ /**
240
+ * Downloads a file from the SCP server.
241
+ *
242
+ * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
243
+ * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
244
+ * operation
245
+ *
246
+ * @param string $remote_file
247
+ * @param string $local_file
248
+ * @return mixed
249
+ * @access public
250
+ */
251
+ function get($remote_file, $local_file = false)
252
+ {
253
+ if (!isset($this->ssh)) {
254
+ return false;
255
+ }
256
+
257
+ if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
258
+ return false;
259
+ }
260
+
261
+ $this->_send("\0");
262
+
263
+ if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) {
264
+ return false;
265
+ }
266
+
267
+ $this->_send("\0");
268
+
269
+ $size = 0;
270
+
271
+ if ($local_file !== false) {
272
+ $fp = @fopen($local_file, 'wb');
273
+ if (!$fp) {
274
+ return false;
275
+ }
276
+ }
277
+
278
+ $content = '';
279
+ while ($size < $info['size']) {
280
+ $data = $this->_receive();
281
+ // SCP usually seems to split stuff out into 16k chunks
282
+ $size+= strlen($data);
283
+
284
+ if ($local_file === false) {
285
+ $content.= $data;
286
+ } else {
287
+ fputs($fp, $data);
288
+ }
289
+ }
290
+
291
+ $this->_close();
292
+
293
+ if ($local_file !== false) {
294
+ fclose($fp);
295
+ return true;
296
+ }
297
+
298
+ return $content;
299
+ }
300
+
301
+ /**
302
+ * Sends a packet to an SSH server
303
+ *
304
+ * @param string $data
305
+ * @access private
306
+ */
307
+ function _send($data)
308
+ {
309
+ switch ($this->mode) {
310
+ case NET_SCP_SSH2:
311
+ $this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data);
312
+ break;
313
+ case NET_SCP_SSH1:
314
+ $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
315
+ $this->ssh->_send_binary_packet($data);
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Receives a packet from an SSH server
321
+ *
322
+ * @return string
323
+ * @access private
324
+ */
325
+ function _receive()
326
+ {
327
+ switch ($this->mode) {
328
+ case NET_SCP_SSH2:
329
+ return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true);
330
+ case NET_SCP_SSH1:
331
+ if (!$this->ssh->bitmap) {
332
+ return false;
333
+ }
334
+ while (true) {
335
+ $response = $this->ssh->_get_binary_packet();
336
+ switch ($response[NET_SSH1_RESPONSE_TYPE]) {
337
+ case NET_SSH1_SMSG_STDOUT_DATA:
338
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
339
+ return false;
340
+ }
341
+ extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA]));
342
+ return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length);
343
+ case NET_SSH1_SMSG_STDERR_DATA:
344
+ break;
345
+ case NET_SSH1_SMSG_EXITSTATUS:
346
+ $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
347
+ fclose($this->ssh->fsock);
348
+ $this->ssh->bitmap = 0;
349
+ return false;
350
+ default:
351
+ user_error('Unknown packet received', E_USER_NOTICE);
352
+ return false;
353
+ }
354
+ }
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Closes the connection to an SSH server
360
+ *
361
+ * @access private
362
+ */
363
+ function _close()
364
+ {
365
+ switch ($this->mode) {
366
+ case NET_SCP_SSH2:
367
+ $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true);
368
+ break;
369
+ case NET_SCP_SSH1:
370
+ $this->ssh->disconnect();
371
+ }
372
+ }
373
+ }
phpseclib/Net/SFTP.php CHANGED
@@ -390,7 +390,7 @@ class Net_SFTP extends Net_SSH2
390
  // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
391
  // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
392
  // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
393
- -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
394
  );
395
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
396
  // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
@@ -1202,7 +1202,7 @@ class Net_SFTP extends Net_SSH2
1202
  $temp[$dir] = array();
1203
  }
1204
  if ($i === $max) {
1205
- if (is_object($temp[$dir])) {
1206
  if (!isset($value->stat) && isset($temp[$dir]->stat)) {
1207
  $value->stat = $temp[$dir]->stat;
1208
  }
390
  // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
391
  // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
392
  // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
393
+ (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
394
  );
395
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
396
  // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
1202
  $temp[$dir] = array();
1203
  }
1204
  if ($i === $max) {
1205
+ if (is_object($temp[$dir]) && is_object($value)) {
1206
  if (!isset($value->stat) && isset($temp[$dir]->stat)) {
1207
  $value->stat = $temp[$dir]->stat;
1208
  }
phpseclib/Net/SFTP/Stream.php ADDED
@@ -0,0 +1,815 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * SFTP Stream Wrapper
5
+ *
6
+ * Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc.
7
+ *
8
+ * PHP version 5
9
+ *
10
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ * of this software and associated documentation files (the "Software"), to deal
12
+ * in the Software without restriction, including without limitation the rights
13
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ * copies of the Software, and to permit persons to whom the Software is
15
+ * furnished to do so, subject to the following conditions:
16
+ *
17
+ * The above copyright notice and this permission notice shall be included in
18
+ * all copies or substantial portions of the Software.
19
+ *
20
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
+ * THE SOFTWARE.
27
+ *
28
+ * @category Net
29
+ * @package Net_SFTP_Stream
30
+ * @author Jim Wigginton <terrafrost@php.net>
31
+ * @copyright 2013 Jim Wigginton
32
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
33
+ * @link http://phpseclib.sourceforge.net
34
+ */
35
+
36
+ /**
37
+ * SFTP Stream Wrapper
38
+ *
39
+ * @package Net_SFTP_Stream
40
+ * @author Jim Wigginton <terrafrost@php.net>
41
+ * @access public
42
+ */
43
+ class Net_SFTP_Stream
44
+ {
45
+ /**
46
+ * SFTP instances
47
+ *
48
+ * Rather than re-create the connection we re-use instances if possible
49
+ *
50
+ * @var array
51
+ */
52
+ static $instances;
53
+
54
+ /**
55
+ * SFTP instance
56
+ *
57
+ * @var object
58
+ * @access private
59
+ */
60
+ var $sftp;
61
+
62
+ /**
63
+ * Path
64
+ *
65
+ * @var string
66
+ * @access private
67
+ */
68
+ var $path;
69
+
70
+ /**
71
+ * Mode
72
+ *
73
+ * @var string
74
+ * @access private
75
+ */
76
+ var $mode;
77
+
78
+ /**
79
+ * Position
80
+ *
81
+ * @var int
82
+ * @access private
83
+ */
84
+ var $pos;
85
+
86
+ /**
87
+ * Size
88
+ *
89
+ * @var int
90
+ * @access private
91
+ */
92
+ var $size;
93
+
94
+ /**
95
+ * Directory entries
96
+ *
97
+ * @var array
98
+ * @access private
99
+ */
100
+ var $entries;
101
+
102
+ /**
103
+ * EOF flag
104
+ *
105
+ * @var bool
106
+ * @access private
107
+ */
108
+ var $eof;
109
+
110
+ /**
111
+ * Context resource
112
+ *
113
+ * Technically this needs to be publically accessible so PHP can set it directly
114
+ *
115
+ * @var resource
116
+ * @access public
117
+ */
118
+ var $context;
119
+
120
+ /**
121
+ * Notification callback function
122
+ *
123
+ * @var callable
124
+ * @access public
125
+ */
126
+ var $notification;
127
+
128
+ /**
129
+ * Registers this class as a URL wrapper.
130
+ *
131
+ * @param string $protocol The wrapper name to be registered.
132
+ * @return bool True on success, false otherwise.
133
+ * @access public
134
+ */
135
+ static function register($protocol = 'sftp')
136
+ {
137
+ if (in_array($protocol, stream_get_wrappers(), true)) {
138
+ return false;
139
+ }
140
+ $class = function_exists('get_called_class') ? get_called_class() : __CLASS__;
141
+ return stream_wrapper_register($protocol, $class);
142
+ }
143
+
144
+ /**
145
+ * The Constructor
146
+ *
147
+ * @access public
148
+ */
149
+ function __construct()
150
+ {
151
+ if (defined('NET_SFTP_STREAM_LOGGING')) {
152
+ echo "__construct()\r\n";
153
+ }
154
+
155
+ if (!class_exists('Net_SFTP')) {
156
+ include_once 'Net/SFTP.php';
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Path Parser
162
+ *
163
+ * Extract a path from a URI and actually connect to an SSH server if appropriate
164
+ *
165
+ * If "notification" is set as a context parameter the message code for successful login is
166
+ * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
167
+ *
168
+ * @param string $path
169
+ * @return string
170
+ * @access private
171
+ */
172
+ function _parse_path($path)
173
+ {
174
+ $orig = $path;
175
+ extract(parse_url($path) + array('port' => 22));
176
+ if (isset($query)) {
177
+ $path.= '?' . $query;
178
+ } elseif (preg_match('/(\?|\?#)$/', $orig)) {
179
+ $path.= '?';
180
+ }
181
+ if (isset($fragment)) {
182
+ $path.= '#' . $fragment;
183
+ } elseif ($orig[strlen($orig) - 1] == '#') {
184
+ $path.= '#';
185
+ }
186
+
187
+ if (!isset($host)) {
188
+ return false;
189
+ }
190
+
191
+ if (isset($this->context)) {
192
+ $context = stream_context_get_params($this->context);
193
+ if (isset($context['notification'])) {
194
+ $this->notification = $context['notification'];
195
+ }
196
+ }
197
+
198
+ if ($host[0] == '$') {
199
+ $host = substr($host, 1);
200
+ global ${$host};
201
+ if (!is_object($$host) || get_class($$host) != 'Net_SFTP') {
202
+ return false;
203
+ }
204
+ $this->sftp = $$host;
205
+ } else {
206
+ if (isset($this->context)) {
207
+ $context = stream_context_get_options($this->context);
208
+ }
209
+ if (isset($context[$scheme]['session'])) {
210
+ $sftp = $context[$scheme]['session'];
211
+ }
212
+ if (isset($context[$scheme]['sftp'])) {
213
+ $sftp = $context[$scheme]['sftp'];
214
+ }
215
+ if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') {
216
+ $this->sftp = $sftp;
217
+ return $path;
218
+ }
219
+ if (isset($context[$scheme]['username'])) {
220
+ $user = $context[$scheme]['username'];
221
+ }
222
+ if (isset($context[$scheme]['password'])) {
223
+ $pass = $context[$scheme]['password'];
224
+ }
225
+ if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') {
226
+ $pass = $context[$scheme]['privkey'];
227
+ }
228
+
229
+ if (!isset($user) || !isset($pass)) {
230
+ return false;
231
+ }
232
+
233
+ // casting $pass to a string is necessary in the event that it's a Crypt_RSA object
234
+ if (isset(self::$instances[$host][$port][$user][(string) $pass])) {
235
+ $this->sftp = self::$instances[$host][$port][$user][(string) $pass];
236
+ } else {
237
+ $this->sftp = new Net_SFTP($host, $port);
238
+ $this->sftp->disableStatCache();
239
+ if (isset($this->notification) && is_callable($this->notification)) {
240
+ /* if !is_callable($this->notification) we could do this:
241
+
242
+ user_error('fopen(): failed to call user notifier', E_USER_WARNING);
243
+
244
+ the ftp wrapper gives errors like that when the notifier isn't callable.
245
+ i've opted not to do that, however, since the ftp wrapper gives the line
246
+ on which the fopen occurred as the line number - not the line that the
247
+ user_error is on.
248
+ */
249
+ call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
250
+ call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
251
+ if (!$this->sftp->login($user, $pass)) {
252
+ call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
253
+ return false;
254
+ }
255
+ call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
256
+ } else {
257
+ if (!$this->sftp->login($user, $pass)) {
258
+ return false;
259
+ }
260
+ }
261
+ self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
262
+ }
263
+ }
264
+
265
+ return $path;
266
+ }
267
+
268
+ /**
269
+ * Opens file or URL
270
+ *
271
+ * @param string $path
272
+ * @param string $mode
273
+ * @param int $options
274
+ * @param string $opened_path
275
+ * @return bool
276
+ * @access public
277
+ */
278
+ function _stream_open($path, $mode, $options, &$opened_path)
279
+ {
280
+ $path = $this->_parse_path($path);
281
+
282
+ if ($path === false) {
283
+ return false;
284
+ }
285
+ $this->path = $path;
286
+
287
+ $this->size = $this->sftp->size($path);
288
+ $this->mode = preg_replace('#[bt]$#', '', $mode);
289
+ $this->eof = false;
290
+
291
+ if ($this->size === false) {
292
+ if ($this->mode[0] == 'r') {
293
+ return false;
294
+ } else {
295
+ $this->sftp->touch($path);
296
+ $this->size = 0;
297
+ }
298
+ } else {
299
+ switch ($this->mode[0]) {
300
+ case 'x':
301
+ return false;
302
+ case 'w':
303
+ $this->sftp->truncate($path, 0);
304
+ $this->size = 0;
305
+ }
306
+ }
307
+
308
+ $this->pos = $this->mode[0] != 'a' ? 0 : $this->size;
309
+
310
+ return true;
311
+ }
312
+
313
+ /**
314
+ * Read from stream
315
+ *
316
+ * @param int $count
317
+ * @return mixed
318
+ * @access public
319
+ */
320
+ function _stream_read($count)
321
+ {
322
+ switch ($this->mode) {
323
+ case 'w':
324
+ case 'a':
325
+ case 'x':
326
+ case 'c':
327
+ return false;
328
+ }
329
+
330
+ // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite
331
+ //if ($this->pos >= $this->size) {
332
+ // $this->eof = true;
333
+ // return false;
334
+ //}
335
+
336
+ $result = $this->sftp->get($this->path, false, $this->pos, $count);
337
+ if (isset($this->notification) && is_callable($this->notification)) {
338
+ if ($result === false) {
339
+ call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
340
+ return 0;
341
+ }
342
+ // seems that PHP calls stream_read in 8k chunks
343
+ call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size);
344
+ }
345
+
346
+ if (empty($result)) { // ie. false or empty string
347
+ $this->eof = true;
348
+ return false;
349
+ }
350
+ $this->pos+= strlen($result);
351
+
352
+ return $result;
353
+ }
354
+
355
+ /**
356
+ * Write to stream
357
+ *
358
+ * @param string $data
359
+ * @return mixed
360
+ * @access public
361
+ */
362
+ function _stream_write($data)
363
+ {
364
+ switch ($this->mode) {
365
+ case 'r':
366
+ return false;
367
+ }
368
+
369
+ $result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos);
370
+ if (isset($this->notification) && is_callable($this->notification)) {
371
+ if (!$result) {
372
+ call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
373
+ return 0;
374
+ }
375
+ // seems that PHP splits up strings into 8k blocks before calling stream_write
376
+ call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
377
+ }
378
+
379
+ if ($result === false) {
380
+ return false;
381
+ }
382
+ $this->pos+= strlen($data);
383
+ if ($this->pos > $this->size) {
384
+ $this->size = $this->pos;
385
+ }
386
+ $this->eof = false;
387
+ return strlen($data);
388
+ }
389
+
390
+ /**
391
+ * Retrieve the current position of a stream
392
+ *
393
+ * @return int
394
+ * @access public
395
+ */
396
+ function _stream_tell()
397
+ {
398
+ return $this->pos;
399
+ }
400
+
401
+ /**
402
+ * Tests for end-of-file on a file pointer
403
+ *
404
+ * In my testing there are four classes functions that normally effect the pointer:
405
+ * fseek, fputs / fwrite, fgets / fread and ftruncate.
406
+ *
407
+ * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof()
408
+ * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof()
409
+ * will return false. do fread($fp, 1) and feof() will then return true.
410
+ *
411
+ * @return bool
412
+ * @access public
413
+ */
414
+ function _stream_eof()
415
+ {
416
+ return $this->eof;
417
+ }
418
+
419
+ /**
420
+ * Seeks to specific location in a stream
421
+ *
422
+ * @param int $offset
423
+ * @param int $whence
424
+ * @return bool
425
+ * @access public
426
+ */
427
+ function _stream_seek($offset, $whence)
428
+ {
429
+ switch ($whence) {
430
+ case SEEK_SET:
431
+ if ($offset >= $this->size || $offset < 0) {
432
+ return false;
433
+ }
434
+ break;
435
+ case SEEK_CUR:
436
+ $offset+= $this->pos;
437
+ break;
438
+ case SEEK_END:
439
+ $offset+= $this->size;
440
+ }
441
+
442
+ $this->pos = $offset;
443
+ $this->eof = false;
444
+ return true;
445
+ }
446
+
447
+ /**
448
+ * Change stream options
449
+ *
450
+ * @param string $path
451
+ * @param int $option
452
+ * @param mixed $var
453
+ * @return bool
454
+ * @access public
455
+ */
456
+ function _stream_metadata($path, $option, $var)
457
+ {
458
+ $path = $this->_parse_path($path);
459
+ if ($path === false) {
460
+ return false;
461
+ }
462
+
463
+ // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined
464
+ // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246
465
+ // and https://github.com/php/php-src/blob/master/main/php_streams.h#L592
466
+ switch ($option) {
467
+ case 1: // PHP_STREAM_META_TOUCH
468
+ return $this->sftp->touch($path, $var[0], $var[1]);
469
+ case 2: // PHP_STREAM_OWNER_NAME
470
+ case 3: // PHP_STREAM_GROUP_NAME
471
+ return false;
472
+ case 4: // PHP_STREAM_META_OWNER
473
+ return $this->sftp->chown($path, $var);
474
+ case 5: // PHP_STREAM_META_GROUP
475
+ return $this->sftp->chgrp($path, $var);
476
+ case 6: // PHP_STREAM_META_ACCESS
477
+ return $this->sftp->chmod($path, $var) !== false;
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Retrieve the underlaying resource
483
+ *
484
+ * @param int $cast_as
485
+ * @return resource
486
+ * @access public
487
+ */
488
+ function _stream_cast($cast_as)
489
+ {
490
+ return $this->sftp->fsock;
491
+ }
492
+
493
+ /**
494
+ * Advisory file locking
495
+ *
496
+ * @param int $operation
497
+ * @return bool
498
+ * @access public
499
+ */
500
+ function _stream_lock($operation)
501
+ {
502
+ return false;
503
+ }
504
+
505
+ /**
506
+ * Renames a file or directory
507
+ *
508
+ * Attempts to rename oldname to newname, moving it between directories if necessary.
509
+ * If newname exists, it will be overwritten. This is a departure from what Net_SFTP
510
+ * does.
511
+ *
512
+ * @param string $path_from
513
+ * @param string $path_to
514
+ * @return bool
515
+ * @access public
516
+ */
517
+ function _rename($path_from, $path_to)
518
+ {
519
+ $path1 = parse_url($path_from);
520
+ $path2 = parse_url($path_to);
521
+ unset($path1['path'], $path2['path']);
522
+ if ($path1 != $path2) {
523
+ return false;
524
+ }
525
+
526
+ $path_from = $this->_parse_path($path_from);
527
+ $path_to = parse_url($path_to);
528
+ if ($path_from === false) {
529
+ return false;
530
+ }
531
+
532
+ $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2
533
+ // "It is an error if there already exists a file with the name specified by newpath."
534
+ // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5
535
+ if (!$this->sftp->rename($path_from, $path_to)) {
536
+ if ($this->sftp->stat($path_to)) {
537
+ return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to);
538
+ }
539
+ return false;
540
+ }
541
+
542
+ return true;
543
+ }
544
+
545
+ /**
546
+ * Open directory handle
547
+ *
548
+ * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and
549
+ * removed in 5.4 I'm just going to ignore it.
550
+ *
551
+ * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client
552
+ * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting
553
+ * the SFTP specs:
554
+ *
555
+ * The SSH_FXP_NAME response has the following format:
556
+ *
557
+ * uint32 id
558
+ * uint32 count
559
+ * repeats count times:
560
+ * string filename
561
+ * string longname
562
+ * ATTRS attrs
563
+ *
564
+ * @param string $path
565
+ * @param int $options
566
+ * @return bool
567
+ * @access public
568
+ */
569
+ function _dir_opendir($path, $options)
570
+ {
571
+ $path = $this->_parse_path($path);
572
+ if ($path === false) {
573
+ return false;
574
+ }
575
+ $this->pos = 0;
576
+ $this->entries = $this->sftp->nlist($path);
577
+ return $this->entries !== false;
578
+ }
579
+
580
+ /**
581
+ * Read entry from directory handle
582
+ *
583
+ * @return mixed
584
+ * @access public
585
+ */
586
+ function _dir_readdir()
587
+ {
588
+ if (isset($this->entries[$this->pos])) {
589
+ return $this->entries[$this->pos++];
590
+ }
591
+ return false;
592
+ }
593
+
594
+ /**
595
+ * Rewind directory handle
596
+ *
597
+ * @return bool
598
+ * @access public
599
+ */
600
+ function _dir_rewinddir()
601
+ {
602
+ $this->pos = 0;
603
+ return true;
604
+ }
605
+
606
+ /**
607
+ * Close directory handle
608
+ *
609
+ * @return bool
610
+ * @access public
611
+ */
612
+ function _dir_closedir()
613
+ {
614
+ return true;
615
+ }
616
+
617
+ /**
618
+ * Create a directory
619
+ *
620
+ * Only valid $options is STREAM_MKDIR_RECURSIVE
621
+ *
622
+ * @param string $path
623
+ * @param int $mode
624
+ * @param int $options
625
+ * @return bool
626
+ * @access public
627
+ */
628
+ function _mkdir($path, $mode, $options)
629
+ {
630
+ $path = $this->_parse_path($path);
631
+ if ($path === false) {
632
+ return false;
633
+ }
634
+
635
+ return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE);
636
+ }
637
+
638
+ /**
639
+ * Removes a directory
640
+ *
641
+ * Only valid $options is STREAM_MKDIR_RECURSIVE per <http://php.net/streamwrapper.rmdir>, however,
642
+ * <http://php.net/rmdir> does not have a $recursive parameter as mkdir() does so I don't know how
643
+ * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as
644
+ * $options. What does 8 correspond to?
645
+ *
646
+ * @param string $path
647
+ * @param int $mode
648
+ * @param int $options
649
+ * @return bool
650
+ * @access public
651
+ */
652
+ function _rmdir($path, $options)
653
+ {
654
+ $path = $this->_parse_path($path);
655
+ if ($path === false) {
656
+ return false;
657
+ }
658
+
659
+ return $this->sftp->rmdir($path);
660
+ }
661
+
662
+ /**
663
+ * Flushes the output
664
+ *
665
+ * See <http://php.net/fflush>. Always returns true because Net_SFTP doesn't cache stuff before writing
666
+ *
667
+ * @return bool
668
+ * @access public
669
+ */
670
+ function _stream_flush()
671
+ {
672
+ return true;
673
+ }
674
+
675
+ /**
676
+ * Retrieve information about a file resource
677
+ *
678
+ * @return mixed
679
+ * @access public
680
+ */
681
+ function _stream_stat()
682
+ {
683
+ $results = $this->sftp->stat($this->path);
684
+ if ($results === false) {
685
+ return false;
686
+ }
687
+ return $results;
688
+ }
689
+
690
+ /**
691
+ * Delete a file
692
+ *
693
+ * @param string $path
694
+ * @return bool
695
+ * @access public
696
+ */
697
+ function _unlink($path)
698
+ {
699
+ $path = $this->_parse_path($path);
700
+ if ($path === false) {
701
+ return false;
702
+ }
703
+
704
+ return $this->sftp->delete($path, false);
705
+ }
706
+
707
+ /**
708
+ * Retrieve information about a file
709
+ *
710
+ * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default
711
+ * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll
712
+ * cross that bridge when and if it's reached
713
+ *
714
+ * @param string $path
715
+ * @param int $flags
716
+ * @return mixed
717
+ * @access public
718
+ */
719
+ function _url_stat($path, $flags)
720
+ {
721
+ $path = $this->_parse_path($path);
722
+ if ($path === false) {
723
+ return false;
724
+ }
725
+
726
+ $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path);
727
+ if ($results === false) {
728
+ return false;
729
+ }
730
+
731
+ return $results;
732
+ }
733
+
734
+ /**
735
+ * Truncate stream
736
+ *
737
+ * @param int $new_size
738
+ * @return bool
739
+ * @access public
740
+ */
741
+ function _stream_truncate($new_size)
742
+ {
743
+ if (!$this->sftp->truncate($this->path, $new_size)) {
744
+ return false;
745
+ }
746
+
747
+ $this->eof = false;
748
+ $this->size = $new_size;
749
+
750
+ return true;
751
+ }
752
+
753
+ /**
754
+ * Change stream options
755
+ *
756
+ * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't.
757
+ * The other two aren't supported because of limitations in Net_SFTP.
758
+ *
759
+ * @param int $option
760
+ * @param int $arg1
761
+ * @param int $arg2
762
+ * @return bool
763
+ * @access public
764
+ */
765
+ function _stream_set_option($option, $arg1, $arg2)
766
+ {
767
+ return false;
768
+ }
769
+
770
+ /**
771
+ * Close an resource
772
+ *
773
+ * @access public
774
+ */
775
+ function _stream_close()
776
+ {
777
+ }
778
+
779
+ /**
780
+ * __call Magic Method
781
+ *
782
+ * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you.
783
+ * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function
784
+ * lets you figure that out.
785
+ *
786
+ * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
787
+ * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
788
+ *
789
+ * @param string
790
+ * @param array
791
+ * @return mixed
792
+ * @access public
793
+ */
794
+ function __call($name, $arguments)
795
+ {
796
+ if (defined('NET_SFTP_STREAM_LOGGING')) {
797
+ echo $name . '(';
798
+ $last = count($arguments) - 1;
799
+ foreach ($arguments as $i => $argument) {
800
+ var_export($argument);
801
+ if ($i != $last) {
802
+ echo ',';
803
+ }
804
+ }
805
+ echo ")\r\n";
806
+ }
807
+ $name = '_' . $name;
808
+ if (!method_exists($this, $name)) {
809
+ return false;
810
+ }
811
+ return call_user_func_array(array($this, $name), $arguments);
812
+ }
813
+ }
814
+
815
+ Net_SFTP_Stream::register();
phpseclib/Net/SSH1.php ADDED
@@ -0,0 +1,1691 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of SSHv1.
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Here's a short example of how to use this library:
9
+ * <code>
10
+ * <?php
11
+ * include 'Net/SSH1.php';
12
+ *
13
+ * $ssh = new Net_SSH1('www.domain.tld');
14
+ * if (!$ssh->login('username', 'password')) {
15
+ * exit('Login Failed');
16
+ * }
17
+ *
18
+ * echo $ssh->exec('ls -la');
19
+ * ?>
20
+ * </code>
21
+ *
22
+ * Here's another short example:
23
+ * <code>
24
+ * <?php
25
+ * include 'Net/SSH1.php';
26
+ *
27
+ * $ssh = new Net_SSH1('www.domain.tld');
28
+ * if (!$ssh->login('username', 'password')) {
29
+ * exit('Login Failed');
30
+ * }
31
+ *
32
+ * echo $ssh->read('username@username:~$');
33
+ * $ssh->write("ls -la\n");
34
+ * echo $ssh->read('username@username:~$');
35
+ * ?>
36
+ * </code>
37
+ *
38
+ * More information on the SSHv1 specification can be found by reading
39
+ * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
40
+ *
41
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
42
+ * of this software and associated documentation files (the "Software"), to deal
43
+ * in the Software without restriction, including without limitation the rights
44
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45
+ * copies of the Software, and to permit persons to whom the Software is
46
+ * furnished to do so, subject to the following conditions:
47
+ *
48
+ * The above copyright notice and this permission notice shall be included in
49
+ * all copies or substantial portions of the Software.
50
+ *
51
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
57
+ * THE SOFTWARE.
58
+ *
59
+ * @category Net
60
+ * @package Net_SSH1
61
+ * @author Jim Wigginton <terrafrost@php.net>
62
+ * @copyright 2007 Jim Wigginton
63
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
64
+ * @link http://phpseclib.sourceforge.net
65
+ */
66
+
67
+ /**#@+
68
+ * Encryption Methods
69
+ *
70
+ * @see self::getSupportedCiphers()
71
+ * @access public
72
+ */
73
+ /**
74
+ * No encryption
75
+ *
76
+ * Not supported.
77
+ */
78
+ define('NET_SSH1_CIPHER_NONE', 0);
79
+ /**
80
+ * IDEA in CFB mode
81
+ *
82
+ * Not supported.
83
+ */
84
+ define('NET_SSH1_CIPHER_IDEA', 1);
85
+ /**
86
+ * DES in CBC mode
87
+ */
88
+ define('NET_SSH1_CIPHER_DES', 2);
89
+ /**
90
+ * Triple-DES in CBC mode
91
+ *
92
+ * All implementations are required to support this
93
+ */
94
+ define('NET_SSH1_CIPHER_3DES', 3);
95
+ /**
96
+ * TRI's Simple Stream encryption CBC
97
+ *
98
+ * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
99
+ * although it doesn't use it (see cipher.c)
100
+ */
101
+ define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
102
+ /**
103
+ * RC4
104
+ *
105
+ * Not supported.
106
+ *
107
+ * @internal According to the SSH1 specs:
108
+ *
109
+ * "The first 16 bytes of the session key are used as the key for
110
+ * the server to client direction. The remaining 16 bytes are used
111
+ * as the key for the client to server direction. This gives
112
+ * independent 128-bit keys for each direction."
113
+ *
114
+ * This library currently only supports encryption when the same key is being used for both directions. This is
115
+ * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
116
+ */
117
+ define('NET_SSH1_CIPHER_RC4', 5);
118
+ /**
119
+ * Blowfish
120
+ *
121
+ * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
122
+ * uses it (see cipher.c)
123
+ */
124
+ define('NET_SSH1_CIPHER_BLOWFISH', 6);
125
+ /**#@-*/
126
+
127
+ /**#@+
128
+ * Authentication Methods
129
+ *
130
+ * @see self::getSupportedAuthentications()
131
+ * @access public
132
+ */
133
+ /**
134
+ * .rhosts or /etc/hosts.equiv
135
+ */
136
+ define('NET_SSH1_AUTH_RHOSTS', 1);
137
+ /**
138
+ * pure RSA authentication
139
+ */
140
+ define('NET_SSH1_AUTH_RSA', 2);
141
+ /**
142
+ * password authentication
143
+ *
144
+ * This is the only method that is supported by this library.
145
+ */
146
+ define('NET_SSH1_AUTH_PASSWORD', 3);
147
+ /**
148
+ * .rhosts with RSA host authentication
149
+ */
150
+ define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
151
+ /**#@-*/
152
+
153
+ /**#@+
154
+ * Terminal Modes
155
+ *
156
+ * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
157
+ * @access private
158
+ */
159
+ define('NET_SSH1_TTY_OP_END', 0);
160
+ /**#@-*/
161
+
162
+ /**
163
+ * The Response Type
164
+ *
165
+ * @see self::_get_binary_packet()
166
+ * @access private
167
+ */
168
+ define('NET_SSH1_RESPONSE_TYPE', 1);
169
+
170
+ /**
171
+ * The Response Data
172
+ *
173
+ * @see self::_get_binary_packet()
174
+ * @access private
175
+ */
176
+ define('NET_SSH1_RESPONSE_DATA', 2);
177
+
178
+ /**#@+
179
+ * Execution Bitmap Masks
180
+ *
181
+ * @see self::bitmap
182
+ * @access private
183
+ */
184
+ define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
185
+ define('NET_SSH1_MASK_CONNECTED', 0x00000002);
186
+ define('NET_SSH1_MASK_LOGIN', 0x00000004);
187
+ define('NET_SSH1_MASK_SHELL', 0x00000008);
188
+ /**#@-*/
189
+
190
+ /**#@+
191
+ * @access public
192
+ * @see self::getLog()
193
+ */
194
+ /**
195
+ * Returns the message numbers
196
+ */
197
+ define('NET_SSH1_LOG_SIMPLE', 1);
198
+ /**
199
+ * Returns the message content
200
+ */
201
+ define('NET_SSH1_LOG_COMPLEX', 2);
202
+ /**
203
+ * Outputs the content real-time
204
+ */
205
+ define('NET_SSH1_LOG_REALTIME', 3);
206
+ /**
207
+ * Dumps the content real-time to a file
208
+ */
209
+ define('NET_SSH1_LOG_REALTIME_FILE', 4);
210
+ /**#@-*/
211
+
212
+ /**#@+
213
+ * @access public
214
+ * @see self::read()
215
+ */
216
+ /**
217
+ * Returns when a string matching $expect exactly is found
218
+ */
219
+ define('NET_SSH1_READ_SIMPLE', 1);
220
+ /**
221
+ * Returns when a string matching the regular expression $expect is found
222
+ */
223
+ define('NET_SSH1_READ_REGEX', 2);
224
+ /**#@-*/
225
+
226
+ /**
227
+ * Pure-PHP implementation of SSHv1.
228
+ *
229
+ * @package Net_SSH1
230
+ * @author Jim Wigginton <terrafrost@php.net>
231
+ * @access public
232
+ */
233
+ class Net_SSH1
234
+ {
235
+ /**
236
+ * The SSH identifier
237
+ *
238
+ * @var string
239
+ * @access private
240
+ */
241
+ var $identifier = 'SSH-1.5-phpseclib';
242
+
243
+ /**
244
+ * The Socket Object
245
+ *
246
+ * @var object
247
+ * @access private
248
+ */
249
+ var $fsock;
250
+
251
+ /**
252
+ * The cryptography object
253
+ *
254
+ * @var object
255
+ * @access private
256
+ */
257
+ var $crypto = false;
258
+
259
+ /**
260
+ * Execution Bitmap
261
+ *
262
+ * The bits that are set represent functions that have been called already. This is used to determine
263
+ * if a requisite function has been successfully executed. If not, an error should be thrown.
264
+ *
265
+ * @var int
266
+ * @access private
267
+ */
268
+ var $bitmap = 0;
269
+
270
+ /**
271
+ * The Server Key Public Exponent
272
+ *
273
+ * Logged for debug purposes
274
+ *
275
+ * @see self::getServerKeyPublicExponent()
276
+ * @var string
277
+ * @access private
278
+ */
279
+ var $server_key_public_exponent;
280
+
281
+ /**
282
+ * The Server Key Public Modulus
283
+ *
284
+ * Logged for debug purposes
285
+ *
286
+ * @see self::getServerKeyPublicModulus()
287
+ * @var string
288
+ * @access private
289
+ */
290
+ var $server_key_public_modulus;
291
+
292
+ /**
293
+ * The Host Key Public Exponent
294
+ *
295
+ * Logged for debug purposes
296
+ *
297
+ * @see self::getHostKeyPublicExponent()
298
+ * @var string
299
+ * @access private
300
+ */
301
+ var $host_key_public_exponent;
302
+
303
+ /**
304
+ * The Host Key Public Modulus
305
+ *
306
+ * Logged for debug purposes
307
+ *
308
+ * @see self::getHostKeyPublicModulus()
309
+ * @var string
310
+ * @access private
311
+ */
312
+ var $host_key_public_modulus;
313
+
314
+ /**
315
+ * Supported Ciphers
316
+ *
317
+ * Logged for debug purposes
318
+ *
319
+ * @see self::getSupportedCiphers()
320
+ * @var array
321
+ * @access private
322
+ */
323
+ var $supported_ciphers = array(
324
+ NET_SSH1_CIPHER_NONE => 'No encryption',
325
+ NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
326
+ NET_SSH1_CIPHER_DES => 'DES in CBC mode',
327
+ NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
328
+ NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
329
+ NET_SSH1_CIPHER_RC4 => 'RC4',
330
+ NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
331
+ );
332
+
333
+ /**
334
+ * Supported Authentications
335
+ *
336
+ * Logged for debug purposes
337
+ *
338
+ * @see self::getSupportedAuthentications()
339
+ * @var array
340
+ * @access private
341
+ */
342
+ var $supported_authentications = array(
343
+ NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
344
+ NET_SSH1_AUTH_RSA => 'pure RSA authentication',
345
+ NET_SSH1_AUTH_PASSWORD => 'password authentication',
346
+ NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
347
+ );
348
+
349
+ /**
350
+ * Server Identification
351
+ *
352
+ * @see self::getServerIdentification()
353
+ * @var string
354
+ * @access private
355
+ */
356
+ var $server_identification = '';
357
+
358
+ /**
359
+ * Protocol Flags
360
+ *
361
+ * @see self::Net_SSH1()
362
+ * @var array
363
+ * @access private
364
+ */
365
+ var $protocol_flags = array();
366
+
367
+ /**
368
+ * Protocol Flag Log
369
+ *
370
+ * @see self::getLog()
371
+ * @var array
372
+ * @access private
373
+ */
374
+ var $protocol_flag_log = array();
375
+
376
+ /**
377
+ * Message Log
378
+ *
379
+ * @see self::getLog()
380
+ * @var array
381
+ * @access private
382
+ */
383
+ var $message_log = array();
384
+
385
+ /**
386
+ * Real-time log file pointer
387
+ *
388
+ * @see self::_append_log()
389
+ * @var resource
390
+ * @access private
391
+ */
392
+ var $realtime_log_file;
393
+
394
+ /**
395
+ * Real-time log file size
396
+ *
397
+ * @see self::_append_log()
398
+ * @var int
399
+ * @access private
400
+ */
401
+ var $realtime_log_size;
402
+
403
+ /**
404
+ * Real-time log file wrap boolean
405
+ *
406
+ * @see self::_append_log()
407
+ * @var bool
408
+ * @access private
409
+ */
410
+ var $realtime_log_wrap;
411
+
412
+ /**
413
+ * Interactive Buffer
414
+ *
415
+ * @see self::read()
416
+ * @var array
417
+ * @access private
418
+ */
419
+ var $interactiveBuffer = '';
420
+
421
+ /**
422
+ * Timeout
423
+ *
424
+ * @see self::setTimeout()
425
+ * @access private
426
+ */
427
+ var $timeout;
428
+
429
+ /**
430
+ * Current Timeout
431
+ *
432
+ * @see self::_get_channel_packet()
433
+ * @access private
434
+ */
435
+ var $curTimeout;
436
+
437
+ /**
438
+ * Log Boundary
439
+ *
440
+ * @see self::_format_log()
441
+ * @access private
442
+ */
443
+ var $log_boundary = ':';
444
+
445
+ /**
446
+ * Log Long Width
447
+ *
448
+ * @see self::_format_log()
449
+ * @access private
450
+ */
451
+ var $log_long_width = 65;
452
+
453
+ /**
454
+ * Log Short Width
455
+ *
456
+ * @see self::_format_log()
457
+ * @access private
458
+ */
459
+ var $log_short_width = 16;
460
+
461
+ /**
462
+ * Hostname
463
+ *
464
+ * @see self::Net_SSH1()
465
+ * @see self::_connect()
466
+ * @var string
467
+ * @access private
468
+ */
469
+ var $host;
470
+
471
+ /**
472
+ * Port Number
473
+ *
474
+ * @see self::Net_SSH1()
475
+ * @see self::_connect()
476
+ * @var int
477
+ * @access private
478
+ */
479
+ var $port;
480
+
481
+ /**
482
+ * Timeout for initial connection
483
+ *
484
+ * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
485
+ * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
486
+ * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
487
+ * 10 seconds. It is used by fsockopen() in that function.
488
+ *
489
+ * @see self::Net_SSH1()
490
+ * @see self::_connect()
491
+ * @var int
492
+ * @access private
493
+ */
494
+ var $connectionTimeout;
495
+
496
+ /**
497
+ * Default cipher
498
+ *
499
+ * @see self::Net_SSH1()
500
+ * @see self::_connect()
501
+ * @var int
502
+ * @access private
503
+ */
504
+ var $cipher;
505
+
506
+ /**
507
+ * Default Constructor.
508
+ *
509
+ * Connects to an SSHv1 server
510
+ *
511
+ * @param string $host
512
+ * @param int $port
513
+ * @param int $timeout
514
+ * @param int $cipher
515
+ * @return Net_SSH1
516
+ * @access public
517
+ */
518
+ function __construct($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
519
+ {
520
+ if (!class_exists('Math_BigInteger')) {
521
+ include_once 'Math/BigInteger.php';
522
+ }
523
+
524
+ // Include Crypt_Random
525
+ // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
526
+ // will trigger a call to __autoload() if you're wanting to auto-load classes
527
+ // call function_exists() a second time to stop the include_once from being called outside
528
+ // of the auto loader
529
+ if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
530
+ include_once 'Crypt/Random.php';
531
+ }
532
+
533
+ $this->protocol_flags = array(
534
+ 1 => 'NET_SSH1_MSG_DISCONNECT',
535
+ 2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
536
+ 3 => 'NET_SSH1_CMSG_SESSION_KEY',
537
+ 4 => 'NET_SSH1_CMSG_USER',
538
+ 9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
539
+ 10 => 'NET_SSH1_CMSG_REQUEST_PTY',
540
+ 12 => 'NET_SSH1_CMSG_EXEC_SHELL',
541
+ 13 => 'NET_SSH1_CMSG_EXEC_CMD',
542
+ 14 => 'NET_SSH1_SMSG_SUCCESS',
543
+ 15 => 'NET_SSH1_SMSG_FAILURE',
544
+ 16 => 'NET_SSH1_CMSG_STDIN_DATA',
545
+ 17 => 'NET_SSH1_SMSG_STDOUT_DATA',
546
+ 18 => 'NET_SSH1_SMSG_STDERR_DATA',
547
+ 19 => 'NET_SSH1_CMSG_EOF',
548
+ 20 => 'NET_SSH1_SMSG_EXITSTATUS',
549
+ 33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
550
+ );
551
+
552
+ $this->_define_array($this->protocol_flags);
553
+
554
+ $this->host = $host;
555
+ $this->port = $port;
556
+ $this->connectionTimeout = $timeout;
557
+ $this->cipher = $cipher;
558
+ }
559
+
560
+ /**
561
+ * PHP4 compatible Default Constructor.
562
+ *
563
+ * @see self::__construct()
564
+ * @param string $host
565
+ * @param int $port
566
+ * @param int $timeout
567
+ * @param int $cipher
568
+ * @access public
569
+ */
570
+ function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
571
+ {
572
+ $this->__construct($host, $port, $timeout, $cipher);
573
+ }
574
+
575
+ /**
576
+ * Connect to an SSHv1 server
577
+ *
578
+ * @return bool
579
+ * @access private
580
+ */
581
+ function _connect()
582
+ {
583
+ $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
584
+ if (!$this->fsock) {
585
+ user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
586
+ return false;
587
+ }
588
+
589
+ $this->server_identification = $init_line = fgets($this->fsock, 255);
590
+
591
+ if (defined('NET_SSH1_LOGGING')) {
592
+ $this->_append_log('<-', $this->server_identification);
593
+ $this->_append_log('->', $this->identifier . "\r\n");
594
+ }
595
+
596
+ if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
597
+ user_error('Can only connect to SSH servers');
598
+ return false;
599
+ }
600
+ if ($parts[1][0] != 1) {
601
+ user_error("Cannot connect to SSH $parts[1] servers");
602
+ return false;
603
+ }
604
+
605
+ fputs($this->fsock, $this->identifier."\r\n");
606
+
607
+ $response = $this->_get_binary_packet();
608
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
609
+ user_error('Expected SSH_SMSG_PUBLIC_KEY');
610
+ return false;
611
+ }
612
+
613
+ $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
614
+
615
+ $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
616
+
617
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
618
+ return false;
619
+ }
620
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
621
+ $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
622
+ $this->server_key_public_exponent = $server_key_public_exponent;
623
+
624
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
625
+ return false;
626
+ }
627
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
628
+ $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
629
+ $this->server_key_public_modulus = $server_key_public_modulus;
630
+
631
+ $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
632
+
633
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
634
+ return false;
635
+ }
636
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
637
+ $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
638
+ $this->host_key_public_exponent = $host_key_public_exponent;
639
+
640
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
641
+ return false;
642
+ }
643
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
644
+ $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
645
+ $this->host_key_public_modulus = $host_key_public_modulus;
646
+
647
+ $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
648
+
649
+ // get a list of the supported ciphers
650
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
651
+ return false;
652
+ }
653
+ extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
654
+ foreach ($this->supported_ciphers as $mask => $name) {
655
+ if (($supported_ciphers_mask & (1 << $mask)) == 0) {
656
+ unset($this->supported_ciphers[$mask]);
657
+ }
658
+ }
659
+
660
+ // get a list of the supported authentications
661
+ if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
662
+ return false;
663
+ }
664
+ extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
665
+ foreach ($this->supported_authentications as $mask => $name) {
666
+ if (($supported_authentications_mask & (1 << $mask)) == 0) {
667
+ unset($this->supported_authentications[$mask]);
668
+ }
669
+ }
670
+
671
+ $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
672
+
673
+ $session_key = crypt_random_string(32);
674
+ $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
675
+
676
+ if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
677
+ $double_encrypted_session_key = $this->_rsa_crypt(
678
+ $double_encrypted_session_key,
679
+ array(
680
+ $server_key_public_exponent,
681
+ $server_key_public_modulus
682
+ )
683
+ );
684
+ $double_encrypted_session_key = $this->_rsa_crypt(
685
+ $double_encrypted_session_key,
686
+ array(
687
+ $host_key_public_exponent,
688
+ $host_key_public_modulus
689
+ )
690
+ );
691
+ } else {
692
+ $double_encrypted_session_key = $this->_rsa_crypt(
693
+ $double_encrypted_session_key,
694
+ array(
695
+ $host_key_public_exponent,
696
+ $host_key_public_modulus
697
+ )
698
+ );
699
+ $double_encrypted_session_key = $this->_rsa_crypt(
700
+ $double_encrypted_session_key,
701
+ array(
702
+ $server_key_public_exponent,
703
+ $server_key_public_modulus
704
+ )
705
+ );
706
+ }
707
+
708
+ $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES;
709
+ $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
710
+
711
+ if (!$this->_send_binary_packet($data)) {
712
+ user_error('Error sending SSH_CMSG_SESSION_KEY');
713
+ return false;
714
+ }
715
+
716
+ switch ($cipher) {
717
+ //case NET_SSH1_CIPHER_NONE:
718
+ // $this->crypto = new Crypt_Null();
719
+ // break;
720
+ case NET_SSH1_CIPHER_DES:
721
+ if (!class_exists('Crypt_DES')) {
722
+ include_once 'Crypt/DES.php';
723
+ }
724
+ $this->crypto = new Crypt_DES();
725
+ $this->crypto->disablePadding();
726
+ $this->crypto->enableContinuousBuffer();
727
+ $this->crypto->setKey(substr($session_key, 0, 8));
728
+ break;
729
+ case NET_SSH1_CIPHER_3DES:
730
+ if (!class_exists('Crypt_TripleDES')) {
731
+ include_once 'Crypt/TripleDES.php';
732
+ }
733
+ $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
734
+ $this->crypto->disablePadding();
735
+ $this->crypto->enableContinuousBuffer();
736
+ $this->crypto->setKey(substr($session_key, 0, 24));
737
+ break;
738
+ //case NET_SSH1_CIPHER_RC4:
739
+ // if (!class_exists('Crypt_RC4')) {
740
+ // include_once 'Crypt/RC4.php';
741
+ // }
742
+ // $this->crypto = new Crypt_RC4();
743
+ // $this->crypto->enableContinuousBuffer();
744
+ // $this->crypto->setKey(substr($session_key, 0, 16));
745
+ // break;
746
+ }
747
+
748
+ $response = $this->_get_binary_packet();
749
+
750
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
751
+ user_error('Expected SSH_SMSG_SUCCESS');
752
+ return false;
753
+ }
754
+
755
+ $this->bitmap = NET_SSH1_MASK_CONNECTED;
756
+
757
+ return true;
758
+ }
759
+
760
+ /**
761
+ * Login
762
+ *
763
+ * @param string $username
764
+ * @param string $password
765
+ * @return bool
766
+ * @access public
767
+ */
768
+ function login($username, $password = '')
769
+ {
770
+ if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
771
+ $this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR;
772
+ if (!$this->_connect()) {
773
+ return false;
774
+ }
775
+ }
776
+
777
+ if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) {
778
+ return false;
779
+ }
780
+
781
+ $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
782
+
783
+ if (!$this->_send_binary_packet($data)) {
784
+ user_error('Error sending SSH_CMSG_USER');
785
+ return false;
786
+ }
787
+
788
+ $response = $this->_get_binary_packet();
789
+
790
+ if ($response === true) {
791
+ return false;
792
+ }
793
+ if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
794
+ $this->bitmap |= NET_SSH1_MASK_LOGIN;
795
+ return true;
796
+ } elseif ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
797
+ user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
798
+ return false;
799
+ }
800
+
801
+ $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
802
+
803
+ if (!$this->_send_binary_packet($data)) {
804
+ user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
805
+ return false;
806
+ }
807
+
808
+ // remove the username and password from the last logged packet
809
+ if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
810
+ $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
811
+ $this->message_log[count($this->message_log) - 1] = $data;
812
+ }
813
+
814
+ $response = $this->_get_binary_packet();
815
+
816
+ if ($response === true) {
817
+ return false;
818
+ }
819
+ if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
820
+ $this->bitmap |= NET_SSH1_MASK_LOGIN;
821
+ return true;
822
+ } elseif ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
823
+ return false;
824
+ } else {
825
+ user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
826
+ return false;
827
+ }
828
+ }
829
+
830
+ /**
831
+ * Set Timeout
832
+ *
833
+ * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
834
+ * Setting $timeout to false or 0 will mean there is no timeout.
835
+ *
836
+ * @param mixed $timeout
837
+ */
838
+ function setTimeout($timeout)
839
+ {
840
+ $this->timeout = $this->curTimeout = $timeout;
841
+ }
842
+
843
+ /**
844
+ * Executes a command on a non-interactive shell, returns the output, and quits.
845
+ *
846
+ * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
847
+ * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
848
+ * shell with the -s option, as discussed in the following links:
849
+ *
850
+ * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
851
+ * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
852
+ *
853
+ * To execute further commands, a new Net_SSH1 object will need to be created.
854
+ *
855
+ * Returns false on failure and the output, otherwise.
856
+ *
857
+ * @see self::interactiveRead()
858
+ * @see self::interactiveWrite()
859
+ * @param string $cmd
860
+ * @return mixed
861
+ * @access public
862
+ */
863
+ function exec($cmd, $block = true)
864
+ {
865
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
866
+ user_error('Operation disallowed prior to login()');
867
+ return false;
868
+ }
869
+
870
+ $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
871
+
872
+ if (!$this->_send_binary_packet($data)) {
873
+ user_error('Error sending SSH_CMSG_EXEC_CMD');
874
+ return false;
875
+ }
876
+
877
+ if (!$block) {
878
+ return true;
879
+ }
880
+
881
+ $output = '';
882
+ $response = $this->_get_binary_packet();
883
+
884
+ if ($response !== false) {
885
+ do {
886
+ $output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
887
+ $response = $this->_get_binary_packet();
888
+ } while (is_array($response) && $response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
889
+ }
890
+
891
+ $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
892
+
893
+ // i don't think it's really all that important if this packet gets sent or not.
894
+ $this->_send_binary_packet($data);
895
+
896
+ fclose($this->fsock);
897
+
898
+ // reset the execution bitmap - a new Net_SSH1 object needs to be created.
899
+ $this->bitmap = 0;
900
+
901
+ return $output;
902
+ }
903
+
904
+ /**
905
+ * Creates an interactive shell
906
+ *
907
+ * @see self::interactiveRead()
908
+ * @see self::interactiveWrite()
909
+ * @return bool
910
+ * @access private
911
+ */
912
+ function _initShell()
913
+ {
914
+ // connect using the sample parameters in protocol-1.5.txt.
915
+ // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
916
+ // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
917
+ $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
918
+
919
+ if (!$this->_send_binary_packet($data)) {
920
+ user_error('Error sending SSH_CMSG_REQUEST_PTY');
921
+ return false;
922
+ }
923
+
924
+ $response = $this->_get_binary_packet();
925
+
926
+ if ($response === true) {
927
+ return false;
928
+ }
929
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
930
+ user_error('Expected SSH_SMSG_SUCCESS');
931
+ return false;
932
+ }
933
+
934
+ $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
935
+
936
+ if (!$this->_send_binary_packet($data)) {
937
+ user_error('Error sending SSH_CMSG_EXEC_SHELL');
938
+ return false;
939
+ }
940
+
941
+ $this->bitmap |= NET_SSH1_MASK_SHELL;
942
+
943
+ //stream_set_blocking($this->fsock, 0);
944
+
945
+ return true;
946
+ }
947
+
948
+ /**
949
+ * Inputs a command into an interactive shell.
950
+ *
951
+ * @see self::interactiveWrite()
952
+ * @param string $cmd
953
+ * @return bool
954
+ * @access public
955
+ */
956
+ function write($cmd)
957
+ {
958
+ return $this->interactiveWrite($cmd);
959
+ }
960
+
961
+ /**
962
+ * Returns the output of an interactive shell when there's a match for $expect
963
+ *
964
+ * $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX,
965
+ * a regular expression.
966
+ *
967
+ * @see self::write()
968
+ * @param string $expect
969
+ * @param int $mode
970
+ * @return bool
971
+ * @access public
972
+ */
973
+ function read($expect, $mode = NET_SSH1_READ_SIMPLE)
974
+ {
975
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
976
+ user_error('Operation disallowed prior to login()');
977
+ return false;
978
+ }
979
+
980
+ if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
981
+ user_error('Unable to initiate an interactive shell session');
982
+ return false;
983
+ }
984
+
985
+ $match = $expect;
986
+ while (true) {
987
+ if ($mode == NET_SSH1_READ_REGEX) {
988
+ preg_match($expect, $this->interactiveBuffer, $matches);
989
+ $match = isset($matches[0]) ? $matches[0] : '';
990
+ }
991
+ $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
992
+ if ($pos !== false) {
993
+ return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
994
+ }
995
+ $response = $this->_get_binary_packet();
996
+
997
+ if ($response === true) {
998
+ return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
999
+ }
1000
+ $this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
1001
+ }
1002
+ }
1003
+
1004
+ /**
1005
+ * Inputs a command into an interactive shell.
1006
+ *
1007
+ * @see self::interactiveRead()
1008
+ * @param string $cmd
1009
+ * @return bool
1010
+ * @access public
1011
+ */
1012
+ function interactiveWrite($cmd)
1013
+ {
1014
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
1015
+ user_error('Operation disallowed prior to login()');
1016
+ return false;
1017
+ }
1018
+
1019
+ if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
1020
+ user_error('Unable to initiate an interactive shell session');
1021
+ return false;
1022
+ }
1023
+
1024
+ $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
1025
+
1026
+ if (!$this->_send_binary_packet($data)) {
1027
+ user_error('Error sending SSH_CMSG_STDIN');
1028
+ return false;
1029
+ }
1030
+
1031
+ return true;
1032
+ }
1033
+
1034
+ /**
1035
+ * Returns the output of an interactive shell when no more output is available.
1036
+ *
1037
+ * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
1038
+ * "^[[00m", you're seeing ANSI escape codes. According to
1039
+ * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
1040
+ * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
1041
+ * there's not going to be much recourse.
1042
+ *
1043
+ * @see self::interactiveRead()
1044
+ * @return string
1045
+ * @access public
1046
+ */
1047
+ function interactiveRead()
1048
+ {
1049
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
1050
+ user_error('Operation disallowed prior to login()');
1051
+ return false;
1052
+ }
1053
+
1054
+ if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
1055
+ user_error('Unable to initiate an interactive shell session');
1056
+ return false;
1057
+ }
1058
+
1059
+ $read = array($this->fsock);
1060
+ $write = $except = null;
1061
+ if (stream_select($read, $write, $except, 0)) {
1062
+ $response = $this->_get_binary_packet();
1063
+ return substr($response[NET_SSH1_RESPONSE_DATA], 4);
1064
+ } else {
1065
+ return '';
1066
+ }
1067
+ }
1068
+
1069
+ /**
1070
+ * Disconnect
1071
+ *
1072
+ * @access public
1073
+ */
1074
+ function disconnect()
1075
+ {
1076
+ $this->_disconnect();
1077
+ }
1078
+
1079
+ /**
1080
+ * Destructor.
1081
+ *
1082
+ * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
1083
+ * disconnect().
1084
+ *
1085
+ * @access public
1086
+ */
1087
+ function __destruct()
1088
+ {
1089
+ $this->_disconnect();
1090
+ }
1091
+
1092
+ /**
1093
+ * Disconnect
1094
+ *
1095
+ * @param string $msg
1096
+ * @access private
1097
+ */
1098
+ function _disconnect($msg = 'Client Quit')
1099
+ {
1100
+ if ($this->bitmap) {
1101
+ $data = pack('C', NET_SSH1_CMSG_EOF);
1102
+ $this->_send_binary_packet($data);
1103
+ /*
1104
+ $response = $this->_get_binary_packet();
1105
+ if ($response === true) {
1106
+ $response = array(NET_SSH1_RESPONSE_TYPE => -1);
1107
+ }
1108
+ switch ($response[NET_SSH1_RESPONSE_TYPE]) {
1109
+ case NET_SSH1_SMSG_EXITSTATUS:
1110
+ $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
1111
+ break;
1112
+ default:
1113
+ $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1114
+ }
1115
+ */
1116
+ $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1117
+
1118
+ $this->_send_binary_packet($data);
1119
+ fclose($this->fsock);
1120
+ $this->bitmap = 0;
1121
+ }
1122
+ }
1123
+
1124
+ /**
1125
+ * Gets Binary Packets
1126
+ *
1127
+ * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
1128
+ *
1129
+ * Also, this function could be improved upon by adding detection for the following exploit:
1130
+ * http://www.securiteam.com/securitynews/5LP042K3FY.html
1131
+ *
1132
+ * @see self::_send_binary_packet()
1133
+ * @return array
1134
+ * @access private
1135
+ */
1136
+ function _get_binary_packet()
1137
+ {
1138
+ if (feof($this->fsock)) {
1139
+ //user_error('connection closed prematurely');
1140
+ return false;
1141
+ }
1142
+
1143
+ if ($this->curTimeout) {
1144
+ $read = array($this->fsock);
1145
+ $write = $except = null;
1146
+
1147
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1148
+ $sec = floor($this->curTimeout);
1149
+ $usec = 1000000 * ($this->curTimeout - $sec);
1150
+ // on windows this returns a "Warning: Invalid CRT parameters detected" error
1151
+ if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
1152
+ //$this->_disconnect('Timeout');
1153
+ return true;
1154
+ }
1155
+ $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1156
+ $this->curTimeout-= $elapsed;
1157
+ }
1158
+
1159
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1160
+ $data = fread($this->fsock, 4);
1161
+ if (strlen($data) < 4) {
1162
+ return false;
1163
+ }
1164
+ $temp = unpack('Nlength', $data);
1165
+
1166
+ $padding_length = 8 - ($temp['length'] & 7);
1167
+ $length = $temp['length'] + $padding_length;
1168
+ $raw = '';
1169
+
1170
+ while ($length > 0) {
1171
+ $temp = fread($this->fsock, $length);
1172
+ $raw.= $temp;
1173
+ $length-= strlen($temp);
1174
+ }
1175
+ $stop = strtok(microtime(), ' ') + strtok('');
1176
+
1177
+ if (strlen($raw) && $this->crypto !== false) {
1178
+ $raw = $this->crypto->decrypt($raw);
1179
+ }
1180
+
1181
+ $padding = substr($raw, 0, $padding_length);
1182
+ $type = $raw[$padding_length];
1183
+ $data = substr($raw, $padding_length + 1, -4);
1184
+
1185
+ if (strlen($raw) < 4) {
1186
+ return false;
1187
+ }
1188
+ $temp = unpack('Ncrc', substr($raw, -4));
1189
+
1190
+ //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
1191
+ // user_error('Bad CRC in packet from server');
1192
+ // return false;
1193
+ //}
1194
+
1195
+ $type = ord($type);
1196
+
1197
+ if (defined('NET_SSH1_LOGGING')) {
1198
+ $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
1199
+ $temp = '<- ' . $temp .
1200
+ ' (' . round($stop - $start, 4) . 's)';
1201
+ $this->_append_log($temp, $data);
1202
+ }
1203
+
1204
+ return array(
1205
+ NET_SSH1_RESPONSE_TYPE => $type,
1206
+ NET_SSH1_RESPONSE_DATA => $data
1207
+ );
1208
+ }
1209
+
1210
+ /**
1211
+ * Sends Binary Packets
1212
+ *
1213
+ * Returns true on success, false on failure.
1214
+ *
1215
+ * @see self::_get_binary_packet()
1216
+ * @param string $data
1217
+ * @return bool
1218
+ * @access private
1219
+ */
1220
+ function _send_binary_packet($data)
1221
+ {
1222
+ if (feof($this->fsock)) {
1223
+ //user_error('connection closed prematurely');
1224
+ return false;
1225
+ }
1226
+
1227
+ $length = strlen($data) + 4;
1228
+
1229
+ $padding = crypt_random_string(8 - ($length & 7));
1230
+
1231
+ $orig = $data;
1232
+ $data = $padding . $data;
1233
+ $data.= pack('N', $this->_crc($data));
1234
+
1235
+ if ($this->crypto !== false) {
1236
+ $data = $this->crypto->encrypt($data);
1237
+ }
1238
+
1239
+ $packet = pack('Na*', $length, $data);
1240
+
1241
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1242
+ $result = strlen($packet) == fputs($this->fsock, $packet);
1243
+ $stop = strtok(microtime(), ' ') + strtok('');
1244
+
1245
+ if (defined('NET_SSH1_LOGGING')) {
1246
+ $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
1247
+ $temp = '-> ' . $temp .
1248
+ ' (' . round($stop - $start, 4) . 's)';
1249
+ $this->_append_log($temp, $orig);
1250
+ }
1251
+
1252
+ return $result;
1253
+ }
1254
+
1255
+ /**
1256
+ * Cyclic Redundancy Check (CRC)
1257
+ *
1258
+ * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
1259
+ * we've reimplemented it. A more detailed discussion of the differences can be found after
1260
+ * $crc_lookup_table's initialization.
1261
+ *
1262
+ * @see self::_get_binary_packet()
1263
+ * @see self::_send_binary_packet()
1264
+ * @param string $data
1265
+ * @return int
1266
+ * @access private
1267
+ */
1268
+ function _crc($data)
1269
+ {
1270
+ static $crc_lookup_table = array(
1271
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1272
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1273
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1274
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1275
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1276
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1277
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1278
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1279
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1280
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1281
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1282
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1283
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1284
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1285
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1286
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1287
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1288
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1289
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1290
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1291
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1292
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1293
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1294
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1295
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1296
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1297
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1298
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1299
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1300
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1301
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1302
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1303
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1304
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1305
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1306
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1307
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1308
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1309
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1310
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1311
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1312
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1313
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1314
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1315
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1316
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1317
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1318
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1319
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1320
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1321
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1322
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1323
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1324
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1325
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1326
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1327
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1328
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1329
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1330
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1331
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1332
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1333
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1334
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1335
+ );
1336
+
1337
+ // For this function to yield the same output as PHP's crc32 function, $crc would have to be
1338
+ // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
1339
+ $crc = 0x00000000;
1340
+ $length = strlen($data);
1341
+
1342
+ for ($i=0; $i<$length; $i++) {
1343
+ // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
1344
+ // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
1345
+ // yields 0xFF800000 - not 0x00800000. The following link elaborates:
1346
+ // http://www.php.net/manual/en/language.operators.bitwise.php#57281
1347
+ $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
1348
+ }
1349
+
1350
+ // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
1351
+ // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
1352
+ return $crc;
1353
+ }
1354
+
1355
+ /**
1356
+ * String Shift
1357
+ *
1358
+ * Inspired by array_shift
1359
+ *
1360
+ * @param string $string
1361
+ * @param int $index
1362
+ * @return string
1363
+ * @access private
1364
+ */
1365
+ function _string_shift(&$string, $index = 1)
1366
+ {
1367
+ $substr = substr($string, 0, $index);
1368
+ $string = substr($string, $index);
1369
+ return $substr;
1370
+ }
1371
+
1372
+ /**
1373
+ * RSA Encrypt
1374
+ *
1375
+ * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1376
+ * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
1377
+ * calls this call modexp, instead, but I think this makes things clearer, maybe...
1378
+ *
1379
+ * @see self::Net_SSH1()
1380
+ * @param Math_BigInteger $m
1381
+ * @param array $key
1382
+ * @return Math_BigInteger
1383
+ * @access private
1384
+ */
1385
+ function _rsa_crypt($m, $key)
1386
+ {
1387
+ /*
1388
+ if (!class_exists('Crypt_RSA')) {
1389
+ include_once 'Crypt/RSA.php';
1390
+ }
1391
+
1392
+ $rsa = new Crypt_RSA();
1393
+ $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
1394
+ $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
1395
+ return $rsa->encrypt($m);
1396
+ */
1397
+
1398
+ // To quote from protocol-1.5.txt:
1399
+ // The most significant byte (which is only partial as the value must be
1400
+ // less than the public modulus, which is never a power of two) is zero.
1401
+ //
1402
+ // The next byte contains the value 2 (which stands for public-key
1403
+ // encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
1404
+ // zero random bytes to fill any unused space, a zero byte, and the data
1405
+ // to be encrypted in the least significant bytes, the last byte of the
1406
+ // data in the least significant byte.
1407
+
1408
+ // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1409
+ // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1410
+ // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1411
+ $modulus = $key[1]->toBytes();
1412
+ $length = strlen($modulus) - strlen($m) - 3;
1413
+ $random = '';
1414
+ while (strlen($random) != $length) {
1415
+ $block = crypt_random_string($length - strlen($random));
1416
+ $block = str_replace("\x00", '', $block);
1417
+ $random.= $block;
1418
+ }
1419
+ $temp = chr(0) . chr(2) . $random . chr(0) . $m;
1420
+
1421
+ $m = new Math_BigInteger($temp, 256);
1422
+ $m = $m->modPow($key[0], $key[1]);
1423
+
1424
+ return $m->toBytes();
1425
+ }
1426
+
1427
+ /**
1428
+ * Define Array
1429
+ *
1430
+ * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
1431
+ * named constants from it, using the value as the name of the constant and the index as the value of the constant.
1432
+ * If any of the constants that would be defined already exists, none of the constants will be defined.
1433
+ *
1434
+ * @param array $array
1435
+ * @access private
1436
+ */
1437
+ function _define_array()
1438
+ {
1439
+ $args = func_get_args();
1440
+ foreach ($args as $arg) {
1441
+ foreach ($arg as $key => $value) {
1442
+ if (!defined($value)) {
1443
+ define($value, $key);
1444
+ } else {
1445
+ break 2;
1446
+ }
1447
+ }
1448
+ }
1449
+ }
1450
+
1451
+ /**
1452
+ * Returns a log of the packets that have been sent and received.
1453
+ *
1454
+ * Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
1455
+ *
1456
+ * @access public
1457
+ * @return array|false|string
1458
+ */
1459
+ function getLog()
1460
+ {
1461
+ if (!defined('NET_SSH1_LOGGING')) {
1462
+ return false;
1463
+ }
1464
+
1465
+ switch (NET_SSH1_LOGGING) {
1466
+ case NET_SSH1_LOG_SIMPLE:
1467
+ return $this->message_number_log;
1468
+ break;
1469
+ case NET_SSH1_LOG_COMPLEX:
1470
+ return $this->_format_log($this->message_log, $this->protocol_flags_log);
1471
+ break;
1472
+ default:
1473
+ return false;
1474
+ }
1475
+ }
1476
+
1477
+ /**
1478
+ * Formats a log for printing
1479
+ *
1480
+ * @param array $message_log
1481
+ * @param array $message_number_log
1482
+ * @access private
1483
+ * @return string
1484
+ */
1485
+ function _format_log($message_log, $message_number_log)
1486
+ {
1487
+ $output = '';
1488
+ for ($i = 0; $i < count($message_log); $i++) {
1489
+ $output.= $message_number_log[$i] . "\r\n";
1490
+ $current_log = $message_log[$i];
1491
+ $j = 0;
1492
+ do {
1493
+ if (strlen($current_log)) {
1494
+ $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
1495
+ }
1496
+ $fragment = $this->_string_shift($current_log, $this->log_short_width);
1497
+ $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
1498
+ // replace non ASCII printable characters with dots
1499
+ // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
1500
+ // also replace < with a . since < messes up the output on web browsers
1501
+ $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
1502
+ $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
1503
+ $j++;
1504
+ } while (strlen($current_log));
1505
+ $output.= "\r\n";
1506
+ }
1507
+
1508
+ return $output;
1509
+ }
1510
+
1511
+ /**
1512
+ * Helper function for _format_log
1513
+ *
1514
+ * For use with preg_replace_callback()
1515
+ *
1516
+ * @param array $matches
1517
+ * @access private
1518
+ * @return string
1519
+ */
1520
+ function _format_log_helper($matches)
1521
+ {
1522
+ return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
1523
+ }
1524
+
1525
+ /**
1526
+ * Return the server key public exponent
1527
+ *
1528
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1529
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1530
+ *
1531
+ * @param bool $raw_output
1532
+ * @return string
1533
+ * @access public
1534
+ */
1535
+ function getServerKeyPublicExponent($raw_output = false)
1536
+ {
1537
+ return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
1538
+ }
1539
+
1540
+ /**
1541
+ * Return the server key public modulus
1542
+ *
1543
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1544
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1545
+ *
1546
+ * @param bool $raw_output
1547
+ * @return string
1548
+ * @access public
1549
+ */
1550
+ function getServerKeyPublicModulus($raw_output = false)
1551
+ {
1552
+ return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
1553
+ }
1554
+
1555
+ /**
1556
+ * Return the host key public exponent
1557
+ *
1558
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1559
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1560
+ *
1561
+ * @param bool $raw_output
1562
+ * @return string
1563
+ * @access public
1564
+ */
1565
+ function getHostKeyPublicExponent($raw_output = false)
1566
+ {
1567
+ return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
1568
+ }
1569
+
1570
+ /**
1571
+ * Return the host key public modulus
1572
+ *
1573
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1574
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1575
+ *
1576
+ * @param bool $raw_output
1577
+ * @return string
1578
+ * @access public
1579
+ */
1580
+ function getHostKeyPublicModulus($raw_output = false)
1581
+ {
1582
+ return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
1583
+ }
1584
+
1585
+ /**
1586
+ * Return a list of ciphers supported by SSH1 server.
1587
+ *
1588
+ * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1589
+ * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
1590
+ * get array(NET_SSH1_CIPHER_3DES).
1591
+ *
1592
+ * @param bool $raw_output
1593
+ * @return array
1594
+ * @access public
1595
+ */
1596
+ function getSupportedCiphers($raw_output = false)
1597
+ {
1598
+ return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
1599
+ }
1600
+
1601
+ /**
1602
+ * Return a list of authentications supported by SSH1 server.
1603
+ *
1604
+ * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1605
+ * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
1606
+ * get array(NET_SSH1_AUTH_PASSWORD).
1607
+ *
1608
+ * @param bool $raw_output
1609
+ * @return array
1610
+ * @access public
1611
+ */
1612
+ function getSupportedAuthentications($raw_output = false)
1613
+ {
1614
+ return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
1615
+ }
1616
+
1617
+ /**
1618
+ * Return the server identification.
1619
+ *
1620
+ * @return string
1621
+ * @access public
1622
+ */
1623
+ function getServerIdentification()
1624
+ {
1625
+ return rtrim($this->server_identification);
1626
+ }
1627
+
1628
+ /**
1629
+ * Logs data packets
1630
+ *
1631
+ * Makes sure that only the last 1MB worth of packets will be logged
1632
+ *
1633
+ * @param string $data
1634
+ * @access private
1635
+ */
1636
+ function _append_log($protocol_flags, $message)
1637
+ {
1638
+ switch (NET_SSH1_LOGGING) {
1639
+ // useful for benchmarks
1640
+ case NET_SSH1_LOG_SIMPLE:
1641
+ $this->protocol_flags_log[] = $protocol_flags;
1642
+ break;
1643
+ // the most useful log for SSH1
1644
+ case NET_SSH1_LOG_COMPLEX:
1645
+ $this->protocol_flags_log[] = $protocol_flags;
1646
+ $this->_string_shift($message);
1647
+ $this->log_size+= strlen($message);
1648
+ $this->message_log[] = $message;
1649
+ while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) {
1650
+ $this->log_size-= strlen(array_shift($this->message_log));
1651
+ array_shift($this->protocol_flags_log);
1652
+ }
1653
+ break;
1654
+ // dump the output out realtime; packets may be interspersed with non packets,
1655
+ // passwords won't be filtered out and select other packets may not be correctly
1656
+ // identified
1657
+ case NET_SSH1_LOG_REALTIME:
1658
+ echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
1659
+ @flush();
1660
+ @ob_flush();
1661
+ break;
1662
+ // basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE
1663
+ // needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE.
1664
+ // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
1665
+ // at the beginning of the file
1666
+ case NET_SSH1_LOG_REALTIME_FILE:
1667
+ if (!isset($this->realtime_log_file)) {
1668
+ // PHP doesn't seem to like using constants in fopen()
1669
+ $filename = NET_SSH1_LOG_REALTIME_FILE;
1670
+ $fp = fopen($filename, 'w');
1671
+ $this->realtime_log_file = $fp;
1672
+ }
1673
+ if (!is_resource($this->realtime_log_file)) {
1674
+ break;
1675
+ }
1676
+ $entry = $this->_format_log(array($message), array($protocol_flags));
1677
+ if ($this->realtime_log_wrap) {
1678
+ $temp = "<<< START >>>\r\n";
1679
+ $entry.= $temp;
1680
+ fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
1681
+ }
1682
+ $this->realtime_log_size+= strlen($entry);
1683
+ if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) {
1684
+ fseek($this->realtime_log_file, 0);
1685
+ $this->realtime_log_size = strlen($entry);
1686
+ $this->realtime_log_wrap = true;
1687
+ }
1688
+ fputs($this->realtime_log_file, $entry);
1689
+ }
1690
+ }
1691
+ }
phpseclib/Net/SSH2.php CHANGED
@@ -3726,31 +3726,80 @@ class Net_SSH2
3726
  $this->window_size_server_to_client[$channel]+= $this->window_size;
3727
  }
3728
 
3729
- if ($type == NET_SSH2_MSG_CHANNEL_EXTENDED_DATA) {
3730
- /*
3731
- if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
3732
- $this->_send_channel_packet($client_channel, chr(0));
3733
- }
3734
- */
3735
- // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
3736
- if (strlen($response) < 8) {
3737
- return false;
3738
- }
3739
- extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
3740
- $data = $this->_string_shift($response, $length);
3741
- $this->stdErrorLog.= $data;
3742
- if ($skip_extended || $this->quiet_mode) {
3743
- continue;
3744
- }
3745
- if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
3746
- return $data;
3747
- }
3748
- if (!isset($this->channel_buffers[$channel])) {
3749
- $this->channel_buffers[$channel] = array();
3750
- }
3751
- $this->channel_buffers[$channel][] = $data;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3752
 
3753
- continue;
 
 
 
 
 
 
 
 
3754
  }
3755
 
3756
  switch ($this->channel_status[$channel]) {
@@ -3835,52 +3884,6 @@ class Net_SSH2
3835
  }
3836
  $this->channel_buffers[$channel][] = $data;
3837
  break;
3838
- case NET_SSH2_MSG_CHANNEL_REQUEST:
3839
- if (strlen($response) < 4) {
3840
- return false;
3841
- }
3842
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
3843
- $value = $this->_string_shift($response, $length);
3844
- switch ($value) {
3845
- case 'exit-signal':
3846
- $this->_string_shift($response, 1);
3847
- if (strlen($response) < 4) {
3848
- return false;
3849
- }
3850
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
3851
- $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
3852
- $this->_string_shift($response, 1);
3853
- if (strlen($response) < 4) {
3854
- return false;
3855
- }
3856
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
3857
- if ($length) {
3858
- $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
3859
- }
3860
-
3861
- $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
3862
- $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
3863
-
3864
- $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
3865
-
3866
- break;
3867
- case 'exit-status':
3868
- if (strlen($response) < 5) {
3869
- return false;
3870
- }
3871
- extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
3872
- $this->exit_status = $exit_status;
3873
-
3874
- // "The client MAY ignore these messages."
3875
- // -- http://tools.ietf.org/html/rfc4254#section-6.10
3876
-
3877
- break;
3878
- default:
3879
- // "Some systems may not implement signals, in which case they SHOULD ignore this message."
3880
- // -- http://tools.ietf.org/html/rfc4254#section-6.9
3881
- break;
3882
- }
3883
- break;
3884
  case NET_SSH2_MSG_CHANNEL_CLOSE:
3885
  $this->curTimeout = 0;
3886
 
3726
  $this->window_size_server_to_client[$channel]+= $this->window_size;
3727
  }
3728
 
3729
+ switch ($type) {
3730
+ case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
3731
+ /*
3732
+ if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
3733
+ $this->_send_channel_packet($client_channel, chr(0));
3734
+ }
3735
+ */
3736
+ // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
3737
+ if (strlen($response) < 8) {
3738
+ return false;
3739
+ }
3740
+ extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
3741
+ $data = $this->_string_shift($response, $length);
3742
+ $this->stdErrorLog.= $data;
3743
+ if ($skip_extended || $this->quiet_mode) {
3744
+ continue 2;
3745
+ }
3746
+ if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
3747
+ return $data;
3748
+ }
3749
+ if (!isset($this->channel_buffers[$channel])) {
3750
+ $this->channel_buffers[$channel] = array();
3751
+ }
3752
+ $this->channel_buffers[$channel][] = $data;
3753
+
3754
+ continue 2;
3755
+ case NET_SSH2_MSG_CHANNEL_REQUEST:
3756
+ if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
3757
+ continue 2;
3758
+ }
3759
+ if (strlen($response) < 4) {
3760
+ return false;
3761
+ }
3762
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
3763
+ $value = $this->_string_shift($response, $length);
3764
+ switch ($value) {
3765
+ case 'exit-signal':
3766
+ $this->_string_shift($response, 1);
3767
+ if (strlen($response) < 4) {
3768
+ return false;
3769
+ }
3770
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
3771
+ $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
3772
+ $this->_string_shift($response, 1);
3773
+ if (strlen($response) < 4) {
3774
+ return false;
3775
+ }
3776
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
3777
+ if ($length) {
3778
+ $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
3779
+ }
3780
+
3781
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
3782
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
3783
+
3784
+ $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
3785
+
3786
+ continue 3;
3787
+ case 'exit-status':
3788
+ if (strlen($response) < 5) {
3789
+ return false;
3790
+ }
3791
+ extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
3792
+ $this->exit_status = $exit_status;
3793
 
3794
+ // "The client MAY ignore these messages."
3795
+ // -- http://tools.ietf.org/html/rfc4254#section-6.10
3796
+
3797
+ continue 3;
3798
+ default:
3799
+ // "Some systems may not implement signals, in which case they SHOULD ignore this message."
3800
+ // -- http://tools.ietf.org/html/rfc4254#section-6.9
3801
+ continue 3;
3802
+ }
3803
  }
3804
 
3805
  switch ($this->channel_status[$channel]) {
3884
  }
3885
  $this->channel_buffers[$channel][] = $data;
3886
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3887
  case NET_SSH2_MSG_CHANNEL_CLOSE:
3888
  $this->curTimeout = 0;
3889
 
phpseclib/System/SSH/Agent.php ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP ssh-agent client.
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Here are some examples of how to use this library:
9
+ * <code>
10
+ * <?php
11
+ * include 'System/SSH/Agent.php';
12
+ * include 'Net/SSH2.php';
13
+ *
14
+ * $agent = new System_SSH_Agent();
15
+ *
16
+ * $ssh = new Net_SSH2('www.domain.tld');
17
+ * if (!$ssh->login('username', $agent)) {
18
+ * exit('Login Failed');
19
+ * }
20
+ *
21
+ * echo $ssh->exec('pwd');
22
+ * echo $ssh->exec('ls -la');
23
+ * ?>
24
+ * </code>
25
+ *
26
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
27
+ * of this software and associated documentation files (the "Software"), to deal
28
+ * in the Software without restriction, including without limitation the rights
29
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30
+ * copies of the Software, and to permit persons to whom the Software is
31
+ * furnished to do so, subject to the following conditions:
32
+ *
33
+ * The above copyright notice and this permission notice shall be included in
34
+ * all copies or substantial portions of the Software.
35
+ *
36
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42
+ * THE SOFTWARE.
43
+ *
44
+ * @category System
45
+ * @package System_SSH_Agent
46
+ * @author Jim Wigginton <terrafrost@php.net>
47
+ * @copyright 2014 Jim Wigginton
48
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
49
+ * @link http://phpseclib.sourceforge.net
50
+ * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
51
+ */
52
+
53
+ /**#@+
54
+ * Message numbers
55
+ *
56
+ * @access private
57
+ */
58
+ // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
59
+ define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
60
+ // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
61
+ define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
62
+ define('SYSTEM_SSH_AGENT_FAILURE', 5);
63
+ // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
64
+ define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
65
+ // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
66
+ define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
67
+
68
+
69
+ /**@+
70
+ * Agent forwarding status
71
+ *
72
+ * @access private
73
+ */
74
+ // no forwarding requested and not active
75
+ define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
76
+ // request agent forwarding when opportune
77
+ define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
78
+ // forwarding has been request and is active
79
+ define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
80
+
81
+ /**#@-*/
82
+
83
+ /**
84
+ * Pure-PHP ssh-agent client identity object
85
+ *
86
+ * Instantiation should only be performed by System_SSH_Agent class.
87
+ * This could be thought of as implementing an interface that Crypt_RSA
88
+ * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
89
+ * The methods in this interface would be getPublicKey, setSignatureMode
90
+ * and sign since those are the methods phpseclib looks for to perform
91
+ * public key authentication.
92
+ *
93
+ * @package System_SSH_Agent
94
+ * @author Jim Wigginton <terrafrost@php.net>
95
+ * @access internal
96
+ */
97
+ class System_SSH_Agent_Identity
98
+ {
99
+ /**
100
+ * Key Object
101
+ *
102
+ * @var Crypt_RSA
103
+ * @access private
104
+ * @see self::getPublicKey()
105
+ */
106
+ var $key;
107
+
108
+ /**
109
+ * Key Blob
110
+ *
111
+ * @var string
112
+ * @access private
113
+ * @see self::sign()
114
+ */
115
+ var $key_blob;
116
+
117
+ /**
118
+ * Socket Resource
119
+ *
120
+ * @var resource
121
+ * @access private
122
+ * @see self::sign()
123
+ */
124
+ var $fsock;
125
+
126
+ /**
127
+ * Default Constructor.
128
+ *
129
+ * @param resource $fsock
130
+ * @return System_SSH_Agent_Identity
131
+ * @access private
132
+ */
133
+ function __construct($fsock)
134
+ {
135
+ $this->fsock = $fsock;
136
+ }
137
+
138
+ /**
139
+ * PHP4 compatible Default Constructor.
140
+ *
141
+ * @see self::__construct()
142
+ * @param resource $fsock
143
+ * @access public
144
+ */
145
+ function System_SSH_Agent_Identity($fsock)
146
+ {
147
+ $this->__construct($fsock);
148
+ }
149
+
150
+ /**
151
+ * Set Public Key
152
+ *
153
+ * Called by System_SSH_Agent::requestIdentities()
154
+ *
155
+ * @param Crypt_RSA $key
156
+ * @access private
157
+ */
158
+ function setPublicKey($key)
159
+ {
160
+ $this->key = $key;
161
+ $this->key->setPublicKey();
162
+ }
163
+
164
+ /**
165
+ * Set Public Key
166
+ *
167
+ * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
168
+ * but this saves a small amount of computation.
169
+ *
170
+ * @param string $key_blob
171
+ * @access private
172
+ */
173
+ function setPublicKeyBlob($key_blob)
174
+ {
175
+ $this->key_blob = $key_blob;
176
+ }
177
+
178
+ /**
179
+ * Get Public Key
180
+ *
181
+ * Wrapper for $this->key->getPublicKey()
182
+ *
183
+ * @param int $format optional
184
+ * @return mixed
185
+ * @access public
186
+ */
187
+ function getPublicKey($format = null)
188
+ {
189
+ return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
190
+ }
191
+
192
+ /**
193
+ * Set Signature Mode
194
+ *
195
+ * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
196
+ * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
197
+ *
198
+ * @param int $mode
199
+ * @access public
200
+ */
201
+ function setSignatureMode($mode)
202
+ {
203
+ }
204
+
205
+ /**
206
+ * Create a signature
207
+ *
208
+ * See "2.6.2 Protocol 2 private key signature request"
209
+ *
210
+ * @param string $message
211
+ * @return string
212
+ * @access public
213
+ */
214
+ function sign($message)
215
+ {
216
+ // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
217
+ $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
218
+ $packet = pack('Na*', strlen($packet), $packet);
219
+ if (strlen($packet) != fputs($this->fsock, $packet)) {
220
+ user_error('Connection closed during signing');
221
+ }
222
+
223
+ $length = current(unpack('N', fread($this->fsock, 4)));
224
+ $type = ord(fread($this->fsock, 1));
225
+ if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
226
+ user_error('Unable to retreive signature');
227
+ }
228
+
229
+ $signature_blob = fread($this->fsock, $length - 1);
230
+ // the only other signature format defined - ssh-dss - is the same length as ssh-rsa
231
+ // the + 12 is for the other various SSH added length fields
232
+ return substr($signature_blob, strlen('ssh-rsa') + 12);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Pure-PHP ssh-agent client identity factory
238
+ *
239
+ * requestIdentities() method pumps out System_SSH_Agent_Identity objects
240
+ *
241
+ * @package System_SSH_Agent
242
+ * @author Jim Wigginton <terrafrost@php.net>
243
+ * @access internal
244
+ */
245
+ class System_SSH_Agent
246
+ {
247
+ /**
248
+ * Socket Resource
249
+ *
250
+ * @var resource
251
+ * @access private
252
+ */
253
+ var $fsock;
254
+
255
+ /**
256
+ * Agent forwarding status
257
+ *
258
+ * @access private
259
+ */
260
+ var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
261
+
262
+ /**
263
+ * Buffer for accumulating forwarded authentication
264
+ * agent data arriving on SSH data channel destined
265
+ * for agent unix socket
266
+ *
267
+ * @access private
268
+ */
269
+ var $socket_buffer = '';
270
+
271
+ /**
272
+ * Tracking the number of bytes we are expecting
273
+ * to arrive for the agent socket on the SSH data
274
+ * channel
275
+ */
276
+ var $expected_bytes = 0;
277
+
278
+ /**
279
+ * Default Constructor
280
+ *
281
+ * @return System_SSH_Agent
282
+ * @access public
283
+ */
284
+ function __construct()
285
+ {
286
+ switch (true) {
287
+ case isset($_SERVER['SSH_AUTH_SOCK']):
288
+ $address = $_SERVER['SSH_AUTH_SOCK'];
289
+ break;
290
+ case isset($_ENV['SSH_AUTH_SOCK']):
291
+ $address = $_ENV['SSH_AUTH_SOCK'];
292
+ break;
293
+ default:
294
+ user_error('SSH_AUTH_SOCK not found');
295
+ return false;
296
+ }
297
+
298
+ $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
299
+ if (!$this->fsock) {
300
+ user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
301
+ }
302
+ }
303
+
304
+ /**
305
+ * PHP4 compatible Default Constructor.
306
+ *
307
+ * @see self::__construct()
308
+ * @access public
309
+ */
310
+ function System_SSH_Agent()
311
+ {
312
+ $this->__construct();
313
+ }
314
+
315
+ /**
316
+ * Request Identities
317
+ *
318
+ * See "2.5.2 Requesting a list of protocol 2 keys"
319
+ * Returns an array containing zero or more System_SSH_Agent_Identity objects
320
+ *
321
+ * @return array
322
+ * @access public
323
+ */
324
+ function requestIdentities()
325
+ {
326
+ if (!$this->fsock) {
327
+ return array();
328
+ }
329
+
330
+ $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
331
+ if (strlen($packet) != fputs($this->fsock, $packet)) {
332
+ user_error('Connection closed while requesting identities');
333
+ }
334
+
335
+ $length = current(unpack('N', fread($this->fsock, 4)));
336
+ $type = ord(fread($this->fsock, 1));
337
+ if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
338
+ user_error('Unable to request identities');
339
+ }
340
+
341
+ $identities = array();
342
+ $keyCount = current(unpack('N', fread($this->fsock, 4)));
343
+ for ($i = 0; $i < $keyCount; $i++) {
344
+ $length = current(unpack('N', fread($this->fsock, 4)));
345
+ $key_blob = fread($this->fsock, $length);
346
+ $key_str = 'ssh-rsa ' . base64_encode($key_blob);
347
+ $length = current(unpack('N', fread($this->fsock, 4)));
348
+ if ($length) {
349
+ $key_str.= ' ' . fread($this->fsock, $length);
350
+ }
351
+ $length = current(unpack('N', substr($key_blob, 0, 4)));
352
+ $key_type = substr($key_blob, 4, $length);
353
+ switch ($key_type) {
354
+ case 'ssh-rsa':
355
+ if (!class_exists('Crypt_RSA')) {
356
+ include_once 'Crypt/RSA.php';
357
+ }
358
+ $key = new Crypt_RSA();
359
+ $key->loadKey($key_str);
360
+ break;
361
+ case 'ssh-dss':
362
+ // not currently supported
363
+ break;
364
+ }
365
+ // resources are passed by reference by default
366
+ if (isset($key)) {
367
+ $identity = new System_SSH_Agent_Identity($this->fsock);
368
+ $identity->setPublicKey($key);
369
+ $identity->setPublicKeyBlob($key_blob);
370
+ $identities[] = $identity;
371
+ unset($key);
372
+ }
373
+ }
374
+
375
+ return $identities;
376
+ }
377
+
378
+ /**
379
+ * Signal that agent forwarding should
380
+ * be requested when a channel is opened
381
+ *
382
+ * @param Net_SSH2 $ssh
383
+ * @return bool
384
+ * @access public
385
+ */
386
+ function startSSHForwarding($ssh)
387
+ {
388
+ if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
389
+ $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Request agent forwarding of remote server
395
+ *
396
+ * @param Net_SSH2 $ssh
397
+ * @return bool
398
+ * @access private
399
+ */
400
+ function _request_forwarding($ssh)
401
+ {
402
+ $request_channel = $ssh->_get_open_channel();
403
+ if ($request_channel === false) {
404
+ return false;
405
+ }
406
+
407
+ $packet = pack(
408
+ 'CNNa*C',
409
+ NET_SSH2_MSG_CHANNEL_REQUEST,
410
+ $ssh->server_channels[$request_channel],
411
+ strlen('auth-agent-req@openssh.com'),
412
+ 'auth-agent-req@openssh.com',
413
+ 1
414
+ );
415
+
416
+ $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
417
+
418
+ if (!$ssh->_send_binary_packet($packet)) {
419
+ return false;
420
+ }
421
+
422
+ $response = $ssh->_get_channel_packet($request_channel);
423
+ if ($response === false) {
424
+ return false;
425
+ }
426
+
427
+ $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
428
+ $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
429
+
430
+ return true;
431
+ }
432
+
433
+ /**
434
+ * On successful channel open
435
+ *
436
+ * This method is called upon successful channel
437
+ * open to give the SSH Agent an opportunity
438
+ * to take further action. i.e. request agent forwarding
439
+ *
440
+ * @param Net_SSH2 $ssh
441
+ * @access private
442
+ */
443
+ function _on_channel_open($ssh)
444
+ {
445
+ if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
446
+ $this->_request_forwarding($ssh);
447
+ }
448
+ }
449
+
450
+ /**
451
+ * Forward data to SSH Agent and return data reply
452
+ *
453
+ * @param string $data
454
+ * @return data from SSH Agent
455
+ * @access private
456
+ */
457
+ function _forward_data($data)
458
+ {
459
+ if ($this->expected_bytes > 0) {
460
+ $this->socket_buffer.= $data;
461
+ $this->expected_bytes -= strlen($data);
462
+ } else {
463
+ $agent_data_bytes = current(unpack('N', $data));
464
+ $current_data_bytes = strlen($data);
465
+ $this->socket_buffer = $data;
466
+ if ($current_data_bytes != $agent_data_bytes + 4) {
467
+ $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
468
+ return false;
469
+ }
470
+ }
471
+
472
+ if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
473
+ user_error('Connection closed attempting to forward data to SSH agent');
474
+ }
475
+
476
+ $this->socket_buffer = '';
477
+ $this->expected_bytes = 0;
478
+
479
+ $agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
480
+
481
+ $agent_reply_data = fread($this->fsock, $agent_reply_bytes);
482
+ $agent_reply_data = current(unpack('a*', $agent_reply_data));
483
+
484
+ return pack('Na*', $agent_reply_bytes, $agent_reply_data);
485
+ }
486
+ }
phpseclib/System/SSH_Agent.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Pure-PHP ssh-agent client wrapper
4
+ *
5
+ * PHP versions 4 and 5
6
+ *
7
+ * Originally System_SSH_Agent was accessed as System/SSH_Agent.php instead of
8
+ * System/SSH/Agent.php. The problem with this is that PSR0 compatible autoloaders
9
+ * don't support that kind of directory layout hence the package being moved and
10
+ * this "alias" being created to maintain backwards compatibility.
11
+ *
12
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ * of this software and associated documentation files (the "Software"), to deal
14
+ * in the Software without restriction, including without limitation the rights
15
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ * copies of the Software, and to permit persons to whom the Software is
17
+ * furnished to do so, subject to the following conditions:
18
+ *
19
+ * The above copyright notice and this permission notice shall be included in
20
+ * all copies or substantial portions of the Software.
21
+ *
22
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
+ * THE SOFTWARE.
29
+ *
30
+ * @category System
31
+ * @package System_SSH_Agent
32
+ * @author Jim Wigginton <terrafrost@php.net>
33
+ * @copyright 2014 Jim Wigginton
34
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
35
+ * @link http://phpseclib.sourceforge.net
36
+ * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
37
+ */
38
+
39
+ require_once 'SSH/Agent.php';
phpseclib/bootstrap.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Bootstrapping File for phpseclib
4
+ *
5
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
6
+ */
7
+
8
+ if (extension_loaded('mbstring')) {
9
+ // 2 - MB_OVERLOAD_STRING
10
+ if (ini_get('mbstring.func_overload') & 2) {
11
+ throw new \UnexpectedValueException(
12
+ 'Overloading of string functions using mbstring.func_overload ' .
13
+ 'is not supported by phpseclib.'
14
+ );
15
+ }
16
+ }
phpseclib/openssl.cnf ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # minimalist openssl.cnf file for use with phpseclib
2
+
3
+ HOME = .
4
+ RANDFILE = $ENV::HOME/.rnd
5
+
6
+ [ v3_ca ]
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === SSH SFTP Updater Support ===
2
- Contributors: TerraFrost
3
  Donate link: http://sourceforge.net/donate/index.php?group_id=198487
4
  Tags: ssh, sftp
5
  Requires at least: 3.1
6
- Tested up to: 4.9.1
7
- Stable tag: 0.7.2
8
 
9
  "SSH SFTP Updater Support" is the easiest way to keep your Wordpress installation up-to-date with SFTP.
10
 
@@ -19,6 +19,13 @@ Keeping your Wordpress install up-to-date and installing plugins in a hassle-fre
19
 
20
  == Changelog ==
21
 
 
 
 
 
 
 
 
22
  = 0.7.2 =
23
  * update phpseclib to latest version
24
 
@@ -56,3 +63,6 @@ Keeping your Wordpress install up-to-date and installing plugins in a hassle-fre
56
 
57
  = 0.1 =
58
  * Initial Release
 
 
 
1
  === SSH SFTP Updater Support ===
2
+ Contributors: TerraFrost, DavidAnderson
3
  Donate link: http://sourceforge.net/donate/index.php?group_id=198487
4
  Tags: ssh, sftp
5
  Requires at least: 3.1
6
+ Tested up to: 4.9
7
+ Stable tag: 0.7.3
8
 
9
  "SSH SFTP Updater Support" is the easiest way to keep your Wordpress installation up-to-date with SFTP.
10
 
19
 
20
  == Changelog ==
21
 
22
+ = 0.7.3 =
23
+
24
+ * TWEAK: Update phpseclib to latest version (1.0.10)
25
+ * TWEAK: Ship complete phpseclib library so that other plugins using it after we have loaded it don't have problems
26
+ * TWEAK: Some minor internal re-factoring
27
+ * TWEAK: Adds a dismissable (and won't reappear for 12 months) notice about other plugins users may be interested in.
28
+
29
  = 0.7.2 =
30
  * update phpseclib to latest version
31
 
63
 
64
  = 0.1 =
65
  * Initial Release
66
+
67
+ == Upgrade Notice ==
68
+ * 1.14.4: Update phpseclib to latest version (1.0.10)
sftp.php CHANGED
@@ -1,255 +1,530 @@
1
- <?php
2
- /*
3
- Plugin Name: SSH SFTP Updater Support
4
- Plugin URI: http://phpseclib.sourceforge.net/wordpress.htm
5
- Description: Update your Wordpress blog / plugins via SFTP without libssh2
6
- Version: 0.7.2
7
- Author: TerraFrost
8
- Author URI: http://phpseclib.sourceforge.net/
9
- */
10
-
11
- // see http://adambrown.info/p/wp_hooks/hook/<filter name>
12
- add_filter('filesystem_method', 'phpseclib_filesystem_method', 10, 2); // since 2.6 - WordPress will ignore the ssh option if the php ssh extension is not loaded
13
- add_filter('request_filesystem_credentials', 'phpseclib_request_filesystem_credentials', 10, 1024); // since 2.5 - Alter some strings and don't ask for the public key
14
- add_filter('fs_ftp_connection_types', 'phpseclib_fs_ftp_connection_types'); // since 2.9 - Add the SSH2 option to the connection options
15
- add_filter('filesystem_method_file', 'phpseclib_filesystem_method_file', 10, 2); // since 2.6 - Direct WordPress to use our ssh2 class
16
- if (version_compare(get_bloginfo('version'), '4.2.0') >= 0) // disable the modal dialog on Wordpress >= 4.2
17
- add_action('admin_head-plugins.php', 'phpseclib_disable_update_link_onclick');
18
-
19
- function phpseclib_disable_update_link_onclick() {
20
- ?>
21
- <script type="text/javascript">
22
- jQuery(function($){
23
- jQuery(".plugin-update-tr").off("click", ".update-link");
24
- });
25
- </script>
26
- <?php
27
- }
28
-
29
- function phpseclib_filesystem_method_file($path, $method) {
30
- return $method == 'ssh2' ?
31
- dirname(__FILE__) . '/class-wp-filesystem-ssh2.php' :
32
- $path;
33
- }
34
-
35
- function phpseclib_filesystem_method($method, $args) {
36
- return ( isset($args['connection_type']) && 'ssh' == $args['connection_type'] ) ? 'ssh2' : $method;
37
- }
38
-
39
- function phpseclib_fs_ftp_connection_types($types) {
40
- $types['ssh'] = __('SSH2');
41
- return $types;
42
- }
43
-
44
- // this has been pretty much copy / pasted from wp-admin/includes/file.php
45
- function phpseclib_request_filesystem_credentials($value, $form_post, $type = '', $error = false, $context = false, $extra_fields = null, $allow_relaxed_file_ownership = false) {
46
- if ( empty($type) )
47
- $type = get_filesystem_method(array(), $context, $allow_relaxed_file_ownership);
48
-
49
- if ( 'direct' == $type )
50
- return true;
51
-
52
- if ( is_null( $extra_fields ) )
53
- $extra_fields = array( 'version', 'locale' );
54
-
55
- $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
56
-
57
- // If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
58
- $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? stripslashes($_POST['hostname']) : $credentials['hostname']);
59
- $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? stripslashes($_POST['username']) : $credentials['username']);
60
- $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? stripslashes($_POST['password']) : '');
61
-
62
- // Check to see if we are setting the private key for ssh
63
- if (defined('FTP_PRIKEY') && file_exists(FTP_PRIKEY)) {
64
- $credentials['private_key'] = file_get_contents(FTP_PRIKEY);
65
- } else {
66
- $credentials['private_key'] = (!empty($_POST['private_key'])) ? stripslashes($_POST['private_key']) : '';
67
- if (isset($_FILES['private_key_file']) && file_exists($_FILES['private_key_file']['tmp_name'])) {
68
- $credentials['private_key'] = file_get_contents($_FILES['private_key_file']['tmp_name']);
69
- }
70
- }
71
-
72
- //sanitize the hostname, Some people might pass in odd-data:
73
- $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
74
-
75
- if ( strpos($credentials['hostname'], ':') ) {
76
- list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
77
- if ( ! is_numeric($credentials['port']) )
78
- unset($credentials['port']);
79
- } else {
80
- unset($credentials['port']);
81
- }
82
-
83
- if ( (defined('FTP_SSH') && FTP_SSH) || (defined('FS_METHOD') && 'ssh' == FS_METHOD) )
84
- $credentials['connection_type'] = 'ssh';
85
- else if ( (defined('FTP_SSL') && FTP_SSL) && 'ftpext' == $type ) //Only the FTP Extension understands SSL
86
- $credentials['connection_type'] = 'ftps';
87
- else if ( !empty($_POST['connection_type']) )
88
- $credentials['connection_type'] = stripslashes($_POST['connection_type']);
89
- else if ( !isset($credentials['connection_type']) ) //All else fails (And its not defaulted to something else saved), Default to FTP
90
- $credentials['connection_type'] = 'ftp';
91
-
92
- if ( ! $error &&
93
- (
94
- ( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
95
- ( 'ssh' == $credentials['connection_type'] && !empty($credentials['private_key']) )
96
- ) ) {
97
- $stored_credentials = $credentials;
98
- if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
99
- $stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
100
-
101
- unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
102
- if ( ! defined( 'WP_INSTALLING' ) ) {
103
- update_option( 'ftp_credentials', $stored_credentials );
104
- }
105
- return $credentials;
106
- }
107
- $hostname = isset( $credentials['hostname'] ) ? $credentials['hostname'] : '';
108
- $username = isset( $credentials['username'] ) ? $credentials['username'] : '';
109
- $public_key = isset( $credentials['public_key'] ) ? $credentials['public_key'] : '';
110
- $private_key = isset( $credentials['private_key'] ) ? $credentials['private_key'] : '';
111
- $port = isset( $credentials['port'] ) ? $credentials['port'] : '';
112
- $connection_type = isset( $credentials['connection_type'] ) ? $credentials['connection_type'] : '';
113
-
114
- if ( $error ) {
115
- $error_string = __('<strong>ERROR:</strong> There was an error connecting to the server, Please verify the settings are correct.');
116
- if ( is_wp_error($error) ) {
117
- $error_strings = $error->get_error_messages();
118
- //foreach ( $error_strings as &$error_string )
119
- // $error_string = esc_html( $error_string );
120
- $error_string = implode('<br />', $error_strings);
121
- }
122
- echo '<div id="message" class="error"><p>' . $error_string . '</p></div>';
123
- }
124
-
125
- $types = array();
126
- if ( extension_loaded('ftp') || extension_loaded('sockets') || function_exists('fsockopen') )
127
- $types[ 'ftp' ] = __('FTP');
128
- if ( extension_loaded('ftp') ) //Only this supports FTPS
129
- $types[ 'ftps' ] = __('FTPS (SSL)');
130
-
131
- $types = apply_filters('fs_ftp_connection_types', $types, $credentials, $type, $error, $context);
132
-
133
- ?>
134
- <script type="text/javascript">
135
- <!--
136
- jQuery(function($){
137
- jQuery("#ssh").click(function () {
138
- jQuery(".ssh_keys").show();
139
- });
140
- jQuery("#ftp, #ftps").click(function () {
141
- jQuery(".ssh_keys").hide();
142
- });
143
- jQuery("#private_key_file").change(function (event) {
144
- if (window.File && window.FileReader) {
145
- var reader = new FileReader();
146
- reader.onload = function(file) {
147
- jQuery("#private_key").val(file.target.result);
148
- };
149
- reader.readAsBinaryString(event.target.files[0]);
150
- }
151
- });
152
- jQuery("form").submit(function () {
153
- if(typeof(Storage)!=="undefined") {
154
- localStorage.privateKeyFile = jQuery("#private_key").val();
155
- }
156
- jQuery("#private_key_file").attr("disabled", "disabled");
157
- });
158
- if(typeof(Storage)!=="undefined" && localStorage.privateKeyFile) {
159
- jQuery("#private_key").val(localStorage.privateKeyFile);
160
- }
161
- jQuery('form input[value=""]:first').focus();
162
- });
163
- -->
164
- </script>
165
- <form action="<?php echo $form_post ?>" method="post" enctype="multipart/form-data">
166
- <div class="wrap">
167
- <h2><?php _e('Connection Information') ?></h2>
168
- <p><?php
169
- $label_user = __('Username');
170
- $label_pass = __('Password');
171
- _e('To perform the requested action, WordPress needs to access your web server.');
172
- echo ' ';
173
- if ( ( isset( $types['ftp'] ) || isset( $types['ftps'] ) ) ) {
174
- if ( isset( $types['ssh'] ) ) {
175
- _e('Please enter your FTP or SSH credentials to proceed.');
176
- $label_user = __('FTP/SSH Username');
177
- $label_pass = __('FTP/SSH Password');
178
- } else {
179
- _e('Please enter your FTP credentials to proceed.');
180
- $label_user = __('FTP Username');
181
- $label_pass = __('FTP Password');
182
- }
183
- echo ' ';
184
- }
185
- _e('If you do not remember your credentials, you should contact your web host.');
186
- ?></p>
187
- <table class="form-table">
188
- <tr valign="top">
189
- <th scope="row"><label for="hostname"><?php _e('Hostname') ?></label></th>
190
- <td><input name="hostname" type="text" id="hostname" value="<?php echo esc_attr($hostname); if ( !empty($port) ) echo ":$port"; ?>"<?php disabled( defined('FTP_HOST') ); ?> size="40" /></td>
191
- </tr>
192
-
193
- <tr valign="top">
194
- <th scope="row"><label for="username"><?php echo $label_user; ?></label></th>
195
- <td><input name="username" type="text" id="username" value="<?php echo esc_attr($username) ?>"<?php disabled( defined('FTP_USER') ); ?> size="40" /></td>
196
- </tr>
197
-
198
- <tr valign="top">
199
- <th scope="row"><label for="password"><?php echo $label_pass; ?></label></th>
200
- <td><input name="password" type="password" id="password" value="<?php if ( defined('FTP_PASS') ) echo '*****'; ?>"<?php disabled( defined('FTP_PASS') ); ?> size="40" /></td>
201
- </tr>
202
-
203
- <?php if ( isset($types['ssh']) ) : ?>
204
- <tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
205
- <th scope="row" colspan="2"><?php _e('SSH Authentication Keys') ?>
206
- <div><?php _e('If a passphrase is needed, enter that in the password field above.') ?></div></th></tr>
207
- <tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
208
- <th scope="row">
209
- <div class="key-labels textright">
210
- <label for="private_key"><?php _e('Copy / Paste Private Key:') ?></label>
211
- </div>
212
- </th>
213
- <td><textarea name="private_key" id="private_key" cols="58" rows="10" value="<?php echo esc_attr($private_key) ?>"<?php disabled( defined('FTP_PRIKEY') ); ?>></textarea>
214
- </td>
215
- </tr>
216
- <tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
217
- <th scope="row">
218
- <div class="key-labels textright">
219
- <label for="private_key_file"><?php _e('Upload Private Key:') ?></label>
220
- </div>
221
- </th>
222
- <td><input name="private_key_file" id="private_key_file" type="file" <?php disabled( defined('FTP_PRIKEY') ); ?>/>
223
- </td>
224
- </tr>
225
- <?php endif; ?>
226
-
227
- <tr valign="top">
228
- <th scope="row"><?php _e('Connection Type') ?></th>
229
- <td>
230
- <fieldset><legend class="screen-reader-text"><span><?php _e('Connection Type') ?></span></legend>
231
- <?php
232
- $disabled = disabled( (defined('FTP_SSL') && FTP_SSL) || (defined('FTP_SSH') && FTP_SSH), true, false );
233
- foreach ( $types as $name => $text ) : ?>
234
- <label for="<?php echo esc_attr($name) ?>">
235
- <input type="radio" name="connection_type" id="<?php echo esc_attr($name) ?>" value="<?php echo esc_attr($name) ?>"<?php checked($name, $connection_type); echo $disabled; ?> />
236
- <?php echo $text ?>
237
- </label>
238
- <?php endforeach; ?>
239
- </fieldset>
240
- </td>
241
- </tr>
242
- </table>
243
-
244
- <?php
245
- foreach ( (array) $extra_fields as $field ) {
246
- if ( isset( $_POST[ $field ] ) )
247
- echo '<input type="hidden" name="' . esc_attr( $field ) . '" value="' . esc_attr( stripslashes( $_POST[ $field ] ) ) . '" />';
248
- }
249
- submit_button( __( 'Proceed' ), 'button', 'upgrade' );
250
- ?>
251
- </div>
252
- </form>
253
- <?php
254
- return false;
255
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: SSH SFTP Updater Support
4
+ Plugin URI: https://wordpress.org/plugins/ssh-sftp-updater-support/
5
+ Description: Update your WordPress blog / plugins via SFTP without libssh2
6
+ Version: 0.7.3
7
+ Author: TerraFrost
8
+ Author URI: http://phpseclib.sourceforge.net/
9
+ */
10
+
11
+ if (!defined('ABSPATH')) die('No direct access allowed');
12
+
13
+ define('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH', plugin_dir_path(__FILE__));
14
+ define('SSH_SFTP_UPDATER_SUPPORT_VERSION', '0.7.3');
15
+ define('SSH_SFTP_UPDATER_SUPPORT_URL', plugin_dir_url(__FILE__));
16
+ // see http://adambrown.info/p/wp_hooks/hook/<filter name>
17
+ add_filter('filesystem_method', 'phpseclib_filesystem_method', 10, 2); // since 2.6 - WordPress will ignore the ssh option if the php ssh extension is not loaded
18
+ add_filter('request_filesystem_credentials', 'phpseclib_request_filesystem_credentials', 10, 1024); // since 2.5 - Alter some strings and don't ask for the public key
19
+ add_filter('fs_ftp_connection_types', 'phpseclib_fs_ftp_connection_types'); // since 2.9 - Add the SSH2 option to the connection options
20
+ add_filter('filesystem_method_file', 'phpseclib_filesystem_method_file', 10, 2); // since 2.6 - Direct WordPress to use our ssh2 class
21
+ if (version_compare(get_bloginfo('version'), '4.2.0') >= 0) // disable the modal dialog on WordPress >= 4.2
22
+ add_action('admin_head-plugins.php', 'phpseclib_disable_update_link_onclick');
23
+
24
+ function phpseclib_disable_update_link_onclick() {
25
+ ?>
26
+ <script type="text/javascript">
27
+ jQuery(function($){
28
+ jQuery(".plugin-update-tr").off("click", ".update-link");
29
+ });
30
+ </script>
31
+ <?php
32
+ }
33
+
34
+ function phpseclib_filesystem_method_file($path, $method) {
35
+ return $method == 'ssh2' ?
36
+ dirname(__FILE__) . '/class-wp-filesystem-ssh2.php' :
37
+ $path;
38
+ }
39
+
40
+ function phpseclib_filesystem_method($method, $args) {
41
+ return ( isset($args['connection_type']) && 'ssh' == $args['connection_type'] ) ? 'ssh2' : $method;
42
+ }
43
+
44
+ function phpseclib_fs_ftp_connection_types($types) {
45
+ $types['ssh'] = __('SSH2');
46
+ return $types;
47
+ }
48
+
49
+ // this has been pretty much copy / pasted from wp-admin/includes/file.php
50
+ function phpseclib_request_filesystem_credentials($value, $form_post, $type = '', $error = false, $context = false, $extra_fields = null, $allow_relaxed_file_ownership = false) {
51
+ if ( empty($type) )
52
+ $type = get_filesystem_method(array(), $context, $allow_relaxed_file_ownership);
53
+
54
+ if ( 'direct' == $type )
55
+ return true;
56
+
57
+ if ( is_null( $extra_fields ) )
58
+ $extra_fields = array( 'version', 'locale' );
59
+
60
+ $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
61
+
62
+ // If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
63
+ $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? stripslashes($_POST['hostname']) : $credentials['hostname']);
64
+ $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? stripslashes($_POST['username']) : $credentials['username']);
65
+ $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? stripslashes($_POST['password']) : '');
66
+
67
+ // Check to see if we are setting the private key for ssh
68
+ if (defined('FTP_PRIKEY') && file_exists(FTP_PRIKEY)) {
69
+ $credentials['private_key'] = file_get_contents(FTP_PRIKEY);
70
+ } else {
71
+ $credentials['private_key'] = (!empty($_POST['private_key'])) ? stripslashes($_POST['private_key']) : '';
72
+ if (isset($_FILES['private_key_file']) && file_exists($_FILES['private_key_file']['tmp_name'])) {
73
+ $credentials['private_key'] = file_get_contents($_FILES['private_key_file']['tmp_name']);
74
+ }
75
+ }
76
+
77
+ //sanitize the hostname, Some people might pass in odd-data:
78
+ $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
79
+
80
+ if ( strpos($credentials['hostname'], ':') ) {
81
+ list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
82
+ if ( ! is_numeric($credentials['port']) )
83
+ unset($credentials['port']);
84
+ } else {
85
+ unset($credentials['port']);
86
+ }
87
+
88
+ if ( (defined('FTP_SSH') && FTP_SSH) || (defined('FS_METHOD') && 'ssh' == FS_METHOD) )
89
+ $credentials['connection_type'] = 'ssh';
90
+ else if ( (defined('FTP_SSL') && FTP_SSL) && 'ftpext' == $type ) //Only the FTP Extension understands SSL
91
+ $credentials['connection_type'] = 'ftps';
92
+ else if ( !empty($_POST['connection_type']) )
93
+ $credentials['connection_type'] = stripslashes($_POST['connection_type']);
94
+ else if ( !isset($credentials['connection_type']) ) //All else fails (And its not defaulted to something else saved), Default to FTP
95
+ $credentials['connection_type'] = 'ftp';
96
+
97
+ if ( ! $error &&
98
+ (
99
+ ( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
100
+ ( 'ssh' == $credentials['connection_type'] && !empty($credentials['private_key']) )
101
+ ) ) {
102
+ $stored_credentials = $credentials;
103
+ if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
104
+ $stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
105
+
106
+ unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
107
+ if ( ! defined( 'WP_INSTALLING' ) ) {
108
+ update_option( 'ftp_credentials', $stored_credentials );
109
+ }
110
+ return $credentials;
111
+ }
112
+ $hostname = isset( $credentials['hostname'] ) ? $credentials['hostname'] : '';
113
+ $username = isset( $credentials['username'] ) ? $credentials['username'] : '';
114
+ $public_key = isset( $credentials['public_key'] ) ? $credentials['public_key'] : '';
115
+ $private_key = isset( $credentials['private_key'] ) ? $credentials['private_key'] : '';
116
+ $port = isset( $credentials['port'] ) ? $credentials['port'] : '';
117
+ $connection_type = isset( $credentials['connection_type'] ) ? $credentials['connection_type'] : '';
118
+
119
+ if ( $error ) {
120
+ $error_string = __('<strong>ERROR:</strong> There was an error connecting to the server, Please verify the settings are correct.');
121
+ if ( is_wp_error($error) ) {
122
+ $error_strings = $error->get_error_messages();
123
+ //foreach ( $error_strings as &$error_string )
124
+ // $error_string = esc_html( $error_string );
125
+ $error_string = implode('<br />', $error_strings);
126
+ }
127
+ echo '<div id="message" class="error"><p>' . $error_string . '</p></div>';
128
+ }
129
+
130
+ $types = array();
131
+ if ( extension_loaded('ftp') || extension_loaded('sockets') || function_exists('fsockopen') )
132
+ $types[ 'ftp' ] = __('FTP');
133
+ if ( extension_loaded('ftp') ) //Only this supports FTPS
134
+ $types[ 'ftps' ] = __('FTPS (SSL)');
135
+
136
+ $types = apply_filters('fs_ftp_connection_types', $types, $credentials, $type, $error, $context);
137
+
138
+ ?>
139
+ <script type="text/javascript">
140
+ <!--
141
+ jQuery(function($){
142
+ jQuery("#ssh").click(function () {
143
+ jQuery(".ssh_keys").show();
144
+ });
145
+ jQuery("#ftp, #ftps").click(function () {
146
+ jQuery(".ssh_keys").hide();
147
+ });
148
+ jQuery("#private_key_file").change(function (event) {
149
+ if (window.File && window.FileReader) {
150
+ var reader = new FileReader();
151
+ reader.onload = function(file) {
152
+ jQuery("#private_key").val(file.target.result);
153
+ };
154
+ reader.readAsBinaryString(event.target.files[0]);
155
+ }
156
+ });
157
+ jQuery("form").submit(function () {
158
+ if(typeof(Storage)!=="undefined") {
159
+ localStorage.privateKeyFile = jQuery("#private_key").val();
160
+ }
161
+ jQuery("#private_key_file").attr("disabled", "disabled");
162
+ });
163
+ if(typeof(Storage)!=="undefined" && localStorage.privateKeyFile) {
164
+ jQuery("#private_key").val(localStorage.privateKeyFile);
165
+ }
166
+ jQuery('form input[value=""]:first').focus();
167
+ });
168
+ -->
169
+ </script>
170
+ <form action="<?php echo $form_post ?>" method="post" enctype="multipart/form-data">
171
+ <div class="wrap">
172
+ <h2><?php _e('Connection Information') ?></h2>
173
+ <p><?php
174
+ $label_user = __('Username');
175
+ $label_pass = __('Password');
176
+ _e('To perform the requested action, WordPress needs to access your web server.');
177
+ echo ' ';
178
+ if ( ( isset( $types['ftp'] ) || isset( $types['ftps'] ) ) ) {
179
+ if ( isset( $types['ssh'] ) ) {
180
+ _e('Please enter your FTP or SSH credentials to proceed.');
181
+ $label_user = __('FTP/SSH Username');
182
+ $label_pass = __('FTP/SSH Password');
183
+ } else {
184
+ _e('Please enter your FTP credentials to proceed.');
185
+ $label_user = __('FTP Username');
186
+ $label_pass = __('FTP Password');
187
+ }
188
+ echo ' ';
189
+ }
190
+ _e('If you do not remember your credentials, you should contact your web host.');
191
+ ?></p>
192
+ <table class="form-table">
193
+ <tr valign="top">
194
+ <th scope="row"><label for="hostname"><?php _e('Hostname') ?></label></th>
195
+ <td><input name="hostname" type="text" id="hostname" value="<?php echo esc_attr($hostname); if ( !empty($port) ) echo ":$port"; ?>"<?php disabled( defined('FTP_HOST') ); ?> size="40" /></td>
196
+ </tr>
197
+
198
+ <tr valign="top">
199
+ <th scope="row"><label for="username"><?php echo $label_user; ?></label></th>
200
+ <td><input name="username" type="text" id="username" value="<?php echo esc_attr($username) ?>"<?php disabled( defined('FTP_USER') ); ?> size="40" /></td>
201
+ </tr>
202
+
203
+ <tr valign="top">
204
+ <th scope="row"><label for="password"><?php echo $label_pass; ?></label></th>
205
+ <td><input name="password" type="password" id="password" value="<?php if ( defined('FTP_PASS') ) echo '*****'; ?>"<?php disabled( defined('FTP_PASS') ); ?> size="40" /></td>
206
+ </tr>
207
+
208
+ <?php if ( isset($types['ssh']) ) : ?>
209
+ <tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
210
+ <th scope="row" colspan="2"><?php _e('SSH Authentication Keys') ?>
211
+ <div><?php _e('If a passphrase is needed, enter that in the password field above.') ?></div></th></tr>
212
+ <tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
213
+ <th scope="row">
214
+ <div class="key-labels textright">
215
+ <label for="private_key"><?php _e('Copy / Paste Private Key:') ?></label>
216
+ </div>
217
+ </th>
218
+ <td><textarea name="private_key" id="private_key" cols="58" rows="10" value="<?php echo esc_attr($private_key) ?>"<?php disabled( defined('FTP_PRIKEY') ); ?>></textarea>
219
+ </td>
220
+ </tr>
221
+ <tr class="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
222
+ <th scope="row">
223
+ <div class="key-labels textright">
224
+ <label for="private_key_file"><?php _e('Upload Private Key:') ?></label>
225
+ </div>
226
+ </th>
227
+ <td><input name="private_key_file" id="private_key_file" type="file" <?php disabled( defined('FTP_PRIKEY') ); ?>/>
228
+ </td>
229
+ </tr>
230
+ <?php endif; ?>
231
+
232
+ <tr valign="top">
233
+ <th scope="row"><?php _e('Connection Type') ?></th>
234
+ <td>
235
+ <fieldset><legend class="screen-reader-text"><span><?php _e('Connection Type') ?></span></legend>
236
+ <?php
237
+ $disabled = disabled( (defined('FTP_SSL') && FTP_SSL) || (defined('FTP_SSH') && FTP_SSH), true, false );
238
+ foreach ( $types as $name => $text ) : ?>
239
+ <label for="<?php echo esc_attr($name) ?>">
240
+ <input type="radio" name="connection_type" id="<?php echo esc_attr($name) ?>" value="<?php echo esc_attr($name) ?>"<?php checked($name, $connection_type); echo $disabled; ?> />
241
+ <?php echo $text ?>
242
+ </label>
243
+ <?php endforeach; ?>
244
+ </fieldset>
245
+ </td>
246
+ </tr>
247
+ </table>
248
+
249
+ <?php
250
+ foreach ( (array) $extra_fields as $field ) {
251
+ if ( isset( $_POST[ $field ] ) )
252
+ echo '<input type="hidden" name="' . esc_attr( $field ) . '" value="' . esc_attr( stripslashes( $_POST[ $field ] ) ) . '" />';
253
+ }
254
+ submit_button( __( 'Proceed' ), 'button', 'upgrade' );
255
+ ?>
256
+ </div>
257
+ </form>
258
+ <?php
259
+ return false;
260
+ }
261
+
262
+ // Check to make sure if SSH_SFTP_Updater_Support is already call and returns.
263
+ if (!class_exists('SSH_SFTP_Updater_Support')) :
264
+
265
+ class SSH_SFTP_Updater_Support {
266
+
267
+ private $template_directories;
268
+
269
+ protected static $_instance = null;
270
+
271
+ protected static $_options_instance = null;
272
+
273
+ protected static $_notices_instance = null;
274
+
275
+ public function __construct() {
276
+ add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
277
+ add_action('admin_init', array($this, 'admin_init'));
278
+ add_action('wp_ajax_ssh_sftp_updater_support_ajax', array($this, 'ssh_sftp_updater_support_ajax_handler'));
279
+ }
280
+
281
+ public static function instance() {
282
+ if (empty(self::$_instance)) {
283
+ self::$_instance = new self();
284
+ }
285
+ return self::$_instance;
286
+ }
287
+
288
+ public static function get_notices() {
289
+ if (empty(self::$_notices_instance)) {
290
+ if (!class_exists('SSH_SFTP_Updater_Support_Notices')) include_once(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/includes/ssh-sftp-updater-support-notices.php');
291
+ self::$_notices_instance = new SSH_SFTP_Updater_Support_Notices();
292
+ }
293
+ return self::$_notices_instance;
294
+ }
295
+
296
+ /**
297
+ * Checks if this is the premium version and loads it. It also ensures that if the free version is installed then it is disabled with an appropriate error message.
298
+ */
299
+ public function plugins_loaded() {
300
+ // Loads the language file.
301
+ load_plugin_textdomain('ssh-sftp-updater-support', false, dirname(plugin_basename(__FILE__)) . '/languages');
302
+ }
303
+
304
+ /**
305
+ * Gets an array of plugins active on either the current site, or site-wide
306
+ *
307
+ * @return Array - a list of plugin paths (relative to the plugin directory)
308
+ */
309
+ private function get_active_plugins() {
310
+
311
+ // Gets all active plugins on the current site
312
+ $active_plugins = get_option('active_plugins');
313
+
314
+ if (is_multisite()) {
315
+ $network_active_plugins = get_site_option('active_sitewide_plugins');
316
+ if (!empty($network_active_plugins)) {
317
+ $network_active_plugins = array_keys($network_active_plugins);
318
+ $active_plugins = array_merge($active_plugins, $network_active_plugins);
319
+ }
320
+ }
321
+
322
+ return $active_plugins;
323
+ }
324
+
325
+ /**
326
+ * This function checks whether a specific plugin is installed, and returns information about it
327
+ *
328
+ * @param string $name Specify "Plugin Name" to return details about it.
329
+ * @return array Returns an array of details such as if installed, the name of the plugin and if it is active.
330
+ */
331
+ public function is_installed($name) {
332
+
333
+ // Needed to have the 'get_plugins()' function
334
+ include_once(ABSPATH.'wp-admin/includes/plugin.php');
335
+
336
+ // Gets all plugins available
337
+ $get_plugins = get_plugins();
338
+
339
+ $active_plugins = $this->get_active_plugins();
340
+
341
+ $plugin_info['installed'] = false;
342
+ $plugin_info['active'] = false;
343
+
344
+ // Loops around each plugin available.
345
+ foreach ($get_plugins as $key => $value) {
346
+ // If the plugin name matches that of the specified name, it will gather details.
347
+ if ($value['Name'] != $name) continue;
348
+ $plugin_info['installed'] = true;
349
+ $plugin_info['name'] = $key;
350
+ $plugin_info['version'] = $value['Version'];
351
+ if (in_array($key, $active_plugins)) {
352
+ $plugin_info['active'] = true;
353
+ }
354
+ break;
355
+ }
356
+ return $plugin_info;
357
+ }
358
+
359
+ public function admin_init() {
360
+ $pagenow = $GLOBALS['pagenow'];
361
+
362
+ $this->register_template_directories();
363
+
364
+ if (('index.php' == $pagenow && current_user_can('update_plugins')) || ('index.php' == $pagenow && defined('SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE') && SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE)) {
365
+
366
+ $dismissed_until = get_site_option('ssh_sftp_updater_support_dismiss_dash_notice_until', 0);
367
+
368
+ if (file_exists(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH . '/index.html')) {
369
+ $installed = filemtime(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH . '/index.html');
370
+ $installed_for = (time() - $installed);
371
+ }
372
+ if (($installed && time() > $dismissed_until && $installed_for < (14 * 86400) && !defined('SSH_SFTP_UPDATER_SUPPORT_NOADS_B')) || (defined('SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE') && SSH_SFTP_UPDATER_SUPPORT_FORCE_DASHNOTICE)) {
373
+ add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead'));
374
+ } else {
375
+ // These are not desired.
376
+ // add_action('all_admin_notices', array($this->get_notices(), 'do_notice'));
377
+ }
378
+ }
379
+ }
380
+
381
+ public function show_admin_notice_upgradead() {
382
+ $this->include_template('notices/thanks-for-using-main-dash.php');
383
+ }
384
+
385
+ public function capability_required() {
386
+ return apply_filters('ssh_sftp_updater_support_capability_required', 'manage_options');
387
+ }
388
+
389
+ public function ssh_sftp_updater_support_ajax_handler() {
390
+ $nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
391
+
392
+ if (!wp_verify_nonce($nonce, 'ssh-sftp-updater-support-ajax-nonce') || empty($_POST['subaction'])) die('Security check');
393
+
394
+ $subaction = $_POST['subaction'];
395
+ $data = isset($_POST['data']) ? $_POST['data'] : null;
396
+
397
+ if (!current_user_can($this->capability_required())) die('Security check');
398
+
399
+ $results = array();
400
+
401
+ // Some commands that are available via AJAX only.
402
+ if ('dismiss_dash_notice_until' == $subaction) {
403
+ update_site_option('ssh_sftp_updater_support_dismiss_dash_notice_until', (time() + 366 * 86400));
404
+ } elseif ('dismiss_page_notice_until' == $subaction) {
405
+ update_site_option('ssh_sftp_updater_support_dismiss_page_notice_until', (time() + 84 * 86400));
406
+ }
407
+
408
+ echo json_encode($results);
409
+
410
+ die;
411
+ }
412
+
413
+ private function wp_normalize_path($path) {
414
+ // Wp_normalize_path is not present before WP 3.9.
415
+ if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
416
+ // Taken from WP 4.6.
417
+ $path = str_replace('\\', '/', $path);
418
+ $path = preg_replace('|(?<=.)/+|', '/', $path);
419
+ if (':' === substr($path, 1, 1)) {
420
+ $path = ucfirst($path);
421
+ }
422
+ return $path;
423
+ }
424
+
425
+ public function get_templates_dir() {
426
+ return apply_filters('ssh_sftp_updater_support_templates_dir', $this->wp_normalize_path(SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/templates'));
427
+ }
428
+
429
+ public function get_templates_url() {
430
+ return apply_filters('ssh_sftp_updater_support_templates_url', SSH_SFTP_UPDATER_SUPPORT_URL.'/templates');
431
+ }
432
+
433
+ public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
434
+ if ($return_instead_of_echo) ob_start();
435
+
436
+ if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
437
+ $prefix = $matches[1];
438
+ $suffix = $matches[2];
439
+ if (isset($this->template_directories[$prefix])) {
440
+ $template_file = $this->template_directories[$prefix].'/'.$suffix;
441
+ }
442
+ }
443
+
444
+ if (!isset($template_file)) {
445
+ $template_file = SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH.'/templates/'.$path;
446
+ }
447
+
448
+ $template_file = apply_filters('ssh_sftp_updater_support_template', $template_file, $path);
449
+
450
+ do_action('ssh_sftp_updater_support_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
451
+
452
+ if (!file_exists($template_file)) {
453
+ error_log("SSH SFTP Updater Support: template not found: ".$template_file);
454
+ echo __('Error:', 'ssh-sftp-updater-support').' '.__('template not found', 'ssh-sftp-updater-support')." (".$path.")";
455
+ } else {
456
+ extract($extract_these);
457
+ $wpdb = $GLOBALS['wpdb'];
458
+ $ssh_sftp_updater_support = $this;
459
+ $ssh_sftp_updater_support_notices = $this->get_notices();
460
+ include $template_file;
461
+ }
462
+
463
+ do_action('ssh_sftp_updater_support_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);
464
+
465
+ if ($return_instead_of_echo) return ob_get_clean();
466
+ }
467
+
468
+ /**
469
+ * Build a list of template directories (stored in self::$template_directories)
470
+ */
471
+ private function register_template_directories() {
472
+
473
+ $template_directories = array();
474
+
475
+ $templates_dir = $this->get_templates_dir();
476
+
477
+ if ($dh = opendir($templates_dir)) {
478
+ while (($file = readdir($dh)) !== false) {
479
+ if ('.' == $file || '..' == $file) continue;
480
+ if (is_dir($templates_dir.'/'.$file)) {
481
+ $template_directories[$file] = $templates_dir.'/'.$file;
482
+ }
483
+ }
484
+ closedir($dh);
485
+ }
486
+
487
+ // Optimal hook for most extensions to hook into.
488
+ $this->template_directories = apply_filters('ssh_sftp_updater_support_template_directories', $template_directories);
489
+
490
+ }
491
+
492
+ /**
493
+ * This will customize a URL with a correct Affiliate link
494
+ * This function can be update to suit any URL as longs as the URL is passed
495
+ *
496
+ * @param String $url - URL to be check to see if it an updraftplus match.
497
+ * @param String $text - Text to be entered within the href a tags.
498
+ * @param String $html - Any specific HTML to be added.
499
+ * @param String $class - Specify a class for the href (including the attribute label)
500
+ * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
501
+ *
502
+ * @return String|void
503
+ */
504
+ public function ssh_sftp_updater_support_url($url, $text, $html = '', $class = '', $return_instead_of_echo = false) {
505
+ // Check if the URL is UpdraftPlus.
506
+ if (false !== strpos($url, '//updraftplus.com')) {
507
+ // Set URL with Affiliate ID.
508
+ $url = $url.'?ref='.$this->get_notices()->get_affiliate_id().'&source=sshsmtp';
509
+
510
+ // Apply filters.
511
+ $url = apply_filters('ssh_sftp_updater_support_updraftplus_com_link', $url);
512
+ }
513
+ // Return URL - check if there is HTML such as images.
514
+ if ('' != $html) {
515
+ $result = '<a '.$class.' href="'.esc_attr($url).'">'.$html.'</a>';
516
+ } else {
517
+ $result = '<a '.$class.' href="'.esc_attr($url).'">'.htmlspecialchars($text).'</a>';
518
+ }
519
+ if ($return_instead_of_echo) return $result;
520
+ echo $result;
521
+ }
522
+ }
523
+
524
+ function SSH_SFTP_Updater_Support() {
525
+ return SSH_SFTP_Updater_Support::instance();
526
+ }
527
+
528
+ endif;
529
+
530
+ $GLOBALS['ssh_sftp_updater_support'] = SSH_SFTP_Updater_Support();
templates/notices/horizontal-notice.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (!defined('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH')) die('No direct access allowed'); ?>
2
+
3
+ <div class="updraft-ad-container updated">
4
+ <div class="updraft_notice_container">
5
+ <div class="updraft_advert_content_left">
6
+ <img src="<?php echo SSH_SFTP_UPDATER_SUPPORT_URL.'/images/'.$image; ?>" width="60" height="60" alt="<?php _e('notice image', 'ssh-sftp-updater-support'); ?>" />
7
+ </div>
8
+ <div class="updraft_advert_content_right">
9
+ <h3 class="updraft_advert_heading">
10
+ <?php
11
+ if (!empty($prefix)) echo $prefix.' ';
12
+ echo $title;
13
+ ?>
14
+ <div class="updraft-advert-dismiss">
15
+ <?php if (!empty($dismiss_time)) { ?>
16
+ <a href="#" onclick="jQuery('.updraft-ad-container').slideUp(); jQuery.post(ajaxurl, {action: 'ssh_sftp_updater_support_ajax', subaction: '<?php echo $dismiss_time; ?>', nonce: '<?php echo wp_create_nonce('ssh-sftp-updater-support-ajax-nonce'); ?>' });"><?php _e('Dismiss', 'ssh-sftp-updater-support'); ?></a>
17
+ <?php } else { ?>
18
+ <a href="#" onclick="jQuery('.updraft-ad-container').slideUp();"><?php _e('Dismiss', 'ssh-sftp-updater-support'); ?></a>
19
+ <?php } ?>
20
+ </div>
21
+ </h3>
22
+ <p>
23
+ <?php
24
+ echo $text;
25
+ $button_text = '';
26
+ if (isset($discount_code)) echo ' <b>' . $discount_code . '</b>';
27
+
28
+ if (!empty($button_link) && !empty($button_meta)) {
29
+ // Check which Message is going to be used.
30
+ if ('updraftcentral' == $button_meta) {
31
+ $button_text = __('Get UpdraftCentral', 'ssh-sftp-updater-support');
32
+ } elseif ('review' == $button_meta) {
33
+ $button_text = __('Review "SSH SFTP Updater Support"', 'ssh-sftp-updater-support');
34
+ } elseif ('updraftplus' == $button_meta) {
35
+ $button_text = __('Get UpdraftPlus', 'ssh-sftp-updater-support');
36
+ } elseif ('signup' == $button_meta) {
37
+ $button_text = __('Sign up', 'ssh-sftp-updater-support');
38
+ } elseif ('go_there' == $button_meta) {
39
+ $button_text = __('Go there', 'ssh-sftp-updater-support');
40
+ } elseif ('wpo-premium' == $button_meta) {
41
+ $button_text = __('Find out more.', 'ssh-sftp-updater-support');
42
+ } elseif ('ssh-sftp-updater-support' == $button_meta) {
43
+ $button_text = __('Find out more.', 'ssh-sftp-updater-support');
44
+ } elseif ('keyy' == $button_meta) {
45
+ $button_text = __('Get Keyy', 'ssh-sftp-updater-support');
46
+ } elseif ('wp-optimize' == $button_meta) {
47
+ $button_text = __('Get WP-Optimize', 'ssh-sftp-updater-support');
48
+ } elseif ('metaslider' == $button_meta) {
49
+ $button_text = __('Get MetaSlider', 'ssh-sftp-updater-support');
50
+ }
51
+ $ssh_sftp_updater_support->ssh_sftp_updater_support_url($button_link, $button_text, null, 'class="updraft_notice_link"');
52
+ }
53
+ ?>
54
+ </p>
55
+ </div>
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
templates/notices/thanks-for-using-main-dash.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (!defined('SSH_SFTP_UPDATER_SUPPORT_MAIN_PATH')) die('No direct access allowed'); ?>
2
+
3
+ <div id="ssh-sftp-updater-support-dashnotice" class="updated">
4
+
5
+ <div style="float:right;"><a href="#" onclick="jQuery('#ssh-sftp-updater-support-dashnotice').slideUp(); jQuery.post(ajaxurl, {action: 'ssh_sftp_updater_support_ajax', subaction: 'dismiss_dash_notice_until', nonce: '<?php echo wp_create_nonce('ssh-sftp-updater-support-ajax-nonce'); ?>' });"><?php printf(__('Dismiss (for %s months)', 'ssh-sftp-updater-support'), 12); ?></a></div>
6
+
7
+ <h3><?php _e("Thank you for installing 'SSH SFTP Updater Support' !", 'ssh-sftp-updater-support'); ?></h3>
8
+ <div id="ssh-sftp-updater-support-dashnotice-wrapper">
9
+ <p>
10
+ <?php echo htmlspecialchars(__("This plugin is offered and maintained as a free service to the WP community. You might also be interested in enhancing your WordPress site with our other top plugins, below. If not, then sorry to trouble you; please use the 'Dismiss' link above and right.", 'ssh-sftp-updater-support')); ?>
11
+ </p>
12
+ <p>
13
+ <?php printf(__('%s simplifies backups and restoration. It is the #1 most-used backup/restore plugin, with over a million currently-active installs.', 'ssh-sftp-updater-support'), '<strong>'.$ssh_sftp_updater_support->ssh_sftp_updater_support_url('https://updraftplus.com/', 'UpdraftPlus', '', '', true).'</strong>'); ?>
14
+ </p>
15
+
16
+ <p>
17
+ <?php printf(__('%s - a highly efficient way to manage, optimize, update and backup multiple websites from one place.', 'ssh-sftp-updater-support'), '<strong>'.$ssh_sftp_updater_support->ssh_sftp_updater_support_url('https://updraftplus.com/updraftcentral/', 'UpdraftCentral', '', '', true).'</strong>'); ?>
18
+ </p>
19
+
20
+ <p>
21
+ <?php printf(__('%s helps you to optimize and clean your WordPress database so that it runs at maximum efficiency.', 'ssh-sftp-updater-support'), '<strong>'.$ssh_sftp_updater_support->ssh_sftp_updater_support_url('https://getwpo.com/', __('WP-Optimize', 'ssh-sftp-updater-support'), '', '', true).'</strong>'); ?>
22
+ </p>
23
+
24
+ <p>
25
+ <strong><?php $ssh_sftp_updater_support->ssh_sftp_updater_support_url('https://getkeyy.com/', __('Keyy:', 'ssh-sftp-updater-support')); ?></strong> <?php echo htmlspecialchars(__('Simple and secure logins with a wave of your phone.', 'ssh-sftp-updater-support')); ?>
26
+ </p>
27
+
28
+ <p>
29
+ <strong><?php $ssh_sftp_updater_support->ssh_sftp_updater_support_url('https://www.metaslider.com', 'MetaSlider');?>: </strong> <?php echo __('Easily create beautifully-designed sliders with the #1-most installed WP slider plugin.', 'ssh-sftp-updater-support'); ?>
30
+ </p>
31
+
32
+ <p>
33
+ <strong><?php $ssh_sftp_updater_support->ssh_sftp_updater_support_url('https://www.simbahosting.co.uk/s3/shop/', __('Premium WooCommerce extensions', 'ssh-sftp-updater-support')); ?></strong>
34
+ </p>
35
+
36
+ </div>
37
+ </div>