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
-