SSH SFTP Updater Support - Version 0.3

Version Description

  • update phpseclib to latest SVN
  • read file when FTP_PRIKEY is defined (thanks, lkraav!)
Download this release

Release Info

Developer TerraFrost
Plugin Icon wp plugin SSH SFTP Updater Support
Version 0.3
Comparing to
See all releases

Version 0.3

class-wp-filesystem-ssh2.php ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress SSH2 Filesystem.
4
+ *
5
+ * @package WordPress
6
+ * @subpackage Filesystem
7
+ */
8
+
9
+ set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/phpseclib/');
10
+
11
+ require_once('Net/SFTP.php');
12
+ require_once('Crypt/RSA.php');
13
+
14
+ /**
15
+ * WordPress Filesystem Class for implementing SSH2.
16
+ *
17
+ * @since 2.7
18
+ * @package WordPress
19
+ * @subpackage Filesystem
20
+ * @uses WP_Filesystem_Base Extends class
21
+ */
22
+
23
+ //define('NET_SFTP_LOGGING', NET_SFTP_LOG_REALTIME);
24
+
25
+ class WP_Filesystem_SSH2 extends WP_Filesystem_Base {
26
+
27
+ var $link = false;
28
+ var $sftp_link = false;
29
+ var $keys = false;
30
+ var $password = false;
31
+ var $errors = array();
32
+ var $options = array();
33
+
34
+ function WP_Filesystem_SSH2($opt='') {
35
+ $this->method = 'ssh2';
36
+ $this->errors = new WP_Error();
37
+
38
+ if ( !function_exists('stream_get_contents') ) {
39
+ $this->errors->add('ssh2_php_requirement', __('We require the PHP5 function <code>stream_get_contents()</code>'));
40
+ return false;
41
+ }
42
+
43
+ // Set defaults:
44
+ if ( empty($opt['port']) )
45
+ $this->options['port'] = 22;
46
+ else
47
+ $this->options['port'] = $opt['port'];
48
+
49
+ if ( empty($opt['hostname']) )
50
+ $this->errors->add('empty_hostname', __('SSH2 hostname is required'));
51
+ else
52
+ $this->options['hostname'] = $opt['hostname'];
53
+
54
+ if ( ! empty($opt['base']) )
55
+ $this->wp_base = $opt['base'];
56
+
57
+ if ( !empty ($opt['private_key']) ) {
58
+ $this->options['private_key'] = $opt['private_key'];
59
+
60
+ $this->keys = true;
61
+ } elseif ( empty ($opt['username']) ) {
62
+ $this->errors->add('empty_username', __('SSH2 username is required'));
63
+ }
64
+
65
+ if ( !empty($opt['username']) )
66
+ $this->options['username'] = $opt['username'];
67
+
68
+ if ( empty ($opt['password']) ) {
69
+ if ( !$this->keys ) //password can be blank if we are using keys
70
+ $this->errors->add('empty_password', __('SSH2 password is required'));
71
+ } else {
72
+ $this->options['password'] = $opt['password'];
73
+
74
+ $this->password = true;
75
+ }
76
+ }
77
+
78
+ function connect() {
79
+ $this->link = new Net_SFTP($this->options['hostname'], $this->options['port']);
80
+
81
+ if ( ! $this->link ) {
82
+ $this->errors->add('connect', sprintf(__('Failed to connect to SSH2 Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
83
+ return false;
84
+ }
85
+
86
+ if ( !$this->keys ) {
87
+ if ( ! $this->link->login($this->options['username'], $this->options['password']) ) {
88
+ $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
89
+ return false;
90
+ }
91
+ } else {
92
+ $rsa = new Crypt_RSA();
93
+ if ( $this->password ) {
94
+ $rsa->setPassword($this->options['password']);
95
+ }
96
+ $rsa->loadKey($this->options['private_key']);
97
+ if ( ! $this->link->login($this->options['username'], $rsa ) ) {
98
+ $this->errors->add('auth', sprintf(__('Private key incorrect for %s'), $this->options['username']));
99
+ return false;
100
+ }
101
+ }
102
+
103
+ return true;
104
+ }
105
+
106
+ function run_command( $command, $returnbool = false) {
107
+
108
+ if ( ! $this->link )
109
+ return false;
110
+
111
+ $data = $this->link->exec($command);
112
+
113
+ if ( $returnbool )
114
+ return ( $data === false ) ? false : '' != trim($data);
115
+ else
116
+ return $data;
117
+ }
118
+
119
+ function get_contents($file, $type = '', $resumepos = 0 ) {
120
+ return $this->link->get($file);
121
+ }
122
+
123
+ function get_contents_array($file) {
124
+ $lines = preg_split('#(\r\n|\r|\n)#', $this->link->get($file), -1, PREG_SPLIT_DELIM_CAPTURE);
125
+ $newLines = array();
126
+ for ($i = 0; $i < count($lines); $i+= 2)
127
+ $newLines[] = $lines[$i] . $lines[$i + 1];
128
+ return $newLines;
129
+ }
130
+
131
+ function put_contents($file, $contents, $mode = false ) {
132
+ $ret = $this->link->put($file, $contents);
133
+
134
+ $this->chmod($file, $mode);
135
+
136
+ return false !== $ret;
137
+ }
138
+
139
+ function cwd() {
140
+ $cwd = $this->run_command('pwd');
141
+ if ( $cwd )
142
+ $cwd = trailingslashit($cwd);
143
+ return $cwd;
144
+ }
145
+
146
+ function chdir($dir) {
147
+ $this->list->chdir($dir);
148
+ return $this->run_command('cd ' . $dir, true);
149
+ }
150
+
151
+ function chgrp($file, $group, $recursive = false ) {
152
+ if ( ! $this->exists($file) )
153
+ return false;
154
+ if ( ! $recursive || ! $this->is_dir($file) )
155
+ return $this->run_command(sprintf('chgrp %o %s', $mode, escapeshellarg($file)), true);
156
+ return $this->run_command(sprintf('chgrp -R %o %s', $mode, escapeshellarg($file)), true);
157
+ }
158
+
159
+ function chmod($file, $mode = false, $recursive = false) {
160
+ return $mode === false ? false : $this->link->chmod($mode, $file, $recursive);
161
+ }
162
+
163
+ function chown($file, $owner, $recursive = false ) {
164
+ if ( ! $this->exists($file) )
165
+ return false;
166
+ if ( ! $recursive || ! $this->is_dir($file) )
167
+ return $this->run_command(sprintf('chown %o %s', $mode, escapeshellarg($file)), true);
168
+ return $this->run_command(sprintf('chown -R %o %s', $mode, escapeshellarg($file)), true);
169
+ }
170
+
171
+ function owner($file, $owneruid = false) {
172
+ if ($owneruid === false) {
173
+ $result = $this->link->stat($file);
174
+ $owneruid = $result['uid'];
175
+ }
176
+
177
+ if ( ! $owneruid )
178
+ return false;
179
+ if ( ! function_exists('posix_getpwuid') )
180
+ return $owneruid;
181
+ $ownerarray = posix_getpwuid($owneruid);
182
+ return $ownerarray['name'];
183
+ }
184
+
185
+ function getchmod($file) {
186
+ $result = $this->link->stat($file);
187
+
188
+ return substr(decoct($result['permissions']),3);
189
+ }
190
+
191
+ function group($file, $gid = false) {
192
+ if ($gid === false) {
193
+ $result = $this->link->stat($file);
194
+ $gid = $result['gid'];
195
+ }
196
+
197
+ if ( ! $gid )
198
+ return false;
199
+ if ( ! function_exists('posix_getgrgid') )
200
+ return $gid;
201
+ $grouparray = posix_getgrgid($gid);
202
+ return $grouparray['name'];
203
+ }
204
+
205
+ function copy($source, $destination, $overwrite = false, $mode = false) {
206
+ if ( ! $overwrite && $this->exists($destination) )
207
+ return false;
208
+ $content = $this->get_contents($source);
209
+ if ( false === $content)
210
+ return false;
211
+ return $this->put_contents($destination, $content, $mode);
212
+ }
213
+
214
+ function move($source, $destination, $overwrite = false) {
215
+ return $this->link->rename($source, $destination);
216
+ }
217
+
218
+ function delete($file, $recursive = false) {
219
+ return $this->link->delete($file, $recursive);
220
+ }
221
+
222
+ function exists($file) {
223
+ return $this->link->stat($file) !== false;
224
+ }
225
+
226
+ function is_file($file) {
227
+ $result = $this->link->stat($file);
228
+ return $result['type'] == NET_SFTP_TYPE_REGULAR;
229
+ }
230
+
231
+ function is_dir($path) {
232
+ $result = $this->link->stat($path);
233
+ return $result['type'] == NET_SFTP_TYPE_DIRECTORY;
234
+ }
235
+
236
+ function is_readable($file) {
237
+ return true;
238
+
239
+ return is_readable('ssh2.sftp://' . $this->sftp_link . '/' . $file);
240
+ }
241
+
242
+ function is_writable($file) {
243
+ return true;
244
+
245
+ return is_writable('ssh2.sftp://' . $this->sftp_link . '/' . $file);
246
+ }
247
+
248
+ function atime($file) {
249
+ $result = $this->link->stat($file);
250
+ return $result['atime'];
251
+ }
252
+
253
+ function mtime($file) {
254
+ $result = $this->link->stat($file);
255
+ return $result['mtime'];
256
+ }
257
+
258
+ function size($file) {
259
+ $result = $this->link->stat($file);
260
+ return $result['size'];
261
+ }
262
+
263
+ function touch($file, $time = 0, $atime = 0) {
264
+ //Not implmented.
265
+ }
266
+
267
+ function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
268
+ $path = untrailingslashit($path);
269
+ if ( ! $chmod )
270
+ $chmod = FS_CHMOD_DIR;
271
+ //if ( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) )
272
+ // return false;
273
+ if ( ! $this->link->mkdir($path) && $this->link->chmod($chmod, $path) )
274
+ return false;
275
+ if ( $chown )
276
+ $this->chown($path, $chown);
277
+ if ( $chgrp )
278
+ $this->chgrp($path, $chgrp);
279
+ return true;
280
+ }
281
+
282
+ function rmdir($path, $recursive = false) {
283
+ return $this->delete($path, $recursive);
284
+ }
285
+
286
+ function dirlist($path, $include_hidden = true, $recursive = false) {
287
+ if ( $this->is_file($path) ) {
288
+ $limit_file = basename($path);
289
+ $path = dirname($path);
290
+ } else {
291
+ $limit_file = false;
292
+ }
293
+
294
+ if ( ! $this->is_dir($path) )
295
+ return false;
296
+
297
+ $ret = array();
298
+ $entries = $this->link->rawlist($path);
299
+
300
+ foreach ($entries as $name => $entry) {
301
+ $struc = array();
302
+ $struc['name'] = $name;
303
+
304
+ if ( '.' == $struc['name'] || '..' == $struc['name'] )
305
+ continue; //Do not care about these folders.
306
+
307
+ if ( ! $include_hidden && '.' == $struc['name'][0] )
308
+ continue;
309
+
310
+ if ( $limit_file && $struc['name'] != $limit_file )
311
+ continue;
312
+
313
+ $struc['perms'] = $entry['permissions'];
314
+ $struc['permsn'] = $this->getnumchmodfromh($struc['perms']);
315
+ $struc['number'] = false;
316
+ $struc['owner'] = $this->owner($path.'/'.$entry, $entry['uid']);
317
+ $struc['group'] = $this->group($path.'/'.$entry, $entry['gid']);
318
+ $struc['size'] = $entry['size'];//$this->size($path.'/'.$entry);
319
+ $struc['lastmodunix']= $entry['mtime'];//$this->mtime($path.'/'.$entry);
320
+ $struc['lastmod'] = date('M j',$struc['lastmodunix']);
321
+ $struc['time'] = date('h:i:s',$struc['lastmodunix']);
322
+ $struc['type'] = $entry['type'] == NET_SFTP_TYPE_DIRECTORY ? 'd' : 'f';
323
+
324
+ if ( 'd' == $struc['type'] ) {
325
+ if ( $recursive )
326
+ $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
327
+ else
328
+ $struc['files'] = array();
329
+ }
330
+
331
+ $ret[ $struc['name'] ] = $struc;
332
+ }
333
+ return $ret;
334
+ }
335
+ }
phpseclib/Crypt/AES.php ADDED
@@ -0,0 +1,612 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of AES.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
12
+ * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
13
+ * it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
14
+ * is called, again, at which point, it'll be recalculated.
15
+ *
16
+ * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
17
+ * make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
18
+ * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
19
+ *
20
+ * Here's a short example of how to use this library:
21
+ * <code>
22
+ * <?php
23
+ * include('Crypt/AES.php');
24
+ *
25
+ * $aes = new Crypt_AES();
26
+ *
27
+ * $aes->setKey('abcdefghijklmnop');
28
+ *
29
+ * $size = 10 * 1024;
30
+ * $plaintext = '';
31
+ * for ($i = 0; $i < $size; $i++) {
32
+ * $plaintext.= 'a';
33
+ * }
34
+ *
35
+ * echo $aes->decrypt($aes->encrypt($plaintext));
36
+ * ?>
37
+ * </code>
38
+ *
39
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
40
+ * of this software and associated documentation files (the "Software"), to deal
41
+ * in the Software without restriction, including without limitation the rights
42
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
+ * copies of the Software, and to permit persons to whom the Software is
44
+ * furnished to do so, subject to the following conditions:
45
+ *
46
+ * The above copyright notice and this permission notice shall be included in
47
+ * all copies or substantial portions of the Software.
48
+ *
49
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55
+ * THE SOFTWARE.
56
+ *
57
+ * @category Crypt
58
+ * @package Crypt_AES
59
+ * @author Jim Wigginton <terrafrost@php.net>
60
+ * @copyright MMVIII Jim Wigginton
61
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
62
+ * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $
63
+ * @link http://phpseclib.sourceforge.net
64
+ */
65
+
66
+ /**
67
+ * Include Crypt_Rijndael
68
+ */
69
+ require_once 'Rijndael.php';
70
+
71
+ /**#@+
72
+ * @access public
73
+ * @see Crypt_AES::encrypt()
74
+ * @see Crypt_AES::decrypt()
75
+ */
76
+ /**
77
+ * Encrypt / decrypt using the Counter mode.
78
+ *
79
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
80
+ *
81
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
82
+ */
83
+ define('CRYPT_AES_MODE_CTR', -1);
84
+ /**
85
+ * Encrypt / decrypt using the Electronic Code Book mode.
86
+ *
87
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
88
+ */
89
+ define('CRYPT_AES_MODE_ECB', 1);
90
+ /**
91
+ * Encrypt / decrypt using the Code Book Chaining mode.
92
+ *
93
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
94
+ */
95
+ define('CRYPT_AES_MODE_CBC', 2);
96
+ /**
97
+ * Encrypt / decrypt using the Cipher Feedback mode.
98
+ *
99
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
100
+ */
101
+ define('CRYPT_AES_MODE_CFB', 3);
102
+ /**
103
+ * Encrypt / decrypt using the Cipher Feedback mode.
104
+ *
105
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
106
+ */
107
+ define('CRYPT_AES_MODE_OFB', 4);
108
+ /**#@-*/
109
+
110
+ /**#@+
111
+ * @access private
112
+ * @see Crypt_AES::Crypt_AES()
113
+ */
114
+ /**
115
+ * Toggles the internal implementation
116
+ */
117
+ define('CRYPT_AES_MODE_INTERNAL', 1);
118
+ /**
119
+ * Toggles the mcrypt implementation
120
+ */
121
+ define('CRYPT_AES_MODE_MCRYPT', 2);
122
+ /**#@-*/
123
+
124
+ /**
125
+ * Pure-PHP implementation of AES.
126
+ *
127
+ * @author Jim Wigginton <terrafrost@php.net>
128
+ * @version 0.1.0
129
+ * @access public
130
+ * @package Crypt_AES
131
+ */
132
+ class Crypt_AES extends Crypt_Rijndael {
133
+ /**
134
+ * mcrypt resource for encryption
135
+ *
136
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
137
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
138
+ *
139
+ * @see Crypt_AES::encrypt()
140
+ * @var String
141
+ * @access private
142
+ */
143
+ var $enmcrypt;
144
+
145
+ /**
146
+ * mcrypt resource for decryption
147
+ *
148
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
149
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
150
+ *
151
+ * @see Crypt_AES::decrypt()
152
+ * @var String
153
+ * @access private
154
+ */
155
+ var $demcrypt;
156
+
157
+ /**
158
+ * mcrypt resource for CFB mode
159
+ *
160
+ * @see Crypt_AES::encrypt()
161
+ * @see Crypt_AES::decrypt()
162
+ * @var String
163
+ * @access private
164
+ */
165
+ var $ecb;
166
+
167
+ /**
168
+ * Default Constructor.
169
+ *
170
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
171
+ * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
172
+ *
173
+ * @param optional Integer $mode
174
+ * @return Crypt_AES
175
+ * @access public
176
+ */
177
+ function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
178
+ {
179
+ if ( !defined('CRYPT_AES_MODE') ) {
180
+ switch (true) {
181
+ case extension_loaded('mcrypt'):
182
+ // i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')),
183
+ // but since that can be changed after the object has been created, there doesn't seem to be
184
+ // a lot of point...
185
+ define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
186
+ break;
187
+ default:
188
+ define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
189
+ }
190
+ }
191
+
192
+ switch ( CRYPT_AES_MODE ) {
193
+ case CRYPT_AES_MODE_MCRYPT:
194
+ switch ($mode) {
195
+ case CRYPT_AES_MODE_ECB:
196
+ $this->paddable = true;
197
+ $this->mode = MCRYPT_MODE_ECB;
198
+ break;
199
+ case CRYPT_AES_MODE_CTR:
200
+ // ctr doesn't have a constant associated with it even though it appears to be fairly widely
201
+ // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
202
+ // include a compatibility layer. the layer has been implemented but, for now, is commented out.
203
+ $this->mode = 'ctr';
204
+ //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
205
+ break;
206
+ case CRYPT_AES_MODE_CFB:
207
+ $this->mode = 'ncfb';
208
+ break;
209
+ case CRYPT_AES_MODE_OFB:
210
+ $this->mode = MCRYPT_MODE_NOFB;
211
+ break;
212
+ case CRYPT_AES_MODE_CBC:
213
+ default:
214
+ $this->paddable = true;
215
+ $this->mode = MCRYPT_MODE_CBC;
216
+ }
217
+
218
+ $this->debuffer = $this->enbuffer = '';
219
+
220
+ break;
221
+ default:
222
+ switch ($mode) {
223
+ case CRYPT_AES_MODE_ECB:
224
+ $this->paddable = true;
225
+ $this->mode = CRYPT_RIJNDAEL_MODE_ECB;
226
+ break;
227
+ case CRYPT_AES_MODE_CTR:
228
+ $this->mode = CRYPT_RIJNDAEL_MODE_CTR;
229
+ break;
230
+ case CRYPT_AES_MODE_CFB:
231
+ $this->mode = CRYPT_RIJNDAEL_MODE_CFB;
232
+ break;
233
+ case CRYPT_AES_MODE_OFB:
234
+ $this->mode = CRYPT_RIJNDAEL_MODE_OFB;
235
+ break;
236
+ case CRYPT_AES_MODE_CBC:
237
+ default:
238
+ $this->paddable = true;
239
+ $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
240
+ }
241
+ }
242
+
243
+ if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
244
+ parent::Crypt_Rijndael($this->mode);
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Dummy function
250
+ *
251
+ * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
252
+ *
253
+ * @access public
254
+ * @param Integer $length
255
+ */
256
+ function setBlockLength($length)
257
+ {
258
+ return;
259
+ }
260
+
261
+
262
+ /**
263
+ * Sets the initialization vector. (optional)
264
+ *
265
+ * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
266
+ * to be all zero's.
267
+ *
268
+ * @access public
269
+ * @param String $iv
270
+ */
271
+ function setIV($iv)
272
+ {
273
+ parent::setIV($iv);
274
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
275
+ $this->changed = true;
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Encrypts a message.
281
+ *
282
+ * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
283
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
284
+ * URL:
285
+ *
286
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
287
+ *
288
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
289
+ * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
290
+ * length.
291
+ *
292
+ * @see Crypt_AES::decrypt()
293
+ * @access public
294
+ * @param String $plaintext
295
+ */
296
+ function encrypt($plaintext)
297
+ {
298
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
299
+ $changed = $this->changed;
300
+ $this->_mcryptSetup();
301
+ /*
302
+ if ($this->mode == CRYPT_AES_MODE_CTR) {
303
+ $iv = $this->encryptIV;
304
+ $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv));
305
+ $ciphertext = $plaintext ^ $xor;
306
+ if ($this->continuousBuffer) {
307
+ $this->encryptIV = $iv;
308
+ }
309
+ return $ciphertext;
310
+ }
311
+ */
312
+ // re: http://phpseclib.sourceforge.net/cfb-demo.phps
313
+ // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
314
+ // rewritten CFB implementation the above outputs the same thing twice.
315
+ if ($this->mode == 'ncfb') {
316
+ if ($changed) {
317
+ $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
318
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
319
+ }
320
+
321
+ if (strlen($this->enbuffer)) {
322
+ $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
323
+ $this->enbuffer.= $ciphertext;
324
+ if (strlen($this->enbuffer) == 16) {
325
+ $this->encryptIV = $this->enbuffer;
326
+ $this->enbuffer = '';
327
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
328
+ }
329
+ $plaintext = substr($plaintext, strlen($ciphertext));
330
+ } else {
331
+ $ciphertext = '';
332
+ }
333
+
334
+ $last_pos = strlen($plaintext) & 0xFFFFFFF0;
335
+ $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
336
+
337
+ if (strlen($plaintext) & 0xF) {
338
+ if (strlen($ciphertext)) {
339
+ $this->encryptIV = substr($ciphertext, -16);
340
+ }
341
+ $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
342
+ $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
343
+ $ciphertext.= $this->enbuffer;
344
+ }
345
+
346
+ return $ciphertext;
347
+ }
348
+
349
+ if ($this->paddable) {
350
+ $plaintext = $this->_pad($plaintext);
351
+ }
352
+
353
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
354
+
355
+ if (!$this->continuousBuffer) {
356
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
357
+ }
358
+
359
+ return $ciphertext;
360
+ }
361
+
362
+ return parent::encrypt($plaintext);
363
+ }
364
+
365
+ /**
366
+ * Decrypts a message.
367
+ *
368
+ * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
369
+ *
370
+ * @see Crypt_AES::encrypt()
371
+ * @access public
372
+ * @param String $ciphertext
373
+ */
374
+ function decrypt($ciphertext)
375
+ {
376
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
377
+ $changed = $this->changed;
378
+ $this->_mcryptSetup();
379
+ /*
380
+ if ($this->mode == CRYPT_AES_MODE_CTR) {
381
+ $iv = $this->decryptIV;
382
+ $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv));
383
+ $plaintext = $ciphertext ^ $xor;
384
+ if ($this->continuousBuffer) {
385
+ $this->decryptIV = $iv;
386
+ }
387
+ return $plaintext;
388
+ }
389
+ */
390
+ if ($this->mode == 'ncfb') {
391
+ if ($changed) {
392
+ $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
393
+ mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
394
+ }
395
+
396
+ if (strlen($this->debuffer)) {
397
+ $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
398
+
399
+ $this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
400
+ if (strlen($this->debuffer) == 16) {
401
+ $this->decryptIV = $this->debuffer;
402
+ $this->debuffer = '';
403
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
404
+ }
405
+ $ciphertext = substr($ciphertext, strlen($plaintext));
406
+ } else {
407
+ $plaintext = '';
408
+ }
409
+
410
+ $last_pos = strlen($ciphertext) & 0xFFFFFFF0;
411
+ $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
412
+
413
+ if (strlen($ciphertext) & 0xF) {
414
+ if (strlen($plaintext)) {
415
+ $this->decryptIV = substr($ciphertext, $last_pos - 16, 16);
416
+ }
417
+ $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
418
+ $this->debuffer = substr($ciphertext, $last_pos);
419
+ $plaintext.= $this->debuffer ^ $this->decryptIV;
420
+ }
421
+
422
+ return $plaintext;
423
+ }
424
+
425
+ if ($this->paddable) {
426
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
427
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
428
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
429
+ }
430
+
431
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
432
+
433
+ if (!$this->continuousBuffer) {
434
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
435
+ }
436
+
437
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
438
+ }
439
+
440
+ return parent::decrypt($ciphertext);
441
+ }
442
+
443
+ /**
444
+ * Setup mcrypt
445
+ *
446
+ * Validates all the variables.
447
+ *
448
+ * @access private
449
+ */
450
+ function _mcryptSetup()
451
+ {
452
+ if (!$this->changed) {
453
+ return;
454
+ }
455
+
456
+ if (!$this->explicit_key_length) {
457
+ // this just copied from Crypt_Rijndael::_setup()
458
+ $length = strlen($this->key) >> 2;
459
+ if ($length > 8) {
460
+ $length = 8;
461
+ } else if ($length < 4) {
462
+ $length = 4;
463
+ }
464
+ $this->Nk = $length;
465
+ $this->key_size = $length << 2;
466
+ }
467
+
468
+ switch ($this->Nk) {
469
+ case 4: // 128
470
+ $this->key_size = 16;
471
+ break;
472
+ case 5: // 160
473
+ case 6: // 192
474
+ $this->key_size = 24;
475
+ break;
476
+ case 7: // 224
477
+ case 8: // 256
478
+ $this->key_size = 32;
479
+ }
480
+
481
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
482
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
483
+
484
+ if (!isset($this->enmcrypt)) {
485
+ $mode = $this->mode;
486
+ //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
487
+
488
+ $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
489
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
490
+ } // else should mcrypt_generic_deinit be called?
491
+
492
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
493
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
494
+
495
+ $this->changed = false;
496
+ }
497
+
498
+ /**
499
+ * Encrypts a block
500
+ *
501
+ * Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
502
+ *
503
+ * @see Crypt_Rijndael::_encryptBlock()
504
+ * @access private
505
+ * @param String $in
506
+ * @return String
507
+ */
508
+ function _encryptBlock($in)
509
+ {
510
+ $state = unpack('N*word', $in);
511
+
512
+ $Nr = $this->Nr;
513
+ $w = $this->w;
514
+ $t0 = $this->t0;
515
+ $t1 = $this->t1;
516
+ $t2 = $this->t2;
517
+ $t3 = $this->t3;
518
+
519
+ // addRoundKey and reindex $state
520
+ $state = array(
521
+ $state['word1'] ^ $w[0][0],
522
+ $state['word2'] ^ $w[0][1],
523
+ $state['word3'] ^ $w[0][2],
524
+ $state['word4'] ^ $w[0][3]
525
+ );
526
+
527
+ // shiftRows + subWord + mixColumns + addRoundKey
528
+ // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
529
+ // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
530
+ for ($round = 1; $round < $this->Nr; $round++) {
531
+ $state = array(
532
+ $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
533
+ $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
534
+ $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2],
535
+ $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3]
536
+ );
537
+
538
+ }
539
+
540
+ // subWord
541
+ $state = array(
542
+ $this->_subWord($state[0]),
543
+ $this->_subWord($state[1]),
544
+ $this->_subWord($state[2]),
545
+ $this->_subWord($state[3])
546
+ );
547
+
548
+ // shiftRows + addRoundKey
549
+ $state = array(
550
+ ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0],
551
+ ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1],
552
+ ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2],
553
+ ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3]
554
+ );
555
+
556
+ return pack('N*', $state[0], $state[1], $state[2], $state[3]);
557
+ }
558
+
559
+ /**
560
+ * Decrypts a block
561
+ *
562
+ * Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
563
+ *
564
+ * @see Crypt_Rijndael::_decryptBlock()
565
+ * @access private
566
+ * @param String $in
567
+ * @return String
568
+ */
569
+ function _decryptBlock($in)
570
+ {
571
+ $state = unpack('N*word', $in);
572
+
573
+ $Nr = $this->Nr;
574
+ $dw = $this->dw;
575
+ $dt0 = $this->dt0;
576
+ $dt1 = $this->dt1;
577
+ $dt2 = $this->dt2;
578
+ $dt3 = $this->dt3;
579
+
580
+ // addRoundKey and reindex $state
581
+ $state = array(
582
+ $state['word1'] ^ $dw[$this->Nr][0],
583
+ $state['word2'] ^ $dw[$this->Nr][1],
584
+ $state['word3'] ^ $dw[$this->Nr][2],
585
+ $state['word4'] ^ $dw[$this->Nr][3]
586
+ );
587
+
588
+
589
+ // invShiftRows + invSubBytes + invMixColumns + addRoundKey
590
+ for ($round = $this->Nr - 1; $round > 0; $round--) {
591
+ $state = array(
592
+ $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
593
+ $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
594
+ $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2],
595
+ $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3]
596
+ );
597
+ }
598
+
599
+ // invShiftRows + invSubWord + addRoundKey
600
+ $state = array(
601
+ $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0],
602
+ $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1],
603
+ $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2],
604
+ $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3]
605
+ );
606
+
607
+ return pack('N*', $state[0], $state[1], $state[2], $state[3]);
608
+ }
609
+ }
610
+
611
+ // vim: ts=4:sw=4:et:
612
+ // vim6: fdl=1:
phpseclib/Crypt/DES.php ADDED
@@ -0,0 +1,1298 @@