Lib_Phpseclib - Version 1.4.1.0

Version Notes

1.4.1.0

Download this release

Release Info

Developer Magento Core Team
Extension Lib_Phpseclib
Version 1.4.1.0
Comparing to
See all releases


Version 1.4.1.0

lib/phpseclib/Crypt/AES.php ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: This library is free software; you can redistribute it and/or
40
+ * modify it under the terms of the GNU Lesser General Public
41
+ * License as published by the Free Software Foundation; either
42
+ * version 2.1 of the License, or (at your option) any later version.
43
+ *
44
+ * This library is distributed in the hope that it will be useful,
45
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
46
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
47
+ * Lesser General Public License for more details.
48
+ *
49
+ * You should have received a copy of the GNU Lesser General Public
50
+ * License along with this library; if not, write to the Free Software
51
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
52
+ * MA 02111-1307 USA
53
+ *
54
+ * @category Crypt
55
+ * @package Crypt_AES
56
+ * @author Jim Wigginton <terrafrost@php.net>
57
+ * @copyright MMVIII Jim Wigginton
58
+ * @license http://www.gnu.org/licenses/lgpl.txt
59
+ * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $
60
+ * @link http://phpseclib.sourceforge.net
61
+ */
62
+
63
+ /**
64
+ * Include Crypt_Rijndael
65
+ */
66
+ require_once 'Rijndael.php';
67
+
68
+ /**#@+
69
+ * @access public
70
+ * @see Crypt_AES::encrypt()
71
+ * @see Crypt_AES::decrypt()
72
+ */
73
+ /**
74
+ * Encrypt / decrypt using the Counter mode.
75
+ *
76
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
77
+ *
78
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
79
+ */
80
+ define('CRYPT_AES_MODE_CTR', -1);
81
+ /**
82
+ * Encrypt / decrypt using the Electronic Code Book mode.
83
+ *
84
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
85
+ */
86
+ define('CRYPT_AES_MODE_ECB', 1);
87
+ /**
88
+ * Encrypt / decrypt using the Code Book Chaining mode.
89
+ *
90
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
91
+ */
92
+ define('CRYPT_AES_MODE_CBC', 2);
93
+ /**#@-*/
94
+
95
+ /**#@+
96
+ * @access private
97
+ * @see Crypt_AES::Crypt_AES()
98
+ */
99
+ /**
100
+ * Toggles the internal implementation
101
+ */
102
+ define('CRYPT_AES_MODE_INTERNAL', 1);
103
+ /**
104
+ * Toggles the mcrypt implementation
105
+ */
106
+ define('CRYPT_AES_MODE_MCRYPT', 2);
107
+ /**#@-*/
108
+
109
+ /**
110
+ * Pure-PHP implementation of AES.
111
+ *
112
+ * @author Jim Wigginton <terrafrost@php.net>
113
+ * @version 0.1.0
114
+ * @access public
115
+ * @package Crypt_AES
116
+ */
117
+ class Crypt_AES extends Crypt_Rijndael {
118
+ /**
119
+ * mcrypt resource for encryption
120
+ *
121
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
122
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
123
+ *
124
+ * @see Crypt_AES::encrypt()
125
+ * @var String
126
+ * @access private
127
+ */
128
+ var $enmcrypt;
129
+
130
+ /**
131
+ * mcrypt resource for decryption
132
+ *
133
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
134
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
135
+ *
136
+ * @see Crypt_AES::decrypt()
137
+ * @var String
138
+ * @access private
139
+ */
140
+ var $demcrypt;
141
+
142
+ /**
143
+ * Default Constructor.
144
+ *
145
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
146
+ * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
147
+ *
148
+ * @param optional Integer $mode
149
+ * @return Crypt_AES
150
+ * @access public
151
+ */
152
+ function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
153
+ {
154
+ if ( !defined('CRYPT_AES_MODE') ) {
155
+ switch (true) {
156
+ case extension_loaded('mcrypt'):
157
+ // i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')),
158
+ // but since that can be changed after the object has been created, there doesn't seem to be
159
+ // a lot of point...
160
+ define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
161
+ break;
162
+ default:
163
+ define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
164
+ }
165
+ }
166
+
167
+ switch ( CRYPT_AES_MODE ) {
168
+ case CRYPT_AES_MODE_MCRYPT:
169
+ switch ($mode) {
170
+ case CRYPT_AES_MODE_ECB:
171
+ $this->mode = MCRYPT_MODE_ECB;
172
+ break;
173
+ case CRYPT_AES_MODE_CTR:
174
+ // ctr doesn't have a constant associated with it even though it appears to be fairly widely
175
+ // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
176
+ // include a compatibility layer. the layer has been implemented but, for now, is commented out.
177
+ $this->mode = 'ctr';
178
+ //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
179
+ break;
180
+ case CRYPT_AES_MODE_CBC:
181
+ default:
182
+ $this->mode = MCRYPT_MODE_CBC;
183
+ }
184
+
185
+ break;
186
+ default:
187
+ switch ($mode) {
188
+ case CRYPT_AES_MODE_ECB:
189
+ $this->mode = CRYPT_RIJNDAEL_MODE_ECB;
190
+ break;
191
+ case CRYPT_AES_MODE_CTR:
192
+ $this->mode = CRYPT_RIJNDAEL_MODE_CTR;
193
+ break;
194
+ case CRYPT_AES_MODE_CBC:
195
+ default:
196
+ $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
197
+ }
198
+ }
199
+
200
+ if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
201
+ parent::Crypt_Rijndael($this->mode);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Dummy function
207
+ *
208
+ * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
209
+ *
210
+ * @access public
211
+ * @param Integer $length
212
+ */
213
+ function setBlockLength($length)
214
+ {
215
+ return;
216
+ }
217
+
218
+ /**
219
+ * Encrypts a message.
220
+ *
221
+ * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
222
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
223
+ * URL:
224
+ *
225
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
226
+ *
227
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
228
+ * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
229
+ * length.
230
+ *
231
+ * @see Crypt_AES::decrypt()
232
+ * @access public
233
+ * @param String $plaintext
234
+ */
235
+ function encrypt($plaintext)
236
+ {
237
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
238
+ $this->_mcryptSetup();
239
+ /*
240
+ if ($this->mode == CRYPT_AES_MODE_CTR) {
241
+ $iv = $this->encryptIV;
242
+ $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv));
243
+ $ciphertext = $plaintext ^ $xor;
244
+ if ($this->continuousBuffer) {
245
+ $this->encryptIV = $iv;
246
+ }
247
+ return $ciphertext;
248
+ }
249
+ */
250
+
251
+ if ($this->mode != 'ctr') {
252
+ $plaintext = $this->_pad($plaintext);
253
+ }
254
+
255
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
256
+
257
+ if (!$this->continuousBuffer) {
258
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
259
+ }
260
+
261
+ return $ciphertext;
262
+ }
263
+
264
+ return parent::encrypt($plaintext);
265
+ }
266
+
267
+ /**
268
+ * Decrypts a message.
269
+ *
270
+ * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
271
+ *
272
+ * @see Crypt_AES::encrypt()
273
+ * @access public
274
+ * @param String $ciphertext
275
+ */
276
+ function decrypt($ciphertext)
277
+ {
278
+ if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
279
+ $this->_mcryptSetup();
280
+ /*
281
+ if ($this->mode == CRYPT_AES_MODE_CTR) {
282
+ $iv = $this->decryptIV;
283
+ $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv));
284
+ $plaintext = $ciphertext ^ $xor;
285
+ if ($this->continuousBuffer) {
286
+ $this->decryptIV = $iv;
287
+ }
288
+ return $plaintext;
289
+ }
290
+ */
291
+
292
+ if ($this->mode != 'ctr') {
293
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
294
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
295
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
296
+ }
297
+
298
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
299
+
300
+ if (!$this->continuousBuffer) {
301
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
302
+ }
303
+
304
+ return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
305
+ }
306
+
307
+ return parent::decrypt($ciphertext);
308
+ }
309
+
310
+ /**
311
+ * Setup mcrypt
312
+ *
313
+ * Validates all the variables.
314
+ *
315
+ * @access private
316
+ */
317
+ function _mcryptSetup()
318
+ {
319
+ if (!$this->changed) {
320
+ return;
321
+ }
322
+
323
+ if (!$this->explicit_key_length) {
324
+ // this just copied from Crypt_Rijndael::_setup()
325
+ $length = strlen($this->key) >> 2;
326
+ if ($length > 8) {
327
+ $length = 8;
328
+ } else if ($length < 4) {
329
+ $length = 4;
330
+ }
331
+ $this->Nk = $length;
332
+ $this->key_size = $length << 2;
333
+ }
334
+
335
+ switch ($this->Nk) {
336
+ case 4: // 128
337
+ $this->key_size = 16;
338
+ break;
339
+ case 5: // 160
340
+ case 6: // 192
341
+ $this->key_size = 24;
342
+ break;
343
+ case 7: // 224
344
+ case 8: // 256
345
+ $this->key_size = 32;
346
+ }
347
+
348
+ $this->key = substr($this->key, 0, $this->key_size);
349
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
350
+
351
+ if (!isset($this->enmcrypt)) {
352
+ $mode = $this->mode;
353
+ //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
354
+
355
+ $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
356
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
357
+ } // else should mcrypt_generic_deinit be called?
358
+
359
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
360
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
361
+
362
+ $this->changed = false;
363
+ }
364
+
365
+ /**
366
+ * Encrypts a block
367
+ *
368
+ * Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
369
+ *
370
+ * @see Crypt_Rijndael::_encryptBlock()
371
+ * @access private
372
+ * @param String $in
373
+ * @return String
374
+ */
375
+ function _encryptBlock($in)
376
+ {
377
+ $state = unpack('N*word', $in);
378
+
379
+ $Nr = $this->Nr;
380
+ $w = $this->w;
381
+ $t0 = $this->t0;
382
+ $t1 = $this->t1;
383
+ $t2 = $this->t2;
384
+ $t3 = $this->t3;
385
+
386
+ // addRoundKey and reindex $state
387
+ $state = array(
388
+ $state['word1'] ^ $w[0][0],
389
+ $state['word2'] ^ $w[0][1],
390
+ $state['word3'] ^ $w[0][2],
391
+ $state['word4'] ^ $w[0][3]
392
+ );
393
+
394
+ // shiftRows + subWord + mixColumns + addRoundKey
395
+ // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
396
+ // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
397
+ for ($round = 1; $round < $this->Nr; $round++) {
398
+ $state = array(
399
+ $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
400
+ $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
401
+ $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2],
402
+ $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3]
403
+ );
404
+
405
+ }
406
+
407
+ // subWord
408
+ $state = array(
409
+ $this->_subWord($state[0]),
410
+ $this->_subWord($state[1]),
411
+ $this->_subWord($state[2]),
412
+ $this->_subWord($state[3])
413
+ );
414
+
415
+ // shiftRows + addRoundKey
416
+ $state = array(
417
+ ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0],
418
+ ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1],
419
+ ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2],
420
+ ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3]
421
+ );
422
+
423
+ return pack('N*', $state[0], $state[1], $state[2], $state[3]);
424
+ }
425
+
426
+ /**
427
+ * Decrypts a block
428
+ *
429
+ * Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
430
+ *
431
+ * @see Crypt_Rijndael::_decryptBlock()
432
+ * @access private
433
+ * @param String $in
434
+ * @return String
435
+ */
436
+ function _decryptBlock($in)
437
+ {
438
+ $state = unpack('N*word', $in);
439
+
440
+ $Nr = $this->Nr;
441
+ $dw = $this->dw;
442
+ $dt0 = $this->dt0;
443
+ $dt1 = $this->dt1;
444
+ $dt2 = $this->dt2;
445
+ $dt3 = $this->dt3;
446
+
447
+ // addRoundKey and reindex $state
448
+ $state = array(
449
+ $state['word1'] ^ $dw[$this->Nr][0],
450
+ $state['word2'] ^ $dw[$this->Nr][1],
451
+ $state['word3'] ^ $dw[$this->Nr][2],
452
+ $state['word4'] ^ $dw[$this->Nr][3]
453
+ );
454
+
455
+
456
+ // invShiftRows + invSubBytes + invMixColumns + addRoundKey
457
+ for ($round = $this->Nr - 1; $round > 0; $round--) {
458
+ $state = array(
459
+ $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
460
+ $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
461
+ $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2],
462
+ $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3]
463
+ );
464
+ }
465
+
466
+ // invShiftRows + invSubWord + addRoundKey
467
+ $state = array(
468
+ $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0],
469
+ $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1],
470
+ $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2],
471
+ $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3]
472
+ );
473
+
474
+ return pack('N*', $state[0], $state[1], $state[2], $state[3]);
475
+ }
476
+ }
477
+
478
+ // vim: ts=4:sw=4:et:
479
+ // vim6: fdl=1:
lib/phpseclib/Crypt/DES.php ADDED
@@ -0,0 +1,945 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of DES.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Useful resources are as follows:
12
+ *
13
+ * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
14
+ * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
15
+ * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
16
+ *
17
+ * Here's a short example of how to use this library:
18
+ * <code>
19
+ * <?php
20
+ * include('Crypt/DES.php');
21
+ *
22
+ * $des = new Crypt_DES();
23
+ *
24
+ * $des->setKey('abcdefgh');
25
+ *
26
+ * $size = 10 * 1024;
27
+ * $plaintext = '';
28
+ * for ($i = 0; $i < $size; $i++) {
29
+ * $plaintext.= 'a';
30
+ * }
31
+ *
32
+ * echo $des->decrypt($des->encrypt($plaintext));
33
+ * ?>
34
+ * </code>
35
+ *
36
+ * LICENSE: This library is free software; you can redistribute it and/or
37
+ * modify it under the terms of the GNU Lesser General Public
38
+ * License as published by the Free Software Foundation; either
39
+ * version 2.1 of the License, or (at your option) any later version.
40
+ *
41
+ * This library is distributed in the hope that it will be useful,
42
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
43
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44
+ * Lesser General Public License for more details.
45
+ *
46
+ * You should have received a copy of the GNU Lesser General Public
47
+ * License along with this library; if not, write to the Free Software
48
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
49
+ * MA 02111-1307 USA
50
+ *
51
+ * @category Crypt
52
+ * @package Crypt_DES
53
+ * @author Jim Wigginton <terrafrost@php.net>
54
+ * @copyright MMVII Jim Wigginton
55
+ * @license http://www.gnu.org/licenses/lgpl.txt
56
+ * @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
57
+ * @link http://phpseclib.sourceforge.net
58
+ */
59
+
60
+ /**#@+
61
+ * @access private
62
+ * @see Crypt_DES::_prepareKey()
63
+ * @see Crypt_DES::_processBlock()
64
+ */
65
+ /**
66
+ * Contains array_reverse($keys[CRYPT_DES_DECRYPT])
67
+ */
68
+ define('CRYPT_DES_ENCRYPT', 0);
69
+ /**
70
+ * Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
71
+ */
72
+ define('CRYPT_DES_DECRYPT', 1);
73
+ /**#@-*/
74
+
75
+ /**#@+
76
+ * @access public
77
+ * @see Crypt_DES::encrypt()
78
+ * @see Crypt_DES::decrypt()
79
+ */
80
+ /**
81
+ * Encrypt / decrypt using the Counter mode.
82
+ *
83
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
84
+ *
85
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
86
+ */
87
+ define('CRYPT_DES_MODE_CTR', -1);
88
+ /**
89
+ * Encrypt / decrypt using the Electronic Code Book mode.
90
+ *
91
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
92
+ */
93
+ define('CRYPT_DES_MODE_ECB', 1);
94
+ /**
95
+ * Encrypt / decrypt using the Code Book Chaining mode.
96
+ *
97
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
98
+ */
99
+ define('CRYPT_DES_MODE_CBC', 2);
100
+ /**#@-*/
101
+
102
+ /**#@+
103
+ * @access private
104
+ * @see Crypt_DES::Crypt_DES()
105
+ */
106
+ /**
107
+ * Toggles the internal implementation
108
+ */
109
+ define('CRYPT_DES_MODE_INTERNAL', 1);
110
+ /**
111
+ * Toggles the mcrypt implementation
112
+ */
113
+ define('CRYPT_DES_MODE_MCRYPT', 2);
114
+ /**#@-*/
115
+
116
+ /**
117
+ * Pure-PHP implementation of DES.
118
+ *
119
+ * @author Jim Wigginton <terrafrost@php.net>
120
+ * @version 0.1.0
121
+ * @access public
122
+ * @package Crypt_DES
123
+ */
124
+ class Crypt_DES {
125
+ /**
126
+ * The Key Schedule
127
+ *
128
+ * @see Crypt_DES::setKey()
129
+ * @var Array
130
+ * @access private
131
+ */
132
+ var $keys = "\0\0\0\0\0\0\0\0";
133
+
134
+ /**
135
+ * The Encryption Mode
136
+ *
137
+ * @see Crypt_DES::Crypt_DES()
138
+ * @var Integer
139
+ * @access private
140
+ */
141
+ var $mode;
142
+
143
+ /**
144
+ * Continuous Buffer status
145
+ *
146
+ * @see Crypt_DES::enableContinuousBuffer()
147
+ * @var Boolean
148
+ * @access private
149
+ */
150
+ var $continuousBuffer = false;
151
+
152
+ /**
153
+ * Padding status
154
+ *
155
+ * @see Crypt_DES::enablePadding()
156
+ * @var Boolean
157
+ * @access private
158
+ */
159
+ var $padding = true;
160
+
161
+ /**
162
+ * The Initialization Vector
163
+ *
164
+ * @see Crypt_DES::setIV()
165
+ * @var String
166
+ * @access private
167
+ */
168
+ var $iv = "\0\0\0\0\0\0\0\0";
169
+
170
+ /**
171
+ * A "sliding" Initialization Vector
172
+ *
173
+ * @see Crypt_DES::enableContinuousBuffer()
174
+ * @var String
175
+ * @access private
176
+ */
177
+ var $encryptIV = "\0\0\0\0\0\0\0\0";
178
+
179
+ /**
180
+ * A "sliding" Initialization Vector
181
+ *
182
+ * @see Crypt_DES::enableContinuousBuffer()
183
+ * @var String
184
+ * @access private
185
+ */
186
+ var $decryptIV = "\0\0\0\0\0\0\0\0";
187
+
188
+ /**
189
+ * mcrypt resource for encryption
190
+ *
191
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
192
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
193
+ *
194
+ * @see Crypt_AES::encrypt()
195
+ * @var String
196
+ * @access private
197
+ */
198
+ var $enmcrypt;
199
+
200
+ /**
201
+ * mcrypt resource for decryption
202
+ *
203
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
204
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
205
+ *
206
+ * @see Crypt_AES::decrypt()
207
+ * @var String
208
+ * @access private
209
+ */
210
+ var $demcrypt;
211
+
212
+ /**
213
+ * Does the (en|de)mcrypt resource need to be (re)initialized?
214
+ *
215
+ * @see setKey()
216
+ * @see setIV()
217
+ * @var Boolean
218
+ * @access private
219
+ */
220
+ var $changed = true;
221
+
222
+ /**
223
+ * Default Constructor.
224
+ *
225
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
226
+ * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
227
+ *
228
+ * @param optional Integer $mode
229
+ * @return Crypt_DES
230
+ * @access public
231
+ */
232
+ function Crypt_DES($mode = CRYPT_MODE_DES_CBC)
233
+ {
234
+ if ( !defined('CRYPT_DES_MODE') ) {
235
+ switch (true) {
236
+ case extension_loaded('mcrypt'):
237
+ // i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
238
+ // but since that can be changed after the object has been created, there doesn't seem to be
239
+ // a lot of point...
240
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
241
+ break;
242
+ default:
243
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
244
+ }
245
+ }
246
+
247
+ switch ( CRYPT_DES_MODE ) {
248
+ case CRYPT_DES_MODE_MCRYPT:
249
+ switch ($mode) {
250
+ case CRYPT_DES_MODE_ECB:
251
+ $this->mode = MCRYPT_MODE_ECB;
252
+ break;
253
+ case CRYPT_DES_MODE_CTR:
254
+ $this->mode = 'ctr';
255
+ //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
256
+ break;
257
+ case CRYPT_DES_MODE_CBC:
258
+ default:
259
+ $this->mode = MCRYPT_MODE_CBC;
260
+ }
261
+
262
+ break;
263
+ default:
264
+ switch ($mode) {
265
+ case CRYPT_DES_MODE_ECB:
266
+ case CRYPT_DES_MODE_CTR:
267
+ case CRYPT_DES_MODE_CBC:
268
+ $this->mode = $mode;
269
+ break;
270
+ default:
271
+ $this->mode = CRYPT_DES_MODE_CBC;
272
+ }
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Sets the key.
278
+ *
279
+ * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
280
+ * only use the first eight, if $key has more then eight characters in it, and pad $key with the
281
+ * null byte if it is less then eight characters long.
282
+ *
283
+ * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
284
+ *
285
+ * If the key is not explicitly set, it'll be assumed to be all zero's.
286
+ *
287
+ * @access public
288
+ * @param String $key
289
+ */
290
+ function setKey($key)
291
+ {
292
+ $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? substr($key, 0, 8) : $this->_prepareKey($key);
293
+ $this->changed = true;
294
+ }
295
+
296
+ /**
297
+ * Sets the initialization vector. (optional)
298
+ *
299
+ * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
300
+ * to be all zero's.
301
+ *
302
+ * @access public
303
+ * @param String $iv
304
+ */
305
+ function setIV($iv)
306
+ {
307
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
308
+ $this->changed = true;
309
+ }
310
+
311
+ /**
312
+ * Generate CTR XOR encryption key
313
+ *
314
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
315
+ * plaintext / ciphertext in CTR mode.
316
+ *
317
+ * @see Crypt_DES::decrypt()
318
+ * @see Crypt_DES::encrypt()
319
+ * @access public
320
+ * @param Integer $length
321
+ * @param String $iv
322
+ */
323
+ function _generate_xor($length, &$iv)
324
+ {
325
+ $xor = '';
326
+ $num_blocks = ($length + 7) >> 3;
327
+ for ($i = 0; $i < $num_blocks; $i++) {
328
+ $xor.= $iv;
329
+ for ($j = 4; $j <= 8; $j+=4) {
330
+ $temp = substr($iv, -$j, 4);
331
+ switch ($temp) {
332
+ case "\xFF\xFF\xFF\xFF":
333
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
334
+ break;
335
+ case "\x7F\xFF\xFF\xFF":
336
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
337
+ break 2;
338
+ default:
339
+ extract(unpack('Ncount', $temp));
340
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
341
+ break 2;
342
+ }
343
+ }
344
+ }
345
+
346
+ return $xor;
347
+ }
348
+
349
+ /**
350
+ * Encrypts a message.
351
+ *
352
+ * $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the
353
+ * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
354
+ * URL:
355
+ *
356
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
357
+ *
358
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
359
+ * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
360
+ * length.
361
+ *
362
+ * @see Crypt_DES::decrypt()
363
+ * @access public
364
+ * @param String $plaintext
365
+ */
366
+ function encrypt($plaintext)
367
+ {
368
+ if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
369
+ $plaintext = $this->_pad($plaintext);
370
+ }
371
+
372
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
373
+ if ($this->changed) {
374
+ if (!isset($this->enmcrypt)) {
375
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
376
+ }
377
+ mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
378
+ $this->changed = false;
379
+ }
380
+
381
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
382
+
383
+ if (!$this->continuousBuffer) {
384
+ mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
385
+ }
386
+
387
+ return $ciphertext;
388
+ }
389
+
390
+ if (!is_array($this->keys)) {
391
+ $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
392
+ }
393
+
394
+ $ciphertext = '';
395
+ switch ($this->mode) {
396
+ case CRYPT_DES_MODE_ECB:
397
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
398
+ $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
399
+ }
400
+ break;
401
+ case CRYPT_DES_MODE_CBC:
402
+ $xor = $this->encryptIV;
403
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
404
+ $block = substr($plaintext, $i, 8);
405
+ $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
406
+ $xor = $block;
407
+ $ciphertext.= $block;
408
+ }
409
+ if ($this->continuousBuffer) {
410
+ $this->encryptIV = $xor;
411
+ }
412
+ break;
413
+ case CRYPT_DES_MODE_CTR:
414
+ $xor = $this->encryptIV;
415
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
416
+ $block = substr($plaintext, $i, 8);
417
+ $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
418
+ $ciphertext.= $block ^ $key;
419
+ }
420
+ if ($this->continuousBuffer) {
421
+ $this->encryptIV = $xor;
422
+ }
423
+ }
424
+
425
+ return $ciphertext;
426
+ }
427
+
428
+ /**
429
+ * Decrypts a message.
430
+ *
431
+ * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
432
+ *
433
+ * @see Crypt_DES::encrypt()
434
+ * @access public
435
+ * @param String $ciphertext
436
+ */
437
+ function decrypt($ciphertext)
438
+ {
439
+ if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
440
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
441
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
442
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
443
+ }
444
+
445
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
446
+ if ($this->changed) {
447
+ if (!isset($this->demcrypt)) {
448
+ $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
449
+ }
450
+ mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
451
+ $this->changed = false;
452
+ }
453
+
454
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
455
+
456
+ if (!$this->continuousBuffer) {
457
+ mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
458
+ }
459
+
460
+ return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
461
+ }
462
+
463
+ if (!is_array($this->keys)) {
464
+ $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
465
+ }
466
+
467
+ $plaintext = '';
468
+ switch ($this->mode) {
469
+ case CRYPT_DES_MODE_ECB:
470
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
471
+ $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
472
+ }
473
+ break;
474
+ case CRYPT_DES_MODE_CBC:
475
+ $xor = $this->decryptIV;
476
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
477
+ $block = substr($ciphertext, $i, 8);
478
+ $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
479
+ $xor = $block;
480
+ }
481
+ if ($this->continuousBuffer) {
482
+ $this->decryptIV = $xor;
483
+ }
484
+ break;
485
+ case CRYPT_DES_MODE_CTR:
486
+ $xor = $this->decryptIV;
487
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
488
+ $block = substr($ciphertext, $i, 8);
489
+ $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
490
+ $plaintext.= $block ^ $key;
491
+ }
492
+ if ($this->continuousBuffer) {
493
+ $this->decryptIV = $xor;
494
+ }
495
+ }
496
+
497
+ return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
498
+ }
499
+
500
+ /**
501
+ * Treat consecutive "packets" as if they are a continuous buffer.
502
+ *
503
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
504
+ * will yield different outputs:
505
+ *
506
+ * <code>
507
+ * echo $des->encrypt(substr($plaintext, 0, 8));
508
+ * echo $des->encrypt(substr($plaintext, 8, 8));
509
+ * </code>
510
+ * <code>
511
+ * echo $des->encrypt($plaintext);
512
+ * </code>
513
+ *
514
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
515
+ * another, as demonstrated with the following:
516
+ *
517
+ * <code>
518
+ * $des->encrypt(substr($plaintext, 0, 8));
519
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
520
+ * </code>
521
+ * <code>
522
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
523
+ * </code>
524
+ *
525
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
526
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
527
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
528
+ *
529
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
530
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
531
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
532
+ * however, they are also less intuitive and more likely to cause you problems.
533
+ *
534
+ * @see Crypt_DES::disableContinuousBuffer()
535
+ * @access public
536
+ */
537
+ function enableContinuousBuffer()
538
+ {
539
+ $this->continuousBuffer = true;
540
+ }
541
+
542
+ /**
543
+ * Treat consecutive packets as if they are a discontinuous buffer.
544
+ *
545
+ * The default behavior.
546
+ *
547
+ * @see Crypt_DES::enableContinuousBuffer()
548
+ * @access public
549
+ */
550
+ function disableContinuousBuffer()
551
+ {
552
+ $this->continuousBuffer = false;
553
+ $this->encryptIV = $this->iv;
554
+ $this->decryptIV = $this->iv;
555
+ }
556
+
557
+ /**
558
+ * Pad "packets".
559
+ *
560
+ * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
561
+ * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
562
+ *
563
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
564
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
565
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
566
+ * transmitted separately)
567
+ *
568
+ * @see Crypt_DES::disablePadding()
569
+ * @access public
570
+ */
571
+ function enablePadding()
572
+ {
573
+ $this->padding = true;
574
+ }
575
+
576
+ /**
577
+ * Do not pad packets.
578
+ *
579
+ * @see Crypt_DES::enablePadding()
580
+ * @access public
581
+ */
582
+ function disablePadding()
583
+ {
584
+ $this->padding = false;
585
+ }
586
+
587
+ /**
588
+ * Pads a string
589
+ *
590
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
591
+ * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
592
+ *
593
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
594
+ * and padding will, hence forth, be enabled.
595
+ *
596
+ * @see Crypt_DES::_unpad()
597
+ * @access private
598
+ */
599
+ function _pad($text)
600
+ {
601
+ $length = strlen($text);
602
+
603
+ if (!$this->padding) {
604
+ if (($length & 7) == 0) {
605
+ return $text;
606
+ } else {
607
+ user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
608
+ $this->padding = true;
609
+ }
610
+ }
611
+
612
+ $pad = 8 - ($length & 7);
613
+ return str_pad($text, $length + $pad, chr($pad));
614
+ }
615
+
616
+ /**
617
+ * Unpads a string
618
+ *
619
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
620
+ * and false will be returned.
621
+ *
622
+ * @see Crypt_DES::_pad()
623
+ * @access private
624
+ */
625
+ function _unpad($text)
626
+ {
627
+ if (!$this->padding) {
628
+ return $text;
629
+ }
630
+
631
+ $length = ord($text[strlen($text) - 1]);
632
+
633
+ if (!$length || $length > 8) {
634
+ return false;
635
+ }
636
+
637
+ return substr($text, 0, -$length);
638
+ }
639
+
640
+ /**
641
+ * Encrypts or decrypts a 64-bit block
642
+ *
643
+ * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
644
+ * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
645
+ * idea of what this function does.
646
+ *
647
+ * @access private
648
+ * @param String $block
649
+ * @param Integer $mode
650
+ * @return String
651
+ */
652
+ function _processBlock($block, $mode)
653
+ {
654
+ // s-boxes. in the official DES docs, they're described as being matrices that
655
+ // one accesses by using the first and last bits to determine the row and the
656
+ // middle four bits to determine the column. in this implementation, they've
657
+ // been converted to vectors
658
+ static $sbox = array(
659
+ array(
660
+ 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
661
+ 3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
662
+ 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
663
+ 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
664
+ ),
665
+ array(
666
+ 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
667
+ 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
668
+ 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
669
+ 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
670
+ ),
671
+ array(
672
+ 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
673
+ 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
674
+ 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
675
+ 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
676
+ ),
677
+ array(
678
+ 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
679
+ 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
680
+ 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
681
+ 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
682
+ ),
683
+ array(
684
+ 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
685
+ 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
686
+ 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
687
+ 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
688
+ ),
689
+ array(
690
+ 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
691
+ 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
692
+ 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
693
+ 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
694
+ ),
695
+ array(
696
+ 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
697
+ 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
698
+ 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
699
+ 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
700
+ ),
701
+ array(
702
+ 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
703
+ 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
704
+ 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
705
+ 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
706
+ )
707
+ );
708
+
709
+ $keys = $this->keys;
710
+
711
+ $temp = unpack('Na/Nb', $block);
712
+ $block = array($temp['a'], $temp['b']);
713
+
714
+ // because php does arithmetic right shifts, if the most significant bits are set, right
715
+ // shifting those into the correct position will add 1's - not 0's. this will intefere
716
+ // with the | operation unless a second & is done. so we isolate these bits and left shift
717
+ // them into place. we then & each block with 0x7FFFFFFF to prevennt 1's from being added
718
+ // for any other shifts.
719
+ $msb = array(
720
+ ($block[0] >> 31) & 1,
721
+ ($block[1] >> 31) & 1
722
+ );
723
+ $block[0] &= 0x7FFFFFFF;
724
+ $block[1] &= 0x7FFFFFFF;
725
+
726
+ // we isolate the appropriate bit in the appropriate integer and shift as appropriate. in
727
+ // some cases, there are going to be multiple bits in the same integer that need to be shifted
728
+ // in the same way. we combine those into one shift operation.
729
+ $block = array(
730
+ (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) |
731
+ (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) |
732
+ (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) |
733
+ (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) |
734
+ (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) |
735
+ (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) |
736
+ (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) |
737
+ (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) |
738
+ (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) |
739
+ (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) |
740
+ (($block[0] & 0x00000004) << 9) | ( $block[0] & 0x00000400 ) |
741
+ (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) |
742
+ (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) |
743
+ (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24)
744
+ ,
745
+ (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) |
746
+ (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) |
747
+ (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) |
748
+ (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) |
749
+ ( $block[1] & 0x00200000 ) | (($block[1] & 0x20000000) >> 9) |
750
+ (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) |
751
+ (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) |
752
+ (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) |
753
+ (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) |
754
+ (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) |
755
+ (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) |
756
+ (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) |
757
+ (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) |
758
+ (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) |
759
+ ($msb[1] << 28) | ($msb[0] << 24)
760
+ );
761
+
762
+ for ($i = 0; $i < 16; $i++) {
763
+ // start of "the Feistel (F) function" - see the following URL:
764
+ // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
765
+ $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28)
766
+ | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24)
767
+ | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20)
768
+ | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16)
769
+ | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12)
770
+ | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8)
771
+ | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4)
772
+ | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]);
773
+
774
+ $msb = ($temp >> 31) & 1;
775
+ $temp &= 0x7FFFFFFF;
776
+ $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5)
777
+ | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10)
778
+ | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6)
779
+ | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9)
780
+ | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27)
781
+ | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8)
782
+ | (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16)
783
+ | (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15)
784
+ | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20)
785
+ | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3)
786
+ | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7)
787
+ | (($temp & 0x00200000) >> 19) | ($msb << 23);
788
+ // end of "the Feistel (F) function" - $newBlock is F's output
789
+
790
+ $temp = $block[1];
791
+ $block[1] = $block[0] ^ $newBlock;
792
+ $block[0] = $temp;
793
+ }
794
+
795
+ $msb = array(
796
+ ($block[0] >> 31) & 1,
797
+ ($block[1] >> 31) & 1
798
+ );
799
+ $block[0] &= 0x7FFFFFFF;
800
+ $block[1] &= 0x7FFFFFFF;
801
+
802
+ $block = array(
803
+ (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) |
804
+ (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) |
805
+ (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) |
806
+ (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) |
807
+ (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) |
808
+ (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) |
809
+ (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) |
810
+ (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) |
811
+ (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) |
812
+ (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) |
813
+ (($block[0] & 0x00000400) << 1) | ( $block[1] & 0x00000400 ) |
814
+ (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) |
815
+ (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) |
816
+ (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9)
817
+ ,
818
+ (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) |
819
+ (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) |
820
+ (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) |
821
+ (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) |
822
+ (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) |
823
+ ( $block[0] & 0x00200000 ) | (($block[1] & 0x00200000) >> 1) |
824
+ (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) |
825
+ (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) |
826
+ (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) |
827
+ (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) |
828
+ (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) |
829
+ (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) |
830
+ (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) |
831
+ ($msb[0] << 7) | ($msb[1] << 6)
832
+ );
833
+
834
+ return pack('NN', $block[0], $block[1]);
835
+ }
836
+
837
+ /**
838
+ * Creates the key schedule.
839
+ *
840
+ * @access private
841
+ * @param String $key
842
+ * @return Array
843
+ */
844
+ function _prepareKey($key)
845
+ {
846
+ static $shifts = array( // number of key bits shifted per round
847
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
848
+ );
849
+
850
+ // pad the key and remove extra characters as appropriate.
851
+ $key = str_pad(substr($key, 0, 8), 8, chr(0));
852
+
853
+ $temp = unpack('Na/Nb', $key);
854
+ $key = array($temp['a'], $temp['b']);
855
+ $msb = array(
856
+ ($key[0] >> 31) & 1,
857
+ ($key[1] >> 31) & 1
858
+ );
859
+ $key[0] &= 0x7FFFFFFF;
860
+ $key[1] &= 0x7FFFFFFF;
861
+
862
+ $key = array(
863
+ (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) |
864
+ (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) |
865
+ (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) |
866
+ (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) |
867
+ (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) |
868
+ (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) |
869
+ (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) |
870
+ (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28)
871
+ ,
872
+ (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) |
873
+ (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) |
874
+ (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) |
875
+ (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) |
876
+ (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) |
877
+ (($key[0] & 0x00000040) << 9) | ( $key[0] & 0x00004000 ) |
878
+ (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) |
879
+ (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) |
880
+ (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) |
881
+ (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) |
882
+ (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) |
883
+ (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) |
884
+ (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) |
885
+ ($msb[1] << 24) | ($msb[0] << 20)
886
+ );
887
+
888
+ $keys = array();
889
+ for ($i = 0; $i < 16; $i++) {
890
+ $key[0] <<= $shifts[$i];
891
+ $temp = ($key[0] & 0xF0000000) >> 28;
892
+ $key[0] = ($key[0] | $temp) & 0x0FFFFFFF;
893
+
894
+ $key[1] <<= $shifts[$i];
895
+ $temp = ($key[1] & 0xF0000000) >> 28;
896
+ $key[1] = ($key[1] | $temp) & 0x0FFFFFFF;
897
+
898
+ $temp = array(
899
+ (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) |
900
+ (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) |
901
+ (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23)
902
+ ,
903
+ (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) |
904
+ (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) |
905
+ (($key[1] & 0x00000080) >> 6)
906
+ ,
907
+ ( $key[1] & 0x00000020 ) | (($key[1] & 0x00000200) >> 5) |
908
+ (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) |
909
+ (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20)
910
+ ,
911
+ (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) |
912
+ (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) |
913
+ (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26)
914
+ ,
915
+ (($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010 ) |
916
+ (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) |
917
+ (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1)
918
+ ,
919
+ (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) |
920
+ (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) |
921
+ (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8)
922
+ ,
923
+ (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) |
924
+ (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) |
925
+ (($key[0] & 0x00400000) >> 21)
926
+ ,
927
+ (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) |
928
+ (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) |
929
+ (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24)
930
+ );
931
+
932
+ $keys[] = $temp;
933
+ }
934
+
935
+ $temp = array(
936
+ CRYPT_DES_ENCRYPT => $keys,
937
+ CRYPT_DES_DECRYPT => array_reverse($keys)
938
+ );
939
+
940
+ return $temp;
941
+ }
942
+ }
943
+
944
+ // vim: ts=4:sw=4:et:
945
+ // vim6: fdl=1:
lib/phpseclib/Crypt/Hash.php ADDED
@@ -0,0 +1,816 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
6
+ *
7
+ * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
8
+ *
9
+ * md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512
10
+ *
11
+ * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
12
+ * the hash. If no valid algorithm is provided, sha1 will be used.
13
+ *
14
+ * PHP versions 4 and 5
15
+ *
16
+ * {@internal The variable names are the same as those in
17
+ * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
18
+ *
19
+ * Here's a short example of how to use this library:
20
+ * <code>
21
+ * <?php
22
+ * include('Crypt/Hash.php');
23
+ *
24
+ * $hash = new Crypt_Hash('sha1');
25
+ *
26
+ * $hash->setKey('abcdefg');
27
+ *
28
+ * echo base64_encode($hash->hash('abcdefg'));
29
+ * ?>
30
+ * </code>
31
+ *
32
+ * LICENSE: This library is free software; you can redistribute it and/or
33
+ * modify it under the terms of the GNU Lesser General Public
34
+ * License as published by the Free Software Foundation; either
35
+ * version 2.1 of the License, or (at your option) any later version.
36
+ *
37
+ * This library is distributed in the hope that it will be useful,
38
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
39
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40
+ * Lesser General Public License for more details.
41
+ *
42
+ * You should have received a copy of the GNU Lesser General Public
43
+ * License along with this library; if not, write to the Free Software
44
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
45
+ * MA 02111-1307 USA
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_Hash
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @copyright MMVII Jim Wigginton
51
+ * @license http://www.gnu.org/licenses/lgpl.txt
52
+ * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $
53
+ * @link http://phpseclib.sourceforge.net
54
+ */
55
+
56
+ /**#@+
57
+ * @access private
58
+ * @see Crypt_Hash::Crypt_Hash()
59
+ */
60
+ /**
61
+ * Toggles the internal implementation
62
+ */
63
+ define('CRYPT_HASH_MODE_INTERNAL', 1);
64
+ /**
65
+ * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
66
+ */
67
+ define('CRYPT_HASH_MODE_MHASH', 2);
68
+ /**
69
+ * Toggles the hash() implementation, which works on PHP 5.1.2+.
70
+ */
71
+ define('CRYPT_HASH_MODE_HASH', 3);
72
+ /**#@-*/
73
+
74
+ /**
75
+ * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
76
+ *
77
+ * @author Jim Wigginton <terrafrost@php.net>
78
+ * @version 0.1.0
79
+ * @access public
80
+ * @package Crypt_Hash
81
+ */
82
+ class Crypt_Hash {
83
+ /**
84
+ * Byte-length of compression blocks / key (Internal HMAC)
85
+ *
86
+ * @see Crypt_Hash::setAlgorithm()
87
+ * @var Integer
88
+ * @access private
89
+ */
90
+ var $b;
91
+
92
+ /**
93
+ * Byte-length of hash output (Internal HMAC)
94
+ *
95
+ * @see Crypt_Hash::setHash()
96
+ * @var Integer
97
+ * @access private
98
+ */
99
+ var $l = false;
100
+
101
+ /**
102
+ * Hash Algorithm
103
+ *
104
+ * @see Crypt_Hash::setHash()
105
+ * @var String
106
+ * @access private
107
+ */
108
+ var $hash;
109
+
110
+ /**
111
+ * Key
112
+ *
113
+ * @see Crypt_Hash::setKey()
114
+ * @var String
115
+ * @access private
116
+ */
117
+ var $key = '';
118
+
119
+ /**
120
+ * Outer XOR (Internal HMAC)
121
+ *
122
+ * @see Crypt_Hash::setKey()
123
+ * @var String
124
+ * @access private
125
+ */
126
+ var $opad;
127
+
128
+ /**
129
+ * Inner XOR (Internal HMAC)
130
+ *
131
+ * @see Crypt_Hash::setKey()
132
+ * @var String
133
+ * @access private
134
+ */
135
+ var $ipad;
136
+
137
+ /**
138
+ * Default Constructor.
139
+ *
140
+ * @param optional String $hash
141
+ * @return Crypt_Hash
142
+ * @access public
143
+ */
144
+ function Crypt_Hash($hash = 'sha1')
145
+ {
146
+ if ( !defined('CRYPT_HASH_MODE') ) {
147
+ switch (true) {
148
+ case extension_loaded('hash'):
149
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
150
+ break;
151
+ case extension_loaded('mhash'):
152
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
153
+ break;
154
+ default:
155
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
156
+ }
157
+ }
158
+
159
+ $this->setHash($hash);
160
+ }
161
+
162
+ /**
163
+ * Sets the key for HMACs
164
+ *
165
+ * Keys can be of any length.
166
+ *
167
+ * @access public
168
+ * @param String $key
169
+ */
170
+ function setKey($key)
171
+ {
172
+ $this->key = $key;
173
+ }
174
+
175
+ /**
176
+ * Sets the hash function.
177
+ *
178
+ * @access public
179
+ * @param String $hash
180
+ */
181
+ function setHash($hash)
182
+ {
183
+ switch ($hash) {
184
+ case 'md5-96':
185
+ case 'sha1-96':
186
+ $this->l = 12; // 96 / 8 = 12
187
+ break;
188
+ case 'md2':
189
+ case 'md5':
190
+ $this->l = 16;
191
+ break;
192
+ case 'sha1':
193
+ $this->l = 20;
194
+ break;
195
+ case 'sha256':
196
+ $this->l = 32;
197
+ break;
198
+ case 'sha384':
199
+ $this->l = 48;
200
+ break;
201
+ case 'sha512':
202
+ $this->l = 64;
203
+ }
204
+
205
+ switch ($hash) {
206
+ case 'md2':
207
+ $mode = CRYPT_HASH_MODE_INTERNAL;
208
+ break;
209
+ case 'sha384':
210
+ case 'sha512':
211
+ $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
212
+ break;
213
+ default:
214
+ $mode = CRYPT_HASH_MODE;
215
+ }
216
+
217
+ switch ( $mode ) {
218
+ case CRYPT_HASH_MODE_MHASH:
219
+ switch ($hash) {
220
+ case 'md5':
221
+ case 'md5-96':
222
+ $this->hash = MHASH_MD5;
223
+ break;
224
+ case 'sha256':
225
+ $this->hash = MHASH_SHA256;
226
+ break;
227
+ case 'sha1':
228
+ case 'sha1-96':
229
+ default:
230
+ $this->hash = MHASH_SHA1;
231
+ }
232
+ return;
233
+ case CRYPT_HASH_MODE_HASH:
234
+ switch ($hash) {
235
+ case 'md5':
236
+ case 'md5-96':
237
+ $this->hash = 'md5';
238
+ return;
239
+ case 'sha256':
240
+ case 'sha384':
241
+ case 'sha512':
242
+ $this->hash = $hash;
243
+ return;
244
+ case 'sha1':
245
+ case 'sha1-96':
246
+ default:
247
+ $this->hash = 'sha1';
248
+ }
249
+ return;
250
+ }
251
+
252
+ switch ($hash) {
253
+ case 'md2':
254
+ $this->b = 16;
255
+ $this->hash = array($this, '_md2');
256
+ break;
257
+ case 'md5':
258
+ case 'md5-96':
259
+ $this->b = 64;
260
+ $this->hash = array($this, '_md5');
261
+ break;
262
+ case 'sha256':
263
+ $this->b = 64;
264
+ $this->hash = array($this, '_sha256');
265
+ break;
266
+ case 'sha384':
267
+ case 'sha512':
268
+ $this->b = 128;
269
+ $this->hash = array($this, '_sha512');
270
+ break;
271
+ case 'sha1':
272
+ case 'sha1-96':
273
+ default:
274
+ $this->b = 64;
275
+ $this->hash = array($this, '_sha1');
276
+ }
277
+
278
+ $this->ipad = str_repeat(chr(0x36), $this->b);
279
+ $this->opad = str_repeat(chr(0x5C), $this->b);
280
+ }
281
+
282
+ /**
283
+ * Compute the HMAC.
284
+ *
285
+ * @access public
286
+ * @param String $text
287
+ * @return String
288
+ */
289
+ function hash($text)
290
+ {
291
+ $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
292
+
293
+ if (!empty($this->key)) {
294
+ switch ( $mode ) {
295
+ case CRYPT_HASH_MODE_MHASH:
296
+ $output = mhash($this->hash, $text, $this->key);
297
+ break;
298
+ case CRYPT_HASH_MODE_HASH:
299
+ $output = hash_hmac($this->hash, $text, $this->key, true);
300
+ break;
301
+ case CRYPT_HASH_MODE_INTERNAL:
302
+ /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
303
+ resultant L byte string as the actual key to HMAC."
304
+
305
+ -- http://tools.ietf.org/html/rfc2104#section-2 */
306
+ $key = strlen($this->key) > $this->b ? call_user_func($this->$hash, $this->key) : $this->key;
307
+
308
+ $key = str_pad($key, $this->b, chr(0)); // step 1
309
+ $temp = $this->ipad ^ $key; // step 2
310
+ $temp .= $text; // step 3
311
+ $temp = call_user_func($this->hash, $temp); // step 4
312
+ $output = $this->opad ^ $key; // step 5
313
+ $output.= $temp; // step 6
314
+ $output = call_user_func($this->hash, $output); // step 7
315
+ }
316
+ } else {
317
+ switch ( $mode ) {
318
+ case CRYPT_HASH_MODE_MHASH:
319
+ $output = mhash($this->hash, $text);
320
+ break;
321
+ case CRYPT_HASH_MODE_HASH:
322
+ $output = hash($this->hash, $text, true);
323
+ break;
324
+ case CRYPT_HASH_MODE_INTERNAL:
325
+ $output = call_user_func($this->hash, $text);
326
+ }
327
+ }
328
+
329
+ return substr($output, 0, $this->l);
330
+ }
331
+
332
+ /**
333
+ * Returns the hash length (in bytes)
334
+ *
335
+ * @access private
336
+ * @return Integer
337
+ */
338
+ function getLength()
339
+ {
340
+ return $this->l;
341
+ }
342
+
343
+ /**
344
+ * Wrapper for MD5
345
+ *
346
+ * @access private
347
+ * @param String $text
348
+ */
349
+ function _md5($m)
350
+ {
351
+ return pack('H*', md5($m));
352
+ }
353
+
354
+ /**
355
+ * Wrapper for SHA1
356
+ *
357
+ * @access private
358
+ * @param String $text
359
+ */
360
+ function _sha1($m)
361
+ {
362
+ return pack('H*', sha1($m));
363
+ }
364
+
365
+ /**
366
+ * Pure-PHP implementation of MD2
367
+ *
368
+ * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
369
+ *
370
+ * @access private
371
+ * @param String $text
372
+ */
373
+ function _md2($m)
374
+ {
375
+ static $s = array(
376
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
377
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
378
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
379
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
380
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
381
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
382
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
383
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
384
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
385
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
386
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
387
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
388
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
389
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
390
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
391
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
392
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
393
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
394
+ );
395
+
396
+ // Step 1. Append Padding Bytes
397
+ $pad = 16 - (strlen($m) & 0xF);
398
+ $m.= str_repeat(chr($pad), $pad);
399
+
400
+ $length = strlen($m);
401
+
402
+ // Step 2. Append Checksum
403
+ $c = str_repeat(chr(0), 16);
404
+ $l = chr(0);
405
+ for ($i = 0; $i < $length; $i+= 16) {
406
+ for ($j = 0; $j < 16; $j++) {
407
+ $c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
408
+ $l = $c[$j];
409
+ }
410
+ }
411
+ $m.= $c;
412
+
413
+ $length+= 16;
414
+
415
+ // Step 3. Initialize MD Buffer
416
+ $x = str_repeat(chr(0), 48);
417
+
418
+ // Step 4. Process Message in 16-Byte Blocks
419
+ for ($i = 0; $i < $length; $i+= 16) {
420
+ for ($j = 0; $j < 16; $j++) {
421
+ $x[$j + 16] = $m[$i + $j];
422
+ $x[$j + 32] = $x[$j + 16] ^ $x[$j];
423
+ }
424
+ $t = chr(0);
425
+ for ($j = 0; $j < 18; $j++) {
426
+ for ($k = 0; $k < 48; $k++) {
427
+ $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
428
+ //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
429
+ }
430
+ $t = chr(ord($t) + $j);
431
+ }
432
+ }
433
+
434
+ // Step 5. Output
435
+ return substr($x, 0, 16);
436
+ }
437
+
438
+ /**
439
+ * Pure-PHP implementation of SHA256
440
+ *
441
+ * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
442
+ *
443
+ * @access private
444
+ * @param String $text
445
+ */
446
+ function _sha256($m)
447
+ {
448
+ if (extension_loaded('suhosin')) {
449
+ return pack('H*', sha256($m));
450
+ }
451
+
452
+ // Initialize variables
453
+ $hash = array(
454
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
455
+ );
456
+ // Initialize table of round constants
457
+ // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
458
+ static $k = array(
459
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
460
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
461
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
462
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
463
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
464
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
465
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
466
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
467
+ );
468
+
469
+ // Pre-processing
470
+ $length = strlen($m);
471
+ // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
472
+ $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
473
+ $m[$length] = chr(0x80);
474
+ // we don't support hashing strings 512MB long
475
+ $m.= pack('N2', 0, $length << 3);
476
+
477
+ // Process the message in successive 512-bit chunks
478
+ $chunks = str_split($m, 64);
479
+ foreach ($chunks as $chunk) {
480
+ $w = array();
481
+ for ($i = 0; $i < 16; $i++) {
482
+ extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
483
+ $w[] = $temp;
484
+ }
485
+
486
+ // Extend the sixteen 32-bit words into sixty-four 32-bit words
487
+ for ($i = 16; $i < 64; $i++) {
488
+ $s0 = $this->_rightRotate($w[$i - 15], 7) ^
489
+ $this->_rightRotate($w[$i - 15], 18) ^
490
+ $this->_rightShift( $w[$i - 15], 3);
491
+ $s1 = $this->_rightRotate($w[$i - 2], 17) ^
492
+ $this->_rightRotate($w[$i - 2], 19) ^
493
+ $this->_rightShift( $w[$i - 2], 10);
494
+ $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
495
+
496
+ }
497
+
498
+ // Initialize hash value for this chunk
499
+ list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
500
+
501
+ // Main loop
502
+ for ($i = 0; $i < 64; $i++) {
503
+ $s0 = $this->_rightRotate($a, 2) ^
504
+ $this->_rightRotate($a, 13) ^
505
+ $this->_rightRotate($a, 22);
506
+ $maj = ($a & $b) ^
507
+ ($a & $c) ^
508
+ ($b & $c);
509
+ $t2 = $this->_add($s0, $maj);
510
+
511
+ $s1 = $this->_rightRotate($e, 6) ^
512
+ $this->_rightRotate($e, 11) ^
513
+ $this->_rightRotate($e, 25);
514
+ $ch = ($e & $f) ^
515
+ ($this->_not($e) & $g);
516
+ $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
517
+
518
+ $h = $g;
519
+ $g = $f;
520
+ $f = $e;
521
+ $e = $this->_add($d, $t1);
522
+ $d = $c;
523
+ $c = $b;
524
+ $b = $a;
525
+ $a = $this->_add($t1, $t2);
526
+ }
527
+
528
+ // Add this chunk's hash to result so far
529
+ $hash = array(
530
+ $this->_add($hash[0], $a),
531
+ $this->_add($hash[1], $b),
532
+ $this->_add($hash[2], $c),
533
+ $this->_add($hash[3], $d),
534
+ $this->_add($hash[4], $e),
535
+ $this->_add($hash[5], $f),
536
+ $this->_add($hash[6], $g),
537
+ $this->_add($hash[7], $h)
538
+ );
539
+ }
540
+
541
+ // Produce the final hash value (big-endian)
542
+ return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
543
+ }
544
+
545
+ /**
546
+ * Pure-PHP implementation of SHA384 and SHA512
547
+ *
548
+ * @access private
549
+ * @param String $text
550
+ */
551
+ function _sha512($m)
552
+ {
553
+ if (!class_exists('Math_BigInteger')) {
554
+ require_once('Math/BigInteger.php');
555
+ }
556
+
557
+ static $init384, $init512, $k;
558
+
559
+ if (!isset($k)) {
560
+ // Initialize variables
561
+ $init384 = array( // initial values for SHA384
562
+ 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
563
+ '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
564
+ );
565
+ $init512 = array( // initial values for SHA512
566
+ '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
567
+ '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
568
+ );
569
+
570
+ for ($i = 0; $i < 8; $i++) {
571
+ $init384[$i] = new Math_BigInteger($init384[$i], 16);
572
+ $init384[$i]->setPrecision(64);
573
+ $init512[$i] = new Math_BigInteger($init512[$i], 16);
574
+ $init512[$i]->setPrecision(64);
575
+ }
576
+
577
+ // Initialize table of round constants
578
+ // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
579
+ $k = array(
580
+ '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
581
+ '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
582
+ 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
583
+ '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
584
+ 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
585
+ '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
586
+ '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
587
+ 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
588
+ '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
589
+ '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
590
+ 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
591
+ 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
592
+ '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
593
+ '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
594
+ '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
595
+ '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
596
+ 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
597
+ '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
598
+ '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
599
+ '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
600
+ );
601
+
602
+ for ($i = 0; $i < 80; $i++) {
603
+ $k[$i] = new Math_BigInteger($k[$i], 16);
604
+ }
605
+ }
606
+
607
+ $hash = $this->l == 48 ? $init384 : $init512;
608
+
609
+ // Pre-processing
610
+ $length = strlen($m);
611
+ // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
612
+ $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
613
+ $m[$length] = chr(0x80);
614
+ // we don't support hashing strings 512MB long
615
+ $m.= pack('N4', 0, 0, 0, $length << 3);
616
+
617
+ // Process the message in successive 1024-bit chunks
618
+ $chunks = str_split($m, 128);
619
+ foreach ($chunks as $chunk) {
620
+ $w = array();
621
+ for ($i = 0; $i < 16; $i++) {
622
+ $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
623
+ $temp->setPrecision(64);
624
+ $w[] = $temp;
625
+ }
626
+
627
+ // Extend the sixteen 32-bit words into eighty 32-bit words
628
+ for ($i = 16; $i < 80; $i++) {
629
+ $temp = array(
630
+ $w[$i - 15]->bitwise_rightRotate(1),
631
+ $w[$i - 15]->bitwise_rightRotate(8),
632
+ $w[$i - 15]->bitwise_rightShift(7)
633
+ );
634
+ $s0 = $temp[0]->bitwise_xor($temp[1]);
635
+ $s0 = $s0->bitwise_xor($temp[2]);
636
+ $temp = array(
637
+ $w[$i - 2]->bitwise_rightRotate(19),
638
+ $w[$i - 2]->bitwise_rightRotate(61),
639
+ $w[$i - 2]->bitwise_rightShift(6)
640
+ );
641
+ $s1 = $temp[0]->bitwise_xor($temp[1]);
642
+ $s1 = $s1->bitwise_xor($temp[2]);
643
+ $w[$i] = $w[$i - 16]->copy();
644
+ $w[$i] = $w[$i]->add($s0);
645
+ $w[$i] = $w[$i]->add($w[$i - 7]);
646
+ $w[$i] = $w[$i]->add($s1);
647
+ }
648
+
649
+ // Initialize hash value for this chunk
650
+ $a = $hash[0]->copy();
651
+ $b = $hash[1]->copy();
652
+ $c = $hash[2]->copy();
653
+ $d = $hash[3]->copy();
654
+ $e = $hash[4]->copy();
655
+ $f = $hash[5]->copy();
656
+ $g = $hash[6]->copy();
657
+ $h = $hash[7]->copy();
658
+
659
+ // Main loop
660
+ for ($i = 0; $i < 80; $i++) {
661
+ $temp = array(
662
+ $a->bitwise_rightRotate(28),
663
+ $a->bitwise_rightRotate(34),
664
+ $a->bitwise_rightRotate(39)
665
+ );
666
+ $s0 = $temp[0]->bitwise_xor($temp[1]);
667
+ $s0 = $s0->bitwise_xor($temp[2]);
668
+ $temp = array(
669
+ $a->bitwise_and($b),
670
+ $a->bitwise_and($c),
671
+ $b->bitwise_and($c)
672
+ );
673
+ $maj = $temp[0]->bitwise_xor($temp[1]);
674
+ $maj = $maj->bitwise_xor($temp[2]);
675
+ $t2 = $s0->add($maj);
676
+
677
+ $temp = array(
678
+ $e->bitwise_rightRotate(14),
679
+ $e->bitwise_rightRotate(18),
680
+ $e->bitwise_rightRotate(41)
681
+ );
682
+ $s1 = $temp[0]->bitwise_xor($temp[1]);
683
+ $s1 = $s1->bitwise_xor($temp[2]);
684
+ $temp = array(
685
+ $e->bitwise_and($f),
686
+ $g->bitwise_and($e->bitwise_not())
687
+ );
688
+ $ch = $temp[0]->bitwise_xor($temp[1]);
689
+ $t1 = $h->add($s1);
690
+ $t1 = $t1->add($ch);
691
+ $t1 = $t1->add($k[$i]);
692
+ $t1 = $t1->add($w[$i]);
693
+
694
+ $h = $g->copy();
695
+ $g = $f->copy();
696
+ $f = $e->copy();
697
+ $e = $d->add($t1);
698
+ $d = $c->copy();
699
+ $c = $b->copy();
700
+ $b = $a->copy();
701
+ $a = $t1->add($t2);
702
+ }
703
+
704
+ // Add this chunk's hash to result so far
705
+ $hash = array(
706
+ $hash[0]->add($a),
707
+ $hash[1]->add($b),
708
+ $hash[2]->add($c),
709
+ $hash[3]->add($d),
710
+ $hash[4]->add($e),
711
+ $hash[5]->add($f),
712
+ $hash[6]->add($g),
713
+ $hash[7]->add($h)
714
+ );
715
+ }
716
+
717
+ // Produce the final hash value (big-endian)
718
+ // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
719
+ $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
720
+ $hash[4]->toBytes() . $hash[5]->toBytes();
721
+ if ($this->l != 48) {
722
+ $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
723
+ }
724
+
725
+ return $temp;
726
+ }
727
+
728
+ /**
729
+ * Right Rotate
730
+ *
731
+ * @access private
732
+ * @param Integer $int
733
+ * @param Integer $amt
734
+ * @see _sha256()
735
+ * @return Integer
736
+ */
737
+ function _rightRotate($int, $amt)
738
+ {
739
+ $invamt = 32 - $amt;
740
+ $mask = (1 << $invamt) - 1;
741
+ return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
742
+ }
743
+
744
+ /**
745
+ * Right Shift
746
+ *
747
+ * @access private
748
+ * @param Integer $int
749
+ * @param Integer $amt
750
+ * @see _sha256()
751
+ * @return Integer
752
+ */
753
+ function _rightShift($int, $amt)
754
+ {
755
+ $mask = (1 << (32 - $amt)) - 1;
756
+ return ($int >> $amt) & $mask;
757
+ }
758
+
759
+ /**
760
+ * Not
761
+ *
762
+ * @access private
763
+ * @param Integer $int
764
+ * @see _sha256()
765
+ * @return Integer
766
+ */
767
+ function _not($int)
768
+ {
769
+ return ~$int & 0xFFFFFFFF;
770
+ }
771
+
772
+ /**
773
+ * Add
774
+ *
775
+ * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
776
+ * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
777
+ *
778
+ * @param String $string
779
+ * @param optional Integer $index
780
+ * @return String
781
+ * @see _sha256()
782
+ * @access private
783
+ */
784
+ function _add()
785
+ {
786
+ static $mod;
787
+ if (!isset($mod)) {
788
+ $mod = pow(2, 32);
789
+ }
790
+
791
+ $result = 0;
792
+ $arguments = func_get_args();
793
+ foreach ($arguments as $argument) {
794
+ $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
795
+ }
796
+
797
+ return fmod($result, $mod);
798
+ }
799
+
800
+ /**
801
+ * String Shift
802
+ *
803
+ * Inspired by array_shift
804
+ *
805
+ * @param String $string
806
+ * @param optional Integer $index
807
+ * @return String
808
+ * @access private
809
+ */
810
+ function _string_shift(&$string, $index = 1)
811
+ {
812
+ $substr = substr($string, 0, $index);
813
+ $string = substr($string, $index);
814
+ return $substr;
815
+ }
816
+ }
lib/phpseclib/Crypt/RC4.php ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of RC4.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Useful resources are as follows:
12
+ *
13
+ * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
14
+ * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
15
+ *
16
+ * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
17
+ * ARCFOUR or ARC4 because RC4 is how it is refered to in the SSH1 specification.
18
+ *
19
+ * Here's a short example of how to use this library:
20
+ * <code>
21
+ * <?php
22
+ * include('Crypt/RC4.php');
23
+ *
24
+ * $rc4 = new Crypt_RC4();
25
+ *
26
+ * $rc4->setKey('abcdefgh');
27
+ *
28
+ * $size = 10 * 1024;
29
+ * $plaintext = '';
30
+ * for ($i = 0; $i < $size; $i++) {
31
+ * $plaintext.= 'a';
32
+ * }
33
+ *
34
+ * echo $rc4->decrypt($rc4->encrypt($plaintext));
35
+ * ?>
36
+ * </code>
37
+ *
38
+ * LICENSE: This library is free software; you can redistribute it and/or
39
+ * modify it under the terms of the GNU Lesser General Public
40
+ * License as published by the Free Software Foundation; either
41
+ * version 2.1 of the License, or (at your option) any later version.
42
+ *
43
+ * This library is distributed in the hope that it will be useful,
44
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
45
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
46
+ * Lesser General Public License for more details.
47
+ *
48
+ * You should have received a copy of the GNU Lesser General Public
49
+ * License along with this library; if not, write to the Free Software
50
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
51
+ * MA 02111-1307 USA
52
+ *
53
+ * @category Crypt
54
+ * @package Crypt_RC4
55
+ * @author Jim Wigginton <terrafrost@php.net>
56
+ * @copyright MMVII Jim Wigginton
57
+ * @license http://www.gnu.org/licenses/lgpl.txt
58
+ * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
59
+ * @link http://phpseclib.sourceforge.net
60
+ */
61
+
62
+ /**#@+
63
+ * @access private
64
+ * @see Crypt_RC4::Crypt_RC4()
65
+ */
66
+ /**
67
+ * Toggles the internal implementation
68
+ */
69
+ define('CRYPT_RC4_MODE_INTERNAL', 1);
70
+ /**
71
+ * Toggles the mcrypt implementation
72
+ */
73
+ define('CRYPT_RC4_MODE_MCRYPT', 2);
74
+ /**#@-*/
75
+
76
+ /**#@+
77
+ * @access private
78
+ * @see Crypt_RC4::_crypt()
79
+ */
80
+ define('CRYPT_RC4_ENCRYPT', 0);
81
+ define('CRYPT_RC4_DECRYPT', 1);
82
+ /**#@-*/
83
+
84
+ /**
85
+ * Pure-PHP implementation of RC4.
86
+ *
87
+ * @author Jim Wigginton <terrafrost@php.net>
88
+ * @version 0.1.0
89
+ * @access public
90
+ * @package Crypt_RC4
91
+ */
92
+ class Crypt_RC4 {
93
+ /**
94
+ * The Key
95
+ *
96
+ * @see Crypt_RC4::setKey()
97
+ * @var String
98
+ * @access private
99
+ */
100
+ var $key = "\0";
101
+
102
+ /**
103
+ * The Key Stream for encryption
104
+ *
105
+ * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
106
+ *
107
+ * @see Crypt_RC4::setKey()
108
+ * @var Array
109
+ * @access private
110
+ */
111
+ var $encryptStream = false;
112
+
113
+ /**
114
+ * The Key Stream for decryption
115
+ *
116
+ * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
117
+ *
118
+ * @see Crypt_RC4::setKey()
119
+ * @var Array
120
+ * @access private
121
+ */
122
+ var $decryptStream = false;
123
+
124
+ /**
125
+ * The $i and $j indexes for encryption
126
+ *
127
+ * @see Crypt_RC4::_crypt()
128
+ * @var Integer
129
+ * @access private
130
+ */
131
+ var $encryptIndex = 0;
132
+
133
+ /**
134
+ * The $i and $j indexes for decryption
135
+ *
136
+ * @see Crypt_RC4::_crypt()
137
+ * @var Integer
138
+ * @access private
139
+ */
140
+ var $decryptIndex = 0;
141
+
142
+ /**
143
+ * MCrypt parameters
144
+ *
145
+ * @see Crypt_RC4::setMCrypt()
146
+ * @var Array
147
+ * @access private
148
+ */
149
+ var $mcrypt = array('', '');
150
+
151
+ /**
152
+ * The Encryption Algorithm
153
+ *
154
+ * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
155
+ *
156
+ * @see Crypt_RC4::Crypt_RC4()
157
+ * @var Integer
158
+ * @access private
159
+ */
160
+ var $mode;
161
+
162
+ /**
163
+ * Default Constructor.
164
+ *
165
+ * Determines whether or not the mcrypt extension should be used.
166
+ *
167
+ * @param optional Integer $mode
168
+ * @return Crypt_RC4
169
+ * @access public
170
+ */
171
+ function Crypt_RC4()
172
+ {
173
+ if ( !defined('CRYPT_RC4_MODE') ) {
174
+ switch (true) {
175
+ case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')):
176
+ // i'd check to see if rc4 was supported, by doing in_array('arcfour', mcrypt_list_algorithms('')),
177
+ // but since that can be changed after the object has been created, there doesn't seem to be
178
+ // a lot of point...
179
+ define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
180
+ break;
181
+ default:
182
+ define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
183
+ }
184
+ }
185
+
186
+ switch ( CRYPT_RC4_MODE ) {
187
+ case CRYPT_RC4_MODE_MCRYPT:
188
+ switch (true) {
189
+ case defined('MCRYPT_ARCFOUR'):
190
+ $this->mode = MCRYPT_ARCFOUR;
191
+ break;
192
+ case defined('MCRYPT_RC4');
193
+ $this->mode = MCRYPT_RC4;
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Sets the key.
200
+ *
201
+ * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
202
+ * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
203
+ *
204
+ * @access public
205
+ * @param String $key
206
+ */
207
+ function setKey($key)
208
+ {
209
+ $this->key = $key;
210
+
211
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
212
+ return;
213
+ }
214
+
215
+ $keyLength = strlen($key);
216
+ $keyStream = array();
217
+ for ($i = 0; $i < 256; $i++) {
218
+ $keyStream[$i] = $i;
219
+ }
220
+ $j = 0;
221
+ for ($i = 0; $i < 256; $i++) {
222
+ $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
223
+ $temp = $keyStream[$i];
224
+ $keyStream[$i] = $keyStream[$j];
225
+ $keyStream[$j] = $temp;
226
+ }
227
+
228
+ $this->encryptIndex = $this->decryptIndex = array(0, 0);
229
+ $this->encryptStream = $this->decryptStream = $keyStream;
230
+ }
231
+
232
+ /**
233
+ * Dummy function.
234
+ *
235
+ * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
236
+ * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
237
+ * calling setKey().
238
+ *
239
+ * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
240
+ * the IV's are relatively easy to predict, an attack described by
241
+ * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
242
+ * can be used to quickly guess at the rest of the key. The following links elaborate:
243
+ *
244
+ * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
245
+ * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
246
+ *
247
+ * @param String $iv
248
+ * @see Crypt_RC4::setKey()
249
+ * @access public
250
+ */
251
+ function setIV($iv)
252
+ {
253
+ }
254
+
255
+ /**
256
+ * Sets MCrypt parameters. (optional)
257
+ *
258
+ * If MCrypt is being used, empty strings will be used, unless otherwise specified.
259
+ *
260
+ * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
261
+ * @access public
262
+ * @param optional Integer $algorithm_directory
263
+ * @param optional Integer $mode_directory
264
+ */
265
+ function setMCrypt($algorithm_directory = '', $mode_directory = '')
266
+ {
267
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
268
+ $this->mcrypt = array($algorithm_directory, $mode_directory);
269
+ $this->_closeMCrypt();
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Encrypts a message.
275
+ *
276
+ * @see Crypt_RC4::_crypt()
277
+ * @access public
278
+ * @param String $plaintext
279
+ */
280
+ function encrypt($plaintext)
281
+ {
282
+ return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
283
+ }
284
+
285
+ /**
286
+ * Decrypts a message.
287
+ *
288
+ * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
289
+ * Atleast if the continuous buffer is disabled.
290
+ *
291
+ * @see Crypt_RC4::_crypt()
292
+ * @access public
293
+ * @param String $ciphertext
294
+ */
295
+ function decrypt($ciphertext)
296
+ {
297
+ return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
298
+ }
299
+
300
+ /**
301
+ * Encrypts or decrypts a message.
302
+ *
303
+ * @see Crypt_RC4::encrypt()
304
+ * @see Crypt_RC4::decrypt()
305
+ * @access private
306
+ * @param String $text
307
+ * @param Integer $mode
308
+ */
309
+ function _crypt($text, $mode)
310
+ {
311
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
312
+ $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
313
+
314
+ if ($this->$keyStream === false) {
315
+ $this->$keyStream = mcrypt_module_open($this->mode, $this->mcrypt[0], MCRYPT_MODE_STREAM, $this->mcrypt[1]);
316
+ mcrypt_generic_init($this->$keyStream, $this->key, '');
317
+ } else if (!$this->continuousBuffer) {
318
+ mcrypt_generic_init($this->$keyStream, $this->key, '');
319
+ }
320
+ $newText = mcrypt_generic($this->$keyStream, $text);
321
+ if (!$this->continuousBuffer) {
322
+ mcrypt_generic_deinit($this->$keyStream);
323
+ }
324
+
325
+ return $newText;
326
+ }
327
+
328
+ if ($this->encryptStream === false) {
329
+ $this->setKey($this->key);
330
+ }
331
+
332
+ switch ($mode) {
333
+ case CRYPT_RC4_ENCRYPT:
334
+ $keyStream = $this->encryptStream;
335
+ list($i, $j) = $this->encryptIndex;
336
+ break;
337
+ case CRYPT_RC4_DECRYPT:
338
+ $keyStream = $this->decryptStream;
339
+ list($i, $j) = $this->decryptIndex;
340
+ }
341
+
342
+ $newText = '';
343
+ for ($k = 0; $k < strlen($text); $k++) {
344
+ $i = ($i + 1) & 255;
345
+ $j = ($j + $keyStream[$i]) & 255;
346
+ $temp = $keyStream[$i];
347
+ $keyStream[$i] = $keyStream[$j];
348
+ $keyStream[$j] = $temp;
349
+ $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
350
+ $newText.= chr(ord($text[$k]) ^ $temp);
351
+ }
352
+
353
+ if ($this->continuousBuffer) {
354
+ switch ($mode) {
355
+ case CRYPT_RC4_ENCRYPT:
356
+ $this->encryptStream = $keyStream;
357
+ $this->encryptIndex = array($i, $j);
358
+ break;
359
+ case CRYPT_RC4_DECRYPT:
360
+ $this->decryptStream = $keyStream;
361
+ $this->decryptIndex = array($i, $j);
362
+ }
363
+ }
364
+
365
+ return $newText;
366
+ }
367
+
368
+ /**
369
+ * Treat consecutive "packets" as if they are a continuous buffer.
370
+ *
371
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
372
+ * will yield different outputs:
373
+ *
374
+ * <code>
375
+ * echo $rc4->encrypt(substr($plaintext, 0, 8));
376
+ * echo $rc4->encrypt(substr($plaintext, 8, 8));
377
+ * </code>
378
+ * <code>
379
+ * echo $rc4->encrypt($plaintext);
380
+ * </code>
381
+ *
382
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
383
+ * another, as demonstrated with the following:
384
+ *
385
+ * <code>
386
+ * $rc4->encrypt(substr($plaintext, 0, 8));
387
+ * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
388
+ * </code>
389
+ * <code>
390
+ * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
391
+ * </code>
392
+ *
393
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
394
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
395
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
396
+ *
397
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
398
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
399
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
400
+ * however, they are also less intuitive and more likely to cause you problems.
401
+ *
402
+ * @see Crypt_RC4::disableContinuousBuffer()
403
+ * @access public
404
+ */
405
+ function enableContinuousBuffer()
406
+ {
407
+ $this->continuousBuffer = true;
408
+ }
409
+
410
+ /**
411
+ * Treat consecutive packets as if they are a discontinuous buffer.
412
+ *
413
+ * The default behavior.
414
+ *
415
+ * @see Crypt_RC4::enableContinuousBuffer()
416
+ * @access public
417
+ */
418
+ function disableContinuousBuffer()
419
+ {
420
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
421
+ $this->encryptIndex = $this->decryptIndex = array(0, 0);
422
+ $this->setKey($this->key);
423
+ }
424
+
425
+ $this->continuousBuffer = false;
426
+ }
427
+
428
+ /**
429
+ * Dummy function.
430
+ *
431
+ * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
432
+ * included is so that you can switch between a block cipher and a stream cipher transparently.
433
+ *
434
+ * @see Crypt_RC4::disablePadding()
435
+ * @access public
436
+ */
437
+ function enablePadding()
438
+ {
439
+ }
440
+
441
+ /**
442
+ * Dummy function.
443
+ *
444
+ * @see Crypt_RC4::enablePadding()
445
+ * @access public
446
+ */
447
+ function disablePadding()
448
+ {
449
+ }
450
+
451
+ /**
452
+ * Class destructor.
453
+ *
454
+ * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
455
+ * needs to be called if mcrypt is being used.
456
+ *
457
+ * @access public
458
+ */
459
+ function __destruct()
460
+ {
461
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
462
+ $this->_closeMCrypt();
463
+ }
464
+ }
465
+
466
+ /**
467
+ * Properly close the MCrypt objects.
468
+ *
469
+ * @access prviate
470
+ */
471
+ function _closeMCrypt()
472
+ {
473
+ if ( $this->encryptStream !== false ) {
474
+ if ( $this->continuousBuffer ) {
475
+ mcrypt_generic_deinit($this->encryptStream);
476
+ }
477
+
478
+ mcrypt_module_close($this->encryptStream);
479
+
480
+ $this->encryptStream = false;
481
+ }
482
+
483
+ if ( $this->decryptStream !== false ) {
484
+ if ( $this->continuousBuffer ) {
485
+ mcrypt_generic_deinit($this->decryptStream);
486
+ }
487
+
488
+ mcrypt_module_close($this->decryptStream);
489
+
490
+ $this->decryptStream = false;
491
+ }
492
+ }
493
+ }
lib/phpseclib/Crypt/RSA.php ADDED
@@ -0,0 +1,2119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Here's an example of how to encrypt and decrypt text with this library:
10
+ * <code>
11
+ * <?php
12
+ * include('Crypt/RSA.php');
13
+ *
14
+ * $rsa = new Crypt_RSA();
15
+ * extract($rsa->createKey());
16
+ *
17
+ * $plaintext = 'terrafrost';
18
+ *
19
+ * $rsa->loadKey($privatekey);
20
+ * $ciphertext = $rsa->encrypt($plaintext);
21
+ *
22
+ * $rsa->loadKey($publickey);
23
+ * echo $rsa->decrypt($ciphertext);
24
+ * ?>
25
+ * </code>
26
+ *
27
+ * Here's an example of how to create signatures and verify signatures with this library:
28
+ * <code>
29
+ * <?php
30
+ * include('Crypt/RSA.php');
31
+ *
32
+ * $rsa = new Crypt_RSA();
33
+ * extract($rsa->createKey());
34
+ *
35
+ * $plaintext = 'terrafrost';
36
+ *
37
+ * $rsa->loadKey($privatekey);
38
+ * $signature = $rsa->sign($plaintext);
39
+ *
40
+ * $rsa->loadKey($publickey);
41
+ * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
42
+ * ?>
43
+ * </code>
44
+ *
45
+ * LICENSE: This library is free software; you can redistribute it and/or
46
+ * modify it under the terms of the GNU Lesser General Public
47
+ * License as published by the Free Software Foundation; either
48
+ * version 2.1 of the License, or (at your option) any later version.
49
+ *
50
+ * This library is distributed in the hope that it will be useful,
51
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
52
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
53
+ * Lesser General Public License for more details.
54
+ *
55
+ * You should have received a copy of the GNU Lesser General Public
56
+ * License along with this library; if not, write to the Free Software
57
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
58
+ * MA 02111-1307 USA
59
+ *
60
+ * @category Crypt
61
+ * @package Crypt_RSA
62
+ * @author Jim Wigginton <terrafrost@php.net>
63
+ * @copyright MMIX Jim Wigginton
64
+ * @license http://www.gnu.org/licenses/lgpl.txt
65
+ * @version $Id: RSA.php,v 1.15 2010/04/10 15:57:02 terrafrost Exp $
66
+ * @link http://phpseclib.sourceforge.net
67
+ */
68
+
69
+ /**
70
+ * Include Math_BigInteger
71
+ */
72
+ require_once('Math/BigInteger.php');
73
+
74
+ /**
75
+ * Include Crypt_Random
76
+ */
77
+ require_once('Crypt/Random.php');
78
+
79
+ /**
80
+ * Include Crypt_Hash
81
+ */
82
+ require_once('Crypt/Hash.php');
83
+
84
+ /**#@+
85
+ * @access public
86
+ * @see Crypt_RSA::encrypt()
87
+ * @see Crypt_RSA::decrypt()
88
+ */
89
+ /**
90
+ * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
91
+ * (OAEP) for encryption / decryption.
92
+ *
93
+ * Uses sha1 by default.
94
+ *
95
+ * @see Crypt_RSA::setHash()
96
+ * @see Crypt_RSA::setMGFHash()
97
+ */
98
+ define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
99
+ /**
100
+ * Use PKCS#1 padding.
101
+ *
102
+ * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
103
+ * compatability with protocols (like SSH-1) written before OAEP's introduction.
104
+ */
105
+ define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
106
+ /**#@-*/
107
+
108
+ /**#@+
109
+ * @access public
110
+ * @see Crypt_RSA::sign()
111
+ * @see Crypt_RSA::verify()
112
+ * @see Crypt_RSA::setHash()
113
+ */
114
+ /**
115
+ * Use the Probabilistic Signature Scheme for signing
116
+ *
117
+ * Uses sha1 by default.
118
+ *
119
+ * @see Crypt_RSA::setSaltLength()
120
+ * @see Crypt_RSA::setMGFHash()
121
+ */
122
+ define('CRYPT_RSA_SIGNATURE_PSS', 1);
123
+ /**
124
+ * Use the PKCS#1 scheme by default.
125
+ *
126
+ * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
127
+ * compatability with protocols (like SSH-2) written before PSS's introduction.
128
+ */
129
+ define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
130
+ /**#@-*/
131
+
132
+ /**#@+
133
+ * @access private
134
+ * @see Crypt_RSA::createKey()
135
+ */
136
+ /**
137
+ * ASN1 Integer
138
+ */
139
+ define('CRYPT_RSA_ASN1_INTEGER', 2);
140
+ /**
141
+ * ASN1 Sequence (with the constucted bit set)
142
+ */
143
+ define('CRYPT_RSA_ASN1_SEQUENCE', 48);
144
+ /**#@-*/
145
+
146
+ /**#@+
147
+ * @access private
148
+ * @see Crypt_RSA::Crypt_RSA()
149
+ */
150
+ /**
151
+ * To use the pure-PHP implementation
152
+ */
153
+ define('CRYPT_RSA_MODE_INTERNAL', 1);
154
+ /**
155
+ * To use the OpenSSL library
156
+ *
157
+ * (if enabled; otherwise, the internal implementation will be used)
158
+ */
159
+ define('CRYPT_RSA_MODE_OPENSSL', 2);
160
+ /**#@-*/
161
+
162
+ /**#@+
163
+ * @access public
164
+ * @see Crypt_RSA::createKey()
165
+ * @see Crypt_RSA::setPrivateKeyFormat()
166
+ */
167
+ /**
168
+ * PKCS#1 formatted private key
169
+ *
170
+ * Used by OpenSSH
171
+ */
172
+ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
173
+ /**#@-*/
174
+
175
+ /**#@+
176
+ * @access public
177
+ * @see Crypt_RSA::createKey()
178
+ * @see Crypt_RSA::setPublicKeyFormat()
179
+ */
180
+ /**
181
+ * Raw public key
182
+ *
183
+ * An array containing two Math_BigInteger objects.
184
+ *
185
+ * The exponent can be indexed with any of the following:
186
+ *
187
+ * 0, e, exponent, publicExponent
188
+ *
189
+ * The modulus can be indexed with any of the following:
190
+ *
191
+ * 1, n, modulo, modulus
192
+ */
193
+ define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 1);
194
+ /**
195
+ * PKCS#1 formatted public key
196
+ */
197
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 2);
198
+ /**
199
+ * OpenSSH formatted public key
200
+ *
201
+ * Place in $HOME/.ssh/authorized_keys
202
+ */
203
+ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 3);
204
+ /**#@-*/
205
+
206
+ /**
207
+ * Pure-PHP PKCS#1 compliant implementation of RSA.
208
+ *
209
+ * @author Jim Wigginton <terrafrost@php.net>
210
+ * @version 0.1.0
211
+ * @access public
212
+ * @package Crypt_RSA
213
+ */
214
+ class Crypt_RSA {
215
+ /**
216
+ * Precomputed Zero
217
+ *
218
+ * @var Array
219
+ * @access private
220
+ */
221
+ var $zero;
222
+
223
+ /**
224
+ * Precomputed One
225
+ *
226
+ * @var Array
227
+ * @access private
228
+ */
229
+ var $one;
230
+
231
+ /**
232
+ * Private Key Format
233
+ *
234
+ * @var Integer
235
+ * @access private
236
+ */
237
+ var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
238
+
239
+ /**
240
+ * Public Key Format
241
+ *
242
+ * @var Integer
243
+ * @access public
244
+ */
245
+ var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
246
+
247
+ /**
248
+ * Modulus (ie. n)
249
+ *
250
+ * @var Math_BigInteger
251
+ * @access private
252
+ */
253
+ var $modulus;
254
+
255
+ /**
256
+ * Modulus length
257
+ *
258
+ * @var Math_BigInteger
259
+ * @access private
260
+ */
261
+ var $k;
262
+
263
+ /**
264
+ * Exponent (ie. e or d)
265
+ *
266
+ * @var Math_BigInteger
267
+ * @access private
268
+ */
269
+ var $exponent;
270
+
271
+ /**
272
+ * Primes for Chinese Remainder Theorem (ie. p and q)
273
+ *
274
+ * @var Array
275
+ * @access private
276
+ */
277
+ var $primes;
278
+
279
+ /**
280
+ * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
281
+ *
282
+ * @var Array
283
+ * @access private
284
+ */
285
+ var $exponents;
286
+
287
+ /**
288
+ * Coefficients for Chinese Remainder Theorem (ie. qInv)
289
+ *
290
+ * @var Array
291
+ * @access private
292
+ */
293
+ var $coefficients;
294
+
295
+ /**
296
+ * Hash name
297
+ *
298
+ * @var String
299
+ * @access private
300
+ */
301
+ var $hashName;
302
+
303
+ /**
304
+ * Hash function
305
+ *
306
+ * @var Crypt_Hash
307
+ * @access private
308
+ */
309
+ var $hash;
310
+
311
+ /**
312
+ * Length of hash function output
313
+ *
314
+ * @var Integer
315
+ * @access private
316
+ */
317
+ var $hLen;
318
+
319
+ /**
320
+ * Length of salt
321
+ *
322
+ * @var Integer
323
+ * @access private
324
+ */
325
+ var $sLen;
326
+
327
+ /**
328
+ * Hash function for the Mask Generation Function
329
+ *
330
+ * @var Crypt_Hash
331
+ * @access private
332
+ */
333
+ var $mgfHash;
334
+
335
+ /**
336
+ * Length of MGF hash function output
337
+ *
338
+ * @var Integer
339
+ * @access private
340
+ */
341
+ var $mgfHLen;
342
+
343
+ /**
344
+ * Encryption mode
345
+ *
346
+ * @var Integer
347
+ * @access private
348
+ */
349
+ var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
350
+
351
+ /**
352
+ * Signature mode
353
+ *
354
+ * @var Integer
355
+ * @access private
356
+ */
357
+ var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
358
+
359
+ /**
360
+ * Public Exponent
361
+ *
362
+ * @var Mixed
363
+ * @access private
364
+ */
365
+ var $publicExponent = false;
366
+
367
+ /**
368
+ * Password
369
+ *
370
+ * @var String
371
+ * @access private
372
+ */
373
+ var $password = '';
374
+
375
+ /**
376
+ * The constructor
377
+ *
378
+ * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
379
+ * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
380
+ * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
381
+ *
382
+ * @return Crypt_RSA
383
+ * @access public
384
+ */
385
+ function Crypt_RSA()
386
+ {
387
+ if ( !defined('CRYPT_RSA_MODE') ) {
388
+ switch (true) {
389
+ //case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
390
+ // define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
391
+ // break;
392
+ default:
393
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
394
+ }
395
+ }
396
+
397
+ $this->zero = new Math_BigInteger();
398
+ $this->one = new Math_BigInteger(1);
399
+
400
+ $this->hash = new Crypt_Hash('sha1');
401
+ $this->hLen = $this->hash->getLength();
402
+ $this->hashName = 'sha1';
403
+ $this->mgfHash = new Crypt_Hash('sha1');
404
+ $this->mgfHLen = $this->mgfHash->getLength();
405
+ }
406
+
407
+ /**
408
+ * Create public / private key pair
409
+ *
410
+ * Returns an array with the following three elements:
411
+ * - 'privatekey': The private key.
412
+ * - 'publickey': The public key.
413
+ * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
414
+ * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
415
+ *
416
+ * @access public
417
+ * @param optional Integer $bits
418
+ * @param optional Integer $timeout
419
+ * @param optional Math_BigInteger $p
420
+ */
421
+ function createKey($bits = 1024, $timeout = false, $partial = array())
422
+ {
423
+ if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
424
+ $rsa = openssl_pkey_new(array('private_key_bits' => $bits));
425
+ openssl_pkey_export($rsa, $privatekey);
426
+ $publickey = openssl_pkey_get_details($rsa);
427
+ $publickey = $publickey['key'];
428
+
429
+ if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) {
430
+ $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
431
+ $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
432
+ }
433
+
434
+ return array(
435
+ 'privatekey' => $privatekey,
436
+ 'publickey' => $publickey,
437
+ 'partialkey' => false
438
+ );
439
+ }
440
+
441
+ static $e;
442
+ if (!isset($e)) {
443
+ if (!defined('CRYPT_RSA_EXPONENT')) {
444
+ // http://en.wikipedia.org/wiki/65537_%28number%29
445
+ define('CRYPT_RSA_EXPONENT', '65537');
446
+ }
447
+ if (!defined('CRYPT_RSA_COMMENT')) {
448
+ define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key');
449
+ }
450
+ // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
451
+ // than 256 bits.
452
+ if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
453
+ define('CRYPT_RSA_SMALLEST_PRIME', 4096);
454
+ }
455
+
456
+ $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
457
+ }
458
+
459
+ extract($this->_generateMinMax($bits));
460
+ $absoluteMin = $min;
461
+ $temp = $bits >> 1;
462
+ if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
463
+ $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
464
+ $temp = CRYPT_RSA_SMALLEST_PRIME;
465
+ } else {
466
+ $num_primes = 2;
467
+ }
468
+ extract($this->_generateMinMax($temp + $bits % $temp));
469
+ $finalMax = $max;
470
+ extract($this->_generateMinMax($temp));
471
+
472
+ $generator = new Math_BigInteger();
473
+ $generator->setRandomGenerator('crypt_random');
474
+
475
+ $n = $this->one->copy();
476
+ if (!empty($partial)) {
477
+ extract(unserialize($partial));
478
+ } else {
479
+ $exponents = $coefficients = $primes = array();
480
+ $lcm = array(
481
+ 'top' => $this->one->copy(),
482
+ 'bottom' => false
483
+ );
484
+ }
485
+
486
+ $start = time();
487
+ $i0 = count($primes) + 1;
488
+
489
+ do {
490
+ for ($i = $i0; $i <= $num_primes; $i++) {
491
+ if ($timeout !== false) {
492
+ $timeout-= time() - $start;
493
+ $start = time();
494
+ if ($timeout <= 0) {
495
+ return serialize(array(
496
+ 'privatekey' => '',
497
+ 'publickey' => '',
498
+ 'partialkey' => array(
499
+ 'primes' => $primes,
500
+ 'coefficients' => $coefficients,
501
+ 'lcm' => $lcm,
502
+ 'exponents' => $exponents
503
+ )
504
+ ));
505
+ }
506
+ }
507
+
508
+ if ($i == $num_primes) {
509
+ list($min, $temp) = $absoluteMin->divide($n);
510
+ if (!$temp->equals($this->zero)) {
511
+ $min = $min->add($this->one); // ie. ceil()
512
+ }
513
+ $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
514
+ } else {
515
+ $primes[$i] = $generator->randomPrime($min, $max, $timeout);
516
+ }
517
+
518
+ if ($primes[$i] === false) { // if we've reached the timeout
519
+ return array(
520
+ 'privatekey' => '',
521
+ 'publickey' => '',
522
+ 'partialkey' => empty($primes) ? '' : serialize(array(
523
+ 'primes' => array_slice($primes, 0, $i - 1),
524
+ 'coefficients' => $coefficients,
525
+ 'lcm' => $lcm,
526
+ 'exponents' => $exponents
527
+ ))
528
+ );
529
+ }
530
+
531
+ // the first coefficient is calculated differently from the rest
532
+ // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
533
+ if ($i > 2) {
534
+ $coefficients[$i] = $n->modInverse($primes[$i]);
535
+ }
536
+
537
+ $n = $n->multiply($primes[$i]);
538
+
539
+ $temp = $primes[$i]->subtract($this->one);
540
+
541
+ // textbook RSA implementations use Euler's totient function instead of the least common multiple.
542
+ // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
543
+ $lcm['top'] = $lcm['top']->multiply($temp);
544
+ $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
545
+
546
+ $exponents[$i] = $e->modInverse($temp);
547
+ }
548
+
549
+ list($lcm) = $lcm['top']->divide($lcm['bottom']);
550
+ $gcd = $lcm->gcd($e);
551
+ $i0 = 1;
552
+ } while (!$gcd->equals($this->one));
553
+
554
+ $d = $e->modInverse($lcm);
555
+
556
+ $coefficients[2] = $primes[2]->modInverse($primes[1]);
557
+
558
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
559
+ // RSAPrivateKey ::= SEQUENCE {
560
+ // version Version,
561
+ // modulus INTEGER, -- n
562
+ // publicExponent INTEGER, -- e
563
+ // privateExponent INTEGER, -- d
564
+ // prime1 INTEGER, -- p
565
+ // prime2 INTEGER, -- q
566
+ // exponent1 INTEGER, -- d mod (p-1)
567
+ // exponent2 INTEGER, -- d mod (q-1)
568
+ // coefficient INTEGER, -- (inverse of q) mod p
569
+ // otherPrimeInfos OtherPrimeInfos OPTIONAL
570
+ // }
571
+
572
+ return array(
573
+ 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
574
+ 'publickey' => $this->_convertPublicKey($n, $e),
575
+ 'partialkey' => false
576
+ );
577
+ }
578
+
579
+ /**
580
+ * Convert a private key to the appropriate format.
581
+ *
582
+ * @access private
583
+ * @see setPrivateKeyFormat()
584
+ * @param String $RSAPrivateKey
585
+ * @return String
586
+ */
587
+ function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
588
+ {
589
+ $num_primes = count($primes);
590
+ $raw = array(
591
+ 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
592
+ 'modulus' => $n->toBytes(true),
593
+ 'publicExponent' => $e->toBytes(true),
594
+ 'privateExponent' => $d->toBytes(true),
595
+ 'prime1' => $primes[1]->toBytes(true),
596
+ 'prime2' => $primes[2]->toBytes(true),
597
+ 'exponent1' => $exponents[1]->toBytes(true),
598
+ 'exponent2' => $exponents[2]->toBytes(true),
599
+ 'coefficient' => $coefficients[2]->toBytes(true)
600
+ );
601
+
602
+ // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
603
+ // call _convertPublicKey() instead.
604
+ switch ($this->privateKeyFormat) {
605
+ default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
606
+ $components = array();
607
+ foreach ($raw as $name => $value) {
608
+ $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
609
+ }
610
+
611
+ $RSAPrivateKey = implode('', $components);
612
+
613
+ if ($num_primes > 2) {
614
+ $OtherPrimeInfos = '';
615
+ for ($i = 3; $i <= $num_primes; $i++) {
616
+ // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
617
+ //
618
+ // OtherPrimeInfo ::= SEQUENCE {
619
+ // prime INTEGER, -- ri
620
+ // exponent INTEGER, -- di
621
+ // coefficient INTEGER -- ti
622
+ // }
623
+ $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
624
+ $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
625
+ $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
626
+ $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
627
+ }
628
+ $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
629
+ }
630
+
631
+ $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
632
+
633
+ if (!empty($this->password)) {
634
+ $iv = $this->_random(8);
635
+ $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
636
+ $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
637
+ if (!class_exists('Crypt_TripleDES')) {
638
+ require_once('Crypt/TripleDES.php');
639
+ }
640
+ $des = new Crypt_TripleDES();
641
+ $des->setKey($symkey);
642
+ $des->setIV($iv);
643
+ $iv = strtoupper(bin2hex($iv));
644
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
645
+ "Proc-Type: 4,ENCRYPTED\r\n" .
646
+ "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
647
+ "\r\n" .
648
+ chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) .
649
+ '-----END RSA PRIVATE KEY-----';
650
+ } else {
651
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
652
+ chunk_split(base64_encode($RSAPrivateKey)) .
653
+ '-----END RSA PRIVATE KEY-----';
654
+ }
655
+
656
+ return $RSAPrivateKey;
657
+ }
658
+ }
659
+
660
+ /**
661
+ * Convert a public key to the appropriate format
662
+ *
663
+ * @access private
664
+ * @see setPublicKeyFormat()
665
+ * @param String $RSAPrivateKey
666
+ * @return String
667
+ */
668
+ function _convertPublicKey($n, $e)
669
+ {
670
+ $modulus = $n->toBytes(true);
671
+ $publicExponent = $e->toBytes(true);
672
+
673
+ switch ($this->publicKeyFormat) {
674
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
675
+ return array('e' => $e->copy(), 'n' => $n->copy());
676
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
677
+ // from <http://tools.ietf.org/html/rfc4253#page-15>:
678
+ // string "ssh-rsa"
679
+ // mpint e
680
+ // mpint n
681
+ $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
682
+ $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
683
+
684
+ return $RSAPublicKey;
685
+ default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1
686
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
687
+ // RSAPublicKey ::= SEQUENCE {
688
+ // modulus INTEGER, -- n
689
+ // publicExponent INTEGER -- e
690
+ // }
691
+ $components = array(
692
+ 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
693
+ 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
694
+ );
695
+
696
+ $RSAPublicKey = pack('Ca*a*a*',
697
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
698
+ $components['modulus'], $components['publicExponent']
699
+ );
700
+
701
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
702
+ chunk_split(base64_encode($RSAPublicKey)) .
703
+ '-----END PUBLIC KEY-----';
704
+
705
+ return $RSAPublicKey;
706
+ }
707
+ }
708
+
709
+ /**
710
+ * Break a public or private key down into its constituant components
711
+ *
712
+ * @access private
713
+ * @see _convertPublicKey()
714
+ * @see _convertPrivateKey()
715
+ * @param String $key
716
+ * @param Integer $type
717
+ * @return Array
718
+ */
719
+ function _parseKey($key, $type)
720
+ {
721
+ switch ($type) {
722
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
723
+ if (!is_array($key)) {
724
+ return false;
725
+ }
726
+ $components = array();
727
+ switch (true) {
728
+ case isset($key['e']):
729
+ $components['publicExponent'] = $key['e']->copy();
730
+ break;
731
+ case isset($key['exponent']):
732
+ $components['publicExponent'] = $key['exponent']->copy();
733
+ break;
734
+ case isset($key['publicExponent']):
735
+ $components['publicExponent'] = $key['publicExponent']->copy();
736
+ break;
737
+ case isset($key[0]):
738
+ $components['publicExponent'] = $key[0]->copy();
739
+ }
740
+ switch (true) {
741
+ case isset($key['n']):
742
+ $components['modulus'] = $key['n']->copy();
743
+ break;
744
+ case isset($key['modulo']):
745
+ $components['modulus'] = $key['modulo']->copy();
746
+ break;
747
+ case isset($key['modulus']):
748
+ $components['modulus'] = $key['modulus']->copy();
749
+ break;
750
+ case isset($key[1]):
751
+ $components['modulus'] = $key[1]->copy();
752
+ }
753
+ return $components;
754
+ case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
755
+ case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
756
+ /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
757
+ "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
758
+ protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
759
+ two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
760
+
761
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.1
762
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.3
763
+
764
+ DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
765
+ DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
766
+ function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
767
+ own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
768
+ implementation are part of the standard, as well.
769
+
770
+ * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
771
+ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
772
+ $iv = pack('H*', trim($matches[2]));
773
+ $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
774
+ $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
775
+ $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
776
+ $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
777
+ if ($ciphertext === false) {
778
+ $ciphertext = $key;
779
+ }
780
+ switch ($matches[1]) {
781
+ case 'DES-EDE3-CBC':
782
+ if (!class_exists('Crypt_TripleDES')) {
783
+ require_once('Crypt/TripleDES.php');
784
+ }
785
+ $crypto = new Crypt_TripleDES();
786
+ break;
787
+ case 'DES-CBC':
788
+ if (!class_exists('Crypt_DES')) {
789
+ require_once('Crypt/DES.php');
790
+ }
791
+ $crypto = new Crypt_DES();
792
+ break;
793
+ default:
794
+ return false;
795
+ }
796
+ $crypto->setKey($symkey);
797
+ $crypto->setIV($iv);
798
+ $decoded = $crypto->decrypt($ciphertext);
799
+ } else {
800
+ $decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
801
+ $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
802
+ }
803
+
804
+ if ($decoded !== false) {
805
+ $key = $decoded;
806
+ }
807
+
808
+ $components = array();
809
+
810
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
811
+ return false;
812
+ }
813
+ if ($this->_decodeLength($key) != strlen($key)) {
814
+ return false;
815
+ }
816
+
817
+ $tag = ord($this->_string_shift($key));
818
+ if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
819
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
820
+
821
+ 0:d=0 hl=4 l= 290 cons: SEQUENCE
822
+ 4:d=1 hl=2 l= 13 cons: SEQUENCE
823
+ 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
824
+ 17:d=2 hl=2 l= 0 prim: NULL
825
+ 19:d=1 hl=4 l= 271 prim: BIT STRING */
826
+ $this->_string_shift($key, $this->_decodeLength($key));
827
+ $this->_string_shift($key); // skip over the BIT STRING tag
828
+ $this->_decodeLength($key); // skip over the BIT STRING length
829
+ // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
830
+ // unused bits in teh final subsequent octet. The number shall be in the range zero to seven."
831
+ // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
832
+ $this->_string_shift($key);
833
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
834
+ return false;
835
+ }
836
+ if ($this->_decodeLength($key) != strlen($key)) {
837
+ return false;
838
+ }
839
+ $tag = ord($this->_string_shift($key));
840
+ }
841
+ if ($tag != CRYPT_RSA_ASN1_INTEGER) {
842
+ return false;
843
+ }
844
+
845
+ $length = $this->_decodeLength($key);
846
+ $temp = $this->_string_shift($key, $length);
847
+ if (strlen($temp) != 1 || ord($temp) > 2) {
848
+ $components['modulus'] = new Math_BigInteger($temp, -256);
849
+ $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
850
+ $length = $this->_decodeLength($key);
851
+ $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
852
+
853
+ return $components;
854
+ }
855
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
856
+ return false;
857
+ }
858
+ $length = $this->_decodeLength($key);
859
+ $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
860
+ $this->_string_shift($key);
861
+ $length = $this->_decodeLength($key);
862
+ $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
863
+ $this->_string_shift($key);
864
+ $length = $this->_decodeLength($key);
865
+ $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
866
+ $this->_string_shift($key);
867
+ $length = $this->_decodeLength($key);
868
+ $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
869
+ $this->_string_shift($key);
870
+ $length = $this->_decodeLength($key);
871
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
872
+ $this->_string_shift($key);
873
+ $length = $this->_decodeLength($key);
874
+ $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
875
+ $this->_string_shift($key);
876
+ $length = $this->_decodeLength($key);
877
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
878
+ $this->_string_shift($key);
879
+ $length = $this->_decodeLength($key);
880
+ $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
881
+
882
+ if (!empty($key)) {
883
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
884
+ return false;
885
+ }
886
+ $this->_decodeLength($key);
887
+ while (!empty($key)) {
888
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
889
+ return false;
890
+ }
891
+ $this->_decodeLength($key);
892
+ $key = substr($key, 1);
893
+ $length = $this->_decodeLength($key);
894
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
895
+ $this->_string_shift($key);
896
+ $length = $this->_decodeLength($key);
897
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
898
+ $this->_string_shift($key);
899
+ $length = $this->_decodeLength($key);
900
+ $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
901
+ }
902
+ }
903
+
904
+ return $components;
905
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
906
+ $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key));
907
+ if ($key === false) {
908
+ return false;
909
+ }
910
+
911
+ $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
912
+
913
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
914
+ $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
915
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
916
+ $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
917
+
918
+ if ($cleanup && strlen($key)) {
919
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
920
+ return array(
921
+ 'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
922
+ 'publicExponent' => $modulus
923
+ );
924
+ } else {
925
+ return array(
926
+ 'modulus' => $modulus,
927
+ 'publicExponent' => $publicExponent
928
+ );
929
+ }
930
+ }
931
+ }
932
+
933
+ /**
934
+ * Loads a public or private key
935
+ *
936
+ * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
937
+ *
938
+ * @access public
939
+ * @param String $key
940
+ * @param Integer $type optional
941
+ */
942
+ function loadKey($key, $type = CRYPT_RSA_PRIVATE_FORMAT_PKCS1)
943
+ {
944
+ $components = $this->_parseKey($key, $type);
945
+ if ($components === false) {
946
+ return false;
947
+ }
948
+
949
+ $this->modulus = $components['modulus'];
950
+ $this->k = strlen($this->modulus->toBytes());
951
+ $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
952
+ if (isset($components['primes'])) {
953
+ $this->primes = $components['primes'];
954
+ $this->exponents = $components['exponents'];
955
+ $this->coefficients = $components['coefficients'];
956
+ $this->publicExponent = $components['publicExponent'];
957
+ } else {
958
+ $this->primes = array();
959
+ $this->exponents = array();
960
+ $this->coefficients = array();
961
+ $this->publicExponent = false;
962
+ }
963
+
964
+ return true;
965
+ }
966
+
967
+ /**
968
+ * Sets the password
969
+ *
970
+ * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
971
+ * Or rather, pass in $password such that empty($password) is true.
972
+ *
973
+ * @see createKey()
974
+ * @see loadKey()
975
+ * @access public
976
+ * @param String $password
977
+ */
978
+ function setPassword($password)
979
+ {
980
+ $this->password = $password;
981
+ }
982
+
983
+ /**
984
+ * Defines the public key
985
+ *
986
+ * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
987
+ * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
988
+ * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
989
+ * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
990
+ * exponent this won't work unless you manually add the public exponent.
991
+ *
992
+ * Do note that when a new key is loaded the index will be cleared.
993
+ *
994
+ * Returns true on success, false on failure
995
+ *
996
+ * @see getPublicKey()
997
+ * @access public
998
+ * @param String $key
999
+ * @param Integer $type optional
1000
+ * @return Boolean
1001
+ */
1002
+ function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1003
+ {
1004
+ $components = $this->_parseKey($key, $type);
1005
+ if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1006
+ return false;
1007
+ }
1008
+ $this->publicExponent = $components['publicExponent'];
1009
+ }
1010
+
1011
+ /**
1012
+ * Returns the public key
1013
+ *
1014
+ * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1015
+ * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1016
+ * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1017
+ *
1018
+ * @see getPublicKey()
1019
+ * @access public
1020
+ * @param String $key
1021
+ * @param Integer $type optional
1022
+ */
1023
+ function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1024
+ {
1025
+ if (empty($this->modulus) || empty($this->publicExponent)) {
1026
+ return false;
1027
+ }
1028
+
1029
+ $oldFormat = $this->publicKeyFormat;
1030
+ $this->publicKeyFormat = $type;
1031
+ $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1032
+ $this->publicKeyFormat = $oldFormat;
1033
+ return $temp;
1034
+ }
1035
+
1036
+ /**
1037
+ * Generates the smallest and largest numbers requiring $bits bits
1038
+ *
1039
+ * @access private
1040
+ * @param Integer $bits
1041
+ * @return Array
1042
+ */
1043
+ function _generateMinMax($bits)
1044
+ {
1045
+ $bytes = $bits >> 3;
1046
+ $min = str_repeat(chr(0), $bytes);
1047
+ $max = str_repeat(chr(0xFF), $bytes);
1048
+ $msb = $bits & 7;
1049
+ if ($msb) {
1050
+ $min = chr(1 << ($msb - 1)) . $min;
1051
+ $max = chr((1 << $msb) - 1) . $max;
1052
+ } else {
1053
+ $min[0] = chr(0x80);
1054
+ }
1055
+
1056
+ return array(
1057
+ 'min' => new Math_BigInteger($min, 256),
1058
+ 'max' => new Math_BigInteger($max, 256)
1059
+ );
1060
+ }
1061
+
1062
+ /**
1063
+ * DER-decode the length
1064
+ *
1065
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1066
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
1067
+ *
1068
+ * @access private
1069
+ * @param String $string
1070
+ * @return Integer
1071
+ */
1072
+ function _decodeLength(&$string)
1073
+ {
1074
+ $length = ord($this->_string_shift($string));
1075
+ if ( $length & 0x80 ) { // definite length, long form
1076
+ $length&= 0x7F;
1077
+ $temp = $this->_string_shift($string, $length);
1078
+ list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1079
+ }
1080
+ return $length;
1081
+ }
1082
+
1083
+ /**
1084
+ * DER-encode the length
1085
+ *
1086
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1087
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
1088
+ *
1089
+ * @access private
1090
+ * @param Integer $length
1091
+ * @return String
1092
+ */
1093
+ function _encodeLength($length)
1094
+ {
1095
+ if ($length <= 0x7F) {
1096
+ return chr($length);
1097
+ }
1098
+
1099
+ $temp = ltrim(pack('N', $length), chr(0));
1100
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
1101
+ }
1102
+
1103
+ /**
1104
+ * String Shift
1105
+ *
1106
+ * Inspired by array_shift
1107
+ *
1108
+ * @param String $string
1109
+ * @param optional Integer $index
1110
+ * @return String
1111
+ * @access private
1112
+ */
1113
+ function _string_shift(&$string, $index = 1)
1114
+ {
1115
+ $substr = substr($string, 0, $index);
1116
+ $string = substr($string, $index);
1117
+ return $substr;
1118
+ }
1119
+
1120
+ /**
1121
+ * Determines the private key format
1122
+ *
1123
+ * @see createKey()
1124
+ * @access public
1125
+ * @param Integer $format
1126
+ */
1127
+ function setPrivateKeyFormat($format)
1128
+ {
1129
+ $this->privateKeyFormat = $format;
1130
+ }
1131
+
1132
+ /**
1133
+ * Determines the public key format
1134
+ *
1135
+ * @see createKey()
1136
+ * @access public
1137
+ * @param Integer $format
1138
+ */
1139
+ function setPublicKeyFormat($format)
1140
+ {
1141
+ $this->publicKeyFormat = $format;
1142
+ }
1143
+
1144
+ /**
1145
+ * Determines which hashing function should be used
1146
+ *
1147
+ * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
1148
+ * decryption. If $hash isn't supported, sha1 is used.
1149
+ *
1150
+ * @access public
1151
+ * @param String $hash
1152
+ */
1153
+ function setHash($hash)
1154
+ {
1155
+ // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1156
+ switch ($hash) {
1157
+ case 'md2':
1158
+ case 'md5':
1159
+ case 'sha1':
1160
+ case 'sha256':
1161
+ case 'sha384':
1162
+ case 'sha512':
1163
+ $this->hash = new Crypt_Hash($hash);
1164
+ $this->hashName = $hash;
1165
+ break;
1166
+ default:
1167
+ $this->hash = new Crypt_Hash('sha1');
1168
+ $this->hashName = 'sha1';
1169
+ }
1170
+ $this->hLen = $this->hash->getLength();
1171
+ }
1172
+
1173
+ /**
1174
+ * Determines which hashing function should be used for the mask generation function
1175
+ *
1176
+ * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
1177
+ * best if Hash and MGFHash are set to the same thing this is not a requirement.
1178
+ *
1179
+ * @access public
1180
+ * @param String $hash
1181
+ */
1182
+ function setMGFHash($hash)
1183
+ {
1184
+ // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1185
+ switch ($hash) {
1186
+ case 'md2':
1187
+ case 'md5':
1188
+ case 'sha1':
1189
+ case 'sha256':
1190
+ case 'sha384':
1191
+ case 'sha512':
1192
+ $this->mgfHash = new Crypt_Hash($hash);
1193
+ break;
1194
+ default:
1195
+ $this->mgfHash = new Crypt_Hash('sha1');
1196
+ }
1197
+ $this->mgfHLen = $this->mgfHash->getLength();
1198
+ }
1199
+
1200
+ /**
1201
+ * Determines the salt length
1202
+ *
1203
+ * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1204
+ *
1205
+ * Typical salt lengths in octets are hLen (the length of the output
1206
+ * of the hash function Hash) and 0.
1207
+ *
1208
+ * @access public
1209
+ * @param Integer $format
1210
+ */
1211
+ function setSaltLength($sLen)
1212
+ {
1213
+ $this->sLen = $sLen;
1214
+ }
1215
+
1216
+ /**
1217
+ * Generates a random string x bytes long
1218
+ *
1219
+ * @access public
1220
+ * @param Integer $bytes
1221
+ * @param optional Integer $nonzero
1222
+ * @return String
1223
+ */
1224
+ function _random($bytes, $nonzero = false)
1225
+ {
1226
+ $temp = '';
1227
+ if ($nonzero) {
1228
+ for ($i = 0; $i < $bytes; $i++) {
1229
+ $temp.= chr(crypt_random(1, 255));
1230
+ }
1231
+ } else {
1232
+ $ints = ($bytes + 1) >> 2;
1233
+ for ($i = 0; $i < $ints; $i++) {
1234
+ $temp.= pack('N', crypt_random());
1235
+ }
1236
+ $temp = substr($temp, 0, $bytes);
1237
+ }
1238
+ return $temp;
1239
+ }
1240
+
1241
+ /**
1242
+ * Integer-to-Octet-String primitive
1243
+ *
1244
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1245
+ *
1246
+ * @access private
1247
+ * @param Math_BigInteger $x
1248
+ * @param Integer $xLen
1249
+ * @return String
1250
+ */
1251
+ function _i2osp($x, $xLen)
1252
+ {
1253
+ $x = $x->toBytes();
1254
+ if (strlen($x) > $xLen) {
1255
+ user_error('Integer too large', E_USER_NOTICE);
1256
+ return false;
1257
+ }
1258
+ return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1259
+ }
1260
+
1261
+ /**
1262
+ * Octet-String-to-Integer primitive
1263
+ *
1264
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1265
+ *
1266
+ * @access private
1267
+ * @param String $x
1268
+ * @return Math_BigInteger
1269
+ */
1270
+ function _os2ip($x)
1271
+ {
1272
+ return new Math_BigInteger($x, 256);
1273
+ }
1274
+
1275
+ /**
1276
+ * Exponentiate with or without Chinese Remainder Theorem
1277
+ *
1278
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1279
+ *
1280
+ * @access private
1281
+ * @param Math_BigInteger $x
1282
+ * @return Math_BigInteger
1283
+ */
1284
+ function _exponentiate($x)
1285
+ {
1286
+ if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1287
+ return $x->modPow($this->exponent, $this->modulus);
1288
+ }
1289
+
1290
+ $num_primes = count($this->primes);
1291
+
1292
+ if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1293
+ $m_i = array(
1294
+ 1 => $x->modPow($this->exponents[1], $this->primes[1]),
1295
+ 2 => $x->modPow($this->exponents[2], $this->primes[2])
1296
+ );
1297
+ $h = $m_i[1]->subtract($m_i[2]);
1298
+ $h = $h->multiply($this->coefficients[2]);
1299
+ list(, $h) = $h->divide($this->primes[1]);
1300
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
1301
+
1302
+ $r = $this->primes[1];
1303
+ for ($i = 3; $i <= $num_primes; $i++) {
1304
+ $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1305
+
1306
+ $r = $r->multiply($this->primes[$i - 1]);
1307
+
1308
+ $h = $m_i->subtract($m);
1309
+ $h = $h->multiply($this->coefficients[$i]);
1310
+ list(, $h) = $h->divide($this->primes[$i]);
1311
+
1312
+ $m = $m->add($r->multiply($h));
1313
+ }
1314
+ } else {
1315
+ $smallest = $this->primes[1];
1316
+ for ($i = 2; $i <= $num_primes; $i++) {
1317
+ if ($smallest->compare($this->primes[$i]) > 0) {
1318
+ $smallest = $this->primes[$i];
1319
+ }
1320
+ }
1321
+
1322
+ $one = new Math_BigInteger(1);
1323
+ $one->setRandomGenerator('crypt_random');
1324
+
1325
+ $r = $one->random($one, $smallest->subtract($one));
1326
+
1327
+ $m_i = array(
1328
+ 1 => $this->_blind($x, $r, 1),
1329
+ 2 => $this->_blind($x, $r, 2)
1330
+ );
1331
+ $h = $m_i[1]->subtract($m_i[2]);
1332
+ $h = $h->multiply($this->coefficients[2]);
1333
+ list(, $h) = $h->divide($this->primes[1]);
1334
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
1335
+
1336
+ $r = $this->primes[1];
1337
+ for ($i = 3; $i <= $num_primes; $i++) {
1338
+ $m_i = $this->_blind($x, $r, $i);
1339
+
1340
+ $r = $r->multiply($this->primes[$i - 1]);
1341
+
1342
+ $h = $m_i->subtract($m);
1343
+ $h = $h->multiply($this->coefficients[$i]);
1344
+ list(, $h) = $h->divide($this->primes[$i]);
1345
+
1346
+ $m = $m->add($r->multiply($h));
1347
+ }
1348
+ }
1349
+
1350
+ return $m;
1351
+ }
1352
+
1353
+ /**
1354
+ * Performs RSA Blinding
1355
+ *
1356
+ * Protects against timing attacks by employing RSA Blinding.
1357
+ * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1358
+ *
1359
+ * @access private
1360
+ * @param Math_BigInteger $x
1361
+ * @param Math_BigInteger $r
1362
+ * @param Integer $i
1363
+ * @return Math_BigInteger
1364
+ */
1365
+ function _blind($x, $r, $i)
1366
+ {
1367
+ $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1368
+
1369
+ $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1370
+
1371
+ $r = $r->modInverse($this->primes[$i]);
1372
+ $x = $x->multiply($r);
1373
+ list(, $x) = $x->divide($this->primes[$i]);
1374
+
1375
+ return $x;
1376
+ }
1377
+
1378
+ /**
1379
+ * RSAEP
1380
+ *
1381
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1382
+ *
1383
+ * @access private
1384
+ * @param Math_BigInteger $m
1385
+ * @return Math_BigInteger
1386
+ */
1387
+ function _rsaep($m)
1388
+ {
1389
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1390
+ user_error('Message representative out of range', E_USER_NOTICE);
1391
+ return false;
1392
+ }
1393
+ return $this->_exponentiate($m);
1394
+ }
1395
+
1396
+ /**
1397
+ * RSADP
1398
+ *
1399
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1400
+ *
1401
+ * @access private
1402
+ * @param Math_BigInteger $c
1403
+ * @return Math_BigInteger
1404
+ */
1405
+ function _rsadp($c)
1406
+ {
1407
+ if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1408
+ user_error('Ciphertext representative out of range', E_USER_NOTICE);
1409
+ return false;
1410
+ }
1411
+ return $this->_exponentiate($c);
1412
+ }
1413
+
1414
+ /**
1415
+ * RSASP1
1416
+ *
1417
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1418
+ *
1419
+ * @access private
1420
+ * @param Math_BigInteger $m
1421
+ * @return Math_BigInteger
1422
+ */
1423
+ function _rsasp1($m)
1424
+ {
1425
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1426
+ user_error('Message representative out of range', E_USER_NOTICE);
1427
+ return false;
1428
+ }
1429
+ return $this->_exponentiate($m);
1430
+ }
1431
+
1432
+ /**
1433
+ * RSAVP1
1434
+ *
1435
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1436
+ *
1437
+ * @access private
1438
+ * @param Math_BigInteger $s
1439
+ * @return Math_BigInteger
1440
+ */
1441
+ function _rsavp1($s)
1442
+ {
1443
+ if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1444
+ user_error('Signature representative out of range', E_USER_NOTICE);
1445
+ return false;
1446
+ }
1447
+ return $this->_exponentiate($s);
1448
+ }
1449
+
1450
+ /**
1451
+ * MGF1
1452
+ *
1453
+ * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1454
+ *
1455
+ * @access private
1456
+ * @param String $mgfSeed
1457
+ * @param Integer $mgfLen
1458
+ * @return String
1459
+ */
1460
+ function _mgf1($mgfSeed, $maskLen)
1461
+ {
1462
+ // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
1463
+
1464
+ $t = '';
1465
+ $count = ceil($maskLen / $this->mgfHLen);
1466
+ for ($i = 0; $i < $count; $i++) {
1467
+ $c = pack('N', $i);
1468
+ $t.= $this->mgfHash->hash($mgfSeed . $c);
1469
+ }
1470
+
1471
+ return substr($t, 0, $maskLen);
1472
+ }
1473
+
1474
+ /**
1475
+ * RSAES-OAEP-ENCRYPT
1476
+ *
1477
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
1478
+ * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
1479
+ *
1480
+ * @access private
1481
+ * @param String $m
1482
+ * @param String $l
1483
+ * @return String
1484
+ */
1485
+ function _rsaes_oaep_encrypt($m, $l = '')
1486
+ {
1487
+ $mLen = strlen($m);
1488
+
1489
+ // Length checking
1490
+
1491
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1492
+ // be output.
1493
+
1494
+ if ($mLen > $this->k - 2 * $this->hLen - 2) {
1495
+ user_error('Message too long', E_USER_NOTICE);
1496
+ return false;
1497
+ }
1498
+
1499
+ // EME-OAEP encoding
1500
+
1501
+ $lHash = $this->hash->hash($l);
1502
+ $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
1503
+ $db = $lHash . $ps . chr(1) . $m;
1504
+ $seed = $this->_random($this->hLen);
1505
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1506
+ $maskedDB = $db ^ $dbMask;
1507
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
1508
+ $maskedSeed = $seed ^ $seedMask;
1509
+ $em = chr(0) . $maskedSeed . $maskedDB;
1510
+
1511
+ // RSA encryption
1512
+
1513
+ $m = $this->_os2ip($em);
1514
+ $c = $this->_rsaep($m);
1515
+ $c = $this->_i2osp($c, $this->k);
1516
+
1517
+ // Output the ciphertext C
1518
+
1519
+ return $c;
1520
+ }
1521
+
1522
+ /**
1523
+ * RSAES-OAEP-DECRYPT
1524
+ *
1525
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
1526
+ * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
1527
+ *
1528
+ * Note. Care must be taken to ensure that an opponent cannot
1529
+ * distinguish the different error conditions in Step 3.g, whether by
1530
+ * error message or timing, or, more generally, learn partial
1531
+ * information about the encoded message EM. Otherwise an opponent may
1532
+ * be able to obtain useful information about the decryption of the
1533
+ * ciphertext C, leading to a chosen-ciphertext attack such as the one
1534
+ * observed by Manger [36].
1535
+ *
1536
+ * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
1537
+ *
1538
+ * Both the encryption and the decryption operations of RSAES-OAEP take
1539
+ * the value of a label L as input. In this version of PKCS #1, L is
1540
+ * the empty string; other uses of the label are outside the scope of
1541
+ * this document.
1542
+ *
1543
+ * @access private
1544
+ * @param String $c
1545
+ * @param String $l
1546
+ * @return String
1547
+ */
1548
+ function _rsaes_oaep_decrypt($c, $l = '')
1549
+ {
1550
+ // Length checking
1551
+
1552
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1553
+ // be output.
1554
+
1555
+ if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
1556
+ user_error('Decryption error', E_USER_NOTICE);
1557
+ return false;
1558
+ }
1559
+
1560
+ // RSA decryption
1561
+
1562
+ $c = $this->_os2ip($c);
1563
+ $m = $this->_rsadp($c);
1564
+ if ($m === false) {
1565
+ user_error('Decryption error', E_USER_NOTICE);
1566
+ return false;
1567
+ }
1568
+ $em = $this->_i2osp($m, $this->k);
1569
+
1570
+ // EME-OAEP decoding
1571
+
1572
+ $lHash = $this->hash->hash($l);
1573
+ $y = ord($em[0]);
1574
+ $maskedSeed = substr($em, 1, $this->hLen);
1575
+ $maskedDB = substr($em, $this->hLen + 1);
1576
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
1577
+ $seed = $maskedSeed ^ $seedMask;
1578
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1579
+ $db = $maskedDB ^ $dbMask;
1580
+ $lHash2 = substr($db, 0, $this->hLen);
1581
+ $m = substr($db, $this->hLen);
1582
+ if ($lHash != $lHash2) {
1583
+ user_error('Decryption error', E_USER_NOTICE);
1584
+ return false;
1585
+ }
1586
+ $m = ltrim($m, chr(0));
1587
+ if (ord($m[0]) != 1) {
1588
+ user_error('Decryption error', E_USER_NOTICE);
1589
+ return false;
1590
+ }
1591
+
1592
+ // Output the message M
1593
+
1594
+ return substr($m, 1);
1595
+ }
1596
+
1597
+ /**
1598
+ * RSAES-PKCS1-V1_5-ENCRYPT
1599
+ *
1600
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
1601
+ *
1602
+ * @access private
1603
+ * @param String $m
1604
+ * @return String
1605
+ */
1606
+ function _rsaes_pkcs1_v1_5_encrypt($m)
1607
+ {
1608
+ $mLen = strlen($m);
1609
+
1610
+ // Length checking
1611
+
1612
+ if ($mLen > $this->k - 11) {
1613
+ user_error('Message too long', E_USER_NOTICE);
1614
+ return false;
1615
+ }
1616
+
1617
+ // EME-PKCS1-v1_5 encoding
1618
+
1619
+ $ps = $this->_random($this->k - $mLen - 3, true);
1620
+ $em = chr(0) . chr(2) . $ps . chr(0) . $m;
1621
+
1622
+ // RSA encryption
1623
+ $m = $this->_os2ip($em);
1624
+ $c = $this->_rsaep($m);
1625
+ $c = $this->_i2osp($c, $this->k);
1626
+
1627
+ // Output the ciphertext C
1628
+
1629
+ return $c;
1630
+ }
1631
+
1632
+ /**
1633
+ * RSAES-PKCS1-V1_5-DECRYPT
1634
+ *
1635
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
1636
+ *
1637
+ * For compatability purposes, this function departs slightly from the description given in RFC3447.
1638
+ * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
1639
+ * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
1640
+ * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
1641
+ * to be 2 regardless of which key is used. for compatability purposes, we'll just check to make sure the
1642
+ * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
1643
+ *
1644
+ * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
1645
+ * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
1646
+ * not private key encrypted ciphertext's.
1647
+ *
1648
+ * @access private
1649
+ * @param String $c
1650
+ * @return String
1651
+ */
1652
+ function _rsaes_pkcs1_v1_5_decrypt($c)
1653
+ {
1654
+ // Length checking
1655
+
1656
+ if (strlen($c) != $this->k) { // or if k < 11
1657
+ user_error('Decryption error', E_USER_NOTICE);
1658
+ return false;
1659
+ }
1660
+
1661
+ // RSA decryption
1662
+
1663
+ $c = $this->_os2ip($c);
1664
+ $m = $this->_rsadp($c);
1665
+ if ($m === false) {
1666
+ user_error('Decryption error', E_USER_NOTICE);
1667
+ return false;
1668
+ }
1669
+ $em = $this->_i2osp($m, $this->k);
1670
+
1671
+ // EME-PKCS1-v1_5 decoding
1672
+
1673
+ if (ord($em[0]) != 0 || ord($em[1]) > 2) {
1674
+ user_error('Decryption error', E_USER_NOTICE);
1675
+ return false;
1676
+ }
1677
+
1678
+ $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
1679
+ $m = substr($em, strlen($ps) + 3);
1680
+
1681
+ if (strlen($ps) < 8) {
1682
+ user_error('Decryption error', E_USER_NOTICE);
1683
+ return false;
1684
+ }
1685
+
1686
+ // Output M
1687
+
1688
+ return $m;
1689
+ }
1690
+
1691
+ /**
1692
+ * EMSA-PSS-ENCODE
1693
+ *
1694
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
1695
+ *
1696
+ * @access private
1697
+ * @param String $m
1698
+ * @param Integer $emBits
1699
+ */
1700
+ function _emsa_pss_encode($m, $emBits)
1701
+ {
1702
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1703
+ // be output.
1704
+
1705
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
1706
+ $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
1707
+
1708
+ $mHash = $this->hash->hash($m);
1709
+ if ($emLen < $this->hLen + $sLen + 2) {
1710
+ user_error('Encoding error', E_USER_NOTICE);
1711
+ return false;
1712
+ }
1713
+
1714
+ $salt = $this->_random($sLen);
1715
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
1716
+ $h = $this->hash->hash($m2);
1717
+ $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
1718
+ $db = $ps . chr(1) . $salt;
1719
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
1720
+ $maskedDB = $db ^ $dbMask;
1721
+ $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
1722
+ $em = $maskedDB . $h . chr(0xBC);
1723
+
1724
+ return $em;
1725
+ }
1726
+
1727
+ /**
1728
+ * EMSA-PSS-VERIFY
1729
+ *
1730
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
1731
+ *
1732
+ * @access private
1733
+ * @param String $m
1734
+ * @param String $em
1735
+ * @param Integer $emBits
1736
+ * @return String
1737
+ */
1738
+ function _emsa_pss_verify($m, $em, $emBits)
1739
+ {
1740
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
1741
+ // be output.
1742
+
1743
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
1744
+ $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
1745
+
1746
+ $mHash = $this->hash->hash($m);
1747
+ if ($emLen < $this->hLen + $sLen + 2) {
1748
+ return false;
1749
+ }
1750
+
1751
+ if ($em[strlen($em) - 1] != chr(0xBC)) {
1752
+ return false;
1753
+ }
1754
+
1755
+ $maskedDB = substr($em, 0, $em - $this->hLen - 1);
1756
+ $h = substr($em, $em - $this->hLen - 1, $this->hLen);
1757
+ $temp = chr(0xFF << ($emBits & 7));
1758
+ if ((~$maskedDB[0] & $temp) != $temp) {
1759
+ return false;
1760
+ }
1761
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
1762
+ $db = $maskedDB ^ $dbMask;
1763
+ $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
1764
+ $temp = $emLen - $this->hLen - $sLen - 2;
1765
+ if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
1766
+ return false;
1767
+ }
1768
+ $salt = substr($db, $temp + 1); // should be $sLen long
1769
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
1770
+ $h2 = $this->hash->hash($m2);
1771
+ return $h == $h2;
1772
+ }
1773
+
1774
+ /**
1775
+ * RSASSA-PSS-SIGN
1776
+ *
1777
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
1778
+ *
1779
+ * @access private
1780
+ * @param String $m
1781
+ * @return String
1782
+ */
1783
+ function _rsassa_pss_sign($m)
1784
+ {
1785
+ // EMSA-PSS encoding
1786
+
1787
+ $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
1788
+
1789
+ // RSA signature
1790
+
1791
+ $m = $this->_os2ip($em);
1792
+ $s = $this->_rsasp1($m);
1793
+ $s = $this->_i2osp($s, $this->k);
1794
+
1795
+ // Output the signature S
1796
+
1797
+ return $s;
1798
+ }
1799
+
1800
+ /**
1801
+ * RSASSA-PSS-VERIFY
1802
+ *
1803
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
1804
+ *
1805
+ * @access private
1806
+ * @param String $m
1807
+ * @param String $s
1808
+ * @return String
1809
+ */
1810
+ function _rsassa_pss_verify($m, $s)
1811
+ {
1812
+ // Length checking
1813
+
1814
+ if (strlen($s) != $this->k) {
1815
+ user_error('Invalid signature', E_USER_NOTICE);
1816
+ return false;
1817
+ }
1818
+
1819
+ // RSA verification
1820
+
1821
+ $modBits = 8 * $this->k;
1822
+
1823
+ $s2 = $this->_os2ip($s);
1824
+ $m2 = $this->_rsavp1($s2);
1825
+ if ($m2 === false) {
1826
+ user_error('Invalid signature', E_USER_NOTICE);
1827
+ return false;
1828
+ }
1829
+ $em = $this->_i2osp($m2, $modBits >> 3);
1830
+ if ($em === false) {
1831
+ user_error('Invalid signature', E_USER_NOTICE);
1832
+ return false;
1833
+ }
1834
+
1835
+ // EMSA-PSS verification
1836
+
1837
+ return $this->_emsa_pss_verify($m, $em, $modBits - 1);
1838
+ }
1839
+
1840
+ /**
1841
+ * EMSA-PKCS1-V1_5-ENCODE
1842
+ *
1843
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
1844
+ *
1845
+ * @access private
1846
+ * @param String $m
1847
+ * @param Integer $emLen
1848
+ * @return String
1849
+ */
1850
+ function _emsa_pkcs1_v1_5_encode($m, $emLen)
1851
+ {
1852
+ $h = $this->hash->hash($m);
1853
+ if ($h === false) {
1854
+ return false;
1855
+ }
1856
+
1857
+ // see http://tools.ietf.org/html/rfc3447#page-43
1858
+ switch ($this->hashName) {
1859
+ case 'md2':
1860
+ $t = pack('H*', '3020300c06082a864886f70d020205000410');
1861
+ break;
1862
+ case 'md5':
1863
+ $t = pack('H*', '3020300c06082a864886f70d020505000410');
1864
+ break;
1865
+ case 'sha1':
1866
+ $t = pack('H*', '3021300906052b0e03021a05000414');
1867
+ break;
1868
+ case 'sha256':
1869
+ $t = pack('H*', '3031300d060960864801650304020105000420');
1870
+ break;
1871
+ case 'sha384':
1872
+ $t = pack('H*', '3041300d060960864801650304020205000430');
1873
+ break;
1874
+ case 'sha512':
1875
+ $t = pack('H*', '3051300d060960864801650304020305000440');
1876
+ }
1877
+ $t.= $h;
1878
+ $tLen = strlen($t);
1879
+
1880
+ if ($emLen < $tLen + 11) {
1881
+ user_error('Intended encoded message length too short', E_USER_NOTICE);
1882
+ return false;
1883
+ }
1884
+
1885
+ $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
1886
+
1887
+ $em = "\0\1$ps\0$t";
1888
+
1889
+ return $em;
1890
+ }
1891
+
1892
+ /**
1893
+ * RSASSA-PKCS1-V1_5-SIGN
1894
+ *
1895
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
1896
+ *
1897
+ * @access private
1898
+ * @param String $m
1899
+ * @return String
1900
+ */
1901
+ function _rsassa_pkcs1_v1_5_sign($m)
1902
+ {
1903
+ // EMSA-PKCS1-v1_5 encoding
1904
+
1905
+ $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
1906
+ if ($em === false) {
1907
+ user_error('RSA modulus too short', E_USER_NOTICE);
1908
+ return false;
1909
+ }
1910
+
1911
+ // RSA signature
1912
+
1913
+ $m = $this->_os2ip($em);
1914
+ $s = $this->_rsasp1($m);
1915
+ $s = $this->_i2osp($s, $this->k);
1916
+
1917
+ // Output the signature S
1918
+
1919
+ return $s;
1920
+ }
1921
+
1922
+ /**
1923
+ * RSASSA-PKCS1-V1_5-VERIFY
1924
+ *
1925
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
1926
+ *
1927
+ * @access private
1928
+ * @param String $m
1929
+ * @return String
1930
+ */
1931
+ function _rsassa_pkcs1_v1_5_verify($m, $s)
1932
+ {
1933
+ // Length checking
1934
+
1935
+ if (strlen($s) != $this->k) {
1936
+ user_error('Invalid signature', E_USER_NOTICE);
1937
+ return false;
1938
+ }
1939
+
1940
+ // RSA verification
1941
+
1942
+ $s = $this->_os2ip($s);
1943
+ $m2 = $this->_rsavp1($s);
1944
+ if ($m2 === false) {
1945
+ user_error('Invalid signature', E_USER_NOTICE);
1946
+ return false;
1947
+ }
1948
+ $em = $this->_i2osp($m2, $this->k);
1949
+ if ($em === false) {
1950
+ user_error('Invalid signature', E_USER_NOTICE);
1951
+ return false;
1952
+ }
1953
+
1954
+ // EMSA-PKCS1-v1_5 encoding
1955
+
1956
+ $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
1957
+ if ($em2 === false) {
1958
+ user_error('RSA modulus too short', E_USER_NOTICE);
1959
+ return false;
1960
+ }
1961
+
1962
+ // Compare
1963
+
1964
+ return $em === $em2;
1965
+ }
1966
+
1967
+ /**
1968
+ * Set Encryption Mode
1969
+ *
1970
+ * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
1971
+ *
1972
+ * @access public
1973
+ * @param Integer $mode
1974
+ */
1975
+ function setEncryptionMode($mode)
1976
+ {
1977
+ $this->encryptionMode = $mode;
1978
+ }
1979
+
1980
+ /**
1981
+ * Set Signature Mode
1982
+ *
1983
+ * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
1984
+ *
1985
+ * @access public
1986
+ * @param Integer $mode
1987
+ */
1988
+ function setSignatureMode($mode)
1989
+ {
1990
+ $this->signatureMode = $mode;
1991
+ }
1992
+
1993
+ /**
1994
+ * Encryption
1995
+ *
1996
+ * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
1997
+ * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
1998
+ * be concatenated together.
1999
+ *
2000
+ * @see decrypt()
2001
+ * @access public
2002
+ * @param String $plaintext
2003
+ * @return String
2004
+ */
2005
+ function encrypt($plaintext)
2006
+ {
2007
+ switch ($this->encryptionMode) {
2008
+ case CRYPT_RSA_ENCRYPTION_PKCS1:
2009
+ $length = $this->k - 11;
2010
+ if ($length <= 0) {
2011
+ return false;
2012
+ }
2013
+
2014
+ $plaintext = str_split($plaintext, $length);
2015
+ $ciphertext = '';
2016
+ foreach ($plaintext as $m) {
2017
+ $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
2018
+ }
2019
+ return $ciphertext;
2020
+ //case CRYPT_RSA_ENCRYPTION_OAEP:
2021
+ default:
2022
+ $length = $this->k - 2 * $this->hLen - 2;
2023
+ if ($length <= 0) {
2024
+ return false;
2025
+ }
2026
+
2027
+ $plaintext = str_split($plaintext, $length);
2028
+ $ciphertext = '';
2029
+ foreach ($plaintext as $m) {
2030
+ $ciphertext.= $this->_rsaes_oaep_encrypt($m);
2031
+ }
2032
+ return $ciphertext;
2033
+ }
2034
+ }
2035
+
2036
+ /**
2037
+ * Decryption
2038
+ *
2039
+ * @see encrypt()
2040
+ * @access public
2041
+ * @param String $plaintext
2042
+ * @return String
2043
+ */
2044
+ function decrypt($ciphertext)
2045
+ {
2046
+ if ($this->k <= 0) {
2047
+ return false;
2048
+ }
2049
+
2050
+ $ciphertext = str_split($ciphertext, $this->k);
2051
+ $plaintext = '';
2052
+
2053
+ switch ($this->encryptionMode) {
2054
+ case CRYPT_RSA_ENCRYPTION_PKCS1:
2055
+ $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2056
+ break;
2057
+ //case CRYPT_RSA_ENCRYPTION_OAEP:
2058
+ default:
2059
+ $decrypt = '_rsaes_oaep_decrypt';
2060
+ }
2061
+
2062
+ foreach ($ciphertext as $c) {
2063
+ $temp = $this->$decrypt($c);
2064
+ if ($temp === false) {
2065
+ return false;
2066
+ }
2067
+ $plaintext.= $temp;
2068
+ }
2069
+
2070
+ return $plaintext;
2071
+ }
2072
+
2073
+ /**
2074
+ * Create a signature
2075
+ *
2076
+ * @see verify()
2077
+ * @access public
2078
+ * @param String $message
2079
+ * @return String
2080
+ */
2081
+ function sign($message)
2082
+ {
2083
+ if (empty($this->modulus) || empty($this->exponent)) {
2084
+ return false;
2085
+ }
2086
+
2087
+ switch ($this->signatureMode) {
2088
+ case CRYPT_RSA_SIGNATURE_PKCS1:
2089
+ return $this->_rsassa_pkcs1_v1_5_sign($message);
2090
+ //case CRYPT_RSA_SIGNATURE_PSS:
2091
+ default:
2092
+ return $this->_rsassa_pss_sign($message);
2093
+ }
2094
+ }
2095
+
2096
+ /**
2097
+ * Verifies a signature
2098
+ *
2099
+ * @see sign()
2100
+ * @access public
2101
+ * @param String $message
2102
+ * @param String $signature
2103
+ * @return Boolean
2104
+ */
2105
+ function verify($message, $signature)
2106
+ {
2107
+ if (empty($this->modulus) || empty($this->exponent)) {
2108
+ return false;
2109
+ }
2110
+
2111
+ switch ($this->signatureMode) {
2112
+ case CRYPT_RSA_SIGNATURE_PKCS1:
2113
+ return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2114
+ //case CRYPT_RSA_SIGNATURE_PSS:
2115
+ default:
2116
+ return $this->_rsassa_pss_verify($message, $signature);
2117
+ }
2118
+ }
2119
+ }
lib/phpseclib/Crypt/Random.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Random Number Generator
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Here's a short example of how to use this library:
10
+ * <code>
11
+ * <?php
12
+ * include('Crypt/Random.php');
13
+ *
14
+ * echo crypt_random();
15
+ * ?>
16
+ * </code>
17
+ *
18
+ * LICENSE: This library is free software; you can redistribute it and/or
19
+ * modify it under the terms of the GNU Lesser General Public
20
+ * License as published by the Free Software Foundation; either
21
+ * version 2.1 of the License, or (at your option) any later version.
22
+ *
23
+ * This library is distributed in the hope that it will be useful,
24
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26
+ * Lesser General Public License for more details.
27
+ *
28
+ * You should have received a copy of the GNU Lesser General Public
29
+ * License along with this library; if not, write to the Free Software
30
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31
+ * MA 02111-1307 USA
32
+ *
33
+ * @category Crypt
34
+ * @package Crypt_Random
35
+ * @author Jim Wigginton <terrafrost@php.net>
36
+ * @copyright MMVII Jim Wigginton
37
+ * @license http://www.gnu.org/licenses/lgpl.txt
38
+ * @version $Id: Random.php,v 1.9 2010/04/24 06:40:48 terrafrost Exp $
39
+ * @link http://phpseclib.sourceforge.net
40
+ */
41
+
42
+ /**
43
+ * Generate a random value.
44
+ *
45
+ * On 32-bit machines, the largest distance that can exist between $min and $max is 2**31.
46
+ * If $min and $max are farther apart than that then the last ($max - range) numbers.
47
+ *
48
+ * Depending on how this is being used, it may be worth while to write a replacement. For example,
49
+ * a PHP-based web app that stores its data in an SQL database can collect more entropy than this function
50
+ * can.
51
+ *
52
+ * @param optional Integer $min
53
+ * @param optional Integer $max
54
+ * @return Integer
55
+ * @access public
56
+ */
57
+ function crypt_random($min = 0, $max = 0x7FFFFFFF)
58
+ {
59
+ if ($min == $max) {
60
+ return $min;
61
+ }
62
+
63
+ // see http://en.wikipedia.org/wiki//dev/random
64
+ // if open_basedir is enabled file_exists() will ouput an "open_basedir restriction in effect" warning,
65
+ // so we suppress it.
66
+ if (@file_exists('/dev/urandom')) {
67
+ static $fp;
68
+ if (!$fp) {
69
+ $fp = fopen('/dev/urandom', 'rb');
70
+ }
71
+ extract(unpack('Nrandom', fread($fp, 4)));
72
+
73
+ // say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this:
74
+ // -4 % 3 + 0 = -1, even though -1 < $min
75
+ return abs($random) % ($max - $min) + $min;
76
+ }
77
+
78
+ /* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
79
+ Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:
80
+
81
+ http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/
82
+
83
+ The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:
84
+
85
+ http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3_2/ext/standard/php_rand.h?view=markup */
86
+ if (version_compare(PHP_VERSION, '5.2.5', '<=')) {
87
+ static $seeded;
88
+ if (!isset($seeded)) {
89
+ $seeded = true;
90
+ mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
91
+ }
92
+ }
93
+
94
+ static $crypto;
95
+
96
+ // The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5
97
+ // in the browser and reloading the page.
98
+
99
+ if (!isset($crypto)) {
100
+ $key = $iv = '';
101
+ for ($i = 0; $i < 8; $i++) {
102
+ $key.= pack('n', mt_rand(0, 0xFFFF));
103
+ $iv .= pack('n', mt_rand(0, 0xFFFF));
104
+ }
105
+ switch (true) {
106
+ case class_exists('Crypt_AES'):
107
+ $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
108
+ break;
109
+ case class_exists('Crypt_TripleDES'):
110
+ $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
111
+ break;
112
+ case class_exists('Crypt_DES'):
113
+ $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
114
+ break;
115
+ case class_exists('Crypt_RC4'):
116
+ $crypto = new Crypt_RC4();
117
+ break;
118
+ default:
119
+ extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF)))));
120
+ return abs($random) % ($max - $min) + $min;
121
+ }
122
+ $crypto->setKey($key);
123
+ $crypto->setIV($iv);
124
+ $crypto->enableContinuousBuffer();
125
+ }
126
+
127
+ extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0")));
128
+ return abs($random) % ($max - $min) + $min;
129
+ }
lib/phpseclib/Crypt/Rijndael.php ADDED
@@ -0,0 +1,1242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of Rijndael.
6
+ *
7
+ * Does not use mcrypt, even when available, for reasons that are explained below.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
12
+ * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
13
+ * {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
14
+ * 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until
15
+ * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
16
+ *
17
+ * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
18
+ * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
19
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
20
+ * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
21
+ * are first defined as valid key / block lengths in
22
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
23
+ * Extensions: Other block and Cipher Key lengths.
24
+ *
25
+ * {@internal The variable names are the same as those in
26
+ * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
27
+ *
28
+ * Here's a short example of how to use this library:
29
+ * <code>
30
+ * <?php
31
+ * include('Crypt/Rijndael.php');
32
+ *
33
+ * $rijndael = new Crypt_Rijndael();
34
+ *
35
+ * $rijndael->setKey('abcdefghijklmnop');
36
+ *
37
+ * $size = 10 * 1024;
38
+ * $plaintext = '';
39
+ * for ($i = 0; $i < $size; $i++) {
40
+ * $plaintext.= 'a';
41
+ * }
42
+ *
43
+ * echo $rijndael->decrypt($rijndael->encrypt($plaintext));
44
+ * ?>
45
+ * </code>
46
+ *
47
+ * LICENSE: This library is free software; you can redistribute it and/or
48
+ * modify it under the terms of the GNU Lesser General Public
49
+ * License as published by the Free Software Foundation; either
50
+ * version 2.1 of the License, or (at your option) any later version.
51
+ *
52
+ * This library is distributed in the hope that it will be useful,
53
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
54
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
55
+ * Lesser General Public License for more details.
56
+ *
57
+ * You should have received a copy of the GNU Lesser General Public
58
+ * License along with this library; if not, write to the Free Software
59
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
60
+ * MA 02111-1307 USA
61
+ *
62
+ * @category Crypt
63
+ * @package Crypt_Rijndael
64
+ * @author Jim Wigginton <terrafrost@php.net>
65
+ * @copyright MMVIII Jim Wigginton
66
+ * @license http://www.gnu.org/licenses/lgpl.txt
67
+ * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
68
+ * @link http://phpseclib.sourceforge.net
69
+ */
70
+
71
+ /**#@+
72
+ * @access public
73
+ * @see Crypt_Rijndael::encrypt()
74
+ * @see Crypt_Rijndael::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_RIJNDAEL_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_RIJNDAEL_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_RIJNDAEL_MODE_CBC', 2);
96
+ /**#@-*/
97
+
98
+ /**#@+
99
+ * @access private
100
+ * @see Crypt_Rijndael::Crypt_Rijndael()
101
+ */
102
+ /**
103
+ * Toggles the internal implementation
104
+ */
105
+ define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
106
+ /**
107
+ * Toggles the mcrypt implementation
108
+ */
109
+ define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
110
+ /**#@-*/
111
+
112
+ /**
113
+ * Pure-PHP implementation of Rijndael.
114
+ *
115
+ * @author Jim Wigginton <terrafrost@php.net>
116
+ * @version 0.1.0
117
+ * @access public
118
+ * @package Crypt_Rijndael
119
+ */
120
+ class Crypt_Rijndael {
121
+ /**
122
+ * The Encryption Mode
123
+ *
124
+ * @see Crypt_Rijndael::Crypt_Rijndael()
125
+ * @var Integer
126
+ * @access private
127
+ */
128
+ var $mode;
129
+
130
+ /**
131
+ * The Key
132
+ *
133
+ * @see Crypt_Rijndael::setKey()
134
+ * @var String
135
+ * @access private
136
+ */
137
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
138
+
139
+ /**
140
+ * The Initialization Vector
141
+ *
142
+ * @see Crypt_Rijndael::setIV()
143
+ * @var String
144
+ * @access private
145
+ */
146
+ var $iv = '';
147
+
148
+ /**
149
+ * A "sliding" Initialization Vector
150
+ *
151
+ * @see Crypt_Rijndael::enableContinuousBuffer()
152
+ * @var String
153
+ * @access private
154
+ */
155
+ var $encryptIV = '';
156
+
157
+ /**
158
+ * A "sliding" Initialization Vector
159
+ *
160
+ * @see Crypt_Rijndael::enableContinuousBuffer()
161
+ * @var String
162
+ * @access private
163
+ */
164
+ var $decryptIV = '';
165
+
166
+ /**
167
+ * Continuous Buffer status
168
+ *
169
+ * @see Crypt_Rijndael::enableContinuousBuffer()
170
+ * @var Boolean
171
+ * @access private
172
+ */
173
+ var $continuousBuffer = false;
174
+
175
+ /**
176
+ * Padding status
177
+ *
178
+ * @see Crypt_Rijndael::enablePadding()
179
+ * @var Boolean
180
+ * @access private
181
+ */
182
+ var $padding = true;
183
+
184
+ /**
185
+ * Does the key schedule need to be (re)calculated?
186
+ *
187
+ * @see setKey()
188
+ * @see setBlockLength()
189
+ * @see setKeyLength()
190
+ * @var Boolean
191
+ * @access private
192
+ */
193
+ var $changed = true;
194
+
195
+ /**
196
+ * Has the key length explicitly been set or should it be derived from the key, itself?
197
+ *
198
+ * @see setKeyLength()
199
+ * @var Boolean
200
+ * @access private
201
+ */
202
+ var $explicit_key_length = false;
203
+
204
+ /**
205
+ * The Key Schedule
206
+ *
207
+ * @see _setup()
208
+ * @var Array
209
+ * @access private
210
+ */
211
+ var $w;
212
+
213
+ /**
214
+ * The Inverse Key Schedule
215
+ *
216
+ * @see _setup()
217
+ * @var Array
218
+ * @access private
219
+ */
220
+ var $dw;
221
+
222
+ /**
223
+ * The Block Length
224
+ *
225
+ * @see setBlockLength()
226
+ * @var Integer
227
+ * @access private
228
+ * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
229
+ * $Nb because we need this value and not $Nb to pad strings appropriately.
230
+ */
231
+ var $block_size = 16;
232
+
233
+ /**
234
+ * The Block Length divided by 32
235
+ *
236
+ * @see setBlockLength()
237
+ * @var Integer
238
+ * @access private
239
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
240
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
241
+ * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
242
+ * of that, we'll just precompute it once.
243
+ *
244
+ */
245
+ var $Nb = 4;
246
+
247
+ /**
248
+ * The Key Length
249
+ *
250
+ * @see setKeyLength()
251
+ * @var Integer
252
+ * @access private
253
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
254
+ * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
255
+ * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
256
+ * of that, we'll just precompute it once.
257
+ */
258
+ var $key_size = 16;
259
+
260
+ /**
261
+ * The Key Length divided by 32
262
+ *
263
+ * @see setKeyLength()
264
+ * @var Integer
265
+ * @access private
266
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
267
+ */
268
+ var $Nk = 4;
269
+
270
+ /**
271
+ * The Number of Rounds
272
+ *
273
+ * @var Integer
274
+ * @access private
275
+ * @internal The max value is 14, the min value is 10.
276
+ */
277
+ var $Nr;
278
+
279
+ /**
280
+ * Shift offsets
281
+ *
282
+ * @var Array
283
+ * @access private
284
+ */
285
+ var $c;
286
+
287
+ /**
288
+ * Precomputed mixColumns table
289
+ *
290
+ * @see Crypt_Rijndael()
291
+ * @var Array
292
+ * @access private
293
+ */
294
+ var $t0;
295
+
296
+ /**
297
+ * Precomputed mixColumns table
298
+ *
299
+ * @see Crypt_Rijndael()
300
+ * @var Array
301
+ * @access private
302
+ */
303
+ var $t1;
304
+
305
+ /**
306
+ * Precomputed mixColumns table
307
+ *
308
+ * @see Crypt_Rijndael()
309
+ * @var Array
310
+ * @access private
311
+ */
312
+ var $t2;
313
+
314
+ /**
315
+ * Precomputed mixColumns table
316
+ *
317
+ * @see Crypt_Rijndael()
318
+ * @var Array
319
+ * @access private
320
+ */
321
+ var $t3;
322
+
323
+ /**
324
+ * Precomputed invMixColumns table
325
+ *
326
+ * @see Crypt_Rijndael()
327
+ * @var Array
328
+ * @access private
329
+ */
330
+ var $dt0;
331
+
332
+ /**
333
+ * Precomputed invMixColumns table
334
+ *
335
+ * @see Crypt_Rijndael()
336
+ * @var Array
337
+ * @access private
338
+ */
339
+ var $dt1;
340
+
341
+ /**
342
+ * Precomputed invMixColumns table
343
+ *
344
+ * @see Crypt_Rijndael()
345
+ * @var Array
346
+ * @access private
347
+ */
348
+ var $dt2;
349
+
350
+ /**
351
+ * Precomputed invMixColumns table
352
+ *
353
+ * @see Crypt_Rijndael()
354
+ * @var Array
355
+ * @access private
356
+ */
357
+ var $dt3;
358
+
359
+ /**
360
+ * Default Constructor.
361
+ *
362
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
363
+ * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
364
+ *
365
+ * @param optional Integer $mode
366
+ * @return Crypt_Rijndael
367
+ * @access public
368
+ */
369
+ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
370
+ {
371
+ switch ($mode) {
372
+ case CRYPT_RIJNDAEL_MODE_ECB:
373
+ case CRYPT_RIJNDAEL_MODE_CBC:
374
+ case CRYPT_RIJNDAEL_MODE_CTR:
375
+ $this->mode = $mode;
376
+ break;
377
+ default:
378
+ $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
379
+ }
380
+
381
+ $t3 = &$this->t3;
382
+ $t2 = &$this->t2;
383
+ $t1 = &$this->t1;
384
+ $t0 = &$this->t0;
385
+
386
+ $dt3 = &$this->dt3;
387
+ $dt2 = &$this->dt2;
388
+ $dt1 = &$this->dt1;
389
+ $dt0 = &$this->dt0;
390
+
391
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
392
+ // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
393
+ // those are the names we'll use.
394
+ $t3 = array(
395
+ 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
396
+ 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
397
+ 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
398
+ 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
399
+ 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
400
+ 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
401
+ 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
402
+ 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
403
+ 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
404
+ 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
405
+ 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
406
+ 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
407
+ 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
408
+ 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
409
+ 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
410
+ 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
411
+ 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
412
+ 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
413
+ 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
414
+ 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
415
+ 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
416
+ 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
417
+ 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
418
+ 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
419
+ 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
420
+ 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
421
+ 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
422
+ 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
423
+ 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
424
+ 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
425
+ 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
426
+ 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
427
+ );
428
+
429
+ $dt3 = array(
430
+ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
431
+ 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
432
+ 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
433
+ 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
434
+ 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
435
+ 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
436
+ 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
437
+ 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
438
+ 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
439
+ 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
440
+ 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
441
+ 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
442
+ 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
443
+ 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
444
+ 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
445
+ 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
446
+ 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
447
+ 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
448
+ 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
449
+ 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
450
+ 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
451
+ 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
452
+ 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
453
+ 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
454
+ 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
455
+ 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
456
+ 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
457
+ 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
458
+ 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
459
+ 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
460
+ 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
461
+ 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
462
+ );
463
+
464
+ for ($i = 0; $i < 256; $i++) {
465
+ $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
466
+ $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
467
+ $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
468
+
469
+ $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
470
+ $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
471
+ $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Sets the key.
477
+ *
478
+ * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
479
+ * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
480
+ * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
481
+ * excess bits.
482
+ *
483
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
484
+ *
485
+ * @access public
486
+ * @param String $key
487
+ */
488
+ function setKey($key)
489
+ {
490
+ $this->key = $key;
491
+ $this->changed = true;
492
+ }
493
+
494
+ /**
495
+ * Sets the initialization vector. (optional)
496
+ *
497
+ * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
498
+ * to be all zero's.
499
+ *
500
+ * @access public
501
+ * @param String $iv
502
+ */
503
+ function setIV($iv)
504
+ {
505
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));;
506
+ }
507
+
508
+ /**
509
+ * Sets the key length
510
+ *
511
+ * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
512
+ * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
513
+ *
514
+ * @access public
515
+ * @param Integer $length
516
+ */
517
+ function setKeyLength($length)
518
+ {
519
+ $length >>= 5;
520
+ if ($length > 8) {
521
+ $length = 8;
522
+ } else if ($length < 4) {
523
+ $length = 4;
524
+ }
525
+ $this->Nk = $length;
526
+ $this->key_size = $length << 2;
527
+
528
+ $this->explicit_key_length = true;
529
+ $this->changed = true;
530
+ }
531
+
532
+ /**
533
+ * Sets the block length
534
+ *
535
+ * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
536
+ * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
537
+ *
538
+ * @access public
539
+ * @param Integer $length
540
+ */
541
+ function setBlockLength($length)
542
+ {
543
+ $length >>= 5;
544
+ if ($length > 8) {
545
+ $length = 8;
546
+ } else if ($length < 4) {
547
+ $length = 4;
548
+ }
549
+ $this->Nb = $length;
550
+ $this->block_size = $length << 2;
551
+ $this->changed = true;
552
+ }
553
+
554
+ /**
555
+ * Generate CTR XOR encryption key
556
+ *
557
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
558
+ * plaintext / ciphertext in CTR mode.
559
+ *
560
+ * @see Crypt_Rijndael::decrypt()
561
+ * @see Crypt_Rijndael::encrypt()
562
+ * @access public
563
+ * @param Integer $length
564
+ * @param String $iv
565
+ */
566
+ function _generate_xor($length, &$iv)
567
+ {
568
+ $xor = '';
569
+ $block_size = $this->block_size;
570
+ $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
571
+ for ($i = 0; $i < $num_blocks; $i++) {
572
+ $xor.= $iv;
573
+ for ($j = 4; $j <= $block_size; $j+=4) {
574
+ $temp = substr($iv, -$j, 4);
575
+ switch ($temp) {
576
+ case "\xFF\xFF\xFF\xFF":
577
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
578
+ break;
579
+ case "\x7F\xFF\xFF\xFF":
580
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
581
+ break 2;
582
+ default:
583
+ extract(unpack('Ncount', $temp));
584
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
585
+ break 2;
586
+ }
587
+ }
588
+ }
589
+
590
+ return $xor;
591
+ }
592
+
593
+ /**
594
+ * Encrypts a message.
595
+ *
596
+ * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
597
+ * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
598
+ * necessary are discussed in the following
599
+ * URL:
600
+ *
601
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
602
+ *
603
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
604
+ * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
605
+ * length.
606
+ *
607
+ * @see Crypt_Rijndael::decrypt()
608
+ * @access public
609
+ * @param String $plaintext
610
+ */
611
+ function encrypt($plaintext)
612
+ {
613
+ $this->_setup();
614
+ if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) {
615
+ $plaintext = $this->_pad($plaintext);
616
+ }
617
+
618
+ $block_size = $this->block_size;
619
+ $ciphertext = '';
620
+ switch ($this->mode) {
621
+ case CRYPT_RIJNDAEL_MODE_ECB:
622
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
623
+ $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
624
+ }
625
+ break;
626
+ case CRYPT_RIJNDAEL_MODE_CBC:
627
+ $xor = $this->encryptIV;
628
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
629
+ $block = substr($plaintext, $i, $block_size);
630
+ $block = $this->_encryptBlock($block ^ $xor);
631
+ $xor = $block;
632
+ $ciphertext.= $block;
633
+ }
634
+ if ($this->continuousBuffer) {
635
+ $this->encryptIV = $xor;
636
+ }
637
+ break;
638
+ case CRYPT_RIJNDAEL_MODE_CTR:
639
+ $xor = $this->encryptIV;
640
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
641
+ $block = substr($plaintext, $i, $block_size);
642
+ $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
643
+ $ciphertext.= $block ^ $key;
644
+ }
645
+ if ($this->continuousBuffer) {
646
+ $this->encryptIV = $xor;
647
+ }
648
+ }
649
+
650
+ return $ciphertext;
651
+ }
652
+
653
+ /**
654
+ * Decrypts a message.
655
+ *
656
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
657
+ * it is.
658
+ *
659
+ * @see Crypt_Rijndael::encrypt()
660
+ * @access public
661
+ * @param String $ciphertext
662
+ */
663
+ function decrypt($ciphertext)
664
+ {
665
+ $this->_setup();
666
+
667
+ if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) {
668
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
669
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
670
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + $this->block_size - 1) % $this->block_size, chr(0));
671
+ }
672
+
673
+ $block_size = $this->block_size;
674
+ $plaintext = '';
675
+ switch ($this->mode) {
676
+ case CRYPT_RIJNDAEL_MODE_ECB:
677
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
678
+ $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
679
+ }
680
+ break;
681
+ case CRYPT_RIJNDAEL_MODE_CBC:
682
+ $xor = $this->decryptIV;
683
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
684
+ $block = substr($ciphertext, $i, $block_size);
685
+ $plaintext.= $this->_decryptBlock($block) ^ $xor;
686
+ $xor = $block;
687
+ }
688
+ if ($this->continuousBuffer) {
689
+ $this->decryptIV = $xor;
690
+ }
691
+ break;
692
+ case CRYPT_RIJNDAEL_MODE_CTR:
693
+ $xor = $this->decryptIV;
694
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
695
+ $block = substr($ciphertext, $i, $block_size);
696
+ $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
697
+ $plaintext.= $block ^ $key;
698
+ }
699
+ if ($this->continuousBuffer) {
700
+ $this->decryptIV = $xor;
701
+ }
702
+ }
703
+
704
+ return $this->mode != CRYPT_RIJNDAEL_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
705
+ }
706
+
707
+ /**
708
+ * Encrypts a block
709
+ *
710
+ * @access private
711
+ * @param String $in
712
+ * @return String
713
+ */
714
+ function _encryptBlock($in)
715
+ {
716
+ $state = array();
717
+ $words = unpack('N*word', $in);
718
+
719
+ $w = $this->w;
720
+ $t0 = $this->t0;
721
+ $t1 = $this->t1;
722
+ $t2 = $this->t2;
723
+ $t3 = $this->t3;
724
+ $Nb = $this->Nb;
725
+ $Nr = $this->Nr;
726
+ $c = $this->c;
727
+
728
+ // addRoundKey
729
+ $i = 0;
730
+ foreach ($words as $word) {
731
+ $state[] = $word ^ $w[0][$i++];
732
+ }
733
+
734
+ // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
735
+ // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
736
+ // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
737
+ // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
738
+ // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
739
+ // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
740
+
741
+ // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
742
+ $temp = array();
743
+ for ($round = 1; $round < $Nr; $round++) {
744
+ $i = 0; // $c[0] == 0
745
+ $j = $c[1];
746
+ $k = $c[2];
747
+ $l = $c[3];
748
+
749
+ while ($i < $this->Nb) {
750
+ $temp[$i] = $t0[$state[$i] & 0xFF000000] ^
751
+ $t1[$state[$j] & 0x00FF0000] ^
752
+ $t2[$state[$k] & 0x0000FF00] ^
753
+ $t3[$state[$l] & 0x000000FF] ^
754
+ $w[$round][$i];
755
+ $i++;
756
+ $j = ($j + 1) % $Nb;
757
+ $k = ($k + 1) % $Nb;
758
+ $l = ($l + 1) % $Nb;
759
+ }
760
+
761
+ for ($i = 0; $i < $Nb; $i++) {
762
+ $state[$i] = $temp[$i];
763
+ }
764
+ }
765
+
766
+ // subWord
767
+ for ($i = 0; $i < $Nb; $i++) {
768
+ $state[$i] = $this->_subWord($state[$i]);
769
+ }
770
+
771
+ // shiftRows + addRoundKey
772
+ $i = 0; // $c[0] == 0
773
+ $j = $c[1];
774
+ $k = $c[2];
775
+ $l = $c[3];
776
+ while ($i < $this->Nb) {
777
+ $temp[$i] = ($state[$i] & 0xFF000000) ^
778
+ ($state[$j] & 0x00FF0000) ^
779
+ ($state[$k] & 0x0000FF00) ^
780
+ ($state[$l] & 0x000000FF) ^
781
+ $w[$Nr][$i];
782
+ $i++;
783
+ $j = ($j + 1) % $Nb;
784
+ $k = ($k + 1) % $Nb;
785
+ $l = ($l + 1) % $Nb;
786
+ }
787
+ $state = $temp;
788
+
789
+ array_unshift($state, 'N*');
790
+
791
+ return call_user_func_array('pack', $state);
792
+ }
793
+
794
+ /**
795
+ * Decrypts a block
796
+ *
797
+ * @access private
798
+ * @param String $in
799
+ * @return String
800
+ */
801
+ function _decryptBlock($in)
802
+ {
803
+ $state = array();
804
+ $words = unpack('N*word', $in);
805
+
806
+ $num_states = count($state);
807
+ $dw = $this->dw;
808
+ $dt0 = $this->dt0;
809
+ $dt1 = $this->dt1;
810
+ $dt2 = $this->dt2;
811
+ $dt3 = $this->dt3;
812
+ $Nb = $this->Nb;
813
+ $Nr = $this->Nr;
814
+ $c = $this->c;
815
+
816
+ // addRoundKey
817
+ $i = 0;
818
+ foreach ($words as $word) {
819
+ $state[] = $word ^ $dw[$Nr][$i++];
820
+ }
821
+
822
+ $temp = array();
823
+ for ($round = $Nr - 1; $round > 0; $round--) {
824
+ $i = 0; // $c[0] == 0
825
+ $j = $Nb - $c[1];
826
+ $k = $Nb - $c[2];
827
+ $l = $Nb - $c[3];
828
+
829
+ while ($i < $Nb) {
830
+ $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
831
+ $dt1[$state[$j] & 0x00FF0000] ^
832
+ $dt2[$state[$k] & 0x0000FF00] ^
833
+ $dt3[$state[$l] & 0x000000FF] ^
834
+ $dw[$round][$i];
835
+ $i++;
836
+ $j = ($j + 1) % $Nb;
837
+ $k = ($k + 1) % $Nb;
838
+ $l = ($l + 1) % $Nb;
839
+ }
840
+
841
+ for ($i = 0; $i < $Nb; $i++) {
842
+ $state[$i] = $temp[$i];
843
+ }
844
+ }
845
+
846
+ // invShiftRows + invSubWord + addRoundKey
847
+ $i = 0; // $c[0] == 0
848
+ $j = $Nb - $c[1];
849
+ $k = $Nb - $c[2];
850
+ $l = $Nb - $c[3];
851
+
852
+ while ($i < $Nb) {
853
+ $temp[$i] = $dw[0][$i] ^
854
+ $this->_invSubWord(($state[$i] & 0xFF000000) |
855
+ ($state[$j] & 0x00FF0000) |
856
+ ($state[$k] & 0x0000FF00) |
857
+ ($state[$l] & 0x000000FF));
858
+ $i++;
859
+ $j = ($j + 1) % $Nb;
860
+ $k = ($k + 1) % $Nb;
861
+ $l = ($l + 1) % $Nb;
862
+ }
863
+
864
+ $state = $temp;
865
+
866
+ array_unshift($state, 'N*');
867
+
868
+ return call_user_func_array('pack', $state);
869
+ }
870
+
871
+ /**
872
+ * Setup Rijndael
873
+ *
874
+ * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
875
+ * key schedule.
876
+ *
877
+ * @access private
878
+ */
879
+ function _setup()
880
+ {
881
+ // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
882
+ // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
883
+ static $rcon = array(0,
884
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
885
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
886
+ 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
887
+ 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
888
+ 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
889
+ 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
890
+ );
891
+
892
+ if (!$this->changed) {
893
+ return;
894
+ }
895
+
896
+ if (!$this->explicit_key_length) {
897
+ // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
898
+ $length = strlen($this->key) >> 2;
899
+ if ($length > 8) {
900
+ $length = 8;
901
+ } else if ($length < 4) {
902
+ $length = 4;
903
+ }
904
+ $this->Nk = $length;
905
+ $this->key_size = $length << 2;
906
+ }
907
+
908
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
909
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
910
+
911
+ // see Rijndael-ammended.pdf#page=44
912
+ $this->Nr = max($this->Nk, $this->Nb) + 6;
913
+
914
+ // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
915
+ // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
916
+ // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
917
+ // "Table 2: Shift offsets for different block lengths"
918
+ switch ($this->Nb) {
919
+ case 4:
920
+ case 5:
921
+ case 6:
922
+ $this->c = array(0, 1, 2, 3);
923
+ break;
924
+ case 7:
925
+ $this->c = array(0, 1, 2, 4);
926
+ break;
927
+ case 8:
928
+ $this->c = array(0, 1, 3, 4);
929
+ }
930
+
931
+ $key = $this->key;
932
+
933
+ $w = array_values(unpack('N*words', $key));
934
+
935
+ $length = $this->Nb * ($this->Nr + 1);
936
+ for ($i = $this->Nk; $i < $length; $i++) {
937
+ $temp = $w[$i - 1];
938
+ if ($i % $this->Nk == 0) {
939
+ // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
940
+ // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
941
+ // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
942
+ // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
943
+ $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
944
+ $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
945
+ } else if ($this->Nk > 6 && $i % $this->Nk == 4) {
946
+ $temp = $this->_subWord($temp);
947
+ }
948
+ $w[$i] = $w[$i - $this->Nk] ^ $temp;
949
+ }
950
+
951
+ // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
952
+ // and generate the inverse key schedule. more specifically,
953
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
954
+ // "The key expansion for the Inverse Cipher is defined as follows:
955
+ // 1. Apply the Key Expansion.
956
+ // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
957
+ // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
958
+ $temp = array();
959
+ for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
960
+ if ($col == $this->Nb) {
961
+ if ($row == 0) {
962
+ $this->dw[0] = $this->w[0];
963
+ } else {
964
+ // subWord + invMixColumn + invSubWord = invMixColumn
965
+ $j = 0;
966
+ while ($j < $this->Nb) {
967
+ $dw = $this->_subWord($this->w[$row][$j]);
968
+ $temp[$j] = $this->dt0[$dw & 0xFF000000] ^
969
+ $this->dt1[$dw & 0x00FF0000] ^
970
+ $this->dt2[$dw & 0x0000FF00] ^
971
+ $this->dt3[$dw & 0x000000FF];
972
+ $j++;
973
+ }
974
+ $this->dw[$row] = $temp;
975
+ }
976
+
977
+ $col = 0;
978
+ $row++;
979
+ }
980
+ $this->w[$row][$col] = $w[$i];
981
+ }
982
+
983
+ $this->dw[$row] = $this->w[$row];
984
+
985
+ $this->changed = false;
986
+ }
987
+
988
+ /**
989
+ * Performs S-Box substitutions
990
+ *
991
+ * @access private
992
+ */
993
+ function _subWord($word)
994
+ {
995
+ static $sbox0, $sbox1, $sbox2, $sbox3;
996
+
997
+ if (empty($sbox0)) {
998
+ $sbox0 = array(
999
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
1000
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
1001
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
1002
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
1003
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
1004
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
1005
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
1006
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
1007
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
1008
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
1009
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
1010
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
1011
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
1012
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
1013
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
1014
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
1015
+ );
1016
+
1017
+ $sbox1 = array();
1018
+ $sbox2 = array();
1019
+ $sbox3 = array();
1020
+
1021
+ for ($i = 0; $i < 256; $i++) {
1022
+ $sbox1[$i << 8] = $sbox0[$i] << 8;
1023
+ $sbox2[$i << 16] = $sbox0[$i] << 16;
1024
+ $sbox3[$i << 24] = $sbox0[$i] << 24;
1025
+ }
1026
+ }
1027
+
1028
+ return $sbox0[$word & 0x000000FF] |
1029
+ $sbox1[$word & 0x0000FF00] |
1030
+ $sbox2[$word & 0x00FF0000] |
1031
+ $sbox3[$word & 0xFF000000];
1032
+ }
1033
+
1034
+ /**
1035
+ * Performs inverse S-Box substitutions
1036
+ *
1037
+ * @access private
1038
+ */
1039
+ function _invSubWord($word)
1040
+ {
1041
+ static $sbox0, $sbox1, $sbox2, $sbox3;
1042
+
1043
+ if (empty($sbox0)) {
1044
+ $sbox0 = array(
1045
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
1046
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
1047
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
1048
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
1049
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
1050
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
1051
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
1052
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
1053
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
1054
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
1055
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
1056
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
1057
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
1058
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1059
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1060
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1061
+ );
1062
+
1063
+ $sbox1 = array();
1064
+ $sbox2 = array();
1065
+ $sbox3 = array();
1066
+
1067
+ for ($i = 0; $i < 256; $i++) {
1068
+ $sbox1[$i << 8] = $sbox0[$i] << 8;
1069
+ $sbox2[$i << 16] = $sbox0[$i] << 16;
1070
+ $sbox3[$i << 24] = $sbox0[$i] << 24;
1071
+ }
1072
+ }
1073
+
1074
+ return $sbox0[$word & 0x000000FF] |
1075
+ $sbox1[$word & 0x0000FF00] |
1076
+ $sbox2[$word & 0x00FF0000] |
1077
+ $sbox3[$word & 0xFF000000];
1078
+ }
1079
+
1080
+ /**
1081
+ * Pad "packets".
1082
+ *
1083
+ * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
1084
+ * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1085
+ * pad the input so that it is of the proper length.
1086
+ *
1087
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1088
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1089
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1090
+ * transmitted separately)
1091
+ *
1092
+ * @see Crypt_Rijndael::disablePadding()
1093
+ * @access public
1094
+ */
1095
+ function enablePadding()
1096
+ {
1097
+ $this->padding = true;
1098
+ }
1099
+
1100
+ /**
1101
+ * Do not pad packets.
1102
+ *
1103
+ * @see Crypt_Rijndael::enablePadding()
1104
+ * @access public
1105
+ */
1106
+ function disablePadding()
1107
+ {
1108
+ $this->padding = false;
1109
+ }
1110
+
1111
+ /**
1112
+ * Pads a string
1113
+ *
1114
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1115
+ * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
1116
+ * chr($block_size - (strlen($text) % $block_size)
1117
+ *
1118
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1119
+ * and padding will, hence forth, be enabled.
1120
+ *
1121
+ * @see Crypt_Rijndael::_unpad()
1122
+ * @access private
1123
+ */
1124
+ function _pad($text)
1125
+ {
1126
+ $length = strlen($text);
1127
+
1128
+ if (!$this->padding) {
1129
+ if ($length % $this->block_size == 0) {
1130
+ return $text;
1131
+ } else {
1132
+ user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE);
1133
+ $this->padding = true;
1134
+ }
1135
+ }
1136
+
1137
+ $pad = $this->block_size - ($length % $this->block_size);
1138
+
1139
+ return str_pad($text, $length + $pad, chr($pad));
1140
+ }
1141
+
1142
+ /**
1143
+ * Unpads a string.
1144
+ *
1145
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1146
+ * and false will be returned.
1147
+ *
1148
+ * @see Crypt_Rijndael::_pad()
1149
+ * @access private
1150
+ */
1151
+ function _unpad($text)
1152
+ {
1153
+ if (!$this->padding) {
1154
+ return $text;
1155
+ }
1156
+
1157
+ $length = ord($text[strlen($text) - 1]);
1158
+
1159
+ if (!$length || $length > $this->block_size) {
1160
+ return false;
1161
+ }
1162
+
1163
+ return substr($text, 0, -$length);
1164
+ }
1165
+
1166
+ /**
1167
+ * Treat consecutive "packets" as if they are a continuous buffer.
1168
+ *
1169
+ * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1170
+ * will yield different outputs:
1171
+ *
1172
+ * <code>
1173
+ * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1174
+ * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1175
+ * </code>
1176
+ * <code>
1177
+ * echo $rijndael->encrypt($plaintext);
1178
+ * </code>
1179
+ *
1180
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1181
+ * another, as demonstrated with the following:
1182
+ *
1183
+ * <code>
1184
+ * $rijndael->encrypt(substr($plaintext, 0, 16));
1185
+ * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1186
+ * </code>
1187
+ * <code>
1188
+ * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1189
+ * </code>
1190
+ *
1191
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1192
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1193
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1194
+ *
1195
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
1196
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1197
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1198
+ * however, they are also less intuitive and more likely to cause you problems.
1199
+ *
1200
+ * @see Crypt_Rijndael::disableContinuousBuffer()
1201
+ * @access public
1202
+ */
1203
+ function enableContinuousBuffer()
1204
+ {
1205
+ $this->continuousBuffer = true;
1206
+ }
1207
+
1208
+ /**
1209
+ * Treat consecutive packets as if they are a discontinuous buffer.
1210
+ *
1211
+ * The default behavior.
1212
+ *
1213
+ * @see Crypt_Rijndael::enableContinuousBuffer()
1214
+ * @access public
1215
+ */
1216
+ function disableContinuousBuffer()
1217
+ {
1218
+ $this->continuousBuffer = false;
1219
+ $this->encryptIV = $this->iv;
1220
+ $this->decryptIV = $this->iv;
1221
+ }
1222
+
1223
+ /**
1224
+ * String Shift
1225
+ *
1226
+ * Inspired by array_shift
1227
+ *
1228
+ * @param String $string
1229
+ * @param optional Integer $index
1230
+ * @return String
1231
+ * @access private
1232
+ */
1233
+ function _string_shift(&$string, $index = 1)
1234
+ {
1235
+ $substr = substr($string, 0, $index);
1236
+ $string = substr($string, $index);
1237
+ return $substr;
1238
+ }
1239
+ }
1240
+
1241
+ // vim: ts=4:sw=4:et:
1242
+ // vim6: fdl=1:
lib/phpseclib/Crypt/TripleDES.php ADDED
@@ -0,0 +1,690 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of Triple DES.
6
+ *
7
+ * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Here's a short example of how to use this library:
12
+ * <code>
13
+ * <?php
14
+ * include('Crypt/TripleDES.php');
15
+ *
16
+ * $des = new Crypt_TripleDES();
17
+ *
18
+ * $des->setKey('abcdefghijklmnopqrstuvwx');
19
+ *
20
+ * $size = 10 * 1024;
21
+ * $plaintext = '';
22
+ * for ($i = 0; $i < $size; $i++) {
23
+ * $plaintext.= 'a';
24
+ * }
25
+ *
26
+ * echo $des->decrypt($des->encrypt($plaintext));
27
+ * ?>
28
+ * </code>
29
+ *
30
+ * LICENSE: This library is free software; you can redistribute it and/or
31
+ * modify it under the terms of the GNU Lesser General Public
32
+ * License as published by the Free Software Foundation; either
33
+ * version 2.1 of the License, or (at your option) any later version.
34
+ *
35
+ * This library is distributed in the hope that it will be useful,
36
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
37
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38
+ * Lesser General Public License for more details.
39
+ *
40
+ * You should have received a copy of the GNU Lesser General Public
41
+ * License along with this library; if not, write to the Free Software
42
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
43
+ * MA 02111-1307 USA
44
+ *
45
+ * @category Crypt
46
+ * @package Crypt_TripleDES
47
+ * @author Jim Wigginton <terrafrost@php.net>
48
+ * @copyright MMVII Jim Wigginton
49
+ * @license http://www.gnu.org/licenses/lgpl.txt
50
+ * @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $
51
+ * @link http://phpseclib.sourceforge.net
52
+ */
53
+
54
+ /**
55
+ * Include Crypt_DES
56
+ */
57
+ require_once 'DES.php';
58
+
59
+ /**
60
+ * Encrypt / decrypt using inner chaining
61
+ *
62
+ * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
63
+ */
64
+ define('CRYPT_DES_MODE_3CBC', 3);
65
+
66
+ /**
67
+ * Encrypt / decrypt using outer chaining
68
+ *
69
+ * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
70
+ */
71
+ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
72
+
73
+ /**
74
+ * Pure-PHP implementation of Triple DES.
75
+ *
76
+ * @author Jim Wigginton <terrafrost@php.net>
77
+ * @version 0.1.0
78
+ * @access public
79
+ * @package Crypt_TerraDES
80
+ */
81
+ class Crypt_TripleDES {
82
+ /**
83
+ * The Three Keys
84
+ *
85
+ * @see Crypt_TripleDES::setKey()
86
+ * @var String
87
+ * @access private
88
+ */
89
+ var $key = "\0\0\0\0\0\0\0\0";
90
+
91
+ /**
92
+ * The Encryption Mode
93
+ *
94
+ * @see Crypt_TripleDES::Crypt_TripleDES()
95
+ * @var Integer
96
+ * @access private
97
+ */
98
+ var $mode = CRYPT_DES_MODE_CBC;
99
+
100
+ /**
101
+ * Continuous Buffer status
102
+ *
103
+ * @see Crypt_TripleDES::enableContinuousBuffer()
104
+ * @var Boolean
105
+ * @access private
106
+ */
107
+ var $continuousBuffer = false;
108
+
109
+ /**
110
+ * Padding status
111
+ *
112
+ * @see Crypt_TripleDES::enablePadding()
113
+ * @var Boolean
114
+ * @access private
115
+ */
116
+ var $padding = true;
117
+
118
+ /**
119
+ * The Initialization Vector
120
+ *
121
+ * @see Crypt_TripleDES::setIV()
122
+ * @var String
123
+ * @access private
124
+ */
125
+ var $iv = "\0\0\0\0\0\0\0\0";
126
+
127
+ /**
128
+ * A "sliding" Initialization Vector
129
+ *
130
+ * @see Crypt_TripleDES::enableContinuousBuffer()
131
+ * @var String
132
+ * @access private
133
+ */
134
+ var $encryptIV = "\0\0\0\0\0\0\0\0";
135
+
136
+ /**
137
+ * A "sliding" Initialization Vector
138
+ *
139
+ * @see Crypt_TripleDES::enableContinuousBuffer()
140
+ * @var String
141
+ * @access private
142
+ */
143
+ var $decryptIV = "\0\0\0\0\0\0\0\0";
144
+
145
+ /**
146
+ * The Crypt_DES objects
147
+ *
148
+ * @var Array
149
+ * @access private
150
+ */
151
+ var $des;
152
+
153
+ /**
154
+ * mcrypt resource for encryption
155
+ *
156
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
157
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
158
+ *
159
+ * @see Crypt_AES::encrypt()
160
+ * @var String
161
+ * @access private
162
+ */
163
+ var $enmcrypt;
164
+
165
+ /**
166
+ * mcrypt resource for decryption
167
+ *
168
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
169
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
170
+ *
171
+ * @see Crypt_AES::decrypt()
172
+ * @var String
173
+ * @access private
174
+ */
175
+ var $demcrypt;
176
+
177
+ /**
178
+ * Does the (en|de)mcrypt resource need to be (re)initialized?
179
+ *
180
+ * @see setKey()
181
+ * @see setIV()
182
+ * @var Boolean
183
+ * @access private
184
+ */
185
+ var $changed = true;
186
+
187
+ /**
188
+ * Default Constructor.
189
+ *
190
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
191
+ * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
192
+ *
193
+ * @param optional Integer $mode
194
+ * @return Crypt_TripleDES
195
+ * @access public
196
+ */
197
+ function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
198
+ {
199
+ if ( !defined('CRYPT_DES_MODE') ) {
200
+ switch (true) {
201
+ case extension_loaded('mcrypt'):
202
+ // i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
203
+ // but since that can be changed after the object has been created, there doesn't seem to be
204
+ // a lot of point...
205
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
206
+ break;
207
+ default:
208
+ define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
209
+ }
210
+ }
211
+
212
+ if ( $mode == CRYPT_DES_MODE_3CBC ) {
213
+ $this->mode = CRYPT_DES_MODE_3CBC;
214
+ $this->des = array(
215
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
216
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
217
+ new Crypt_DES(CRYPT_DES_MODE_CBC)
218
+ );
219
+
220
+ // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
221
+ $this->des[0]->disablePadding();
222
+ $this->des[1]->disablePadding();
223
+ $this->des[2]->disablePadding();
224
+
225
+ return;
226
+ }
227
+
228
+ switch ( CRYPT_DES_MODE ) {
229
+ case CRYPT_DES_MODE_MCRYPT:
230
+ switch ($mode) {
231
+ case CRYPT_DES_MODE_ECB:
232
+ $this->mode = MCRYPT_MODE_ECB;
233
+ break;
234
+ case CRYPT_DES_MODE_CTR:
235
+ $this->mode = 'ctr';
236
+ break;
237
+ case CRYPT_DES_MODE_CBC:
238
+ default:
239
+ $this->mode = MCRYPT_MODE_CBC;
240
+ }
241
+
242
+ break;
243
+ default:
244
+ $this->des = array(
245
+ new Crypt_DES(CRYPT_DES_MODE_ECB),
246
+ new Crypt_DES(CRYPT_DES_MODE_ECB),
247
+ new Crypt_DES(CRYPT_DES_MODE_ECB)
248
+ );
249
+
250
+ // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
251
+ $this->des[0]->disablePadding();
252
+ $this->des[1]->disablePadding();
253
+ $this->des[2]->disablePadding();
254
+
255
+ switch ($mode) {
256
+ case CRYPT_DES_MODE_ECB:
257
+ case CRYPT_DES_MODE_CTR:
258
+ case CRYPT_DES_MODE_CBC:
259
+ $this->mode = $mode;
260
+ break;
261
+ default:
262
+ $this->mode = CRYPT_DES_MODE_CBC;
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Sets the key.
269
+ *
270
+ * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
271
+ * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
272
+ *
273
+ * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
274
+ *
275
+ * If the key is not explicitly set, it'll be assumed to be all zero's.
276
+ *
277
+ * @access public
278
+ * @param String $key
279
+ */
280
+ function setKey($key)
281
+ {
282
+ $length = strlen($key);
283
+ if ($length > 8) {
284
+ $key = str_pad($key, 24, chr(0));
285
+ // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
286
+ // http://php.net/function.mcrypt-encrypt#47973
287
+ //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
288
+ }
289
+ $this->key = $key;
290
+ switch (true) {
291
+ case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
292
+ case $this->mode == CRYPT_DES_MODE_3CBC:
293
+ $this->des[0]->setKey(substr($key, 0, 8));
294
+ $this->des[1]->setKey(substr($key, 8, 8));
295
+ $this->des[2]->setKey(substr($key, 16, 8));
296
+ }
297
+ $this->changed = true;
298
+ }
299
+
300
+ /**
301
+ * Sets the initialization vector. (optional)
302
+ *
303
+ * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
304
+ * to be all zero's.
305
+ *
306
+ * @access public
307
+ * @param String $iv
308
+ */
309
+ function setIV($iv)
310
+ {
311
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
312
+ if ($this->mode == CRYPT_DES_MODE_3CBC) {
313
+ $this->des[0]->setIV($iv);
314
+ $this->des[1]->setIV($iv);
315
+ $this->des[2]->setIV($iv);
316
+ }
317
+ $this->changed = true;
318
+ }
319
+
320
+ /**
321
+ * Generate CTR XOR encryption key
322
+ *
323
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
324
+ * plaintext / ciphertext in CTR mode.
325
+ *
326
+ * @see Crypt_DES::decrypt()
327
+ * @see Crypt_DES::encrypt()
328
+ * @access public
329
+ * @param Integer $length
330
+ * @param String $iv
331
+ */
332
+ function _generate_xor($length, &$iv)
333
+ {
334
+ $xor = '';
335
+ $num_blocks = ($length + 7) >> 3;
336
+ for ($i = 0; $i < $num_blocks; $i++) {
337
+ $xor.= $iv;
338
+ for ($j = 4; $j <= 8; $j+=4) {
339
+ $temp = substr($iv, -$j, 4);
340
+ switch ($temp) {
341
+ case "\xFF\xFF\xFF\xFF":
342
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
343
+ break;
344
+ case "\x7F\xFF\xFF\xFF":
345
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
346
+ break 2;
347
+ default:
348
+ extract(unpack('Ncount', $temp));
349
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
350
+ break 2;
351
+ }
352
+ }
353
+ }
354
+
355
+ return $xor;
356
+ }
357
+
358
+ /**
359
+ * Encrypts a message.
360
+ *
361
+ * @access public
362
+ * @param String $plaintext
363
+ */
364
+ function encrypt($plaintext)
365
+ {
366
+ if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
367
+ $plaintext = $this->_pad($plaintext);
368
+ }
369
+
370
+ // if the key is smaller then 8, do what we'd normally do
371
+ if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
372
+ $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
373
+
374
+ return $ciphertext;
375
+ }
376
+
377
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
378
+ if ($this->changed) {
379
+ if (!isset($this->enmcrypt)) {
380
+ $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
381
+ }
382
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
383
+ $this->changed = false;
384
+ }
385
+
386
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
387
+
388
+ if (!$this->continuousBuffer) {
389
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
390
+ }
391
+
392
+ return $ciphertext;
393
+ }
394
+
395
+ if (strlen($this->key) <= 8) {
396
+ $this->des[0]->mode = $this->mode;
397
+
398
+ return $this->des[0]->encrypt($plaintext);
399
+ }
400
+
401
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
402
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
403
+ $plaintext = str_pad($plaintext, ceil(strlen($plaintext) / 8) * 8, chr(0));
404
+
405
+ $des = $this->des;
406
+
407
+ $ciphertext = '';
408
+ switch ($this->mode) {
409
+ case CRYPT_DES_MODE_ECB:
410
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
411
+ $block = substr($plaintext, $i, 8);
412
+ $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
413
+ $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
414
+ $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
415
+ $ciphertext.= $block;
416
+ }
417
+ break;
418
+ case CRYPT_DES_MODE_CBC:
419
+ $xor = $this->encryptIV;
420
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
421
+ $block = substr($plaintext, $i, 8) ^ $xor;
422
+ $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
423
+ $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
424
+ $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
425
+ $xor = $block;
426
+ $ciphertext.= $block;
427
+ }
428
+ if ($this->continuousBuffer) {
429
+ $this->encryptIV = $xor;
430
+ }
431
+ break;
432
+ case CRYPT_DES_MODE_CTR:
433
+ $xor = $this->encryptIV;
434
+ for ($i = 0; $i < strlen($plaintext); $i+=8) {
435
+ $key = $this->_generate_xor(8, $xor);
436
+ $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
437
+ $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
438
+ $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
439
+ $block = substr($plaintext, $i, 8);
440
+ $ciphertext.= $block ^ $key;
441
+ }
442
+ if ($this->continuousBuffer) {
443
+ $this->encryptIV = $xor;
444
+ }
445
+ }
446
+
447
+ return $ciphertext;
448
+ }
449
+
450
+ /**
451
+ * Decrypts a message.
452
+ *
453
+ * @access public
454
+ * @param String $ciphertext
455
+ */
456
+ function decrypt($ciphertext)
457
+ {
458
+ if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
459
+ $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
460
+
461
+ return $this->_unpad($plaintext);
462
+ }
463
+
464
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
465
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
466
+ $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
467
+
468
+ if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
469
+ if ($this->changed) {
470
+ if (!isset($this->demcrypt)) {
471
+ $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
472
+ }
473
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
474
+ $this->changed = false;
475
+ }
476
+
477
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
478
+
479
+ if (!$this->continuousBuffer) {
480
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
481
+ }
482
+
483
+ return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
484
+ }
485
+
486
+ if (strlen($this->key) <= 8) {
487
+ $this->des[0]->mode = $this->mode;
488
+
489
+ return $this->_unpad($this->des[0]->decrypt($plaintext));
490
+ }
491
+
492
+ $des = $this->des;
493
+
494
+ $plaintext = '';
495
+ switch ($this->mode) {
496
+ case CRYPT_DES_MODE_ECB:
497
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
498
+ $block = substr($ciphertext, $i, 8);
499
+ $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
500
+ $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
501
+ $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
502
+ $plaintext.= $block;
503
+ }
504
+ break;
505
+ case CRYPT_DES_MODE_CBC:
506
+ $xor = $this->decryptIV;
507
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
508
+ $orig = $block = substr($ciphertext, $i, 8);
509
+ $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
510
+ $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
511
+ $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
512
+ $plaintext.= $block ^ $xor;
513
+ $xor = $orig;
514
+ }
515
+ if ($this->continuousBuffer) {
516
+ $this->decryptIV = $xor;
517
+ }
518
+ break;
519
+ case CRYPT_DES_MODE_CTR:
520
+ $xor = $this->decryptIV;
521
+ for ($i = 0; $i < strlen($ciphertext); $i+=8) {
522
+ $key = $this->_generate_xor(8, $xor);
523
+ $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
524
+ $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
525
+ $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
526
+ $block = substr($ciphertext, $i, 8);
527
+ $plaintext.= $block ^ $key;
528
+ }
529
+ if ($this->continuousBuffer) {
530
+ $this->decryptIV = $xor;
531
+ }
532
+ }
533
+
534
+ return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
535
+ }
536
+
537
+ /**
538
+ * Treat consecutive "packets" as if they are a continuous buffer.
539
+ *
540
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
541
+ * will yield different outputs:
542
+ *
543
+ * <code>
544
+ * echo $des->encrypt(substr($plaintext, 0, 8));
545
+ * echo $des->encrypt(substr($plaintext, 8, 8));
546
+ * </code>
547
+ * <code>
548
+ * echo $des->encrypt($plaintext);
549
+ * </code>
550
+ *
551
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
552
+ * another, as demonstrated with the following:
553
+ *
554
+ * <code>
555
+ * $des->encrypt(substr($plaintext, 0, 8));
556
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
557
+ * </code>
558
+ * <code>
559
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
560
+ * </code>
561
+ *
562
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
563
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
564
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
565
+ *
566
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
567
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
568
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
569
+ * however, they are also less intuitive and more likely to cause you problems.
570
+ *
571
+ * @see Crypt_TripleDES::disableContinuousBuffer()
572
+ * @access public
573
+ */
574
+ function enableContinuousBuffer()
575
+ {
576
+ $this->continuousBuffer = true;
577
+ if ($this->mode == CRYPT_DES_MODE_3CBC) {
578
+ $this->des[0]->enableContinuousBuffer();
579
+ $this->des[1]->enableContinuousBuffer();
580
+ $this->des[2]->enableContinuousBuffer();
581
+ }
582
+ }
583
+
584
+ /**
585
+ * Treat consecutive packets as if they are a discontinuous buffer.
586
+ *
587
+ * The default behavior.
588
+ *
589
+ * @see Crypt_TripleDES::enableContinuousBuffer()
590
+ * @access public
591
+ */
592
+ function disableContinuousBuffer()
593
+ {
594
+ $this->continuousBuffer = false;
595
+ $this->encryptIV = $this->iv;
596
+ $this->decryptIV = $this->iv;
597
+
598
+ if ($this->mode == CRYPT_DES_MODE_3CBC) {
599
+ $this->des[0]->disableContinuousBuffer();
600
+ $this->des[1]->disableContinuousBuffer();
601
+ $this->des[2]->disableContinuousBuffer();
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Pad "packets".
607
+ *
608
+ * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
609
+ * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
610
+ *
611
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
612
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
613
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
614
+ * transmitted separately)
615
+ *
616
+ * @see Crypt_TripleDES::disablePadding()
617
+ * @access public
618
+ */
619
+ function enablePadding()
620
+ {
621
+ $this->padding = true;
622
+ }
623
+
624
+ /**
625
+ * Do not pad packets.
626
+ *
627
+ * @see Crypt_TripleDES::enablePadding()
628
+ * @access public
629
+ */
630
+ function disablePadding()
631
+ {
632
+ $this->padding = false;
633
+ }
634
+
635
+ /**
636
+ * Pads a string
637
+ *
638
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
639
+ * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
640
+ *
641
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
642
+ * and padding will, hence forth, be enabled.
643
+ *
644
+ * @see Crypt_TripleDES::_unpad()
645
+ * @access private
646
+ */
647
+ function _pad($text)
648
+ {
649
+ $length = strlen($text);
650
+
651
+ if (!$this->padding) {
652
+ if (($length & 7) == 0) {
653
+ return $text;
654
+ } else {
655
+ user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
656
+ $this->padding = true;
657
+ }
658
+ }
659
+
660
+ $pad = 8 - ($length & 7);
661
+ return str_pad($text, $length + $pad, chr($pad));
662
+ }
663
+
664
+ /**
665
+ * Unpads a string
666
+ *
667
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
668
+ * and false will be returned.
669
+ *
670
+ * @see Crypt_TripleDES::_pad()
671
+ * @access private
672
+ */
673
+ function _unpad($text)
674
+ {
675
+ if (!$this->padding) {
676
+ return $text;
677
+ }
678
+
679
+ $length = ord($text[strlen($text) - 1]);
680
+
681
+ if (!$length || $length > 8) {
682
+ return false;
683
+ }
684
+
685
+ return substr($text, 0, -$length);
686
+ }
687
+ }
688
+
689
+ // vim: ts=4:sw=4:et:
690
+ // vim6: fdl=1:
lib/phpseclib/Math/BigInteger.php ADDED
@@ -0,0 +1,3545 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP arbitrary precision integer arithmetic library.
6
+ *
7
+ * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
8
+ * and an internal implementation, otherwise.
9
+ *
10
+ * PHP versions 4 and 5
11
+ *
12
+ * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
13
+ * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
14
+ *
15
+ * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
16
+ * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
17
+ * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
18
+ * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
19
+ * used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
20
+ * which only supports integers. Although this fact will slow this library down, the fact that such a high
21
+ * base is being used should more than compensate.
22
+ *
23
+ * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again,
24
+ * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
25
+ * subtraction).
26
+ *
27
+ * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
28
+ * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
29
+ *
30
+ * Useful resources are as follows:
31
+ *
32
+ * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
33
+ * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
34
+ * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
35
+ *
36
+ * Here's an example of how to use this library:
37
+ * <code>
38
+ * <?php
39
+ * include('Math/BigInteger.php');
40
+ *
41
+ * $a = new Math_BigInteger(2);
42
+ * $b = new Math_BigInteger(3);
43
+ *
44
+ * $c = $a->add($b);
45
+ *
46
+ * echo $c->toString(); // outputs 5
47
+ * ?>
48
+ * </code>
49
+ *
50
+ * LICENSE: This library is free software; you can redistribute it and/or
51
+ * modify it under the terms of the GNU Lesser General Public
52
+ * License as published by the Free Software Foundation; either
53
+ * version 2.1 of the License, or (at your option) any later version.
54
+ *
55
+ * This library is distributed in the hope that it will be useful,
56
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
57
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
58
+ * Lesser General Public License for more details.
59
+ *
60
+ * You should have received a copy of the GNU Lesser General Public
61
+ * License along with this library; if not, write to the Free Software
62
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
63
+ * MA 02111-1307 USA
64
+ *
65
+ * @category Math
66
+ * @package Math_BigInteger
67
+ * @author Jim Wigginton <terrafrost@php.net>
68
+ * @copyright MMVI Jim Wigginton
69
+ * @license http://www.gnu.org/licenses/lgpl.txt
70
+ * @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $
71
+ * @link http://pear.php.net/package/Math_BigInteger
72
+ */
73
+
74
+ /**#@+
75
+ * Reduction constants
76
+ *
77
+ * @access private
78
+ * @see Math_BigInteger::_reduce()
79
+ */
80
+ /**
81
+ * @see Math_BigInteger::_montgomery()
82
+ * @see Math_BigInteger::_prepMontgomery()
83
+ */
84
+ define('MATH_BIGINTEGER_MONTGOMERY', 0);
85
+ /**
86
+ * @see Math_BigInteger::_barrett()
87
+ */
88
+ define('MATH_BIGINTEGER_BARRETT', 1);
89
+ /**
90
+ * @see Math_BigInteger::_mod2()
91
+ */
92
+ define('MATH_BIGINTEGER_POWEROF2', 2);
93
+ /**
94
+ * @see Math_BigInteger::_remainder()
95
+ */
96
+ define('MATH_BIGINTEGER_CLASSIC', 3);
97
+ /**
98
+ * @see Math_BigInteger::__clone()
99
+ */
100
+ define('MATH_BIGINTEGER_NONE', 4);
101
+ /**#@-*/
102
+
103
+ /**#@+
104
+ * Array constants
105
+ *
106
+ * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
107
+ * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
108
+ *
109
+ * @access private
110
+ */
111
+ /**
112
+ * $result[MATH_BIGINTEGER_VALUE] contains the value.
113
+ */
114
+ define('MATH_BIGINTEGER_VALUE', 0);
115
+ /**
116
+ * $result[MATH_BIGINTEGER_SIGN] contains the sign.
117
+ */
118
+ define('MATH_BIGINTEGER_SIGN', 1);
119
+ /**#@-*/
120
+
121
+ /**#@+
122
+ * @access private
123
+ * @see Math_BigInteger::_montgomery()
124
+ * @see Math_BigInteger::_barrett()
125
+ */
126
+ /**
127
+ * Cache constants
128
+ *
129
+ * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
130
+ */
131
+ define('MATH_BIGINTEGER_VARIABLE', 0);
132
+ /**
133
+ * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
134
+ */
135
+ define('MATH_BIGINTEGER_DATA', 1);
136
+ /**#@-*/
137
+
138
+ /**#@+
139
+ * Mode constants.
140
+ *
141
+ * @access private
142
+ * @see Math_BigInteger::Math_BigInteger()
143
+ */
144
+ /**
145
+ * To use the pure-PHP implementation
146
+ */
147
+ define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
148
+ /**
149
+ * To use the BCMath library
150
+ *
151
+ * (if enabled; otherwise, the internal implementation will be used)
152
+ */
153
+ define('MATH_BIGINTEGER_MODE_BCMATH', 2);
154
+ /**
155
+ * To use the GMP library
156
+ *
157
+ * (if present; otherwise, either the BCMath or the internal implementation will be used)
158
+ */
159
+ define('MATH_BIGINTEGER_MODE_GMP', 3);
160
+ /**#@-*/
161
+
162
+ /**
163
+ * The largest digit that may be used in addition / subtraction
164
+ *
165
+ * (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations
166
+ * will truncate 4503599627370496)
167
+ *
168
+ * @access private
169
+ */
170
+ define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52));
171
+
172
+ /**
173
+ * Karatsuba Cutoff
174
+ *
175
+ * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
176
+ *
177
+ * @access private
178
+ */
179
+ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
180
+
181
+ /**
182
+ * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
183
+ * numbers.
184
+ *
185
+ * @author Jim Wigginton <terrafrost@php.net>
186
+ * @version 1.0.0RC4
187
+ * @access public
188
+ * @package Math_BigInteger
189
+ */
190
+ class Math_BigInteger {
191
+ /**
192
+ * Holds the BigInteger's value.
193
+ *
194
+ * @var Array
195
+ * @access private
196
+ */
197
+ var $value;
198
+
199
+ /**
200
+ * Holds the BigInteger's magnitude.
201
+ *
202
+ * @var Boolean
203
+ * @access private
204
+ */
205
+ var $is_negative = false;
206
+
207
+ /**
208
+ * Random number generator function
209
+ *
210
+ * @see setRandomGenerator()
211
+ * @access private
212
+ */
213
+ var $generator = 'mt_rand';
214
+
215
+ /**
216
+ * Precision
217
+ *
218
+ * @see setPrecision()
219
+ * @access private
220
+ */
221
+ var $precision = -1;
222
+
223
+ /**
224
+ * Precision Bitmask
225
+ *
226
+ * @see setPrecision()
227
+ * @access private
228
+ */
229
+ var $bitmask = false;
230
+
231
+ /**
232
+ * Mode independant value used for serialization.
233
+ *
234
+ * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
235
+ * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
236
+ * however, $this->hex is only calculated when $this->__sleep() is called.
237
+ *
238
+ * @see __sleep()
239
+ * @see __wakeup()
240
+ * @var String
241
+ * @access private
242
+ */
243
+ var $hex;
244
+
245
+ /**
246
+ * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers.
247
+ *
248
+ * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
249
+ * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
250
+ *
251
+ * Here's an example:
252
+ * <code>
253
+ * <?php
254
+ * include('Math/BigInteger.php');
255
+ *
256
+ * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
257
+ *
258
+ * echo $a->toString(); // outputs 50
259
+ * ?>
260
+ * </code>
261
+ *
262
+ * @param optional $x base-10 number or base-$base number if $base set.
263
+ * @param optional integer $base
264
+ * @return Math_BigInteger
265
+ * @access public
266
+ */
267
+ function Math_BigInteger($x = 0, $base = 10)
268
+ {
269
+ if ( !defined('MATH_BIGINTEGER_MODE') ) {
270
+ switch (true) {
271
+ case extension_loaded('gmp'):
272
+ define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
273
+ break;
274
+ case extension_loaded('bcmath'):
275
+ define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
276
+ break;
277
+ default:
278
+ define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
279
+ }
280
+ }
281
+
282
+ switch ( MATH_BIGINTEGER_MODE ) {
283
+ case MATH_BIGINTEGER_MODE_GMP:
284
+ if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
285
+ $this->value = $x;
286
+ return;
287
+ }
288
+ $this->value = gmp_init(0);
289
+ break;
290
+ case MATH_BIGINTEGER_MODE_BCMATH:
291
+ $this->value = '0';
292
+ break;
293
+ default:
294
+ $this->value = array();
295
+ }
296
+
297
+ if (empty($x)) {
298
+ return;
299
+ }
300
+
301
+ switch ($base) {
302
+ case -256:
303
+ if (ord($x[0]) & 0x80) {
304
+ $x = ~$x;
305
+ $this->is_negative = true;
306
+ }
307
+ case 256:
308
+ switch ( MATH_BIGINTEGER_MODE ) {
309
+ case MATH_BIGINTEGER_MODE_GMP:
310
+ $sign = $this->is_negative ? '-' : '';
311
+ $this->value = gmp_init($sign . '0x' . bin2hex($x));
312
+ break;
313
+ case MATH_BIGINTEGER_MODE_BCMATH:
314
+ // round $len to the nearest 4 (thanks, DavidMJ!)
315
+ $len = (strlen($x) + 3) & 0xFFFFFFFC;
316
+
317
+ $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
318
+
319
+ for ($i = 0; $i < $len; $i+= 4) {
320
+ $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
321
+ $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
322
+ }
323
+
324
+ if ($this->is_negative) {
325
+ $this->value = '-' . $this->value;
326
+ }
327
+
328
+ break;
329
+ // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
330
+ default:
331
+ while (strlen($x)) {
332
+ $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
333
+ }
334
+ }
335
+
336
+ if ($this->is_negative) {
337
+ if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
338
+ $this->is_negative = false;
339
+ }
340
+ $temp = $this->add(new Math_BigInteger('-1'));
341
+ $this->value = $temp->value;
342
+ }
343
+ break;
344
+ case 16:
345
+ case -16:
346
+ if ($base > 0 && $x[0] == '-') {
347
+ $this->is_negative = true;
348
+ $x = substr($x, 1);
349
+ }
350
+
351
+ $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
352
+
353
+ $is_negative = false;
354
+ if ($base < 0 && hexdec($x[0]) >= 8) {
355
+ $this->is_negative = $is_negative = true;
356
+ $x = bin2hex(~pack('H*', $x));
357
+ }
358
+
359
+ switch ( MATH_BIGINTEGER_MODE ) {
360
+ case MATH_BIGINTEGER_MODE_GMP:
361
+ $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
362
+ $this->value = gmp_init($temp);
363
+ $this->is_negative = false;
364
+ break;
365
+ case MATH_BIGINTEGER_MODE_BCMATH:
366
+ $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
367
+ $temp = new Math_BigInteger(pack('H*', $x), 256);
368
+ $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
369
+ $this->is_negative = false;
370
+ break;
371
+ default:
372
+ $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
373
+ $temp = new Math_BigInteger(pack('H*', $x), 256);
374
+ $this->value = $temp->value;
375
+ }
376
+
377
+ if ($is_negative) {
378
+ $temp = $this->add(new Math_BigInteger('-1'));
379
+ $this->value = $temp->value;
380
+ }
381
+ break;
382
+ case 10:
383
+ case -10:
384
+ $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x);
385
+
386
+ switch ( MATH_BIGINTEGER_MODE ) {
387
+ case MATH_BIGINTEGER_MODE_GMP:
388
+ $this->value = gmp_init($x);
389
+ break;
390
+ case MATH_BIGINTEGER_MODE_BCMATH:
391
+ // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
392
+ // results then doing it on '-1' does (modInverse does $x[0])
393
+ $this->value = (string) $x;
394
+ break;
395
+ default:
396
+ $temp = new Math_BigInteger();
397
+
398
+ // array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it.
399
+ $multiplier = new Math_BigInteger();
400
+ $multiplier->value = array(10000000);
401
+
402
+ if ($x[0] == '-') {
403
+ $this->is_negative = true;
404
+ $x = substr($x, 1);
405
+ }
406
+
407
+ $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
408
+
409
+ while (strlen($x)) {
410
+ $temp = $temp->multiply($multiplier);
411
+ $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
412
+ $x = substr($x, 7);
413
+ }
414
+
415
+ $this->value = $temp->value;
416
+ }
417
+ break;
418
+ case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
419
+ case -2:
420
+ if ($base > 0 && $x[0] == '-') {
421
+ $this->is_negative = true;
422
+ $x = substr($x, 1);
423
+ }
424
+
425
+ $x = preg_replace('#^([01]*).*#', '$1', $x);
426
+ $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
427
+
428
+ $str = '0x';
429
+ while (strlen($x)) {
430
+ $part = substr($x, 0, 4);
431
+ $str.= dechex(bindec($part));
432
+ $x = substr($x, 4);
433
+ }
434
+
435
+ if ($this->is_negative) {
436
+ $str = '-' . $str;
437
+ }
438
+
439
+ $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
440
+ $this->value = $temp->value;
441
+ $this->is_negative = $temp->is_negative;
442
+
443
+ break;
444
+ default:
445
+ // base not supported, so we'll let $this == 0
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Converts a BigInteger to a byte string (eg. base-256).
451
+ *
452
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
453
+ * saved as two's compliment.
454
+ *
455
+ * Here's an example:
456
+ * <code>
457
+ * <?php
458
+ * include('Math/BigInteger.php');
459
+ *
460
+ * $a = new Math_BigInteger('65');
461
+ *
462
+ * echo $a->toBytes(); // outputs chr(65)
463
+ * ?>
464
+ * </code>
465
+ *
466
+ * @param Boolean $twos_compliment
467
+ * @return String
468
+ * @access public
469
+ * @internal Converts a base-2**26 number to base-2**8
470
+ */
471
+ function toBytes($twos_compliment = false)
472
+ {
473
+ if ($twos_compliment) {
474
+ $comparison = $this->compare(new Math_BigInteger());
475
+ if ($comparison == 0) {
476
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
477
+ }
478
+
479
+ $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
480
+ $bytes = $temp->toBytes();
481
+
482
+ if (empty($bytes)) { // eg. if the number we're trying to convert is -1
483
+ $bytes = chr(0);
484
+ }
485
+
486
+ if (ord($bytes[0]) & 0x80) {
487
+ $bytes = chr(0) . $bytes;
488
+ }
489
+
490
+ return $comparison < 0 ? ~$bytes : $bytes;
491
+ }
492
+
493
+ switch ( MATH_BIGINTEGER_MODE ) {
494
+ case MATH_BIGINTEGER_MODE_GMP:
495
+ if (gmp_cmp($this->value, gmp_init(0)) == 0) {
496
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
497
+ }
498
+
499
+ $temp = gmp_strval(gmp_abs($this->value), 16);
500
+ $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
501
+ $temp = pack('H*', $temp);
502
+
503
+ return $this->precision > 0 ?
504
+ substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
505
+ ltrim($temp, chr(0));
506
+ case MATH_BIGINTEGER_MODE_BCMATH:
507
+ if ($this->value === '0') {
508
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
509
+ }
510
+
511
+ $value = '';
512
+ $current = $this->value;
513
+
514
+ if ($current[0] == '-') {
515
+ $current = substr($current, 1);
516
+ }
517
+
518
+ while (bccomp($current, '0', 0) > 0) {
519
+ $temp = bcmod($current, '16777216');
520
+ $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
521
+ $current = bcdiv($current, '16777216', 0);
522
+ }
523
+
524
+ return $this->precision > 0 ?
525
+ substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
526
+ ltrim($value, chr(0));
527
+ }
528
+
529
+ if (!count($this->value)) {
530
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
531
+ }
532
+ $result = $this->_int2bytes($this->value[count($this->value) - 1]);
533
+
534
+ $temp = $this->copy();
535
+
536
+ for ($i = count($temp->value) - 2; $i >= 0; --$i) {
537
+ $temp->_base256_lshift($result, 26);
538
+ $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
539
+ }
540
+
541
+ return $this->precision > 0 ?
542
+ str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
543
+ $result;
544
+ }
545
+
546
+ /**
547
+ * Converts a BigInteger to a hex string (eg. base-16)).
548
+ *
549
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
550
+ * saved as two's compliment.
551
+ *
552
+ * Here's an example:
553
+ * <code>
554
+ * <?php
555
+ * include('Math/BigInteger.php');
556
+ *
557
+ * $a = new Math_BigInteger('65');
558
+ *
559
+ * echo $a->toHex(); // outputs '41'
560
+ * ?>
561
+ * </code>
562
+ *
563
+ * @param Boolean $twos_compliment
564
+ * @return String
565
+ * @access public
566
+ * @internal Converts a base-2**26 number to base-2**8
567
+ */
568
+ function toHex($twos_compliment = false)
569
+ {
570
+ return bin2hex($this->toBytes($twos_compliment));
571
+ }
572
+
573
+ /**
574
+ * Converts a BigInteger to a bit string (eg. base-2).
575
+ *
576
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
577
+ * saved as two's compliment.
578
+ *
579
+ * Here's an example:
580
+ * <code>
581
+ * <?php
582
+ * include('Math/BigInteger.php');
583
+ *
584
+ * $a = new Math_BigInteger('65');
585
+ *
586
+ * echo $a->toBits(); // outputs '1000001'
587
+ * ?>
588
+ * </code>
589
+ *
590
+ * @param Boolean $twos_compliment
591
+ * @return String
592
+ * @access public
593
+ * @internal Converts a base-2**26 number to base-2**2
594
+ */
595
+ function toBits($twos_compliment = false)
596
+ {
597
+ $hex = $this->toHex($twos_compliment);
598
+ $bits = '';
599
+ for ($i = 0; $i < strlen($hex); $i+=8) {
600
+ $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT);
601
+ }
602
+ return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
603
+ }
604
+
605
+ /**
606
+ * Converts a BigInteger to a base-10 number.
607
+ *
608
+ * Here's an example:
609
+ * <code>
610
+ * <?php
611
+ * include('Math/BigInteger.php');
612
+ *
613
+ * $a = new Math_BigInteger('50');
614
+ *
615
+ * echo $a->toString(); // outputs 50
616
+ * ?>
617
+ * </code>
618
+ *
619
+ * @return String
620
+ * @access public
621
+ * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
622
+ */
623
+ function toString()
624
+ {
625
+ switch ( MATH_BIGINTEGER_MODE ) {
626
+ case MATH_BIGINTEGER_MODE_GMP:
627
+ return gmp_strval($this->value);
628
+ case MATH_BIGINTEGER_MODE_BCMATH:
629
+ if ($this->value === '0') {
630
+ return '0';
631
+ }
632
+
633
+ return ltrim($this->value, '0');
634
+ }
635
+
636
+ if (!count($this->value)) {
637
+ return '0';
638
+ }
639
+
640
+ $temp = $this->copy();
641
+ $temp->is_negative = false;
642
+
643
+ $divisor = new Math_BigInteger();
644
+ $divisor->value = array(10000000); // eg. 10**7
645
+ $result = '';
646
+ while (count($temp->value)) {
647
+ list($temp, $mod) = $temp->divide($divisor);
648
+ $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result;
649
+ }
650
+ $result = ltrim($result, '0');
651
+ if (empty($result)) {
652
+ $result = '0';
653
+ }
654
+
655
+ if ($this->is_negative) {
656
+ $result = '-' . $result;
657
+ }
658
+
659
+ return $result;
660
+ }
661
+
662
+ /**
663
+ * Copy an object
664
+ *
665
+ * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
666
+ * that all objects are passed by value, when appropriate. More information can be found here:
667
+ *
668
+ * {@link http://php.net/language.oop5.basic#51624}
669
+ *
670
+ * @access public
671
+ * @see __clone()
672
+ * @return Math_BigInteger
673
+ */
674
+ function copy()
675
+ {
676
+ $temp = new Math_BigInteger();
677
+ $temp->value = $this->value;
678
+ $temp->is_negative = $this->is_negative;
679
+ $temp->generator = $this->generator;
680
+ $temp->precision = $this->precision;
681
+ $temp->bitmask = $this->bitmask;
682
+ return $temp;
683
+ }
684
+
685
+ /**
686
+ * __toString() magic method
687
+ *
688
+ * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
689
+ * toString().
690
+ *
691
+ * @access public
692
+ * @internal Implemented per a suggestion by Techie-Michael - thanks!
693
+ */
694
+ function __toString()
695
+ {
696
+ return $this->toString();
697
+ }
698
+
699
+ /**
700
+ * __clone() magic method
701
+ *
702
+ * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
703
+ * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
704
+ * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
705
+ * call Math_BigInteger::copy(), instead.
706
+ *
707
+ * @access public
708
+ * @see copy()
709
+ * @return Math_BigInteger
710
+ */
711
+ function __clone()
712
+ {
713
+ return $this->copy();
714
+ }
715
+
716
+ /**
717
+ * __sleep() magic method
718
+ *
719
+ * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
720
+ *
721
+ * @see __wakeup()
722
+ * @access public
723
+ */
724
+ function __sleep()
725
+ {
726
+ $this->hex = $this->toHex(true);
727
+ $vars = array('hex');
728
+ if ($this->generator != 'mt_rand') {
729
+ $vars[] = 'generator';
730
+ }
731
+ if ($this->precision > 0) {
732
+ $vars[] = 'precision';
733
+ }
734
+ return $vars;
735
+
736
+ }
737
+
738
+ /**
739
+ * __wakeup() magic method
740
+ *
741
+ * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
742
+ *
743
+ * @see __sleep()
744
+ * @access public
745
+ */
746
+ function __wakeup()
747
+ {
748
+ $temp = new Math_BigInteger($this->hex, -16);
749
+ $this->value = $temp->value;
750
+ $this->is_negative = $temp->is_negative;
751
+ $this->setRandomGenerator($this->generator);
752
+ if ($this->precision > 0) {
753
+ // recalculate $this->bitmask
754
+ $this->setPrecision($this->precision);
755
+ }
756
+ }
757
+
758
+ /**
759
+ * Adds two BigIntegers.
760
+ *
761
+ * Here's an example:
762
+ * <code>
763
+ * <?php
764
+ * include('Math/BigInteger.php');
765
+ *
766
+ * $a = new Math_BigInteger('10');
767
+ * $b = new Math_BigInteger('20');
768
+ *
769
+ * $c = $a->add($b);
770
+ *
771
+ * echo $c->toString(); // outputs 30
772
+ * ?>
773
+ * </code>
774
+ *
775
+ * @param Math_BigInteger $y
776
+ * @return Math_BigInteger
777
+ * @access public
778
+ * @internal Performs base-2**52 addition
779
+ */
780
+ function add($y)
781
+ {
782
+ switch ( MATH_BIGINTEGER_MODE ) {
783
+ case MATH_BIGINTEGER_MODE_GMP:
784
+ $temp = new Math_BigInteger();
785
+ $temp->value = gmp_add($this->value, $y->value);
786
+
787
+ return $this->_normalize($temp);
788
+ case MATH_BIGINTEGER_MODE_BCMATH:
789
+ $temp = new Math_BigInteger();
790
+ $temp->value = bcadd($this->value, $y->value, 0);
791
+
792
+ return $this->_normalize($temp);
793
+ }
794
+
795
+ $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
796
+
797
+ $result = new Math_BigInteger();
798
+ $result->value = $temp[MATH_BIGINTEGER_VALUE];
799
+ $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
800
+
801
+ return $this->_normalize($result);
802
+ }
803
+
804
+ /**
805
+ * Performs addition.
806
+ *
807
+ * @param Array $x_value
808
+ * @param Boolean $x_negative
809
+ * @param Array $y_value
810
+ * @param Boolean $y_negative
811
+ * @return Array
812
+ * @access private
813
+ */
814
+ function _add($x_value, $x_negative, $y_value, $y_negative)
815
+ {
816
+ $x_size = count($x_value);
817
+ $y_size = count($y_value);
818
+
819
+ if ($x_size == 0) {
820
+ return array(
821
+ MATH_BIGINTEGER_VALUE => $y_value,
822
+ MATH_BIGINTEGER_SIGN => $y_negative
823
+ );
824
+ } else if ($y_size == 0) {
825
+ return array(
826
+ MATH_BIGINTEGER_VALUE => $x_value,
827
+ MATH_BIGINTEGER_SIGN => $x_negative
828
+ );
829
+ }
830
+
831
+ // subtract, if appropriate
832
+ if ( $x_negative != $y_negative ) {
833
+ if ( $x_value == $y_value ) {
834
+ return array(
835
+ MATH_BIGINTEGER_VALUE => array(),
836
+ MATH_BIGINTEGER_SIGN => false
837
+ );
838
+ }
839
+
840
+ $temp = $this->_subtract($x_value, false, $y_value, false);
841
+ $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
842
+ $x_negative : $y_negative;
843
+
844
+ return $temp;
845
+ }
846
+
847
+ if ($x_size < $y_size) {
848
+ $size = $x_size;
849
+ $value = $y_value;
850
+ } else {
851
+ $size = $y_size;
852
+ $value = $x_value;
853
+ }
854
+
855
+ $value[] = 0; // just in case the carry adds an extra digit
856
+
857
+ $carry = 0;
858
+ for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
859
+ $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry;
860
+ $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
861
+ $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
862
+
863
+ $temp = (int) ($sum / 0x4000000);
864
+
865
+ $value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
866
+ $value[$j] = $temp;
867
+ }
868
+
869
+ if ($j == $size) { // ie. if $y_size is odd
870
+ $sum = $x_value[$i] + $y_value[$i] + $carry;
871
+ $carry = $sum >= 0x4000000;
872
+ $value[$i] = $carry ? $sum - 0x4000000 : $sum;
873
+ ++$i; // ie. let $i = $j since we've just done $value[$i]
874
+ }
875
+
876
+ if ($carry) {
877
+ for (; $value[$i] == 0x3FFFFFF; ++$i) {
878
+ $value[$i] = 0;
879
+ }
880
+ ++$value[$i];
881
+ }
882
+
883
+ return array(
884
+ MATH_BIGINTEGER_VALUE => $this->_trim($value),
885
+ MATH_BIGINTEGER_SIGN => $x_negative
886
+ );
887
+ }
888
+
889
+ /**
890
+ * Subtracts two BigIntegers.
891
+ *
892
+ * Here's an example:
893
+ * <code>
894
+ * <?php
895
+ * include('Math/BigInteger.php');
896
+ *
897
+ * $a = new Math_BigInteger('10');
898
+ * $b = new Math_BigInteger('20');
899
+ *
900
+ * $c = $a->subtract($b);
901
+ *
902
+ * echo $c->toString(); // outputs -10
903
+ * ?>
904
+ * </code>
905
+ *
906
+ * @param Math_BigInteger $y
907
+ * @return Math_BigInteger
908
+ * @access public
909
+ * @internal Performs base-2**52 subtraction
910
+ */
911
+ function subtract($y)
912
+ {
913
+ switch ( MATH_BIGINTEGER_MODE ) {
914
+ case MATH_BIGINTEGER_MODE_GMP:
915
+ $temp = new Math_BigInteger();
916
+ $temp->value = gmp_sub($this->value, $y->value);
917
+
918
+ return $this->_normalize($temp);
919
+ case MATH_BIGINTEGER_MODE_BCMATH:
920
+ $temp = new Math_BigInteger();
921
+ $temp->value = bcsub($this->value, $y->value, 0);
922
+
923
+ return $this->_normalize($temp);
924
+ }
925
+
926
+ $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
927
+
928
+ $result = new Math_BigInteger();
929
+ $result->value = $temp[MATH_BIGINTEGER_VALUE];
930
+ $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
931
+
932
+ return $this->_normalize($result);
933
+ }
934
+
935
+ /**
936
+ * Performs subtraction.
937
+ *
938
+ * @param Array $x_value
939
+ * @param Boolean $x_negative
940
+ * @param Array $y_value
941
+ * @param Boolean $y_negative
942
+ * @return Array
943
+ * @access private
944
+ */
945
+ function _subtract($x_value, $x_negative, $y_value, $y_negative)
946
+ {
947
+ $x_size = count($x_value);
948
+ $y_size = count($y_value);
949
+
950
+ if ($x_size == 0) {
951
+ return array(
952
+ MATH_BIGINTEGER_VALUE => $y_value,
953
+ MATH_BIGINTEGER_SIGN => !$y_negative
954
+ );
955
+ } else if ($y_size == 0) {
956
+ return array(
957
+ MATH_BIGINTEGER_VALUE => $x_value,
958
+ MATH_BIGINTEGER_SIGN => $x_negative
959
+ );
960
+ }
961
+
962
+ // add, if appropriate (ie. -$x - +$y or +$x - -$y)
963
+ if ( $x_negative != $y_negative ) {
964
+ $temp = $this->_add($x_value, false, $y_value, false);
965
+ $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
966
+
967
+ return $temp;
968
+ }
969
+
970
+ $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
971
+
972
+ if ( !$diff ) {
973
+ return array(
974
+ MATH_BIGINTEGER_VALUE => array(),
975
+ MATH_BIGINTEGER_SIGN => false
976
+ );
977
+ }
978
+
979
+ // switch $x and $y around, if appropriate.
980
+ if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
981
+ $temp = $x_value;
982
+ $x_value = $y_value;
983
+ $y_value = $temp;
984
+
985
+ $x_negative = !$x_negative;
986
+
987
+ $x_size = count($x_value);
988
+ $y_size = count($y_value);
989
+ }
990
+
991
+ // at this point, $x_value should be at least as big as - if not bigger than - $y_value
992
+
993
+ $carry = 0;
994
+ for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
995
+ $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry;
996
+ $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
997
+ $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
998
+
999
+ $temp = (int) ($sum / 0x4000000);
1000
+
1001
+ $x_value[$i] = (int) ($sum - 0x4000000 * $temp);
1002
+ $x_value[$j] = $temp;
1003
+ }
1004
+
1005
+ if ($j == $y_size) { // ie. if $y_size is odd
1006
+ $sum = $x_value[$i] - $y_value[$i] - $carry;
1007
+ $carry = $sum < 0;
1008
+ $x_value[$i] = $carry ? $sum + 0x4000000 : $sum;
1009
+ ++$i;
1010
+ }
1011
+
1012
+ if ($carry) {
1013
+ for (; !$x_value[$i]; ++$i) {
1014
+ $x_value[$i] = 0x3FFFFFF;
1015
+ }
1016
+ --$x_value[$i];
1017
+ }
1018
+
1019
+ return array(
1020
+ MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1021
+ MATH_BIGINTEGER_SIGN => $x_negative
1022
+ );
1023
+ }
1024
+
1025
+ /**
1026
+ * Multiplies two BigIntegers
1027
+ *
1028
+ * Here's an example:
1029
+ * <code>
1030
+ * <?php
1031
+ * include('Math/BigInteger.php');
1032
+ *
1033
+ * $a = new Math_BigInteger('10');
1034
+ * $b = new Math_BigInteger('20');
1035
+ *
1036
+ * $c = $a->multiply($b);
1037
+ *
1038
+ * echo $c->toString(); // outputs 200
1039
+ * ?>
1040
+ * </code>
1041
+ *
1042
+ * @param Math_BigInteger $x
1043
+ * @return Math_BigInteger
1044
+ * @access public
1045
+ */
1046
+ function multiply($x)
1047
+ {
1048
+ switch ( MATH_BIGINTEGER_MODE ) {
1049
+ case MATH_BIGINTEGER_MODE_GMP:
1050
+ $temp = new Math_BigInteger();
1051
+ $temp->value = gmp_mul($this->value, $x->value);
1052
+
1053
+ return $this->_normalize($temp);
1054
+ case MATH_BIGINTEGER_MODE_BCMATH:
1055
+ $temp = new Math_BigInteger();
1056
+ $temp->value = bcmul($this->value, $x->value, 0);
1057
+
1058
+ return $this->_normalize($temp);
1059
+ }
1060
+
1061
+ $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1062
+
1063
+ $product = new Math_BigInteger();
1064
+ $product->value = $temp[MATH_BIGINTEGER_VALUE];
1065
+ $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1066
+
1067
+ return $this->_normalize($product);
1068
+ }
1069
+
1070
+ /**
1071
+ * Performs multiplication.
1072
+ *
1073
+ * @param Array $x_value
1074
+ * @param Boolean $x_negative
1075
+ * @param Array $y_value
1076
+ * @param Boolean $y_negative
1077
+ * @return Array
1078
+ * @access private
1079
+ */
1080
+ function _multiply($x_value, $x_negative, $y_value, $y_negative)
1081
+ {
1082
+ //if ( $x_value == $y_value ) {
1083
+ // return array(
1084
+ // MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1085
+ // MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1086
+ // );
1087
+ //}
1088
+
1089
+ $x_length = count($x_value);
1090
+ $y_length = count($y_value);
1091
+
1092
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1093
+ return array(
1094
+ MATH_BIGINTEGER_VALUE => array(),
1095
+ MATH_BIGINTEGER_SIGN => false
1096
+ );
1097
+ }
1098
+
1099
+ return array(
1100
+ MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1101
+ $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1102
+ $this->_trim($this->_karatsuba($x_value, $y_value)),
1103
+ MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1104
+ );
1105
+ }
1106
+
1107
+ /**
1108
+ * Performs long multiplication on two BigIntegers
1109
+ *
1110
+ * Modeled after 'multiply' in MutableBigInteger.java.
1111
+ *
1112
+ * @param Array $x_value
1113
+ * @param Array $y_value
1114
+ * @return Array
1115
+ * @access private
1116
+ */
1117
+ function _regularMultiply($x_value, $y_value)
1118
+ {
1119
+ $x_length = count($x_value);
1120
+ $y_length = count($y_value);
1121
+
1122
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1123
+ return array();
1124
+ }
1125
+
1126
+ if ( $x_length < $y_length ) {
1127
+ $temp = $x_value;
1128
+ $x_value = $y_value;
1129
+ $y_value = $temp;
1130
+
1131
+ $x_length = count($x_value);
1132
+ $y_length = count($y_value);
1133
+ }
1134
+
1135
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
1136
+
1137
+ // the following for loop could be removed if the for loop following it
1138
+ // (the one with nested for loops) initially set $i to 0, but
1139
+ // doing so would also make the result in one set of unnecessary adds,
1140
+ // since on the outermost loops first pass, $product->value[$k] is going
1141
+ // to always be 0
1142
+
1143
+ $carry = 0;
1144
+
1145
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1146
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1147
+ $carry = (int) ($temp / 0x4000000);
1148
+ $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
1149
+ }
1150
+
1151
+ $product_value[$j] = $carry;
1152
+
1153
+ // the above for loop is what the previous comment was talking about. the
1154
+ // following for loop is the "one with nested for loops"
1155
+ for ($i = 1; $i < $y_length; ++$i) {
1156
+ $carry = 0;
1157
+
1158
+ for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1159
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1160
+ $carry = (int) ($temp / 0x4000000);
1161
+ $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
1162
+ }
1163
+
1164
+ $product_value[$k] = $carry;
1165
+ }
1166
+
1167
+ return $product_value;
1168
+ }
1169
+
1170
+ /**
1171
+ * Performs Karatsuba multiplication on two BigIntegers
1172
+ *
1173
+ * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1174
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1175
+ *
1176
+ * @param Array $x_value
1177
+ * @param Array $y_value
1178
+ * @return Array
1179
+ * @access private
1180
+ */
1181
+ function _karatsuba($x_value, $y_value)
1182
+ {
1183
+ $m = min(count($x_value) >> 1, count($y_value) >> 1);
1184
+
1185
+ if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1186
+ return $this->_regularMultiply($x_value, $y_value);
1187
+ }
1188
+
1189
+ $x1 = array_slice($x_value, $m);
1190
+ $x0 = array_slice($x_value, 0, $m);
1191
+ $y1 = array_slice($y_value, $m);
1192
+ $y0 = array_slice($y_value, 0, $m);
1193
+
1194
+ $z2 = $this->_karatsuba($x1, $y1);
1195
+ $z0 = $this->_karatsuba($x0, $y0);
1196
+
1197
+ $z1 = $this->_add($x1, false, $x0, false);
1198
+ $temp = $this->_add($y1, false, $y0, false);
1199
+ $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1200
+ $temp = $this->_add($z2, false, $z0, false);
1201
+ $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1202
+
1203
+ $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1204
+ $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1205
+
1206
+ $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1207
+ $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1208
+
1209
+ return $xy[MATH_BIGINTEGER_VALUE];
1210
+ }
1211
+
1212
+ /**
1213
+ * Performs squaring
1214
+ *
1215
+ * @param Array $x
1216
+ * @return Array
1217
+ * @access private
1218
+ */
1219
+ function _square($x = false)
1220
+ {
1221
+ return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1222
+ $this->_trim($this->_baseSquare($x)) :
1223
+ $this->_trim($this->_karatsubaSquare($x));
1224
+ }
1225
+
1226
+ /**
1227
+ * Performs traditional squaring on two BigIntegers
1228
+ *
1229
+ * Squaring can be done faster than multiplying a number by itself can be. See
1230
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1231
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1232
+ *
1233
+ * @param Array $value
1234
+ * @return Array
1235
+ * @access private
1236
+ */
1237
+ function _baseSquare($value)
1238
+ {
1239
+ if ( empty($value) ) {
1240
+ return array();
1241
+ }
1242
+ $square_value = $this->_array_repeat(0, 2 * count($value));
1243
+
1244
+ for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1245
+ $i2 = $i << 1;
1246
+
1247
+ $temp = $square_value[$i2] + $value[$i] * $value[$i];
1248
+ $carry = (int) ($temp / 0x4000000);
1249
+ $square_value[$i2] = (int) ($temp - 0x4000000 * $carry);
1250
+
1251
+ // note how we start from $i+1 instead of 0 as we do in multiplication.
1252
+ for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1253
+ $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1254
+ $carry = (int) ($temp / 0x4000000);
1255
+ $square_value[$k] = (int) ($temp - 0x4000000 * $carry);
1256
+ }
1257
+
1258
+ // the following line can yield values larger 2**15. at this point, PHP should switch
1259
+ // over to floats.
1260
+ $square_value[$i + $max_index + 1] = $carry;
1261
+ }
1262
+
1263
+ return $square_value;
1264
+ }
1265
+
1266
+ /**
1267
+ * Performs Karatsuba "squaring" on two BigIntegers
1268
+ *
1269
+ * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1270
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1271
+ *
1272
+ * @param Array $value
1273
+ * @return Array
1274
+ * @access private
1275
+ */
1276
+ function _karatsubaSquare($value)
1277
+ {
1278
+ $m = count($value) >> 1;
1279
+
1280
+ if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1281
+ return $this->_baseSquare($value);
1282
+ }
1283
+
1284
+ $x1 = array_slice($value, $m);
1285
+ $x0 = array_slice($value, 0, $m);
1286
+
1287
+ $z2 = $this->_karatsubaSquare($x1);
1288
+ $z0 = $this->_karatsubaSquare($x0);
1289
+
1290
+ $z1 = $this->_add($x1, false, $x0, false);
1291
+ $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
1292
+ $temp = $this->_add($z2, false, $z0, false);
1293
+ $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1294
+
1295
+ $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1296
+ $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1297
+
1298
+ $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1299
+ $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
1300
+
1301
+ return $xx[MATH_BIGINTEGER_VALUE];
1302
+ }
1303
+
1304
+ /**
1305
+ * Divides two BigIntegers.
1306
+ *
1307
+ * Returns an array whose first element contains the quotient and whose second element contains the
1308
+ * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
1309
+ * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1310
+ * and the divisor (basically, the "common residue" is the first positive modulo).
1311
+ *
1312
+ * Here's an example:
1313
+ * <code>
1314
+ * <?php
1315
+ * include('Math/BigInteger.php');
1316
+ *
1317
+ * $a = new Math_BigInteger('10');
1318
+ * $b = new Math_BigInteger('20');
1319
+ *
1320
+ * list($quotient, $remainder) = $a->divide($b);
1321
+ *
1322
+ * echo $quotient->toString(); // outputs 0
1323
+ * echo "\r\n";
1324
+ * echo $remainder->toString(); // outputs 10
1325
+ * ?>
1326
+ * </code>
1327
+ *
1328
+ * @param Math_BigInteger $y
1329
+ * @return Array
1330
+ * @access public
1331
+ * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1332
+ */
1333
+ function divide($y)
1334
+ {
1335
+ switch ( MATH_BIGINTEGER_MODE ) {
1336
+ case MATH_BIGINTEGER_MODE_GMP:
1337
+ $quotient = new Math_BigInteger();
1338
+ $remainder = new Math_BigInteger();
1339
+
1340
+ list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1341
+
1342
+ if (gmp_sign($remainder->value) < 0) {
1343
+ $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1344
+ }
1345
+
1346
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1347
+ case MATH_BIGINTEGER_MODE_BCMATH:
1348
+ $quotient = new Math_BigInteger();
1349
+ $remainder = new Math_BigInteger();
1350
+
1351
+ $quotient->value = bcdiv($this->value, $y->value, 0);
1352
+ $remainder->value = bcmod($this->value, $y->value);
1353
+
1354
+ if ($remainder->value[0] == '-') {
1355
+ $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1356
+ }
1357
+
1358
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1359
+ }
1360
+
1361
+ if (count($y->value) == 1) {
1362
+ list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1363
+ $quotient = new Math_BigInteger();
1364
+ $remainder = new Math_BigInteger();
1365
+ $quotient->value = $q;
1366
+ $remainder->value = array($r);
1367
+ $quotient->is_negative = $this->is_negative != $y->is_negative;
1368
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1369
+ }
1370
+
1371
+ static $zero;
1372
+ if ( !isset($zero) ) {
1373
+ $zero = new Math_BigInteger();
1374
+ }
1375
+
1376
+ $x = $this->copy();
1377
+ $y = $y->copy();
1378
+
1379
+ $x_sign = $x->is_negative;
1380
+ $y_sign = $y->is_negative;
1381
+
1382
+ $x->is_negative = $y->is_negative = false;
1383
+
1384
+ $diff = $x->compare($y);
1385
+
1386
+ if ( !$diff ) {
1387
+ $temp = new Math_BigInteger();
1388
+ $temp->value = array(1);
1389
+ $temp->is_negative = $x_sign != $y_sign;
1390
+ return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
1391
+ }
1392
+
1393
+ if ( $diff < 0 ) {
1394
+ // if $x is negative, "add" $y.
1395
+ if ( $x_sign ) {
1396
+ $x = $y->subtract($x);
1397
+ }
1398
+ return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
1399
+ }
1400
+
1401
+ // normalize $x and $y as described in HAC 14.23 / 14.24
1402
+ $msb = $y->value[count($y->value) - 1];
1403
+ for ($shift = 0; !($msb & 0x2000000); ++$shift) {
1404
+ $msb <<= 1;
1405
+ }
1406
+ $x->_lshift($shift);
1407
+ $y->_lshift($shift);
1408
+ $y_value = &$y->value;
1409
+
1410
+ $x_max = count($x->value) - 1;
1411
+ $y_max = count($y->value) - 1;
1412
+
1413
+ $quotient = new Math_BigInteger();
1414
+ $quotient_value = &$quotient->value;
1415
+ $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1416
+
1417
+ static $temp, $lhs, $rhs;
1418
+ if (!isset($temp)) {
1419
+ $temp = new Math_BigInteger();
1420
+ $lhs = new Math_BigInteger();
1421
+ $rhs = new Math_BigInteger();
1422
+ }
1423
+ $temp_value = &$temp->value;
1424
+ $rhs_value = &$rhs->value;
1425
+
1426
+ // $temp = $y << ($x_max - $y_max-1) in base 2**26
1427
+ $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1428
+
1429
+ while ( $x->compare($temp) >= 0 ) {
1430
+ // calculate the "common residue"
1431
+ ++$quotient_value[$x_max - $y_max];
1432
+ $x = $x->subtract($temp);
1433
+ $x_max = count($x->value) - 1;
1434
+ }
1435
+
1436
+ for ($i = $x_max; $i >= $y_max + 1; --$i) {
1437
+ $x_value = &$x->value;
1438
+ $x_window = array(
1439
+ isset($x_value[$i]) ? $x_value[$i] : 0,
1440
+ isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1441
+ isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1442
+ );
1443
+ $y_window = array(
1444
+ $y_value[$y_max],
1445
+ ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
1446
+ );
1447
+
1448
+ $q_index = $i - $y_max - 1;
1449
+ if ($x_window[0] == $y_window[0]) {
1450
+ $quotient_value[$q_index] = 0x3FFFFFF;
1451
+ } else {
1452
+ $quotient_value[$q_index] = (int) (
1453
+ ($x_window[0] * 0x4000000 + $x_window[1])
1454
+ /
1455
+ $y_window[0]
1456
+ );
1457
+ }
1458
+
1459
+ $temp_value = array($y_window[1], $y_window[0]);
1460
+
1461
+ $lhs->value = array($quotient_value[$q_index]);
1462
+ $lhs = $lhs->multiply($temp);
1463
+
1464
+ $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1465
+
1466
+ while ( $lhs->compare($rhs) > 0 ) {
1467
+ --$quotient_value[$q_index];
1468
+
1469
+ $lhs->value = array($quotient_value[$q_index]);
1470
+ $lhs = $lhs->multiply($temp);
1471
+ }
1472
+
1473
+ $adjust = $this->_array_repeat(0, $q_index);
1474
+ $temp_value = array($quotient_value[$q_index]);
1475
+ $temp = $temp->multiply($y);
1476
+ $temp_value = &$temp->value;
1477
+ $temp_value = array_merge($adjust, $temp_value);
1478
+
1479
+ $x = $x->subtract($temp);
1480
+
1481
+ if ($x->compare($zero) < 0) {
1482
+ $temp_value = array_merge($adjust, $y_value);
1483
+ $x = $x->add($temp);
1484
+
1485
+ --$quotient_value[$q_index];
1486
+ }
1487
+
1488
+ $x_max = count($x_value) - 1;
1489
+ }
1490
+
1491
+ // unnormalize the remainder
1492
+ $x->_rshift($shift);
1493
+
1494
+ $quotient->is_negative = $x_sign != $y_sign;
1495
+
1496
+ // calculate the "common residue", if appropriate
1497
+ if ( $x_sign ) {
1498
+ $y->_rshift($shift);
1499
+ $x = $y->subtract($x);
1500
+ }
1501
+
1502
+ return array($this->_normalize($quotient), $this->_normalize($x));
1503
+ }
1504
+
1505
+ /**
1506
+ * Divides a BigInteger by a regular integer
1507
+ *
1508
+ * abc / x = a00 / x + b0 / x + c / x
1509
+ *
1510
+ * @param Array $dividend
1511
+ * @param Array $divisor
1512
+ * @return Array
1513
+ * @access private
1514
+ */
1515
+ function _divide_digit($dividend, $divisor)
1516
+ {
1517
+ $carry = 0;
1518
+ $result = array();
1519
+
1520
+ for ($i = count($dividend) - 1; $i >= 0; --$i) {
1521
+ $temp = 0x4000000 * $carry + $dividend[$i];
1522
+ $result[$i] = (int) ($temp / $divisor);
1523
+ $carry = (int) ($temp - $divisor * $result[$i]);
1524
+ }
1525
+
1526
+ return array($result, $carry);
1527
+ }
1528
+
1529
+ /**
1530
+ * Performs modular exponentiation.
1531
+ *
1532
+ * Here's an example:
1533
+ * <code>
1534
+ * <?php
1535
+ * include('Math/BigInteger.php');
1536
+ *
1537
+ * $a = new Math_BigInteger('10');
1538
+ * $b = new Math_BigInteger('20');
1539
+ * $c = new Math_BigInteger('30');
1540
+ *
1541
+ * $c = $a->modPow($b, $c);
1542
+ *
1543
+ * echo $c->toString(); // outputs 10
1544
+ * ?>
1545
+ * </code>
1546
+ *
1547
+ * @param Math_BigInteger $e
1548
+ * @param Math_BigInteger $n
1549
+ * @return Math_BigInteger
1550
+ * @access public
1551
+ * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1552
+ * and although the approach involving repeated squaring does vastly better, it, too, is impractical
1553
+ * for our purposes. The reason being that division - by far the most complicated and time-consuming
1554
+ * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1555
+ *
1556
+ * Modular reductions resolve this issue. Although an individual modular reduction takes more time
1557
+ * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1558
+ *
1559
+ * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
1560
+ * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
1561
+ * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1562
+ * the product of two odd numbers is odd), but what about when RSA isn't used?
1563
+ *
1564
+ * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
1565
+ * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
1566
+ * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
1567
+ * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1568
+ * the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
1569
+ * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1570
+ */
1571
+ function modPow($e, $n)
1572
+ {
1573
+ $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1574
+
1575
+ if ($e->compare(new Math_BigInteger()) < 0) {
1576
+ $e = $e->abs();
1577
+
1578
+ $temp = $this->modInverse($n);
1579
+ if ($temp === false) {
1580
+ return false;
1581
+ }
1582
+
1583
+ return $this->_normalize($temp->modPow($e, $n));
1584
+ }
1585
+
1586
+ switch ( MATH_BIGINTEGER_MODE ) {
1587
+ case MATH_BIGINTEGER_MODE_GMP:
1588
+ $temp = new Math_BigInteger();
1589
+ $temp->value = gmp_powm($this->value, $e->value, $n->value);
1590
+
1591
+ return $this->_normalize($temp);
1592
+ case MATH_BIGINTEGER_MODE_BCMATH:
1593
+ $temp = new Math_BigInteger();
1594
+ $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1595
+
1596
+ return $this->_normalize($temp);
1597
+ }
1598
+
1599
+ if ( empty($e->value) ) {
1600
+ $temp = new Math_BigInteger();
1601
+ $temp->value = array(1);
1602
+ return $this->_normalize($temp);
1603
+ }
1604
+
1605
+ if ( $e->value == array(1) ) {
1606
+ list(, $temp) = $this->divide($n);
1607
+ return $this->_normalize($temp);
1608
+ }
1609
+
1610
+ if ( $e->value == array(2) ) {
1611
+ $temp = new Math_BigInteger();
1612
+ $temp->value = $this->_square($this->value);
1613
+ list(, $temp) = $temp->divide($n);
1614
+ return $this->_normalize($temp);
1615
+ }
1616
+
1617
+ return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
1618
+
1619
+ // is the modulo odd?
1620
+ if ( $n->value[0] & 1 ) {
1621
+ return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
1622
+ }
1623
+ // if it's not, it's even
1624
+
1625
+ // find the lowest set bit (eg. the max pow of 2 that divides $n)
1626
+ for ($i = 0; $i < count($n->value); ++$i) {
1627
+ if ( $n->value[$i] ) {
1628
+ $temp = decbin($n->value[$i]);
1629
+ $j = strlen($temp) - strrpos($temp, '1') - 1;
1630
+ $j+= 26 * $i;
1631
+ break;
1632
+ }
1633
+ }
1634
+ // at this point, 2^$j * $n/(2^$j) == $n
1635
+
1636
+ $mod1 = $n->copy();
1637
+ $mod1->_rshift($j);
1638
+ $mod2 = new Math_BigInteger();
1639
+ $mod2->value = array(1);
1640
+ $mod2->_lshift($j);
1641
+
1642
+ $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
1643
+ $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
1644
+
1645
+ $y1 = $mod2->modInverse($mod1);
1646
+ $y2 = $mod1->modInverse($mod2);
1647
+
1648
+ $result = $part1->multiply($mod2);
1649
+ $result = $result->multiply($y1);
1650
+
1651
+ $temp = $part2->multiply($mod1);
1652
+ $temp = $temp->multiply($y2);
1653
+
1654
+ $result = $result->add($temp);
1655
+ list(, $result) = $result->divide($n);
1656
+
1657
+ return $this->_normalize($result);
1658
+ }
1659
+
1660
+ /**
1661
+ * Performs modular exponentiation.
1662
+ *
1663
+ * Alias for Math_BigInteger::modPow()
1664
+ *
1665
+ * @param Math_BigInteger $e
1666
+ * @param Math_BigInteger $n
1667
+ * @return Math_BigInteger
1668
+ * @access public
1669
+ */
1670
+ function powMod($e, $n)
1671
+ {
1672
+ return $this->modPow($e, $n);
1673
+ }
1674
+
1675
+ /**
1676
+ * Sliding Window k-ary Modular Exponentiation
1677
+ *
1678
+ * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1679
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
1680
+ * however, this function performs a modular reduction after every multiplication and squaring operation.
1681
+ * As such, this function has the same preconditions that the reductions being used do.
1682
+ *
1683
+ * @param Math_BigInteger $e
1684
+ * @param Math_BigInteger $n
1685
+ * @param Integer $mode
1686
+ * @return Math_BigInteger
1687
+ * @access private
1688
+ */
1689
+ function _slidingWindow($e, $n, $mode)
1690
+ {
1691
+ static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1692
+ //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1693
+
1694
+ $e_value = $e->value;
1695
+ $e_length = count($e_value) - 1;
1696
+ $e_bits = decbin($e_value[$e_length]);
1697
+ for ($i = $e_length - 1; $i >= 0; --$i) {
1698
+ $e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT);
1699
+ }
1700
+
1701
+ $e_length = strlen($e_bits);
1702
+
1703
+ // calculate the appropriate window size.
1704
+ // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1705
+ for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
1706
+
1707
+ $n_value = $n->value;
1708
+
1709
+ // precompute $this^0 through $this^$window_size
1710
+ $powers = array();
1711
+ $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1712
+ $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1713
+
1714
+ // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1715
+ // in a 1. ie. it's supposed to be odd.
1716
+ $temp = 1 << ($window_size - 1);
1717
+ for ($i = 1; $i < $temp; ++$i) {
1718
+ $i2 = $i << 1;
1719
+ $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1720
+ }
1721
+
1722
+ $result = array(1);
1723
+ $result = $this->_prepareReduce($result, $n_value, $mode);
1724
+
1725
+ for ($i = 0; $i < $e_length; ) {
1726
+ if ( !$e_bits[$i] ) {
1727
+ $result = $this->_squareReduce($result, $n_value, $mode);
1728
+ ++$i;
1729
+ } else {
1730
+ for ($j = $window_size - 1; $j > 0; --$j) {
1731
+ if ( !empty($e_bits[$i + $j]) ) {
1732
+ break;
1733
+ }
1734
+ }
1735
+
1736
+ for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
1737
+ $result = $this->_squareReduce($result, $n_value, $mode);
1738
+ }
1739
+
1740
+ $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1741
+
1742
+ $i+=$j + 1;
1743
+ }
1744
+ }
1745
+
1746
+ $temp = new Math_BigInteger();
1747
+ $temp->value = $this->_reduce($result, $n_value, $mode);
1748
+
1749
+ return $temp;
1750
+ }
1751
+
1752
+ /**
1753
+ * Modular reduction
1754
+ *
1755
+ * For most $modes this will return the remainder.
1756
+ *
1757
+ * @see _slidingWindow()
1758
+ * @access private
1759
+ * @param Array $x
1760
+ * @param Array $n
1761
+ * @param Integer $mode
1762
+ * @return Array
1763
+ */
1764
+ function _reduce($x, $n, $mode)
1765
+ {
1766
+ switch ($mode) {
1767
+ case MATH_BIGINTEGER_MONTGOMERY:
1768
+ return $this->_montgomery($x, $n);
1769
+ case MATH_BIGINTEGER_BARRETT:
1770
+ return $this->_barrett($x, $n);
1771
+ case MATH_BIGINTEGER_POWEROF2:
1772
+ $lhs = new Math_BigInteger();
1773
+ $lhs->value = $x;
1774
+ $rhs = new Math_BigInteger();
1775
+ $rhs->value = $n;
1776
+ return $x->_mod2($n);
1777
+ case MATH_BIGINTEGER_CLASSIC:
1778
+ $lhs = new Math_BigInteger();
1779
+ $lhs->value = $x;
1780
+ $rhs = new Math_BigInteger();
1781
+ $rhs->value = $n;
1782
+ list(, $temp) = $lhs->divide($rhs);
1783
+ return $temp->value;
1784
+ case MATH_BIGINTEGER_NONE:
1785
+ return $x;
1786
+ default:
1787
+ // an invalid $mode was provided
1788
+ }
1789
+ }
1790
+
1791
+ /**
1792
+ * Modular reduction preperation
1793
+ *
1794
+ * @see _slidingWindow()
1795
+ * @access private
1796
+ * @param Array $x
1797
+ * @param Array $n
1798
+ * @param Integer $mode
1799
+ * @return Array
1800
+ */
1801
+ function _prepareReduce($x, $n, $mode)
1802
+ {
1803
+ if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1804
+ return $this->_prepMontgomery($x, $n);
1805
+ }
1806
+ return $this->_reduce($x, $n, $mode);
1807
+ }
1808
+
1809
+ /**
1810
+ * Modular multiply
1811
+ *
1812
+ * @see _slidingWindow()
1813
+ * @access private
1814
+ * @param Array $x
1815
+ * @param Array $y
1816
+ * @param Array $n
1817
+ * @param Integer $mode
1818
+ * @return Array
1819
+ */
1820
+ function _multiplyReduce($x, $y, $n, $mode)
1821
+ {
1822
+ if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1823
+ return $this->_montgomeryMultiply($x, $y, $n);
1824
+ }
1825
+ $temp = $this->_multiply($x, false, $y, false);
1826
+ return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
1827
+ }
1828
+
1829
+ /**
1830
+ * Modular square
1831
+ *
1832
+ * @see _slidingWindow()
1833
+ * @access private
1834
+ * @param Array $x
1835
+ * @param Array $n
1836
+ * @param Integer $mode
1837
+ * @return Array
1838
+ */
1839
+ function _squareReduce($x, $n, $mode)
1840
+ {
1841
+ if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1842
+ return $this->_montgomeryMultiply($x, $x, $n);
1843
+ }
1844
+ return $this->_reduce($this->_square($x), $n, $mode);
1845
+ }
1846
+
1847
+ /**
1848
+ * Modulos for Powers of Two
1849
+ *
1850
+ * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
1851
+ * we'll just use this function as a wrapper for doing that.
1852
+ *
1853
+ * @see _slidingWindow()
1854
+ * @access private
1855
+ * @param Math_BigInteger
1856
+ * @return Math_BigInteger
1857
+ */
1858
+ function _mod2($n)
1859
+ {
1860
+ $temp = new Math_BigInteger();
1861
+ $temp->value = array(1);
1862
+ return $this->bitwise_and($n->subtract($temp));
1863
+ }
1864
+
1865
+ /**
1866
+ * Barrett Modular Reduction
1867
+ *
1868
+ * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
1869
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
1870
+ * so as not to require negative numbers (initially, this script didn't support negative numbers).
1871
+ *
1872
+ * Employs "folding", as described at
1873
+ * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
1874
+ * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
1875
+ *
1876
+ * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
1877
+ * usable on account of (1) its not using reasonable radix points as discussed in
1878
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
1879
+ * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
1880
+ * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
1881
+ * comments for details.
1882
+ *
1883
+ * @see _slidingWindow()
1884
+ * @access private
1885
+ * @param Array $n
1886
+ * @param Array $m
1887
+ * @return Array
1888
+ */
1889
+ function _barrett($n, $m)
1890
+ {
1891
+ static $cache = array(
1892
+ MATH_BIGINTEGER_VARIABLE => array(),
1893
+ MATH_BIGINTEGER_DATA => array()
1894
+ );
1895
+
1896
+ $m_length = count($m);
1897
+
1898
+ // if ($this->_compare($n, $this->_square($m)) >= 0) {
1899
+ if (count($n) > 2 * $m_length) {
1900
+ $lhs = new Math_BigInteger();
1901
+ $rhs = new Math_BigInteger();
1902
+ $lhs->value = $n;
1903
+ $rhs->value = $m;
1904
+ list(, $temp) = $lhs->divide($rhs);
1905
+ return $temp->value;
1906
+ }
1907
+
1908
+ // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
1909
+ if ($m_length < 5) {
1910
+ return $this->_regularBarrett($n, $m);
1911
+ }
1912
+
1913
+ // n = 2 * m.length
1914
+
1915
+ if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
1916
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
1917
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
1918
+
1919
+ $lhs = new Math_BigInteger();
1920
+ $lhs_value = &$lhs->value;
1921
+ $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
1922
+ $lhs_value[] = 1;
1923
+ $rhs = new Math_BigInteger();
1924
+ $rhs->value = $m;
1925
+
1926
+ list($u, $m1) = $lhs->divide($rhs);
1927
+ $u = $u->value;
1928
+ $m1 = $m1->value;
1929
+
1930
+ $cache[MATH_BIGINTEGER_DATA][] = array(
1931
+ 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
1932
+ 'm1'=> $m1 // m.length
1933
+ );
1934
+ } else {
1935
+ extract($cache[MATH_BIGINTEGER_DATA][$key]);
1936
+ }
1937
+
1938
+ $cutoff = $m_length + ($m_length >> 1);
1939
+ $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
1940
+ $msd = array_slice($n, $cutoff); // m.length >> 1
1941
+ $lsd = $this->_trim($lsd);
1942
+ $temp = $this->_multiply($msd, false, $m1, false);
1943
+ $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
1944
+
1945
+ if ($m_length & 1) {
1946
+ return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
1947
+ }
1948
+
1949
+ // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
1950
+ $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
1951
+ // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
1952
+ // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
1953
+ $temp = $this->_multiply($temp, false, $u, false);
1954
+ // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
1955
+ // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
1956
+ $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
1957
+ // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
1958
+ // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
1959
+ $temp = $this->_multiply($temp, false, $m, false);
1960
+
1961
+ // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
1962
+ // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
1963
+ // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
1964
+
1965
+ $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
1966
+
1967
+ while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
1968
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
1969
+ }
1970
+
1971
+ return $result[MATH_BIGINTEGER_VALUE];
1972
+ }
1973
+
1974
+ /**
1975
+ * (Regular) Barrett Modular Reduction
1976
+ *
1977
+ * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this
1978
+ * is that this function does not fold the denominator into a smaller form.
1979
+ *
1980
+ * @see _slidingWindow()
1981
+ * @access private
1982
+ * @param Array $x
1983
+ * @param Array $n
1984
+ * @return Array
1985
+ */
1986
+ function _regularBarrett($x, $n)
1987
+ {
1988
+ static $cache = array(
1989
+ MATH_BIGINTEGER_VARIABLE => array(),
1990
+ MATH_BIGINTEGER_DATA => array()
1991
+ );
1992
+
1993
+ $n_length = count($n);
1994
+
1995
+ if (count($x) > 2 * $n_length) {
1996
+ $lhs = new Math_BigInteger();
1997
+ $rhs = new Math_BigInteger();
1998
+ $lhs->value = $x;
1999
+ $rhs->value = $n;
2000
+ list(, $temp) = $lhs->divide($rhs);
2001
+ return $temp->value;
2002
+ }
2003
+
2004
+ if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2005
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2006
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
2007
+ $lhs = new Math_BigInteger();
2008
+ $lhs_value = &$lhs->value;
2009
+ $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2010
+ $lhs_value[] = 1;
2011
+ $rhs = new Math_BigInteger();
2012
+ $rhs->value = $n;
2013
+ list($temp, ) = $lhs->divide($rhs); // m.length
2014
+ $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
2015
+ }
2016
+
2017
+ // 2 * m.length - (m.length - 1) = m.length + 1
2018
+ $temp = array_slice($x, $n_length - 1);
2019
+ // (m.length + 1) + m.length = 2 * m.length + 1
2020
+ $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
2021
+ // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2022
+ $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
2023
+
2024
+ // m.length + 1
2025
+ $result = array_slice($x, 0, $n_length + 1);
2026
+ // m.length + 1
2027
+ $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2028
+ // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2029
+
2030
+ if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
2031
+ $corrector_value = $this->_array_repeat(0, $n_length + 1);
2032
+ $corrector_value[] = 1;
2033
+ $result = $this->_add($result, false, $corrector, false);
2034
+ $result = $result[MATH_BIGINTEGER_VALUE];
2035
+ }
2036
+
2037
+ // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2038
+ $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
2039
+ while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
2040
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
2041
+ }
2042
+
2043
+ return $result[MATH_BIGINTEGER_VALUE];
2044
+ }
2045
+
2046
+ /**
2047
+ * Performs long multiplication up to $stop digits
2048
+ *
2049
+ * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2050
+ *
2051
+ * @see _regularBarrett()
2052
+ * @param Array $x_value
2053
+ * @param Boolean $x_negative
2054
+ * @param Array $y_value
2055
+ * @param Boolean $y_negative
2056
+ * @return Array
2057
+ * @access private
2058
+ */
2059
+ function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2060
+ {
2061
+ $x_length = count($x_value);
2062
+ $y_length = count($y_value);
2063
+
2064
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
2065
+ return array(
2066
+ MATH_BIGINTEGER_VALUE => array(),
2067
+ MATH_BIGINTEGER_SIGN => false
2068
+ );
2069
+ }
2070
+
2071
+ if ( $x_length < $y_length ) {
2072
+ $temp = $x_value;
2073
+ $x_value = $y_value;
2074
+ $y_value = $temp;
2075
+
2076
+ $x_length = count($x_value);
2077
+ $y_length = count($y_value);
2078
+ }
2079
+
2080
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
2081
+
2082
+ // the following for loop could be removed if the for loop following it
2083
+ // (the one with nested for loops) initially set $i to 0, but
2084
+ // doing so would also make the result in one set of unnecessary adds,
2085
+ // since on the outermost loops first pass, $product->value[$k] is going
2086
+ // to always be 0
2087
+
2088
+ $carry = 0;
2089
+
2090
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2091
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2092
+ $carry = (int) ($temp / 0x4000000);
2093
+ $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
2094
+ }
2095
+
2096
+ if ($j < $stop) {
2097
+ $product_value[$j] = $carry;
2098
+ }
2099
+
2100
+ // the above for loop is what the previous comment was talking about. the
2101
+ // following for loop is the "one with nested for loops"
2102
+
2103
+ for ($i = 1; $i < $y_length; ++$i) {
2104
+ $carry = 0;
2105
+
2106
+ for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2107
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2108
+ $carry = (int) ($temp / 0x4000000);
2109
+ $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
2110
+ }
2111
+
2112
+ if ($k < $stop) {
2113
+ $product_value[$k] = $carry;
2114
+ }
2115
+ }
2116
+
2117
+ return array(
2118
+ MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
2119
+ MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
2120
+ );
2121
+ }
2122
+
2123
+ /**
2124
+ * Montgomery Modular Reduction
2125
+ *
2126
+ * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2127
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2128
+ * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
2129
+ * to work correctly.
2130
+ *
2131
+ * @see _prepMontgomery()
2132
+ * @see _slidingWindow()
2133
+ * @access private
2134
+ * @param Array $x
2135
+ * @param Array $n
2136
+ * @return Array
2137
+ */
2138
+ function _montgomery($x, $n)
2139
+ {
2140
+ static $cache = array(
2141
+ MATH_BIGINTEGER_VARIABLE => array(),
2142
+ MATH_BIGINTEGER_DATA => array()
2143
+ );
2144
+
2145
+ if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2146
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2147
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
2148
+ $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
2149
+ }
2150
+
2151
+ $k = count($n);
2152
+
2153
+ $result = array(MATH_BIGINTEGER_VALUE => $x);
2154
+
2155
+ for ($i = 0; $i < $k; ++$i) {
2156
+ $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
2157
+ $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
2158
+ $temp = $this->_regularMultiply(array($temp), $n);
2159
+ $temp = array_merge($this->_array_repeat(0, $i), $temp);
2160
+ $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
2161
+ }
2162
+
2163
+ $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
2164
+
2165
+ if ($this->_compare($result, false, $n, false) >= 0) {
2166
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
2167
+ }
2168
+
2169
+ return $result[MATH_BIGINTEGER_VALUE];
2170
+ }
2171
+
2172
+ /**
2173
+ * Montgomery Multiply
2174
+ *
2175
+ * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2176
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2177
+ *
2178
+ * @see _prepMontgomery()
2179
+ * @see _montgomery()
2180
+ * @access private
2181
+ * @param Array $x
2182
+ * @param Array $y
2183
+ * @param Array $m
2184
+ * @return Array
2185
+ */
2186
+ function _montgomeryMultiply($x, $y, $m)
2187
+ {
2188
+ $temp = $this->_multiply($x, false, $y, false);
2189
+ return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
2190
+
2191
+ static $cache = array(
2192
+ MATH_BIGINTEGER_VARIABLE => array(),
2193
+ MATH_BIGINTEGER_DATA => array()
2194
+ );
2195
+
2196
+ if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2197
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2198
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2199
+ $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
2200
+ }
2201
+
2202
+ $n = max(count($x), count($y), count($m));
2203
+ $x = array_pad($x, $n, 0);
2204
+ $y = array_pad($y, $n, 0);
2205
+ $m = array_pad($m, $n, 0);
2206
+ $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
2207
+ for ($i = 0; $i < $n; ++$i) {
2208
+ $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
2209
+ $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
2210
+ $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
2211
+ $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
2212
+ $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2213
+ $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2214
+ $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
2215
+ }
2216
+ if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
2217
+ $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
2218
+ }
2219
+ return $a[MATH_BIGINTEGER_VALUE];
2220
+ }
2221
+
2222
+ /**
2223
+ * Prepare a number for use in Montgomery Modular Reductions
2224
+ *
2225
+ * @see _montgomery()
2226
+ * @see _slidingWindow()
2227
+ * @access private
2228
+ * @param Array $x
2229
+ * @param Array $n
2230
+ * @return Array
2231
+ */
2232
+ function _prepMontgomery($x, $n)
2233
+ {
2234
+ $lhs = new Math_BigInteger();
2235
+ $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2236
+ $rhs = new Math_BigInteger();
2237
+ $rhs->value = $n;
2238
+
2239
+ list(, $temp) = $lhs->divide($rhs);
2240
+ return $temp->value;
2241
+ }
2242
+
2243
+ /**
2244
+ * Modular Inverse of a number mod 2**26 (eg. 67108864)
2245
+ *
2246
+ * Based off of the bnpInvDigit function implemented and justified in the following URL:
2247
+ *
2248
+ * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2249
+ *
2250
+ * The following URL provides more info:
2251
+ *
2252
+ * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2253
+ *
2254
+ * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
2255
+ * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2256
+ * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2257
+ * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
2258
+ * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
2259
+ * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
2260
+ * 40 bits, which only 64-bit floating points will support.
2261
+ *
2262
+ * Thanks to Pedro Gimeno Fortea for input!
2263
+ *
2264
+ * @see _montgomery()
2265
+ * @access private
2266
+ * @param Array $x
2267
+ * @return Integer
2268
+ */
2269
+ function _modInverse67108864($x) // 2**26 == 67108864
2270
+ {
2271
+ $x = -$x[0];
2272
+ $result = $x & 0x3; // x**-1 mod 2**2
2273
+ $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2274
+ $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
2275
+ $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2276
+ $result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26
2277
+ return $result & 0x3FFFFFF;
2278
+ }
2279
+
2280
+ /**
2281
+ * Calculates modular inverses.
2282
+ *
2283
+ * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
2284
+ *
2285
+ * Here's an example:
2286
+ * <code>
2287
+ * <?php
2288
+ * include('Math/BigInteger.php');
2289
+ *
2290
+ * $a = new Math_BigInteger(30);
2291
+ * $b = new Math_BigInteger(17);
2292
+ *
2293
+ * $c = $a->modInverse($b);
2294
+ * echo $c->toString(); // outputs 4
2295
+ *
2296
+ * echo "\r\n";
2297
+ *
2298
+ * $d = $a->multiply($c);
2299
+ * list(, $d) = $d->divide($b);
2300
+ * echo $d; // outputs 1 (as per the definition of modular inverse)
2301
+ * ?>
2302
+ * </code>
2303
+ *
2304
+ * @param Math_BigInteger $n
2305
+ * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
2306
+ * @access public
2307
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2308
+ */
2309
+ function modInverse($n)
2310
+ {
2311
+ switch ( MATH_BIGINTEGER_MODE ) {
2312
+ case MATH_BIGINTEGER_MODE_GMP:
2313
+ $temp = new Math_BigInteger();
2314
+ $temp->value = gmp_invert($this->value, $n->value);
2315
+
2316
+ return ( $temp->value === false ) ? false : $this->_normalize($temp);
2317
+ }
2318
+
2319
+ static $zero, $one;
2320
+ if (!isset($zero)) {
2321
+ $zero = new Math_BigInteger();
2322
+ $one = new Math_BigInteger(1);
2323
+ }
2324
+
2325
+ // $x mod $n == $x mod -$n.
2326
+ $n = $n->abs();
2327
+
2328
+ if ($this->compare($zero) < 0) {
2329
+ $temp = $this->abs();
2330
+ $temp = $temp->modInverse($n);
2331
+ return $negated === false ? false : $this->_normalize($n->subtract($temp));
2332
+ }
2333
+
2334
+ extract($this->extendedGCD($n));
2335
+
2336
+ if (!$gcd->equals($one)) {
2337
+ return false;
2338
+ }
2339
+
2340
+ $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2341
+
2342
+ return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2343
+ }
2344
+
2345
+ /**
2346
+ * Calculates the greatest common divisor and B�zout's identity.
2347
+ *
2348
+ * Say you have 693 and 609. The GCD is 21. B�zout's identity states that there exist integers x and y such that
2349
+ * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
2350
+ * combination is returned is dependant upon which mode is in use. See
2351
+ * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity B�zout's identity - Wikipedia} for more information.
2352
+ *
2353
+ * Here's an example:
2354
+ * <code>
2355
+ * <?php
2356
+ * include('Math/BigInteger.php');
2357
+ *
2358
+ * $a = new Math_BigInteger(693);
2359
+ * $b = new Math_BigInteger(609);
2360
+ *
2361
+ * extract($a->extendedGCD($b));
2362
+ *
2363
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2364
+ * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2365
+ * ?>
2366
+ * </code>
2367
+ *
2368
+ * @param Math_BigInteger $n
2369
+ * @return Math_BigInteger
2370
+ * @access public
2371
+ * @internal Calculates the GCD using the binary xGCD algorithim described in
2372
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
2373
+ * the more traditional algorithim requires "relatively costly multiple-precision divisions".
2374
+ */
2375
+ function extendedGCD($n)
2376
+ {
2377
+ switch ( MATH_BIGINTEGER_MODE ) {
2378
+ case MATH_BIGINTEGER_MODE_GMP:
2379
+ extract(gmp_gcdext($this->value, $n->value));
2380
+
2381
+ return array(
2382
+ 'gcd' => $this->_normalize(new Math_BigInteger($g)),
2383
+ 'x' => $this->_normalize(new Math_BigInteger($s)),
2384
+ 'y' => $this->_normalize(new Math_BigInteger($t))
2385
+ );
2386
+ case MATH_BIGINTEGER_MODE_BCMATH:
2387
+ // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2388
+ // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
2389
+ // the basic extended euclidean algorithim is what we're using.
2390
+
2391
+ $u = $this->value;
2392
+ $v = $n->value;
2393
+
2394
+ $a = '1';
2395
+ $b = '0';
2396
+ $c = '0';
2397
+ $d = '1';
2398
+
2399
+ while (bccomp($v, '0', 0) != 0) {
2400
+ $q = bcdiv($u, $v, 0);
2401
+
2402
+ $temp = $u;
2403
+ $u = $v;
2404
+ $v = bcsub($temp, bcmul($v, $q, 0), 0);
2405
+
2406
+ $temp = $a;
2407
+ $a = $c;
2408
+ $c = bcsub($temp, bcmul($a, $q, 0), 0);
2409
+
2410
+ $temp = $b;
2411
+ $b = $d;
2412
+ $d = bcsub($temp, bcmul($b, $q, 0), 0);
2413
+ }
2414
+
2415
+ return array(
2416
+ 'gcd' => $this->_normalize(new Math_BigInteger($u)),
2417
+ 'x' => $this->_normalize(new Math_BigInteger($a)),
2418
+ 'y' => $this->_normalize(new Math_BigInteger($b))
2419
+ );
2420
+ }
2421
+
2422
+ $y = $n->copy();
2423
+ $x = $this->copy();
2424
+ $g = new Math_BigInteger();
2425
+ $g->value = array(1);
2426
+
2427
+ while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
2428
+ $x->_rshift(1);
2429
+ $y->_rshift(1);
2430
+ $g->_lshift(1);
2431
+ }
2432
+
2433
+ $u = $x->copy();
2434
+ $v = $y->copy();
2435
+
2436
+ $a = new Math_BigInteger();
2437
+ $b = new Math_BigInteger();
2438
+ $c = new Math_BigInteger();
2439
+ $d = new Math_BigInteger();
2440
+
2441
+ $a->value = $d->value = $g->value = array(1);
2442
+ $b->value = $c->value = array();
2443
+
2444
+ while ( !empty($u->value) ) {
2445
+ while ( !($u->value[0] & 1) ) {
2446
+ $u->_rshift(1);
2447
+ if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
2448
+ $a = $a->add($y);
2449
+ $b = $b->subtract($x);
2450
+ }
2451
+ $a->_rshift(1);
2452
+ $b->_rshift(1);
2453
+ }
2454
+
2455
+ while ( !($v->value[0] & 1) ) {
2456
+ $v->_rshift(1);
2457
+ if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
2458
+ $c = $c->add($y);
2459
+ $d = $d->subtract($x);
2460
+ }
2461
+ $c->_rshift(1);
2462
+ $d->_rshift(1);
2463
+ }
2464
+
2465
+ if ($u->compare($v) >= 0) {
2466
+ $u = $u->subtract($v);
2467
+ $a = $a->subtract($c);
2468
+ $b = $b->subtract($d);
2469
+ } else {
2470
+ $v = $v->subtract($u);
2471
+ $c = $c->subtract($a);
2472
+ $d = $d->subtract($b);
2473
+ }
2474
+ }
2475
+
2476
+ return array(
2477
+ 'gcd' => $this->_normalize($g->multiply($v)),
2478
+ 'x' => $this->_normalize($c),
2479
+ 'y' => $this->_normalize($d)
2480
+ );
2481
+ }
2482
+
2483
+ /**
2484
+ * Calculates the greatest common divisor
2485
+ *
2486
+ * Say you have 693 and 609. The GCD is 21.
2487
+ *
2488
+ * Here's an example:
2489
+ * <code>
2490
+ * <?php
2491
+ * include('Math/BigInteger.php');
2492
+ *
2493
+ * $a = new Math_BigInteger(693);
2494
+ * $b = new Math_BigInteger(609);
2495
+ *
2496
+ * $gcd = a->extendedGCD($b);
2497
+ *
2498
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2499
+ * ?>
2500
+ * </code>
2501
+ *
2502
+ * @param Math_BigInteger $n
2503
+ * @return Math_BigInteger
2504
+ * @access public
2505
+ */
2506
+ function gcd($n)
2507
+ {
2508
+ extract($this->extendedGCD($n));
2509
+ return $gcd;
2510
+ }
2511
+
2512
+ /**
2513
+ * Absolute value.
2514
+ *
2515
+ * @return Math_BigInteger
2516
+ * @access public
2517
+ */
2518
+ function abs()
2519
+ {
2520
+ $temp = new Math_BigInteger();
2521
+
2522
+ switch ( MATH_BIGINTEGER_MODE ) {
2523
+ case MATH_BIGINTEGER_MODE_GMP:
2524
+ $temp->value = gmp_abs($this->value);
2525
+ break;
2526
+ case MATH_BIGINTEGER_MODE_BCMATH:
2527
+ $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2528
+ break;
2529
+ default:
2530
+ $temp->value = $this->value;
2531
+ }
2532
+
2533
+ return $temp;
2534
+ }
2535
+
2536
+ /**
2537
+ * Compares two numbers.
2538
+ *
2539
+ * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
2540
+ * demonstrated thusly:
2541
+ *
2542
+ * $x > $y: $x->compare($y) > 0
2543
+ * $x < $y: $x->compare($y) < 0
2544
+ * $x == $y: $x->compare($y) == 0
2545
+ *
2546
+ * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
2547
+ *
2548
+ * @param Math_BigInteger $x
2549
+ * @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal.
2550
+ * @access public
2551
+ * @see equals()
2552
+ * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2553
+ */
2554
+ function compare($y)
2555
+ {
2556
+ switch ( MATH_BIGINTEGER_MODE ) {
2557
+ case MATH_BIGINTEGER_MODE_GMP:
2558
+ return gmp_cmp($this->value, $y->value);
2559
+ case MATH_BIGINTEGER_MODE_BCMATH:
2560
+ return bccomp($this->value, $y->value, 0);
2561
+ }
2562
+
2563
+ return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2564
+ }
2565
+
2566
+ /**
2567
+ * Compares two numbers.
2568
+ *
2569
+ * @param Array $x_value
2570
+ * @param Boolean $x_negative
2571
+ * @param Array $y_value
2572
+ * @param Boolean $y_negative
2573
+ * @return Integer
2574
+ * @see compare()
2575
+ * @access private
2576
+ */
2577
+ function _compare($x_value, $x_negative, $y_value, $y_negative)
2578
+ {
2579
+ if ( $x_negative != $y_negative ) {
2580
+ return ( !$x_negative && $y_negative ) ? 1 : -1;
2581
+ }
2582
+
2583
+ $result = $x_negative ? -1 : 1;
2584
+
2585
+ if ( count($x_value) != count($y_value) ) {
2586
+ return ( count($x_value) > count($y_value) ) ? $result : -$result;
2587
+ }
2588
+ $size = max(count($x_value), count($y_value));
2589
+
2590
+ $x_value = array_pad($x_value, $size, 0);
2591
+ $y_value = array_pad($y_value, $size, 0);
2592
+
2593
+ for ($i = count($x_value) - 1; $i >= 0; --$i) {
2594
+ if ($x_value[$i] != $y_value[$i]) {
2595
+ return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
2596
+ }
2597
+ }
2598
+
2599
+ return 0;
2600
+ }
2601
+
2602
+ /**
2603
+ * Tests the equality of two numbers.
2604
+ *
2605
+ * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
2606
+ *
2607
+ * @param Math_BigInteger $x
2608
+ * @return Boolean
2609
+ * @access public
2610
+ * @see compare()
2611
+ */
2612
+ function equals($x)
2613
+ {
2614
+ switch ( MATH_BIGINTEGER_MODE ) {
2615
+ case MATH_BIGINTEGER_MODE_GMP:
2616
+ return gmp_cmp($this->value, $x->value) == 0;
2617
+ default:
2618
+ return $this->value === $x->value && $this->is_negative == $x->is_negative;
2619
+ }
2620
+ }
2621
+
2622
+ /**
2623
+ * Set Precision
2624
+ *
2625
+ * Some bitwise operations give different results depending on the precision being used. Examples include left
2626
+ * shift, not, and rotates.
2627
+ *
2628
+ * @param Math_BigInteger $x
2629
+ * @access public
2630
+ * @return Math_BigInteger
2631
+ */
2632
+ function setPrecision($bits)
2633
+ {
2634
+ $this->precision = $bits;
2635
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
2636
+ $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2637
+ } else {
2638
+ $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
2639
+ }
2640
+
2641
+ $temp = $this->_normalize($this);
2642
+ $this->value = $temp->value;
2643
+ }
2644
+
2645
+ /**
2646
+ * Logical And
2647
+ *
2648
+ * @param Math_BigInteger $x
2649
+ * @access public
2650
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2651
+ * @return Math_BigInteger
2652
+ */
2653
+ function bitwise_and($x)
2654
+ {
2655
+ switch ( MATH_BIGINTEGER_MODE ) {
2656
+ case MATH_BIGINTEGER_MODE_GMP:
2657
+ $temp = new Math_BigInteger();
2658
+ $temp->value = gmp_and($this->value, $x->value);
2659
+
2660
+ return $this->_normalize($temp);
2661
+ case MATH_BIGINTEGER_MODE_BCMATH:
2662
+ $left = $this->toBytes();
2663
+ $right = $x->toBytes();
2664
+
2665
+ $length = max(strlen($left), strlen($right));
2666
+
2667
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2668
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2669
+
2670
+ return $this->_normalize(new Math_BigInteger($left & $right, 256));
2671
+ }
2672
+
2673
+ $result = $this->copy();
2674
+
2675
+ $length = min(count($x->value), count($this->value));
2676
+
2677
+ $result->value = array_slice($result->value, 0, $length);
2678
+
2679
+ for ($i = 0; $i < $length; ++$i) {
2680
+ $result->value[$i] = $result->value[$i] & $x->value[$i];
2681
+ }
2682
+
2683
+ return $this->_normalize($result);
2684
+ }
2685
+
2686
+ /**
2687
+ * Logical Or
2688
+ *
2689
+ * @param Math_BigInteger $x
2690
+ * @access public
2691
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2692
+ * @return Math_BigInteger
2693
+ */
2694
+ function bitwise_or($x)
2695
+ {
2696
+ switch ( MATH_BIGINTEGER_MODE ) {
2697
+ case MATH_BIGINTEGER_MODE_GMP:
2698
+ $temp = new Math_BigInteger();
2699
+ $temp->value = gmp_or($this->value, $x->value);
2700
+
2701
+ return $this->_normalize($temp);
2702
+ case MATH_BIGINTEGER_MODE_BCMATH:
2703
+ $left = $this->toBytes();
2704
+ $right = $x->toBytes();
2705
+
2706
+ $length = max(strlen($left), strlen($right));
2707
+
2708
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2709
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2710
+
2711
+ return $this->_normalize(new Math_BigInteger($left | $right, 256));
2712
+ }
2713
+
2714
+ $length = max(count($this->value), count($x->value));
2715
+ $result = $this->copy();
2716
+ $result->value = array_pad($result->value, 0, $length);
2717
+ $x->value = array_pad($x->value, 0, $length);
2718
+
2719
+ for ($i = 0; $i < $length; ++$i) {
2720
+ $result->value[$i] = $this->value[$i] | $x->value[$i];
2721
+ }
2722
+
2723
+ return $this->_normalize($result);
2724
+ }
2725
+
2726
+ /**
2727
+ * Logical Exclusive-Or
2728
+ *
2729
+ * @param Math_BigInteger $x
2730
+ * @access public
2731
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2732
+ * @return Math_BigInteger
2733
+ */
2734
+ function bitwise_xor($x)
2735
+ {
2736
+ switch ( MATH_BIGINTEGER_MODE ) {
2737
+ case MATH_BIGINTEGER_MODE_GMP:
2738
+ $temp = new Math_BigInteger();
2739
+ $temp->value = gmp_xor($this->value, $x->value);
2740
+
2741
+ return $this->_normalize($temp);
2742
+ case MATH_BIGINTEGER_MODE_BCMATH:
2743
+ $left = $this->toBytes();
2744
+ $right = $x->toBytes();
2745
+
2746
+ $length = max(strlen($left), strlen($right));
2747
+
2748
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2749
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2750
+
2751
+ return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
2752
+ }
2753
+
2754
+ $length = max(count($this->value), count($x->value));
2755
+ $result = $this->copy();
2756
+ $result->value = array_pad($result->value, 0, $length);
2757
+ $x->value = array_pad($x->value, 0, $length);
2758
+
2759
+ for ($i = 0; $i < $length; ++$i) {
2760
+ $result->value[$i] = $this->value[$i] ^ $x->value[$i];
2761
+ }
2762
+
2763
+ return $this->_normalize($result);
2764
+ }
2765
+
2766
+ /**
2767
+ * Logical Not
2768
+ *
2769
+ * @access public
2770
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2771
+ * @return Math_BigInteger
2772
+ */
2773
+ function bitwise_not()
2774
+ {
2775
+ // calculuate "not" without regard to $this->precision
2776
+ // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
2777
+ $temp = $this->toBytes();
2778
+ $pre_msb = decbin(ord($temp[0]));
2779
+ $temp = ~$temp;
2780
+ $msb = decbin(ord($temp[0]));
2781
+ if (strlen($msb) == 8) {
2782
+ $msb = substr($msb, strpos($msb, '0'));
2783
+ }
2784
+ $temp[0] = chr(bindec($msb));
2785
+
2786
+ // see if we need to add extra leading 1's
2787
+ $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2788
+ $new_bits = $this->precision - $current_bits;
2789
+ if ($new_bits <= 0) {
2790
+ return $this->_normalize(new Math_BigInteger($temp, 256));
2791
+ }
2792
+
2793
+ // generate as many leading 1's as we need to.
2794
+ $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2795
+ $this->_base256_lshift($leading_ones, $current_bits);
2796
+
2797
+ $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);
2798
+
2799
+ return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
2800
+ }
2801
+
2802
+ /**
2803
+ * Logical Right Shift
2804
+ *
2805
+ * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2806
+ *
2807
+ * @param Integer $shift
2808
+ * @return Math_BigInteger
2809
+ * @access public
2810
+ * @internal The only version that yields any speed increases is the internal version.
2811
+ */
2812
+ function bitwise_rightShift($shift)
2813
+ {
2814
+ $temp = new Math_BigInteger();
2815
+
2816
+ switch ( MATH_BIGINTEGER_MODE ) {
2817
+ case MATH_BIGINTEGER_MODE_GMP:
2818
+ static $two;
2819
+
2820
+ if (!isset($two)) {
2821
+ $two = gmp_init('2');
2822
+ }
2823
+
2824
+ $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2825
+
2826
+ break;
2827
+ case MATH_BIGINTEGER_MODE_BCMATH:
2828
+ $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2829
+
2830
+ break;
2831
+ default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2832
+ // and I don't want to do that...
2833
+ $temp->value = $this->value;
2834
+ $temp->_rshift($shift);
2835
+ }
2836
+
2837
+ return $this->_normalize($temp);
2838
+ }
2839
+
2840
+ /**
2841
+ * Logical Left Shift
2842
+ *
2843
+ * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2844
+ *
2845
+ * @param Integer $shift
2846
+ * @return Math_BigInteger
2847
+ * @access public
2848
+ * @internal The only version that yields any speed increases is the internal version.
2849
+ */
2850
+ function bitwise_leftShift($shift)
2851
+ {
2852
+ $temp = new Math_BigInteger();
2853
+
2854
+ switch ( MATH_BIGINTEGER_MODE ) {
2855
+ case MATH_BIGINTEGER_MODE_GMP:
2856
+ static $two;
2857
+
2858
+ if (!isset($two)) {
2859
+ $two = gmp_init('2');
2860
+ }
2861
+
2862
+ $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2863
+
2864
+ break;
2865
+ case MATH_BIGINTEGER_MODE_BCMATH:
2866
+ $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
2867
+
2868
+ break;
2869
+ default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
2870
+ // and I don't want to do that...
2871
+ $temp->value = $this->value;
2872
+ $temp->_lshift($shift);
2873
+ }
2874
+
2875
+ return $this->_normalize($temp);
2876
+ }
2877
+
2878
+ /**
2879
+ * Logical Left Rotate
2880
+ *
2881
+ * Instead of the top x bits being dropped they're appended to the shifted bit string.
2882
+ *
2883
+ * @param Integer $shift
2884
+ * @return Math_BigInteger
2885
+ * @access public
2886
+ */
2887
+ function bitwise_leftRotate($shift)
2888
+ {
2889
+ $bits = $this->toBytes();
2890
+
2891
+ if ($this->precision > 0) {
2892
+ $precision = $this->precision;
2893
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
2894
+ $mask = $this->bitmask->subtract(new Math_BigInteger(1));
2895
+ $mask = $mask->toBytes();
2896
+ } else {
2897
+ $mask = $this->bitmask->toBytes();
2898
+ }
2899
+ } else {
2900
+ $temp = ord($bits[0]);
2901
+ for ($i = 0; $temp >> $i; ++$i);
2902
+ $precision = 8 * strlen($bits) - 8 + $i;
2903
+ $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
2904
+ }
2905
+
2906
+ if ($shift < 0) {
2907
+ $shift+= $precision;
2908
+ }
2909
+ $shift%= $precision;
2910
+
2911
+ if (!$shift) {
2912
+ return $this->copy();
2913
+ }
2914
+
2915
+ $left = $this->bitwise_leftShift($shift);
2916
+ $left = $left->bitwise_and(new Math_BigInteger($mask, 256));
2917
+ $right = $this->bitwise_rightShift($precision - $shift);
2918
+ $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
2919
+ return $this->_normalize($result);
2920
+ }
2921
+
2922
+ /**
2923
+ * Logical Right Rotate
2924
+ *
2925
+ * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
2926
+ *
2927
+ * @param Integer $shift
2928
+ * @return Math_BigInteger
2929
+ * @access public
2930
+ */
2931
+ function bitwise_rightRotate($shift)
2932
+ {
2933
+ return $this->bitwise_leftRotate(-$shift);
2934
+ }
2935
+
2936
+ /**
2937
+ * Set random number generator function
2938
+ *
2939
+ * $generator should be the name of a random generating function whose first parameter is the minimum
2940
+ * value and whose second parameter is the maximum value. If this function needs to be seeded, it should
2941
+ * be seeded prior to calling Math_BigInteger::random() or Math_BigInteger::randomPrime()
2942
+ *
2943
+ * If the random generating function is not explicitly set, it'll be assumed to be mt_rand().
2944
+ *
2945
+ * @see random()
2946
+ * @see randomPrime()
2947
+ * @param optional String $generator
2948
+ * @access public
2949
+ */
2950
+ function setRandomGenerator($generator)
2951
+ {
2952
+ $this->generator = $generator;
2953
+ }
2954
+
2955
+ /**
2956
+ * Generate a random number
2957
+ *
2958
+ * @param optional Integer $min
2959
+ * @param optional Integer $max
2960
+ * @return Math_BigInteger
2961
+ * @access public
2962
+ */
2963
+ function random($min = false, $max = false)
2964
+ {
2965
+ if ($min === false) {
2966
+ $min = new Math_BigInteger(0);
2967
+ }
2968
+
2969
+ if ($max === false) {
2970
+ $max = new Math_BigInteger(0x7FFFFFFF);
2971
+ }
2972
+
2973
+ $compare = $max->compare($min);
2974
+
2975
+ if (!$compare) {
2976
+ return $this->_normalize($min);
2977
+ } else if ($compare < 0) {
2978
+ // if $min is bigger then $max, swap $min and $max
2979
+ $temp = $max;
2980
+ $max = $min;
2981
+ $min = $temp;
2982
+ }
2983
+
2984
+ $generator = $this->generator;
2985
+
2986
+ $max = $max->subtract($min);
2987
+ $max = ltrim($max->toBytes(), chr(0));
2988
+ $size = strlen($max) - 1;
2989
+ $random = '';
2990
+
2991
+ $bytes = $size & 1;
2992
+ for ($i = 0; $i < $bytes; ++$i) {
2993
+ $random.= chr($generator(0, 255));
2994
+ }
2995
+
2996
+ $blocks = $size >> 1;
2997
+ for ($i = 0; $i < $blocks; ++$i) {
2998
+ // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
2999
+ $random.= pack('n', $generator(0, 0xFFFF));
3000
+ }
3001
+
3002
+ $temp = new Math_BigInteger($random, 256);
3003
+ if ($temp->compare(new Math_BigInteger(substr($max, 1), 256)) > 0) {
3004
+ $random = chr($generator(0, ord($max[0]) - 1)) . $random;
3005
+ } else {
3006
+ $random = chr($generator(0, ord($max[0]) )) . $random;
3007
+ }
3008
+
3009
+ $random = new Math_BigInteger($random, 256);
3010
+
3011
+ return $this->_normalize($random->add($min));
3012
+ }
3013
+
3014
+ /**
3015
+ * Generate a random prime number.
3016
+ *
3017
+ * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed,
3018
+ * give up and return false.
3019
+ *
3020
+ * @param optional Integer $min
3021
+ * @param optional Integer $max
3022
+ * @param optional Integer $timeout
3023
+ * @return Math_BigInteger
3024
+ * @access public
3025
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3026
+ */
3027
+ function randomPrime($min = false, $max = false, $timeout = false)
3028
+ {
3029
+ $compare = $max->compare($min);
3030
+
3031
+ if (!$compare) {
3032
+ return $min;
3033
+ } else if ($compare < 0) {
3034
+ // if $min is bigger then $max, swap $min and $max
3035
+ $temp = $max;
3036
+ $max = $min;
3037
+ $min = $temp;
3038
+ }
3039
+
3040
+ // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3041
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
3042
+ // we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function
3043
+ // does its own checks on $max / $min when gmp_nextprime() is used. When gmp_nextprime() is not used, however,
3044
+ // the same $max / $min checks are not performed.
3045
+ if ($min === false) {
3046
+ $min = new Math_BigInteger(0);
3047
+ }
3048
+
3049
+ if ($max === false) {
3050
+ $max = new Math_BigInteger(0x7FFFFFFF);
3051
+ }
3052
+
3053
+ $x = $this->random($min, $max);
3054
+
3055
+ $x->value = gmp_nextprime($x->value);
3056
+
3057
+ if ($x->compare($max) <= 0) {
3058
+ return $x;
3059
+ }
3060
+
3061
+ $x->value = gmp_nextprime($min->value);
3062
+
3063
+ if ($x->compare($max) <= 0) {
3064
+ return $x;
3065
+ }
3066
+
3067
+ return false;
3068
+ }
3069
+
3070
+ static $one, $two;
3071
+ if (!isset($one)) {
3072
+ $one = new Math_BigInteger(1);
3073
+ $two = new Math_BigInteger(2);
3074
+ }
3075
+
3076
+ $start = time();
3077
+
3078
+ $x = $this->random($min, $max);
3079
+ if ($x->equals($two)) {
3080
+ return $x;
3081
+ }
3082
+
3083
+ $x->_make_odd();
3084
+ if ($x->compare($max) > 0) {
3085
+ // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3086
+ if ($min->equals($max)) {
3087
+ return false;
3088
+ }
3089
+ $x = $min->copy();
3090
+ $x->_make_odd();
3091
+ }
3092
+
3093
+ $initial_x = $x->copy();
3094
+
3095
+ while (true) {
3096
+ if ($timeout !== false && time() - $start > $timeout) {
3097
+ return false;
3098
+ }
3099
+
3100
+ if ($x->isPrime()) {
3101
+ return $x;
3102
+ }
3103
+
3104
+ $x = $x->add($two);
3105
+
3106
+ if ($x->compare($max) > 0) {
3107
+ $x = $min->copy();
3108
+ if ($x->equals($two)) {
3109
+ return $x;
3110
+ }
3111
+ $x->_make_odd();
3112
+ }
3113
+
3114
+ if ($x->equals($initial_x)) {
3115
+ return false;
3116
+ }
3117
+ }
3118
+ }
3119
+
3120
+ /**
3121
+ * Make the current number odd
3122
+ *
3123
+ * If the current number is odd it'll be unchanged. If it's even, one will be added to it.
3124
+ *
3125
+ * @see randomPrime()
3126
+ * @access private
3127
+ */
3128
+ function _make_odd()
3129
+ {
3130
+ switch ( MATH_BIGINTEGER_MODE ) {
3131
+ case MATH_BIGINTEGER_MODE_GMP:
3132
+ gmp_setbit($this->value, 0);
3133
+ break;
3134
+ case MATH_BIGINTEGER_MODE_BCMATH:
3135
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3136
+ $this->value = bcadd($this->value, '1');
3137
+ }
3138
+ break;
3139
+ default:
3140
+ $this->value[0] |= 1;
3141
+ }
3142
+ }
3143
+
3144
+ /**
3145
+ * Checks a numer to see if it's prime
3146
+ *
3147
+ * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
3148
+ * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads
3149
+ * on a website instead of just one.
3150
+ *
3151
+ * @param optional Integer $t
3152
+ * @return Boolean
3153
+ * @access public
3154
+ * @internal Uses the
3155
+ * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
3156
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3157
+ */
3158
+ function isPrime($t = false)
3159
+ {
3160
+ $length = strlen($this->toBytes());
3161
+
3162
+ if (!$t) {
3163
+ // see HAC 4.49 "Note (controlling the error probability)"
3164
+ if ($length >= 163) { $t = 2; } // floor(1300 / 8)
3165
+ else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
3166
+ else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
3167
+ else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
3168
+ else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
3169
+ else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
3170
+ else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
3171
+ else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
3172
+ else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3173
+ else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3174
+ else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3175
+ else { $t = 27; }
3176
+ }
3177
+
3178
+ // ie. gmp_testbit($this, 0)
3179
+ // ie. isEven() or !isOdd()
3180
+ switch ( MATH_BIGINTEGER_MODE ) {
3181
+ case MATH_BIGINTEGER_MODE_GMP:
3182
+ return gmp_prob_prime($this->value, $t) != 0;
3183
+ case MATH_BIGINTEGER_MODE_BCMATH:
3184
+ if ($this->value === '2') {
3185
+ return true;
3186
+ }
3187
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3188
+ return false;
3189
+ }
3190
+ break;
3191
+ default:
3192
+ if ($this->value == array(2)) {
3193
+ return true;
3194
+ }
3195
+ if (~$this->value[0] & 1) {
3196
+ return false;
3197
+ }
3198
+ }
3199
+
3200
+ static $primes, $zero, $one, $two;
3201
+
3202
+ if (!isset($primes)) {
3203
+ $primes = array(
3204
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3205
+ 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3206
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3207
+ 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3208
+ 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3209
+ 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3210
+ 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3211
+ 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3212
+ 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3213
+ 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3214
+ 953, 967, 971, 977, 983, 991, 997
3215
+ );
3216
+
3217
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3218
+ for ($i = 0; $i < count($primes); ++$i) {
3219
+ $primes[$i] = new Math_BigInteger($primes[$i]);
3220
+ }
3221
+ }
3222
+
3223
+ $zero = new Math_BigInteger();
3224
+ $one = new Math_BigInteger(1);
3225
+ $two = new Math_BigInteger(2);
3226
+ }
3227
+
3228
+ if ($this->equals($one)) {
3229
+ return false;
3230
+ }
3231
+
3232
+ // see HAC 4.4.1 "Random search for probable primes"
3233
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3234
+ foreach ($primes as $prime) {
3235
+ list(, $r) = $this->divide($prime);
3236
+ if ($r->equals($zero)) {
3237
+ return $this->equals($prime);
3238
+ }
3239
+ }
3240
+ } else {
3241
+ $value = $this->value;
3242
+ foreach ($primes as $prime) {
3243
+ list(, $r) = $this->_divide_digit($value, $prime);
3244
+ if (!$r) {
3245
+ return count($value) == 1 && $value[0] == $prime;
3246
+ }
3247
+ }
3248
+ }
3249
+
3250
+ $n = $this->copy();
3251
+ $n_1 = $n->subtract($one);
3252
+ $n_2 = $n->subtract($two);
3253
+
3254
+ $r = $n_1->copy();
3255
+ $r_value = $r->value;
3256
+ // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3257
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3258
+ $s = 0;
3259
+ // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3260
+ while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3261
+ $r->value = bcdiv($r->value, '2', 0);
3262
+ ++$s;
3263
+ }
3264
+ } else {
3265
+ for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3266
+ $temp = ~$r_value[$i] & 0xFFFFFF;
3267
+ for ($j = 1; ($temp >> $j) & 1; ++$j);
3268
+ if ($j != 25) {
3269
+ break;
3270
+ }
3271
+ }
3272
+ $s = 26 * $i + $j - 1;
3273
+ $r->_rshift($s);
3274
+ }
3275
+
3276
+ for ($i = 0; $i < $t; ++$i) {
3277
+ $a = $this->random($two, $n_2);
3278
+ $y = $a->modPow($r, $n);
3279
+
3280
+ if (!$y->equals($one) && !$y->equals($n_1)) {
3281
+ for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3282
+ $y = $y->modPow($two, $n);
3283
+ if ($y->equals($one)) {
3284
+ return false;
3285
+ }
3286
+ }
3287
+
3288
+ if (!$y->equals($n_1)) {
3289
+ return false;
3290
+ }
3291
+ }
3292
+ }
3293
+ return true;
3294
+ }
3295
+
3296
+ /**
3297
+ * Logical Left Shift
3298
+ *
3299
+ * Shifts BigInteger's by $shift bits.
3300
+ *
3301
+ * @param Integer $shift
3302
+ * @access private
3303
+ */
3304
+ function _lshift($shift)
3305
+ {
3306
+ if ( $shift == 0 ) {
3307
+ return;
3308
+ }
3309
+
3310
+ $num_digits = (int) ($shift / 26);
3311
+ $shift %= 26;
3312
+ $shift = 1 << $shift;
3313
+
3314
+ $carry = 0;
3315
+
3316
+ for ($i = 0; $i < count($this->value); ++$i) {
3317
+ $temp = $this->value[$i] * $shift + $carry;
3318
+ $carry = (int) ($temp / 0x4000000);
3319
+ $this->value[$i] = (int) ($temp - $carry * 0x4000000);
3320
+ }
3321
+
3322
+ if ( $carry ) {
3323
+ $this->value[] = $carry;
3324
+ }
3325
+
3326
+ while ($num_digits--) {
3327
+ array_unshift($this->value, 0);
3328
+ }
3329
+ }
3330
+
3331
+ /**
3332
+ * Logical Right Shift
3333
+ *
3334
+ * Shifts BigInteger's by $shift bits.
3335
+ *
3336
+ * @param Integer $shift
3337
+ * @access private
3338
+ */
3339
+ function _rshift($shift)
3340
+ {
3341
+ if ($shift == 0) {
3342
+ return;
3343
+ }
3344
+
3345
+ $num_digits = (int) ($shift / 26);
3346
+ $shift %= 26;
3347
+ $carry_shift = 26 - $shift;
3348
+ $carry_mask = (1 << $shift) - 1;
3349
+
3350
+ if ( $num_digits ) {
3351
+ $this->value = array_slice($this->value, $num_digits);
3352
+ }
3353
+
3354
+ $carry = 0;
3355
+
3356
+ for ($i = count($this->value) - 1; $i >= 0; --$i) {
3357
+ $temp = $this->value[$i] >> $shift | $carry;
3358
+ $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3359
+ $this->value[$i] = $temp;
3360
+ }
3361
+
3362
+ $this->value = $this->_trim($this->value);
3363
+ }
3364
+
3365
+ /**
3366
+ * Normalize
3367
+ *
3368
+ * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3369
+ *
3370
+ * @param Math_BigInteger
3371
+ * @return Math_BigInteger
3372
+ * @see _trim()
3373
+ * @access private
3374
+ */
3375
+ function _normalize($result)
3376
+ {
3377
+ $result->precision = $this->precision;
3378
+ $result->bitmask = $this->bitmask;
3379
+
3380
+ switch ( MATH_BIGINTEGER_MODE ) {
3381
+ case MATH_BIGINTEGER_MODE_GMP:
3382
+ if (!empty($result->bitmask->value)) {
3383
+ $result->value = gmp_and($result->value, $result->bitmask->value);
3384
+ }
3385
+
3386
+ return $result;
3387
+ case MATH_BIGINTEGER_MODE_BCMATH:
3388
+ if (!empty($result->bitmask->value)) {
3389
+ $result->value = bcmod($result->value, $result->bitmask->value);
3390
+ }
3391
+
3392
+ return $result;
3393
+ }
3394
+
3395
+ $value = &$result->value;
3396
+
3397
+ if ( !count($value) ) {
3398
+ return $result;
3399
+ }
3400
+
3401
+ $value = $this->_trim($value);
3402
+
3403
+ if (!empty($result->bitmask->value)) {
3404
+ $length = min(count($value), count($this->bitmask->value));
3405
+ $value = array_slice($value, 0, $length);
3406
+
3407
+ for ($i = 0; $i < $length; ++$i) {
3408
+ $value[$i] = $value[$i] & $this->bitmask->value[$i];
3409
+ }
3410
+ }
3411
+
3412
+ return $result;
3413
+ }
3414
+
3415
+ /**
3416
+ * Trim
3417
+ *
3418
+ * Removes leading zeros
3419
+ *
3420
+ * @return Math_BigInteger
3421
+ * @access private
3422
+ */
3423
+ function _trim($value)
3424
+ {
3425
+ for ($i = count($value) - 1; $i >= 0; --$i) {
3426
+ if ( $value[$i] ) {
3427
+ break;
3428
+ }
3429
+ unset($value[$i]);
3430
+ }
3431
+
3432
+ return $value;
3433
+ }
3434
+
3435
+ /**
3436
+ * Array Repeat
3437
+ *
3438
+ * @param $input Array
3439
+ * @param $multiplier mixed
3440
+ * @return Array
3441
+ * @access private
3442
+ */
3443
+ function _array_repeat($input, $multiplier)
3444
+ {
3445
+ return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3446
+ }
3447
+
3448
+ /**
3449
+ * Logical Left Shift
3450
+ *
3451
+ * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3452
+ *
3453
+ * @param $x String
3454
+ * @param $shift Integer
3455
+ * @return String
3456
+ * @access private
3457
+ */
3458
+ function _base256_lshift(&$x, $shift)
3459
+ {
3460
+ if ($shift == 0) {
3461
+ return;
3462
+ }
3463
+
3464
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3465
+ $shift &= 7; // eg. $shift % 8
3466
+
3467
+ $carry = 0;
3468
+ for ($i = strlen($x) - 1; $i >= 0; --$i) {
3469
+ $temp = ord($x[$i]) << $shift | $carry;
3470
+ $x[$i] = chr($temp);
3471
+ $carry = $temp >> 8;
3472
+ }
3473
+ $carry = ($carry != 0) ? chr($carry) : '';
3474
+ $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3475
+ }
3476
+
3477
+ /**
3478
+ * Logical Right Shift
3479
+ *
3480
+ * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3481
+ *
3482
+ * @param $x String
3483
+ * @param $shift Integer
3484
+ * @return String
3485
+ * @access private
3486
+ */
3487
+ function _base256_rshift(&$x, $shift)
3488
+ {
3489
+ if ($shift == 0) {
3490
+ $x = ltrim($x, chr(0));
3491
+ return '';
3492
+ }
3493
+
3494
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3495
+ $shift &= 7; // eg. $shift % 8
3496
+
3497
+ $remainder = '';
3498
+ if ($num_bytes) {
3499
+ $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3500
+ $remainder = substr($x, $start);
3501
+ $x = substr($x, 0, -$num_bytes);
3502
+ }
3503
+
3504
+ $carry = 0;
3505
+ $carry_shift = 8 - $shift;
3506
+ for ($i = 0; $i < strlen($x); ++$i) {
3507
+ $temp = (ord($x[$i]) >> $shift) | $carry;
3508
+ $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3509
+ $x[$i] = chr($temp);
3510
+ }
3511
+ $x = ltrim($x, chr(0));
3512
+
3513
+ $remainder = chr($carry >> $carry_shift) . $remainder;
3514
+
3515
+ return ltrim($remainder, chr(0));
3516
+ }
3517
+
3518
+ // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3519
+ // at 32-bits, while java's longs are 64-bits.
3520
+
3521
+ /**
3522
+ * Converts 32-bit integers to bytes.
3523
+ *
3524
+ * @param Integer $x
3525
+ * @return String
3526
+ * @access private
3527
+ */
3528
+ function _int2bytes($x)
3529
+ {
3530
+ return ltrim(pack('N', $x), chr(0));
3531
+ }
3532
+
3533
+ /**
3534
+ * Converts bytes to 32-bit integers
3535
+ *
3536
+ * @param String $x
3537
+ * @return Integer
3538
+ * @access private
3539
+ */
3540
+ function _bytes2int($x)
3541
+ {
3542
+ $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3543
+ return $temp['int'];
3544
+ }
3545
+ }
lib/phpseclib/Net/SFTP.php ADDED
@@ -0,0 +1,1461 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of SFTP.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Currently only supports SFTPv3, which, according to wikipedia.org, "is the most widely used version,
10
+ * implemented by the popular OpenSSH SFTP server". If you want SFTPv4/5/6 support, provide me with access
11
+ * to an SFTPv4/5/6 server.
12
+ *
13
+ * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
14
+ *
15
+ * Here's a short example of how to use this library:
16
+ * <code>
17
+ * <?php
18
+ * include('Net/SFTP.php');
19
+ *
20
+ * $sftp = new Net_SFTP('www.domain.tld');
21
+ * if (!$sftp->login('username', 'password')) {
22
+ * exit('Login Failed');
23
+ * }
24
+ *
25
+ * echo $sftp->pwd() . "\r\n";
26
+ * $sftp->put('filename.ext', 'hello, world!');
27
+ * print_r($sftp->nlist());
28
+ * ?>
29
+ * </code>
30
+ *
31
+ * LICENSE: This library is free software; you can redistribute it and/or
32
+ * modify it under the terms of the GNU Lesser General Public
33
+ * License as published by the Free Software Foundation; either
34
+ * version 2.1 of the License, or (at your option) any later version.
35
+ *
36
+ * This library is distributed in the hope that it will be useful,
37
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
38
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39
+ * Lesser General Public License for more details.
40
+ *
41
+ * You should have received a copy of the GNU Lesser General Public
42
+ * License along with this library; if not, write to the Free Software
43
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
44
+ * MA 02111-1307 USA
45
+ *
46
+ * @category Net
47
+ * @package Net_SFTP
48
+ * @author Jim Wigginton <terrafrost@php.net>
49
+ * @copyright MMIX Jim Wigginton
50
+ * @license http://www.gnu.org/licenses/lgpl.txt
51
+ * @version $Id: SFTP.php,v 1.21 2010/04/09 02:31:34 terrafrost Exp $
52
+ * @link http://phpseclib.sourceforge.net
53
+ */
54
+
55
+ /**
56
+ * Include Net_SSH2
57
+ */
58
+ require_once('phpseclib/Net/SSH2.php');
59
+
60
+ /**#@+
61
+ * @access public
62
+ * @see Net_SFTP::getLog()
63
+ */
64
+ /**
65
+ * Returns the message numbers
66
+ */
67
+ define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE);
68
+ /**
69
+ * Returns the message content
70
+ */
71
+ define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX);
72
+ /**#@-*/
73
+
74
+ /**
75
+ * SFTP channel constant
76
+ *
77
+ * Net_SSH2::exec() uses 0 and Net_SSH2::interactiveRead() / Net_SSH2::interactiveWrite() use 1.
78
+ *
79
+ * @see Net_SSH2::_send_channel_packet()
80
+ * @see Net_SSH2::_get_channel_packet()
81
+ * @access private
82
+ */
83
+ define('NET_SFTP_CHANNEL', 2);
84
+
85
+ /**#@+
86
+ * @access public
87
+ * @see Net_SFTP::put()
88
+ */
89
+ /**
90
+ * Reads data from a local file.
91
+ */
92
+ define('NET_SFTP_LOCAL_FILE', 1);
93
+ /**
94
+ * Reads data from a string.
95
+ */
96
+ define('NET_SFTP_STRING', 2);
97
+ /**#@-*/
98
+
99
+ /**
100
+ * Pure-PHP implementations of SFTP.
101
+ *
102
+ * @author Jim Wigginton <terrafrost@php.net>
103
+ * @version 0.1.0
104
+ * @access public
105
+ * @package Net_SFTP
106
+ */
107
+ class Net_SFTP extends Net_SSH2 {
108
+ /**
109
+ * Packet Types
110
+ *
111
+ * @see Net_SFTP::Net_SFTP()
112
+ * @var Array
113
+ * @access private
114
+ */
115
+ var $packet_types = array();
116
+
117
+ /**
118
+ * Status Codes
119
+ *
120
+ * @see Net_SFTP::Net_SFTP()
121
+ * @var Array
122
+ * @access private
123
+ */
124
+ var $status_codes = array();
125
+
126
+ /**
127
+ * The Request ID
128
+ *
129
+ * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
130
+ * concurrent actions, so it's somewhat academic, here.
131
+ *
132
+ * @var Integer
133
+ * @see Net_SFTP::_send_sftp_packet()
134
+ * @access private
135
+ */
136
+ var $request_id = false;
137
+
138
+ /**
139
+ * The Packet Type
140
+ *
141
+ * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
142
+ * concurrent actions, so it's somewhat academic, here.
143
+ *
144
+ * @var Integer
145
+ * @see Net_SFTP::_get_sftp_packet()
146
+ * @access private
147
+ */
148
+ var $packet_type = -1;
149
+
150
+ /**
151
+ * Packet Buffer
152
+ *
153
+ * @var String
154
+ * @see Net_SFTP::_get_sftp_packet()
155
+ * @access private
156
+ */
157
+ var $packet_buffer = '';
158
+
159
+ /**
160
+ * Extensions supported by the server
161
+ *
162
+ * @var Array
163
+ * @see Net_SFTP::_initChannel()
164
+ * @access private
165
+ */
166
+ var $extensions = array();
167
+
168
+ /**
169
+ * Server SFTP version
170
+ *
171
+ * @var Integer
172
+ * @see Net_SFTP::_initChannel()
173
+ * @access private
174
+ */
175
+ var $version;
176
+
177
+ /**
178
+ * Current working directory
179
+ *
180
+ * @var String
181
+ * @see Net_SFTP::_realpath()
182
+ * @see Net_SFTP::chdir()
183
+ * @access private
184
+ */
185
+ var $pwd = false;
186
+
187
+ /**
188
+ * Packet Type Log
189
+ *
190
+ * @see Net_SFTP::getLog()
191
+ * @var Array
192
+ * @access private
193
+ */
194
+ var $packet_type_log = array();
195
+
196
+ /**
197
+ * Packet Log
198
+ *
199
+ * @see Net_SFTP::getLog()
200
+ * @var Array
201
+ * @access private
202
+ */
203
+ var $packet_log = array();
204
+
205
+ /**
206
+ * Error information
207
+ *
208
+ * @see Net_SFTP::getSFTPErrors()
209
+ * @see Net_SFTP::getLastSFTPError()
210
+ * @var String
211
+ * @access private
212
+ */
213
+ var $errors = array();
214
+
215
+ /**
216
+ * Default Constructor.
217
+ *
218
+ * Connects to an SFTP server
219
+ *
220
+ * @param String $host
221
+ * @param optional Integer $port
222
+ * @param optional Integer $timeout
223
+ * @return Net_SFTP
224
+ * @access public
225
+ */
226
+ function Net_SFTP($host, $port = 22, $timeout = 10)
227
+ {
228
+ parent::Net_SSH2($host, $port, $timeout);
229
+ $this->packet_types = array(
230
+ 1 => 'NET_SFTP_INIT',
231
+ 2 => 'NET_SFTP_VERSION',
232
+ /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
233
+ SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
234
+ pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
235
+ 3 => 'NET_SFTP_OPEN',
236
+ 4 => 'NET_SFTP_CLOSE',
237
+ 5 => 'NET_SFTP_READ',
238
+ 6 => 'NET_SFTP_WRITE',
239
+ 8 => 'NET_SFTP_FSTAT',
240
+ 9 => 'NET_SFTP_SETSTAT',
241
+ 11 => 'NET_SFTP_OPENDIR',
242
+ 12 => 'NET_SFTP_READDIR',
243
+ 13 => 'NET_SFTP_REMOVE',
244
+ 14 => 'NET_SFTP_MKDIR',
245
+ 15 => 'NET_SFTP_RMDIR',
246
+ 16 => 'NET_SFTP_REALPATH',
247
+ 17 => 'NET_SFTP_STAT',
248
+ /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
249
+ SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
250
+ pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
251
+ 18 => 'NET_SFTP_RENAME',
252
+
253
+ 101=> 'NET_SFTP_STATUS',
254
+ 102=> 'NET_SFTP_HANDLE',
255
+ /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
256
+ SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
257
+ pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
258
+ 103=> 'NET_SFTP_DATA',
259
+ 104=> 'NET_SFTP_NAME',
260
+ 105=> 'NET_SFTP_ATTRS',
261
+
262
+ 200=> 'NET_SFTP_EXTENDED'
263
+ );
264
+ $this->status_codes = array(
265
+ 0 => 'NET_SFTP_STATUS_OK',
266
+ 1 => 'NET_SFTP_STATUS_EOF',
267
+ 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
268
+ 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
269
+ 4 => 'NET_SFTP_STATUS_FAILURE',
270
+ 5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
271
+ 6 => 'NET_SFTP_STATUS_NO_CONNECTION',
272
+ 7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
273
+ 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED'
274
+ );
275
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
276
+ // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why
277
+ $this->attributes = array(
278
+ 0x00000001 => 'NET_SFTP_ATTR_SIZE',
279
+ 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
280
+ 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
281
+ 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
282
+ -1 => 'NET_SFTP_ATTR_EXTENDED' // unpack('N', "\xFF\xFF\xFF\xFF") == array(1 => int(-1))
283
+ );
284
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
285
+ // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
286
+ // the array for that $this->open5_flags and similarily alter the constant names.
287
+ $this->open_flags = array(
288
+ 0x00000001 => 'NET_SFTP_OPEN_READ',
289
+ 0x00000002 => 'NET_SFTP_OPEN_WRITE',
290
+ 0x00000008 => 'NET_SFTP_OPEN_CREATE',
291
+ 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE'
292
+ );
293
+ $this->_define_array(
294
+ $this->packet_types,
295
+ $this->status_codes,
296
+ $this->attributes,
297
+ $this->open_flags
298
+ );
299
+ }
300
+
301
+ /**
302
+ * Login
303
+ *
304
+ * @param String $username
305
+ * @param optional String $password
306
+ * @return Boolean
307
+ * @access public
308
+ */
309
+ function login($username, $password = '')
310
+ {
311
+ if (!parent::login($username, $password)) {
312
+ return false;
313
+ }
314
+
315
+ $this->window_size_client_to_server[NET_SFTP_CHANNEL] = $this->window_size;
316
+
317
+ $packet = pack('CNa*N3',
318
+ NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000);
319
+
320
+ if (!$this->_send_binary_packet($packet)) {
321
+ return false;
322
+ }
323
+
324
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
325
+
326
+ $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
327
+ if ($response === false) {
328
+ return false;
329
+ }
330
+
331
+ $packet = pack('CNNa*CNa*',
332
+ NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp');
333
+ if (!$this->_send_binary_packet($packet)) {
334
+ return false;
335
+ }
336
+
337
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
338
+
339
+ $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
340
+ if ($response === false) {
341
+ return false;
342
+ }
343
+
344
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
345
+
346
+ if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
347
+ return false;
348
+ }
349
+
350
+ $response = $this->_get_sftp_packet();
351
+ if ($this->packet_type != NET_SFTP_VERSION) {
352
+ user_error('Expected SSH_FXP_VERSION', E_USER_NOTICE);
353
+ return false;
354
+ }
355
+
356
+ extract(unpack('Nversion', $this->_string_shift($response, 4)));
357
+ $this->version = $version;
358
+ while (!empty($response)) {
359
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
360
+ $key = $this->_string_shift($response, $length);
361
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
362
+ $value = $this->_string_shift($response, $length);
363
+ $this->extensions[$key] = $value;
364
+ }
365
+
366
+ /*
367
+ SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
368
+ however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
369
+ not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
370
+ one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
371
+ 'newline@vandyke.com' would.
372
+ */
373
+ /*
374
+ if (isset($this->extensions['newline@vandyke.com'])) {
375
+ $this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
376
+ unset($this->extensions['newline@vandyke.com']);
377
+ }
378
+ */
379
+
380
+ $this->request_id = 1;
381
+
382
+ /*
383
+ A Note on SFTPv4/5/6 support:
384
+ <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:
385
+
386
+ "If the client wishes to interoperate with servers that support noncontiguous version
387
+ numbers it SHOULD send '3'"
388
+
389
+ Given that the server only sends its version number after the client has already done so, the above
390
+ seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
391
+ most popular.
392
+
393
+ <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;
394
+
395
+ "If the server did not send the "versions" extension, or the version-from-list was not included, the
396
+ server MAY send a status response describing the failure, but MUST then close the channel without
397
+ processing any further requests."
398
+
399
+ So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
400
+ a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
401
+ v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
402
+ in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
403
+ channel and reopen it with a new and updated SSH_FXP_INIT packet.
404
+ */
405
+ if ($this->version != 3) {
406
+ return false;
407
+ }
408
+
409
+ $this->pwd = $this->_realpath('.');
410
+
411
+ return true;
412
+ }
413
+
414
+ /**
415
+ * Returns the current directory name
416
+ *
417
+ * @return Mixed
418
+ * @access public
419
+ */
420
+ function pwd()
421
+ {
422
+ return $this->pwd;
423
+ }
424
+
425
+ /**
426
+ * Canonicalize the Server-Side Path Name
427
+ *
428
+ * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
429
+ * the absolute (canonicalized) path. If $mode is set to NET_SFTP_CONFIRM_DIR (as opposed to NET_SFTP_CONFIRM_NONE,
430
+ * which is what it is set to by default), false is returned if $dir is not a valid directory.
431
+ *
432
+ * @see Net_SFTP::chdir()
433
+ * @param String $dir
434
+ * @param optional Integer $mode
435
+ * @return Mixed
436
+ * @access private
437
+ */
438
+ function _realpath($dir)
439
+ {
440
+ /*
441
+ "This protocol represents file names as strings. File names are
442
+ assumed to use the slash ('/') character as a directory separator.
443
+
444
+ File names starting with a slash are "absolute", and are relative to
445
+ the root of the file system. Names starting with any other character
446
+ are relative to the user's default directory (home directory). Note
447
+ that identifying the user is assumed to take place outside of this
448
+ protocol."
449
+
450
+ -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-6
451
+ */
452
+ $file = '';
453
+ if ($this->pwd !== false) {
454
+ // if the SFTP server returned the canonicalized path even for non-existant files this wouldn't be necessary
455
+ // on OpenSSH it isn't necessary but on other SFTP servers it is. that and since the specs say nothing on
456
+ // the subject, we'll go ahead and work around it with the following.
457
+ if ($dir[strlen($dir) - 1] != '/') {
458
+ $file = basename($dir);
459
+ $dir = dirname($dir);
460
+ }
461
+
462
+ if ($dir == '.' || $dir == $this->pwd) {
463
+ return $this->pwd . $file;
464
+ }
465
+
466
+ if ($dir[0] != '/') {
467
+ $dir = $this->pwd . '/' . $dir;
468
+ }
469
+ // on the surface it seems like maybe resolving a path beginning with / is unnecessary, but such paths
470
+ // can contain .'s and ..'s just like any other. we could parse those out as appropriate or we can let
471
+ // the server do it. we'll do the latter.
472
+ }
473
+
474
+ /*
475
+ that SSH_FXP_REALPATH returns SSH_FXP_NAME does not necessarily mean that anything actually exists at the
476
+ specified path. generally speaking, no attributes are returned with this particular SSH_FXP_NAME packet
477
+ regardless of whether or not a file actually exists. and in SFTPv3, the longname field and the filename
478
+ field match for this particular SSH_FXP_NAME packet. for other SSH_FXP_NAME packets, this will likely
479
+ not be the case, but for this one, it is.
480
+ */
481
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
482
+ if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($dir), $dir))) {
483
+ return false;
484
+ }
485
+
486
+ $response = $this->_get_sftp_packet();
487
+ switch ($this->packet_type) {
488
+ case NET_SFTP_NAME:
489
+ // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
490
+ // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
491
+ // at is the first part and that part is defined the same in SFTP versions 3 through 6.
492
+ $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
493
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
494
+ $realpath = $this->_string_shift($response, $length);
495
+ break;
496
+ case NET_SFTP_STATUS:
497
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
498
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
499
+ return false;
500
+ default:
501
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE);
502
+ return false;
503
+ }
504
+
505
+ // if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to
506
+ // be a bonafide directory
507
+ return $realpath . '/' . $file;
508
+ }
509
+
510
+ /**
511
+ * Changes the current directory
512
+ *
513
+ * @param String $dir
514
+ * @return Boolean
515
+ * @access public
516
+ */
517
+ function chdir($dir)
518
+ {
519
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
520
+ return false;
521
+ }
522
+
523
+ if ($dir[strlen($dir) - 1] != '/') {
524
+ $dir.= '/';
525
+ }
526
+ $dir = $this->_realpath($dir);
527
+
528
+ // confirm that $dir is, in fact, a valid directory
529
+ if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
530
+ return false;
531
+ }
532
+
533
+ // see Net_SFTP::nlist() for a more thorough explanation of the following
534
+ $response = $this->_get_sftp_packet();
535
+ switch ($this->packet_type) {
536
+ case NET_SFTP_HANDLE:
537
+ $handle = substr($response, 4);
538
+ break;
539
+ case NET_SFTP_STATUS:
540
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
541
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
542
+ return false;
543
+ default:
544
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
545
+ return false;
546
+ }
547
+
548
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
549
+ return false;
550
+ }
551
+
552
+ $response = $this->_get_sftp_packet();
553
+ if ($this->packet_type != NET_SFTP_STATUS) {
554
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
555
+ return false;
556
+ }
557
+
558
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
559
+ if ($status != NET_SFTP_STATUS_OK) {
560
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
561
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
562
+ return false;
563
+ }
564
+
565
+ $this->pwd = $dir;
566
+ return true;
567
+ }
568
+
569
+ /**
570
+ * Returns a list of files in the given directory
571
+ *
572
+ * @param optional String $dir
573
+ * @return Mixed
574
+ * @access public
575
+ */
576
+ function nlist($dir = '.')
577
+ {
578
+ return $this->_list($dir, false);
579
+ }
580
+
581
+ /**
582
+ * Returns a list of files in the given directory
583
+ *
584
+ * @param optional String $dir
585
+ * @return Mixed
586
+ * @access public
587
+ */
588
+ function rawlist($dir = '.')
589
+ {
590
+ return $this->_list($dir, true);
591
+ }
592
+
593
+ function _list($dir, $raw = true)
594
+ {
595
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
596
+ return false;
597
+ }
598
+
599
+ $dir = $this->_realpath($dir);
600
+ if ($dir === false) {
601
+ return false;
602
+ }
603
+
604
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
605
+ if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
606
+ return false;
607
+ }
608
+
609
+ $response = $this->_get_sftp_packet();
610
+ switch ($this->packet_type) {
611
+ case NET_SFTP_HANDLE:
612
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
613
+ // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
614
+ // represent the length of the string and leave it at that
615
+ $handle = substr($response, 4);
616
+ break;
617
+ case NET_SFTP_STATUS:
618
+ // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
619
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
620
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
621
+ return false;
622
+ default:
623
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
624
+ return false;
625
+ }
626
+
627
+ $contents = array();
628
+ while (true) {
629
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
630
+ // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
631
+ // SSH_MSG_CHANNEL_DATA messages is not known to me.
632
+ if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
633
+ return false;
634
+ }
635
+
636
+ $response = $this->_get_sftp_packet();
637
+ switch ($this->packet_type) {
638
+ case NET_SFTP_NAME:
639
+ extract(unpack('Ncount', $this->_string_shift($response, 4)));
640
+ for ($i = 0; $i < $count; $i++) {
641
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
642
+ $shortname = $this->_string_shift($response, $length);
643
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
644
+ $this->_string_shift($response, $length); // SFTPv4+ drop this field - the "longname" field
645
+ $attributes = $this->_parseAttributes($response); // we also don't care about the attributes
646
+ if (!$raw) {
647
+ $contents[] = $shortname;
648
+ } else {
649
+ $contents[$shortname] = $attributes;
650
+ }
651
+ // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
652
+ // final SSH_FXP_STATUS packet should tell us that, already.
653
+ }
654
+ break;
655
+ case NET_SFTP_STATUS:
656
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
657
+ if ($status != NET_SFTP_STATUS_EOF) {
658
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
659
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
660
+ return false;
661
+ }
662
+ break 2;
663
+ default:
664
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE);
665
+ return false;
666
+ }
667
+ }
668
+
669
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
670
+ return false;
671
+ }
672
+
673
+ // "The client MUST release all resources associated with the handle regardless of the status."
674
+ // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
675
+ $response = $this->_get_sftp_packet();
676
+ if ($this->packet_type != NET_SFTP_STATUS) {
677
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
678
+ return false;
679
+ }
680
+
681
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
682
+ if ($status != NET_SFTP_STATUS_OK) {
683
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
684
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
685
+ return false;
686
+ }
687
+
688
+ return $contents;
689
+ }
690
+
691
+ /**
692
+ * Returns the file size, in bytes, or false, on failure
693
+ *
694
+ * Files larger than 4GB will show up as being exactly 4GB.
695
+ *
696
+ * @param optional String $dir
697
+ * @return Mixed
698
+ * @access public
699
+ */
700
+ function size($filename)
701
+ {
702
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
703
+ return false;
704
+ }
705
+
706
+ $filename = $this->_realpath($filename);
707
+ if ($filename === false) {
708
+ return false;
709
+ }
710
+
711
+ // SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
712
+ $packet = pack('Na*', strlen($filename), $filename);
713
+ if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
714
+ return false;
715
+ }
716
+
717
+ $response = $this->_get_sftp_packet();
718
+ switch ($this->packet_type) {
719
+ case NET_SFTP_ATTRS:
720
+ $attrs = $this->_parseAttributes($response);
721
+ return $attrs['size'];
722
+ case NET_SFTP_STATUS:
723
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
724
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
725
+ return false;
726
+ }
727
+
728
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
729
+ return false;
730
+ }
731
+
732
+ /**
733
+ * Set permissions on a file.
734
+ *
735
+ * Returns the new file permissions on success or FALSE on error.
736
+ *
737
+ * @param Integer $mode
738
+ * @param String $filename
739
+ * @return Mixed
740
+ * @access public
741
+ */
742
+ function chmod($mode, $filename)
743
+ {
744
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
745
+ return false;
746
+ }
747
+
748
+ $filename = $this->_realpath($filename);
749
+ if ($filename === false) {
750
+ return false;
751
+ }
752
+
753
+ // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
754
+ // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
755
+ $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
756
+ if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
757
+ return false;
758
+ }
759
+
760
+ /*
761
+ "Because some systems must use separate system calls to set various attributes, it is possible that a failure
762
+ response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
763
+ servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
764
+
765
+ -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
766
+ */
767
+ $response = $this->_get_sftp_packet();
768
+ if ($this->packet_type != NET_SFTP_STATUS) {
769
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
770
+ return false;
771
+ }
772
+
773
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
774
+ if ($status != NET_SFTP_STATUS_EOF) {
775
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
776
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
777
+ }
778
+
779
+ // rather than return what the permissions *should* be, we'll return what they actually are. this will also
780
+ // tell us if the file actually exists.
781
+ // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
782
+ $packet = pack('Na*', strlen($filename), $filename);
783
+ if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
784
+ return false;
785
+ }
786
+
787
+ $response = $this->_get_sftp_packet();
788
+ switch ($this->packet_type) {
789
+ case NET_SFTP_ATTRS:
790
+ $attrs = $this->_parseAttributes($response);
791
+ return $attrs['permissions'];
792
+ case NET_SFTP_STATUS:
793
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
794
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
795
+ return false;
796
+ }
797
+
798
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
799
+ return false;
800
+ }
801
+
802
+ /**
803
+ * Creates a directory.
804
+ *
805
+ * @param String $dir
806
+ * @return Boolean
807
+ * @access public
808
+ */
809
+ function mkdir($dir)
810
+ {
811
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
812
+ return false;
813
+ }
814
+
815
+ $dir = $this->_realpath(rtrim($dir, '/'));
816
+ if ($dir === false) {
817
+ return false;
818
+ }
819
+
820
+ // by not providing any permissions, hopefully the server will use the logged in users umask - their
821
+ // default permissions.
822
+ if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*N', strlen($dir), $dir, 0))) {
823
+ return false;
824
+ }
825
+
826
+ $response = $this->_get_sftp_packet();
827
+ if ($this->packet_type != NET_SFTP_STATUS) {
828
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
829
+ return false;
830
+ }
831
+
832
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
833
+ if ($status != NET_SFTP_STATUS_OK) {
834
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
835
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
836
+ return false;
837
+ }
838
+
839
+ return true;
840
+ }
841
+
842
+ /**
843
+ * Removes a directory.
844
+ *
845
+ * @param String $dir
846
+ * @return Boolean
847
+ * @access public
848
+ */
849
+ function rmdir($dir)
850
+ {
851
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
852
+ return false;
853
+ }
854
+
855
+ $dir = $this->_realpath($dir);
856
+ if ($dir === false) {
857
+ return false;
858
+ }
859
+
860
+ if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
861
+ return false;
862
+ }
863
+
864
+ $response = $this->_get_sftp_packet();
865
+ if ($this->packet_type != NET_SFTP_STATUS) {
866
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
867
+ return false;
868
+ }
869
+
870
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
871
+ if ($status != NET_SFTP_STATUS_OK) {
872
+ // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
873
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
874
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
875
+ return false;
876
+ }
877
+
878
+ return true;
879
+ }
880
+
881
+ /**
882
+ * Uploads a file to the SFTP server.
883
+ *
884
+ * By default, Net_SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
885
+ * So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes
886
+ * long, containing 'filename.ext' as its contents.
887
+ *
888
+ * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
889
+ * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
890
+ * large $remote_file will be, as well.
891
+ *
892
+ * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
893
+ * care of that, yourself.
894
+ *
895
+ * @param String $remote_file
896
+ * @param String $data
897
+ * @param optional Integer $flags
898
+ * @return Boolean
899
+ * @access public
900
+ * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode().
901
+ */
902
+ function put($remote_file, $data, $mode = NET_SFTP_STRING)
903
+ {
904
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
905
+ return false;
906
+ }
907
+
908
+ $remote_file = $this->_realpath($remote_file);
909
+ if ($remote_file === false) {
910
+ return false;
911
+ }
912
+
913
+ $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_TRUNCATE, 0);
914
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
915
+ return false;
916
+ }
917
+
918
+ $response = $this->_get_sftp_packet();
919
+ switch ($this->packet_type) {
920
+ case NET_SFTP_HANDLE:
921
+ $handle = substr($response, 4);
922
+ break;
923
+ case NET_SFTP_STATUS:
924
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
925
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
926
+ return false;
927
+ default:
928
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
929
+ return false;
930
+ }
931
+
932
+ $initialize = true;
933
+
934
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
935
+ if ($mode == NET_SFTP_LOCAL_FILE) {
936
+ if (!is_file($data)) {
937
+ user_error("$data is not a valid file", E_USER_NOTICE);
938
+ return false;
939
+ }
940
+ $fp = fopen($data, 'rb');
941
+ if (!$fp) {
942
+ return false;
943
+ }
944
+ $sent = 0;
945
+ $size = filesize($data);
946
+ } else {
947
+ $sent = 0;
948
+ $size = strlen($data);
949
+ }
950
+
951
+ $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
952
+
953
+ $sftp_packet_size = 34000; // PuTTY uses 4096
954
+ $i = 0;
955
+ while ($sent < $size) {
956
+ $temp = $mode == NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : $this->_string_shift($data, $sftp_packet_size);
957
+ $packet = pack('Na*N3a*', strlen($handle), $handle, 0, $sent, strlen($temp), $temp);
958
+ if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
959
+ fclose($fp);
960
+ return false;
961
+ }
962
+ $sent+= strlen($temp);
963
+
964
+ $i++;
965
+
966
+ if ($i == 50) {
967
+ if (!$this->_read_put_responses($i)) {
968
+ $i = 0;
969
+ break;
970
+ }
971
+ $i = 0;
972
+ }
973
+ }
974
+
975
+ $this->_read_put_responses($i);
976
+
977
+ if ($mode == NET_SFTP_LOCAL_FILE) {
978
+ fclose($fp);
979
+ }
980
+
981
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
982
+ return false;
983
+ }
984
+
985
+ $response = $this->_get_sftp_packet();
986
+ if ($this->packet_type != NET_SFTP_STATUS) {
987
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
988
+ return false;
989
+ }
990
+
991
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
992
+ if ($status != NET_SFTP_STATUS_OK) {
993
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
994
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
995
+ return false;
996
+ }
997
+
998
+ return true;
999
+ }
1000
+
1001
+ /**
1002
+ * Reads multiple successive SSH_FXP_WRITE responses
1003
+ *
1004
+ * Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i
1005
+ * SSH_FXP_WRITEs, in succession, and then reading $i responses.
1006
+ *
1007
+ * @param Integer $i
1008
+ * @return Boolean
1009
+ * @access private
1010
+ */
1011
+ function _read_put_responses($i)
1012
+ {
1013
+ while ($i--) {
1014
+ $response = $this->_get_sftp_packet();
1015
+ if ($this->packet_type != NET_SFTP_STATUS) {
1016
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1017
+ return false;
1018
+ }
1019
+
1020
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1021
+ if ($status != NET_SFTP_STATUS_OK) {
1022
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1023
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1024
+ break;
1025
+ }
1026
+ }
1027
+
1028
+ return $i < 0;
1029
+ }
1030
+
1031
+ /**
1032
+ * Downloads a file from the SFTP server.
1033
+ *
1034
+ * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
1035
+ * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
1036
+ * operation
1037
+ *
1038
+ * @param String $remote_file
1039
+ * @param optional String $local_file
1040
+ * @return Mixed
1041
+ * @access public
1042
+ */
1043
+ function get($remote_file, $local_file = false)
1044
+ {
1045
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1046
+ return false;
1047
+ }
1048
+
1049
+ $remote_file = $this->_realpath($remote_file);
1050
+ if ($remote_file === false) {
1051
+ return false;
1052
+ }
1053
+
1054
+ $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
1055
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1056
+ return false;
1057
+ }
1058
+
1059
+ $response = $this->_get_sftp_packet();
1060
+ switch ($this->packet_type) {
1061
+ case NET_SFTP_HANDLE:
1062
+ $handle = substr($response, 4);
1063
+ break;
1064
+ case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1065
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1066
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1067
+ return false;
1068
+ default:
1069
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
1070
+ return false;
1071
+ }
1072
+
1073
+ $packet = pack('Na*', strlen($handle), $handle);
1074
+ if (!$this->_send_sftp_packet(NET_SFTP_FSTAT, $packet)) {
1075
+ return false;
1076
+ }
1077
+
1078
+ $response = $this->_get_sftp_packet();
1079
+ switch ($this->packet_type) {
1080
+ case NET_SFTP_ATTRS:
1081
+ $attrs = $this->_parseAttributes($response);
1082
+ break;
1083
+ case NET_SFTP_STATUS:
1084
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1085
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1086
+ return false;
1087
+ default:
1088
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
1089
+ return false;
1090
+ }
1091
+
1092
+ if ($local_file !== false) {
1093
+ $fp = fopen($local_file, 'wb');
1094
+ if (!$fp) {
1095
+ return false;
1096
+ }
1097
+ } else {
1098
+ $content = '';
1099
+ }
1100
+
1101
+ $read = 0;
1102
+ while ($read < $attrs['size']) {
1103
+ $packet = pack('Na*N3', strlen($handle), $handle, 0, $read, 1 << 20);
1104
+ if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
1105
+ return false;
1106
+ }
1107
+
1108
+ $response = $this->_get_sftp_packet();
1109
+ switch ($this->packet_type) {
1110
+ case NET_SFTP_DATA:
1111
+ $temp = substr($response, 4);
1112
+ $read+= strlen($temp);
1113
+ if ($local_file === false) {
1114
+ $content.= $temp;
1115
+ } else {
1116
+ fputs($fp, $temp);
1117
+ }
1118
+ break;
1119
+ case NET_SFTP_STATUS:
1120
+ extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1121
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1122
+ break 2;
1123
+ default:
1124
+ user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS', E_USER_NOTICE);
1125
+ return false;
1126
+ }
1127
+ }
1128
+
1129
+ if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
1130
+ return false;
1131
+ }
1132
+
1133
+ $response = $this->_get_sftp_packet();
1134
+ if ($this->packet_type != NET_SFTP_STATUS) {
1135
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1136
+ return false;
1137
+ }
1138
+
1139
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1140
+ if ($status != NET_SFTP_STATUS_OK) {
1141
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1142
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1143
+ return false;
1144
+ }
1145
+
1146
+ if (isset($content)) {
1147
+ return $content;
1148
+ }
1149
+
1150
+ fclose($fp);
1151
+ return true;
1152
+ }
1153
+
1154
+ /**
1155
+ * Deletes a file on the SFTP server.
1156
+ *
1157
+ * @param String $path
1158
+ * @return Boolean
1159
+ * @access public
1160
+ */
1161
+ function delete($path)
1162
+ {
1163
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1164
+ return false;
1165
+ }
1166
+
1167
+ $remote_file = $this->_realpath($path);
1168
+ if ($path === false) {
1169
+ return false;
1170
+ }
1171
+
1172
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
1173
+ if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
1174
+ return false;
1175
+ }
1176
+
1177
+ $response = $this->_get_sftp_packet();
1178
+ if ($this->packet_type != NET_SFTP_STATUS) {
1179
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1180
+ return false;
1181
+ }
1182
+
1183
+ // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1184
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1185
+ if ($status != NET_SFTP_STATUS_OK) {
1186
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1187
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1188
+ return false;
1189
+ }
1190
+
1191
+ return true;
1192
+ }
1193
+
1194
+ /**
1195
+ * Renames a file or a directory on the SFTP server
1196
+ *
1197
+ * @param String $oldname
1198
+ * @param String $newname
1199
+ * @return Boolean
1200
+ * @access public
1201
+ */
1202
+ function rename($oldname, $newname)
1203
+ {
1204
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1205
+ return false;
1206
+ }
1207
+
1208
+ $oldname = $this->_realpath($oldname);
1209
+ $newname = $this->_realpath($newname);
1210
+ if ($oldname === false || $newname === false) {
1211
+ return false;
1212
+ }
1213
+
1214
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
1215
+ $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
1216
+ if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
1217
+ return false;
1218
+ }
1219
+
1220
+ $response = $this->_get_sftp_packet();
1221
+ if ($this->packet_type != NET_SFTP_STATUS) {
1222
+ user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1223
+ return false;
1224
+ }
1225
+
1226
+ // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1227
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1228
+ if ($status != NET_SFTP_STATUS_OK) {
1229
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1230
+ $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1231
+ return false;
1232
+ }
1233
+
1234
+ return true;
1235
+ }
1236
+
1237
+ /**
1238
+ * Parse Attributes
1239
+ *
1240
+ * See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info.
1241
+ *
1242
+ * @param String $response
1243
+ * @return Array
1244
+ * @access private
1245
+ */
1246
+ function _parseAttributes(&$response)
1247
+ {
1248
+ $attr = array();
1249
+ extract(unpack('Nflags', $this->_string_shift($response, 4)));
1250
+ // SFTPv4+ have a type field (a byte) that follows the above flag field
1251
+ foreach ($this->attributes as $key => $value) {
1252
+ switch ($flags & $key) {
1253
+ case NET_SFTP_ATTR_SIZE: // 0x00000001
1254
+ // size is represented by a 64-bit integer, so we perhaps ought to be doing the following:
1255
+ // $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256);
1256
+ // of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB
1257
+ // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than
1258
+ // 4GB as being 4GB.
1259
+ extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8)));
1260
+ if ($upper) {
1261
+ $attr['size'] = 0xFFFFFFFF;
1262
+ } else {
1263
+ $attr['size'] = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
1264
+ }
1265
+ break;
1266
+ case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
1267
+ $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
1268
+ break;
1269
+ case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
1270
+ $attr+= unpack('Npermissions', $this->_string_shift($response, 4));
1271
+ break;
1272
+ case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
1273
+ $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
1274
+ break;
1275
+ case NET_SFTP_ATTR_EXTENDED: // 0x80000000
1276
+ extract(unpack('Ncount', $this->_string_shift($response, 4)));
1277
+ for ($i = 0; $i < $count; $i++) {
1278
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1279
+ $key = $this->_string_shift($response, $length);
1280
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1281
+ $attr[$key] = $this->_string_shift($response, $length);
1282
+ }
1283
+ }
1284
+ }
1285
+ return $attr;
1286
+ }
1287
+
1288
+ /**
1289
+ * Sends SFTP Packets
1290
+ *
1291
+ * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
1292
+ *
1293
+ * @param Integer $type
1294
+ * @param String $data
1295
+ * @see Net_SFTP::_get_sftp_packet()
1296
+ * @see Net_SSH2::_send_channel_packet()
1297
+ * @return Boolean
1298
+ * @access private
1299
+ */
1300
+ function _send_sftp_packet($type, $data)
1301
+ {
1302
+ $packet = $this->request_id !== false ?
1303
+ pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
1304
+ pack('NCa*', strlen($data) + 1, $type, $data);
1305
+
1306
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1307
+ $result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet);
1308
+ $stop = strtok(microtime(), ' ') + strtok('');
1309
+
1310
+ if (defined('NET_SFTP_LOGGING')) {
1311
+ $this->packet_type_log[] = '-> ' . $this->packet_types[$type] .
1312
+ ' (' . round($stop - $start, 4) . 's)';
1313
+ if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
1314
+ $this->packet_log[] = $data;
1315
+ }
1316
+ }
1317
+
1318
+ return $result;
1319
+ }
1320
+
1321
+ /**
1322
+ * Receives SFTP Packets
1323
+ *
1324
+ * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
1325
+ *
1326
+ * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present.
1327
+ * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
1328
+ * messages containing one SFTP packet.
1329
+ *
1330
+ * @see Net_SFTP::_send_sftp_packet()
1331
+ * @return String
1332
+ * @access private
1333
+ */
1334
+ function _get_sftp_packet()
1335
+ {
1336
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1337
+
1338
+ // SFTP packet length
1339
+ while (strlen($this->packet_buffer) < 4) {
1340
+ $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL);
1341
+ if (is_bool($temp)) {
1342
+ $this->packet_type = false;
1343
+ $this->packet_buffer = '';
1344
+ return false;
1345
+ }
1346
+ $this->packet_buffer.= $temp;
1347
+ }
1348
+ extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
1349
+ $tempLength = $length;
1350
+ $tempLength-= strlen($this->packet_buffer);
1351
+
1352
+ // SFTP packet type and data payload
1353
+ while ($tempLength > 0) {
1354
+ $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL);
1355
+ if (is_bool($temp)) {
1356
+ $this->packet_type = false;
1357
+ $this->packet_buffer = '';
1358
+ return false;
1359
+ }
1360
+ $this->packet_buffer.= $temp;
1361
+ $tempLength-= strlen($temp);
1362
+ }
1363
+
1364
+ $stop = strtok(microtime(), ' ') + strtok('');
1365
+
1366
+ $this->packet_type = ord($this->_string_shift($this->packet_buffer));
1367
+
1368
+ if ($this->request_id !== false) {
1369
+ $this->_string_shift($this->packet_buffer, 4); // remove the request id
1370
+ $length-= 5; // account for the request id and the packet type
1371
+ } else {
1372
+ $length-= 1; // account for the packet type
1373
+ }
1374
+
1375
+ $packet = $this->_string_shift($this->packet_buffer, $length);
1376
+
1377
+ if (defined('NET_SFTP_LOGGING')) {
1378
+ $this->packet_type_log[] = '<- ' . $this->packet_types[$this->packet_type] .
1379
+ ' (' . round($stop - $start, 4) . 's)';
1380
+ if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
1381
+ $this->packet_log[] = $packet;
1382
+ }
1383
+ }
1384
+
1385
+ return $packet;
1386
+ }
1387
+
1388
+ /**
1389
+ * Returns a log of the packets that have been sent and received.
1390
+ *
1391
+ * Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
1392
+ *
1393
+ * @access public
1394
+ * @return String or Array
1395
+ */
1396
+ function getSFTPLog()
1397
+ {
1398
+ if (!defined('NET_SFTP_LOGGING')) {
1399
+ return false;
1400
+ }
1401
+
1402
+ switch (NET_SFTP_LOGGING) {
1403
+ case NET_SFTP_LOG_COMPLEX:
1404
+ return $this->_format_log($this->packet_log, $this->packet_type_log);
1405
+ break;
1406
+ //case NET_SFTP_LOG_SIMPLE:
1407
+ default:
1408
+ return $this->packet_type_log;
1409
+ }
1410
+ }
1411
+
1412
+ /**
1413
+ * Returns all errors
1414
+ *
1415
+ * @return String
1416
+ * @access public
1417
+ */
1418
+ function getSFTPErrors()
1419
+ {
1420
+ return $this->sftp_errors;
1421
+ }
1422
+
1423
+ /**
1424
+ * Returns the last error
1425
+ *
1426
+ * @return String
1427
+ * @access public
1428
+ */
1429
+ function getLastSFTPError()
1430
+ {
1431
+ return $this->sftp_errors[count($this->sftp_errors) - 1];
1432
+ }
1433
+
1434
+ /**
1435
+ * Get supported SFTP versions
1436
+ *
1437
+ * @return Array
1438
+ * @access public
1439
+ */
1440
+ function getSupportedVersions()
1441
+ {
1442
+ $temp = array('version' => $this->version);
1443
+ if (isset($this->extensions['versions'])) {
1444
+ $temp['extensions'] = $this->extensions['versions'];
1445
+ }
1446
+ return $temp;
1447
+ }
1448
+
1449
+ /**
1450
+ * Disconnect
1451
+ *
1452
+ * @param Integer $reason
1453
+ * @return Boolean
1454
+ * @access private
1455
+ */
1456
+ function _disconnect($reason)
1457
+ {
1458
+ $this->pwd = false;
1459
+ parent::_disconnect($reason);
1460
+ }
1461
+ }
lib/phpseclib/Net/SSH1.php ADDED
@@ -0,0 +1,1159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of SSHv1.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Here's a short example of how to use this library:
10
+ * <code>
11
+ * <?php
12
+ * include('Net/SSH1.php');
13
+ *
14
+ * $ssh = new Net_SSH1('www.domain.tld');
15
+ * if (!$ssh->login('username', 'password')) {
16
+ * exit('Login Failed');
17
+ * }
18
+ *
19
+ * while (true) {
20
+ * echo $ssh->interactiveRead();
21
+ *
22
+ * $read = array(STDIN);
23
+ * $write = $except = NULL;
24
+ * if (stream_select($read, $write, $except, 0)) {
25
+ * $ssh->interactiveWrite(fread(STDIN, 1));
26
+ * }
27
+ * }
28
+ * ?>
29
+ * </code>
30
+ *
31
+ * Here's another short example:
32
+ * <code>
33
+ * <?php
34
+ * include('Net/SSH1.php');
35
+ *
36
+ * $ssh = new Net_SSH1('www.domain.tld');
37
+ * if (!$ssh->login('username', 'password')) {
38
+ * exit('Login Failed');
39
+ * }
40
+ *
41
+ * echo $ssh->exec('ls -la');
42
+ * ?>
43
+ * </code>
44
+ *
45
+ * More information on the SSHv1 specification can be found by reading
46
+ * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
47
+ *
48
+ * LICENSE: This library is free software; you can redistribute it and/or
49
+ * modify it under the terms of the GNU Lesser General Public
50
+ * License as published by the Free Software Foundation; either
51
+ * version 2.1 of the License, or (at your option) any later version.
52
+ *
53
+ * This library is distributed in the hope that it will be useful,
54
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
55
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
56
+ * Lesser General Public License for more details.
57
+ *
58
+ * You should have received a copy of the GNU Lesser General Public
59
+ * License along with this library; if not, write to the Free Software
60
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
61
+ * MA 02111-1307 USA
62
+ *
63
+ * @category Net
64
+ * @package Net_SSH1
65
+ * @author Jim Wigginton <terrafrost@php.net>
66
+ * @copyright MMVII Jim Wigginton
67
+ * @license http://www.gnu.org/licenses/lgpl.txt
68
+ * @version $Id: SSH1.php,v 1.15 2010/03/22 22:01:38 terrafrost Exp $
69
+ * @link http://phpseclib.sourceforge.net
70
+ */
71
+
72
+ /**
73
+ * Include Math_BigInteger
74
+ *
75
+ * Used to do RSA encryption.
76
+ */
77
+ require_once('phpseclib/Math/BigInteger.php');
78
+
79
+ /**
80
+ * Include Crypt_Null
81
+ */
82
+ //require_once('Crypt/Null.php');
83
+
84
+ /**
85
+ * Include Crypt_DES
86
+ */
87
+ require_once('phpseclib/Crypt/DES.php');
88
+
89
+ /**
90
+ * Include Crypt_TripleDES
91
+ */
92
+ require_once('phpseclib/Crypt/TripleDES.php');
93
+
94
+ /**
95
+ * Include Crypt_RC4
96
+ */
97
+ require_once('phpseclib/Crypt/RC4.php');
98
+
99
+ /**
100
+ * Include Crypt_Random
101
+ */
102
+ require_once('phpseclib/Crypt/Random.php');
103
+
104
+ /**#@+
105
+ * Protocol Flags
106
+ *
107
+ * @access private
108
+ */
109
+ define('NET_SSH1_MSG_DISCONNECT', 1);
110
+ define('NET_SSH1_SMSG_PUBLIC_KEY', 2);
111
+ define('NET_SSH1_CMSG_SESSION_KEY', 3);
112
+ define('NET_SSH1_CMSG_USER', 4);
113
+ define('NET_SSH1_CMSG_AUTH_PASSWORD', 9);
114
+ define('NET_SSH1_CMSG_REQUEST_PTY', 10);
115
+ define('NET_SSH1_CMSG_EXEC_SHELL', 12);
116
+ define('NET_SSH1_CMSG_EXEC_CMD', 13);
117
+ define('NET_SSH1_SMSG_SUCCESS', 14);
118
+ define('NET_SSH1_SMSG_FAILURE', 15);
119
+ define('NET_SSH1_CMSG_STDIN_DATA', 16);
120
+ define('NET_SSH1_SMSG_STDOUT_DATA', 17);
121
+ define('NET_SSH1_SMSG_STDERR_DATA', 18);
122
+ define('NET_SSH1_SMSG_EXITSTATUS', 20);
123
+ define('NET_SSH1_CMSG_EXIT_CONFIRMATION', 33);
124
+ /**#@-*/
125
+
126
+ /**#@+
127
+ * Encryption Methods
128
+ *
129
+ * @see Net_SSH1::getSupportedCiphers()
130
+ * @access public
131
+ */
132
+ /**
133
+ * No encryption
134
+ *
135
+ * Not supported.
136
+ */
137
+ define('NET_SSH1_CIPHER_NONE', 0);
138
+ /**
139
+ * IDEA in CFB mode
140
+ *
141
+ * Not supported.
142
+ */
143
+ define('NET_SSH1_CIPHER_IDEA', 1);
144
+ /**
145
+ * DES in CBC mode
146
+ */
147
+ define('NET_SSH1_CIPHER_DES', 2);
148
+ /**
149
+ * Triple-DES in CBC mode
150
+ *
151
+ * All implementations are required to support this
152
+ */
153
+ define('NET_SSH1_CIPHER_3DES', 3);
154
+ /**
155
+ * TRI's Simple Stream encryption CBC
156
+ *
157
+ * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
158
+ * although it doesn't use it (see cipher.c)
159
+ */
160
+ define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
161
+ /**
162
+ * RC4
163
+ *
164
+ * Not supported.
165
+ *
166
+ * @internal According to the SSH1 specs:
167
+ *
168
+ * "The first 16 bytes of the session key are used as the key for
169
+ * the server to client direction. The remaining 16 bytes are used
170
+ * as the key for the client to server direction. This gives
171
+ * independent 128-bit keys for each direction."
172
+ *
173
+ * This library currently only supports encryption when the same key is being used for both directions. This is
174
+ * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
175
+ */
176
+ define('NET_SSH1_CIPHER_RC4', 5);
177
+ /**
178
+ * Blowfish
179
+ *
180
+ * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
181
+ * uses it (see cipher.c)
182
+ */
183
+ define('NET_SSH1_CIPHER_BLOWFISH', 6);
184
+ /**#@-*/
185
+
186
+ /**#@+
187
+ * Authentication Methods
188
+ *
189
+ * @see Net_SSH1::getSupportedAuthentications()
190
+ * @access public
191
+ */
192
+ /**
193
+ * .rhosts or /etc/hosts.equiv
194
+ */
195
+ define('NET_SSH1_AUTH_RHOSTS', 1);
196
+ /**
197
+ * pure RSA authentication
198
+ */
199
+ define('NET_SSH1_AUTH_RSA', 2);
200
+ /**
201
+ * password authentication
202
+ *
203
+ * This is the only method that is supported by this library.
204
+ */
205
+ define('NET_SSH1_AUTH_PASSWORD', 3);
206
+ /**
207
+ * .rhosts with RSA host authentication
208
+ */
209
+ define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
210
+ /**#@-*/
211
+
212
+ /**#@+
213
+ * Terminal Modes
214
+ *
215
+ * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
216
+ * @access private
217
+ */
218
+ define('NET_SSH1_TTY_OP_END', 0);
219
+ /**#@-*/
220
+
221
+ /**
222
+ * The Response Type
223
+ *
224
+ * @see Net_SSH1::_get_binary_packet()
225
+ * @access private
226
+ */
227
+ define('NET_SSH1_RESPONSE_TYPE', 1);
228
+
229
+ /**
230
+ * The Response Data
231
+ *
232
+ * @see Net_SSH1::_get_binary_packet()
233
+ * @access private
234
+ */
235
+ define('NET_SSH1_RESPONSE_DATA', 2);
236
+
237
+ /**#@+
238
+ * Execution Bitmap Masks
239
+ *
240
+ * @see Net_SSH1::bitmap
241
+ * @access private
242
+ */
243
+ define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
244
+ define('NET_SSH1_MASK_LOGIN', 0x00000002);
245
+ define('NET_SSH1_MASK_SHELL', 0x00000004);
246
+ /**#@-*/
247
+
248
+ /**
249
+ * Pure-PHP implementation of SSHv1.
250
+ *
251
+ * @author Jim Wigginton <terrafrost@php.net>
252
+ * @version 0.1.0
253
+ * @access public
254
+ * @package Net_SSH1
255
+ */
256
+ class Net_SSH1 {
257
+ /**
258
+ * The SSH identifier
259
+ *
260
+ * @var String
261
+ * @access private
262
+ */
263
+ var $identifier = 'SSH-1.5-phpseclib';
264
+
265
+ /**
266
+ * The Socket Object
267
+ *
268
+ * @var Object
269
+ * @access private
270
+ */
271
+ var $fsock;
272
+
273
+ /**
274
+ * The cryptography object
275
+ *
276
+ * @var Object
277
+ * @access private
278
+ */
279
+ var $crypto = false;
280
+
281
+ /**
282
+ * Execution Bitmap
283
+ *
284
+ * The bits that are set reprsent functions that have been called already. This is used to determine
285
+ * if a requisite function has been successfully executed. If not, an error should be thrown.
286
+ *
287
+ * @var Integer
288
+ * @access private
289
+ */
290
+ var $bitmap = 0;
291
+
292
+ /**
293
+ * The Server Key Public Exponent
294
+ *
295
+ * Logged for debug purposes
296
+ *
297
+ * @see Net_SSH1::getServerKeyPublicExponent()
298
+ * @var String
299
+ * @access private
300
+ */
301
+ var $server_key_public_exponent;
302
+
303
+ /**
304
+ * The Server Key Public Modulus
305
+ *
306
+ * Logged for debug purposes
307
+ *
308
+ * @see Net_SSH1::getServerKeyPublicModulus()
309
+ * @var String
310
+ * @access private
311
+ */
312
+ var $server_key_public_modulus;
313
+
314
+ /**
315
+ * The Host Key Public Exponent
316
+ *
317
+ * Logged for debug purposes
318
+ *
319
+ * @see Net_SSH1::getHostKeyPublicExponent()
320
+ * @var String
321
+ * @access private
322
+ */
323
+ var $host_key_public_exponent;
324
+
325
+ /**
326
+ * The Host Key Public Modulus
327
+ *
328
+ * Logged for debug purposes
329
+ *
330
+ * @see Net_SSH1::getHostKeyPublicModulus()
331
+ * @var String
332
+ * @access private
333
+ */
334
+ var $host_key_public_modulus;
335
+
336
+ /**
337
+ * Supported Ciphers
338
+ *
339
+ * Logged for debug purposes
340
+ *
341
+ * @see Net_SSH1::getSupportedCiphers()
342
+ * @var Array
343
+ * @access private
344
+ */
345
+ var $supported_ciphers = array(
346
+ NET_SSH1_CIPHER_NONE => 'No encryption',
347
+ NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
348
+ NET_SSH1_CIPHER_DES => 'DES in CBC mode',
349
+ NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
350
+ NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
351
+ NET_SSH1_CIPHER_RC4 => 'RC4',
352
+ NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
353
+ );
354
+
355
+ /**
356
+ * Supported Authentications
357
+ *
358
+ * Logged for debug purposes
359
+ *
360
+ * @see Net_SSH1::getSupportedAuthentications()
361
+ * @var Array
362
+ * @access private
363
+ */
364
+ var $supported_authentications = array(
365
+ NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
366
+ NET_SSH1_AUTH_RSA => 'pure RSA authentication',
367
+ NET_SSH1_AUTH_PASSWORD => 'password authentication',
368
+ NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
369
+ );
370
+
371
+ /**
372
+ * Server Identification
373
+ *
374
+ * @see Net_SSH1::getServerIdentification()
375
+ * @var String
376
+ * @access private
377
+ */
378
+ var $server_identification = '';
379
+
380
+ /**
381
+ * Default Constructor.
382
+ *
383
+ * Connects to an SSHv1 server
384
+ *
385
+ * @param String $host
386
+ * @param optional Integer $port
387
+ * @param optional Integer $timeout
388
+ * @param optional Integer $cipher
389
+ * @return Net_SSH1
390
+ * @access public
391
+ */
392
+ function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
393
+ {
394
+ $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
395
+ if (!$this->fsock) {
396
+ user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
397
+ return;
398
+ }
399
+
400
+ $this->server_identification = $init_line = fgets($this->fsock, 255);
401
+ if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
402
+ user_error('Can only connect to SSH servers', E_USER_NOTICE);
403
+ return;
404
+ }
405
+ if ($parts[1][0] != 1) {
406
+ user_error("Cannot connect to SSH $parts[1] servers", E_USER_NOTICE);
407
+ return;
408
+ }
409
+
410
+ fputs($this->fsock, $this->identifier."\r\n");
411
+
412
+ $response = $this->_get_binary_packet();
413
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
414
+ user_error('Expected SSH_SMSG_PUBLIC_KEY', E_USER_NOTICE);
415
+ return;
416
+ }
417
+
418
+ $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
419
+
420
+ $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
421
+
422
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
423
+ $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
424
+ $this->server_key_public_exponent = $server_key_public_exponent;
425
+
426
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
427
+ $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
428
+ $this->server_key_public_modulus = $server_key_public_modulus;
429
+
430
+ $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
431
+
432
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
433
+ $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
434
+ $this->host_key_public_exponent = $host_key_public_exponent;
435
+
436
+ $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
437
+ $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
438
+ $this->host_key_public_modulus = $host_key_public_modulus;
439
+
440
+ $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
441
+
442
+ // get a list of the supported ciphers
443
+ extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
444
+ foreach ($this->supported_ciphers as $mask=>$name) {
445
+ if (($supported_ciphers_mask & (1 << $mask)) == 0) {
446
+ unset($this->supported_ciphers[$mask]);
447
+ }
448
+ }
449
+
450
+ // get a list of the supported authentications
451
+ extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
452
+ foreach ($this->supported_authentications as $mask=>$name) {
453
+ if (($supported_authentications_mask & (1 << $mask)) == 0) {
454
+ unset($this->supported_authentications[$mask]);
455
+ }
456
+ }
457
+
458
+ $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
459
+
460
+ $session_key = '';
461
+ for ($i = 0; $i < 32; $i++) {
462
+ $session_key.= chr(crypt_random(0, 255));
463
+ }
464
+ $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
465
+
466
+ if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
467
+ $double_encrypted_session_key = $this->_rsa_crypt(
468
+ $double_encrypted_session_key,
469
+ array(
470
+ $server_key_public_exponent,
471
+ $server_key_public_modulus
472
+ )
473
+ );
474
+ $double_encrypted_session_key = $this->_rsa_crypt(
475
+ $double_encrypted_session_key,
476
+ array(
477
+ $host_key_public_exponent,
478
+ $host_key_public_modulus
479
+ )
480
+ );
481
+ } else {
482
+ $double_encrypted_session_key = $this->_rsa_crypt(
483
+ $double_encrypted_session_key,
484
+ array(
485
+ $host_key_public_exponent,
486
+ $host_key_public_modulus
487
+ )
488
+ );
489
+ $double_encrypted_session_key = $this->_rsa_crypt(
490
+ $double_encrypted_session_key,
491
+ array(
492
+ $server_key_public_exponent,
493
+ $server_key_public_modulus
494
+ )
495
+ );
496
+ }
497
+
498
+ $cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : NET_SSH1_CIPHER_3DES;
499
+ $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
500
+
501
+ if (!$this->_send_binary_packet($data)) {
502
+ user_error('Error sending SSH_CMSG_SESSION_KEY', E_USER_NOTICE);
503
+ return;
504
+ }
505
+
506
+ switch ($cipher) {
507
+ //case NET_SSH1_CIPHER_NONE:
508
+ // $this->crypto = new Crypt_Null();
509
+ // break;
510
+ case NET_SSH1_CIPHER_DES:
511
+ $this->crypto = new Crypt_DES();
512
+ $this->crypto->disablePadding();
513
+ $this->crypto->enableContinuousBuffer();
514
+ $this->crypto->setKey(substr($session_key, 0, 8));
515
+ break;
516
+ case NET_SSH1_CIPHER_3DES:
517
+ $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
518
+ $this->crypto->disablePadding();
519
+ $this->crypto->enableContinuousBuffer();
520
+ $this->crypto->setKey(substr($session_key, 0, 24));
521
+ break;
522
+ //case NET_SSH1_CIPHER_RC4:
523
+ // $this->crypto = new Crypt_RC4();
524
+ // $this->crypto->enableContinuousBuffer();
525
+ // $this->crypto->setKey(substr($session_key, 0, 16));
526
+ // break;
527
+ }
528
+
529
+ $response = $this->_get_binary_packet();
530
+
531
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
532
+ user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
533
+ return;
534
+ }
535
+
536
+ $this->bitmap = NET_SSH1_MASK_CONSTRUCTOR;
537
+ }
538
+
539
+ /**
540
+ * Login
541
+ *
542
+ * @param String $username
543
+ * @param optional String $password
544
+ * @return Boolean
545
+ * @access public
546
+ */
547
+ function login($username, $password = '')
548
+ {
549
+ if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
550
+ return false;
551
+ }
552
+
553
+ $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
554
+
555
+ if (!$this->_send_binary_packet($data)) {
556
+ user_error('Error sending SSH_CMSG_USER', E_USER_NOTICE);
557
+ return false;
558
+ }
559
+
560
+ $response = $this->_get_binary_packet();
561
+
562
+ if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
563
+ $this->bitmap |= NET_SSH1_MASK_LOGIN;
564
+ return true;
565
+ } else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
566
+ user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
567
+ return false;
568
+ }
569
+
570
+ $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
571
+
572
+ if (!$this->_send_binary_packet($data)) {
573
+ user_error('Error sending SSH_CMSG_AUTH_PASSWORD', E_USER_NOTICE);
574
+ return false;
575
+ }
576
+
577
+ $response = $this->_get_binary_packet();
578
+
579
+ if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
580
+ $this->bitmap |= NET_SSH1_MASK_LOGIN;
581
+ return true;
582
+ } else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
583
+ return false;
584
+ } else {
585
+ user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
586
+ return false;
587
+ }
588
+ }
589
+
590
+ /**
591
+ * Executes a command on a non-interactive shell, returns the output, and quits.
592
+ *
593
+ * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
594
+ * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
595
+ * shell with the -s option, as discussed in the following links:
596
+ *
597
+ * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
598
+ * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
599
+ *
600
+ * To execute further commands, a new Net_SSH1 object will need to be created.
601
+ *
602
+ * Returns false on failure and the output, otherwise.
603
+ *
604
+ * @see Net_SSH1::interactiveRead()
605
+ * @see Net_SSH1::interactiveWrite()
606
+ * @param String $cmd
607
+ * @return mixed
608
+ * @access public
609
+ */
610
+ function exec($cmd)
611
+ {
612
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
613
+ user_error('Operation disallowed prior to login()', E_USER_NOTICE);
614
+ return false;
615
+ }
616
+
617
+ // connect using the sample parameters in protocol-1.5.txt.
618
+ // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
619
+ // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
620
+ $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
621
+
622
+ if (!$this->_send_binary_packet($data)) {
623
+ user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE);
624
+ return false;
625
+ }
626
+
627
+ $response = $this->_get_binary_packet();
628
+
629
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
630
+ user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
631
+ return false;
632
+ }
633
+
634
+ $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
635
+
636
+ if (!$this->_send_binary_packet($data)) {
637
+ user_error('Error sending SSH_CMSG_EXEC_CMD', E_USER_NOTICE);
638
+ return false;
639
+ }
640
+
641
+ $output = '';
642
+ $response = $this->_get_binary_packet();
643
+
644
+ do {
645
+ $output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
646
+ $response = $this->_get_binary_packet();
647
+ } while ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
648
+
649
+ $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
650
+
651
+ // i don't think it's really all that important if this packet gets sent or not.
652
+ $this->_send_binary_packet($data);
653
+
654
+ fclose($this->fsock);
655
+
656
+ // reset the execution bitmap - a new Net_SSH1 object needs to be created.
657
+ $this->bitmap = 0;
658
+
659
+ return $output;
660
+ }
661
+
662
+ /**
663
+ * Creates an interactive shell
664
+ *
665
+ * @see Net_SSH1::interactiveRead()
666
+ * @see Net_SSH1::interactiveWrite()
667
+ * @return Boolean
668
+ * @access private
669
+ */
670
+ function _initShell()
671
+ {
672
+ $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
673
+
674
+ if (!$this->_send_binary_packet($data)) {
675
+ user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE);
676
+ return false;
677
+ }
678
+
679
+ $response = $this->_get_binary_packet();
680
+
681
+ if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
682
+ user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
683
+ return false;
684
+ }
685
+
686
+ $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
687
+
688
+ if (!$this->_send_binary_packet($data)) {
689
+ user_error('Error sending SSH_CMSG_EXEC_SHELL', E_USER_NOTICE);
690
+ return false;
691
+ }
692
+
693
+ $this->bitmap |= NET_SSH1_MASK_SHELL;
694
+
695
+ //stream_set_blocking($this->fsock, 0);
696
+
697
+ return true;
698
+ }
699
+
700
+ /**
701
+ * Inputs a command into an interactive shell.
702
+ *
703
+ * @see Net_SSH1::interactiveRead()
704
+ * @param String $cmd
705
+ * @return Boolean
706
+ * @access public
707
+ */
708
+ function interactiveWrite($cmd)
709
+ {
710
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
711
+ user_error('Operation disallowed prior to login()', E_USER_NOTICE);
712
+ return false;
713
+ }
714
+
715
+ if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
716
+ user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
717
+ return false;
718
+ }
719
+
720
+ $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
721
+
722
+ if (!$this->_send_binary_packet($data)) {
723
+ user_error('Error sending SSH_CMSG_STDIN', E_USER_NOTICE);
724
+ return false;
725
+ }
726
+
727
+ return true;
728
+ }
729
+
730
+ /**
731
+ * Reads the output of an interactive shell.
732
+ *
733
+ * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
734
+ * "[00m", you're seeing ANSI escape codes. According to
735
+ * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
736
+ * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
737
+ * there's not going to be much recourse.
738
+ *
739
+ * @see Net_SSH1::interactiveRead()
740
+ * @return String
741
+ * @access public
742
+ */
743
+ function interactiveRead()
744
+ {
745
+ if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
746
+ user_error('Operation disallowed prior to login()', E_USER_NOTICE);
747
+ return false;
748
+ }
749
+
750
+ if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
751
+ user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
752
+ return false;
753
+ }
754
+
755
+ $read = array($this->fsock);
756
+ $write = $except = null;
757
+ if (stream_select($read, $write, $except, 0)) {
758
+ $response = $this->_get_binary_packet();
759
+ return substr($response[NET_SSH1_RESPONSE_DATA], 4);
760
+ } else {
761
+ return '';
762
+ }
763
+ }
764
+
765
+ /**
766
+ * Disconnect
767
+ *
768
+ * @access public
769
+ */
770
+ function disconnect()
771
+ {
772
+ $this->_disconnect();
773
+ }
774
+
775
+ /**
776
+ * Destructor.
777
+ *
778
+ * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
779
+ * disconnect().
780
+ *
781
+ * @access public
782
+ */
783
+ function __destruct()
784
+ {
785
+ $this->_disconnect();
786
+ }
787
+
788
+ /**
789
+ * Disconnect
790
+ *
791
+ * @param String $msg
792
+ * @access private
793
+ */
794
+ function _disconnect($msg = 'Client Quit')
795
+ {
796
+ if ($this->bitmap) {
797
+ $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
798
+ $this->_send_binary_packet($data);
799
+ fclose($this->fsock);
800
+ $this->bitmap = 0;
801
+ }
802
+ }
803
+
804
+ /**
805
+ * Gets Binary Packets
806
+ *
807
+ * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
808
+ *
809
+ * Also, this function could be improved upon by adding detection for the following exploit:
810
+ * http://www.securiteam.com/securitynews/5LP042K3FY.html
811
+ *
812
+ * @see Net_SSH1::_send_binary_packet()
813
+ * @return Array
814
+ * @access private
815
+ */
816
+ function _get_binary_packet()
817
+ {
818
+ if (feof($this->fsock)) {
819
+ //user_error('connection closed prematurely', E_USER_NOTICE);
820
+ return false;
821
+ }
822
+
823
+ $temp = unpack('Nlength', fread($this->fsock, 4));
824
+
825
+ $padding_length = 8 - ($temp['length'] & 7);
826
+ $length = $temp['length'] + $padding_length;
827
+
828
+ $raw = fread($this->fsock, $length);
829
+
830
+ if ($this->crypto !== false) {
831
+ $raw = $this->crypto->decrypt($raw);
832
+ }
833
+
834
+ $padding = substr($raw, 0, $padding_length);
835
+ $type = $raw[$padding_length];
836
+ $data = substr($raw, $padding_length + 1, -4);
837
+
838
+ $temp = unpack('Ncrc', substr($raw, -4));
839
+
840
+ //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
841
+ // user_error('Bad CRC in packet from server', E_USER_NOTICE);
842
+ // return false;
843
+ //}
844
+
845
+ return array(
846
+ NET_SSH1_RESPONSE_TYPE => ord($type),
847
+ NET_SSH1_RESPONSE_DATA => $data
848
+ );
849
+ }
850
+
851
+ /**
852
+ * Sends Binary Packets
853
+ *
854
+ * Returns true on success, false on failure.
855
+ *
856
+ * @see Net_SSH1::_get_binary_packet()
857
+ * @param String $data
858
+ * @return Boolean
859
+ * @access private
860
+ */
861
+ function _send_binary_packet($data) {
862
+ if (feof($this->fsock)) {
863
+ //user_error('connection closed prematurely', E_USER_NOTICE);
864
+ return false;
865
+ }
866
+
867
+ $length = strlen($data) + 4;
868
+
869
+ $padding_length = 8 - ($length & 7);
870
+ $padding = '';
871
+ for ($i = 0; $i < $padding_length; $i++) {
872
+ $padding.= chr(crypt_random(0, 255));
873
+ }
874
+
875
+ $data = $padding . $data;
876
+ $data.= pack('N', $this->_crc($data));
877
+
878
+ if ($this->crypto !== false) {
879
+ $data = $this->crypto->encrypt($data);
880
+ }
881
+
882
+ $packet = pack('Na*', $length, $data);
883
+
884
+ return strlen($packet) == fputs($this->fsock, $packet);
885
+ }
886
+
887
+ /**
888
+ * Cyclic Redundancy Check (CRC)
889
+ *
890
+ * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
891
+ * we've reimplemented it. A more detailed discussion of the differences can be found after
892
+ * $crc_lookup_table's initialization.
893
+ *
894
+ * @see Net_SSH1::_get_binary_packet()
895
+ * @see Net_SSH1::_send_binary_packet()
896
+ * @param String $data
897
+ * @return Integer
898
+ * @access private
899
+ */
900
+ function _crc($data)
901
+ {
902
+ static $crc_lookup_table = array(
903
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
904
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
905
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
906
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
907
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
908
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
909
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
910
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
911
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
912
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
913
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
914
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
915
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
916
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
917
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
918
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
919
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
920
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
921
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
922
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
923
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
924
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
925
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
926
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
927
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
928
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
929
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
930
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
931
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
932
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
933
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
934
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
935
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
936
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
937
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
938
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
939
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
940
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
941
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
942
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
943
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
944
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
945
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
946
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
947
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
948
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
949
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
950
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
951
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
952
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
953
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
954
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
955
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
956
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
957
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
958
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
959
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
960
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
961
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
962
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
963
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
964
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
965
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
966
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
967
+ );
968
+
969
+ // For this function to yield the same output as PHP's crc32 function, $crc would have to be
970
+ // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
971
+ $crc = 0x00000000;
972
+ $length = strlen($data);
973
+
974
+ for ($i=0;$i<$length;$i++) {
975
+ // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
976
+ // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
977
+ // yields 0xFF800000 - not 0x00800000. The following link elaborates:
978
+ // http://www.php.net/manual/en/language.operators.bitwise.php#57281
979
+ $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
980
+ }
981
+
982
+ // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
983
+ // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
984
+ return $crc;
985
+ }
986
+
987
+ /**
988
+ * String Shift
989
+ *
990
+ * Inspired by array_shift
991
+ *
992
+ * @param String $string
993
+ * @param optional Integer $index
994
+ * @return String
995
+ * @access private
996
+ */
997
+ function _string_shift(&$string, $index = 1)
998
+ {
999
+ $substr = substr($string, 0, $index);
1000
+ $string = substr($string, $index);
1001
+ return $substr;
1002
+ }
1003
+
1004
+ /**
1005
+ * RSA Encrypt
1006
+ *
1007
+ * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1008
+ * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
1009
+ * calls this call modexp, instead, but I think this makes things clearer, maybe...
1010
+ *
1011
+ * @see Net_SSH1::Net_SSH1()
1012
+ * @param Math_BigInteger $m
1013
+ * @param Array $key
1014
+ * @return Math_BigInteger
1015
+ * @access private
1016
+ */
1017
+ function _rsa_crypt($m, $key)
1018
+ {
1019
+ /*
1020
+ if (!class_exists('Crypt_RSA')) {
1021
+ require_once('Crypt/RSA.php');
1022
+ }
1023
+
1024
+ $rsa = new Crypt_RSA();
1025
+ $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
1026
+ $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
1027
+ return $rsa->encrypt($m);
1028
+ */
1029
+
1030
+ // To quote from protocol-1.5.txt:
1031
+ // The most significant byte (which is only partial as the value must be
1032
+ // less than the public modulus, which is never a power of two) is zero.
1033
+ //
1034
+ // The next byte contains the value 2 (which stands for public-key
1035
+ // encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
1036
+ // zero random bytes to fill any unused space, a zero byte, and the data
1037
+ // to be encrypted in the least significant bytes, the last byte of the
1038
+ // data in the least significant byte.
1039
+
1040
+ // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1041
+ // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1042
+ // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1043
+ $temp = chr(0) . chr(2);
1044
+ $modulus = $key[1]->toBytes();
1045
+ $length = strlen($modulus) - strlen($m) - 3;
1046
+ for ($i = 0; $i < $length; $i++) {
1047
+ $temp.= chr(crypt_random(1, 255));
1048
+ }
1049
+ $temp.= chr(0) . $m;
1050
+
1051
+ $m = new Math_BigInteger($temp, 256);
1052
+ $m = $m->modPow($key[0], $key[1]);
1053
+
1054
+ return $m->toBytes();
1055
+ }
1056
+
1057
+ /**
1058
+ * Return the server key public exponent
1059
+ *
1060
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1061
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1062
+ *
1063
+ * @param optional Boolean $raw_output
1064
+ * @return String
1065
+ * @access public
1066
+ */
1067
+ function getServerKeyPublicExponent($raw_output = false)
1068
+ {
1069
+ return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
1070
+ }
1071
+
1072
+ /**
1073
+ * Return the server key public modulus
1074
+ *
1075
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1076
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1077
+ *
1078
+ * @param optional Boolean $raw_output
1079
+ * @return String
1080
+ * @access public
1081
+ */
1082
+ function getServerKeyPublicModulus($raw_output = false)
1083
+ {
1084
+ return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
1085
+ }
1086
+
1087
+ /**
1088
+ * Return the host key public exponent
1089
+ *
1090
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1091
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1092
+ *
1093
+ * @param optional Boolean $raw_output
1094
+ * @return String
1095
+ * @access public
1096
+ */
1097
+ function getHostKeyPublicExponent($raw_output = false)
1098
+ {
1099
+ return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
1100
+ }
1101
+
1102
+ /**
1103
+ * Return the host key public modulus
1104
+ *
1105
+ * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1106
+ * the raw bytes. This behavior is similar to PHP's md5() function.
1107
+ *
1108
+ * @param optional Boolean $raw_output
1109
+ * @return String
1110
+ * @access public
1111
+ */
1112
+ function getHostKeyPublicModulus($raw_output = false)
1113
+ {
1114
+ return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
1115
+ }
1116
+
1117
+ /**
1118
+ * Return a list of ciphers supported by SSH1 server.
1119
+ *
1120
+ * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1121
+ * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
1122
+ * get array(NET_SSH1_CIPHER_3DES).
1123
+ *
1124
+ * @param optional Boolean $raw_output
1125
+ * @return Array
1126
+ * @access public
1127
+ */
1128
+ function getSupportedCiphers($raw_output = false)
1129
+ {
1130
+ return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
1131
+ }
1132
+
1133
+ /**
1134
+ * Return a list of authentications supported by SSH1 server.
1135
+ *
1136
+ * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1137
+ * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
1138
+ * get array(NET_SSH1_AUTH_PASSWORD).
1139
+ *
1140
+ * @param optional Boolean $raw_output
1141
+ * @return Array
1142
+ * @access public
1143
+ */
1144
+ function getSupportedAuthentications($raw_output = false)
1145
+ {
1146
+ return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
1147
+ }
1148
+
1149
+ /**
1150
+ * Return the server identification.
1151
+ *
1152
+ * @return String
1153
+ * @access public
1154
+ */
1155
+ function getServerIdentification()
1156
+ {
1157
+ return rtrim($this->server_identification);
1158
+ }
1159
+ }
lib/phpseclib/Net/SSH2.php ADDED
@@ -0,0 +1,2302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
+
4
+ /**
5
+ * Pure-PHP implementation of SSHv2.
6
+ *
7
+ * PHP versions 4 and 5
8
+ *
9
+ * Here are some examples of how to use this library:
10
+ * <code>
11
+ * <?php
12
+ * include('Net/SSH2.php');
13
+ *
14
+ * $ssh = new Net_SSH2('www.domain.tld');
15
+ * if (!$ssh->login('username', 'password')) {
16
+ * exit('Login Failed');
17
+ * }
18
+ *
19
+ * echo $ssh->exec('pwd');
20
+ * echo $ssh->exec('ls -la');
21
+ * ?>
22
+ * </code>
23
+ *
24
+ * <code>
25
+ * <?php
26
+ * include('Crypt/RSA.php');
27
+ * include('Net/SSH2.php');
28
+ *
29
+ * $key = new Crypt_RSA();
30
+ * //$key->setPassword('whatever');
31
+ * $key->loadKey(file_get_contents('privatekey'));
32
+ *
33
+ * $ssh = new Net_SSH2('www.domain.tld');
34
+ * if (!$ssh->login('username', $key)) {
35
+ * exit('Login Failed');
36
+ * }
37
+ *
38
+ * echo $ssh->exec('pwd');
39
+ * echo $ssh->exec('ls -la');
40
+ * ?>
41
+ * </code>
42
+ *
43
+ * LICENSE: This library is free software; you can redistribute it and/or
44
+ * modify it under the terms of the GNU Lesser General Public
45
+ * License as published by the Free Software Foundation; either
46
+ * version 2.1 of the License, or (at your option) any later version.
47
+ *
48
+ * This library is distributed in the hope that it will be useful,
49
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
50
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
51
+ * Lesser General Public License for more details.
52
+ *
53
+ * You should have received a copy of the GNU Lesser General Public
54
+ * License along with this library; if not, write to the Free Software
55
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
56
+ * MA 02111-1307 USA
57
+ *
58
+ * @category Net
59
+ * @package Net_SSH2
60
+ * @author Jim Wigginton <terrafrost@php.net>
61
+ * @copyright MMVII Jim Wigginton
62
+ * @license http://www.gnu.org/licenses/lgpl.txt
63
+ * @version $Id: SSH2.php,v 1.46 2010/04/27 21:29:36 terrafrost Exp $
64
+ * @link http://phpseclib.sourceforge.net
65
+ */
66
+
67
+ /**
68
+ * Include Math_BigInteger
69
+ *
70
+ * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
71
+ */
72
+ require_once('phpseclib/Math/BigInteger.php');
73
+
74
+ /**
75
+ * Include Crypt_Random
76
+ */
77
+ require_once('phpseclib/Crypt/Random.php');
78
+
79
+ /**
80
+ * Include Crypt_Hash
81
+ */
82
+ require_once('phpseclib/Crypt/Hash.php');
83
+
84
+ /**
85
+ * Include Crypt_TripleDES
86
+ */
87
+ require_once('phpseclib/Crypt/TripleDES.php');
88
+
89
+ /**
90
+ * Include Crypt_RC4
91
+ */
92
+ require_once('phpseclib/Crypt/RC4.php');
93
+
94
+ /**
95
+ * Include Crypt_AES
96
+ */
97
+ require_once('phpseclib/Crypt/AES.php');
98
+
99
+ /**#@+
100
+ * Execution Bitmap Masks
101
+ *
102
+ * @see Net_SSH2::bitmap
103
+ * @access private
104
+ */
105
+ define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
106
+ define('NET_SSH2_MASK_LOGIN', 0x00000002);
107
+ /**#@-*/
108
+
109
+ /**#@+
110
+ * Channel constants
111
+ *
112
+ * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer
113
+ * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
114
+ * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
115
+ * recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
116
+ * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet:
117
+ * The 'recipient channel' is the channel number given in the original
118
+ * open request, and 'sender channel' is the channel number allocated by
119
+ * the other side.
120
+ *
121
+ * @see Net_SSH2::_send_channel_packet()
122
+ * @see Net_SSH2::_get_channel_packet()
123
+ * @access private
124
+ */
125
+ define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
126
+ /**#@-*/
127
+
128
+ /**#@+
129
+ * @access public
130
+ * @see Net_SSH2::getLog()
131
+ */
132
+ /**
133
+ * Returns the message numbers
134
+ */
135
+ define('NET_SSH2_LOG_SIMPLE', 1);
136
+ /**
137
+ * Returns the message content
138
+ */
139
+ define('NET_SSH2_LOG_COMPLEX', 2);
140
+ /**#@-*/
141
+
142
+ /**
143
+ * Pure-PHP implementation of SSHv2.
144
+ *
145
+ * @author Jim Wigginton <terrafrost@php.net>
146
+ * @version 0.1.0
147
+ * @access public
148
+ * @package Net_SSH2
149
+ */
150
+ class Net_SSH2 {
151
+ /**
152
+ * The SSH identifier
153
+ *
154
+ * @var String
155
+ * @access private
156
+ */
157
+ var $identifier = 'SSH-2.0-phpseclib_0.2';
158
+
159
+ /**
160
+ * The Socket Object
161
+ *
162
+ * @var Object
163
+ * @access private
164
+ */
165
+ var $fsock;
166
+
167
+ /**
168
+ * Execution Bitmap
169
+ *
170
+ * The bits that are set reprsent functions that have been called already. This is used to determine
171
+ * if a requisite function has been successfully executed. If not, an error should be thrown.
172
+ *
173
+ * @var Integer
174
+ * @access private
175
+ */
176
+ var $bitmap = 0;
177
+
178
+ /**
179
+ * Error information
180
+ *
181
+ * @see Net_SSH2::getErrors()
182
+ * @see Net_SSH2::getLastError()
183
+ * @var String
184
+ * @access private
185
+ */
186
+ var $errors = array();
187
+
188
+ /**
189
+ * Server Identifier
190
+ *
191
+ * @see Net_SSH2::getServerIdentification()
192
+ * @var String
193
+ * @access private
194
+ */
195
+ var $server_identifier = '';
196
+
197
+ /**
198
+ * Key Exchange Algorithms
199
+ *
200
+ * @see Net_SSH2::getKexAlgorithims()
201
+ * @var Array
202
+ * @access private
203
+ */
204
+ var $kex_algorithms;
205
+
206
+ /**
207
+ * Server Host Key Algorithms
208
+ *
209
+ * @see Net_SSH2::getServerHostKeyAlgorithms()
210
+ * @var Array
211
+ * @access private
212
+ */
213
+ var $server_host_key_algorithms;
214
+
215
+ /**
216
+ * Encryption Algorithms: Client to Server
217
+ *
218
+ * @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
219
+ * @var Array
220
+ * @access private
221
+ */
222
+ var $encryption_algorithms_client_to_server;
223
+
224
+ /**
225
+ * Encryption Algorithms: Server to Client
226
+ *
227
+ * @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
228
+ * @var Array
229
+ * @access private
230
+ */
231
+ var $encryption_algorithms_server_to_client;
232
+
233
+ /**
234
+ * MAC Algorithms: Client to Server
235
+ *
236
+ * @see Net_SSH2::getMACAlgorithmsClient2Server()
237
+ * @var Array
238
+ * @access private
239
+ */
240
+ var $mac_algorithms_client_to_server;
241
+
242
+ /**
243
+ * MAC Algorithms: Server to Client
244
+ *
245
+ * @see Net_SSH2::getMACAlgorithmsServer2Client()
246
+ * @var Array
247
+ * @access private
248
+ */
249
+ var $mac_algorithms_server_to_client;
250
+
251
+ /**
252
+ * Compression Algorithms: Client to Server
253
+ *
254
+ * @see Net_SSH2::getCompressionAlgorithmsClient2Server()
255
+ * @var Array
256
+ * @access private
257
+ */
258
+ var $compression_algorithms_client_to_server;
259
+
260
+ /**
261
+ * Compression Algorithms: Server to Client
262
+ *
263
+ * @see Net_SSH2::getCompressionAlgorithmsServer2Client()
264
+ * @var Array
265
+ * @access private
266
+ */
267
+ var $compression_algorithms_server_to_client;
268
+
269
+ /**
270
+ * Languages: Server to Client
271
+ *
272
+ * @see Net_SSH2::getLanguagesServer2Client()
273
+ * @var Array
274
+ * @access private
275
+ */
276
+ var $languages_server_to_client;
277
+
278
+ /**
279
+ * Languages: Client to Server
280
+ *
281
+ * @see Net_SSH2::getLanguagesClient2Server()
282
+ * @var Array
283
+ * @access private
284
+ */
285
+ var $languages_client_to_server;
286
+
287
+ /**
288
+ * Block Size for Server to Client Encryption
289
+ *
290
+ * "Note that the length of the concatenation of 'packet_length',
291
+ * 'padding_length', 'payload', and 'random padding' MUST be a multiple
292
+ * of the cipher block size or 8, whichever is larger. This constraint
293
+ * MUST be enforced, even when using stream ciphers."
294
+ *
295
+ * -- http://tools.ietf.org/html/rfc4253#section-6
296
+ *
297
+ * @see Net_SSH2::Net_SSH2()
298
+ * @see Net_SSH2::_send_binary_packet()
299
+ * @var Integer
300
+ * @access private
301
+ */
302
+ var $encrypt_block_size = 8;
303
+
304
+ /**
305
+ * Block Size for Client to Server Encryption
306
+ *
307
+ * @see Net_SSH2::Net_SSH2()
308
+ * @see Net_SSH2::_get_binary_packet()
309
+ * @var Integer
310
+ * @access private
311
+ */
312
+ var $decrypt_block_size = 8;
313
+
314
+ /**
315
+ * Server to Client Encryption Object
316
+ *
317
+ * @see Net_SSH2::_get_binary_packet()
318
+ * @var Object
319
+ * @access private
320
+ */
321
+ var $decrypt = false;
322
+
323
+ /**
324
+ * Client to Server Encryption Object
325
+ *
326
+ * @see Net_SSH2::_send_binary_packet()
327
+ * @var Object
328
+ * @access private
329
+ */
330
+ var $encrypt = false;
331
+
332
+ /**
333
+ * Client to Server HMAC Object
334
+ *
335
+ * @see Net_SSH2::_send_binary_packet()
336
+ * @var Object
337
+ * @access private
338
+ */
339
+ var $hmac_create = false;
340
+
341
+ /**
342
+ * Server to Client HMAC Object
343
+ *
344
+ * @see Net_SSH2::_get_binary_packet()
345
+ * @var Object
346
+ * @access private
347
+ */
348
+ var $hmac_check = false;
349
+
350
+ /**
351
+ * Size of server to client HMAC
352
+ *
353
+ * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
354
+ * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
355
+ * append it.
356
+ *
357
+ * @see Net_SSH2::_get_binary_packet()
358
+ * @var Integer
359
+ * @access private
360
+ */
361
+ var $hmac_size = false;
362
+
363
+ /**
364
+ * Server Public Host Key
365
+ *
366
+ * @see Net_SSH2::getServerPublicHostKey()
367
+ * @var String
368
+ * @access private
369
+ */
370
+ var $server_public_host_key;
371
+
372
+ /**
373
+ * Session identifer
374
+ *
375
+ * "The exchange hash H from the first key exchange is additionally
376
+ * used as the session identifier, which is a unique identifier for
377
+ * this connection."
378
+ *
379
+ * -- http://tools.ietf.org/html/rfc4253#section-7.2
380
+ *
381
+ * @see Net_SSH2::_key_exchange()
382
+ * @var String
383
+ * @access private
384
+ */
385
+ var $session_id = false;
386
+
387
+ /**
388
+ * Message Numbers
389
+ *
390
+ * @see Net_SSH2::Net_SSH2()
391
+ * @var Array
392
+ * @access private
393
+ */
394
+ var $message_numbers = array();
395
+
396
+ /**
397
+ * Disconnection Message 'reason codes' defined in RFC4253
398
+ *
399
+ * @see Net_SSH2::Net_SSH2()
400
+ * @var Array
401
+ * @access private
402
+ */
403
+ var $disconnect_reasons = array();
404
+
405
+ /**
406
+ * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
407
+ *
408
+ * @see Net_SSH2::Net_SSH2()
409
+ * @var Array
410
+ * @access private
411
+ */
412
+ var $channel_open_failure_reasons = array();
413
+
414
+ /**
415
+ * Terminal Modes
416
+ *
417
+ * @link http://tools.ietf.org/html/rfc4254#section-8
418
+ * @see Net_SSH2::Net_SSH2()
419
+ * @var Array
420
+ * @access private
421
+ */
422
+ var $terminal_modes = array();
423
+
424
+ /**
425
+ * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
426
+ *
427
+ * @link http://tools.ietf.org/html/rfc4254#section-5.2
428
+ * @see Net_SSH2::Net_SSH2()
429
+ * @var Array
430
+ * @access private
431
+ */
432
+ var $channel_extended_data_type_codes = array();
433
+
434
+ /**
435
+ * Send Sequence Number
436
+ *
437
+ * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
438
+ *
439
+ * @see Net_SSH2::_send_binary_packet()
440
+ * @var Integer
441
+ * @access private
442
+ */
443
+ var $send_seq_no = 0;
444
+
445
+ /**
446
+ * Get Sequence Number
447
+ *
448
+ * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
449
+ *
450
+ * @see Net_SSH2::_get_binary_packet()
451
+ * @var Integer
452
+ * @access private
453
+ */
454
+ var $get_seq_no = 0;
455
+
456
+ /**
457
+ * Server Channels
458
+ *
459
+ * Maps client channels to server channels
460
+ *
461
+ * @see Net_SSH2::_get_channel_packet()
462
+ * @see Net_SSH2::exec()
463
+ * @var Array
464
+ * @access private
465
+ */
466
+ var $server_channels = array();
467
+
468
+ /**
469
+ * Channel Buffers
470
+ *
471
+ * If a client requests a packet from one channel but receives two packets from another those packets should
472
+ * be placed in a buffer
473
+ *
474
+ * @see Net_SSH2::_get_channel_packet()
475
+ * @see Net_SSH2::exec()
476
+ * @var Array
477
+ * @access private
478
+ */
479
+ var $channel_buffers = array();
480
+
481
+ /**
482
+ * Channel Status
483
+ *
484
+ * Contains the type of the last sent message
485
+ *
486
+ * @see Net_SSH2::_get_channel_packet()
487
+ * @var Array
488
+ * @access private
489
+ */
490
+ var $channel_status = array();
491
+
492
+ /**
493
+ * Packet Size
494
+ *
495
+ * Maximum packet size indexed by channel
496
+ *
497
+ * @see Net_SSH2::_send_channel_packet()
498
+ * @var Array
499
+ * @access private
500
+ */
501
+ var $packet_size_client_to_server = array();
502
+
503
+ /**
504
+ * Message Number Log
505
+ *
506
+ * @see Net_SSH2::getLog()
507
+ * @var Array
508
+ * @access private
509
+ */
510
+ var $message_number_log = array();
511
+
512
+ /**
513
+ * Message Log
514
+ *
515
+ * @see Net_SSH2::getLog()
516
+ * @var Array
517
+ * @access private
518
+ */
519
+ var $message_log = array();
520
+
521
+ /**
522
+ * The Window Size
523
+ *
524
+ * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 4GB)
525
+ *
526
+ * @var Integer
527
+ * @see Net_SSH2::_send_channel_packet()
528
+ * @see Net_SSH2::exec()
529
+ * @access private
530
+ */
531
+ var $window_size = 0x7FFFFFFF;
532
+
533
+ /**
534
+ * Window size
535
+ *
536
+ * Window size indexed by channel
537
+ *
538
+ * @see Net_SSH2::_send_channel_packet()
539
+ * @var Array
540
+ * @access private
541
+ */
542
+ var $window_size_client_to_server = array();
543
+
544
+ /**
545
+ * Server signature
546
+ *
547
+ * Verified against $this->session_id
548
+ *
549
+ * @see Net_SSH2::getServerPublicHostKey()
550
+ * @var String
551
+ * @access private
552
+ */
553
+ var $signature = '';
554
+
555
+ /**
556
+ * Server signature format
557
+ *
558
+ * ssh-rsa or ssh-dss.
559
+ *
560
+ * @see Net_SSH2::getServerPublicHostKey()
561
+ * @var String
562
+ * @access private
563
+ */
564
+ var $signature_format = '';
565
+
566
+ /**
567
+ * Default Constructor.
568
+ *
569
+ * Connects to an SSHv2 server
570
+ *
571
+ * @param String $host
572
+ * @param optional Integer $port
573
+ * @param optional Integer $timeout
574
+ * @return Net_SSH2
575
+ * @access public
576
+ */
577
+ function Net_SSH2($host, $port = 22, $timeout = 10)
578
+ {
579
+ $this->message_numbers = array(
580
+ 1 => 'NET_SSH2_MSG_DISCONNECT',
581
+ 2 => 'NET_SSH2_MSG_IGNORE',
582
+ 3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
583
+ 4 => 'NET_SSH2_MSG_DEBUG',
584
+ 5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
585
+ 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
586
+ 20 => 'NET_SSH2_MSG_KEXINIT',
587
+ 21 => 'NET_SSH2_MSG_NEWKEYS',
588
+ 30 => 'NET_SSH2_MSG_KEXDH_INIT',
589
+ 31 => 'NET_SSH2_MSG_KEXDH_REPLY',
590
+ 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
591
+ 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
592
+ 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
593
+ 53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
594
+
595
+ 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
596
+ 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
597
+ 82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
598
+ 90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
599
+ 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
600
+ 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
601
+ 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
602
+ 94 => 'NET_SSH2_MSG_CHANNEL_DATA',
603
+ 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
604
+ 96 => 'NET_SSH2_MSG_CHANNEL_EOF',
605
+ 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
606
+ 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
607
+ 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
608
+ 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
609
+ );
610
+ $this->disconnect_reasons = array(
611
+ 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
612
+ 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
613
+ 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
614
+ 4 => 'NET_SSH2_DISCONNECT_RESERVED',
615
+ 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
616
+ 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
617
+ 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
618
+ 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
619
+ 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
620
+ 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
621
+ 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
622
+ 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
623
+ 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
624
+ 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
625
+ 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
626
+ );
627
+ $this->channel_open_failure_reasons = array(
628
+ 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
629
+ );
630
+ $this->terminal_modes = array(
631
+ 0 => 'NET_SSH2_TTY_OP_END'
632
+ );
633
+ $this->channel_extended_data_type_codes = array(
634
+ 1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
635
+ );
636
+
637
+ $this->_define_array(
638
+ $this->message_numbers,
639
+ $this->disconnect_reasons,
640
+ $this->channel_open_failure_reasons,
641
+ $this->terminal_modes,
642
+ $this->channel_extended_data_type_codes,
643
+ array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
644
+ array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK')
645
+ );
646
+
647
+ $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
648
+ if (!$this->fsock) {
649
+ user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
650
+ return;
651
+ }
652
+
653
+ /* According to the SSH2 specs,
654
+
655
+ "The server MAY send other lines of data before sending the version
656
+ string. Each line SHOULD be terminated by a Carriage Return and Line
657
+ Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
658
+ in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
659
+ MUST be able to process such lines." */
660
+ $temp = '';
661
+ $extra = '';
662
+ while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
663
+ if (substr($temp, -2) == "\r\n") {
664
+ $extra.= $temp;
665
+ $temp = '';
666
+ }
667
+ $temp.= fgets($this->fsock, 255);
668
+ }
669
+
670
+ $ext = array();
671
+ if (extension_loaded('mcrypt')) {
672
+ $ext[] = 'mcrypt';
673
+ }
674
+ if (extension_loaded('gmp')) {
675
+ $ext[] = 'gmp';
676
+ } else if (extension_loaded('bcmath')) {
677
+ $ext[] = 'bcmath';
678
+ }
679
+
680
+ if (!empty($ext)) {
681
+ $this->identifier.= ' (' . implode(', ', $ext) . ')';
682
+ }
683
+
684
+ if (defined('NET_SSH2_LOGGING')) {
685
+ $this->message_number_log[] = '<-';
686
+ $this->message_number_log[] = '->';
687
+
688
+ if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
689
+ $this->message_log[] = $temp;
690
+ $this->message_log[] = $this->identifier . "\r\n";
691
+ }
692
+ }
693
+
694
+ $this->server_identifier = trim($temp, "\r\n");
695
+ if (!empty($extra)) {
696
+ $this->errors[] = utf8_decode($extra);
697
+ }
698
+
699
+ if ($matches[1] != '1.99' && $matches[1] != '2.0') {
700
+ user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE);
701
+ return;
702
+ }
703
+
704
+ fputs($this->fsock, $this->identifier . "\r\n");
705
+
706
+ $response = $this->_get_binary_packet();
707
+ if ($response === false) {
708
+ user_error('Connection closed by server', E_USER_NOTICE);
709
+ return;
710
+ }
711
+
712
+ if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
713
+ user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE);
714
+ return;
715
+ }
716
+
717
+ if (!$this->_key_exchange($response)) {
718
+ return;
719
+ }
720
+
721
+ $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR;
722
+ }
723
+
724
+ /**
725
+ * Key Exchange
726
+ *
727
+ * @param String $kexinit_payload_server
728
+ * @access private
729
+ */
730
+ function _key_exchange($kexinit_payload_server)
731
+ {
732
+ static $kex_algorithms = array(
733
+ 'diffie-hellman-group1-sha1', // REQUIRED
734
+ 'diffie-hellman-group14-sha1' // REQUIRED
735
+ );
736
+
737
+ static $server_host_key_algorithms = array(
738
+ 'ssh-rsa', // RECOMMENDED sign Raw RSA Key
739
+ 'ssh-dss' // REQUIRED sign Raw DSS Key
740
+ );
741
+
742
+ static $encryption_algorithms = array(
743
+ // from <http://tools.ietf.org/html/rfc4345#section-4>:
744
+ 'arcfour256',
745
+ 'arcfour128',
746
+
747
+ 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
748
+
749
+ 'aes128-cbc', // RECOMMENDED AES with a 128-bit key
750
+ 'aes192-cbc', // OPTIONAL AES with a 192-bit key
751
+ 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
752
+
753
+ // from <http://tools.ietf.org/html/rfc4344#section-4>:
754
+ 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
755
+ 'aes192-ctr', // RECOMMENDED AES with 192-bit key
756
+ 'aes256-ctr', // RECOMMENDED AES with 256-bit key
757
+ '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
758
+
759
+ '3des-cbc', // REQUIRED three-key 3DES in CBC mode
760
+ 'none' // OPTIONAL no encryption; NOT RECOMMENDED
761
+ );
762
+
763
+ static $mac_algorithms = array(
764
+ 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
765
+ 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
766
+ 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
767
+ 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
768
+ 'none' // OPTIONAL no MAC; NOT RECOMMENDED
769
+ );
770
+
771
+ static $compression_algorithms = array(
772
+ 'none' // REQUIRED no compression
773
+ //'zlib' // OPTIONAL ZLIB (LZ77) compression
774
+ );
775
+
776
+ static $str_kex_algorithms, $str_server_host_key_algorithms,
777
+ $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
778
+ $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
779
+
780
+ if (empty($str_kex_algorithms)) {
781
+ $str_kex_algorithms = implode(',', $kex_algorithms);
782
+ $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
783
+ $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
784
+ $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
785
+ $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
786
+ }
787
+
788
+ $client_cookie = '';
789
+ for ($i = 0; $i < 16; $i++) {
790
+ $client_cookie.= chr(crypt_random(0, 255));
791
+ }
792
+
793
+ $response = $kexinit_payload_server;
794
+ $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
795
+ $server_cookie = $this->_string_shift($response, 16);
796
+
797
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
798
+ $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
799
+
800
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
801
+ $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
802
+
803
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
804
+ $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
805
+
806
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
807
+ $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
808
+
809
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
810
+ $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
811
+
812
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
813
+ $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
814
+
815
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
816
+ $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
817
+
818
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
819
+ $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
820
+
821
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
822
+ $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
823
+
824
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
825
+ $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
826
+
827
+ extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
828
+ $first_kex_packet_follows = $first_kex_packet_follows != 0;
829
+
830
+ // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
831
+ $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
832
+ NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms,
833
+ strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server),
834
+ $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client,
835
+ strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client),
836
+ $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server,
837
+ strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '',
838
+ 0, 0
839
+ );
840
+
841
+ if (!$this->_send_binary_packet($kexinit_payload_client)) {
842
+ return false;
843
+ }
844
+ // here ends the second place.
845
+
846
+ // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
847
+ for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
848
+ if ($i == count($encryption_algorithms)) {
849
+ user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
850
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
851
+ }
852
+
853
+ // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
854
+ // diffie-hellman key exchange as fast as possible
855
+ $decrypt = $encryption_algorithms[$i];
856
+ switch ($decrypt) {
857
+ case '3des-cbc':
858
+ case '3des-ctr':
859
+ $decryptKeyLength = 24; // eg. 192 / 8
860
+ break;
861
+ case 'aes256-cbc':
862
+ case 'aes256-ctr':
863
+ $decryptKeyLength = 32; // eg. 256 / 8
864
+ break;
865
+ case 'aes192-cbc':
866
+ case 'aes192-ctr':
867
+ $decryptKeyLength = 24; // eg. 192 / 8
868
+ break;
869
+ case 'aes128-cbc':
870
+ case 'aes128-ctr':
871
+ $decryptKeyLength = 16; // eg. 128 / 8
872
+ break;
873
+ case 'arcfour':
874
+ case 'arcfour128':
875
+ $decryptKeyLength = 16; // eg. 128 / 8
876
+ break;
877
+ case 'arcfour256':
878
+ $decryptKeyLength = 32; // eg. 128 / 8
879
+ break;
880
+ case 'none';
881
+ $decryptKeyLength = 0;
882
+ }
883
+
884
+ for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
885
+ if ($i == count($encryption_algorithms)) {
886
+ user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
887
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
888
+ }
889
+
890
+ $encrypt = $encryption_algorithms[$i];
891
+ switch ($encrypt) {
892
+ case '3des-cbc':
893
+ case '3des-ctr':
894
+ $encryptKeyLength = 24;
895
+ break;
896
+ case 'aes256-cbc':
897
+ case 'aes256-ctr':
898
+ $encryptKeyLength = 32;
899
+ break;
900
+ case 'aes192-cbc':
901
+ case 'aes192-ctr':
902
+ $encryptKeyLength = 24;
903
+ break;
904
+ case 'aes128-cbc':
905
+ case 'aes128-ctr':
906
+ $encryptKeyLength = 16;
907
+ break;
908
+ case 'arcfour':
909
+ case 'arcfour128':
910
+ $encryptKeyLength = 16;
911
+ break;
912
+ case 'arcfour256':
913
+ $encryptKeyLength = 32;
914
+ break;
915
+ case 'none';
916
+ $encryptKeyLength = 0;
917
+ }
918
+
919
+ $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
920
+
921
+ // through diffie-hellman key exchange a symmetric key is obtained
922
+ for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
923
+ if ($i == count($kex_algorithms)) {
924
+ user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
925
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
926
+ }
927
+
928
+ switch ($kex_algorithms[$i]) {
929
+ // see http://tools.ietf.org/html/rfc2409#section-6.2 and
930
+ // http://tools.ietf.org/html/rfc2412, appendex E
931
+ case 'diffie-hellman-group1-sha1':
932
+ $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
933
+ '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
934
+ '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
935
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF');
936
+ $keyLength = $keyLength < 160 ? $keyLength : 160;
937
+ $hash = 'sha1';
938
+ break;
939
+ // see http://tools.ietf.org/html/rfc3526#section-3
940
+ case 'diffie-hellman-group14-sha1':
941
+ $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
942
+ '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
943
+ '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
944
+ 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
945
+ '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
946
+ '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
947
+ 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
948
+ '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF');
949
+ $keyLength = $keyLength < 160 ? $keyLength : 160;
950
+ $hash = 'sha1';
951
+ }
952
+
953
+ $p = new Math_BigInteger($p, 256);
954
+ //$q = $p->bitwise_rightShift(1);
955
+
956
+ /* To increase the speed of the key exchange, both client and server may
957
+ reduce the size of their private exponents. It should be at least
958
+ twice as long as the key material that is generated from the shared
959
+ secret. For more details, see the paper by van Oorschot and Wiener
960
+ [VAN-OORSCHOT].
961
+
962
+ -- http://tools.ietf.org/html/rfc4419#section-6.2 */
963
+ $q = new Math_BigInteger(1);
964
+ $q = $q->bitwise_leftShift(2 * $keyLength);
965
+ $q = $q->subtract(new Math_BigInteger(1));
966
+
967
+ $g = new Math_BigInteger(2);
968
+ $x = new Math_BigInteger();
969
+ $x->setRandomGenerator('crypt_random');
970
+ $x = $x->random(new Math_BigInteger(1), $q);
971
+ $e = $g->modPow($x, $p);
972
+
973
+ $eBytes = $e->toBytes(true);
974
+ $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
975
+
976
+ if (!$this->_send_binary_packet($data)) {
977
+ user_error('Connection closed by server', E_USER_NOTICE);
978
+ return false;
979
+ }
980
+
981
+ $response = $this->_get_binary_packet();
982
+ if ($response === false) {
983
+ user_error('Connection closed by server', E_USER_NOTICE);
984
+ return false;
985
+ }
986
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
987
+
988
+ if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
989
+ user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
990
+ return false;
991
+ }
992
+
993
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
994
+ $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
995
+
996
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
997
+ $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
998
+
999
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
1000
+ $fBytes = $this->_string_shift($response, $temp['length']);
1001
+ $f = new Math_BigInteger($fBytes, -256);
1002
+
1003
+ $temp = unpack('Nlength', $this->_string_shift($response, 4));
1004
+ $this->signature = $this->_string_shift($response, $temp['length']);
1005
+
1006
+ $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
1007
+ $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
1008
+
1009
+ $key = $f->modPow($x, $p);
1010
+ $keyBytes = $key->toBytes(true);
1011
+
1012
+ if ($this->session_id === false) {
1013
+ $source = pack('Na*Na*Na*Na*Na*Na*Na*Na*',
1014
+ strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier,
1015
+ strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server),
1016
+ $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes),
1017
+ $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes
1018
+ );
1019
+
1020
+ $source = pack('H*', $hash($source));
1021
+
1022
+ $this->session_id = $source;
1023
+ }
1024
+
1025
+ for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
1026
+ if ($i == count($server_host_key_algorithms)) {
1027
+ user_error('No compatible server host key algorithms found', E_USER_NOTICE);
1028
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1029
+ }
1030
+
1031
+ if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
1032
+ user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
1033
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1034
+ }
1035
+
1036
+ $packet = pack('C',
1037
+ NET_SSH2_MSG_NEWKEYS
1038
+ );
1039
+
1040
+ if (!$this->_send_binary_packet($packet)) {
1041
+ return false;
1042
+ }
1043
+
1044
+ $response = $this->_get_binary_packet();
1045
+
1046
+ if ($response === false) {
1047
+ user_error('Connection closed by server', E_USER_NOTICE);
1048
+ return false;
1049
+ }
1050
+
1051
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
1052
+
1053
+ if ($type != NET_SSH2_MSG_NEWKEYS) {
1054
+ user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
1055
+ return false;
1056
+ }
1057
+
1058
+ switch ($encrypt) {
1059
+ case '3des-cbc':
1060
+ $this->encrypt = new Crypt_TripleDES();
1061
+ // $this->encrypt_block_size = 64 / 8 == the default
1062
+ break;
1063
+ case '3des-ctr':
1064
+ $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
1065
+ // $this->encrypt_block_size = 64 / 8 == the default
1066
+ break;
1067
+ case 'aes256-cbc':
1068
+ case 'aes192-cbc':
1069
+ case 'aes128-cbc':
1070
+ $this->encrypt = new Crypt_AES();
1071
+ $this->encrypt_block_size = 16; // eg. 128 / 8
1072
+ break;
1073
+ case 'aes256-ctr':
1074
+ case 'aes192-ctr':
1075
+ case 'aes128-ctr':
1076
+ $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
1077
+ $this->encrypt_block_size = 16; // eg. 128 / 8
1078
+ break;
1079
+ case 'arcfour':
1080
+ case 'arcfour128':
1081
+ case 'arcfour256':
1082
+ $this->encrypt = new Crypt_RC4();
1083
+ break;
1084
+ case 'none';
1085
+ //$this->encrypt = new Crypt_Null();
1086
+ }
1087
+
1088
+ switch ($decrypt) {
1089
+ case '3des-cbc':
1090
+ $this->decrypt = new Crypt_TripleDES();
1091
+ break;
1092
+ case '3des-ctr':
1093
+ $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
1094
+ break;
1095
+ case 'aes256-cbc':
1096
+ case 'aes192-cbc':
1097
+ case 'aes128-cbc':
1098
+ $this->decrypt = new Crypt_AES();
1099
+ $this->decrypt_block_size = 16;
1100
+ break;
1101
+ case 'aes256-ctr':
1102
+ case 'aes192-ctr':
1103
+ case 'aes128-ctr':
1104
+ $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
1105
+ $this->decrypt_block_size = 16;
1106
+ break;
1107
+ case 'arcfour':
1108
+ case 'arcfour128':
1109
+ case 'arcfour256':
1110
+ $this->decrypt = new Crypt_RC4();
1111
+ break;
1112
+ case 'none';
1113
+ //$this->decrypt = new Crypt_Null();
1114
+ }
1115
+
1116
+ $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
1117
+
1118
+ if ($this->encrypt) {
1119
+ $this->encrypt->enableContinuousBuffer();
1120
+ $this->encrypt->disablePadding();
1121
+
1122
+ $iv = pack('H*', $hash($keyBytes . $this->session_id . 'A' . $this->session_id));
1123
+ while ($this->encrypt_block_size > strlen($iv)) {
1124
+ $iv.= pack('H*', $hash($keyBytes . $this->session_id . $iv));
1125
+ }
1126
+ $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
1127
+
1128
+ $key = pack('H*', $hash($keyBytes . $this->session_id . 'C' . $this->session_id));
1129
+ while ($encryptKeyLength > strlen($key)) {
1130
+ $key.= pack('H*', $hash($keyBytes . $this->session_id . $key));
1131
+ }
1132
+ $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
1133
+ }
1134
+
1135
+ if ($this->decrypt) {
1136
+ $this->decrypt->enableContinuousBuffer();
1137
+ $this->decrypt->disablePadding();
1138
+
1139
+ $iv = pack('H*', $hash($keyBytes . $this->session_id . 'B' . $this->session_id));
1140
+ while ($this->decrypt_block_size > strlen($iv)) {
1141
+ $iv.= pack('H*', $hash($keyBytes . $this->session_id . $iv));
1142
+ }
1143
+ $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
1144
+
1145
+ $key = pack('H*', $hash($keyBytes . $this->session_id . 'D' . $this->session_id));
1146
+ while ($decryptKeyLength > strlen($key)) {
1147
+ $key.= pack('H*', $hash($keyBytes . $this->session_id . $key));
1148
+ }
1149
+ $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
1150
+ }
1151
+
1152
+ /* The "arcfour128" algorithm is the RC4 cipher, as described in
1153
+ [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
1154
+ generated by the cipher MUST be discarded, and the first byte of the
1155
+ first encrypted packet MUST be encrypted using the 1537th byte of
1156
+ keystream.
1157
+
1158
+ -- http://tools.ietf.org/html/rfc4345#section-4 */
1159
+ if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
1160
+ $this->encrypt->encrypt(str_repeat("\0", 1536));
1161
+ }
1162
+ if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
1163
+ $this->decrypt->decrypt(str_repeat("\0", 1536));
1164
+ }
1165
+
1166
+ for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
1167
+ if ($i == count($mac_algorithms)) {
1168
+ user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
1169
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1170
+ }
1171
+
1172
+ $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
1173
+ switch ($mac_algorithms[$i]) {
1174
+ case 'hmac-sha1':
1175
+ $this->hmac_create = new Crypt_Hash('sha1');
1176
+ $createKeyLength = 20;
1177
+ break;
1178
+ case 'hmac-sha1-96':
1179
+ $this->hmac_create = new Crypt_Hash('sha1-96');
1180
+ $createKeyLength = 20;
1181
+ break;
1182
+ case 'hmac-md5':
1183
+ $this->hmac_create = new Crypt_Hash('md5');
1184
+ $createKeyLength = 16;
1185
+ break;
1186
+ case 'hmac-md5-96':
1187
+ $this->hmac_create = new Crypt_Hash('md5-96');
1188
+ $createKeyLength = 16;
1189
+ }
1190
+
1191
+ for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
1192
+ if ($i == count($mac_algorithms)) {
1193
+ user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
1194
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1195
+ }
1196
+
1197
+ $checkKeyLength = 0;
1198
+ $this->hmac_size = 0;
1199
+ switch ($mac_algorithms[$i]) {
1200
+ case 'hmac-sha1':
1201
+ $this->hmac_check = new Crypt_Hash('sha1');
1202
+ $checkKeyLength = 20;
1203
+ $this->hmac_size = 20;
1204
+ break;
1205
+ case 'hmac-sha1-96':
1206
+ $this->hmac_check = new Crypt_Hash('sha1-96');
1207
+ $checkKeyLength = 20;
1208
+ $this->hmac_size = 12;
1209
+ break;
1210
+ case 'hmac-md5':
1211
+ $this->hmac_check = new Crypt_Hash('md5');
1212
+ $checkKeyLength = 16;
1213
+ $this->hmac_size = 16;
1214
+ break;
1215
+ case 'hmac-md5-96':
1216
+ $this->hmac_check = new Crypt_Hash('md5-96');
1217
+ $checkKeyLength = 16;
1218
+ $this->hmac_size = 12;
1219
+ }
1220
+
1221
+ $key = pack('H*', $hash($keyBytes . $this->session_id . 'E' . $this->session_id));
1222
+ while ($createKeyLength > strlen($key)) {
1223
+ $key.= pack('H*', $hash($keyBytes . $this->session_id . $key));
1224
+ }
1225
+ $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
1226
+
1227
+ $key = pack('H*', $hash($keyBytes . $this->session_id . 'F' . $this->session_id));
1228
+ while ($checkKeyLength > strlen($key)) {
1229
+ $key.= pack('H*', $hash($keyBytes . $this->session_id . $key));
1230
+ }
1231
+ $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
1232
+
1233
+ for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
1234
+ if ($i == count($compression_algorithms)) {
1235
+ user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
1236
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1237
+ }
1238
+ $this->decompress = $compression_algorithms[$i] == 'zlib';
1239
+
1240
+ for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
1241
+ if ($i == count($compression_algorithms)) {
1242
+ user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
1243
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1244
+ }
1245
+ $this->compress = $compression_algorithms[$i] == 'zlib';
1246
+
1247
+ return true;
1248
+ }
1249
+
1250
+ /**
1251
+ * Login
1252
+ *
1253
+ * @param String $username
1254
+ * @param optional String $password
1255
+ * @return Boolean
1256
+ * @access public
1257
+ * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
1258
+ * by sending dummy SSH_MSG_IGNORE messages.
1259
+ */
1260
+ function login($username, $password = '')
1261
+ {
1262
+ if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
1263
+ return false;
1264
+ }
1265
+
1266
+ $packet = pack('CNa*',
1267
+ NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth'
1268
+ );
1269
+
1270
+ if (!$this->_send_binary_packet($packet)) {
1271
+ return false;
1272
+ }
1273
+
1274
+ $response = $this->_get_binary_packet();
1275
+ if ($response === false) {
1276
+ user_error('Connection closed by server', E_USER_NOTICE);
1277
+ return false;
1278
+ }
1279
+
1280
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
1281
+
1282
+ if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
1283
+ user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE);
1284
+ return false;
1285
+ }
1286
+
1287
+ // although PHP5's get_class() preserves the case, PHP4's does not
1288
+ if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') {
1289
+ return $this->_privatekey_login($username, $password);
1290
+ }
1291
+
1292
+ $utf8_password = utf8_encode($password);
1293
+ $packet = pack('CNa*Na*Na*CNa*',
1294
+ NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
1295
+ strlen('password'), 'password', 0, strlen($utf8_password), $utf8_password
1296
+ );
1297
+
1298
+ if (!$this->_send_binary_packet($packet)) {
1299
+ return false;
1300
+ }
1301
+
1302
+ // remove the username and password from the last logged packet
1303
+ if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
1304
+ $packet = pack('CNa*Na*Na*CNa*',
1305
+ NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection',
1306
+ strlen('password'), 'password', 0, strlen('password'), 'password'
1307
+ );
1308
+ $this->message_log[count($this->message_log) - 1] = $packet;
1309
+ }
1310
+
1311
+ $response = $this->_get_binary_packet();
1312
+ if ($response === false) {
1313
+ user_error('Connection closed by server', E_USER_NOTICE);
1314
+ return false;
1315
+ }
1316
+
1317
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
1318
+
1319
+ switch ($type) {
1320
+ case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
1321
+ if (defined('NET_SSH2_LOGGING')) {
1322
+ $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
1323
+ }
1324
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1325
+ $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
1326
+ return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
1327
+ case NET_SSH2_MSG_USERAUTH_FAILURE:
1328
+ // either the login is bad or the server employees multi-factor authentication
1329
+ return false;
1330
+ case NET_SSH2_MSG_USERAUTH_SUCCESS:
1331
+ $this->bitmap |= NET_SSH2_MASK_LOGIN;
1332
+ return true;
1333
+ }
1334
+
1335
+ return false;
1336
+ }
1337
+
1338
+ /**
1339
+ * Login with an RSA private key
1340
+ *
1341
+ * @param String $username
1342
+ * @param Crypt_RSA $password
1343
+ * @return Boolean
1344
+ * @access private
1345
+ * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
1346
+ * by sending dummy SSH_MSG_IGNORE messages.
1347
+ */
1348
+ function _privatekey_login($username, $privatekey)
1349
+ {
1350
+ // see http://tools.ietf.org/html/rfc4253#page-15
1351
+ $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW);
1352
+ if ($publickey === false) {
1353
+ return false;
1354
+ }
1355
+
1356
+ $publickey = array(
1357
+ 'e' => $publickey['e']->toBytes(true),
1358
+ 'n' => $publickey['n']->toBytes(true)
1359
+ );
1360
+ $publickey = pack('Na*Na*Na*',
1361
+ strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n']
1362
+ );
1363
+
1364
+ $part1 = pack('CNa*Na*Na*',
1365
+ NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
1366
+ strlen('publickey'), 'publickey'
1367
+ );
1368
+ $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey);
1369
+
1370
+ $packet = $part1 . chr(0) . $part2;
1371
+
1372
+ if (!$this->_send_binary_packet($packet)) {
1373
+ return false;
1374
+ }
1375
+
1376
+ $response = $this->_get_binary_packet();
1377
+ if ($response === false) {
1378
+ user_error('Connection closed by server', E_USER_NOTICE);
1379
+ return false;
1380
+ }
1381
+
1382
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
1383
+
1384
+ switch ($type) {
1385
+ case NET_SSH2_MSG_USERAUTH_FAILURE:
1386
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1387
+ $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length);
1388
+ return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
1389
+ case NET_SSH2_MSG_USERAUTH_PK_OK:
1390
+ // we'll just take it on faith that the public key blob and the public key algorithm name are as
1391
+ // they should be
1392
+ if (defined('NET_SSH2_LOGGING')) {
1393
+ $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PK_OK';
1394
+ }
1395
+ }
1396
+
1397
+ $packet = $part1 . chr(1) . $part2;
1398
+ $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
1399
+ $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
1400
+ $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
1401
+ $packet.= pack('Na*', strlen($signature), $signature);
1402
+
1403
+ if (!$this->_send_binary_packet($packet)) {
1404
+ return false;
1405
+ }
1406
+
1407
+ $response = $this->_get_binary_packet();
1408
+ if ($response === false) {
1409
+ user_error('Connection closed by server', E_USER_NOTICE);
1410
+ return false;
1411
+ }
1412
+
1413
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
1414
+
1415
+ switch ($type) {
1416
+ case NET_SSH2_MSG_USERAUTH_FAILURE:
1417
+ // either the login is bad or the server employees multi-factor authentication
1418
+ return false;
1419
+ case NET_SSH2_MSG_USERAUTH_SUCCESS:
1420
+ $this->bitmap |= NET_SSH2_MASK_LOGIN;
1421
+ return true;
1422
+ }
1423
+
1424
+ return false;
1425
+ }
1426
+
1427
+ /**
1428
+ * Execute Command
1429
+ *
1430
+ * @param String $command
1431
+ * @return String
1432
+ * @access public
1433
+ */
1434
+ function exec($command)
1435
+ {
1436
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1437
+ return false;
1438
+ }
1439
+
1440
+ // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to
1441
+ // be adjusted". 0x7FFFFFFF is, at 4GB, the max size. technically, it should probably be decremented, but,
1442
+ // honestly, if you're transfering more than 4GB, you probably shouldn't be using phpseclib, anyway.
1443
+ // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
1444
+ $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF;
1445
+ // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
1446
+ // uses 0x4000, that's what will be used here, as well.
1447
+ $packet_size = 0x4000;
1448
+
1449
+ $packet = pack('CNa*N3',
1450
+ NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC], $packet_size);
1451
+
1452
+ if (!$this->_send_binary_packet($packet)) {
1453
+ return false;
1454
+ }
1455
+
1456
+ $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;
1457
+
1458
+ $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
1459
+ if ($response === false) {
1460
+ return false;
1461
+ }
1462
+
1463
+ // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things
1464
+ // down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &').
1465
+ // with a pty-req SSH_MSG_cHANNEL_REQUEST, exec() will return immediately and the ping process will then
1466
+ // then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but
1467
+ // neither will your script.
1468
+
1469
+ // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by
1470
+ // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the
1471
+ // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates.
1472
+ $packet = pack('CNNa*CNa*',
1473
+ NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command);
1474
+ if (!$this->_send_binary_packet($packet)) {
1475
+ return false;
1476
+ }
1477
+
1478
+ $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
1479
+
1480
+ $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
1481
+ if ($response === false) {
1482
+ return false;
1483
+ }
1484
+
1485
+ $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;
1486
+
1487
+ $output = '';
1488
+ while (true) {
1489
+ $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
1490
+ switch (true) {
1491
+ case $temp === true:
1492
+ return $output;
1493
+ case $temp === false:
1494
+ return false;
1495
+ default:
1496
+ $output.= $temp;
1497
+ }
1498
+ }
1499
+ }
1500
+
1501
+ /**
1502
+ * Disconnect
1503
+ *
1504
+ * @access public
1505
+ */
1506
+ function disconnect()
1507
+ {
1508
+ $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1509
+ }
1510
+
1511
+ /**
1512
+ * Destructor.
1513
+ *
1514
+ * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
1515
+ * disconnect().
1516
+ *
1517
+ * @access public
1518
+ */
1519
+ function __destruct()
1520
+ {
1521
+ $this->disconnect();
1522
+ }
1523
+
1524
+ /**
1525
+ * Gets Binary Packets
1526
+ *
1527
+ * See '6. Binary Packet Protocol' of rfc4253 for more info.
1528
+ *
1529
+ * @see Net_SSH2::_send_binary_packet()
1530
+ * @return String
1531
+ * @access private
1532
+ */
1533
+ function _get_binary_packet()
1534
+ {
1535
+ if (feof($this->fsock)) {
1536
+ user_error('Connection closed prematurely', E_USER_NOTICE);
1537
+ return false;
1538
+ }
1539
+
1540
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1541
+ $raw = fread($this->fsock, $this->decrypt_block_size);
1542
+ $stop = strtok(microtime(), ' ') + strtok('');
1543
+
1544
+ if ($this->decrypt !== false) {
1545
+ $raw = $this->decrypt->decrypt($raw);
1546
+ }
1547
+
1548
+ extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
1549
+
1550
+ $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
1551
+ $buffer = '';
1552
+ while ($remaining_length > 0) {
1553
+ $temp = fread($this->fsock, $remaining_length);
1554
+ $buffer.= $temp;
1555
+ $remaining_length-= strlen($temp);
1556
+ }
1557
+ if (!empty($buffer)) {
1558
+ $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
1559
+ $buffer = $temp = '';
1560
+ }
1561
+
1562
+ $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
1563
+ $padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
1564
+
1565
+ if ($this->hmac_check !== false) {
1566
+ $hmac = fread($this->fsock, $this->hmac_size);
1567
+ if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
1568
+ user_error('Invalid HMAC', E_USER_NOTICE);
1569
+ return false;
1570
+ }
1571
+ }
1572
+
1573
+ //if ($this->decompress) {
1574
+ // $payload = gzinflate(substr($payload, 2));
1575
+ //}
1576
+
1577
+ $this->get_seq_no++;
1578
+
1579
+ if (defined('NET_SSH2_LOGGING')) {
1580
+ $temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN';
1581
+ $this->message_number_log[] = '<- ' . $temp .
1582
+ ' (' . round($stop - $start, 4) . 's)';
1583
+ if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
1584
+ $this->message_log[] = substr($payload, 1);
1585
+ }
1586
+ }
1587
+
1588
+ return $this->_filter($payload);
1589
+ }
1590
+
1591
+ /**
1592
+ * Filter Binary Packets
1593
+ *
1594
+ * Because some binary packets need to be ignored...
1595
+ *
1596
+ * @see Net_SSH2::_get_binary_packet()
1597
+ * @return String
1598
+ * @access private
1599
+ */
1600
+ function _filter($payload)
1601
+ {
1602
+ switch (ord($payload[0])) {
1603
+ case NET_SSH2_MSG_DISCONNECT:
1604
+ $this->_string_shift($payload, 1);
1605
+ extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
1606
+ $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length));
1607
+ $this->bitmask = 0;
1608
+ return false;
1609
+ case NET_SSH2_MSG_IGNORE:
1610
+ $payload = $this->_get_binary_packet();
1611
+ break;
1612
+ case NET_SSH2_MSG_DEBUG:
1613
+ $this->_string_shift($payload, 2);
1614
+ extract(unpack('Nlength', $this->_string_shift($payload, 4)));
1615
+ $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
1616
+ $payload = $this->_get_binary_packet();
1617
+ break;
1618
+ case NET_SSH2_MSG_UNIMPLEMENTED:
1619
+ return false;
1620
+ case NET_SSH2_MSG_KEXINIT:
1621
+ if ($this->session_id !== false) {
1622
+ if (!$this->_key_exchange($payload)) {
1623
+ $this->bitmask = 0;
1624
+ return false;
1625
+ }
1626
+ $payload = $this->_get_binary_packet();
1627
+ }
1628
+ }
1629
+
1630
+ // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
1631
+ if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
1632
+ $this->_string_shift($payload, 1);
1633
+ extract(unpack('Nlength', $this->_string_shift($payload, 4)));
1634
+ $this->errors[] = 'SSH_MSG_USERAUTH_BANNER: ' . utf8_decode($this->_string_shift($payload, $length));
1635
+ $payload = $this->_get_binary_packet();
1636
+ }
1637
+
1638
+ // only called when we've already logged in
1639
+ if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1640
+ switch (ord($payload[0])) {
1641
+ case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
1642
+ $this->_string_shift($payload, 1);
1643
+ extract(unpack('Nlength', $this->_string_shift($payload)));
1644
+ $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length));
1645
+
1646
+ if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) {
1647
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1648
+ }
1649
+
1650
+ $payload = $this->_get_binary_packet();
1651
+ break;
1652
+ case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
1653
+ $this->_string_shift($payload, 1);
1654
+ extract(unpack('N', $this->_string_shift($payload, 4)));
1655
+ $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length));
1656
+
1657
+ $this->_string_shift($payload, 4); // skip over client channel
1658
+ extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
1659
+
1660
+ $packet = pack('CN3a*Na*',
1661
+ NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, '');
1662
+
1663
+ if (!$this->_send_binary_packet($packet)) {
1664
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1665
+ }
1666
+
1667
+ $payload = $this->_get_binary_packet();
1668
+ break;
1669
+ case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
1670
+ $payload = $this->_get_binary_packet();
1671
+ }
1672
+ }
1673
+
1674
+ return $payload;
1675
+ }
1676
+
1677
+ /**
1678
+ * Gets channel data
1679
+ *
1680
+ * Returns the data as a string if it's available and false if not.
1681
+ *
1682
+ * @param $client_channel
1683
+ * @return Mixed
1684
+ * @access private
1685
+ */
1686
+ function _get_channel_packet($client_channel)
1687
+ {
1688
+ if (!empty($this->channel_buffers[$client_channel])) {
1689
+ return array_shift($this->channel_buffers[$client_channel]);
1690
+ }
1691
+
1692
+ while (true) {
1693
+ $response = $this->_get_binary_packet();
1694
+ if ($response === false) {
1695
+ user_error('Connection closed by server', E_USER_NOTICE);
1696
+ return false;
1697
+ }
1698
+
1699
+ extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5)));
1700
+
1701
+ switch ($this->channel_status[$channel]) {
1702
+ case NET_SSH2_MSG_CHANNEL_OPEN:
1703
+ switch ($type) {
1704
+ case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
1705
+ extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
1706
+ $this->server_channels[$client_channel] = $server_channel;
1707
+ $this->_string_shift($response, 4); // skip over (server) window size
1708
+ $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
1709
+ $this->packet_size_client_to_server[$client_channel] = $temp['packet_size_client_to_server'];
1710
+ return true;
1711
+ //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
1712
+ default:
1713
+ user_error('Unable to open channel', E_USER_NOTICE);
1714
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1715
+ }
1716
+ break;
1717
+ case NET_SSH2_MSG_CHANNEL_REQUEST:
1718
+ switch ($type) {
1719
+ case NET_SSH2_MSG_CHANNEL_SUCCESS:
1720
+ return true;
1721
+ //case NET_SSH2_MSG_CHANNEL_FAILURE:
1722
+ default:
1723
+ user_error('Unable to request pseudo-terminal', E_USER_NOTICE);
1724
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1725
+ }
1726
+
1727
+ }
1728
+
1729
+ switch ($type) {
1730
+ case NET_SSH2_MSG_CHANNEL_DATA:
1731
+ if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
1732
+ // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server
1733
+ // this actually seems to make things twice as fast. more to the point, the message right after
1734
+ // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise.
1735
+ // in OpenSSH it slows things down but only by a couple thousandths of a second.
1736
+ $this->_send_channel_packet($client_channel, chr(0));
1737
+ }
1738
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1739
+ $data = $this->_string_shift($response, $length);
1740
+ if ($client_channel == $channel) {
1741
+ return $data;
1742
+ }
1743
+ if (!isset($this->channel_buffers[$client_channel])) {
1744
+ $this->channel_buffers[$client_channel] = array();
1745
+ }
1746
+ $this->channel_buffers[$client_channel][] = $data;
1747
+ break;
1748
+ case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
1749
+ if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
1750
+ $this->_send_channel_packet($client_channel, chr(0));
1751
+ }
1752
+ // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
1753
+ extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
1754
+ $data = $this->_string_shift($response, $length);
1755
+ if ($client_channel == $channel) {
1756
+ return $data;
1757
+ }
1758
+ if (!isset($this->channel_buffers[$client_channel])) {
1759
+ $this->channel_buffers[$client_channel] = array();
1760
+ }
1761
+ $this->channel_buffers[$client_channel][] = $data;
1762
+ break;
1763
+ case NET_SSH2_MSG_CHANNEL_REQUEST:
1764
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1765
+ $value = $this->_string_shift($response, $length);
1766
+ switch ($value) {
1767
+ case 'exit-signal':
1768
+ $this->_string_shift($response, 1);
1769
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1770
+ $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
1771
+ $this->_string_shift($response, 1);
1772
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1773
+ if ($length) {
1774
+ $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
1775
+ }
1776
+ //case 'exit-status':
1777
+ default:
1778
+ // "Some systems may not implement signals, in which case they SHOULD ignore this message."
1779
+ // -- http://tools.ietf.org/html/rfc4254#section-6.9
1780
+ break;
1781
+ }
1782
+ break;
1783
+ case NET_SSH2_MSG_CHANNEL_CLOSE:
1784
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
1785
+ return true;
1786
+ case NET_SSH2_MSG_CHANNEL_EOF:
1787
+ break;
1788
+ default:
1789
+ user_error('Error reading channel data', E_USER_NOTICE);
1790
+ return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1791
+ }
1792
+ }
1793
+ }
1794
+
1795
+ /**
1796
+ * Sends Binary Packets
1797
+ *
1798
+ * See '6. Binary Packet Protocol' of rfc4253 for more info.
1799
+ *
1800
+ * @param String $data
1801
+ * @see Net_SSH2::_get_binary_packet()
1802
+ * @return Boolean
1803
+ * @access private
1804
+ */
1805
+ function _send_binary_packet($data)
1806
+ {
1807
+ if (feof($this->fsock)) {
1808
+ user_error('Connection closed prematurely', E_USER_NOTICE);
1809
+ return false;
1810
+ }
1811
+
1812
+ //if ($this->compress) {
1813
+ // // the -4 removes the checksum:
1814
+ // // http://php.net/function.gzcompress#57710
1815
+ // $data = substr(gzcompress($data), 0, -4);
1816
+ //}
1817
+
1818
+ // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
1819
+ $packet_length = strlen($data) + 9;
1820
+ // round up to the nearest $this->encrypt_block_size
1821
+ $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
1822
+ // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
1823
+ $padding_length = $packet_length - strlen($data) - 5;
1824
+
1825
+ $padding = '';
1826
+ for ($i = 0; $i < $padding_length; $i++) {
1827
+ $padding.= chr(crypt_random(0, 255));
1828
+ }
1829
+
1830
+ // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
1831
+ $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);
1832
+
1833
+ $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : '';
1834
+ $this->send_seq_no++;
1835
+
1836
+ if ($this->encrypt !== false) {
1837
+ $packet = $this->encrypt->encrypt($packet);
1838
+ }
1839
+
1840
+ $packet.= $hmac;
1841
+
1842
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1843
+ $result = strlen($packet) == fputs($this->fsock, $packet);
1844
+ $stop = strtok(microtime(), ' ') + strtok('');
1845
+
1846
+ if (defined('NET_SSH2_LOGGING')) {
1847
+ $temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN';
1848
+ $this->message_number_log[] = '-> ' . $temp .
1849
+ ' (' . round($stop - $start, 4) . 's)';
1850
+ if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
1851
+ $this->message_log[] = substr($data, 1);
1852
+ }
1853
+ }
1854
+
1855
+ return $result;
1856
+ }
1857
+
1858
+ /**
1859
+ * Sends channel data
1860
+ *
1861
+ * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate
1862
+ *
1863
+ * @param Integer $client_channel
1864
+ * @param String $data
1865
+ * @return Boolean
1866
+ * @access private
1867
+ */
1868
+ function _send_channel_packet($client_channel, $data)
1869
+ {
1870
+ while (strlen($data) > $this->packet_size_client_to_server[$client_channel]) {
1871
+ // resize the window, if appropriate
1872
+ $this->window_size_client_to_server[$client_channel]-= $this->packet_size_client_to_server[$client_channel];
1873
+ if ($this->window_size_client_to_server[$client_channel] < 0) {
1874
+ $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size);
1875
+ if (!$this->_send_binary_packet($packet)) {
1876
+ return false;
1877
+ }
1878
+ $this->window_size_client_to_server[$client_channel]+= $this->window_size;
1879
+ }
1880
+
1881
+ $packet = pack('CN2a*',
1882
+ NET_SSH2_MSG_CHANNEL_DATA,
1883
+ $this->server_channels[$client_channel],
1884
+ $this->packet_size_client_to_server[$client_channel],
1885
+ $this->_string_shift($data, $this->packet_size_client_to_server[$client_channel])
1886
+ );
1887
+
1888
+ if (!$this->_send_binary_packet($packet)) {
1889
+ return false;
1890
+ }
1891
+ }
1892
+
1893
+ // resize the window, if appropriate
1894
+ $this->window_size_client_to_server[$client_channel]-= strlen($data);
1895
+ if ($this->window_size_client_to_server[$client_channel] < 0) {
1896
+ $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size);
1897
+ if (!$this->_send_binary_packet($packet)) {
1898
+ return false;
1899
+ }
1900
+ $this->window_size_client_to_server[$client_channel]+= $this->window_size;
1901
+ }
1902
+
1903
+ return $this->_send_binary_packet(pack('CN2a*',
1904
+ NET_SSH2_MSG_CHANNEL_DATA,
1905
+ $this->server_channels[$client_channel],
1906
+ strlen($data),
1907
+ $data));
1908
+ }
1909
+
1910
+ /**
1911
+ * Disconnect
1912
+ *
1913
+ * @param Integer $reason
1914
+ * @return Boolean
1915
+ * @access private
1916
+ */
1917
+ function _disconnect($reason)
1918
+ {
1919
+ if ($this->bitmap) {
1920
+ $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
1921
+ $this->_send_binary_packet($data);
1922
+ $this->bitmap = 0;
1923
+ fclose($this->fsock);
1924
+ return false;
1925
+ }
1926
+ }
1927
+
1928
+ /**
1929
+ * String Shift
1930
+ *
1931
+ * Inspired by array_shift
1932
+ *
1933
+ * @param String $string
1934
+ * @param optional Integer $index
1935
+ * @return String
1936
+ * @access private
1937
+ */
1938
+ function _string_shift(&$string, $index = 1)
1939
+ {
1940
+ $substr = substr($string, 0, $index);
1941
+ $string = substr($string, $index);
1942
+ return $substr;
1943
+ }
1944
+
1945
+ /**
1946
+ * Define Array
1947
+ *
1948
+ * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
1949
+ * named constants from it, using the value as the name of the constant and the index as the value of the constant.
1950
+ * If any of the constants that would be defined already exists, none of the constants will be defined.
1951
+ *
1952
+ * @param Array $array
1953
+ * @access private
1954
+ */
1955
+ function _define_array()
1956
+ {
1957
+ $args = func_get_args();
1958
+ foreach ($args as $arg) {
1959
+ foreach ($arg as $key=>$value) {
1960
+ if (!defined($value)) {
1961
+ define($value, $key);
1962
+ } else {
1963
+ break 2;
1964
+ }
1965
+ }
1966
+ }
1967
+ }
1968
+
1969
+ /**
1970
+ * Returns a log of the packets that have been sent and received.
1971
+ *
1972
+ * Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
1973
+ *
1974
+ * @access public
1975
+ * @return String or Array
1976
+ */
1977
+ function getLog()
1978
+ {
1979
+ if (!defined('NET_SSH2_LOGGING')) {
1980
+ return false;
1981
+ }
1982
+
1983
+ switch (NET_SSH2_LOGGING) {
1984
+ case NET_SSH2_LOG_SIMPLE:
1985
+ return $this->message_number_log;
1986
+ break;
1987
+ case NET_SSH2_LOG_COMPLEX:
1988
+ return $this->_format_log($this->message_log, $this->message_number_log);
1989
+ break;
1990
+ default:
1991
+ return false;
1992
+ }
1993
+ }
1994
+
1995
+ /**
1996
+ * Formats a log for printing
1997
+ *
1998
+ * @param Array $message_log
1999
+ * @param Array $message_number_log
2000
+ * @access private
2001
+ * @return String
2002
+ */
2003
+ function _format_log($message_log, $message_number_log)
2004
+ {
2005
+ static $boundary = ':', $long_width = 65, $short_width = 16;
2006
+
2007
+ $output = '';
2008
+ for ($i = 0; $i < count($message_log); $i++) {
2009
+ $output.= $message_number_log[$i] . "\r\n";
2010
+ $current_log = $message_log[$i];
2011
+ $j = 0;
2012
+ do {
2013
+ if (!empty($current_log)) {
2014
+ $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
2015
+ }
2016
+ $fragment = $this->_string_shift($current_log, $short_width);
2017
+ $hex = substr(
2018
+ preg_replace(
2019
+ '#(.)#es',
2020
+ '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)',
2021
+ $fragment),
2022
+ strlen($boundary)
2023
+ );
2024
+ // replace non ASCII printable characters with dots
2025
+ // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
2026
+ // also replace < with a . since < messes up the output on web browsers
2027
+ $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
2028
+ $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n";
2029
+ $j++;
2030
+ } while (!empty($current_log));
2031
+ $output.= "\r\n";
2032
+ }
2033
+
2034
+ return $output;
2035
+ }
2036
+
2037
+ /**
2038
+ * Returns all errors
2039
+ *
2040
+ * @return String
2041
+ * @access public
2042
+ */
2043
+ function getErrors()
2044
+ {
2045
+ return $this->errors;
2046
+ }
2047
+
2048
+ /**
2049
+ * Returns the last error
2050
+ *
2051
+ * @return String
2052
+ * @access public
2053
+ */
2054
+ function getLastError()
2055
+ {
2056
+ return $this->errors[count($this->errors) - 1];
2057
+ }
2058
+
2059
+ /**
2060
+ * Return the server identification.
2061
+ *
2062
+ * @return String
2063
+ * @access public
2064
+ */
2065
+ function getServerIdentification()
2066
+ {
2067
+ return $this->server_identifier;
2068
+ }
2069
+
2070
+ /**
2071
+ * Return a list of the key exchange algorithms the server supports.
2072
+ *
2073
+ * @return Array
2074
+ * @access public
2075
+ */
2076
+ function getKexAlgorithms()
2077
+ {
2078
+ return $this->kex_algorithms;
2079
+ }
2080
+
2081
+ /**
2082
+ * Return a list of the host key (public key) algorithms the server supports.
2083
+ *
2084
+ * @return Array
2085
+ * @access public
2086
+ */
2087
+ function getServerHostKeyAlgorithms()
2088
+ {
2089
+ return $this->server_host_key_algorithms;
2090
+ }
2091
+
2092
+ /**
2093
+ * Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff from the client.
2094
+ *
2095
+ * @return Array
2096
+ * @access public
2097
+ */
2098
+ function getEncryptionAlgorithmsClient2Server()
2099
+ {
2100
+ return $this->encryption_algorithms_client_to_server;
2101
+ }
2102
+
2103
+ /**
2104
+ * Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to the client.
2105
+ *
2106
+ * @return Array
2107
+ * @access public
2108
+ */
2109
+ function getEncryptionAlgorithmsServer2Client()
2110
+ {
2111
+ return $this->encryption_algorithms_server_to_client;
2112
+ }
2113
+
2114
+ /**
2115
+ * Return a list of the MAC algorithms the server supports, when receiving stuff from the client.
2116
+ *
2117
+ * @return Array
2118
+ * @access public
2119
+ */
2120
+ function getMACAlgorithmsClient2Server()
2121
+ {
2122
+ return $this->mac_algorithms_client_to_server;
2123
+ }
2124
+
2125
+ /**
2126
+ * Return a list of the MAC algorithms the server supports, when sending stuff to the client.
2127
+ *
2128
+ * @return Array
2129
+ * @access public
2130
+ */
2131
+ function getMACAlgorithmsServer2Client()
2132
+ {
2133
+ return $this->mac_algorithms_server_to_client;
2134
+ }
2135
+
2136
+ /**
2137
+ * Return a list of the compression algorithms the server supports, when receiving stuff from the client.
2138
+ *
2139
+ * @return Array
2140
+ * @access public
2141
+ */
2142
+ function getCompressionAlgorithmsClient2Server()
2143
+ {
2144
+ return $this->compression_algorithms_client_to_server;
2145
+ }
2146
+
2147
+ /**
2148
+ * Return a list of the compression algorithms the server supports, when sending stuff to the client.
2149
+ *
2150
+ * @return Array
2151
+ * @access public
2152
+ */
2153
+ function getCompressionAlgorithmsServer2Client()
2154
+ {
2155
+ return $this->compression_algorithms_server_to_client;
2156
+ }
2157
+
2158
+ /**
2159
+ * Return a list of the languages the server supports, when sending stuff to the client.
2160
+ *
2161
+ * @return Array
2162
+ * @access public
2163
+ */
2164
+ function getLanguagesServer2Client()
2165
+ {
2166
+ return $this->languages_server_to_client;
2167
+ }
2168
+
2169
+ /**
2170
+ * Return a list of the languages the server supports, when receiving stuff from the client.
2171
+ *
2172
+ * @return Array
2173
+ * @access public
2174
+ */
2175
+ function getLanguagesClient2Server()
2176
+ {
2177
+ return $this->languages_client_to_server;
2178
+ }
2179
+
2180
+ /**
2181
+ * Returns the server public host key.
2182
+ *
2183
+ * Caching this the first time you connect to a server and checking the result on subsequent connections
2184
+ * is recommended. Returns false if the server signature is not signed correctly with the public host key.
2185
+ *
2186
+ * @return Mixed
2187
+ * @access public
2188
+ */
2189
+ function getServerPublicHostKey()
2190
+ {
2191
+ $signature = $this->signature;
2192
+ $server_public_host_key = $this->server_public_host_key;
2193
+
2194
+ extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
2195
+ $this->_string_shift($server_public_host_key, $length);
2196
+
2197
+ switch ($this->signature_format) {
2198
+ case 'ssh-dss':
2199
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2200
+ $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
2201
+
2202
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2203
+ $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
2204
+
2205
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2206
+ $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
2207
+
2208
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2209
+ $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
2210
+
2211
+ /* The value for 'dss_signature_blob' is encoded as a string containing
2212
+ r, followed by s (which are 160-bit integers, without lengths or
2213
+ padding, unsigned, and in network byte order). */
2214
+ $temp = unpack('Nlength', $this->_string_shift($signature, 4));
2215
+ if ($temp['length'] != 40) {
2216
+ user_error('Invalid signature', E_USER_NOTICE);
2217
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2218
+ }
2219
+
2220
+ $r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
2221
+ $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
2222
+
2223
+ if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
2224
+ user_error('Invalid signature', E_USER_NOTICE);
2225
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2226
+ }
2227
+
2228
+ $w = $s->modInverse($q);
2229
+
2230
+ $u1 = $w->multiply(new Math_BigInteger(sha1($this->session_id), 16));
2231
+ list(, $u1) = $u1->divide($q);
2232
+
2233
+ $u2 = $w->multiply($r);
2234
+ list(, $u2) = $u2->divide($q);
2235
+
2236
+ $g = $g->modPow($u1, $p);
2237
+ $y = $y->modPow($u2, $p);
2238
+
2239
+ $v = $g->multiply($y);
2240
+ list(, $v) = $v->divide($p);
2241
+ list(, $v) = $v->divide($q);
2242
+
2243
+ if (!$v->equals($r)) {
2244
+ user_error('Bad server signature', E_USER_NOTICE);
2245
+ return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2246
+ }
2247
+
2248
+ break;
2249
+ case 'ssh-rsa':
2250
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2251
+ $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
2252
+
2253
+ $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2254
+ $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
2255
+ $nLength = $temp['length'];
2256
+
2257
+ /*
2258
+ $temp = unpack('Nlength', $this->_string_shift($signature, 4));
2259
+ $signature = $this->_string_shift($signature, $temp['length']);
2260
+
2261
+ if (!class_exists('Crypt_RSA')) {
2262
+ require_once('Crypt/RSA.php');
2263
+ }
2264
+
2265
+ $rsa = new Crypt_RSA();
2266
+ $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2267
+ $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
2268
+ if (!$rsa->verify($this->session_id, $signature)) {
2269
+ user_error('Bad server signature', E_USER_NOTICE);
2270
+ return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2271
+ }
2272
+ */
2273
+
2274
+ $temp = unpack('Nlength', $this->_string_shift($signature, 4));
2275
+ $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
2276
+
2277
+ // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
2278
+ // following URL:
2279
+ // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
2280
+
2281
+ // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
2282
+
2283
+ if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
2284
+ user_error('Invalid signature', E_USER_NOTICE);
2285
+ return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2286
+ }
2287
+
2288
+ $s = $s->modPow($e, $n);
2289
+ $s = $s->toBytes();
2290
+
2291
+ $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->session_id));
2292
+ $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h;
2293
+
2294
+ if ($s != $h) {
2295
+ user_error('Bad server signature', E_USER_NOTICE);
2296
+ return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2297
+ }
2298
+ }
2299
+
2300
+ return $this->server_public_host_key;
2301
+ }
2302
+ }
lib/phpseclib/PHP/Compat/Function/array_fill.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // $Id: array_fill.php,v 1.1 2007/07/02 04:19:55 terrafrost Exp $
3
+
4
+
5
+ /**
6
+ * Replace array_fill()
7
+ *
8
+ * @category PHP
9
+ * @package PHP_Compat
10
+ * @license LGPL - http://www.gnu.org/licenses/lgpl.html
11
+ * @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
12
+ * @link http://php.net/function.array_fill
13
+ * @author Jim Wigginton <terrafrost@php.net>
14
+ * @version $Revision: 1.1 $
15
+ * @since PHP 4.2.0
16
+ */
17
+ function php_compat_array_fill($start_index, $num, $value)
18
+ {
19
+ if ($num <= 0) {
20
+ user_error('array_fill(): Number of elements must be positive', E_USER_WARNING);
21
+
22
+ return false;
23
+ }
24
+
25
+ $temp = array();
26
+
27
+ $end_index = $start_index + $num;
28
+ for ($i = (int) $start_index; $i < $end_index; $i++) {
29
+ $temp[$i] = $value;
30
+ }
31
+
32
+ return $temp;
33
+ }
34
+
35
+ // Define
36
+ if (!function_exists('array_fill')) {
37
+ function array_fill($start_index, $num, $value)
38
+ {
39
+ return php_compat_array_fill($start_index, $num, $value);
40
+ }
41
+ }
lib/phpseclib/PHP/Compat/Function/bcpowmod.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // $Id: bcpowmod.php,v 1.1 2007/07/02 04:19:55 terrafrost Exp $
3
+
4
+
5
+ /**
6
+ * Replace bcpowmod()
7
+ *
8
+ * @category PHP
9
+ * @package PHP_Compat
10
+ * @license LGPL - http://www.gnu.org/licenses/lgpl.html
11
+ * @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
12
+ * @link http://php.net/function.bcpowmod
13
+ * @author Sara Golemon <pollita@php.net>
14
+ * @version $Revision: 1.1 $
15
+ * @since PHP 5.0.0
16
+ * @require PHP 4.0.0 (user_error)
17
+ */
18
+ function php_compat_bcpowmod($x, $y, $modulus, $scale = 0)
19
+ {
20
+ // Sanity check
21
+ if (!is_scalar($x)) {
22
+ user_error('bcpowmod() expects parameter 1 to be string, ' .
23
+ gettype($x) . ' given', E_USER_WARNING);
24
+ return false;
25
+ }
26
+
27
+ if (!is_scalar($y)) {
28
+ user_error('bcpowmod() expects parameter 2 to be string, ' .
29
+ gettype($y) . ' given', E_USER_WARNING);
30
+ return false;
31
+ }
32
+
33
+ if (!is_scalar($modulus)) {
34
+ user_error('bcpowmod() expects parameter 3 to be string, ' .
35
+ gettype($modulus) . ' given', E_USER_WARNING);
36
+ return false;
37
+ }
38
+
39
+ if (!is_scalar($scale)) {
40
+ user_error('bcpowmod() expects parameter 4 to be integer, ' .
41
+ gettype($scale) . ' given', E_USER_WARNING);
42
+ return false;
43
+ }
44
+
45
+ $t = '1';
46
+ while (bccomp($y, '0')) {
47
+ if (bccomp(bcmod($y, '2'), '0')) {
48
+ $t = bcmod(bcmul($t, $x), $modulus);
49
+ $y = bcsub($y, '1');
50
+ }
51
+
52
+ $x = bcmod(bcmul($x, $x), $modulus);
53
+ $y = bcdiv($y, '2');
54
+ }
55
+
56
+ return $t;
57
+ }
58
+
59
+
60
+ // Define
61
+ if (!function_exists('bcpowmod')) {
62
+ function bcpowmod($x, $y, $modulus, $scale = 0)
63
+ {
64
+ return php_compat_bcpowmod($x, $y, $modulus, $scale);
65
+ }
66
+ }
lib/phpseclib/PHP/Compat/Function/str_split.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Replace str_split()
4
+ *
5
+ * @category PHP
6
+ * @package PHP_Compat
7
+ * @license LGPL - http://www.gnu.org/licenses/lgpl.html
8
+ * @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
9
+ * @link http://php.net/function.str_split
10
+ * @author Aidan Lister <aidan@php.net>
11
+ * @version $Revision: 1.1 $
12
+ * @since PHP 5
13
+ * @require PHP 4.0.0 (user_error)
14
+ */
15
+ function php_compat_str_split($string, $split_length = 1)
16
+ {
17
+ if (!is_scalar($split_length)) {
18
+ user_error('str_split() expects parameter 2 to be long, ' .
19
+ gettype($split_length) . ' given', E_USER_WARNING);
20
+ return false;
21
+ }
22
+
23
+ $split_length = (int) $split_length;
24
+ if ($split_length < 1) {
25
+ user_error('str_split() The length of each segment must be greater than zero', E_USER_WARNING);
26
+ return false;
27
+ }
28
+
29
+ // Select split method
30
+ if ($split_length < 65536) {
31
+ // Faster, but only works for less than 2^16
32
+ preg_match_all('/.{1,' . $split_length . '}/s', $string, $matches);
33
+ return $matches[0];
34
+ } else {
35
+ // Required due to preg limitations
36
+ $arr = array();
37
+ $idx = 0;
38
+ $pos = 0;
39
+ $len = strlen($string);
40
+
41
+ while ($len > 0) {
42
+ $blk = ($len < $split_length) ? $len : $split_length;
43
+ $arr[$idx++] = substr($string, $pos, $blk);
44
+ $pos += $blk;
45
+ $len -= $blk;
46
+ }
47
+
48
+ return $arr;
49
+ }
50
+ }
51
+
52
+
53
+ // Define
54
+ if (!function_exists('str_split')) {
55
+ function str_split($string, $split_length = 1)
56
+ {
57
+ return php_compat_str_split($string, $split_length);
58
+ }
59
+ }
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Lib_Phpseclib</name>
4
+ <version>1.4.1.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.gnu.org/licenses/lgpl.txt">LGPL v.3</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Phpseclib Library</summary>
10
+ <description>Phpseclib Library</description>
11
+ <notes>1.4.1.0</notes>
12
+ <authors><author><name>Magento Core Team</name><user>core</user><email>core@magentocommerce.com</email></author></authors>
13
+ <date>2010-07-27</date>
14
+ <time>2010-07-27</time>
15
+ <contents><target name="magelib"><dir name="phpseclib"><dir name="Crypt"><file name="AES.php" hash="6af09e1f2da7eb069760d788ee0d54e0"/><file name="DES.php" hash="1b75baa9ddad68309b8e82a6cebc8dc1"/><file name="Hash.php" hash="f8ca80e79e2d570afeb2f78023f213d4"/><file name="RC4.php" hash="2e507f5635b6d98d9daaa341a8a6fb8b"/><file name="RSA.php" hash="579c11f7b2e05cae01b67b31461ca264"/><file name="Random.php" hash="6e86dfbd3f8f19f32f13a53a756e53af"/><file name="Rijndael.php" hash="3a0aa237cbc23ffba12aad6dd5215ab8"/><file name="TripleDES.php" hash="db12eebd6ed7290e4ac0d521ab5c55ce"/></dir><dir name="Math"><file name="BigInteger.php" hash="8dd950e566864b28c92b58acb06e1535"/></dir><dir name="Net"><file name="SFTP.php" hash="4665bea6e721ec016e0e70207cf45339"/><file name="SSH1.php" hash="19155c50cf00370152905b2a4a6ce657"/><file name="SSH2.php" hash="65563b38d6e6df3e8ebc628cec86f86d"/></dir><dir name="PHP"><dir name="Compat"><dir name="Function"><file name="array_fill.php" hash="2c0a4268deed10ced9491155e2284a82"/><file name="bcpowmod.php" hash="37fc1de34085874a930eaa76888f0cb1"/><file name="str_split.php" hash="889ab2b0d90b0962ded2ee65f1bfbc37"/></dir></dir></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
18
+ </package>