Wisepricer_Syncer - Version 1.1.2.6

Version Notes

wisepricer

Download this release

Release Info

Developer Moshe
Extension Wisepricer_Syncer
Version 1.1.2.6
Comparing to
See all releases


Code changes from version 1.1.2.5 to 1.1.2.6

app/code/local/Wisepricer/Syncer/Model/Mysql4/Mapping.php CHANGED
@@ -12,11 +12,12 @@ class Wisepricer_Syncer_Model_Mysql4_Mapping extends Mage_Core_Model_Mysql4_Abst
12
  }
13
 
14
  public function loadIdByWsfield(Wisepricer_Syncer_Model_Mapping $mapping, $wsfield, $testOnly = false)
15
- {
16
  $adapter = $this->_getReadAdapter();
 
17
  $bind = array('wsp_field' => $wsfield);
18
  $select = $adapter->select()
19
- ->from('wisepricer_syncer_mapping')
20
  ->where('wsp_field = :wsp_field');
21
 
22
 
12
  }
13
 
14
  public function loadIdByWsfield(Wisepricer_Syncer_Model_Mapping $mapping, $wsfield, $testOnly = false)
15
+ {
16
  $adapter = $this->_getReadAdapter();
17
+ $tableName = Mage::getSingleton('core/resource')->getTableName('wisepricer_syncer_mapping');
18
  $bind = array('wsp_field' => $wsfield);
19
  $select = $adapter->select()
20
+ ->from($tableName)
21
  ->where('wsp_field = :wsp_field');
22
 
23
 
app/code/local/Wisepricer/Syncer/controllers/ProductsController.php CHANGED
@@ -103,9 +103,10 @@ class Wisepricer_Syncer_ProductsController extends Mage_Core_Controller_Front_Ac
103
 
104
  }elseif($field['wsp_field']=='shipping'){
105
 
106
- if(is_numeric($productOrigData['shipping'])){
107
  $productData['shipping']=$field['magento_field'];
108
  }else{
 
109
  $productData['shipping']=$this->productOrigData[$field['magento_field']];
110
  }
111
 
@@ -115,6 +116,7 @@ class Wisepricer_Syncer_ProductsController extends Mage_Core_Controller_Front_Ac
115
  $productData[$field['wsp_field']]=$this->_calculateMinPrice($field);
116
 
117
  }else{
 
118
  $productData[$field['wsp_field']]=$this->productOrigData[$field['magento_field']];
119
  }
120
  }else{
@@ -128,7 +130,8 @@ class Wisepricer_Syncer_ProductsController extends Mage_Core_Controller_Front_Ac
128
  $productData[$field['wsp_field']]=$attrLabel;
129
  // echo '<pre>'.print_r($attr,true).'</pre>';//die;
130
  }else{
131
- $productData[$field['wsp_field']]=$this->productOrigData[$field['magento_field']];
 
132
  }
133
 
134
 
103
 
104
  }elseif($field['wsp_field']=='shipping'){
105
 
106
+ if(is_numeric($this->productOrigData['shipping'])){
107
  $productData['shipping']=$field['magento_field'];
108
  }else{
109
+ if(!isset($this->productOrigData[$field['magento_field']])){continue;}
110
  $productData['shipping']=$this->productOrigData[$field['magento_field']];
111
  }
112
 
116
  $productData[$field['wsp_field']]=$this->_calculateMinPrice($field);
117
 
118
  }else{
119
+ if(!isset($this->productOrigData[$field['magento_field']])){continue;}
120
  $productData[$field['wsp_field']]=$this->productOrigData[$field['magento_field']];
121
  }
122
  }else{
130
  $productData[$field['wsp_field']]=$attrLabel;
131
  // echo '<pre>'.print_r($attr,true).'</pre>';//die;
132
  }else{
133
+ if(!isset($this->productOrigData[$field['magento_field']])){continue;}
134
+ $productData[$field['wsp_field']]=$this->productOrigData[$field['magento_field']];
135
  }
136
 
137
 
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/AES.php CHANGED
@@ -1,479 +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:
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:
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/DES.php CHANGED
@@ -1,945 +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:
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:
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/Hash.php CHANGED
@@ -1,816 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/RC4.php CHANGED
@@ -1,493 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/RSA.php CHANGED
@@ -1,2119 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/Random.php CHANGED
@@ -1,129 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/Rijndael.php CHANGED
@@ -1,1242 +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:
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:
app/code/local/Wisepricer/Syncer/lib/phpseclib/Crypt/TripleDES.php CHANGED
@@ -1,690 +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:
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:
app/code/local/Wisepricer/Syncer/lib/phpseclib/Math/BigInteger.php CHANGED
@@ -1,3545 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Net/SFTP.php CHANGED
@@ -1,1461 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Net/SSH1.php CHANGED
@@ -1,1159 +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
- }
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
+ }
app/code/local/Wisepricer/Syncer/lib/phpseclib/Net/SSH2.php CHANGED
@@ -1,2302 +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
- }
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.