SSH SFTP Updater Support - Version 0.4

Version Description

  • fix an E_NOTICE (thanks, runblip!)
  • make it so keys that are copy / pasted in are saved with HTML5's localStorage (thanks, kkzk!)
  • update phpseclib to latest Git
Download this release

Release Info

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

Code changes from version 0.3 to 0.4

phpseclib/Crypt/AES.php CHANGED
@@ -66,7 +66,9 @@
66
  /**
67
  * Include Crypt_Rijndael
68
  */
69
- require_once 'Rijndael.php';
 
 
70
 
71
  /**#@+
72
  * @access public
@@ -178,10 +180,7 @@ class Crypt_AES extends Crypt_Rijndael {
178
  {
179
  if ( !defined('CRYPT_AES_MODE') ) {
180
  switch (true) {
181
- case extension_loaded('mcrypt'):
182
- // i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')),
183
- // but since that can be changed after the object has been created, there doesn't seem to be
184
- // a lot of point...
185
  define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
186
  break;
187
  default:
@@ -215,8 +214,6 @@ class Crypt_AES extends Crypt_Rijndael {
215
  $this->mode = MCRYPT_MODE_CBC;
216
  }
217
 
218
- $this->debuffer = $this->enbuffer = '';
219
-
220
  break;
221
  default:
222
  switch ($mode) {
@@ -312,18 +309,20 @@ class Crypt_AES extends Crypt_Rijndael {
312
  // re: http://phpseclib.sourceforge.net/cfb-demo.phps
313
  // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
314
  // rewritten CFB implementation the above outputs the same thing twice.
315
- if ($this->mode == 'ncfb') {
316
  if ($changed) {
317
  $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
318
  mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
319
  }
320
 
321
- if (strlen($this->enbuffer)) {
322
- $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
323
- $this->enbuffer.= $ciphertext;
324
- if (strlen($this->enbuffer) == 16) {
325
- $this->encryptIV = $this->enbuffer;
326
- $this->enbuffer = '';
 
 
327
  mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
328
  }
329
  $plaintext = substr($plaintext, strlen($ciphertext));
@@ -332,15 +331,15 @@ class Crypt_AES extends Crypt_Rijndael {
332
  }
333
 
334
  $last_pos = strlen($plaintext) & 0xFFFFFFF0;
335
- $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
 
 
 
336
 
337
  if (strlen($plaintext) & 0xF) {
338
- if (strlen($ciphertext)) {
339
- $this->encryptIV = substr($ciphertext, -16);
340
- }
341
  $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
342
- $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
343
- $ciphertext.= $this->enbuffer;
344
  }
345
 
346
  return $ciphertext;
@@ -387,19 +386,21 @@ class Crypt_AES extends Crypt_Rijndael {
387
  return $plaintext;
388
  }
389
  */
390
- if ($this->mode == 'ncfb') {
391
  if ($changed) {
392
  $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
393
  mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
394
  }
395
 
396
- if (strlen($this->debuffer)) {
397
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
398
 
399
- $this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
400
- if (strlen($this->debuffer) == 16) {
401
- $this->decryptIV = $this->debuffer;
402
- $this->debuffer = '';
 
 
 
403
  mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
404
  }
405
  $ciphertext = substr($ciphertext, strlen($plaintext));
@@ -408,15 +409,15 @@ class Crypt_AES extends Crypt_Rijndael {
408
  }
409
 
410
  $last_pos = strlen($ciphertext) & 0xFFFFFFF0;
411
- $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
 
 
 
 
412
 
413
  if (strlen($ciphertext) & 0xF) {
414
- if (strlen($plaintext)) {
415
- $this->decryptIV = substr($ciphertext, $last_pos - 16, 16);
416
- }
417
- $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
418
- $this->debuffer = substr($ciphertext, $last_pos);
419
- $plaintext.= $this->debuffer ^ $this->decryptIV;
420
  }
421
 
422
  return $plaintext;
@@ -527,7 +528,7 @@ class Crypt_AES extends Crypt_Rijndael {
527
  // shiftRows + subWord + mixColumns + addRoundKey
528
  // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
529
  // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
530
- for ($round = 1; $round < $this->Nr; $round++) {
531
  $state = array(
532
  $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
533
  $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
@@ -587,7 +588,7 @@ class Crypt_AES extends Crypt_Rijndael {
587
 
588
 
589
  // invShiftRows + invSubBytes + invMixColumns + addRoundKey
590
- for ($round = $this->Nr - 1; $round > 0; $round--) {
591
  $state = array(
592
  $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
593
  $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
@@ -606,6 +607,24 @@ class Crypt_AES extends Crypt_Rijndael {
606
 
607
  return pack('N*', $state[0], $state[1], $state[2], $state[3]);
608
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
609
  }
610
 
611
  // vim: ts=4:sw=4:et:
66
  /**
67
  * Include Crypt_Rijndael
68
  */
69
+ if (!class_exists('Crypt_Rijndael')) {
70
+ require_once 'Rijndael.php';
71
+ }
72
 
73
  /**#@+
74
  * @access public
180
  {
181
  if ( !defined('CRYPT_AES_MODE') ) {
182
  switch (true) {
183
+ case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()):
 
 
 
184
  define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
185
  break;
186
  default:
214
  $this->mode = MCRYPT_MODE_CBC;
215
  }
216
 
 
 
217
  break;
218
  default:
219
  switch ($mode) {
309
  // re: http://phpseclib.sourceforge.net/cfb-demo.phps
310
  // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
311
  // rewritten CFB implementation the above outputs the same thing twice.
312
+ if ($this->mode == 'ncfb' && $this->continuousBuffer) {
313
  if ($changed) {
314
  $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
315
  mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
316
  }
317
 
318
+ $buffer = &$this->enbuffer['encrypted'];
319
+
320
+ if (strlen($buffer)) {
321
+ $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($buffer));
322
+ $buffer.= $ciphertext;
323
+ if (strlen($buffer) == 16) {
324
+ $this->encryptIV = $buffer;
325
+ $buffer = '';
326
  mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
327
  }
328
  $plaintext = substr($plaintext, strlen($ciphertext));
331
  }
332
 
333
  $last_pos = strlen($plaintext) & 0xFFFFFFF0;
334
+ if ($last_pos) {
335
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos));
336
+ $this->encryptIV = substr($ciphertext, -16);
337
+ }
338
 
339
  if (strlen($plaintext) & 0xF) {
 
 
 
340
  $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
341
+ $buffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
342
+ $ciphertext.= $buffer;
343
  }
344
 
345
  return $ciphertext;
386
  return $plaintext;
387
  }
388
  */
389
+ if ($this->mode == 'ncfb' && $this->continuousBuffer) {
390
  if ($changed) {
391
  $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
392
  mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
393
  }
394
 
395
+ $buffer = &$this->debuffer['ciphertext'];
 
396
 
397
+ if (strlen($buffer)) {
398
+ $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer));
399
+
400
+ $buffer.= substr($ciphertext, 0, strlen($plaintext));
401
+ if (strlen($buffer) == 16) {
402
+ $this->decryptIV = $buffer;
403
+ $buffer = '';
404
  mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
405
  }
406
  $ciphertext = substr($ciphertext, strlen($plaintext));
409
  }
410
 
411
  $last_pos = strlen($ciphertext) & 0xFFFFFFF0;
412
+ if ($last_pos) {
413
+ $plaintext = mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos));
414
+ $this->decryptIV = substr($ciphertext, $last_pos - 16, 16);
415
+ $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
416
+ }
417
 
418
  if (strlen($ciphertext) & 0xF) {
419
+ $buffer = substr($ciphertext, $last_pos);
420
+ $plaintext.= $buffer ^ $this->decryptIV;
 
 
 
 
421
  }
422
 
423
  return $plaintext;
528
  // shiftRows + subWord + mixColumns + addRoundKey
529
  // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
530
  // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
531
+ for ($round = 1; $round < $Nr; $round++) {
532
  $state = array(
533
  $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
534
  $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
588
 
589
 
590
  // invShiftRows + invSubBytes + invMixColumns + addRoundKey
591
+ for ($round = $Nr - 1; $round > 0; $round--) {
592
  $state = array(
593
  $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
594
  $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
607
 
608
  return pack('N*', $state[0], $state[1], $state[2], $state[3]);
609
  }
610
+
611
+ /**
612
+ * Treat consecutive packets as if they are a discontinuous buffer.
613
+ *
614
+ * The default behavior.
615
+ *
616
+ * @see Crypt_Rijndael::enableContinuousBuffer()
617
+ * @access public
618
+ */
619
+ function disableContinuousBuffer()
620
+ {
621
+ parent::disableContinuousBuffer();
622
+
623
+ if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
624
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
625
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
626
+ }
627
+ }
628
  }
629
 
630
  // vim: ts=4:sw=4:et:
phpseclib/Crypt/DES.php CHANGED
@@ -291,14 +291,11 @@ class Crypt_DES {
291
  * @return Crypt_DES
292
  * @access public
293
  */
294
- function Crypt_DES($mode = CRYPT_MODE_DES_CBC)
295
  {
296
  if ( !defined('CRYPT_DES_MODE') ) {
297
  switch (true) {
298
- case extension_loaded('mcrypt'):
299
- // i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
300
- // but since that can be changed after the object has been created, there doesn't seem to be
301
- // a lot of point...
302
  define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
303
  break;
304
  default:
@@ -374,7 +371,7 @@ class Crypt_DES {
374
  *
375
  * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
376
  * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
377
- * $hash, $salt, $method
378
  *
379
  * @param String $password
380
  * @param optional String $method
@@ -392,7 +389,7 @@ class Crypt_DES {
392
  }
393
  // WPA and WPA use the SSID as the salt
394
  if (!isset($salt)) {
395
- $salt = 'phpseclib';
396
  }
397
  // RFC2898#section-4.2 uses 1,000 iterations by default
398
  // WPA and WPA2 use 4,096.
@@ -600,7 +597,7 @@ class Crypt_DES {
600
  }
601
  break;
602
  case CRYPT_DES_MODE_CFB:
603
- if (!empty($buffer['xor'])) {
604
  $ciphertext = $plaintext ^ $buffer['xor'];
605
  $iv = $buffer['encrypted'] . $ciphertext;
606
  $start = strlen($ciphertext);
@@ -726,7 +723,7 @@ class Crypt_DES {
726
  mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
727
  }
728
 
729
- return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
730
  }
731
 
732
  if (!is_array($this->keys)) {
@@ -777,15 +774,17 @@ class Crypt_DES {
777
  }
778
  break;
779
  case CRYPT_DES_MODE_CFB:
780
- if (!empty($buffer['ciphertext'])) {
781
  $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
782
  $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
783
- if (strlen($buffer['ciphertext']) == 8) {
 
 
 
784
  $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
785
  $buffer['ciphertext'] = '';
786
  }
787
  $start = strlen($plaintext);
788
- $block = $this->decryptIV;
789
  } else {
790
  $plaintext = '';
791
  $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
@@ -940,7 +939,7 @@ class Crypt_DES {
940
  if (($length & 7) == 0) {
941
  return $text;
942
  } else {
943
- user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
944
  $this->padding = true;
945
  }
946
  }
291
  * @return Crypt_DES
292
  * @access public
293
  */
294
+ function Crypt_DES($mode = CRYPT_DES_MODE_CBC)
295
  {
296
  if ( !defined('CRYPT_DES_MODE') ) {
297
  switch (true) {
298
+ case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()):
 
 
 
299
  define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
300
  break;
301
  default:
371
  *
372
  * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
373
  * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
374
+ * $hash, $salt, $count
375
  *
376
  * @param String $password
377
  * @param optional String $method
389
  }
390
  // WPA and WPA use the SSID as the salt
391
  if (!isset($salt)) {
392
+ $salt = 'phpseclib/salt';
393
  }
394
  // RFC2898#section-4.2 uses 1,000 iterations by default
395
  // WPA and WPA2 use 4,096.
597
  }
598
  break;
599
  case CRYPT_DES_MODE_CFB:
600
+ if (strlen($buffer['xor'])) {
601
  $ciphertext = $plaintext ^ $buffer['xor'];
602
  $iv = $buffer['encrypted'] . $ciphertext;
603
  $start = strlen($ciphertext);
723
  mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
724
  }
725
 
726
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
727
  }
728
 
729
  if (!is_array($this->keys)) {
774
  }
775
  break;
776
  case CRYPT_DES_MODE_CFB:
777
+ if (strlen($buffer['ciphertext'])) {
778
  $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
779
  $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
780
+ if (strlen($buffer['ciphertext']) != 8) {
781
+ $block = $this->decryptIV;
782
+ } else {
783
+ $block = $buffer['ciphertext'];
784
  $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
785
  $buffer['ciphertext'] = '';
786
  }
787
  $start = strlen($plaintext);
 
788
  } else {
789
  $plaintext = '';
790
  $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
939
  if (($length & 7) == 0) {
940
  return $text;
941
  } else {
942
+ user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
943
  $this->padding = true;
944
  }
945
  }
phpseclib/Crypt/Hash.php CHANGED
@@ -1,825 +1,825 @@
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: Permission is hereby granted, free of charge, to any person obtaining a copy
33
- * of this software and associated documentation files (the "Software"), to deal
34
- * in the Software without restriction, including without limitation the rights
35
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
- * copies of the Software, and to permit persons to whom the Software is
37
- * furnished to do so, subject to the following conditions:
38
- *
39
- * The above copyright notice and this permission notice shall be included in
40
- * all copies or substantial portions of the Software.
41
- *
42
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48
- * THE SOFTWARE.
49
- *
50
- * @category Crypt
51
- * @package Crypt_Hash
52
- * @author Jim Wigginton <terrafrost@php.net>
53
- * @copyright MMVII Jim Wigginton
54
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
55
- * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $
56
- * @link http://phpseclib.sourceforge.net
57
- */
58
-
59
- /**#@+
60
- * @access private
61
- * @see Crypt_Hash::Crypt_Hash()
62
- */
63
- /**
64
- * Toggles the internal implementation
65
- */
66
- define('CRYPT_HASH_MODE_INTERNAL', 1);
67
- /**
68
- * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
69
- */
70
- define('CRYPT_HASH_MODE_MHASH', 2);
71
- /**
72
- * Toggles the hash() implementation, which works on PHP 5.1.2+.
73
- */
74
- define('CRYPT_HASH_MODE_HASH', 3);
75
- /**#@-*/
76
-
77
- /**
78
- * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
79
- *
80
- * @author Jim Wigginton <terrafrost@php.net>
81
- * @version 0.1.0
82
- * @access public
83
- * @package Crypt_Hash
84
- */
85
- class Crypt_Hash {
86
- /**
87
- * Byte-length of compression blocks / key (Internal HMAC)
88
- *
89
- * @see Crypt_Hash::setAlgorithm()
90
- * @var Integer
91
- * @access private
92
- */
93
- var $b;
94
-
95
- /**
96
- * Byte-length of hash output (Internal HMAC)
97
- *
98
- * @see Crypt_Hash::setHash()
99
- * @var Integer
100
- * @access private
101
- */
102
- var $l = false;
103
-
104
- /**
105
- * Hash Algorithm
106
- *
107
- * @see Crypt_Hash::setHash()
108
- * @var String
109
- * @access private
110
- */
111
- var $hash;
112
-
113
- /**
114
- * Key
115
- *
116
- * @see Crypt_Hash::setKey()
117
- * @var String
118
- * @access private
119
- */
120
- var $key = '';
121
-
122
- /**
123
- * Outer XOR (Internal HMAC)
124
- *
125
- * @see Crypt_Hash::setKey()
126
- * @var String
127
- * @access private
128
- */
129
- var $opad;
130
-
131
- /**
132
- * Inner XOR (Internal HMAC)
133
- *
134
- * @see Crypt_Hash::setKey()
135
- * @var String
136
- * @access private
137
- */
138
- var $ipad;
139
-
140
- /**
141
- * Default Constructor.
142
- *
143
- * @param optional String $hash
144
- * @return Crypt_Hash
145
- * @access public
146
- */
147
- function Crypt_Hash($hash = 'sha1')
148
- {
149
- if ( !defined('CRYPT_HASH_MODE') ) {
150
- switch (true) {
151
- case extension_loaded('hash'):
152
- define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
153
- break;
154
- case extension_loaded('mhash'):
155
- define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
156
- break;
157
- default:
158
- define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
159
- }
160
- }
161
-
162
- $this->setHash($hash);
163
- }
164
-
165
- /**
166
- * Sets the key for HMACs
167
- *
168
- * Keys can be of any length.
169
- *
170
- * @access public
171
- * @param String $key
172
- */
173
- function setKey($key)
174
- {
175
- $this->key = $key;
176
- }
177
-
178
- /**
179
- * Sets the hash function.
180
- *
181
- * @access public
182
- * @param String $hash
183
- */
184
- function setHash($hash)
185
- {
186
- $hash = strtolower($hash);
187
- switch ($hash) {
188
- case 'md5-96':
189
- case 'sha1-96':
190
- $this->l = 12; // 96 / 8 = 12
191
- break;
192
- case 'md2':
193
- case 'md5':
194
- $this->l = 16;
195
- break;
196
- case 'sha1':
197
- $this->l = 20;
198
- break;
199
- case 'sha256':
200
- $this->l = 32;
201
- break;
202
- case 'sha384':
203
- $this->l = 48;
204
- break;
205
- case 'sha512':
206
- $this->l = 64;
207
- }
208
-
209
- switch ($hash) {
210
- case 'md2':
211
- $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
212
- CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
213
- break;
214
- case 'sha384':
215
- case 'sha512':
216
- $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
217
- break;
218
- default:
219
- $mode = CRYPT_HASH_MODE;
220
- }
221
-
222
- switch ( $mode ) {
223
- case CRYPT_HASH_MODE_MHASH:
224
- switch ($hash) {
225
- case 'md5':
226
- case 'md5-96':
227
- $this->hash = MHASH_MD5;
228
- break;
229
- case 'sha256':
230
- $this->hash = MHASH_SHA256;
231
- break;
232
- case 'sha1':
233
- case 'sha1-96':
234
- default:
235
- $this->hash = MHASH_SHA1;
236
- }
237
- return;
238
- case CRYPT_HASH_MODE_HASH:
239
- switch ($hash) {
240
- case 'md5':
241
- case 'md5-96':
242
- $this->hash = 'md5';
243
- return;
244
- case 'md2':
245
- case 'sha256':
246
- case 'sha384':
247
- case 'sha512':
248
- $this->hash = $hash;
249
- return;
250
- case 'sha1':
251
- case 'sha1-96':
252
- default:
253
- $this->hash = 'sha1';
254
- }
255
- return;
256
- }
257
-
258
- switch ($hash) {
259
- case 'md2':
260
- $this->b = 16;
261
- $this->hash = array($this, '_md2');
262
- break;
263
- case 'md5':
264
- case 'md5-96':
265
- $this->b = 64;
266
- $this->hash = array($this, '_md5');
267
- break;
268
- case 'sha256':
269
- $this->b = 64;
270
- $this->hash = array($this, '_sha256');
271
- break;
272
- case 'sha384':
273
- case 'sha512':
274
- $this->b = 128;
275
- $this->hash = array($this, '_sha512');
276
- break;
277
- case 'sha1':
278
- case 'sha1-96':
279
- default:
280
- $this->b = 64;
281
- $this->hash = array($this, '_sha1');
282
- }
283
-
284
- $this->ipad = str_repeat(chr(0x36), $this->b);
285
- $this->opad = str_repeat(chr(0x5C), $this->b);
286
- }
287
-
288
- /**
289
- * Compute the HMAC.
290
- *
291
- * @access public
292
- * @param String $text
293
- * @return String
294
- */
295
- function hash($text)
296
- {
297
- $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
298
-
299
- if (!empty($this->key)) {
300
- switch ( $mode ) {
301
- case CRYPT_HASH_MODE_MHASH:
302
- $output = mhash($this->hash, $text, $this->key);
303
- break;
304
- case CRYPT_HASH_MODE_HASH:
305
- $output = hash_hmac($this->hash, $text, $this->key, true);
306
- break;
307
- case CRYPT_HASH_MODE_INTERNAL:
308
- /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
309
- resultant L byte string as the actual key to HMAC."
310
-
311
- -- http://tools.ietf.org/html/rfc2104#section-2 */
312
- $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
313
-
314
- $key = str_pad($key, $this->b, chr(0)); // step 1
315
- $temp = $this->ipad ^ $key; // step 2
316
- $temp .= $text; // step 3
317
- $temp = call_user_func($this->hash, $temp); // step 4
318
- $output = $this->opad ^ $key; // step 5
319
- $output.= $temp; // step 6
320
- $output = call_user_func($this->hash, $output); // step 7
321
- }
322
- } else {
323
- switch ( $mode ) {
324
- case CRYPT_HASH_MODE_MHASH:
325
- $output = mhash($this->hash, $text);
326
- break;
327
- case CRYPT_HASH_MODE_HASH:
328
- $output = hash($this->hash, $text, true);
329
- break;
330
- case CRYPT_HASH_MODE_INTERNAL:
331
- $output = call_user_func($this->hash, $text);
332
- }
333
- }
334
-
335
- return substr($output, 0, $this->l);
336
- }
337
-
338
- /**
339
- * Returns the hash length (in bytes)
340
- *
341
- * @access public
342
- * @return Integer
343
- */
344
- function getLength()
345
- {
346
- return $this->l;
347
- }
348
-
349
- /**
350
- * Wrapper for MD5
351
- *
352
- * @access private
353
- * @param String $text
354
- */
355
- function _md5($m)
356
- {
357
- return pack('H*', md5($m));
358
- }
359
-
360
- /**
361
- * Wrapper for SHA1
362
- *
363
- * @access private
364
- * @param String $text
365
- */
366
- function _sha1($m)
367
- {
368
- return pack('H*', sha1($m));
369
- }
370
-
371
- /**
372
- * Pure-PHP implementation of MD2
373
- *
374
- * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
375
- *
376
- * @access private
377
- * @param String $text
378
- */
379
- function _md2($m)
380
- {
381
- static $s = array(
382
- 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
383
- 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
384
- 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
385
- 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
386
- 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
387
- 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
388
- 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
389
- 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
390
- 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
391
- 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
392
- 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
393
- 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
394
- 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
395
- 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
396
- 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
397
- 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
398
- 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
399
- 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
400
- );
401
-
402
- // Step 1. Append Padding Bytes
403
- $pad = 16 - (strlen($m) & 0xF);
404
- $m.= str_repeat(chr($pad), $pad);
405
-
406
- $length = strlen($m);
407
-
408
- // Step 2. Append Checksum
409
- $c = str_repeat(chr(0), 16);
410
- $l = chr(0);
411
- for ($i = 0; $i < $length; $i+= 16) {
412
- for ($j = 0; $j < 16; $j++) {
413
- // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
414
- //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
415
- // per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
416
- $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
417
- $l = $c[$j];
418
- }
419
- }
420
- $m.= $c;
421
-
422
- $length+= 16;
423
-
424
- // Step 3. Initialize MD Buffer
425
- $x = str_repeat(chr(0), 48);
426
-
427
- // Step 4. Process Message in 16-Byte Blocks
428
- for ($i = 0; $i < $length; $i+= 16) {
429
- for ($j = 0; $j < 16; $j++) {
430
- $x[$j + 16] = $m[$i + $j];
431
- $x[$j + 32] = $x[$j + 16] ^ $x[$j];
432
- }
433
- $t = chr(0);
434
- for ($j = 0; $j < 18; $j++) {
435
- for ($k = 0; $k < 48; $k++) {
436
- $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
437
- //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
438
- }
439
- $t = chr(ord($t) + $j);
440
- }
441
- }
442
-
443
- // Step 5. Output
444
- return substr($x, 0, 16);
445
- }
446
-
447
- /**
448
- * Pure-PHP implementation of SHA256
449
- *
450
- * 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}.
451
- *
452
- * @access private
453
- * @param String $text
454
- */
455
- function _sha256($m)
456
- {
457
- if (extension_loaded('suhosin')) {
458
- return pack('H*', sha256($m));
459
- }
460
-
461
- // Initialize variables
462
- $hash = array(
463
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
464
- );
465
- // Initialize table of round constants
466
- // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
467
- static $k = array(
468
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
469
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
470
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
471
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
472
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
473
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
474
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
475
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
476
- );
477
-
478
- // Pre-processing
479
- $length = strlen($m);
480
- // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
481
- $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
482
- $m[$length] = chr(0x80);
483
- // we don't support hashing strings 512MB long
484
- $m.= pack('N2', 0, $length << 3);
485
-
486
- // Process the message in successive 512-bit chunks
487
- $chunks = str_split($m, 64);
488
- foreach ($chunks as $chunk) {
489
- $w = array();
490
- for ($i = 0; $i < 16; $i++) {
491
- extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
492
- $w[] = $temp;
493
- }
494
-
495
- // Extend the sixteen 32-bit words into sixty-four 32-bit words
496
- for ($i = 16; $i < 64; $i++) {
497
- $s0 = $this->_rightRotate($w[$i - 15], 7) ^
498
- $this->_rightRotate($w[$i - 15], 18) ^
499
- $this->_rightShift( $w[$i - 15], 3);
500
- $s1 = $this->_rightRotate($w[$i - 2], 17) ^
501
- $this->_rightRotate($w[$i - 2], 19) ^
502
- $this->_rightShift( $w[$i - 2], 10);
503
- $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
504
-
505
- }
506
-
507
- // Initialize hash value for this chunk
508
- list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
509
-
510
- // Main loop
511
- for ($i = 0; $i < 64; $i++) {
512
- $s0 = $this->_rightRotate($a, 2) ^
513
- $this->_rightRotate($a, 13) ^
514
- $this->_rightRotate($a, 22);
515
- $maj = ($a & $b) ^
516
- ($a & $c) ^
517
- ($b & $c);
518
- $t2 = $this->_add($s0, $maj);
519
-
520
- $s1 = $this->_rightRotate($e, 6) ^
521
- $this->_rightRotate($e, 11) ^
522
- $this->_rightRotate($e, 25);
523
- $ch = ($e & $f) ^
524
- ($this->_not($e) & $g);
525
- $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
526
-
527
- $h = $g;
528
- $g = $f;
529
- $f = $e;
530
- $e = $this->_add($d, $t1);
531
- $d = $c;
532
- $c = $b;
533
- $b = $a;
534
- $a = $this->_add($t1, $t2);
535
- }
536
-
537
- // Add this chunk's hash to result so far
538
- $hash = array(
539
- $this->_add($hash[0], $a),
540
- $this->_add($hash[1], $b),
541
- $this->_add($hash[2], $c),
542
- $this->_add($hash[3], $d),
543
- $this->_add($hash[4], $e),
544
- $this->_add($hash[5], $f),
545
- $this->_add($hash[6], $g),
546
- $this->_add($hash[7], $h)
547
- );
548
- }
549
-
550
- // Produce the final hash value (big-endian)
551
- return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
552
- }
553
-
554
- /**
555
- * Pure-PHP implementation of SHA384 and SHA512
556
- *
557
- * @access private
558
- * @param String $text
559
- */
560
- function _sha512($m)
561
- {
562
- if (!class_exists('Math_BigInteger')) {
563
- require_once('Math/BigInteger.php');
564
- }
565
-
566
- static $init384, $init512, $k;
567
-
568
- if (!isset($k)) {
569
- // Initialize variables
570
- $init384 = array( // initial values for SHA384
571
- 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
572
- '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
573
- );
574
- $init512 = array( // initial values for SHA512
575
- '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
576
- '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
577
- );
578
-
579
- for ($i = 0; $i < 8; $i++) {
580
- $init384[$i] = new Math_BigInteger($init384[$i], 16);
581
- $init384[$i]->setPrecision(64);
582
- $init512[$i] = new Math_BigInteger($init512[$i], 16);
583
- $init512[$i]->setPrecision(64);
584
- }
585
-
586
- // Initialize table of round constants
587
- // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
588
- $k = array(
589
- '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
590
- '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
591
- 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
592
- '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
593
- 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
594
- '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
595
- '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
596
- 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
597
- '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
598
- '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
599
- 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
600
- 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
601
- '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
602
- '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
603
- '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
604
- '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
605
- 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
606
- '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
607
- '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
608
- '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
609
- );
610
-
611
- for ($i = 0; $i < 80; $i++) {
612
- $k[$i] = new Math_BigInteger($k[$i], 16);
613
- }
614
- }
615
-
616
- $hash = $this->l == 48 ? $init384 : $init512;
617
-
618
- // Pre-processing
619
- $length = strlen($m);
620
- // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
621
- $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
622
- $m[$length] = chr(0x80);
623
- // we don't support hashing strings 512MB long
624
- $m.= pack('N4', 0, 0, 0, $length << 3);
625
-
626
- // Process the message in successive 1024-bit chunks
627
- $chunks = str_split($m, 128);
628
- foreach ($chunks as $chunk) {
629
- $w = array();
630
- for ($i = 0; $i < 16; $i++) {
631
- $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
632
- $temp->setPrecision(64);
633
- $w[] = $temp;
634
- }
635
-
636
- // Extend the sixteen 32-bit words into eighty 32-bit words
637
- for ($i = 16; $i < 80; $i++) {
638
- $temp = array(
639
- $w[$i - 15]->bitwise_rightRotate(1),
640
- $w[$i - 15]->bitwise_rightRotate(8),
641
- $w[$i - 15]->bitwise_rightShift(7)
642
- );
643
- $s0 = $temp[0]->bitwise_xor($temp[1]);
644
- $s0 = $s0->bitwise_xor($temp[2]);
645
- $temp = array(
646
- $w[$i - 2]->bitwise_rightRotate(19),
647
- $w[$i - 2]->bitwise_rightRotate(61),
648
- $w[$i - 2]->bitwise_rightShift(6)
649
- );
650
- $s1 = $temp[0]->bitwise_xor($temp[1]);
651
- $s1 = $s1->bitwise_xor($temp[2]);
652
- $w[$i] = $w[$i - 16]->copy();
653
- $w[$i] = $w[$i]->add($s0);
654
- $w[$i] = $w[$i]->add($w[$i - 7]);
655
- $w[$i] = $w[$i]->add($s1);
656
- }
657
-
658
- // Initialize hash value for this chunk
659
- $a = $hash[0]->copy();
660
- $b = $hash[1]->copy();
661
- $c = $hash[2]->copy();
662
- $d = $hash[3]->copy();
663
- $e = $hash[4]->copy();
664
- $f = $hash[5]->copy();
665
- $g = $hash[6]->copy();
666
- $h = $hash[7]->copy();
667
-
668
- // Main loop
669
- for ($i = 0; $i < 80; $i++) {
670
- $temp = array(
671
- $a->bitwise_rightRotate(28),
672
- $a->bitwise_rightRotate(34),
673
- $a->bitwise_rightRotate(39)
674
- );
675
- $s0 = $temp[0]->bitwise_xor($temp[1]);
676
- $s0 = $s0->bitwise_xor($temp[2]);
677
- $temp = array(
678
- $a->bitwise_and($b),
679
- $a->bitwise_and($c),
680
- $b->bitwise_and($c)
681
- );
682
- $maj = $temp[0]->bitwise_xor($temp[1]);
683
- $maj = $maj->bitwise_xor($temp[2]);
684
- $t2 = $s0->add($maj);
685
-
686
- $temp = array(
687
- $e->bitwise_rightRotate(14),
688
- $e->bitwise_rightRotate(18),
689
- $e->bitwise_rightRotate(41)
690
- );
691
- $s1 = $temp[0]->bitwise_xor($temp[1]);
692
- $s1 = $s1->bitwise_xor($temp[2]);
693
- $temp = array(
694
- $e->bitwise_and($f),
695
- $g->bitwise_and($e->bitwise_not())
696
- );
697
- $ch = $temp[0]->bitwise_xor($temp[1]);
698
- $t1 = $h->add($s1);
699
- $t1 = $t1->add($ch);
700
- $t1 = $t1->add($k[$i]);
701
- $t1 = $t1->add($w[$i]);
702
-
703
- $h = $g->copy();
704
- $g = $f->copy();
705
- $f = $e->copy();
706
- $e = $d->add($t1);
707
- $d = $c->copy();
708
- $c = $b->copy();
709
- $b = $a->copy();
710
- $a = $t1->add($t2);
711
- }
712
-
713
- // Add this chunk's hash to result so far
714
- $hash = array(
715
- $hash[0]->add($a),
716
- $hash[1]->add($b),
717
- $hash[2]->add($c),
718
- $hash[3]->add($d),
719
- $hash[4]->add($e),
720
- $hash[5]->add($f),
721
- $hash[6]->add($g),
722
- $hash[7]->add($h)
723
- );
724
- }
725
-
726
- // Produce the final hash value (big-endian)
727
- // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
728
- $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
729
- $hash[4]->toBytes() . $hash[5]->toBytes();
730
- if ($this->l != 48) {
731
- $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
732
- }
733
-
734
- return $temp;
735
- }
736
-
737
- /**
738
- * Right Rotate
739
- *
740
- * @access private
741
- * @param Integer $int
742
- * @param Integer $amt
743
- * @see _sha256()
744
- * @return Integer
745
- */
746
- function _rightRotate($int, $amt)
747
- {
748
- $invamt = 32 - $amt;
749
- $mask = (1 << $invamt) - 1;
750
- return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
751
- }
752
-
753
- /**
754
- * Right Shift
755
- *
756
- * @access private
757
- * @param Integer $int
758
- * @param Integer $amt
759
- * @see _sha256()
760
- * @return Integer
761
- */
762
- function _rightShift($int, $amt)
763
- {
764
- $mask = (1 << (32 - $amt)) - 1;
765
- return ($int >> $amt) & $mask;
766
- }
767
-
768
- /**
769
- * Not
770
- *
771
- * @access private
772
- * @param Integer $int
773
- * @see _sha256()
774
- * @return Integer
775
- */
776
- function _not($int)
777
- {
778
- return ~$int & 0xFFFFFFFF;
779
- }
780
-
781
- /**
782
- * Add
783
- *
784
- * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
785
- * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
786
- *
787
- * @param String $string
788
- * @param optional Integer $index
789
- * @return String
790
- * @see _sha256()
791
- * @access private
792
- */
793
- function _add()
794
- {
795
- static $mod;
796
- if (!isset($mod)) {
797
- $mod = pow(2, 32);
798
- }
799
-
800
- $result = 0;
801
- $arguments = func_get_args();
802
- foreach ($arguments as $argument) {
803
- $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
804
- }
805
-
806
- return fmod($result, $mod);
807
- }
808
-
809
- /**
810
- * String Shift
811
- *
812
- * Inspired by array_shift
813
- *
814
- * @param String $string
815
- * @param optional Integer $index
816
- * @return String
817
- * @access private
818
- */
819
- function _string_shift(&$string, $index = 1)
820
- {
821
- $substr = substr($string, 0, $index);
822
- $string = substr($string, $index);
823
- return $substr;
824
- }
825
- }
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: Permission is hereby granted, free of charge, to any person obtaining a copy
33
+ * of this software and associated documentation files (the "Software"), to deal
34
+ * in the Software without restriction, including without limitation the rights
35
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
+ * copies of the Software, and to permit persons to whom the Software is
37
+ * furnished to do so, subject to the following conditions:
38
+ *
39
+ * The above copyright notice and this permission notice shall be included in
40
+ * all copies or substantial portions of the Software.
41
+ *
42
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48
+ * THE SOFTWARE.
49
+ *
50
+ * @category Crypt
51
+ * @package Crypt_Hash
52
+ * @author Jim Wigginton <terrafrost@php.net>
53
+ * @copyright MMVII Jim Wigginton
54
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
55
+ * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $
56
+ * @link http://phpseclib.sourceforge.net
57
+ */
58
+
59
+ /**#@+
60
+ * @access private
61
+ * @see Crypt_Hash::Crypt_Hash()
62
+ */
63
+ /**
64
+ * Toggles the internal implementation
65
+ */
66
+ define('CRYPT_HASH_MODE_INTERNAL', 1);
67
+ /**
68
+ * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
69
+ */
70
+ define('CRYPT_HASH_MODE_MHASH', 2);
71
+ /**
72
+ * Toggles the hash() implementation, which works on PHP 5.1.2+.
73
+ */
74
+ define('CRYPT_HASH_MODE_HASH', 3);
75
+ /**#@-*/
76
+
77
+ /**
78
+ * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
79
+ *
80
+ * @author Jim Wigginton <terrafrost@php.net>
81
+ * @version 0.1.0
82
+ * @access public
83
+ * @package Crypt_Hash
84
+ */
85
+ class Crypt_Hash {
86
+ /**
87
+ * Byte-length of compression blocks / key (Internal HMAC)
88
+ *
89
+ * @see Crypt_Hash::setAlgorithm()
90
+ * @var Integer
91
+ * @access private
92
+ */
93
+ var $b;
94
+
95
+ /**
96
+ * Byte-length of hash output (Internal HMAC)
97
+ *
98
+ * @see Crypt_Hash::setHash()
99
+ * @var Integer
100
+ * @access private
101
+ */
102
+ var $l = false;
103
+
104
+ /**
105
+ * Hash Algorithm
106
+ *
107
+ * @see Crypt_Hash::setHash()
108
+ * @var String
109
+ * @access private
110
+ */
111
+ var $hash;
112
+
113
+ /**
114
+ * Key
115
+ *
116
+ * @see Crypt_Hash::setKey()
117
+ * @var String
118
+ * @access private
119
+ */
120
+ var $key = false;
121
+
122
+ /**
123
+ * Outer XOR (Internal HMAC)
124
+ *
125
+ * @see Crypt_Hash::setKey()
126
+ * @var String
127
+ * @access private
128
+ */
129
+ var $opad;
130
+
131
+ /**
132
+ * Inner XOR (Internal HMAC)
133
+ *
134
+ * @see Crypt_Hash::setKey()
135
+ * @var String
136
+ * @access private
137
+ */
138
+ var $ipad;
139
+
140
+ /**
141
+ * Default Constructor.
142
+ *
143
+ * @param optional String $hash
144
+ * @return Crypt_Hash
145
+ * @access public
146
+ */
147
+ function Crypt_Hash($hash = 'sha1')
148
+ {
149
+ if ( !defined('CRYPT_HASH_MODE') ) {
150
+ switch (true) {
151
+ case extension_loaded('hash'):
152
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
153
+ break;
154
+ case extension_loaded('mhash'):
155
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
156
+ break;
157
+ default:
158
+ define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
159
+ }
160
+ }
161
+
162
+ $this->setHash($hash);
163
+ }
164
+
165
+ /**
166
+ * Sets the key for HMACs
167
+ *
168
+ * Keys can be of any length.
169
+ *
170
+ * @access public
171
+ * @param String $key
172
+ */
173
+ function setKey($key = false)
174
+ {
175
+ $this->key = $key;
176
+ }
177
+
178
+ /**
179
+ * Sets the hash function.
180
+ *
181
+ * @access public
182
+ * @param String $hash
183
+ */
184
+ function setHash($hash)
185
+ {
186
+ $hash = strtolower($hash);
187
+ switch ($hash) {
188
+ case 'md5-96':
189
+ case 'sha1-96':
190
+ $this->l = 12; // 96 / 8 = 12
191
+ break;
192
+ case 'md2':
193
+ case 'md5':
194
+ $this->l = 16;
195
+ break;
196
+ case 'sha1':
197
+ $this->l = 20;
198
+ break;
199
+ case 'sha256':
200
+ $this->l = 32;
201
+ break;
202
+ case 'sha384':
203
+ $this->l = 48;
204
+ break;
205
+ case 'sha512':
206
+ $this->l = 64;
207
+ }
208
+
209
+ switch ($hash) {
210
+ case 'md2':
211
+ $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
212
+ CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
213
+ break;
214
+ case 'sha384':
215
+ case 'sha512':
216
+ $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
217
+ break;
218
+ default:
219
+ $mode = CRYPT_HASH_MODE;
220
+ }
221
+
222
+ switch ( $mode ) {
223
+ case CRYPT_HASH_MODE_MHASH:
224
+ switch ($hash) {
225
+ case 'md5':
226
+ case 'md5-96':
227
+ $this->hash = MHASH_MD5;
228
+ break;
229
+ case 'sha256':
230
+ $this->hash = MHASH_SHA256;
231
+ break;
232
+ case 'sha1':
233
+ case 'sha1-96':
234
+ default:
235
+ $this->hash = MHASH_SHA1;
236
+ }
237
+ return;
238
+ case CRYPT_HASH_MODE_HASH:
239
+ switch ($hash) {
240
+ case 'md5':
241
+ case 'md5-96':
242
+ $this->hash = 'md5';
243
+ return;
244
+ case 'md2':
245
+ case 'sha256':
246
+ case 'sha384':
247
+ case 'sha512':
248
+ $this->hash = $hash;
249
+ return;
250
+ case 'sha1':
251
+ case 'sha1-96':
252
+ default:
253
+ $this->hash = 'sha1';
254
+ }
255
+ return;
256
+ }
257
+
258
+ switch ($hash) {
259
+ case 'md2':
260
+ $this->b = 16;
261
+ $this->hash = array($this, '_md2');
262
+ break;
263
+ case 'md5':
264
+ case 'md5-96':
265
+ $this->b = 64;
266
+ $this->hash = array($this, '_md5');
267
+ break;
268
+ case 'sha256':
269
+ $this->b = 64;
270
+ $this->hash = array($this, '_sha256');
271
+ break;
272
+ case 'sha384':
273
+ case 'sha512':
274
+ $this->b = 128;
275
+ $this->hash = array($this, '_sha512');
276
+ break;
277
+ case 'sha1':
278
+ case 'sha1-96':
279
+ default:
280
+ $this->b = 64;
281
+ $this->hash = array($this, '_sha1');
282
+ }
283
+
284
+ $this->ipad = str_repeat(chr(0x36), $this->b);
285
+ $this->opad = str_repeat(chr(0x5C), $this->b);
286
+ }
287
+
288
+ /**
289
+ * Compute the HMAC.
290
+ *
291
+ * @access public
292
+ * @param String $text
293
+ * @return String
294
+ */
295
+ function hash($text)
296
+ {
297
+ $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
298
+
299
+ if (!empty($this->key) || is_string($this->key)) {
300
+ switch ( $mode ) {
301
+ case CRYPT_HASH_MODE_MHASH:
302
+ $output = mhash($this->hash, $text, $this->key);
303
+ break;
304
+ case CRYPT_HASH_MODE_HASH:
305
+ $output = hash_hmac($this->hash, $text, $this->key, true);
306
+ break;
307
+ case CRYPT_HASH_MODE_INTERNAL:
308
+ /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
309
+ resultant L byte string as the actual key to HMAC."
310
+
311
+ -- http://tools.ietf.org/html/rfc2104#section-2 */
312
+ $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
313
+
314
+ $key = str_pad($key, $this->b, chr(0)); // step 1
315
+ $temp = $this->ipad ^ $key; // step 2
316
+ $temp .= $text; // step 3
317
+ $temp = call_user_func($this->hash, $temp); // step 4
318
+ $output = $this->opad ^ $key; // step 5
319
+ $output.= $temp; // step 6
320
+ $output = call_user_func($this->hash, $output); // step 7
321
+ }
322
+ } else {
323
+ switch ( $mode ) {
324
+ case CRYPT_HASH_MODE_MHASH:
325
+ $output = mhash($this->hash, $text);
326
+ break;
327
+ case CRYPT_HASH_MODE_HASH:
328
+ $output = hash($this->hash, $text, true);
329
+ break;
330
+ case CRYPT_HASH_MODE_INTERNAL:
331
+ $output = call_user_func($this->hash, $text);
332
+ }
333
+ }
334
+
335
+ return substr($output, 0, $this->l);
336
+ }
337
+
338
+ /**
339
+ * Returns the hash length (in bytes)
340
+ *
341
+ * @access public
342
+ * @return Integer
343
+ */
344
+ function getLength()
345
+ {
346
+ return $this->l;
347
+ }
348
+
349
+ /**
350
+ * Wrapper for MD5
351
+ *
352
+ * @access private
353
+ * @param String $text
354
+ */
355
+ function _md5($m)
356
+ {
357
+ return pack('H*', md5($m));
358
+ }
359
+
360
+ /**
361
+ * Wrapper for SHA1
362
+ *
363
+ * @access private
364
+ * @param String $text
365
+ */
366
+ function _sha1($m)
367
+ {
368
+ return pack('H*', sha1($m));
369
+ }
370
+
371
+ /**
372
+ * Pure-PHP implementation of MD2
373
+ *
374
+ * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
375
+ *
376
+ * @access private
377
+ * @param String $text
378
+ */
379
+ function _md2($m)
380
+ {
381
+ static $s = array(
382
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
383
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
384
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
385
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
386
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
387
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
388
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
389
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
390
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
391
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
392
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
393
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
394
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
395
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
396
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
397
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
398
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
399
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
400
+ );
401
+
402
+ // Step 1. Append Padding Bytes
403
+ $pad = 16 - (strlen($m) & 0xF);
404
+ $m.= str_repeat(chr($pad), $pad);
405
+
406
+ $length = strlen($m);
407
+
408
+ // Step 2. Append Checksum
409
+ $c = str_repeat(chr(0), 16);
410
+ $l = chr(0);
411
+ for ($i = 0; $i < $length; $i+= 16) {
412
+ for ($j = 0; $j < 16; $j++) {
413
+ // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
414
+ //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
415
+ // per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
416
+ $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
417
+ $l = $c[$j];
418
+ }
419
+ }
420
+ $m.= $c;
421
+
422
+ $length+= 16;
423
+
424
+ // Step 3. Initialize MD Buffer
425
+ $x = str_repeat(chr(0), 48);
426
+
427
+ // Step 4. Process Message in 16-Byte Blocks
428
+ for ($i = 0; $i < $length; $i+= 16) {
429
+ for ($j = 0; $j < 16; $j++) {
430
+ $x[$j + 16] = $m[$i + $j];
431
+ $x[$j + 32] = $x[$j + 16] ^ $x[$j];
432
+ }
433
+ $t = chr(0);
434
+ for ($j = 0; $j < 18; $j++) {
435
+ for ($k = 0; $k < 48; $k++) {
436
+ $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
437
+ //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
438
+ }
439
+ $t = chr(ord($t) + $j);
440
+ }
441
+ }
442
+
443
+ // Step 5. Output
444
+ return substr($x, 0, 16);
445
+ }
446
+
447
+ /**
448
+ * Pure-PHP implementation of SHA256
449
+ *
450
+ * 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}.
451
+ *
452
+ * @access private
453
+ * @param String $text
454
+ */
455
+ function _sha256($m)
456
+ {
457
+ if (extension_loaded('suhosin')) {
458
+ return pack('H*', sha256($m));
459
+ }
460
+
461
+ // Initialize variables
462
+ $hash = array(
463
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
464
+ );
465
+ // Initialize table of round constants
466
+ // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
467
+ static $k = array(
468
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
469
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
470
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
471
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
472
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
473
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
474
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
475
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
476
+ );
477
+
478
+ // Pre-processing
479
+ $length = strlen($m);
480
+ // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
481
+ $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
482
+ $m[$length] = chr(0x80);
483
+ // we don't support hashing strings 512MB long
484
+ $m.= pack('N2', 0, $length << 3);
485
+
486
+ // Process the message in successive 512-bit chunks
487
+ $chunks = str_split($m, 64);
488
+ foreach ($chunks as $chunk) {
489
+ $w = array();
490
+ for ($i = 0; $i < 16; $i++) {
491
+ extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
492
+ $w[] = $temp;
493
+ }
494
+
495
+ // Extend the sixteen 32-bit words into sixty-four 32-bit words
496
+ for ($i = 16; $i < 64; $i++) {
497
+ $s0 = $this->_rightRotate($w[$i - 15], 7) ^
498
+ $this->_rightRotate($w[$i - 15], 18) ^
499
+ $this->_rightShift( $w[$i - 15], 3);
500
+ $s1 = $this->_rightRotate($w[$i - 2], 17) ^
501
+ $this->_rightRotate($w[$i - 2], 19) ^
502
+ $this->_rightShift( $w[$i - 2], 10);
503
+ $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
504
+
505
+ }
506
+
507
+ // Initialize hash value for this chunk
508
+ list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
509
+
510
+ // Main loop
511
+ for ($i = 0; $i < 64; $i++) {
512
+ $s0 = $this->_rightRotate($a, 2) ^
513
+ $this->_rightRotate($a, 13) ^
514
+ $this->_rightRotate($a, 22);
515
+ $maj = ($a & $b) ^
516
+ ($a & $c) ^
517
+ ($b & $c);
518
+ $t2 = $this->_add($s0, $maj);
519
+
520
+ $s1 = $this->_rightRotate($e, 6) ^
521
+ $this->_rightRotate($e, 11) ^
522
+ $this->_rightRotate($e, 25);
523
+ $ch = ($e & $f) ^
524
+ ($this->_not($e) & $g);
525
+ $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
526
+
527
+ $h = $g;
528
+ $g = $f;
529
+ $f = $e;
530
+ $e = $this->_add($d, $t1);
531
+ $d = $c;
532
+ $c = $b;
533
+ $b = $a;
534
+ $a = $this->_add($t1, $t2);
535
+ }
536
+
537
+ // Add this chunk's hash to result so far
538
+ $hash = array(
539
+ $this->_add($hash[0], $a),
540
+ $this->_add($hash[1], $b),
541
+ $this->_add($hash[2], $c),
542
+ $this->_add($hash[3], $d),
543
+ $this->_add($hash[4], $e),
544
+ $this->_add($hash[5], $f),
545
+ $this->_add($hash[6], $g),
546
+ $this->_add($hash[7], $h)
547
+ );
548
+ }
549
+
550
+ // Produce the final hash value (big-endian)
551
+ return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
552
+ }
553
+
554
+ /**
555
+ * Pure-PHP implementation of SHA384 and SHA512
556
+ *
557
+ * @access private
558
+ * @param String $text
559
+ */
560
+ function _sha512($m)
561
+ {
562
+ if (!class_exists('Math_BigInteger')) {
563
+ require_once('Math/BigInteger.php');
564
+ }
565
+
566
+ static $init384, $init512, $k;
567
+
568
+ if (!isset($k)) {
569
+ // Initialize variables
570
+ $init384 = array( // initial values for SHA384
571
+ 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
572
+ '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
573
+ );
574
+ $init512 = array( // initial values for SHA512
575
+ '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
576
+ '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
577
+ );
578
+
579
+ for ($i = 0; $i < 8; $i++) {
580
+ $init384[$i] = new Math_BigInteger($init384[$i], 16);
581
+ $init384[$i]->setPrecision(64);
582
+ $init512[$i] = new Math_BigInteger($init512[$i], 16);
583
+ $init512[$i]->setPrecision(64);
584
+ }
585
+
586
+ // Initialize table of round constants
587
+ // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
588
+ $k = array(
589
+ '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
590
+ '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
591
+ 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
592
+ '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
593
+ 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
594
+ '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
595
+ '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
596
+ 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
597
+ '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
598
+ '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
599
+ 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
600
+ 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
601
+ '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
602
+ '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
603
+ '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
604
+ '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
605
+ 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
606
+ '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
607
+ '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
608
+ '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
609
+ );
610
+
611
+ for ($i = 0; $i < 80; $i++) {
612
+ $k[$i] = new Math_BigInteger($k[$i], 16);
613
+ }
614
+ }
615
+
616
+ $hash = $this->l == 48 ? $init384 : $init512;
617
+
618
+ // Pre-processing
619
+ $length = strlen($m);
620
+ // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
621
+ $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
622
+ $m[$length] = chr(0x80);
623
+ // we don't support hashing strings 512MB long
624
+ $m.= pack('N4', 0, 0, 0, $length << 3);
625
+
626
+ // Process the message in successive 1024-bit chunks
627
+ $chunks = str_split($m, 128);
628
+ foreach ($chunks as $chunk) {
629
+ $w = array();
630
+ for ($i = 0; $i < 16; $i++) {
631
+ $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
632
+ $temp->setPrecision(64);
633
+ $w[] = $temp;
634
+ }
635
+
636
+ // Extend the sixteen 32-bit words into eighty 32-bit words
637
+ for ($i = 16; $i < 80; $i++) {
638
+ $temp = array(
639
+ $w[$i - 15]->bitwise_rightRotate(1),
640
+ $w[$i - 15]->bitwise_rightRotate(8),
641
+ $w[$i - 15]->bitwise_rightShift(7)
642
+ );
643
+ $s0 = $temp[0]->bitwise_xor($temp[1]);
644
+ $s0 = $s0->bitwise_xor($temp[2]);
645
+ $temp = array(
646
+ $w[$i - 2]->bitwise_rightRotate(19),
647
+ $w[$i - 2]->bitwise_rightRotate(61),
648
+ $w[$i - 2]->bitwise_rightShift(6)
649
+ );
650
+ $s1 = $temp[0]->bitwise_xor($temp[1]);
651
+ $s1 = $s1->bitwise_xor($temp[2]);
652
+ $w[$i] = $w[$i - 16]->copy();
653
+ $w[$i] = $w[$i]->add($s0);
654
+ $w[$i] = $w[$i]->add($w[$i - 7]);
655
+ $w[$i] = $w[$i]->add($s1);
656
+ }
657
+
658
+ // Initialize hash value for this chunk
659
+ $a = $hash[0]->copy();
660
+ $b = $hash[1]->copy();
661
+ $c = $hash[2]->copy();
662
+ $d = $hash[3]->copy();
663
+ $e = $hash[4]->copy();
664
+ $f = $hash[5]->copy();
665
+ $g = $hash[6]->copy();
666
+ $h = $hash[7]->copy();
667
+
668
+ // Main loop
669
+ for ($i = 0; $i < 80; $i++) {
670
+ $temp = array(
671
+ $a->bitwise_rightRotate(28),
672
+ $a->bitwise_rightRotate(34),
673
+ $a->bitwise_rightRotate(39)
674
+ );
675
+ $s0 = $temp[0]->bitwise_xor($temp[1]);
676
+ $s0 = $s0->bitwise_xor($temp[2]);
677
+ $temp = array(
678
+ $a->bitwise_and($b),
679
+ $a->bitwise_and($c),
680
+ $b->bitwise_and($c)
681
+ );
682
+ $maj = $temp[0]->bitwise_xor($temp[1]);
683
+ $maj = $maj->bitwise_xor($temp[2]);
684
+ $t2 = $s0->add($maj);
685
+
686
+ $temp = array(
687
+ $e->bitwise_rightRotate(14),
688
+ $e->bitwise_rightRotate(18),
689
+ $e->bitwise_rightRotate(41)
690
+ );
691
+ $s1 = $temp[0]->bitwise_xor($temp[1]);
692
+ $s1 = $s1->bitwise_xor($temp[2]);
693
+ $temp = array(
694
+ $e->bitwise_and($f),
695
+ $g->bitwise_and($e->bitwise_not())
696
+ );
697
+ $ch = $temp[0]->bitwise_xor($temp[1]);
698
+ $t1 = $h->add($s1);
699
+ $t1 = $t1->add($ch);
700
+ $t1 = $t1->add($k[$i]);
701
+ $t1 = $t1->add($w[$i]);
702
+
703
+ $h = $g->copy();
704
+ $g = $f->copy();
705
+ $f = $e->copy();
706
+ $e = $d->add($t1);
707
+ $d = $c->copy();
708
+ $c = $b->copy();
709
+ $b = $a->copy();
710
+ $a = $t1->add($t2);
711
+ }
712
+
713
+ // Add this chunk's hash to result so far
714
+ $hash = array(
715
+ $hash[0]->add($a),
716
+ $hash[1]->add($b),
717
+ $hash[2]->add($c),
718
+ $hash[3]->add($d),
719
+ $hash[4]->add($e),
720
+ $hash[5]->add($f),
721
+ $hash[6]->add($g),
722
+ $hash[7]->add($h)
723
+ );
724
+ }
725
+
726
+ // Produce the final hash value (big-endian)
727
+ // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
728
+ $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
729
+ $hash[4]->toBytes() . $hash[5]->toBytes();
730
+ if ($this->l != 48) {
731
+ $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
732
+ }
733
+
734
+ return $temp;
735
+ }
736
+
737
+ /**
738
+ * Right Rotate
739
+ *
740
+ * @access private
741
+ * @param Integer $int
742
+ * @param Integer $amt
743
+ * @see _sha256()
744
+ * @return Integer
745
+ */
746
+ function _rightRotate($int, $amt)
747
+ {
748
+ $invamt = 32 - $amt;
749
+ $mask = (1 << $invamt) - 1;
750
+ return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
751
+ }
752
+
753
+ /**
754
+ * Right Shift
755
+ *
756
+ * @access private
757
+ * @param Integer $int
758
+ * @param Integer $amt
759
+ * @see _sha256()
760
+ * @return Integer
761
+ */
762
+ function _rightShift($int, $amt)
763
+ {
764
+ $mask = (1 << (32 - $amt)) - 1;
765
+ return ($int >> $amt) & $mask;
766
+ }
767
+
768
+ /**
769
+ * Not
770
+ *
771
+ * @access private
772
+ * @param Integer $int
773
+ * @see _sha256()
774
+ * @return Integer
775
+ */
776
+ function _not($int)
777
+ {
778
+ return ~$int & 0xFFFFFFFF;
779
+ }
780
+
781
+ /**
782
+ * Add
783
+ *
784
+ * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
785
+ * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
786
+ *
787
+ * @param String $string
788
+ * @param optional Integer $index
789
+ * @return String
790
+ * @see _sha256()
791
+ * @access private
792
+ */
793
+ function _add()
794
+ {
795
+ static $mod;
796
+ if (!isset($mod)) {
797
+ $mod = pow(2, 32);
798
+ }
799
+
800
+ $result = 0;
801
+ $arguments = func_get_args();
802
+ foreach ($arguments as $argument) {
803
+ $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
804
+ }
805
+
806
+ return fmod($result, $mod);
807
+ }
808
+
809
+ /**
810
+ * String Shift
811
+ *
812
+ * Inspired by array_shift
813
+ *
814
+ * @param String $string
815
+ * @param optional Integer $index
816
+ * @return String
817
+ * @access private
818
+ */
819
+ function _string_shift(&$string, $index = 1)
820
+ {
821
+ $substr = substr($string, 0, $index);
822
+ $string = substr($string, $index);
823
+ return $substr;
824
+ }
825
+ }
phpseclib/Crypt/RC4.php CHANGED
@@ -1,564 +1,531 @@
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: Permission is hereby granted, free of charge, to any person obtaining a copy
39
- * of this software and associated documentation files (the "Software"), to deal
40
- * in the Software without restriction, including without limitation the rights
41
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
- * copies of the Software, and to permit persons to whom the Software is
43
- * furnished to do so, subject to the following conditions:
44
- *
45
- * The above copyright notice and this permission notice shall be included in
46
- * all copies or substantial portions of the Software.
47
- *
48
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54
- * THE SOFTWARE.
55
- *
56
- * @category Crypt
57
- * @package Crypt_RC4
58
- * @author Jim Wigginton <terrafrost@php.net>
59
- * @copyright MMVII Jim Wigginton
60
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
61
- * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
62
- * @link http://phpseclib.sourceforge.net
63
- */
64
-
65
- /**#@+
66
- * @access private
67
- * @see Crypt_RC4::Crypt_RC4()
68
- */
69
- /**
70
- * Toggles the internal implementation
71
- */
72
- define('CRYPT_RC4_MODE_INTERNAL', 1);
73
- /**
74
- * Toggles the mcrypt implementation
75
- */
76
- define('CRYPT_RC4_MODE_MCRYPT', 2);
77
- /**#@-*/
78
-
79
- /**#@+
80
- * @access private
81
- * @see Crypt_RC4::_crypt()
82
- */
83
- define('CRYPT_RC4_ENCRYPT', 0);
84
- define('CRYPT_RC4_DECRYPT', 1);
85
- /**#@-*/
86
-
87
- /**
88
- * Pure-PHP implementation of RC4.
89
- *
90
- * @author Jim Wigginton <terrafrost@php.net>
91
- * @version 0.1.0
92
- * @access public
93
- * @package Crypt_RC4
94
- */
95
- class Crypt_RC4 {
96
- /**
97
- * The Key
98
- *
99
- * @see Crypt_RC4::setKey()
100
- * @var String
101
- * @access private
102
- */
103
- var $key = "\0";
104
-
105
- /**
106
- * The Key Stream for encryption
107
- *
108
- * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
109
- *
110
- * @see Crypt_RC4::setKey()
111
- * @var Array
112
- * @access private
113
- */
114
- var $encryptStream = false;
115
-
116
- /**
117
- * The Key Stream for decryption
118
- *
119
- * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
120
- *
121
- * @see Crypt_RC4::setKey()
122
- * @var Array
123
- * @access private
124
- */
125
- var $decryptStream = false;
126
-
127
- /**
128
- * The $i and $j indexes for encryption
129
- *
130
- * @see Crypt_RC4::_crypt()
131
- * @var Integer
132
- * @access private
133
- */
134
- var $encryptIndex = 0;
135
-
136
- /**
137
- * The $i and $j indexes for decryption
138
- *
139
- * @see Crypt_RC4::_crypt()
140
- * @var Integer
141
- * @access private
142
- */
143
- var $decryptIndex = 0;
144
-
145
- /**
146
- * MCrypt parameters
147
- *
148
- * @see Crypt_RC4::setMCrypt()
149
- * @var Array
150
- * @access private
151
- */
152
- var $mcrypt = array('', '');
153
-
154
- /**
155
- * The Encryption Algorithm
156
- *
157
- * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
158
- *
159
- * @see Crypt_RC4::Crypt_RC4()
160
- * @var Integer
161
- * @access private
162
- */
163
- var $mode;
164
-
165
- /**
166
- * Continuous Buffer status
167
- *
168
- * @see Crypt_RC4::enableContinuousBuffer()
169
- * @var Boolean
170
- * @access private
171
- */
172
- var $continuousBuffer = false;
173
-
174
- /**
175
- * Default Constructor.
176
- *
177
- * Determines whether or not the mcrypt extension should be used.
178
- *
179
- * @param optional Integer $mode
180
- * @return Crypt_RC4
181
- * @access public
182
- */
183
- function Crypt_RC4()
184
- {
185
- if ( !defined('CRYPT_RC4_MODE') ) {
186
- switch (true) {
187
- case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')):
188
- // i'd check to see if rc4 was supported, by doing in_array('arcfour', mcrypt_list_algorithms('')),
189
- // but since that can be changed after the object has been created, there doesn't seem to be
190
- // a lot of point...
191
- define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
192
- break;
193
- default:
194
- define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
195
- }
196
- }
197
-
198
- switch ( CRYPT_RC4_MODE ) {
199
- case CRYPT_RC4_MODE_MCRYPT:
200
- switch (true) {
201
- case defined('MCRYPT_ARCFOUR'):
202
- $this->mode = MCRYPT_ARCFOUR;
203
- break;
204
- case defined('MCRYPT_RC4');
205
- $this->mode = MCRYPT_RC4;
206
- }
207
- }
208
- }
209
-
210
- /**
211
- * Sets the key.
212
- *
213
- * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
214
- * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
215
- *
216
- * @access public
217
- * @param String $key
218
- */
219
- function setKey($key)
220
- {
221
- $this->key = $key;
222
-
223
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
224
- return;
225
- }
226
-
227
- $keyLength = strlen($key);
228
- $keyStream = array();
229
- for ($i = 0; $i < 256; $i++) {
230
- $keyStream[$i] = $i;
231
- }
232
- $j = 0;
233
- for ($i = 0; $i < 256; $i++) {
234
- $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
235
- $temp = $keyStream[$i];
236
- $keyStream[$i] = $keyStream[$j];
237
- $keyStream[$j] = $temp;
238
- }
239
-
240
- $this->encryptIndex = $this->decryptIndex = array(0, 0);
241
- $this->encryptStream = $this->decryptStream = $keyStream;
242
- }
243
-
244
- /**
245
- * Sets the password.
246
- *
247
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
248
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
249
- * $hash, $salt, $method, $dkLen
250
- *
251
- * @param String $password
252
- * @param optional String $method
253
- * @access public
254
- */
255
- function setPassword($password, $method = 'pbkdf2')
256
- {
257
- $key = '';
258
-
259
- switch ($method) {
260
- default: // 'pbkdf2'
261
- list(, , $hash, $salt, $count) = func_get_args();
262
- if (!isset($hash)) {
263
- $hash = 'sha1';
264
- }
265
- // WPA and WPA use the SSID as the salt
266
- if (!isset($salt)) {
267
- $salt = 'phpseclib';
268
- }
269
- // RFC2898#section-4.2 uses 1,000 iterations by default
270
- // WPA and WPA2 use 4,096.
271
- if (!isset($count)) {
272
- $count = 1000;
273
- }
274
- if (!isset($count)) {
275
- $count = 1000;
276
- }
277
- if (!isset($dkLen)) {
278
- $count = 1000;
279
- }
280
-
281
- if (!class_exists('Crypt_Hash')) {
282
- require_once('Crypt/Hash.php');
283
- }
284
-
285
- $i = 1;
286
- while (strlen($key) < $dkLen) {
287
- //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
288
- $hmac = new Crypt_Hash();
289
- $hmac->setHash($hash);
290
- $hmac->setKey($password);
291
- $f = $u = $hmac->hash($salt . pack('N', $i++));
292
- for ($j = 2; $j <= $count; $j++) {
293
- $u = $hmac->hash($u);
294
- $f^= $u;
295
- }
296
- $key.= $f;
297
- }
298
- }
299
-
300
- $this->setKey(substr($key, 0, $dkLen));
301
- }
302
-
303
- /**
304
- * Dummy function.
305
- *
306
- * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
307
- * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
308
- * calling setKey().
309
- *
310
- * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
311
- * the IV's are relatively easy to predict, an attack described by
312
- * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
313
- * can be used to quickly guess at the rest of the key. The following links elaborate:
314
- *
315
- * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
316
- * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
317
- *
318
- * @param String $iv
319
- * @see Crypt_RC4::setKey()
320
- * @access public
321
- */
322
- function setIV($iv)
323
- {
324
- }
325
-
326
- /**
327
- * Sets MCrypt parameters. (optional)
328
- *
329
- * If MCrypt is being used, empty strings will be used, unless otherwise specified.
330
- *
331
- * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
332
- * @access public
333
- * @param optional Integer $algorithm_directory
334
- * @param optional Integer $mode_directory
335
- */
336
- function setMCrypt($algorithm_directory = '', $mode_directory = '')
337
- {
338
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
339
- $this->mcrypt = array($algorithm_directory, $mode_directory);
340
- $this->_closeMCrypt();
341
- }
342
- }
343
-
344
- /**
345
- * Encrypts a message.
346
- *
347
- * @see Crypt_RC4::_crypt()
348
- * @access public
349
- * @param String $plaintext
350
- */
351
- function encrypt($plaintext)
352
- {
353
- return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
354
- }
355
-
356
- /**
357
- * Decrypts a message.
358
- *
359
- * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
360
- * Atleast if the continuous buffer is disabled.
361
- *
362
- * @see Crypt_RC4::_crypt()
363
- * @access public
364
- * @param String $ciphertext
365
- */
366
- function decrypt($ciphertext)
367
- {
368
- return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
369
- }
370
-
371
- /**
372
- * Encrypts or decrypts a message.
373
- *
374
- * @see Crypt_RC4::encrypt()
375
- * @see Crypt_RC4::decrypt()
376
- * @access private
377
- * @param String $text
378
- * @param Integer $mode
379
- */
380
- function _crypt($text, $mode)
381
- {
382
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
383
- $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
384
-
385
- if ($this->$keyStream === false) {
386
- $this->$keyStream = mcrypt_module_open($this->mode, $this->mcrypt[0], MCRYPT_MODE_STREAM, $this->mcrypt[1]);
387
- mcrypt_generic_init($this->$keyStream, $this->key, '');
388
- } else if (!$this->continuousBuffer) {
389
- mcrypt_generic_init($this->$keyStream, $this->key, '');
390
- }
391
- $newText = mcrypt_generic($this->$keyStream, $text);
392
- if (!$this->continuousBuffer) {
393
- mcrypt_generic_deinit($this->$keyStream);
394
- }
395
-
396
- return $newText;
397
- }
398
-
399
- if ($this->encryptStream === false) {
400
- $this->setKey($this->key);
401
- }
402
-
403
- switch ($mode) {
404
- case CRYPT_RC4_ENCRYPT:
405
- $keyStream = $this->encryptStream;
406
- list($i, $j) = $this->encryptIndex;
407
- break;
408
- case CRYPT_RC4_DECRYPT:
409
- $keyStream = $this->decryptStream;
410
- list($i, $j) = $this->decryptIndex;
411
- }
412
-
413
- $newText = '';
414
- for ($k = 0; $k < strlen($text); $k++) {
415
- $i = ($i + 1) & 255;
416
- $j = ($j + $keyStream[$i]) & 255;
417
- $temp = $keyStream[$i];
418
- $keyStream[$i] = $keyStream[$j];
419
- $keyStream[$j] = $temp;
420
- $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
421
- $newText.= chr(ord($text[$k]) ^ $temp);
422
- }
423
-
424
- if ($this->continuousBuffer) {
425
- switch ($mode) {
426
- case CRYPT_RC4_ENCRYPT:
427
- $this->encryptStream = $keyStream;
428
- $this->encryptIndex = array($i, $j);
429
- break;
430
- case CRYPT_RC4_DECRYPT:
431
- $this->decryptStream = $keyStream;
432
- $this->decryptIndex = array($i, $j);
433
- }
434
- }
435
-
436
- return $newText;
437
- }
438
-
439
- /**
440
- * Treat consecutive "packets" as if they are a continuous buffer.
441
- *
442
- * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
443
- * will yield different outputs:
444
- *
445
- * <code>
446
- * echo $rc4->encrypt(substr($plaintext, 0, 8));
447
- * echo $rc4->encrypt(substr($plaintext, 8, 8));
448
- * </code>
449
- * <code>
450
- * echo $rc4->encrypt($plaintext);
451
- * </code>
452
- *
453
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
454
- * another, as demonstrated with the following:
455
- *
456
- * <code>
457
- * $rc4->encrypt(substr($plaintext, 0, 8));
458
- * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
459
- * </code>
460
- * <code>
461
- * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
462
- * </code>
463
- *
464
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
465
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
466
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
467
- *
468
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
469
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
470
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
471
- * however, they are also less intuitive and more likely to cause you problems.
472
- *
473
- * @see Crypt_RC4::disableContinuousBuffer()
474
- * @access public
475
- */
476
- function enableContinuousBuffer()
477
- {
478
- $this->continuousBuffer = true;
479
- }
480
-
481
- /**
482
- * Treat consecutive packets as if they are a discontinuous buffer.
483
- *
484
- * The default behavior.
485
- *
486
- * @see Crypt_RC4::enableContinuousBuffer()
487
- * @access public
488
- */
489
- function disableContinuousBuffer()
490
- {
491
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
492
- $this->encryptIndex = $this->decryptIndex = array(0, 0);
493
- $this->setKey($this->key);
494
- }
495
-
496
- $this->continuousBuffer = false;
497
- }
498
-
499
- /**
500
- * Dummy function.
501
- *
502
- * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
503
- * included is so that you can switch between a block cipher and a stream cipher transparently.
504
- *
505
- * @see Crypt_RC4::disablePadding()
506
- * @access public
507
- */
508
- function enablePadding()
509
- {
510
- }
511
-
512
- /**
513
- * Dummy function.
514
- *
515
- * @see Crypt_RC4::enablePadding()
516
- * @access public
517
- */
518
- function disablePadding()
519
- {
520
- }
521
-
522
- /**
523
- * Class destructor.
524
- *
525
- * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
526
- * needs to be called if mcrypt is being used.
527
- *
528
- * @access public
529
- */
530
- function __destruct()
531
- {
532
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
533
- $this->_closeMCrypt();
534
- }
535
- }
536
-
537
- /**
538
- * Properly close the MCrypt objects.
539
- *
540
- * @access prviate
541
- */
542
- function _closeMCrypt()
543
- {
544
- if ( $this->encryptStream !== false ) {
545
- if ( $this->continuousBuffer ) {
546
- mcrypt_generic_deinit($this->encryptStream);
547
- }
548
-
549
- mcrypt_module_close($this->encryptStream);
550
-
551
- $this->encryptStream = false;
552
- }
553
-
554
- if ( $this->decryptStream !== false ) {
555
- if ( $this->continuousBuffer ) {
556
- mcrypt_generic_deinit($this->decryptStream);
557
- }
558
-
559
- mcrypt_module_close($this->decryptStream);
560
-
561
- $this->decryptStream = false;
562
- }
563
- }
564
- }
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: Permission is hereby granted, free of charge, to any person obtaining a copy
39
+ * of this software and associated documentation files (the "Software"), to deal
40
+ * in the Software without restriction, including without limitation the rights
41
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
+ * copies of the Software, and to permit persons to whom the Software is
43
+ * furnished to do so, subject to the following conditions:
44
+ *
45
+ * The above copyright notice and this permission notice shall be included in
46
+ * all copies or substantial portions of the Software.
47
+ *
48
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54
+ * THE SOFTWARE.
55
+ *
56
+ * @category Crypt
57
+ * @package Crypt_RC4
58
+ * @author Jim Wigginton <terrafrost@php.net>
59
+ * @copyright MMVII Jim Wigginton
60
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
61
+ * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
62
+ * @link http://phpseclib.sourceforge.net
63
+ */
64
+
65
+ /**#@+
66
+ * @access private
67
+ * @see Crypt_RC4::Crypt_RC4()
68
+ */
69
+ /**
70
+ * Toggles the internal implementation
71
+ */
72
+ define('CRYPT_RC4_MODE_INTERNAL', 1);
73
+ /**
74
+ * Toggles the mcrypt implementation
75
+ */
76
+ define('CRYPT_RC4_MODE_MCRYPT', 2);
77
+ /**#@-*/
78
+
79
+ /**#@+
80
+ * @access private
81
+ * @see Crypt_RC4::_crypt()
82
+ */
83
+ define('CRYPT_RC4_ENCRYPT', 0);
84
+ define('CRYPT_RC4_DECRYPT', 1);
85
+ /**#@-*/
86
+
87
+ /**
88
+ * Pure-PHP implementation of RC4.
89
+ *
90
+ * @author Jim Wigginton <terrafrost@php.net>
91
+ * @version 0.1.0
92
+ * @access public
93
+ * @package Crypt_RC4
94
+ */
95
+ class Crypt_RC4 {
96
+ /**
97
+ * The Key
98
+ *
99
+ * @see Crypt_RC4::setKey()
100
+ * @var String
101
+ * @access private
102
+ */
103
+ var $key = "\0";
104
+
105
+ /**
106
+ * The Key Stream for encryption
107
+ *
108
+ * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
109
+ *
110
+ * @see Crypt_RC4::setKey()
111
+ * @var Array
112
+ * @access private
113
+ */
114
+ var $encryptStream = false;
115
+
116
+ /**
117
+ * The Key Stream for decryption
118
+ *
119
+ * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
120
+ *
121
+ * @see Crypt_RC4::setKey()
122
+ * @var Array
123
+ * @access private
124
+ */
125
+ var $decryptStream = false;
126
+
127
+ /**
128
+ * The $i and $j indexes for encryption
129
+ *
130
+ * @see Crypt_RC4::_crypt()
131
+ * @var Integer
132
+ * @access private
133
+ */
134
+ var $encryptIndex = 0;
135
+
136
+ /**
137
+ * The $i and $j indexes for decryption
138
+ *
139
+ * @see Crypt_RC4::_crypt()
140
+ * @var Integer
141
+ * @access private
142
+ */
143
+ var $decryptIndex = 0;
144
+
145
+ /**
146
+ * The Encryption Algorithm
147
+ *
148
+ * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
149
+ *
150
+ * @see Crypt_RC4::Crypt_RC4()
151
+ * @var Integer
152
+ * @access private
153
+ */
154
+ var $mode;
155
+
156
+ /**
157
+ * Continuous Buffer status
158
+ *
159
+ * @see Crypt_RC4::enableContinuousBuffer()
160
+ * @var Boolean
161
+ * @access private
162
+ */
163
+ var $continuousBuffer = false;
164
+
165
+ /**
166
+ * Default Constructor.
167
+ *
168
+ * Determines whether or not the mcrypt extension should be used.
169
+ *
170
+ * @param optional Integer $mode
171
+ * @return Crypt_RC4
172
+ * @access public
173
+ */
174
+ function Crypt_RC4()
175
+ {
176
+ if ( !defined('CRYPT_RC4_MODE') ) {
177
+ switch (true) {
178
+ case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
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
+ * Sets the password.
234
+ *
235
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
236
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
237
+ * $hash, $salt, $count, $dkLen
238
+ *
239
+ * @param String $password
240
+ * @param optional String $method
241
+ * @access public
242
+ */
243
+ function setPassword($password, $method = 'pbkdf2')
244
+ {
245
+ $key = '';
246
+
247
+ switch ($method) {
248
+ default: // 'pbkdf2'
249
+ list(, , $hash, $salt, $count) = func_get_args();
250
+ if (!isset($hash)) {
251
+ $hash = 'sha1';
252
+ }
253
+ // WPA and WPA use the SSID as the salt
254
+ if (!isset($salt)) {
255
+ $salt = 'phpseclib/salt';
256
+ }
257
+ // RFC2898#section-4.2 uses 1,000 iterations by default
258
+ // WPA and WPA2 use 4,096.
259
+ if (!isset($count)) {
260
+ $count = 1000;
261
+ }
262
+ if (!isset($dkLen)) {
263
+ $dkLen = 128;
264
+ }
265
+
266
+ if (!class_exists('Crypt_Hash')) {
267
+ require_once('Crypt/Hash.php');
268
+ }
269
+
270
+ $i = 1;
271
+ while (strlen($key) < $dkLen) {
272
+ //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
273
+ $hmac = new Crypt_Hash();
274
+ $hmac->setHash($hash);
275
+ $hmac->setKey($password);
276
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
277
+ for ($j = 2; $j <= $count; $j++) {
278
+ $u = $hmac->hash($u);
279
+ $f^= $u;
280
+ }
281
+ $key.= $f;
282
+ }
283
+ }
284
+
285
+ $this->setKey(substr($key, 0, $dkLen));
286
+ }
287
+
288
+ /**
289
+ * Dummy function.
290
+ *
291
+ * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
292
+ * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
293
+ * calling setKey().
294
+ *
295
+ * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
296
+ * the IV's are relatively easy to predict, an attack described by
297
+ * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
298
+ * can be used to quickly guess at the rest of the key. The following links elaborate:
299
+ *
300
+ * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
301
+ * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
302
+ *
303
+ * @param String $iv
304
+ * @see Crypt_RC4::setKey()
305
+ * @access public
306
+ */
307
+ function setIV($iv)
308
+ {
309
+ }
310
+
311
+ /**
312
+ * Encrypts a message.
313
+ *
314
+ * @see Crypt_RC4::_crypt()
315
+ * @access public
316
+ * @param String $plaintext
317
+ */
318
+ function encrypt($plaintext)
319
+ {
320
+ return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
321
+ }
322
+
323
+ /**
324
+ * Decrypts a message.
325
+ *
326
+ * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
327
+ * Atleast if the continuous buffer is disabled.
328
+ *
329
+ * @see Crypt_RC4::_crypt()
330
+ * @access public
331
+ * @param String $ciphertext
332
+ */
333
+ function decrypt($ciphertext)
334
+ {
335
+ return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
336
+ }
337
+
338
+ /**
339
+ * Encrypts or decrypts a message.
340
+ *
341
+ * @see Crypt_RC4::encrypt()
342
+ * @see Crypt_RC4::decrypt()
343
+ * @access private
344
+ * @param String $text
345
+ * @param Integer $mode
346
+ */
347
+ function _crypt($text, $mode)
348
+ {
349
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
350
+ $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
351
+
352
+ if ($this->$keyStream === false) {
353
+ $this->$keyStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
354
+ mcrypt_generic_init($this->$keyStream, $this->key, '');
355
+ } else if (!$this->continuousBuffer) {
356
+ mcrypt_generic_init($this->$keyStream, $this->key, '');
357
+ }
358
+ $newText = mcrypt_generic($this->$keyStream, $text);
359
+ if (!$this->continuousBuffer) {
360
+ mcrypt_generic_deinit($this->$keyStream);
361
+ }
362
+
363
+ return $newText;
364
+ }
365
+
366
+ if ($this->encryptStream === false) {
367
+ $this->setKey($this->key);
368
+ }
369
+
370
+ switch ($mode) {
371
+ case CRYPT_RC4_ENCRYPT:
372
+ $keyStream = $this->encryptStream;
373
+ list($i, $j) = $this->encryptIndex;
374
+ break;
375
+ case CRYPT_RC4_DECRYPT:
376
+ $keyStream = $this->decryptStream;
377
+ list($i, $j) = $this->decryptIndex;
378
+ }
379
+
380
+ $newText = '';
381
+ for ($k = 0; $k < strlen($text); $k++) {
382
+ $i = ($i + 1) & 255;
383
+ $j = ($j + $keyStream[$i]) & 255;
384
+ $temp = $keyStream[$i];
385
+ $keyStream[$i] = $keyStream[$j];
386
+ $keyStream[$j] = $temp;
387
+ $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
388
+ $newText.= chr(ord($text[$k]) ^ $temp);
389
+ }
390
+
391
+ if ($this->continuousBuffer) {
392
+ switch ($mode) {
393
+ case CRYPT_RC4_ENCRYPT:
394
+ $this->encryptStream = $keyStream;
395
+ $this->encryptIndex = array($i, $j);
396
+ break;
397
+ case CRYPT_RC4_DECRYPT:
398
+ $this->decryptStream = $keyStream;
399
+ $this->decryptIndex = array($i, $j);
400
+ }
401
+ }
402
+
403
+ return $newText;
404
+ }
405
+
406
+ /**
407
+ * Treat consecutive "packets" as if they are a continuous buffer.
408
+ *
409
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
410
+ * will yield different outputs:
411
+ *
412
+ * <code>
413
+ * echo $rc4->encrypt(substr($plaintext, 0, 8));
414
+ * echo $rc4->encrypt(substr($plaintext, 8, 8));
415
+ * </code>
416
+ * <code>
417
+ * echo $rc4->encrypt($plaintext);
418
+ * </code>
419
+ *
420
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
421
+ * another, as demonstrated with the following:
422
+ *
423
+ * <code>
424
+ * $rc4->encrypt(substr($plaintext, 0, 8));
425
+ * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
426
+ * </code>
427
+ * <code>
428
+ * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
429
+ * </code>
430
+ *
431
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
432
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
433
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
434
+ *
435
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
436
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
437
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
438
+ * however, they are also less intuitive and more likely to cause you problems.
439
+ *
440
+ * @see Crypt_RC4::disableContinuousBuffer()
441
+ * @access public
442
+ */
443
+ function enableContinuousBuffer()
444
+ {
445
+ $this->continuousBuffer = true;
446
+ }
447
+
448
+ /**
449
+ * Treat consecutive packets as if they are a discontinuous buffer.
450
+ *
451
+ * The default behavior.
452
+ *
453
+ * @see Crypt_RC4::enableContinuousBuffer()
454
+ * @access public
455
+ */
456
+ function disableContinuousBuffer()
457
+ {
458
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
459
+ $this->encryptIndex = $this->decryptIndex = array(0, 0);
460
+ $this->setKey($this->key);
461
+ }
462
+
463
+ $this->continuousBuffer = false;
464
+ }
465
+
466
+ /**
467
+ * Dummy function.
468
+ *
469
+ * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
470
+ * included is so that you can switch between a block cipher and a stream cipher transparently.
471
+ *
472
+ * @see Crypt_RC4::disablePadding()
473
+ * @access public
474
+ */
475
+ function enablePadding()
476
+ {
477
+ }
478
+
479
+ /**
480
+ * Dummy function.
481
+ *
482
+ * @see Crypt_RC4::enablePadding()
483
+ * @access public
484
+ */
485
+ function disablePadding()
486
+ {
487
+ }
488
+
489
+ /**
490
+ * Class destructor.
491
+ *
492
+ * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
493
+ * needs to be called if mcrypt is being used.
494
+ *
495
+ * @access public
496
+ */
497
+ function __destruct()
498
+ {
499
+ if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
500
+ $this->_closeMCrypt();
501
+ }
502
+ }
503
+
504
+ /**
505
+ * Properly close the MCrypt objects.
506
+ *
507
+ * @access prviate
508
+ */
509
+ function _closeMCrypt()
510
+ {
511
+ if ( $this->encryptStream !== false ) {
512
+ if ( $this->continuousBuffer ) {
513
+ mcrypt_generic_deinit($this->encryptStream);
514
+ }
515
+
516
+ mcrypt_module_close($this->encryptStream);
517
+
518
+ $this->encryptStream = false;
519
+ }
520
+
521
+ if ( $this->decryptStream !== false ) {
522
+ if ( $this->continuousBuffer ) {
523
+ mcrypt_generic_deinit($this->decryptStream);
524
+ }
525
+
526
+ mcrypt_module_close($this->decryptStream);
527
+
528
+ $this->decryptStream = false;
529
+ }
530
+ }
531
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
phpseclib/Crypt/RSA.php CHANGED
@@ -72,17 +72,27 @@
72
  /**
73
  * Include Math_BigInteger
74
  */
75
- require_once('Math/BigInteger.php');
 
 
76
 
77
  /**
78
  * Include Crypt_Random
79
  */
80
- require_once('Crypt/Random.php');
 
 
 
 
 
 
81
 
82
  /**
83
  * Include Crypt_Hash
84
  */
85
- require_once('Crypt/Hash.php');
 
 
86
 
87
  /**#@+
88
  * @access public
@@ -166,6 +176,12 @@ define('CRYPT_RSA_MODE_INTERNAL', 1);
166
  define('CRYPT_RSA_MODE_OPENSSL', 2);
167
  /**#@-*/
168
 
 
 
 
 
 
 
169
  /**#@+
170
  * @access public
171
  * @see Crypt_RSA::createKey()
@@ -207,9 +223,11 @@ define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
207
  */
208
  define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
209
  /**
210
- * PKCS#1 formatted public key
 
 
211
  */
212
- define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
213
  /**
214
  * XML formatted public key
215
  */
@@ -220,6 +238,12 @@ define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
220
  * Place in $HOME/.ssh/authorized_keys
221
  */
222
  define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
 
 
 
 
 
 
223
  /**#@-*/
224
 
225
  /**
@@ -389,7 +413,7 @@ class Crypt_RSA {
389
  * @var String
390
  * @access private
391
  */
392
- var $password = '';
393
 
394
  /**
395
  * Components
@@ -415,6 +439,16 @@ class Crypt_RSA {
415
  */
416
  var $current;
417
 
 
 
 
 
 
 
 
 
 
 
418
  /**
419
  * The constructor
420
  *
@@ -427,11 +461,13 @@ class Crypt_RSA {
427
  */
428
  function Crypt_RSA()
429
  {
 
 
430
  if ( !defined('CRYPT_RSA_MODE') ) {
431
  switch (true) {
432
- //case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
433
- // define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
434
- // break;
435
  default:
436
  define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
437
  }
@@ -467,16 +503,36 @@ class Crypt_RSA {
467
  */
468
  function createKey($bits = 1024, $timeout = false, $partial = array())
469
  {
470
- if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
471
- $rsa = openssl_pkey_new(array('private_key_bits' => $bits));
472
- openssl_pkey_export($rsa, $privatekey);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  $publickey = openssl_pkey_get_details($rsa);
474
  $publickey = $publickey['key'];
475
 
476
- if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) {
477
- $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
478
- $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
479
- }
 
480
 
481
  return array(
482
  'privatekey' => $privatekey,
@@ -487,22 +543,12 @@ class Crypt_RSA {
487
 
488
  static $e;
489
  if (!isset($e)) {
490
- if (!defined('CRYPT_RSA_EXPONENT')) {
491
- // http://en.wikipedia.org/wiki/65537_%28number%29
492
- define('CRYPT_RSA_EXPONENT', '65537');
493
- }
494
- // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
495
- // than 256 bits.
496
- if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
497
- define('CRYPT_RSA_SMALLEST_PRIME', 4096);
498
- }
499
-
500
  $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
501
  }
502
 
503
  extract($this->_generateMinMax($bits));
504
  $absoluteMin = $min;
505
- $temp = $bits >> 1;
506
  if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
507
  $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
508
  $temp = CRYPT_RSA_SMALLEST_PRIME;
@@ -514,7 +560,6 @@ class Crypt_RSA {
514
  extract($this->_generateMinMax($temp));
515
 
516
  $generator = new Math_BigInteger();
517
- $generator->setRandomGenerator('crypt_random');
518
 
519
  $n = $this->one->copy();
520
  if (!empty($partial)) {
@@ -673,7 +718,7 @@ class Crypt_RSA {
673
  return false;
674
  }
675
  $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
676
- $encryption = (!empty($this->password)) ? 'aes256-cbc' : 'none';
677
  $key.= $encryption;
678
  $key.= "\r\nComment: " . CRYPT_RSA_COMMENT . "\r\n";
679
  $public = pack('Na*Na*Na*',
@@ -690,11 +735,11 @@ class Crypt_RSA {
690
  strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
691
  strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
692
  );
693
- if (empty($this->password)) {
694
  $source.= pack('Na*', strlen($private), $private);
695
  $hashkey = 'putty-private-key-file-mac-key';
696
  } else {
697
- $private.= $this->_random(16 - (strlen($private) & 15));
698
  $source.= pack('Na*', strlen($private), $private);
699
  if (!class_exists('Crypt_AES')) {
700
  require_once('Crypt/AES.php');
@@ -753,8 +798,8 @@ class Crypt_RSA {
753
 
754
  $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
755
 
756
- if (!empty($this->password)) {
757
- $iv = $this->_random(8);
758
  $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
759
  $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
760
  if (!class_exists('Crypt_TripleDES')) {
@@ -768,11 +813,11 @@ class Crypt_RSA {
768
  "Proc-Type: 4,ENCRYPTED\r\n" .
769
  "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
770
  "\r\n" .
771
- chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) .
772
  '-----END RSA PRIVATE KEY-----';
773
  } else {
774
  $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
775
- chunk_split(base64_encode($RSAPrivateKey)) .
776
  '-----END RSA PRIVATE KEY-----';
777
  }
778
 
@@ -811,7 +856,7 @@ class Crypt_RSA {
811
  $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
812
 
813
  return $RSAPublicKey;
814
- default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1
815
  // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
816
  // RSAPublicKey ::= SEQUENCE {
817
  // modulus INTEGER, -- n
@@ -827,8 +872,19 @@ class Crypt_RSA {
827
  $components['modulus'], $components['publicExponent']
828
  );
829
 
 
 
 
 
 
 
 
 
 
 
 
830
  $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
831
- chunk_split(base64_encode($RSAPublicKey)) .
832
  '-----END PUBLIC KEY-----';
833
 
834
  return $RSAPublicKey;
@@ -905,7 +961,7 @@ class Crypt_RSA {
905
  $iv = pack('H*', trim($matches[2]));
906
  $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
907
  $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
908
- $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
909
  $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
910
  if ($ciphertext === false) {
911
  $ciphertext = $key;
@@ -943,7 +999,7 @@ class Crypt_RSA {
943
  $crypto->setIV($iv);
944
  $decoded = $crypto->decrypt($ciphertext);
945
  } else {
946
- $decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
947
  $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
948
  }
949
 
@@ -1007,10 +1063,10 @@ class Crypt_RSA {
1007
  $length = $this->_decodeLength($key);
1008
  $temp = $this->_string_shift($key, $length);
1009
  if (strlen($temp) != 1 || ord($temp) > 2) {
1010
- $components['modulus'] = new Math_BigInteger($temp, -256);
1011
  $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1012
  $length = $this->_decodeLength($key);
1013
- $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1014
 
1015
  return $components;
1016
  }
@@ -1018,28 +1074,28 @@ class Crypt_RSA {
1018
  return false;
1019
  }
1020
  $length = $this->_decodeLength($key);
1021
- $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1022
  $this->_string_shift($key);
1023
  $length = $this->_decodeLength($key);
1024
- $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1025
  $this->_string_shift($key);
1026
  $length = $this->_decodeLength($key);
1027
- $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1028
  $this->_string_shift($key);
1029
  $length = $this->_decodeLength($key);
1030
- $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
1031
  $this->_string_shift($key);
1032
  $length = $this->_decodeLength($key);
1033
- $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1034
  $this->_string_shift($key);
1035
  $length = $this->_decodeLength($key);
1036
- $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
1037
  $this->_string_shift($key);
1038
  $length = $this->_decodeLength($key);
1039
- $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1040
  $this->_string_shift($key);
1041
  $length = $this->_decodeLength($key);
1042
- $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
1043
 
1044
  if (!empty($key)) {
1045
  if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
@@ -1053,13 +1109,13 @@ class Crypt_RSA {
1053
  $this->_decodeLength($key);
1054
  $key = substr($key, 1);
1055
  $length = $this->_decodeLength($key);
1056
- $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1057
  $this->_string_shift($key);
1058
  $length = $this->_decodeLength($key);
1059
- $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1060
  $this->_string_shift($key);
1061
  $length = $this->_decodeLength($key);
1062
- $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
1063
  }
1064
  }
1065
 
@@ -1088,8 +1144,9 @@ class Crypt_RSA {
1088
  return false;
1089
  }
1090
  extract(unpack('Nlength', $this->_string_shift($key, 4)));
 
1091
  return strlen($key) ? false : array(
1092
- 'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
1093
  'publicExponent' => $modulus
1094
  );
1095
  } else {
@@ -1108,7 +1165,8 @@ class Crypt_RSA {
1108
  xml_set_object($xml, $this);
1109
  xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1110
  xml_set_character_data_handler($xml, '_data_handler');
1111
- if (!xml_parse($xml, $key)) {
 
1112
  return false;
1113
  }
1114
 
@@ -1189,6 +1247,19 @@ class Crypt_RSA {
1189
  }
1190
  }
1191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1192
  /**
1193
  * Start Element Handler
1194
  *
@@ -1324,14 +1395,14 @@ class Crypt_RSA {
1324
  * Sets the password
1325
  *
1326
  * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1327
- * Or rather, pass in $password such that empty($password) is true.
1328
  *
1329
  * @see createKey()
1330
  * @see loadKey()
1331
  * @access public
1332
  * @param String $password
1333
  */
1334
- function setPassword($password)
1335
  {
1336
  $this->password = $password;
1337
  }
@@ -1442,6 +1513,45 @@ class Crypt_RSA {
1442
  return $temp;
1443
  }
1444
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1445
  /**
1446
  * Generates the smallest and largest numbers requiring $bits bits
1447
  *
@@ -1622,23 +1732,6 @@ class Crypt_RSA {
1622
  $this->sLen = $sLen;
1623
  }
1624
 
1625
- /**
1626
- * Generates a random string x bytes long
1627
- *
1628
- * @access public
1629
- * @param Integer $bytes
1630
- * @param optional Integer $nonzero
1631
- * @return String
1632
- */
1633
- function _random($bytes, $nonzero = false)
1634
- {
1635
- $temp = '';
1636
- for ($i = 0; $i < $bytes; $i++) {
1637
- $temp.= chr(crypt_random($nonzero, 255));
1638
- }
1639
- return $temp;
1640
- }
1641
-
1642
  /**
1643
  * Integer-to-Octet-String primitive
1644
  *
@@ -1653,7 +1746,7 @@ class Crypt_RSA {
1653
  {
1654
  $x = $x->toBytes();
1655
  if (strlen($x) > $xLen) {
1656
- user_error('Integer too large', E_USER_NOTICE);
1657
  return false;
1658
  }
1659
  return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
@@ -1721,7 +1814,6 @@ class Crypt_RSA {
1721
  }
1722
 
1723
  $one = new Math_BigInteger(1);
1724
- $one->setRandomGenerator('crypt_random');
1725
 
1726
  $r = $one->random($one, $smallest->subtract($one));
1727
 
@@ -1775,6 +1867,34 @@ class Crypt_RSA {
1775
  return $x;
1776
  }
1777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1778
  /**
1779
  * RSAEP
1780
  *
@@ -1787,7 +1907,7 @@ class Crypt_RSA {
1787
  function _rsaep($m)
1788
  {
1789
  if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1790
- user_error('Message representative out of range', E_USER_NOTICE);
1791
  return false;
1792
  }
1793
  return $this->_exponentiate($m);
@@ -1805,7 +1925,7 @@ class Crypt_RSA {
1805
  function _rsadp($c)
1806
  {
1807
  if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1808
- user_error('Ciphertext representative out of range', E_USER_NOTICE);
1809
  return false;
1810
  }
1811
  return $this->_exponentiate($c);
@@ -1823,7 +1943,7 @@ class Crypt_RSA {
1823
  function _rsasp1($m)
1824
  {
1825
  if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1826
- user_error('Message representative out of range', E_USER_NOTICE);
1827
  return false;
1828
  }
1829
  return $this->_exponentiate($m);
@@ -1841,7 +1961,7 @@ class Crypt_RSA {
1841
  function _rsavp1($s)
1842
  {
1843
  if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1844
- user_error('Signature representative out of range', E_USER_NOTICE);
1845
  return false;
1846
  }
1847
  return $this->_exponentiate($s);
@@ -1892,7 +2012,7 @@ class Crypt_RSA {
1892
  // be output.
1893
 
1894
  if ($mLen > $this->k - 2 * $this->hLen - 2) {
1895
- user_error('Message too long', E_USER_NOTICE);
1896
  return false;
1897
  }
1898
 
@@ -1901,7 +2021,7 @@ class Crypt_RSA {
1901
  $lHash = $this->hash->hash($l);
1902
  $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
1903
  $db = $lHash . $ps . chr(1) . $m;
1904
- $seed = $this->_random($this->hLen);
1905
  $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
1906
  $maskedDB = $db ^ $dbMask;
1907
  $seedMask = $this->_mgf1($maskedDB, $this->hLen);
@@ -1953,7 +2073,7 @@ class Crypt_RSA {
1953
  // be output.
1954
 
1955
  if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
1956
- user_error('Decryption error', E_USER_NOTICE);
1957
  return false;
1958
  }
1959
 
@@ -1962,7 +2082,7 @@ class Crypt_RSA {
1962
  $c = $this->_os2ip($c);
1963
  $m = $this->_rsadp($c);
1964
  if ($m === false) {
1965
- user_error('Decryption error', E_USER_NOTICE);
1966
  return false;
1967
  }
1968
  $em = $this->_i2osp($m, $this->k);
@@ -1980,12 +2100,12 @@ class Crypt_RSA {
1980
  $lHash2 = substr($db, 0, $this->hLen);
1981
  $m = substr($db, $this->hLen);
1982
  if ($lHash != $lHash2) {
1983
- user_error('Decryption error', E_USER_NOTICE);
1984
  return false;
1985
  }
1986
  $m = ltrim($m, chr(0));
1987
  if (ord($m[0]) != 1) {
1988
- user_error('Decryption error', E_USER_NOTICE);
1989
  return false;
1990
  }
1991
 
@@ -2010,13 +2130,18 @@ class Crypt_RSA {
2010
  // Length checking
2011
 
2012
  if ($mLen > $this->k - 11) {
2013
- user_error('Message too long', E_USER_NOTICE);
2014
  return false;
2015
  }
2016
 
2017
  // EME-PKCS1-v1_5 encoding
2018
-
2019
- $ps = $this->_random($this->k - $mLen - 3, true);
 
 
 
 
 
2020
  $em = chr(0) . chr(2) . $ps . chr(0) . $m;
2021
 
2022
  // RSA encryption
@@ -2038,7 +2163,7 @@ class Crypt_RSA {
2038
  * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2039
  * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2040
  * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2041
- * to be 2 regardless of which key is used. for compatability purposes, we'll just check to make sure the
2042
  * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2043
  *
2044
  * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
@@ -2054,7 +2179,7 @@ class Crypt_RSA {
2054
  // Length checking
2055
 
2056
  if (strlen($c) != $this->k) { // or if k < 11
2057
- user_error('Decryption error', E_USER_NOTICE);
2058
  return false;
2059
  }
2060
 
@@ -2064,7 +2189,7 @@ class Crypt_RSA {
2064
  $m = $this->_rsadp($c);
2065
 
2066
  if ($m === false) {
2067
- user_error('Decryption error', E_USER_NOTICE);
2068
  return false;
2069
  }
2070
  $em = $this->_i2osp($m, $this->k);
@@ -2072,7 +2197,7 @@ class Crypt_RSA {
2072
  // EME-PKCS1-v1_5 decoding
2073
 
2074
  if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2075
- user_error('Decryption error', E_USER_NOTICE);
2076
  return false;
2077
  }
2078
 
@@ -2080,7 +2205,7 @@ class Crypt_RSA {
2080
  $m = substr($em, strlen($ps) + 3);
2081
 
2082
  if (strlen($ps) < 8) {
2083
- user_error('Decryption error', E_USER_NOTICE);
2084
  return false;
2085
  }
2086
 
@@ -2108,11 +2233,11 @@ class Crypt_RSA {
2108
 
2109
  $mHash = $this->hash->hash($m);
2110
  if ($emLen < $this->hLen + $sLen + 2) {
2111
- user_error('Encoding error', E_USER_NOTICE);
2112
  return false;
2113
  }
2114
 
2115
- $salt = $this->_random($sLen);
2116
  $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2117
  $h = $this->hash->hash($m2);
2118
  $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
@@ -2169,7 +2294,7 @@ class Crypt_RSA {
2169
  $salt = substr($db, $temp + 1); // should be $sLen long
2170
  $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2171
  $h2 = $this->hash->hash($m2);
2172
- return $h == $h2;
2173
  }
2174
 
2175
  /**
@@ -2213,7 +2338,7 @@ class Crypt_RSA {
2213
  // Length checking
2214
 
2215
  if (strlen($s) != $this->k) {
2216
- user_error('Invalid signature', E_USER_NOTICE);
2217
  return false;
2218
  }
2219
 
@@ -2224,12 +2349,12 @@ class Crypt_RSA {
2224
  $s2 = $this->_os2ip($s);
2225
  $m2 = $this->_rsavp1($s2);
2226
  if ($m2 === false) {
2227
- user_error('Invalid signature', E_USER_NOTICE);
2228
  return false;
2229
  }
2230
  $em = $this->_i2osp($m2, $modBits >> 3);
2231
  if ($em === false) {
2232
- user_error('Invalid signature', E_USER_NOTICE);
2233
  return false;
2234
  }
2235
 
@@ -2279,7 +2404,7 @@ class Crypt_RSA {
2279
  $tLen = strlen($t);
2280
 
2281
  if ($emLen < $tLen + 11) {
2282
- user_error('Intended encoded message length too short', E_USER_NOTICE);
2283
  return false;
2284
  }
2285
 
@@ -2305,7 +2430,7 @@ class Crypt_RSA {
2305
 
2306
  $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2307
  if ($em === false) {
2308
- user_error('RSA modulus too short', E_USER_NOTICE);
2309
  return false;
2310
  }
2311
 
@@ -2334,7 +2459,7 @@ class Crypt_RSA {
2334
  // Length checking
2335
 
2336
  if (strlen($s) != $this->k) {
2337
- user_error('Invalid signature', E_USER_NOTICE);
2338
  return false;
2339
  }
2340
 
@@ -2343,12 +2468,12 @@ class Crypt_RSA {
2343
  $s = $this->_os2ip($s);
2344
  $m2 = $this->_rsavp1($s);
2345
  if ($m2 === false) {
2346
- user_error('Invalid signature', E_USER_NOTICE);
2347
  return false;
2348
  }
2349
  $em = $this->_i2osp($m2, $this->k);
2350
  if ($em === false) {
2351
- user_error('Invalid signature', E_USER_NOTICE);
2352
  return false;
2353
  }
2354
 
@@ -2356,13 +2481,12 @@ class Crypt_RSA {
2356
 
2357
  $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2358
  if ($em2 === false) {
2359
- user_error('RSA modulus too short', E_USER_NOTICE);
2360
  return false;
2361
  }
2362
 
2363
  // Compare
2364
-
2365
- return $em === $em2;
2366
  }
2367
 
2368
  /**
@@ -2449,6 +2573,8 @@ class Crypt_RSA {
2449
  }
2450
 
2451
  $ciphertext = str_split($ciphertext, $this->k);
 
 
2452
  $plaintext = '';
2453
 
2454
  switch ($this->encryptionMode) {
@@ -2517,4 +2643,4 @@ class Crypt_RSA {
2517
  return $this->_rsassa_pss_verify($message, $signature);
2518
  }
2519
  }
2520
- }
72
  /**
73
  * Include Math_BigInteger
74
  */
75
+ if (!class_exists('Math_BigInteger')) {
76
+ require_once('Math/BigInteger.php');
77
+ }
78
 
79
  /**
80
  * Include Crypt_Random
81
  */
82
+ // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
83
+ // will trigger a call to __autoload() if you're wanting to auto-load classes
84
+ // call function_exists() a second time to stop the require_once from being called outside
85
+ // of the auto loader
86
+ if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
87
+ require_once('Crypt/Random.php');
88
+ }
89
 
90
  /**
91
  * Include Crypt_Hash
92
  */
93
+ if (!class_exists('Crypt_Hash')) {
94
+ require_once('Crypt/Hash.php');
95
+ }
96
 
97
  /**#@+
98
  * @access public
176
  define('CRYPT_RSA_MODE_OPENSSL', 2);
177
  /**#@-*/
178
 
179
+ /**
180
+ * Default openSSL configuration file.
181
+ */
182
+ define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
183
+
184
+
185
  /**#@+
186
  * @access public
187
  * @see Crypt_RSA::createKey()
223
  */
224
  define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
225
  /**
226
+ * PKCS#1 formatted public key (raw)
227
+ *
228
+ * Used by File/X509.php
229
  */
230
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
231
  /**
232
  * XML formatted public key
233
  */
238
  * Place in $HOME/.ssh/authorized_keys
239
  */
240
  define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
241
+ /**
242
+ * PKCS#1 formatted public key (encapsulated)
243
+ *
244
+ * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
245
+ */
246
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
247
  /**#@-*/
248
 
249
  /**
413
  * @var String
414
  * @access private
415
  */
416
+ var $password = false;
417
 
418
  /**
419
  * Components
439
  */
440
  var $current;
441
 
442
+ /**
443
+ * OpenSSL configuration file name.
444
+ *
445
+ * Set to NULL to use system configuration file.
446
+ * @see Crypt_RSA::createKey()
447
+ * @var Mixed
448
+ * @Access public
449
+ */
450
+ var $configFile;
451
+
452
  /**
453
  * The constructor
454
  *
461
  */
462
  function Crypt_RSA()
463
  {
464
+ $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
465
+
466
  if ( !defined('CRYPT_RSA_MODE') ) {
467
  switch (true) {
468
+ case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
469
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
470
+ break;
471
  default:
472
  define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
473
  }
503
  */
504
  function createKey($bits = 1024, $timeout = false, $partial = array())
505
  {
506
+ if (!defined('CRYPT_RSA_EXPONENT')) {
507
+ // http://en.wikipedia.org/wiki/65537_%28number%29
508
+ define('CRYPT_RSA_EXPONENT', '65537');
509
+ }
510
+ // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
511
+ // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
512
+ // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
513
+ // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
514
+ // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
515
+ // generation when there's a chance neither gmp nor OpenSSL are installed)
516
+ if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
517
+ define('CRYPT_RSA_SMALLEST_PRIME', 4096);
518
+ }
519
+
520
+ // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
521
+ if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
522
+ $config = array();
523
+ if (isset($this->configFile)) {
524
+ $config['config'] = $this->configFile;
525
+ }
526
+ $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
527
+ openssl_pkey_export($rsa, $privatekey, NULL, $config);
528
  $publickey = openssl_pkey_get_details($rsa);
529
  $publickey = $publickey['key'];
530
 
531
+ $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
532
+ $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
533
+
534
+ // clear the buffer of error strings stemming from a minimalistic openssl.cnf
535
+ while (openssl_error_string() !== false);
536
 
537
  return array(
538
  'privatekey' => $privatekey,
543
 
544
  static $e;
545
  if (!isset($e)) {
 
 
 
 
 
 
 
 
 
 
546
  $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
547
  }
548
 
549
  extract($this->_generateMinMax($bits));
550
  $absoluteMin = $min;
551
+ $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
552
  if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
553
  $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
554
  $temp = CRYPT_RSA_SMALLEST_PRIME;
560
  extract($this->_generateMinMax($temp));
561
 
562
  $generator = new Math_BigInteger();
 
563
 
564
  $n = $this->one->copy();
565
  if (!empty($partial)) {
718
  return false;
719
  }
720
  $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
721
+ $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
722
  $key.= $encryption;
723
  $key.= "\r\nComment: " . CRYPT_RSA_COMMENT . "\r\n";
724
  $public = pack('Na*Na*Na*',
735
  strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
736
  strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
737
  );
738
+ if (empty($this->password) && !is_string($this->password)) {
739
  $source.= pack('Na*', strlen($private), $private);
740
  $hashkey = 'putty-private-key-file-mac-key';
741
  } else {
742
+ $private.= crypt_random_string(16 - (strlen($private) & 15));
743
  $source.= pack('Na*', strlen($private), $private);
744
  if (!class_exists('Crypt_AES')) {
745
  require_once('Crypt/AES.php');
798
 
799
  $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
800
 
801
+ if (!empty($this->password) || is_string($this->password)) {
802
+ $iv = crypt_random_string(8);
803
  $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
804
  $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
805
  if (!class_exists('Crypt_TripleDES')) {
813
  "Proc-Type: 4,ENCRYPTED\r\n" .
814
  "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
815
  "\r\n" .
816
+ chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
817
  '-----END RSA PRIVATE KEY-----';
818
  } else {
819
  $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
820
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
821
  '-----END RSA PRIVATE KEY-----';
822
  }
823
 
856
  $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
857
 
858
  return $RSAPublicKey;
859
+ default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
860
  // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
861
  // RSAPublicKey ::= SEQUENCE {
862
  // modulus INTEGER, -- n
872
  $components['modulus'], $components['publicExponent']
873
  );
874
 
875
+ if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) {
876
+ // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
877
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
878
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
879
+ $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
880
+
881
+ $RSAPublicKey = pack('Ca*a*',
882
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
883
+ );
884
+ }
885
+
886
  $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
887
+ chunk_split(base64_encode($RSAPublicKey), 64) .
888
  '-----END PUBLIC KEY-----';
889
 
890
  return $RSAPublicKey;
961
  $iv = pack('H*', trim($matches[2]));
962
  $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
963
  $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
964
+ $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
965
  $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
966
  if ($ciphertext === false) {
967
  $ciphertext = $key;
999
  $crypto->setIV($iv);
1000
  $decoded = $crypto->decrypt($ciphertext);
1001
  } else {
1002
+ $decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
1003
  $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
1004
  }
1005
 
1063
  $length = $this->_decodeLength($key);
1064
  $temp = $this->_string_shift($key, $length);
1065
  if (strlen($temp) != 1 || ord($temp) > 2) {
1066
+ $components['modulus'] = new Math_BigInteger($temp, 256);
1067
  $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1068
  $length = $this->_decodeLength($key);
1069
+ $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1070
 
1071
  return $components;
1072
  }
1074
  return false;
1075
  }
1076
  $length = $this->_decodeLength($key);
1077
+ $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1078
  $this->_string_shift($key);
1079
  $length = $this->_decodeLength($key);
1080
+ $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1081
  $this->_string_shift($key);
1082
  $length = $this->_decodeLength($key);
1083
+ $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1084
  $this->_string_shift($key);
1085
  $length = $this->_decodeLength($key);
1086
+ $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1087
  $this->_string_shift($key);
1088
  $length = $this->_decodeLength($key);
1089
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1090
  $this->_string_shift($key);
1091
  $length = $this->_decodeLength($key);
1092
+ $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1093
  $this->_string_shift($key);
1094
  $length = $this->_decodeLength($key);
1095
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1096
  $this->_string_shift($key);
1097
  $length = $this->_decodeLength($key);
1098
+ $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1099
 
1100
  if (!empty($key)) {
1101
  if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1109
  $this->_decodeLength($key);
1110
  $key = substr($key, 1);
1111
  $length = $this->_decodeLength($key);
1112
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1113
  $this->_string_shift($key);
1114
  $length = $this->_decodeLength($key);
1115
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1116
  $this->_string_shift($key);
1117
  $length = $this->_decodeLength($key);
1118
+ $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1119
  }
1120
  }
1121
 
1144
  return false;
1145
  }
1146
  extract(unpack('Nlength', $this->_string_shift($key, 4)));
1147
+ $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1148
  return strlen($key) ? false : array(
1149
+ 'modulus' => $realModulus,
1150
  'publicExponent' => $modulus
1151
  );
1152
  } else {
1165
  xml_set_object($xml, $this);
1166
  xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1167
  xml_set_character_data_handler($xml, '_data_handler');
1168
+ // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1169
+ if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1170
  return false;
1171
  }
1172
 
1247
  }
1248
  }
1249
 
1250
+ /**
1251
+ * Returns the key size
1252
+ *
1253
+ * More specifically, this returns the size of the modulo in bits.
1254
+ *
1255
+ * @access public
1256
+ * @return Integer
1257
+ */
1258
+ function getSize()
1259
+ {
1260
+ return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1261
+ }
1262
+
1263
  /**
1264
  * Start Element Handler
1265
  *
1395
  * Sets the password
1396
  *
1397
  * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1398
+ * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1399
  *
1400
  * @see createKey()
1401
  * @see loadKey()
1402
  * @access public
1403
  * @param String $password
1404
  */
1405
+ function setPassword($password = false)
1406
  {
1407
  $this->password = $password;
1408
  }
1513
  return $temp;
1514
  }
1515
 
1516
+ /**
1517
+ * Returns a minimalistic private key
1518
+ *
1519
+ * Returns the private key without the prime number constituants. Structurally identical to a public key that
1520
+ * hasn't been set as the public key
1521
+ *
1522
+ * @see getPrivateKey()
1523
+ * @access private
1524
+ * @param String $key
1525
+ * @param Integer $type optional
1526
+ */
1527
+ function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1528
+ {
1529
+ if (empty($this->modulus) || empty($this->exponent)) {
1530
+ return false;
1531
+ }
1532
+
1533
+ $oldFormat = $this->publicKeyFormat;
1534
+ $this->publicKeyFormat = $mode;
1535
+ $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1536
+ $this->publicKeyFormat = $oldFormat;
1537
+ return $temp;
1538
+ }
1539
+
1540
+ /**
1541
+ * __toString() magic method
1542
+ *
1543
+ * @access public
1544
+ */
1545
+ function __toString()
1546
+ {
1547
+ $key = $this->getPrivateKey($this->privateKeyFormat);
1548
+ if ($key !== false) {
1549
+ return $key;
1550
+ }
1551
+ $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1552
+ return $key !== false ? $key : '';
1553
+ }
1554
+
1555
  /**
1556
  * Generates the smallest and largest numbers requiring $bits bits
1557
  *
1732
  $this->sLen = $sLen;
1733
  }
1734
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1735
  /**
1736
  * Integer-to-Octet-String primitive
1737
  *
1746
  {
1747
  $x = $x->toBytes();
1748
  if (strlen($x) > $xLen) {
1749
+ user_error('Integer too large');
1750
  return false;
1751
  }
1752
  return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1814
  }
1815
 
1816
  $one = new Math_BigInteger(1);
 
1817
 
1818
  $r = $one->random($one, $smallest->subtract($one));
1819
 
1867
  return $x;
1868
  }
1869
 
1870
+ /**
1871
+ * Performs blinded RSA equality testing
1872
+ *
1873
+ * Protects against a particular type of timing attack described.
1874
+ *
1875
+ * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don�t use MessageDigest.isEquals)}
1876
+ *
1877
+ * Thanks for the heads up singpolyma!
1878
+ *
1879
+ * @access private
1880
+ * @param String $x
1881
+ * @param String $y
1882
+ * @return Boolean
1883
+ */
1884
+ function _equals($x, $y)
1885
+ {
1886
+ if (strlen($x) != strlen($y)) {
1887
+ return false;
1888
+ }
1889
+
1890
+ $result = 0;
1891
+ for ($i = 0; $i < strlen($x); $i++) {
1892
+ $result |= ord($x[$i]) ^ ord($y[$i]);
1893
+ }
1894
+
1895
+ return $result == 0;
1896
+ }
1897
+
1898
  /**
1899
  * RSAEP
1900
  *
1907
  function _rsaep($m)
1908
  {
1909
  if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1910
+ user_error('Message representative out of range');
1911
  return false;
1912
  }
1913
  return $this->_exponentiate($m);
1925
  function _rsadp($c)
1926
  {
1927
  if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1928
+ user_error('Ciphertext representative out of range');
1929
  return false;
1930
  }
1931
  return $this->_exponentiate($c);
1943
  function _rsasp1($m)
1944
  {
1945
  if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1946
+ user_error('Message representative out of range');
1947
  return false;
1948
  }
1949
  return $this->_exponentiate($m);
1961
  function _rsavp1($s)
1962
  {
1963
  if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1964
+ user_error('Signature representative out of range');
1965
  return false;
1966
  }
1967
  return $this->_exponentiate($s);
2012
  // be output.
2013
 
2014
  if ($mLen > $this->k - 2 * $this->hLen - 2) {
2015
+ user_error('Message too long');
2016
  return false;
2017
  }
2018
 
2021
  $lHash = $this->hash->hash($l);
2022
  $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2023
  $db = $lHash . $ps . chr(1) . $m;
2024
+ $seed = crypt_random_string($this->hLen);
2025
  $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2026
  $maskedDB = $db ^ $dbMask;
2027
  $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2073
  // be output.
2074
 
2075
  if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2076
+ user_error('Decryption error');
2077
  return false;
2078
  }
2079
 
2082
  $c = $this->_os2ip($c);
2083
  $m = $this->_rsadp($c);
2084
  if ($m === false) {
2085
+ user_error('Decryption error');
2086
  return false;
2087
  }
2088
  $em = $this->_i2osp($m, $this->k);
2100
  $lHash2 = substr($db, 0, $this->hLen);
2101
  $m = substr($db, $this->hLen);
2102
  if ($lHash != $lHash2) {
2103
+ user_error('Decryption error');
2104
  return false;
2105
  }
2106
  $m = ltrim($m, chr(0));
2107
  if (ord($m[0]) != 1) {
2108
+ user_error('Decryption error');
2109
  return false;
2110
  }
2111
 
2130
  // Length checking
2131
 
2132
  if ($mLen > $this->k - 11) {
2133
+ user_error('Message too long');
2134
  return false;
2135
  }
2136
 
2137
  // EME-PKCS1-v1_5 encoding
2138
+ $psLen = $this->k - $mLen - 3;
2139
+ $ps = '';
2140
+ while (strlen($ps) != $psLen) {
2141
+ $temp = crypt_random_string($psLen - strlen($ps));
2142
+ $temp = str_replace("\x00", '', $temp);
2143
+ $ps.= $temp;
2144
+ }
2145
  $em = chr(0) . chr(2) . $ps . chr(0) . $m;
2146
 
2147
  // RSA encryption
2163
  * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2164
  * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2165
  * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2166
+ * to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the
2167
  * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2168
  *
2169
  * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
2179
  // Length checking
2180
 
2181
  if (strlen($c) != $this->k) { // or if k < 11
2182
+ user_error('Decryption error');
2183
  return false;
2184
  }
2185
 
2189
  $m = $this->_rsadp($c);
2190
 
2191
  if ($m === false) {
2192
+ user_error('Decryption error');
2193
  return false;
2194
  }
2195
  $em = $this->_i2osp($m, $this->k);
2197
  // EME-PKCS1-v1_5 decoding
2198
 
2199
  if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2200
+ user_error('Decryption error');
2201
  return false;
2202
  }
2203
 
2205
  $m = substr($em, strlen($ps) + 3);
2206
 
2207
  if (strlen($ps) < 8) {
2208
+ user_error('Decryption error');
2209
  return false;
2210
  }
2211
 
2233
 
2234
  $mHash = $this->hash->hash($m);
2235
  if ($emLen < $this->hLen + $sLen + 2) {
2236
+ user_error('Encoding error');
2237
  return false;
2238
  }
2239
 
2240
+ $salt = crypt_random_string($sLen);
2241
  $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2242
  $h = $this->hash->hash($m2);
2243
  $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2294
  $salt = substr($db, $temp + 1); // should be $sLen long
2295
  $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2296
  $h2 = $this->hash->hash($m2);
2297
+ return $this->_equals($h, $h2);
2298
  }
2299
 
2300
  /**
2338
  // Length checking
2339
 
2340
  if (strlen($s) != $this->k) {
2341
+ user_error('Invalid signature');
2342
  return false;
2343
  }
2344
 
2349
  $s2 = $this->_os2ip($s);
2350
  $m2 = $this->_rsavp1($s2);
2351
  if ($m2 === false) {
2352
+ user_error('Invalid signature');
2353
  return false;
2354
  }
2355
  $em = $this->_i2osp($m2, $modBits >> 3);
2356
  if ($em === false) {
2357
+ user_error('Invalid signature');
2358
  return false;
2359
  }
2360
 
2404
  $tLen = strlen($t);
2405
 
2406
  if ($emLen < $tLen + 11) {
2407
+ user_error('Intended encoded message length too short');
2408
  return false;
2409
  }
2410
 
2430
 
2431
  $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2432
  if ($em === false) {
2433
+ user_error('RSA modulus too short');
2434
  return false;
2435
  }
2436
 
2459
  // Length checking
2460
 
2461
  if (strlen($s) != $this->k) {
2462
+ user_error('Invalid signature');
2463
  return false;
2464
  }
2465
 
2468
  $s = $this->_os2ip($s);
2469
  $m2 = $this->_rsavp1($s);
2470
  if ($m2 === false) {
2471
+ user_error('Invalid signature');
2472
  return false;
2473
  }
2474
  $em = $this->_i2osp($m2, $this->k);
2475
  if ($em === false) {
2476
+ user_error('Invalid signature');
2477
  return false;
2478
  }
2479
 
2481
 
2482
  $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2483
  if ($em2 === false) {
2484
+ user_error('RSA modulus too short');
2485
  return false;
2486
  }
2487
 
2488
  // Compare
2489
+ return $this->_equals($em, $em2);
 
2490
  }
2491
 
2492
  /**
2573
  }
2574
 
2575
  $ciphertext = str_split($ciphertext, $this->k);
2576
+ $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2577
+
2578
  $plaintext = '';
2579
 
2580
  switch ($this->encryptionMode) {
2643
  return $this->_rsassa_pss_verify($message, $signature);
2644
  }
2645
  }
2646
+ }
phpseclib/Crypt/Random.php CHANGED
@@ -11,7 +11,7 @@
11
  * <?php
12
  * include('Crypt/Random.php');
13
  *
14
- * echo crypt_random();
15
  * ?>
16
  * </code>
17
  *
@@ -43,78 +43,146 @@
43
  */
44
 
45
  /**
46
- * Generate a random value.
47
  *
48
- * On 32-bit machines, the largest distance that can exist between $min and $max is 2**31.
49
- * If $min and $max are farther apart than that then the last ($max - range) numbers.
 
50
  *
51
- * Depending on how this is being used, it may be worth while to write a replacement. For example,
52
- * a PHP-based web app that stores its data in an SQL database can collect more entropy than this function
53
- * can.
54
- *
55
- * @param optional Integer $min
56
- * @param optional Integer $max
57
- * @return Integer
58
  * @access public
59
  */
60
- function crypt_random($min = 0, $max = 0x7FFFFFFF)
61
- {
62
- if ($min == $max) {
63
- return $min;
64
- }
65
-
66
- if (function_exists('openssl_random_pseudo_bytes')) {
67
- // openssl_random_pseudo_bytes() is slow on windows per the following:
68
- // http://stackoverflow.com/questions/1940168/openssl-random-pseudo-bytes-is-slow-php
69
- if ((PHP_OS & "\xDF\xDF\xDF") !== 'WIN') { // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
70
- extract(unpack('Nrandom', openssl_random_pseudo_bytes(4)));
71
-
72
- return abs($random) % ($max - $min) + $min;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
  }
 
75
 
76
- // see http://en.wikipedia.org/wiki//dev/random
77
- static $urandom = true;
78
- if ($urandom === true) {
79
- // Warning's will be output unles the error suppression operator is used. Errors such as
80
- // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
81
- $urandom = @fopen('/dev/urandom', 'rb');
82
- }
83
- if (!is_bool($urandom)) {
84
- extract(unpack('Nrandom', fread($urandom, 4)));
85
-
86
- // say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this:
87
- // -4 % 3 + 0 = -1, even though -1 < $min
88
- return abs($random) % ($max - $min) + $min;
89
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
- /* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
92
- Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:
 
 
93
 
94
- http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:
97
 
98
- http://svn.php.net/viewvc/php/php-src/tags/php_5_3_2/ext/standard/php_rand.h?view=markup */
99
- if (version_compare(PHP_VERSION, '5.2.5', '<=')) {
100
- static $seeded;
101
- if (!isset($seeded)) {
102
- $seeded = true;
103
- mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
 
 
 
 
 
 
 
104
  }
105
- }
106
-
107
- static $crypto;
108
 
109
- // The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5
110
- // in the browser and reloading the page.
 
 
 
 
 
 
 
 
111
 
112
- if (!isset($crypto)) {
113
- $key = $iv = '';
114
- for ($i = 0; $i < 8; $i++) {
115
- $key.= pack('n', mt_rand(0, 0xFFFF));
116
- $iv .= pack('n', mt_rand(0, 0xFFFF));
117
- }
118
  switch (true) {
119
  case class_exists('Crypt_AES'):
120
  $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
@@ -129,15 +197,47 @@ function crypt_random($min = 0, $max = 0x7FFFFFFF)
129
  $crypto = new Crypt_RC4();
130
  break;
131
  default:
132
- extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF)))));
133
- return abs($random) % ($max - $min) + $min;
134
  }
 
135
  $crypto->setKey($key);
136
  $crypto->setIV($iv);
137
  $crypto->enableContinuousBuffer();
138
  }
139
 
140
- extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0")));
141
- return abs($random) % ($max - $min) + $min;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  }
143
- ?>
11
  * <?php
12
  * include('Crypt/Random.php');
13
  *
14
+ * echo bin2hex(crypt_random_string(8));
15
  * ?>
16
  * </code>
17
  *
43
  */
44
 
45
  /**
46
+ * Generate a random string.
47
  *
48
+ * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
49
+ * microoptimizations because this function has the potential of being called a huge number of times.
50
+ * eg. for RSA key generation.
51
  *
52
+ * @param Integer $length
53
+ * @return String
 
 
 
 
 
54
  * @access public
55
  */
56
+ function crypt_random_string($length) {
57
+ // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
58
+ if ((PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
59
+ // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
60
+ // ie. class_alias is a function that was introduced in PHP 5.3
61
+ if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
62
+ return mcrypt_create_iv($length);
63
+ }
64
+ // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
65
+ // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
66
+ // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
67
+ // call php_win32_get_random_bytes():
68
+ //
69
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
70
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
71
+ //
72
+ // php_win32_get_random_bytes() is defined thusly:
73
+ //
74
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
75
+ //
76
+ // we're calling it, all the same, in the off chance that the mcrypt extension is not available
77
+ if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
78
+ return openssl_random_pseudo_bytes($length);
79
+ }
80
+ } else {
81
+ // method 1. the fastest
82
+ if (function_exists('openssl_random_pseudo_bytes')) {
83
+ return openssl_random_pseudo_bytes($length);
84
+ }
85
+ // method 2
86
+ static $fp = true;
87
+ if ($fp === true) {
88
+ // warning's will be output unles the error suppression operator is used. errors such as
89
+ // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
90
+ $fp = @fopen('/dev/urandom', 'rb');
91
+ }
92
+ if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
93
+ return fread($fp, $length);
94
+ }
95
+ // method 3. pretty much does the same thing as method 2 per the following url:
96
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
97
+ // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
98
+ // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
99
+ // restrictions or some such
100
+ if (function_exists('mcrypt_create_iv')) {
101
+ return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
102
  }
103
  }
104
+ // at this point we have no choice but to use a pure-PHP CSPRNG
105
 
106
+ // cascade entropy across multiple PHP instances by fixing the session and collecting all
107
+ // environmental variables, including the previous session data and the current session
108
+ // data.
109
+ //
110
+ // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
111
+ // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
112
+ // PHP isn't low level to be able to use those as sources and on a web server there's not likely
113
+ // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
114
+ // however. a ton of people visiting the website. obviously you don't want to base your seeding
115
+ // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
116
+ // by the user and (2) this isn't just looking at the data sent by the current user - it's based
117
+ // on the data sent by all users. one user requests the page and a hash of their info is saved.
118
+ // another user visits the page and the serialization of their data is utilized along with the
119
+ // server envirnment stuff and a hash of the previous http request data (which itself utilizes
120
+ // a hash of the session data before that). certainly an attacker should be assumed to have
121
+ // full control over his own http requests. he, however, is not going to have control over
122
+ // everyone's http requests.
123
+ static $crypto = false, $v;
124
+ if ($crypto === false) {
125
+ // save old session data
126
+ $old_session_id = session_id();
127
+ $old_use_cookies = ini_get('session.use_cookies');
128
+ $old_session_cache_limiter = session_cache_limiter();
129
+ if (isset($_SESSION)) {
130
+ $_OLD_SESSION = $_SESSION;
131
+ }
132
+ if ($old_session_id != '') {
133
+ session_write_close();
134
+ }
135
 
136
+ session_id(1);
137
+ ini_set('session.use_cookies', 0);
138
+ session_cache_limiter('');
139
+ session_start();
140
 
141
+ $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
142
+ serialize($_SERVER) .
143
+ serialize($_POST) .
144
+ serialize($_GET) .
145
+ serialize($_COOKIE) .
146
+ serialize($_GLOBAL) .
147
+ serialize($_SESSION) .
148
+ serialize($_OLD_SESSION)
149
+ ));
150
+ if (!isset($_SESSION['count'])) {
151
+ $_SESSION['count'] = 0;
152
+ }
153
+ $_SESSION['count']++;
154
 
155
+ session_write_close();
156
 
157
+ // restore old session data
158
+ if ($old_session_id != '') {
159
+ session_id($old_session_id);
160
+ session_start();
161
+ ini_set('session.use_cookies', $old_use_cookies);
162
+ session_cache_limiter($old_session_cache_limiter);
163
+ } else {
164
+ if (isset($_OLD_SESSION)) {
165
+ $_SESSION = $_OLD_SESSION;
166
+ unset($_OLD_SESSION);
167
+ } else {
168
+ unset($_SESSION);
169
+ }
170
  }
 
 
 
171
 
172
+ // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
173
+ // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
174
+ // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
175
+ // original hash and the current hash. we'll be emulating that. for more info see the following URL:
176
+ //
177
+ // http://tools.ietf.org/html/rfc4253#section-7.2
178
+ //
179
+ // see the is_string($crypto) part for an example of how to expand the keys
180
+ $key = pack('H*', sha1($seed . 'A'));
181
+ $iv = pack('H*', sha1($seed . 'C'));
182
 
183
+ // ciphers are used as per the nist.gov link below. also, see this link:
184
+ //
185
+ // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
 
 
 
186
  switch (true) {
187
  case class_exists('Crypt_AES'):
188
  $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
197
  $crypto = new Crypt_RC4();
198
  break;
199
  default:
200
+ $crypto = $seed;
201
+ return crypt_random_string($length);
202
  }
203
+
204
  $crypto->setKey($key);
205
  $crypto->setIV($iv);
206
  $crypto->enableContinuousBuffer();
207
  }
208
 
209
+ if (is_string($crypto)) {
210
+ // the following is based off of ANSI X9.31:
211
+ //
212
+ // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
213
+ //
214
+ // OpenSSL uses that same standard for it's random numbers:
215
+ //
216
+ // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
217
+ // (do a search for "ANS X9.31 A.2.4")
218
+ //
219
+ // ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
220
+ // later on in the code) but if they're not we'll use sha1
221
+ $result = '';
222
+ while (strlen($result) < $length) { // each loop adds 20 bytes
223
+ // microtime() isn't packed as "densely" as it could be but then neither is that the idea.
224
+ // the idea is simply to ensure that each "block" has a unique element to it.
225
+ $i = pack('H*', sha1(microtime()));
226
+ $r = pack('H*', sha1($i ^ $v));
227
+ $v = pack('H*', sha1($r ^ $i));
228
+ $result.= $r;
229
+ }
230
+ return substr($result, 0, $length);
231
+ }
232
+
233
+ //return $crypto->encrypt(str_repeat("\0", $length));
234
+
235
+ $result = '';
236
+ while (strlen($result) < $length) {
237
+ $i = $crypto->encrypt(microtime());
238
+ $r = $crypto->encrypt($i ^ $v);
239
+ $v = $crypto->encrypt($r ^ $i);
240
+ $result.= $r;
241
+ }
242
+ return substr($result, 0, $length);
243
  }
 
phpseclib/Crypt/Rijndael.php CHANGED
@@ -1,1478 +1,1502 @@
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: Permission is hereby granted, free of charge, to any person obtaining a copy
48
- * of this software and associated documentation files (the "Software"), to deal
49
- * in the Software without restriction, including without limitation the rights
50
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
- * copies of the Software, and to permit persons to whom the Software is
52
- * furnished to do so, subject to the following conditions:
53
- *
54
- * The above copyright notice and this permission notice shall be included in
55
- * all copies or substantial portions of the Software.
56
- *
57
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
61
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63
- * THE SOFTWARE.
64
- *
65
- * @category Crypt
66
- * @package Crypt_Rijndael
67
- * @author Jim Wigginton <terrafrost@php.net>
68
- * @copyright MMVIII Jim Wigginton
69
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
- * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
71
- * @link http://phpseclib.sourceforge.net
72
- */
73
-
74
- /**#@+
75
- * @access public
76
- * @see Crypt_Rijndael::encrypt()
77
- * @see Crypt_Rijndael::decrypt()
78
- */
79
- /**
80
- * Encrypt / decrypt using the Counter mode.
81
- *
82
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
83
- *
84
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
85
- */
86
- define('CRYPT_RIJNDAEL_MODE_CTR', -1);
87
- /**
88
- * Encrypt / decrypt using the Electronic Code Book mode.
89
- *
90
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
91
- */
92
- define('CRYPT_RIJNDAEL_MODE_ECB', 1);
93
- /**
94
- * Encrypt / decrypt using the Code Book Chaining mode.
95
- *
96
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
97
- */
98
- define('CRYPT_RIJNDAEL_MODE_CBC', 2);
99
- /**
100
- * Encrypt / decrypt using the Cipher Feedback mode.
101
- *
102
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
103
- */
104
- define('CRYPT_RIJNDAEL_MODE_CFB', 3);
105
- /**
106
- * Encrypt / decrypt using the Cipher Feedback mode.
107
- *
108
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
109
- */
110
- define('CRYPT_RIJNDAEL_MODE_OFB', 4);
111
- /**#@-*/
112
-
113
- /**#@+
114
- * @access private
115
- * @see Crypt_Rijndael::Crypt_Rijndael()
116
- */
117
- /**
118
- * Toggles the internal implementation
119
- */
120
- define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
121
- /**
122
- * Toggles the mcrypt implementation
123
- */
124
- define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
125
- /**#@-*/
126
-
127
- /**
128
- * Pure-PHP implementation of Rijndael.
129
- *
130
- * @author Jim Wigginton <terrafrost@php.net>
131
- * @version 0.1.0
132
- * @access public
133
- * @package Crypt_Rijndael
134
- */
135
- class Crypt_Rijndael {
136
- /**
137
- * The Encryption Mode
138
- *
139
- * @see Crypt_Rijndael::Crypt_Rijndael()
140
- * @var Integer
141
- * @access private
142
- */
143
- var $mode;
144
-
145
- /**
146
- * The Key
147
- *
148
- * @see Crypt_Rijndael::setKey()
149
- * @var String
150
- * @access private
151
- */
152
- var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
153
-
154
- /**
155
- * The Initialization Vector
156
- *
157
- * @see Crypt_Rijndael::setIV()
158
- * @var String
159
- * @access private
160
- */
161
- var $iv = '';
162
-
163
- /**
164
- * A "sliding" Initialization Vector
165
- *
166
- * @see Crypt_Rijndael::enableContinuousBuffer()
167
- * @var String
168
- * @access private
169
- */
170
- var $encryptIV = '';
171
-
172
- /**
173
- * A "sliding" Initialization Vector
174
- *
175
- * @see Crypt_Rijndael::enableContinuousBuffer()
176
- * @var String
177
- * @access private
178
- */
179
- var $decryptIV = '';
180
-
181
- /**
182
- * Continuous Buffer status
183
- *
184
- * @see Crypt_Rijndael::enableContinuousBuffer()
185
- * @var Boolean
186
- * @access private
187
- */
188
- var $continuousBuffer = false;
189
-
190
- /**
191
- * Padding status
192
- *
193
- * @see Crypt_Rijndael::enablePadding()
194
- * @var Boolean
195
- * @access private
196
- */
197
- var $padding = true;
198
-
199
- /**
200
- * Does the key schedule need to be (re)calculated?
201
- *
202
- * @see setKey()
203
- * @see setBlockLength()
204
- * @see setKeyLength()
205
- * @var Boolean
206
- * @access private
207
- */
208
- var $changed = true;
209
-
210
- /**
211
- * Has the key length explicitly been set or should it be derived from the key, itself?
212
- *
213
- * @see setKeyLength()
214
- * @var Boolean
215
- * @access private
216
- */
217
- var $explicit_key_length = false;
218
-
219
- /**
220
- * The Key Schedule
221
- *
222
- * @see _setup()
223
- * @var Array
224
- * @access private
225
- */
226
- var $w;
227
-
228
- /**
229
- * The Inverse Key Schedule
230
- *
231
- * @see _setup()
232
- * @var Array
233
- * @access private
234
- */
235
- var $dw;
236
-
237
- /**
238
- * The Block Length
239
- *
240
- * @see setBlockLength()
241
- * @var Integer
242
- * @access private
243
- * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
244
- * $Nb because we need this value and not $Nb to pad strings appropriately.
245
- */
246
- var $block_size = 16;
247
-
248
- /**
249
- * The Block Length divided by 32
250
- *
251
- * @see setBlockLength()
252
- * @var Integer
253
- * @access private
254
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
255
- * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
256
- * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
257
- * of that, we'll just precompute it once.
258
- *
259
- */
260
- var $Nb = 4;
261
-
262
- /**
263
- * The Key Length
264
- *
265
- * @see setKeyLength()
266
- * @var Integer
267
- * @access private
268
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
269
- * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
270
- * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
271
- * of that, we'll just precompute it once.
272
- */
273
- var $key_size = 16;
274
-
275
- /**
276
- * The Key Length divided by 32
277
- *
278
- * @see setKeyLength()
279
- * @var Integer
280
- * @access private
281
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
282
- */
283
- var $Nk = 4;
284
-
285
- /**
286
- * The Number of Rounds
287
- *
288
- * @var Integer
289
- * @access private
290
- * @internal The max value is 14, the min value is 10.
291
- */
292
- var $Nr;
293
-
294
- /**
295
- * Shift offsets
296
- *
297
- * @var Array
298
- * @access private
299
- */
300
- var $c;
301
-
302
- /**
303
- * Precomputed mixColumns table
304
- *
305
- * @see Crypt_Rijndael()
306
- * @var Array
307
- * @access private
308
- */
309
- var $t0;
310
-
311
- /**
312
- * Precomputed mixColumns table
313
- *
314
- * @see Crypt_Rijndael()
315
- * @var Array
316
- * @access private
317
- */
318
- var $t1;
319
-
320
- /**
321
- * Precomputed mixColumns table
322
- *
323
- * @see Crypt_Rijndael()
324
- * @var Array
325
- * @access private
326
- */
327
- var $t2;
328
-
329
- /**
330
- * Precomputed mixColumns table
331
- *
332
- * @see Crypt_Rijndael()
333
- * @var Array
334
- * @access private
335
- */
336
- var $t3;
337
-
338
- /**
339
- * Precomputed invMixColumns table
340
- *
341
- * @see Crypt_Rijndael()
342
- * @var Array
343
- * @access private
344
- */
345
- var $dt0;
346
-
347
- /**
348
- * Precomputed invMixColumns table
349
- *
350
- * @see Crypt_Rijndael()
351
- * @var Array
352
- * @access private
353
- */
354
- var $dt1;
355
-
356
- /**
357
- * Precomputed invMixColumns table
358
- *
359
- * @see Crypt_Rijndael()
360
- * @var Array
361
- * @access private
362
- */
363
- var $dt2;
364
-
365
- /**
366
- * Precomputed invMixColumns table
367
- *
368
- * @see Crypt_Rijndael()
369
- * @var Array
370
- * @access private
371
- */
372
- var $dt3;
373
-
374
- /**
375
- * Is the mode one that is paddable?
376
- *
377
- * @see Crypt_Rijndael::Crypt_Rijndael()
378
- * @var Boolean
379
- * @access private
380
- */
381
- var $paddable = false;
382
-
383
- /**
384
- * Encryption buffer for CTR, OFB and CFB modes
385
- *
386
- * @see Crypt_Rijndael::encrypt()
387
- * @var String
388
- * @access private
389
- */
390
- var $enbuffer = array('encrypted' => '', 'xor' => '');
391
-
392
- /**
393
- * Decryption buffer for CTR, OFB and CFB modes
394
- *
395
- * @see Crypt_Rijndael::decrypt()
396
- * @var String
397
- * @access private
398
- */
399
- var $debuffer = array('ciphertext' => '');
400
-
401
- /**
402
- * Default Constructor.
403
- *
404
- * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
405
- * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
406
- *
407
- * @param optional Integer $mode
408
- * @return Crypt_Rijndael
409
- * @access public
410
- */
411
- function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
412
- {
413
- switch ($mode) {
414
- case CRYPT_RIJNDAEL_MODE_ECB:
415
- case CRYPT_RIJNDAEL_MODE_CBC:
416
- $this->paddable = true;
417
- $this->mode = $mode;
418
- break;
419
- case CRYPT_RIJNDAEL_MODE_CTR:
420
- case CRYPT_RIJNDAEL_MODE_CFB:
421
- case CRYPT_RIJNDAEL_MODE_OFB:
422
- $this->mode = $mode;
423
- break;
424
- default:
425
- $this->paddable = true;
426
- $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
427
- }
428
-
429
- $t3 = &$this->t3;
430
- $t2 = &$this->t2;
431
- $t1 = &$this->t1;
432
- $t0 = &$this->t0;
433
-
434
- $dt3 = &$this->dt3;
435
- $dt2 = &$this->dt2;
436
- $dt1 = &$this->dt1;
437
- $dt0 = &$this->dt0;
438
-
439
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
440
- // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
441
- // those are the names we'll use.
442
- $t3 = array(
443
- 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
444
- 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
445
- 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
446
- 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
447
- 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
448
- 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
449
- 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
450
- 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
451
- 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
452
- 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
453
- 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
454
- 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
455
- 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
456
- 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
457
- 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
458
- 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
459
- 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
460
- 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
461
- 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
462
- 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
463
- 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
464
- 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
465
- 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
466
- 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
467
- 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
468
- 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
469
- 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
470
- 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
471
- 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
472
- 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
473
- 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
474
- 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
475
- );
476
-
477
- $dt3 = array(
478
- 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
479
- 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
480
- 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
481
- 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
482
- 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
483
- 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
484
- 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
485
- 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
486
- 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
487
- 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
488
- 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
489
- 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
490
- 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
491
- 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
492
- 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
493
- 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
494
- 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
495
- 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
496
- 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
497
- 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
498
- 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
499
- 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
500
- 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
501
- 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
502
- 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
503
- 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
504
- 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
505
- 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
506
- 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
507
- 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
508
- 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
509
- 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
510
- );
511
-
512
- for ($i = 0; $i < 256; $i++) {
513
- $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
514
- $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
515
- $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
516
-
517
- $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
518
- $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
519
- $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
520
- }
521
- }
522
-
523
- /**
524
- * Sets the key.
525
- *
526
- * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
527
- * 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
528
- * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
529
- * excess bits.
530
- *
531
- * If the key is not explicitly set, it'll be assumed to be all null bytes.
532
- *
533
- * @access public
534
- * @param String $key
535
- */
536
- function setKey($key)
537
- {
538
- $this->key = $key;
539
- $this->changed = true;
540
- }
541
-
542
- /**
543
- * Sets the initialization vector. (optional)
544
- *
545
- * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
546
- * to be all zero's.
547
- *
548
- * @access public
549
- * @param String $iv
550
- */
551
- function setIV($iv)
552
- {
553
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));
554
- }
555
-
556
- /**
557
- * Sets the key length
558
- *
559
- * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
560
- * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
561
- *
562
- * @access public
563
- * @param Integer $length
564
- */
565
- function setKeyLength($length)
566
- {
567
- $length >>= 5;
568
- if ($length > 8) {
569
- $length = 8;
570
- } else if ($length < 4) {
571
- $length = 4;
572
- }
573
- $this->Nk = $length;
574
- $this->key_size = $length << 2;
575
-
576
- $this->explicit_key_length = true;
577
- $this->changed = true;
578
- }
579
-
580
- /**
581
- * Sets the password.
582
- *
583
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
584
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
585
- * $hash, $salt, $method
586
- * Set $dkLen by calling setKeyLength()
587
- *
588
- * @param String $password
589
- * @param optional String $method
590
- * @access public
591
- */
592
- function setPassword($password, $method = 'pbkdf2')
593
- {
594
- $key = '';
595
-
596
- switch ($method) {
597
- default: // 'pbkdf2'
598
- list(, , $hash, $salt, $count) = func_get_args();
599
- if (!isset($hash)) {
600
- $hash = 'sha1';
601
- }
602
- // WPA and WPA use the SSID as the salt
603
- if (!isset($salt)) {
604
- $salt = 'phpseclib';
605
- }
606
- // RFC2898#section-4.2 uses 1,000 iterations by default
607
- // WPA and WPA2 use 4,096.
608
- if (!isset($count)) {
609
- $count = 1000;
610
- }
611
-
612
- if (!class_exists('Crypt_Hash')) {
613
- require_once('Crypt/Hash.php');
614
- }
615
-
616
- $i = 1;
617
- while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size
618
- //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
619
- $hmac = new Crypt_Hash();
620
- $hmac->setHash($hash);
621
- $hmac->setKey($password);
622
- $f = $u = $hmac->hash($salt . pack('N', $i++));
623
- for ($j = 2; $j <= $count; $j++) {
624
- $u = $hmac->hash($u);
625
- $f^= $u;
626
- }
627
- $key.= $f;
628
- }
629
- }
630
-
631
- $this->setKey(substr($key, 0, $this->key_size));
632
- }
633
-
634
- /**
635
- * Sets the block length
636
- *
637
- * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
638
- * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
639
- *
640
- * @access public
641
- * @param Integer $length
642
- */
643
- function setBlockLength($length)
644
- {
645
- $length >>= 5;
646
- if ($length > 8) {
647
- $length = 8;
648
- } else if ($length < 4) {
649
- $length = 4;
650
- }
651
- $this->Nb = $length;
652
- $this->block_size = $length << 2;
653
- $this->changed = true;
654
- }
655
-
656
- /**
657
- * Generate CTR XOR encryption key
658
- *
659
- * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
660
- * plaintext / ciphertext in CTR mode.
661
- *
662
- * @see Crypt_Rijndael::decrypt()
663
- * @see Crypt_Rijndael::encrypt()
664
- * @access public
665
- * @param Integer $length
666
- * @param String $iv
667
- */
668
- function _generate_xor($length, &$iv)
669
- {
670
- $xor = '';
671
- $block_size = $this->block_size;
672
- $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
673
- for ($i = 0; $i < $num_blocks; $i++) {
674
- $xor.= $iv;
675
- for ($j = 4; $j <= $block_size; $j+=4) {
676
- $temp = substr($iv, -$j, 4);
677
- switch ($temp) {
678
- case "\xFF\xFF\xFF\xFF":
679
- $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
680
- break;
681
- case "\x7F\xFF\xFF\xFF":
682
- $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
683
- break 2;
684
- default:
685
- extract(unpack('Ncount', $temp));
686
- $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
687
- break 2;
688
- }
689
- }
690
- }
691
-
692
- return $xor;
693
- }
694
-
695
- /**
696
- * Encrypts a message.
697
- *
698
- * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
699
- * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
700
- * necessary are discussed in the following
701
- * URL:
702
- *
703
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
704
- *
705
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
706
- * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
707
- * length.
708
- *
709
- * @see Crypt_Rijndael::decrypt()
710
- * @access public
711
- * @param String $plaintext
712
- */
713
- function encrypt($plaintext)
714
- {
715
- $this->_setup();
716
- if ($this->paddable) {
717
- $plaintext = $this->_pad($plaintext);
718
- }
719
-
720
- $block_size = $this->block_size;
721
- $buffer = &$this->enbuffer;
722
- $continuousBuffer = $this->continuousBuffer;
723
- $ciphertext = '';
724
- switch ($this->mode) {
725
- case CRYPT_RIJNDAEL_MODE_ECB:
726
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
727
- $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
728
- }
729
- break;
730
- case CRYPT_RIJNDAEL_MODE_CBC:
731
- $xor = $this->encryptIV;
732
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
733
- $block = substr($plaintext, $i, $block_size);
734
- $block = $this->_encryptBlock($block ^ $xor);
735
- $xor = $block;
736
- $ciphertext.= $block;
737
- }
738
- if ($this->continuousBuffer) {
739
- $this->encryptIV = $xor;
740
- }
741
- break;
742
- case CRYPT_RIJNDAEL_MODE_CTR:
743
- $xor = $this->encryptIV;
744
- if (!empty($buffer['encrypted'])) {
745
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
746
- $block = substr($plaintext, $i, $block_size);
747
- $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
748
- $key = $this->_string_shift($buffer['encrypted'], $block_size);
749
- $ciphertext.= $block ^ $key;
750
- }
751
- } else {
752
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
753
- $block = substr($plaintext, $i, $block_size);
754
- $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
755
- $ciphertext.= $block ^ $key;
756
- }
757
- }
758
- if ($this->continuousBuffer) {
759
- $this->encryptIV = $xor;
760
- if ($start = strlen($plaintext) % $block_size) {
761
- $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
762
- }
763
- }
764
- break;
765
- case CRYPT_RIJNDAEL_MODE_CFB:
766
- if (!empty($buffer['xor'])) {
767
- $ciphertext = $plaintext ^ $buffer['xor'];
768
- $iv = $buffer['encrypted'] . $ciphertext;
769
- $start = strlen($ciphertext);
770
- $buffer['encrypted'].= $ciphertext;
771
- $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
772
- } else {
773
- $ciphertext = '';
774
- $iv = $this->encryptIV;
775
- $start = 0;
776
- }
777
-
778
- for ($i = $start; $i < strlen($plaintext); $i+=$block_size) {
779
- $block = substr($plaintext, $i, $block_size);
780
- $xor = $this->_encryptBlock($iv);
781
- $iv = $block ^ $xor;
782
- if ($continuousBuffer && strlen($iv) != $block_size) {
783
- $buffer = array(
784
- 'encrypted' => $iv,
785
- 'xor' => substr($xor, strlen($iv))
786
- );
787
- }
788
- $ciphertext.= $iv;
789
- }
790
-
791
- if ($this->continuousBuffer) {
792
- $this->encryptIV = $iv;
793
- }
794
- break;
795
- case CRYPT_RIJNDAEL_MODE_OFB:
796
- $xor = $this->encryptIV;
797
- if (strlen($buffer)) {
798
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
799
- $xor = $this->_encryptBlock($xor);
800
- $buffer.= $xor;
801
- $key = $this->_string_shift($buffer, $block_size);
802
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $key;
803
- }
804
- } else {
805
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
806
- $xor = $this->_encryptBlock($xor);
807
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
808
- }
809
- $key = $xor;
810
- }
811
- if ($this->continuousBuffer) {
812
- $this->encryptIV = $xor;
813
- if ($start = strlen($plaintext) % $block_size) {
814
- $buffer = substr($key, $start) . $buffer;
815
- }
816
- }
817
- }
818
-
819
- return $ciphertext;
820
- }
821
-
822
- /**
823
- * Decrypts a message.
824
- *
825
- * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
826
- * it is.
827
- *
828
- * @see Crypt_Rijndael::encrypt()
829
- * @access public
830
- * @param String $ciphertext
831
- */
832
- function decrypt($ciphertext)
833
- {
834
- $this->_setup();
835
-
836
- if ($this->paddable) {
837
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
838
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
839
- $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
840
- }
841
-
842
- $block_size = $this->block_size;
843
- $buffer = &$this->debuffer;
844
- $continuousBuffer = $this->continuousBuffer;
845
- $plaintext = '';
846
- switch ($this->mode) {
847
- case CRYPT_RIJNDAEL_MODE_ECB:
848
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
849
- $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
850
- }
851
- break;
852
- case CRYPT_RIJNDAEL_MODE_CBC:
853
- $xor = $this->decryptIV;
854
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
855
- $block = substr($ciphertext, $i, $block_size);
856
- $plaintext.= $this->_decryptBlock($block) ^ $xor;
857
- $xor = $block;
858
- }
859
- if ($this->continuousBuffer) {
860
- $this->decryptIV = $xor;
861
- }
862
- break;
863
- case CRYPT_RIJNDAEL_MODE_CTR:
864
- $xor = $this->decryptIV;
865
- if (!empty($buffer['ciphertext'])) {
866
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
867
- $block = substr($ciphertext, $i, $block_size);
868
- $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
869
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
870
- $plaintext.= $block ^ $key;
871
- }
872
- } else {
873
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
874
- $block = substr($ciphertext, $i, $block_size);
875
- $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
876
- $plaintext.= $block ^ $key;
877
- }
878
- }
879
- if ($this->continuousBuffer) {
880
- $this->decryptIV = $xor;
881
- if ($start = strlen($ciphertext) % $block_size) {
882
- $buffer['ciphertext'] = substr($key, $start) . $buffer['encrypted'];
883
- }
884
- }
885
- break;
886
- case CRYPT_RIJNDAEL_MODE_CFB:
887
- if (!empty($buffer['ciphertext'])) {
888
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
889
- $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
890
- if (strlen($buffer['ciphertext']) == $block_size) {
891
- $xor = $this->_encryptBlock($buffer['ciphertext']);
892
- $buffer['ciphertext'] = '';
893
- }
894
- $start = strlen($plaintext);
895
- $block = $this->decryptIV;
896
- } else {
897
- $plaintext = '';
898
- $xor = $this->_encryptBlock($this->decryptIV);
899
- $start = 0;
900
- }
901
-
902
- for ($i = $start; $i < strlen($ciphertext); $i+=$block_size) {
903
- $block = substr($ciphertext, $i, $block_size);
904
- $plaintext.= $block ^ $xor;
905
- if ($continuousBuffer && strlen($block) != $block_size) {
906
- $buffer['ciphertext'].= $block;
907
- $block = $xor;
908
- } else if (strlen($block) == $block_size) {
909
- $xor = $this->_encryptBlock($block);
910
- }
911
- }
912
- if ($this->continuousBuffer) {
913
- $this->decryptIV = $block;
914
- }
915
- break;
916
- case CRYPT_RIJNDAEL_MODE_OFB:
917
- $xor = $this->decryptIV;
918
- if (strlen($buffer)) {
919
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
920
- $xor = $this->_encryptBlock($xor);
921
- $buffer.= $xor;
922
- $key = $this->_string_shift($buffer, $block_size);
923
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $key;
924
- }
925
- } else {
926
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
927
- $xor = $this->_encryptBlock($xor);
928
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
929
- }
930
- $key = $xor;
931
- }
932
- if ($this->continuousBuffer) {
933
- $this->decryptIV = $xor;
934
- if ($start = strlen($ciphertext) % $block_size) {
935
- $buffer = substr($key, $start) . $buffer;
936
- }
937
- }
938
- }
939
-
940
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
941
- }
942
-
943
- /**
944
- * Encrypts a block
945
- *
946
- * @access private
947
- * @param String $in
948
- * @return String
949
- */
950
- function _encryptBlock($in)
951
- {
952
- $state = array();
953
- $words = unpack('N*word', $in);
954
-
955
- $w = $this->w;
956
- $t0 = $this->t0;
957
- $t1 = $this->t1;
958
- $t2 = $this->t2;
959
- $t3 = $this->t3;
960
- $Nb = $this->Nb;
961
- $Nr = $this->Nr;
962
- $c = $this->c;
963
-
964
- // addRoundKey
965
- $i = 0;
966
- foreach ($words as $word) {
967
- $state[] = $word ^ $w[0][$i++];
968
- }
969
-
970
- // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
971
- // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
972
- // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
973
- // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
974
- // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
975
- // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
976
-
977
- // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
978
- $temp = array();
979
- for ($round = 1; $round < $Nr; $round++) {
980
- $i = 0; // $c[0] == 0
981
- $j = $c[1];
982
- $k = $c[2];
983
- $l = $c[3];
984
-
985
- while ($i < $this->Nb) {
986
- $temp[$i] = $t0[$state[$i] & 0xFF000000] ^
987
- $t1[$state[$j] & 0x00FF0000] ^
988
- $t2[$state[$k] & 0x0000FF00] ^
989
- $t3[$state[$l] & 0x000000FF] ^
990
- $w[$round][$i];
991
- $i++;
992
- $j = ($j + 1) % $Nb;
993
- $k = ($k + 1) % $Nb;
994
- $l = ($l + 1) % $Nb;
995
- }
996
-
997
- for ($i = 0; $i < $Nb; $i++) {
998
- $state[$i] = $temp[$i];
999
- }
1000
- }
1001
-
1002
- // subWord
1003
- for ($i = 0; $i < $Nb; $i++) {
1004
- $state[$i] = $this->_subWord($state[$i]);
1005
- }
1006
-
1007
- // shiftRows + addRoundKey
1008
- $i = 0; // $c[0] == 0
1009
- $j = $c[1];
1010
- $k = $c[2];
1011
- $l = $c[3];
1012
- while ($i < $this->Nb) {
1013
- $temp[$i] = ($state[$i] & 0xFF000000) ^
1014
- ($state[$j] & 0x00FF0000) ^
1015
- ($state[$k] & 0x0000FF00) ^
1016
- ($state[$l] & 0x000000FF) ^
1017
- $w[$Nr][$i];
1018
- $i++;
1019
- $j = ($j + 1) % $Nb;
1020
- $k = ($k + 1) % $Nb;
1021
- $l = ($l + 1) % $Nb;
1022
- }
1023
- $state = $temp;
1024
-
1025
- array_unshift($state, 'N*');
1026
-
1027
- return call_user_func_array('pack', $state);
1028
- }
1029
-
1030
- /**
1031
- * Decrypts a block
1032
- *
1033
- * @access private
1034
- * @param String $in
1035
- * @return String
1036
- */
1037
- function _decryptBlock($in)
1038
- {
1039
- $state = array();
1040
- $words = unpack('N*word', $in);
1041
-
1042
- $num_states = count($state);
1043
- $dw = $this->dw;
1044
- $dt0 = $this->dt0;
1045
- $dt1 = $this->dt1;
1046
- $dt2 = $this->dt2;
1047
- $dt3 = $this->dt3;
1048
- $Nb = $this->Nb;
1049
- $Nr = $this->Nr;
1050
- $c = $this->c;
1051
-
1052
- // addRoundKey
1053
- $i = 0;
1054
- foreach ($words as $word) {
1055
- $state[] = $word ^ $dw[$Nr][$i++];
1056
- }
1057
-
1058
- $temp = array();
1059
- for ($round = $Nr - 1; $round > 0; $round--) {
1060
- $i = 0; // $c[0] == 0
1061
- $j = $Nb - $c[1];
1062
- $k = $Nb - $c[2];
1063
- $l = $Nb - $c[3];
1064
-
1065
- while ($i < $Nb) {
1066
- $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
1067
- $dt1[$state[$j] & 0x00FF0000] ^
1068
- $dt2[$state[$k] & 0x0000FF00] ^
1069
- $dt3[$state[$l] & 0x000000FF] ^
1070
- $dw[$round][$i];
1071
- $i++;
1072
- $j = ($j + 1) % $Nb;
1073
- $k = ($k + 1) % $Nb;
1074
- $l = ($l + 1) % $Nb;
1075
- }
1076
-
1077
- for ($i = 0; $i < $Nb; $i++) {
1078
- $state[$i] = $temp[$i];
1079
- }
1080
- }
1081
-
1082
- // invShiftRows + invSubWord + addRoundKey
1083
- $i = 0; // $c[0] == 0
1084
- $j = $Nb - $c[1];
1085
- $k = $Nb - $c[2];
1086
- $l = $Nb - $c[3];
1087
-
1088
- while ($i < $Nb) {
1089
- $temp[$i] = $dw[0][$i] ^
1090
- $this->_invSubWord(($state[$i] & 0xFF000000) |
1091
- ($state[$j] & 0x00FF0000) |
1092
- ($state[$k] & 0x0000FF00) |
1093
- ($state[$l] & 0x000000FF));
1094
- $i++;
1095
- $j = ($j + 1) % $Nb;
1096
- $k = ($k + 1) % $Nb;
1097
- $l = ($l + 1) % $Nb;
1098
- }
1099
-
1100
- $state = $temp;
1101
-
1102
- array_unshift($state, 'N*');
1103
-
1104
- return call_user_func_array('pack', $state);
1105
- }
1106
-
1107
- /**
1108
- * Setup Rijndael
1109
- *
1110
- * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
1111
- * key schedule.
1112
- *
1113
- * @access private
1114
- */
1115
- function _setup()
1116
- {
1117
- // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
1118
- // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
1119
- static $rcon = array(0,
1120
- 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
1121
- 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
1122
- 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
1123
- 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
1124
- 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
1125
- 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
1126
- );
1127
-
1128
- if (!$this->changed) {
1129
- return;
1130
- }
1131
-
1132
- if (!$this->explicit_key_length) {
1133
- // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
1134
- $length = strlen($this->key) >> 2;
1135
- if ($length > 8) {
1136
- $length = 8;
1137
- } else if ($length < 4) {
1138
- $length = 4;
1139
- }
1140
- $this->Nk = $length;
1141
- $this->key_size = $length << 2;
1142
- }
1143
-
1144
- $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
1145
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
1146
-
1147
- // see Rijndael-ammended.pdf#page=44
1148
- $this->Nr = max($this->Nk, $this->Nb) + 6;
1149
-
1150
- // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
1151
- // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
1152
- // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
1153
- // "Table 2: Shift offsets for different block lengths"
1154
- switch ($this->Nb) {
1155
- case 4:
1156
- case 5:
1157
- case 6:
1158
- $this->c = array(0, 1, 2, 3);
1159
- break;
1160
- case 7:
1161
- $this->c = array(0, 1, 2, 4);
1162
- break;
1163
- case 8:
1164
- $this->c = array(0, 1, 3, 4);
1165
- }
1166
-
1167
- $key = $this->key;
1168
-
1169
- $w = array_values(unpack('N*words', $key));
1170
-
1171
- $length = $this->Nb * ($this->Nr + 1);
1172
- for ($i = $this->Nk; $i < $length; $i++) {
1173
- $temp = $w[$i - 1];
1174
- if ($i % $this->Nk == 0) {
1175
- // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
1176
- // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
1177
- // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
1178
- // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
1179
- $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
1180
- $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
1181
- } else if ($this->Nk > 6 && $i % $this->Nk == 4) {
1182
- $temp = $this->_subWord($temp);
1183
- }
1184
- $w[$i] = $w[$i - $this->Nk] ^ $temp;
1185
- }
1186
-
1187
- // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
1188
- // and generate the inverse key schedule. more specifically,
1189
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
1190
- // "The key expansion for the Inverse Cipher is defined as follows:
1191
- // 1. Apply the Key Expansion.
1192
- // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
1193
- // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
1194
- $temp = array();
1195
- for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
1196
- if ($col == $this->Nb) {
1197
- if ($row == 0) {
1198
- $this->dw[0] = $this->w[0];
1199
- } else {
1200
- // subWord + invMixColumn + invSubWord = invMixColumn
1201
- $j = 0;
1202
- while ($j < $this->Nb) {
1203
- $dw = $this->_subWord($this->w[$row][$j]);
1204
- $temp[$j] = $this->dt0[$dw & 0xFF000000] ^
1205
- $this->dt1[$dw & 0x00FF0000] ^
1206
- $this->dt2[$dw & 0x0000FF00] ^
1207
- $this->dt3[$dw & 0x000000FF];
1208
- $j++;
1209
- }
1210
- $this->dw[$row] = $temp;
1211
- }
1212
-
1213
- $col = 0;
1214
- $row++;
1215
- }
1216
- $this->w[$row][$col] = $w[$i];
1217
- }
1218
-
1219
- $this->dw[$row] = $this->w[$row];
1220
-
1221
- $this->changed = false;
1222
- }
1223
-
1224
- /**
1225
- * Performs S-Box substitutions
1226
- *
1227
- * @access private
1228
- */
1229
- function _subWord($word)
1230
- {
1231
- static $sbox0, $sbox1, $sbox2, $sbox3;
1232
-
1233
- if (empty($sbox0)) {
1234
- $sbox0 = array(
1235
- 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
1236
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
1237
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
1238
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
1239
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
1240
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
1241
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
1242
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
1243
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
1244
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
1245
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
1246
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
1247
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
1248
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
1249
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
1250
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
1251
- );
1252
-
1253
- $sbox1 = array();
1254
- $sbox2 = array();
1255
- $sbox3 = array();
1256
-
1257
- for ($i = 0; $i < 256; $i++) {
1258
- $sbox1[$i << 8] = $sbox0[$i] << 8;
1259
- $sbox2[$i << 16] = $sbox0[$i] << 16;
1260
- $sbox3[$i << 24] = $sbox0[$i] << 24;
1261
- }
1262
- }
1263
-
1264
- return $sbox0[$word & 0x000000FF] |
1265
- $sbox1[$word & 0x0000FF00] |
1266
- $sbox2[$word & 0x00FF0000] |
1267
- $sbox3[$word & 0xFF000000];
1268
- }
1269
-
1270
- /**
1271
- * Performs inverse S-Box substitutions
1272
- *
1273
- * @access private
1274
- */
1275
- function _invSubWord($word)
1276
- {
1277
- static $sbox0, $sbox1, $sbox2, $sbox3;
1278
-
1279
- if (empty($sbox0)) {
1280
- $sbox0 = array(
1281
- 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
1282
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
1283
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
1284
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
1285
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
1286
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
1287
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
1288
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
1289
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
1290
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
1291
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
1292
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
1293
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
1294
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1295
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1296
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1297
- );
1298
-
1299
- $sbox1 = array();
1300
- $sbox2 = array();
1301
- $sbox3 = array();
1302
-
1303
- for ($i = 0; $i < 256; $i++) {
1304
- $sbox1[$i << 8] = $sbox0[$i] << 8;
1305
- $sbox2[$i << 16] = $sbox0[$i] << 16;
1306
- $sbox3[$i << 24] = $sbox0[$i] << 24;
1307
- }
1308
- }
1309
-
1310
- return $sbox0[$word & 0x000000FF] |
1311
- $sbox1[$word & 0x0000FF00] |
1312
- $sbox2[$word & 0x00FF0000] |
1313
- $sbox3[$word & 0xFF000000];
1314
- }
1315
-
1316
- /**
1317
- * Pad "packets".
1318
- *
1319
- * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
1320
- * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1321
- * pad the input so that it is of the proper length.
1322
- *
1323
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1324
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1325
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1326
- * transmitted separately)
1327
- *
1328
- * @see Crypt_Rijndael::disablePadding()
1329
- * @access public
1330
- */
1331
- function enablePadding()
1332
- {
1333
- $this->padding = true;
1334
- }
1335
-
1336
- /**
1337
- * Do not pad packets.
1338
- *
1339
- * @see Crypt_Rijndael::enablePadding()
1340
- * @access public
1341
- */
1342
- function disablePadding()
1343
- {
1344
- $this->padding = false;
1345
- }
1346
-
1347
- /**
1348
- * Pads a string
1349
- *
1350
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1351
- * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
1352
- * chr($block_size - (strlen($text) % $block_size)
1353
- *
1354
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1355
- * and padding will, hence forth, be enabled.
1356
- *
1357
- * @see Crypt_Rijndael::_unpad()
1358
- * @access private
1359
- */
1360
- function _pad($text)
1361
- {
1362
- $length = strlen($text);
1363
-
1364
- if (!$this->padding) {
1365
- if ($length % $this->block_size == 0) {
1366
- return $text;
1367
- } else {
1368
- user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE);
1369
- $this->padding = true;
1370
- }
1371
- }
1372
-
1373
- $pad = $this->block_size - ($length % $this->block_size);
1374
-
1375
- return str_pad($text, $length + $pad, chr($pad));
1376
- }
1377
-
1378
- /**
1379
- * Unpads a string.
1380
- *
1381
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1382
- * and false will be returned.
1383
- *
1384
- * @see Crypt_Rijndael::_pad()
1385
- * @access private
1386
- */
1387
- function _unpad($text)
1388
- {
1389
- if (!$this->padding) {
1390
- return $text;
1391
- }
1392
-
1393
- $length = ord($text[strlen($text) - 1]);
1394
-
1395
- if (!$length || $length > $this->block_size) {
1396
- return false;
1397
- }
1398
-
1399
- return substr($text, 0, -$length);
1400
- }
1401
-
1402
- /**
1403
- * Treat consecutive "packets" as if they are a continuous buffer.
1404
- *
1405
- * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1406
- * will yield different outputs:
1407
- *
1408
- * <code>
1409
- * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1410
- * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1411
- * </code>
1412
- * <code>
1413
- * echo $rijndael->encrypt($plaintext);
1414
- * </code>
1415
- *
1416
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1417
- * another, as demonstrated with the following:
1418
- *
1419
- * <code>
1420
- * $rijndael->encrypt(substr($plaintext, 0, 16));
1421
- * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1422
- * </code>
1423
- * <code>
1424
- * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1425
- * </code>
1426
- *
1427
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1428
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1429
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1430
- *
1431
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
1432
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1433
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1434
- * however, they are also less intuitive and more likely to cause you problems.
1435
- *
1436
- * @see Crypt_Rijndael::disableContinuousBuffer()
1437
- * @access public
1438
- */
1439
- function enableContinuousBuffer()
1440
- {
1441
- $this->continuousBuffer = true;
1442
- }
1443
-
1444
- /**
1445
- * Treat consecutive packets as if they are a discontinuous buffer.
1446
- *
1447
- * The default behavior.
1448
- *
1449
- * @see Crypt_Rijndael::enableContinuousBuffer()
1450
- * @access public
1451
- */
1452
- function disableContinuousBuffer()
1453
- {
1454
- $this->continuousBuffer = false;
1455
- $this->encryptIV = $this->iv;
1456
- $this->decryptIV = $this->iv;
1457
- }
1458
-
1459
- /**
1460
- * String Shift
1461
- *
1462
- * Inspired by array_shift
1463
- *
1464
- * @param String $string
1465
- * @param optional Integer $index
1466
- * @return String
1467
- * @access private
1468
- */
1469
- function _string_shift(&$string, $index = 1)
1470
- {
1471
- $substr = substr($string, 0, $index);
1472
- $string = substr($string, $index);
1473
- return $substr;
1474
- }
1475
- }
1476
-
1477
- // vim: ts=4:sw=4:et:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1478
  // 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: Permission is hereby granted, free of charge, to any person obtaining a copy
48
+ * of this software and associated documentation files (the "Software"), to deal
49
+ * in the Software without restriction, including without limitation the rights
50
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
+ * copies of the Software, and to permit persons to whom the Software is
52
+ * furnished to do so, subject to the following conditions:
53
+ *
54
+ * The above copyright notice and this permission notice shall be included in
55
+ * all copies or substantial portions of the Software.
56
+ *
57
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
61
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
62
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63
+ * THE SOFTWARE.
64
+ *
65
+ * @category Crypt
66
+ * @package Crypt_Rijndael
67
+ * @author Jim Wigginton <terrafrost@php.net>
68
+ * @copyright MMVIII Jim Wigginton
69
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
+ * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
71
+ * @link http://phpseclib.sourceforge.net
72
+ */
73
+
74
+ /**#@+
75
+ * @access public
76
+ * @see Crypt_Rijndael::encrypt()
77
+ * @see Crypt_Rijndael::decrypt()
78
+ */
79
+ /**
80
+ * Encrypt / decrypt using the Counter mode.
81
+ *
82
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
83
+ *
84
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
85
+ */
86
+ define('CRYPT_RIJNDAEL_MODE_CTR', -1);
87
+ /**
88
+ * Encrypt / decrypt using the Electronic Code Book mode.
89
+ *
90
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
91
+ */
92
+ define('CRYPT_RIJNDAEL_MODE_ECB', 1);
93
+ /**
94
+ * Encrypt / decrypt using the Code Book Chaining mode.
95
+ *
96
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
97
+ */
98
+ define('CRYPT_RIJNDAEL_MODE_CBC', 2);
99
+ /**
100
+ * Encrypt / decrypt using the Cipher Feedback mode.
101
+ *
102
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
103
+ */
104
+ define('CRYPT_RIJNDAEL_MODE_CFB', 3);
105
+ /**
106
+ * Encrypt / decrypt using the Cipher Feedback mode.
107
+ *
108
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
109
+ */
110
+ define('CRYPT_RIJNDAEL_MODE_OFB', 4);
111
+ /**#@-*/
112
+
113
+ /**#@+
114
+ * @access private
115
+ * @see Crypt_Rijndael::Crypt_Rijndael()
116
+ */
117
+ /**
118
+ * Toggles the internal implementation
119
+ */
120
+ define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
121
+ /**
122
+ * Toggles the mcrypt implementation
123
+ */
124
+ define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
125
+ /**#@-*/
126
+
127
+ /**
128
+ * Pure-PHP implementation of Rijndael.
129
+ *
130
+ * @author Jim Wigginton <terrafrost@php.net>
131
+ * @version 0.1.0
132
+ * @access public
133
+ * @package Crypt_Rijndael
134
+ */
135
+ class Crypt_Rijndael {
136
+ /**
137
+ * The Encryption Mode
138
+ *
139
+ * @see Crypt_Rijndael::Crypt_Rijndael()
140
+ * @var Integer
141
+ * @access private
142
+ */
143
+ var $mode;
144
+
145
+ /**
146
+ * The Key
147
+ *
148
+ * @see Crypt_Rijndael::setKey()
149
+ * @var String
150
+ * @access private
151
+ */
152
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
153
+
154
+ /**
155
+ * The Initialization Vector
156
+ *
157
+ * @see Crypt_Rijndael::setIV()
158
+ * @var String
159
+ * @access private
160
+ */
161
+ var $iv = '';
162
+
163
+ /**
164
+ * A "sliding" Initialization Vector
165
+ *
166
+ * @see Crypt_Rijndael::enableContinuousBuffer()
167
+ * @var String
168
+ * @access private
169
+ */
170
+ var $encryptIV = '';
171
+
172
+ /**
173
+ * A "sliding" Initialization Vector
174
+ *
175
+ * @see Crypt_Rijndael::enableContinuousBuffer()
176
+ * @var String
177
+ * @access private
178
+ */
179
+ var $decryptIV = '';
180
+
181
+ /**
182
+ * Continuous Buffer status
183
+ *
184
+ * @see Crypt_Rijndael::enableContinuousBuffer()
185
+ * @var Boolean
186
+ * @access private
187
+ */
188
+ var $continuousBuffer = false;
189
+
190
+ /**
191
+ * Padding status
192
+ *
193
+ * @see Crypt_Rijndael::enablePadding()
194
+ * @var Boolean
195
+ * @access private
196
+ */
197
+ var $padding = true;
198
+
199
+ /**
200
+ * Does the key schedule need to be (re)calculated?
201
+ *
202
+ * @see setKey()
203
+ * @see setBlockLength()
204
+ * @see setKeyLength()
205
+ * @var Boolean
206
+ * @access private
207
+ */
208
+ var $changed = true;
209
+
210
+ /**
211
+ * Has the key length explicitly been set or should it be derived from the key, itself?
212
+ *
213
+ * @see setKeyLength()
214
+ * @var Boolean
215
+ * @access private
216
+ */
217
+ var $explicit_key_length = false;
218
+
219
+ /**
220
+ * The Key Schedule
221
+ *
222
+ * @see _setup()
223
+ * @var Array
224
+ * @access private
225
+ */
226
+ var $w;
227
+
228
+ /**
229
+ * The Inverse Key Schedule
230
+ *
231
+ * @see _setup()
232
+ * @var Array
233
+ * @access private
234
+ */
235
+ var $dw;
236
+
237
+ /**
238
+ * The Block Length
239
+ *
240
+ * @see setBlockLength()
241
+ * @var Integer
242
+ * @access private
243
+ * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
244
+ * $Nb because we need this value and not $Nb to pad strings appropriately.
245
+ */
246
+ var $block_size = 16;
247
+
248
+ /**
249
+ * The Block Length divided by 32
250
+ *
251
+ * @see setBlockLength()
252
+ * @var Integer
253
+ * @access private
254
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
255
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
256
+ * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
257
+ * of that, we'll just precompute it once.
258
+ *
259
+ */
260
+ var $Nb = 4;
261
+
262
+ /**
263
+ * The Key Length
264
+ *
265
+ * @see setKeyLength()
266
+ * @var Integer
267
+ * @access private
268
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
269
+ * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
270
+ * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
271
+ * of that, we'll just precompute it once.
272
+ */
273
+ var $key_size = 16;
274
+
275
+ /**
276
+ * The Key Length divided by 32
277
+ *
278
+ * @see setKeyLength()
279
+ * @var Integer
280
+ * @access private
281
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
282
+ */
283
+ var $Nk = 4;
284
+
285
+ /**
286
+ * The Number of Rounds
287
+ *
288
+ * @var Integer
289
+ * @access private
290
+ * @internal The max value is 14, the min value is 10.
291
+ */
292
+ var $Nr;
293
+
294
+ /**
295
+ * Shift offsets
296
+ *
297
+ * @var Array
298
+ * @access private
299
+ */
300
+ var $c;
301
+
302
+ /**
303
+ * Precomputed mixColumns table
304
+ *
305
+ * @see Crypt_Rijndael()
306
+ * @var Array
307
+ * @access private
308
+ */
309
+ var $t0;
310
+
311
+ /**
312
+ * Precomputed mixColumns table
313
+ *
314
+ * @see Crypt_Rijndael()
315
+ * @var Array
316
+ * @access private
317
+ */
318
+ var $t1;
319
+
320
+ /**
321
+ * Precomputed mixColumns table
322
+ *
323
+ * @see Crypt_Rijndael()
324
+ * @var Array
325
+ * @access private
326
+ */
327
+ var $t2;
328
+
329
+ /**
330
+ * Precomputed mixColumns table
331
+ *
332
+ * @see Crypt_Rijndael()
333
+ * @var Array
334
+ * @access private
335
+ */
336
+ var $t3;
337
+
338
+ /**
339
+ * Precomputed invMixColumns table
340
+ *
341
+ * @see Crypt_Rijndael()
342
+ * @var Array
343
+ * @access private
344
+ */
345
+ var $dt0;
346
+
347
+ /**
348
+ * Precomputed invMixColumns table
349
+ *
350
+ * @see Crypt_Rijndael()
351
+ * @var Array
352
+ * @access private
353
+ */
354
+ var $dt1;
355
+
356
+ /**
357
+ * Precomputed invMixColumns table
358
+ *
359
+ * @see Crypt_Rijndael()
360
+ * @var Array
361
+ * @access private
362
+ */
363
+ var $dt2;
364
+
365
+ /**
366
+ * Precomputed invMixColumns table
367
+ *
368
+ * @see Crypt_Rijndael()
369
+ * @var Array
370
+ * @access private
371
+ */
372
+ var $dt3;
373
+
374
+ /**
375
+ * Is the mode one that is paddable?
376
+ *
377
+ * @see Crypt_Rijndael::Crypt_Rijndael()
378
+ * @var Boolean
379
+ * @access private
380
+ */
381
+ var $paddable = false;
382
+
383
+ /**
384
+ * Encryption buffer for CTR, OFB and CFB modes
385
+ *
386
+ * @see Crypt_Rijndael::encrypt()
387
+ * @var String
388
+ * @access private
389
+ */
390
+ var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
391
+
392
+ /**
393
+ * Decryption buffer for CTR, OFB and CFB modes
394
+ *
395
+ * @see Crypt_Rijndael::decrypt()
396
+ * @var String
397
+ * @access private
398
+ */
399
+ var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
400
+
401
+ /**
402
+ * Default Constructor.
403
+ *
404
+ * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
405
+ * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
406
+ *
407
+ * @param optional Integer $mode
408
+ * @return Crypt_Rijndael
409
+ * @access public
410
+ */
411
+ function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
412
+ {
413
+ switch ($mode) {
414
+ case CRYPT_RIJNDAEL_MODE_ECB:
415
+ case CRYPT_RIJNDAEL_MODE_CBC:
416
+ $this->paddable = true;
417
+ $this->mode = $mode;
418
+ break;
419
+ case CRYPT_RIJNDAEL_MODE_CTR:
420
+ case CRYPT_RIJNDAEL_MODE_CFB:
421
+ case CRYPT_RIJNDAEL_MODE_OFB:
422
+ $this->mode = $mode;
423
+ break;
424
+ default:
425
+ $this->paddable = true;
426
+ $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
427
+ }
428
+
429
+ $t3 = &$this->t3;
430
+ $t2 = &$this->t2;
431
+ $t1 = &$this->t1;
432
+ $t0 = &$this->t0;
433
+
434
+ $dt3 = &$this->dt3;
435
+ $dt2 = &$this->dt2;
436
+ $dt1 = &$this->dt1;
437
+ $dt0 = &$this->dt0;
438
+
439
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
440
+ // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
441
+ // those are the names we'll use.
442
+ $t3 = array(
443
+ 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
444
+ 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
445
+ 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
446
+ 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
447
+ 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
448
+ 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
449
+ 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
450
+ 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
451
+ 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
452
+ 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
453
+ 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
454
+ 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
455
+ 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
456
+ 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
457
+ 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
458
+ 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
459
+ 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
460
+ 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
461
+ 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
462
+ 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
463
+ 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
464
+ 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
465
+ 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
466
+ 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
467
+ 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
468
+ 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
469
+ 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
470
+ 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
471
+ 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
472
+ 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
473
+ 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
474
+ 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
475
+ );
476
+
477
+ $dt3 = array(
478
+ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
479
+ 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
480
+ 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
481
+ 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
482
+ 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
483
+ 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
484
+ 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
485
+ 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
486
+ 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
487
+ 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
488
+ 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
489
+ 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
490
+ 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
491
+ 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
492
+ 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
493
+ 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
494
+ 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
495
+ 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
496
+ 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
497
+ 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
498
+ 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
499
+ 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
500
+ 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
501
+ 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
502
+ 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
503
+ 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
504
+ 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
505
+ 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
506
+ 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
507
+ 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
508
+ 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
509
+ 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
510
+ );
511
+
512
+ for ($i = 0; $i < 256; $i++) {
513
+ $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
514
+ $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
515
+ $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
516
+
517
+ $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
518
+ $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
519
+ $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
520
+ }
521
+ }
522
+
523
+ /**
524
+ * Sets the key.
525
+ *
526
+ * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
527
+ * 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
528
+ * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
529
+ * excess bits.
530
+ *
531
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
532
+ *
533
+ * @access public
534
+ * @param String $key
535
+ */
536
+ function setKey($key)
537
+ {
538
+ $this->key = $key;
539
+ $this->changed = true;
540
+ }
541
+
542
+ /**
543
+ * Sets the initialization vector. (optional)
544
+ *
545
+ * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
546
+ * to be all zero's.
547
+ *
548
+ * @access public
549
+ * @param String $iv
550
+ */
551
+ function setIV($iv)
552
+ {
553
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));
554
+ }
555
+
556
+ /**
557
+ * Sets the key length
558
+ *
559
+ * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
560
+ * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
561
+ *
562
+ * @access public
563
+ * @param Integer $length
564
+ */
565
+ function setKeyLength($length)
566
+ {
567
+ $length >>= 5;
568
+ if ($length > 8) {
569
+ $length = 8;
570
+ } else if ($length < 4) {
571
+ $length = 4;
572
+ }
573
+ $this->Nk = $length;
574
+ $this->key_size = $length << 2;
575
+
576
+ $this->explicit_key_length = true;
577
+ $this->changed = true;
578
+ }
579
+
580
+ /**
581
+ * Sets the password.
582
+ *
583
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
584
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
585
+ * $hash, $salt, $method
586
+ * Set $dkLen by calling setKeyLength()
587
+ *
588
+ * @param String $password
589
+ * @param optional String $method
590
+ * @access public
591
+ */
592
+ function setPassword($password, $method = 'pbkdf2')
593
+ {
594
+ $key = '';
595
+
596
+ switch ($method) {
597
+ default: // 'pbkdf2'
598
+ list(, , $hash, $salt, $count) = func_get_args();
599
+ if (!isset($hash)) {
600
+ $hash = 'sha1';
601
+ }
602
+ // WPA and WPA use the SSID as the salt
603
+ if (!isset($salt)) {
604
+ $salt = 'phpseclib';
605
+ }
606
+ // RFC2898#section-4.2 uses 1,000 iterations by default
607
+ // WPA and WPA2 use 4,096.
608
+ if (!isset($count)) {
609
+ $count = 1000;
610
+ }
611
+
612
+ if (!class_exists('Crypt_Hash')) {
613
+ require_once('Crypt/Hash.php');
614
+ }
615
+
616
+ $i = 1;
617
+ while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size
618
+ //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
619
+ $hmac = new Crypt_Hash();
620
+ $hmac->setHash($hash);
621
+ $hmac->setKey($password);
622
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
623
+ for ($j = 2; $j <= $count; $j++) {
624
+ $u = $hmac->hash($u);
625
+ $f^= $u;
626
+ }
627
+ $key.= $f;
628
+ }
629
+ }
630
+
631
+ $this->setKey(substr($key, 0, $this->key_size));
632
+ }
633
+
634
+ /**
635
+ * Sets the block length
636
+ *
637
+ * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
638
+ * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
639
+ *
640
+ * @access public
641
+ * @param Integer $length
642
+ */
643
+ function setBlockLength($length)
644
+ {
645
+ $length >>= 5;
646
+ if ($length > 8) {
647
+ $length = 8;
648
+ } else if ($length < 4) {
649
+ $length = 4;
650
+ }
651
+ $this->Nb = $length;
652
+ $this->block_size = $length << 2;
653
+ $this->changed = true;
654
+ }
655
+
656
+ /**
657
+ * Generate CTR XOR encryption key
658
+ *
659
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
660
+ * plaintext / ciphertext in CTR mode.
661
+ *
662
+ * @see Crypt_Rijndael::decrypt()
663
+ * @see Crypt_Rijndael::encrypt()
664
+ * @access public
665
+ * @param Integer $length
666
+ * @param String $iv
667
+ */
668
+ function _generate_xor($length, &$iv)
669
+ {
670
+ $xor = '';
671
+ $block_size = $this->block_size;
672
+ $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
673
+ for ($i = 0; $i < $num_blocks; $i++) {
674
+ $xor.= $iv;
675
+ for ($j = 4; $j <= $block_size; $j+=4) {
676
+ $temp = substr($iv, -$j, 4);
677
+ switch ($temp) {
678
+ case "\xFF\xFF\xFF\xFF":
679
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
680
+ break;
681
+ case "\x7F\xFF\xFF\xFF":
682
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
683
+ break 2;
684
+ default:
685
+ extract(unpack('Ncount', $temp));
686
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
687
+ break 2;
688
+ }
689
+ }
690
+ }
691
+
692
+ return $xor;
693
+ }
694
+
695
+ /**
696
+ * Encrypts a message.
697
+ *
698
+ * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
699
+ * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
700
+ * necessary are discussed in the following
701
+ * URL:
702
+ *
703
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
704
+ *
705
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
706
+ * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
707
+ * length.
708
+ *
709
+ * @see Crypt_Rijndael::decrypt()
710
+ * @access public
711
+ * @param String $plaintext
712
+ */
713
+ function encrypt($plaintext)
714
+ {
715
+ $this->_setup();
716
+ if ($this->paddable) {
717
+ $plaintext = $this->_pad($plaintext);
718
+ }
719
+
720
+ $block_size = $this->block_size;
721
+ $buffer = &$this->enbuffer;
722
+ $continuousBuffer = $this->continuousBuffer;
723
+ $ciphertext = '';
724
+ switch ($this->mode) {
725
+ case CRYPT_RIJNDAEL_MODE_ECB:
726
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
727
+ $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
728
+ }
729
+ break;
730
+ case CRYPT_RIJNDAEL_MODE_CBC:
731
+ $xor = $this->encryptIV;
732
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
733
+ $block = substr($plaintext, $i, $block_size);
734
+ $block = $this->_encryptBlock($block ^ $xor);
735
+ $xor = $block;
736
+ $ciphertext.= $block;
737
+ }
738
+ if ($this->continuousBuffer) {
739
+ $this->encryptIV = $xor;
740
+ }
741
+ break;
742
+ case CRYPT_RIJNDAEL_MODE_CTR:
743
+ $xor = $this->encryptIV;
744
+ if (strlen($buffer['encrypted'])) {
745
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
746
+ $block = substr($plaintext, $i, $block_size);
747
+ $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
748
+ $key = $this->_string_shift($buffer['encrypted'], $block_size);
749
+ $ciphertext.= $block ^ $key;
750
+ }
751
+ } else {
752
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
753
+ $block = substr($plaintext, $i, $block_size);
754
+ $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
755
+ $ciphertext.= $block ^ $key;
756
+ }
757
+ }
758
+ if ($this->continuousBuffer) {
759
+ $this->encryptIV = $xor;
760
+ if ($start = strlen($plaintext) % $block_size) {
761
+ $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
762
+ }
763
+ }
764
+ break;
765
+ case CRYPT_RIJNDAEL_MODE_CFB:
766
+ // cfb loosely routines inspired by openssl's:
767
+ // http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1
768
+ $iv = $this->encryptIV;
769
+ $pos = $this->continuousBuffer === true ? $buffer['pos'] : 0;
770
+ $len = strlen($plaintext);
771
+ $i = 0;
772
+ if ($pos) {
773
+ $orig_pos = $pos;
774
+ $max = $block_size - $pos;
775
+ if ($len >= $max) {
776
+ $i = $max;
777
+ $len-= $max;
778
+ $pos = 0;
779
+ } else {
780
+ $i = $len;
781
+ $pos+= $len;
782
+ $len = 0;
783
+ }
784
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
785
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
786
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
787
+ }
788
+ while ($len >= $block_size) {
789
+ $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
790
+ $ciphertext.= $iv;
791
+ $len-= $block_size;
792
+ $i+= $block_size;
793
+ }
794
+ if ($len) {
795
+ $iv = $this->_encryptBlock($iv);
796
+ //$block = substr($iv, $pos, $len) ^ substr($plaintext, $i, $len);
797
+ $block = substr($iv, $pos) ^ substr($plaintext, $i);
798
+ $iv = substr_replace($iv, $block, $pos, $len);
799
+ $ciphertext.= $block;
800
+ $pos+= $len;
801
+ }
802
+ if($this->continuousBuffer) {
803
+ $this->encryptIV = $iv;
804
+ $buffer['pos'] = $pos;
805
+ }
806
+ break;
807
+ case CRYPT_RIJNDAEL_MODE_OFB:
808
+ $xor = $this->encryptIV;
809
+ if (strlen($buffer['xor'])) {
810
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
811
+ $xor = $this->_encryptBlock($xor);
812
+ $buffer['xor'].= $xor;
813
+ $key = $this->_string_shift($buffer['xor'], $block_size);
814
+ $ciphertext.= substr($plaintext, $i, $block_size) ^ $key;
815
+ }
816
+ } else {
817
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
818
+ $xor = $this->_encryptBlock($xor);
819
+ $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
820
+ }
821
+ $key = $xor;
822
+ }
823
+ if ($this->continuousBuffer) {
824
+ $this->encryptIV = $xor;
825
+ if ($start = strlen($plaintext) % $block_size) {
826
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
827
+ }
828
+ }
829
+ }
830
+
831
+ return $ciphertext;
832
+ }
833
+
834
+ /**
835
+ * Decrypts a message.
836
+ *
837
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
838
+ * it is.
839
+ *
840
+ * @see Crypt_Rijndael::encrypt()
841
+ * @access public
842
+ * @param String $ciphertext
843
+ */
844
+ function decrypt($ciphertext)
845
+ {
846
+ $this->_setup();
847
+
848
+ if ($this->paddable) {
849
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
850
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
851
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
852
+ }
853
+
854
+ $block_size = $this->block_size;
855
+ $buffer = &$this->debuffer;
856
+ $continuousBuffer = $this->continuousBuffer;
857
+ $plaintext = '';
858
+ switch ($this->mode) {
859
+ case CRYPT_RIJNDAEL_MODE_ECB:
860
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
861
+ $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
862
+ }
863
+ break;
864
+ case CRYPT_RIJNDAEL_MODE_CBC:
865
+ $xor = $this->decryptIV;
866
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
867
+ $block = substr($ciphertext, $i, $block_size);
868
+ $plaintext.= $this->_decryptBlock($block) ^ $xor;
869
+ $xor = $block;
870
+ }
871
+ if ($this->continuousBuffer) {
872
+ $this->decryptIV = $xor;
873
+ }
874
+ break;
875
+ case CRYPT_RIJNDAEL_MODE_CTR:
876
+ $xor = $this->decryptIV;
877
+ if (strlen($buffer['ciphertext'])) {
878
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
879
+ $block = substr($ciphertext, $i, $block_size);
880
+ $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
881
+ $key = $this->_string_shift($buffer['ciphertext'], $block_size);
882
+ $plaintext.= $block ^ $key;
883
+ }
884
+ } else {
885
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
886
+ $block = substr($ciphertext, $i, $block_size);
887
+ $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
888
+ $plaintext.= $block ^ $key;
889
+ }
890
+ }
891
+ if ($this->continuousBuffer) {
892
+ $this->decryptIV = $xor;
893
+ if ($start = strlen($ciphertext) % $block_size) {
894
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
895
+ }
896
+ }
897
+ break;
898
+ case CRYPT_RIJNDAEL_MODE_CFB:
899
+ $iv = $this->decryptIV;
900
+ $pos = $this->continuousBuffer === true ? $buffer['pos'] : 0;
901
+ $len = strlen($ciphertext);
902
+ $i = 0;
903
+ if ($pos) {
904
+ $orig_pos = $pos;
905
+ $max = $block_size - $pos;
906
+ if ($len >= $max) {
907
+ $i = $max;
908
+ $len-= $max;
909
+ $pos = 0;
910
+ } else {
911
+ $i = $len;
912
+ $pos+= $len;
913
+ $len = 0;
914
+ }
915
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
916
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
917
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
918
+ }
919
+ while ($len >= $block_size) {
920
+ $iv = $this->_encryptBlock($iv);
921
+ $cb = substr($ciphertext, $i, $block_size);
922
+ $plaintext.= $iv ^ $cb;
923
+ $iv = $cb;
924
+ $len-= $block_size;
925
+ $i+= $block_size;
926
+ }
927
+ if ($len) {
928
+ $iv = $this->_encryptBlock($iv);
929
+ $plaintext.= substr($iv, $pos) ^ substr($ciphertext, $i);
930
+ $iv = substr_replace($iv, substr($ciphertext, $i, $len), $pos, $len);
931
+ $pos+= $len;
932
+ }
933
+ if ($this->continuousBuffer) {
934
+ $this->decryptIV = $iv;
935
+ $buffer['pos'] = $pos;
936
+ }
937
+ break;
938
+ case CRYPT_RIJNDAEL_MODE_OFB:
939
+ $xor = $this->decryptIV;
940
+ if (strlen($buffer['xor'])) {
941
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
942
+ $xor = $this->_encryptBlock($xor);
943
+ $buffer['xor'].= $xor;
944
+ $key = $this->_string_shift($buffer['xor'], $block_size);
945
+ $plaintext.= substr($ciphertext, $i, $block_size) ^ $key;
946
+ }
947
+ } else {
948
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
949
+ $xor = $this->_encryptBlock($xor);
950
+ $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
951
+ }
952
+ $key = $xor;
953
+ }
954
+ if ($this->continuousBuffer) {
955
+ $this->decryptIV = $xor;
956
+ if ($start = strlen($ciphertext) % $block_size) {
957
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
958
+ }
959
+ }
960
+ }
961
+
962
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
963
+ }
964
+
965
+ /**
966
+ * Encrypts a block
967
+ *
968
+ * @access private
969
+ * @param String $in
970
+ * @return String
971
+ */
972
+ function _encryptBlock($in)
973
+ {
974
+ $state = array();
975
+ $words = unpack('N*word', $in);
976
+
977
+ $w = $this->w;
978
+ $t0 = $this->t0;
979
+ $t1 = $this->t1;
980
+ $t2 = $this->t2;
981
+ $t3 = $this->t3;
982
+ $Nb = $this->Nb;
983
+ $Nr = $this->Nr;
984
+ $c = $this->c;
985
+
986
+ // addRoundKey
987
+ $i = 0;
988
+ foreach ($words as $word) {
989
+ $state[] = $word ^ $w[0][$i++];
990
+ }
991
+
992
+ // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
993
+ // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
994
+ // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
995
+ // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
996
+ // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
997
+ // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
998
+
999
+ // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
1000
+ $temp = array();
1001
+ for ($round = 1; $round < $Nr; $round++) {
1002
+ $i = 0; // $c[0] == 0
1003
+ $j = $c[1];
1004
+ $k = $c[2];
1005
+ $l = $c[3];
1006
+
1007
+ while ($i < $this->Nb) {
1008
+ $temp[$i] = $t0[$state[$i] & 0xFF000000] ^
1009
+ $t1[$state[$j] & 0x00FF0000] ^
1010
+ $t2[$state[$k] & 0x0000FF00] ^
1011
+ $t3[$state[$l] & 0x000000FF] ^
1012
+ $w[$round][$i];
1013
+ $i++;
1014
+ $j = ($j + 1) % $Nb;
1015
+ $k = ($k + 1) % $Nb;
1016
+ $l = ($l + 1) % $Nb;
1017
+ }
1018
+
1019
+ for ($i = 0; $i < $Nb; $i++) {
1020
+ $state[$i] = $temp[$i];
1021
+ }
1022
+ }
1023
+
1024
+ // subWord
1025
+ for ($i = 0; $i < $Nb; $i++) {
1026
+ $state[$i] = $this->_subWord($state[$i]);
1027
+ }
1028
+
1029
+ // shiftRows + addRoundKey
1030
+ $i = 0; // $c[0] == 0
1031
+ $j = $c[1];
1032
+ $k = $c[2];
1033
+ $l = $c[3];
1034
+ while ($i < $this->Nb) {
1035
+ $temp[$i] = ($state[$i] & 0xFF000000) ^
1036
+ ($state[$j] & 0x00FF0000) ^
1037
+ ($state[$k] & 0x0000FF00) ^
1038
+ ($state[$l] & 0x000000FF) ^
1039
+ $w[$Nr][$i];
1040
+ $i++;
1041
+ $j = ($j + 1) % $Nb;
1042
+ $k = ($k + 1) % $Nb;
1043
+ $l = ($l + 1) % $Nb;
1044
+ }
1045
+ $state = $temp;
1046
+
1047
+ array_unshift($state, 'N*');
1048
+
1049
+ return call_user_func_array('pack', $state);
1050
+ }
1051
+
1052
+ /**
1053
+ * Decrypts a block
1054
+ *
1055
+ * @access private
1056
+ * @param String $in
1057
+ * @return String
1058
+ */
1059
+ function _decryptBlock($in)
1060
+ {
1061
+ $state = array();
1062
+ $words = unpack('N*word', $in);
1063
+
1064
+ $num_states = count($state);
1065
+ $dw = $this->dw;
1066
+ $dt0 = $this->dt0;
1067
+ $dt1 = $this->dt1;
1068
+ $dt2 = $this->dt2;
1069
+ $dt3 = $this->dt3;
1070
+ $Nb = $this->Nb;
1071
+ $Nr = $this->Nr;
1072
+ $c = $this->c;
1073
+
1074
+ // addRoundKey
1075
+ $i = 0;
1076
+ foreach ($words as $word) {
1077
+ $state[] = $word ^ $dw[$Nr][$i++];
1078
+ }
1079
+
1080
+ $temp = array();
1081
+ for ($round = $Nr - 1; $round > 0; $round--) {
1082
+ $i = 0; // $c[0] == 0
1083
+ $j = $Nb - $c[1];
1084
+ $k = $Nb - $c[2];
1085
+ $l = $Nb - $c[3];
1086
+
1087
+ while ($i < $Nb) {
1088
+ $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
1089
+ $dt1[$state[$j] & 0x00FF0000] ^
1090
+ $dt2[$state[$k] & 0x0000FF00] ^
1091
+ $dt3[$state[$l] & 0x000000FF] ^
1092
+ $dw[$round][$i];
1093
+ $i++;
1094
+ $j = ($j + 1) % $Nb;
1095
+ $k = ($k + 1) % $Nb;
1096
+ $l = ($l + 1) % $Nb;
1097
+ }
1098
+
1099
+ for ($i = 0; $i < $Nb; $i++) {
1100
+ $state[$i] = $temp[$i];
1101
+ }
1102
+ }
1103
+
1104
+ // invShiftRows + invSubWord + addRoundKey
1105
+ $i = 0; // $c[0] == 0
1106
+ $j = $Nb - $c[1];
1107
+ $k = $Nb - $c[2];
1108
+ $l = $Nb - $c[3];
1109
+
1110
+ while ($i < $Nb) {
1111
+ $temp[$i] = $dw[0][$i] ^
1112
+ $this->_invSubWord(($state[$i] & 0xFF000000) |
1113
+ ($state[$j] & 0x00FF0000) |
1114
+ ($state[$k] & 0x0000FF00) |
1115
+ ($state[$l] & 0x000000FF));
1116
+ $i++;
1117
+ $j = ($j + 1) % $Nb;
1118
+ $k = ($k + 1) % $Nb;
1119
+ $l = ($l + 1) % $Nb;
1120
+ }
1121
+
1122
+ $state = $temp;
1123
+
1124
+ array_unshift($state, 'N*');
1125
+
1126
+ return call_user_func_array('pack', $state);
1127
+ }
1128
+
1129
+ /**
1130
+ * Setup Rijndael
1131
+ *
1132
+ * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
1133
+ * key schedule.
1134
+ *
1135
+ * @access private
1136
+ */
1137
+ function _setup()
1138
+ {
1139
+ // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
1140
+ // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
1141
+ static $rcon = array(0,
1142
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
1143
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
1144
+ 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
1145
+ 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
1146
+ 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
1147
+ 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
1148
+ );
1149
+
1150
+ if (!$this->changed) {
1151
+ return;
1152
+ }
1153
+
1154
+ if (!$this->explicit_key_length) {
1155
+ // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
1156
+ $length = strlen($this->key) >> 2;
1157
+ if ($length > 8) {
1158
+ $length = 8;
1159
+ } else if ($length < 4) {
1160
+ $length = 4;
1161
+ }
1162
+ $this->Nk = $length;
1163
+ $this->key_size = $length << 2;
1164
+ }
1165
+
1166
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
1167
+ $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
1168
+
1169
+ // see Rijndael-ammended.pdf#page=44
1170
+ $this->Nr = max($this->Nk, $this->Nb) + 6;
1171
+
1172
+ // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
1173
+ // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
1174
+ // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
1175
+ // "Table 2: Shift offsets for different block lengths"
1176
+ switch ($this->Nb) {
1177
+ case 4:
1178
+ case 5:
1179
+ case 6:
1180
+ $this->c = array(0, 1, 2, 3);
1181
+ break;
1182
+ case 7:
1183
+ $this->c = array(0, 1, 2, 4);
1184
+ break;
1185
+ case 8:
1186
+ $this->c = array(0, 1, 3, 4);
1187
+ }
1188
+
1189
+ $key = $this->key;
1190
+
1191
+ $w = array_values(unpack('N*words', $key));
1192
+
1193
+ $length = $this->Nb * ($this->Nr + 1);
1194
+ for ($i = $this->Nk; $i < $length; $i++) {
1195
+ $temp = $w[$i - 1];
1196
+ if ($i % $this->Nk == 0) {
1197
+ // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
1198
+ // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
1199
+ // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
1200
+ // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
1201
+ $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
1202
+ $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
1203
+ } else if ($this->Nk > 6 && $i % $this->Nk == 4) {
1204
+ $temp = $this->_subWord($temp);
1205
+ }
1206
+ $w[$i] = $w[$i - $this->Nk] ^ $temp;
1207
+ }
1208
+
1209
+ // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
1210
+ // and generate the inverse key schedule. more specifically,
1211
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
1212
+ // "The key expansion for the Inverse Cipher is defined as follows:
1213
+ // 1. Apply the Key Expansion.
1214
+ // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
1215
+ // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
1216
+ $temp = array();
1217
+ for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
1218
+ if ($col == $this->Nb) {
1219
+ if ($row == 0) {
1220
+ $this->dw[0] = $this->w[0];
1221
+ } else {
1222
+ // subWord + invMixColumn + invSubWord = invMixColumn
1223
+ $j = 0;
1224
+ while ($j < $this->Nb) {
1225
+ $dw = $this->_subWord($this->w[$row][$j]);
1226
+ $temp[$j] = $this->dt0[$dw & 0xFF000000] ^
1227
+ $this->dt1[$dw & 0x00FF0000] ^
1228
+ $this->dt2[$dw & 0x0000FF00] ^
1229
+ $this->dt3[$dw & 0x000000FF];
1230
+ $j++;
1231
+ }
1232
+ $this->dw[$row] = $temp;
1233
+ }
1234
+
1235
+ $col = 0;
1236
+ $row++;
1237
+ }
1238
+ $this->w[$row][$col] = $w[$i];
1239
+ }
1240
+
1241
+ $this->dw[$row] = $this->w[$row];
1242
+
1243
+ $this->changed = false;
1244
+ }
1245
+
1246
+ /**
1247
+ * Performs S-Box substitutions
1248
+ *
1249
+ * @access private
1250
+ */
1251
+ function _subWord($word)
1252
+ {
1253
+ static $sbox0, $sbox1, $sbox2, $sbox3;
1254
+
1255
+ if (empty($sbox0)) {
1256
+ $sbox0 = array(
1257
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
1258
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
1259
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
1260
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
1261
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
1262
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
1263
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
1264
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
1265
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
1266
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
1267
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
1268
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
1269
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
1270
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
1271
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
1272
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
1273
+ );
1274
+
1275
+ $sbox1 = array();
1276
+ $sbox2 = array();
1277
+ $sbox3 = array();
1278
+
1279
+ for ($i = 0; $i < 256; $i++) {
1280
+ $sbox1[$i << 8] = $sbox0[$i] << 8;
1281
+ $sbox2[$i << 16] = $sbox0[$i] << 16;
1282
+ $sbox3[$i << 24] = $sbox0[$i] << 24;
1283
+ }
1284
+ }
1285
+
1286
+ return $sbox0[$word & 0x000000FF] |
1287
+ $sbox1[$word & 0x0000FF00] |
1288
+ $sbox2[$word & 0x00FF0000] |
1289
+ $sbox3[$word & 0xFF000000];
1290
+ }
1291
+
1292
+ /**
1293
+ * Performs inverse S-Box substitutions
1294
+ *
1295
+ * @access private
1296
+ */
1297
+ function _invSubWord($word)
1298
+ {
1299
+ static $sbox0, $sbox1, $sbox2, $sbox3;
1300
+
1301
+ if (empty($sbox0)) {
1302
+ $sbox0 = array(
1303
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
1304
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
1305
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
1306
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
1307
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
1308
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
1309
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
1310
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
1311
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
1312
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
1313
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
1314
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
1315
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
1316
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1317
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1318
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1319
+ );
1320
+
1321
+ $sbox1 = array();
1322
+ $sbox2 = array();
1323
+ $sbox3 = array();
1324
+
1325
+ for ($i = 0; $i < 256; $i++) {
1326
+ $sbox1[$i << 8] = $sbox0[$i] << 8;
1327
+ $sbox2[$i << 16] = $sbox0[$i] << 16;
1328
+ $sbox3[$i << 24] = $sbox0[$i] << 24;
1329
+ }
1330
+ }
1331
+
1332
+ return $sbox0[$word & 0x000000FF] |
1333
+ $sbox1[$word & 0x0000FF00] |
1334
+ $sbox2[$word & 0x00FF0000] |
1335
+ $sbox3[$word & 0xFF000000];
1336
+ }
1337
+
1338
+ /**
1339
+ * Pad "packets".
1340
+ *
1341
+ * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
1342
+ * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1343
+ * pad the input so that it is of the proper length.
1344
+ *
1345
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1346
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1347
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1348
+ * transmitted separately)
1349
+ *
1350
+ * @see Crypt_Rijndael::disablePadding()
1351
+ * @access public
1352
+ */
1353
+ function enablePadding()
1354
+ {
1355
+ $this->padding = true;
1356
+ }
1357
+
1358
+ /**
1359
+ * Do not pad packets.
1360
+ *
1361
+ * @see Crypt_Rijndael::enablePadding()
1362
+ * @access public
1363
+ */
1364
+ function disablePadding()
1365
+ {
1366
+ $this->padding = false;
1367
+ }
1368
+
1369
+ /**
1370
+ * Pads a string
1371
+ *
1372
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1373
+ * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
1374
+ * chr($block_size - (strlen($text) % $block_size)
1375
+ *
1376
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1377
+ * and padding will, hence forth, be enabled.
1378
+ *
1379
+ * @see Crypt_Rijndael::_unpad()
1380
+ * @access private
1381
+ */
1382
+ function _pad($text)
1383
+ {
1384
+ $length = strlen($text);
1385
+
1386
+ if (!$this->padding) {
1387
+ if ($length % $this->block_size == 0) {
1388
+ return $text;
1389
+ } else {
1390
+ user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1391
+ $this->padding = true;
1392
+ }
1393
+ }
1394
+
1395
+ $pad = $this->block_size - ($length % $this->block_size);
1396
+
1397
+ return str_pad($text, $length + $pad, chr($pad));
1398
+ }
1399
+
1400
+ /**
1401
+ * Unpads a string.
1402
+ *
1403
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1404
+ * and false will be returned.
1405
+ *
1406
+ * @see Crypt_Rijndael::_pad()
1407
+ * @access private
1408
+ */
1409
+ function _unpad($text)
1410
+ {
1411
+ if (!$this->padding) {
1412
+ return $text;
1413
+ }
1414
+
1415
+ $length = ord($text[strlen($text) - 1]);
1416
+
1417
+ if (!$length || $length > $this->block_size) {
1418
+ return false;
1419
+ }
1420
+
1421
+ return substr($text, 0, -$length);
1422
+ }
1423
+
1424
+ /**
1425
+ * Treat consecutive "packets" as if they are a continuous buffer.
1426
+ *
1427
+ * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1428
+ * will yield different outputs:
1429
+ *
1430
+ * <code>
1431
+ * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1432
+ * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1433
+ * </code>
1434
+ * <code>
1435
+ * echo $rijndael->encrypt($plaintext);
1436
+ * </code>
1437
+ *
1438
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1439
+ * another, as demonstrated with the following:
1440
+ *
1441
+ * <code>
1442
+ * $rijndael->encrypt(substr($plaintext, 0, 16));
1443
+ * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1444
+ * </code>
1445
+ * <code>
1446
+ * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1447
+ * </code>
1448
+ *
1449
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1450
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1451
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1452
+ *
1453
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
1454
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1455
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1456
+ * however, they are also less intuitive and more likely to cause you problems.
1457
+ *
1458
+ * @see Crypt_Rijndael::disableContinuousBuffer()
1459
+ * @access public
1460
+ */
1461
+ function enableContinuousBuffer()
1462
+ {
1463
+ $this->continuousBuffer = true;
1464
+ }
1465
+
1466
+ /**
1467
+ * Treat consecutive packets as if they are a discontinuous buffer.
1468
+ *
1469
+ * The default behavior.
1470
+ *
1471
+ * @see Crypt_Rijndael::enableContinuousBuffer()
1472
+ * @access public
1473
+ */
1474
+ function disableContinuousBuffer()
1475
+ {
1476
+ $this->continuousBuffer = false;
1477
+ $this->encryptIV = $this->iv;
1478
+ $this->decryptIV = $this->iv;
1479
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
1480
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
1481
+ }
1482
+
1483
+ /**
1484
+ * String Shift
1485
+ *
1486
+ * Inspired by array_shift
1487
+ *
1488
+ * @param String $string
1489
+ * @param optional Integer $index
1490
+ * @return String
1491
+ * @access private
1492
+ */
1493
+ function _string_shift(&$string, $index = 1)
1494
+ {
1495
+ $substr = substr($string, 0, $index);
1496
+ $string = substr($string, $index);
1497
+ return $substr;
1498
+ }
1499
+ }
1500
+
1501
+ // vim: ts=4:sw=4:et:
1502
  // vim6: fdl=1:
phpseclib/Crypt/TripleDES.php CHANGED
@@ -57,7 +57,9 @@
57
  /**
58
  * Include Crypt_DES
59
  */
60
- require_once('DES.php');
 
 
61
 
62
  /**
63
  * Encrypt / decrypt using inner chaining
@@ -248,10 +250,7 @@ class Crypt_TripleDES {
248
  {
249
  if ( !defined('CRYPT_DES_MODE') ) {
250
  switch (true) {
251
- case extension_loaded('mcrypt'):
252
- // i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
253
- // but since that can be changed after the object has been created, there doesn't seem to be
254
- // a lot of point...
255
  define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
256
  break;
257
  default:
@@ -266,6 +265,7 @@ class Crypt_TripleDES {
266
  new Crypt_DES(CRYPT_DES_MODE_CBC),
267
  new Crypt_DES(CRYPT_DES_MODE_CBC)
268
  );
 
269
 
270
  // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
271
  $this->des[0]->disablePadding();
@@ -617,7 +617,7 @@ class Crypt_TripleDES {
617
  }
618
  break;
619
  case CRYPT_DES_MODE_CFB:
620
- if (!empty($buffer['xor'])) {
621
  $ciphertext = $plaintext ^ $buffer['xor'];
622
  $iv = $buffer['encrypted'] . $ciphertext;
623
  $start = strlen($ciphertext);
@@ -822,17 +822,19 @@ class Crypt_TripleDES {
822
  }
823
  break;
824
  case CRYPT_DES_MODE_CFB:
825
- if (!empty($buffer['ciphertext'])) {
826
  $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
827
  $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
828
- if (strlen($buffer['ciphertext']) == 8) {
 
 
 
829
  $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
830
  $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
831
  $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
832
  $buffer['ciphertext'] = '';
833
  }
834
  $start = strlen($plaintext);
835
- $block = $this->decryptIV;
836
  } else {
837
  $plaintext = '';
838
  $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
@@ -1058,4 +1060,4 @@ class Crypt_TripleDES {
1058
  }
1059
 
1060
  // vim: ts=4:sw=4:et:
1061
- // vim6: fdl=1:
57
  /**
58
  * Include Crypt_DES
59
  */
60
+ if (!class_exists('Crypt_DES')) {
61
+ require_once('DES.php');
62
+ }
63
 
64
  /**
65
  * Encrypt / decrypt using inner chaining
250
  {
251
  if ( !defined('CRYPT_DES_MODE') ) {
252
  switch (true) {
253
+ case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()):
 
 
 
254
  define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
255
  break;
256
  default:
265
  new Crypt_DES(CRYPT_DES_MODE_CBC),
266
  new Crypt_DES(CRYPT_DES_MODE_CBC)
267
  );
268
+ $this->paddable = true;
269
 
270
  // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
271
  $this->des[0]->disablePadding();
617
  }
618
  break;
619
  case CRYPT_DES_MODE_CFB:
620
+ if (strlen($buffer['xor'])) {
621
  $ciphertext = $plaintext ^ $buffer['xor'];
622
  $iv = $buffer['encrypted'] . $ciphertext;
623
  $start = strlen($ciphertext);
822
  }
823
  break;
824
  case CRYPT_DES_MODE_CFB:
825
+ if (strlen($buffer['ciphertext'])) {
826
  $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
827
  $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
828
+ if (strlen($buffer['ciphertext']) != 8) {
829
+ $block = $this->decryptIV;
830
+ } else {
831
+ $block = $buffer['ciphertext'];
832
  $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
833
  $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
834
  $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
835
  $buffer['ciphertext'] = '';
836
  }
837
  $start = strlen($plaintext);
 
838
  } else {
839
  $plaintext = '';
840
  $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
1060
  }
1061
 
1062
  // vim: ts=4:sw=4:et:
1063
+ // vim6: fdl=1:
phpseclib/Math/BigInteger.php CHANGED
@@ -282,6 +282,10 @@ class Math_BigInteger {
282
  }
283
  }
284
 
 
 
 
 
285
  switch ( MATH_BIGINTEGER_MODE ) {
286
  case MATH_BIGINTEGER_MODE_GMP:
287
  if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
@@ -297,7 +301,9 @@ class Math_BigInteger {
297
  $this->value = array();
298
  }
299
 
300
- if (empty($x)) {
 
 
301
  return;
302
  }
303
 
@@ -599,13 +605,19 @@ class Math_BigInteger {
599
  {
600
  $hex = $this->toHex($twos_compliment);
601
  $bits = '';
602
- for ($i = 0, $end = strlen($hex) & 0xFFFFFFF8; $i < $end; $i+=8) {
603
- $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT);
604
  }
605
- if ($end != strlen($hex)) { // hexdec('') == 0
606
- $bits.= str_pad(decbin(hexdec(substr($hex, $end))), strlen($hex) & 7, '0', STR_PAD_LEFT);
 
 
 
 
 
607
  }
608
- return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
 
609
  }
610
 
611
  /**
@@ -1589,13 +1601,54 @@ class Math_BigInteger {
1589
  return $this->_normalize($temp->modPow($e, $n));
1590
  }
1591
 
1592
- switch ( MATH_BIGINTEGER_MODE ) {
1593
- case MATH_BIGINTEGER_MODE_GMP:
1594
- $temp = new Math_BigInteger();
1595
- $temp->value = gmp_powm($this->value, $e->value, $n->value);
1596
 
1597
- return $this->_normalize($temp);
1598
- case MATH_BIGINTEGER_MODE_BCMATH:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1599
  $temp = new Math_BigInteger();
1600
  $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1601
 
@@ -2942,20 +2995,13 @@ class Math_BigInteger {
2942
  /**
2943
  * Set random number generator function
2944
  *
2945
- * $generator should be the name of a random generating function whose first parameter is the minimum
2946
- * value and whose second parameter is the maximum value. If this function needs to be seeded, it should
2947
- * be seeded prior to calling Math_BigInteger::random() or Math_BigInteger::randomPrime()
2948
- *
2949
- * If the random generating function is not explicitly set, it'll be assumed to be mt_rand().
2950
  *
2951
- * @see random()
2952
- * @see randomPrime()
2953
- * @param optional String $generator
2954
  * @access public
2955
  */
2956
  function setRandomGenerator($generator)
2957
  {
2958
- $this->generator = $generator;
2959
  }
2960
 
2961
  /**
@@ -2992,27 +3038,43 @@ class Math_BigInteger {
2992
  $max = $max->subtract($min);
2993
  $max = ltrim($max->toBytes(), chr(0));
2994
  $size = strlen($max) - 1;
2995
- $random = '';
2996
 
2997
- $bytes = $size & 1;
2998
- for ($i = 0; $i < $bytes; ++$i) {
2999
- $random.= chr($generator(0, 255));
3000
- }
 
 
 
 
 
3001
 
3002
- $blocks = $size >> 1;
3003
- for ($i = 0; $i < $blocks; ++$i) {
3004
- // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3005
- $random.= pack('n', $generator(0, 0xFFFF));
 
3006
  }
3007
 
3008
- $temp = new Math_BigInteger($random, 256);
3009
- if ($temp->compare(new Math_BigInteger(substr($max, 1), 256)) > 0) {
3010
- $random = chr($generator(0, ord($max[0]) - 1)) . $random;
 
 
 
3011
  } else {
3012
- $random = chr($generator(0, ord($max[0]) )) . $random;
 
 
 
 
 
 
 
 
3013
  }
3014
 
3015
- $random = new Math_BigInteger($random, 256);
3016
 
3017
  return $this->_normalize($random->add($min));
3018
  }
@@ -3548,4 +3610,24 @@ class Math_BigInteger {
3548
  $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3549
  return $temp['int'];
3550
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3551
  }
282
  }
283
  }
284
 
285
+ if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
286
+ define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
287
+ }
288
+
289
  switch ( MATH_BIGINTEGER_MODE ) {
290
  case MATH_BIGINTEGER_MODE_GMP:
291
  if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
301
  $this->value = array();
302
  }
303
 
304
+ // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
305
+ // '0' is the only value like this per http://php.net/empty
306
+ if (empty($x) && (abs($base) != 256 || $x !== '0')) {
307
  return;
308
  }
309
 
605
  {
606
  $hex = $this->toHex($twos_compliment);
607
  $bits = '';
608
+ for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
609
+ $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
610
  }
611
+ if ($start) { // hexdec('') == 0
612
+ $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
613
+ }
614
+ $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
615
+
616
+ if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
617
+ return '0' . $result;
618
  }
619
+
620
+ return $result;
621
  }
622
 
623
  /**
1601
  return $this->_normalize($temp->modPow($e, $n));
1602
  }
1603
 
1604
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
1605
+ $temp = new Math_BigInteger();
1606
+ $temp->value = gmp_powm($this->value, $e->value, $n->value);
 
1607
 
1608
+ return $this->_normalize($temp);
1609
+ }
1610
+
1611
+ if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
1612
+ list(, $temp) = $this->divide($n);
1613
+ return $temp->modPow($e, $n);
1614
+ }
1615
+
1616
+ if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1617
+ $components = array(
1618
+ 'modulus' => $n->toBytes(true),
1619
+ 'publicExponent' => $e->toBytes(true)
1620
+ );
1621
+
1622
+ $components = array(
1623
+ 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1624
+ 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1625
+ );
1626
+
1627
+ $RSAPublicKey = pack('Ca*a*a*',
1628
+ 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1629
+ $components['modulus'], $components['publicExponent']
1630
+ );
1631
+
1632
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1633
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
1634
+ $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1635
+
1636
+ $encapsulated = pack('Ca*a*',
1637
+ 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
1638
+ );
1639
+
1640
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1641
+ chunk_split(base64_encode($encapsulated)) .
1642
+ '-----END PUBLIC KEY-----';
1643
+
1644
+ $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1645
+
1646
+ if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1647
+ return new Math_BigInteger($result, 256);
1648
+ }
1649
+ }
1650
+
1651
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
1652
  $temp = new Math_BigInteger();
1653
  $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1654
 
2995
  /**
2996
  * Set random number generator function
2997
  *
2998
+ * This function is deprecated.
 
 
 
 
2999
  *
3000
+ * @param String $generator
 
 
3001
  * @access public
3002
  */
3003
  function setRandomGenerator($generator)
3004
  {
 
3005
  }
3006
 
3007
  /**
3038
  $max = $max->subtract($min);
3039
  $max = ltrim($max->toBytes(), chr(0));
3040
  $size = strlen($max) - 1;
 
3041
 
3042
+ $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string'));
3043
+ if ($crypt_random) {
3044
+ $random = crypt_random_string($size);
3045
+ } else {
3046
+ $random = '';
3047
+
3048
+ if ($size & 1) {
3049
+ $random.= chr(mt_rand(0, 255));
3050
+ }
3051
 
3052
+ $blocks = $size >> 1;
3053
+ for ($i = 0; $i < $blocks; ++$i) {
3054
+ // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3055
+ $random.= pack('n', mt_rand(0, 0xFFFF));
3056
+ }
3057
  }
3058
 
3059
+ $fragment = new Math_BigInteger($random, 256);
3060
+ $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ?
3061
+ ord($max[0]) - 1 : ord($max[0]);
3062
+
3063
+ if (!$crypt_random) {
3064
+ $msb = chr(mt_rand(0, $leading));
3065
  } else {
3066
+ $cutoff = floor(0xFF / $leading) * $leading;
3067
+ while (true) {
3068
+ $msb = ord(crypt_random_string(1));
3069
+ if ($msb <= $cutoff) {
3070
+ $msb%= $leading;
3071
+ break;
3072
+ }
3073
+ }
3074
+ $msb = chr($msb);
3075
  }
3076
 
3077
+ $random = new Math_BigInteger($msb . $random, 256);
3078
 
3079
  return $this->_normalize($random->add($min));
3080
  }
3610
  $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3611
  return $temp['int'];
3612
  }
3613
+
3614
+ /**
3615
+ * DER-encode an integer
3616
+ *
3617
+ * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3618
+ *
3619
+ * @see modPow()
3620
+ * @access private
3621
+ * @param Integer $length
3622
+ * @return String
3623
+ */
3624
+ function _encodeASN1Length($length)
3625
+ {
3626
+ if ($length <= 0x7F) {
3627
+ return chr($length);
3628
+ }
3629
+
3630
+ $temp = ltrim(pack('N', $length), chr(0));
3631
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
3632
+ }
3633
  }
phpseclib/Net/SFTP.php CHANGED
@@ -6,7 +6,7 @@
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
  *
@@ -57,7 +57,9 @@
57
  /**
58
  * Include Net_SSH2
59
  */
60
- require_once('Net/SSH2.php');
 
 
61
 
62
  /**#@+
63
  * @access public
@@ -397,7 +399,7 @@ class Net_SFTP extends Net_SSH2 {
397
 
398
  $response = $this->_get_sftp_packet();
399
  if ($this->packet_type != NET_SFTP_VERSION) {
400
- user_error('Expected SSH_FXP_VERSION', E_USER_NOTICE);
401
  return false;
402
  }
403
 
@@ -450,8 +452,12 @@ class Net_SFTP extends Net_SSH2 {
450
  in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
451
  channel and reopen it with a new and updated SSH_FXP_INIT packet.
452
  */
453
- if ($this->version != 3) {
454
- return false;
 
 
 
 
455
  }
456
 
457
  $this->pwd = $this->_realpath('.', false);
@@ -472,16 +478,36 @@ class Net_SFTP extends Net_SSH2 {
472
  return $this->pwd;
473
  }
474
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  /**
476
  * Canonicalize the Server-Side Path Name
477
  *
478
  * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
479
- * the absolute (canonicalized) path. If $mode is set to NET_SFTP_CONFIRM_DIR (as opposed to NET_SFTP_CONFIRM_NONE,
480
- * which is what it is set to by default), false is returned if $dir is not a valid directory.
481
  *
482
  * @see Net_SFTP::chdir()
483
  * @param String $dir
484
- * @param optional Integer $mode
485
  * @return Mixed
486
  * @access private
487
  */
@@ -516,7 +542,11 @@ class Net_SFTP extends Net_SSH2 {
516
  $dir = $dir[0] == '/' ? '/' . rtrim(substr($dir, 1), '/') : rtrim($dir, '/');
517
 
518
  if ($dir == '.' || $dir == $this->pwd) {
519
- return $this->pwd . $file;
 
 
 
 
520
  }
521
 
522
  if ($dir[0] != '/') {
@@ -555,17 +585,20 @@ class Net_SFTP extends Net_SSH2 {
555
  $this->fileType = $this->_parseLongname($this->_string_shift($response, $length));
556
  break;
557
  case NET_SFTP_STATUS:
558
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
559
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
560
  return false;
561
  default:
562
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE);
563
  return false;
564
  }
565
 
566
  // if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to
567
  // be a bonafide directory
568
- return $realpath . '/' . $file;
 
 
 
 
569
  }
570
 
571
  /**
@@ -609,11 +642,10 @@ class Net_SFTP extends Net_SSH2 {
609
  $handle = substr($response, 4);
610
  break;
611
  case NET_SFTP_STATUS:
612
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
613
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
614
  return false;
615
  default:
616
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
617
  return false;
618
  }
619
 
@@ -623,14 +655,13 @@ class Net_SFTP extends Net_SSH2 {
623
 
624
  $response = $this->_get_sftp_packet();
625
  if ($this->packet_type != NET_SFTP_STATUS) {
626
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
627
  return false;
628
  }
629
 
630
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
631
  if ($status != NET_SFTP_STATUS_OK) {
632
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
633
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
634
  return false;
635
  }
636
 
@@ -667,7 +698,12 @@ class Net_SFTP extends Net_SSH2 {
667
  /**
668
  * Reads a list, be it detailed or not, of files in the given directory
669
  *
670
- * @param optional String $dir
 
 
 
 
 
671
  * @return Mixed
672
  * @access private
673
  */
@@ -697,11 +733,10 @@ class Net_SFTP extends Net_SSH2 {
697
  break;
698
  case NET_SFTP_STATUS:
699
  // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
700
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
701
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
702
  return false;
703
  default:
704
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
705
  return false;
706
  }
707
 
@@ -745,13 +780,12 @@ class Net_SFTP extends Net_SSH2 {
745
  case NET_SFTP_STATUS:
746
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
747
  if ($status != NET_SFTP_STATUS_EOF) {
748
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
749
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
750
  return false;
751
  }
752
  break 2;
753
  default:
754
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE);
755
  return false;
756
  }
757
  }
@@ -764,14 +798,13 @@ class Net_SFTP extends Net_SSH2 {
764
  // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
765
  $response = $this->_get_sftp_packet();
766
  if ($this->packet_type != NET_SFTP_STATUS) {
767
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
768
  return false;
769
  }
770
 
771
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
772
  if ($status != NET_SFTP_STATUS_OK) {
773
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
774
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
775
  return false;
776
  }
777
 
@@ -835,11 +868,12 @@ class Net_SFTP extends Net_SSH2 {
835
  foreach ($dirs as $dir) {
836
  if ($dir == end($dirs)) {
837
  unset($temp[$dir]);
838
- break;
839
  }
840
- if (isset($new[$key])) {
841
- $temp = &$temp[$dir];
842
  }
 
843
  }
844
  }
845
 
@@ -883,6 +917,9 @@ class Net_SFTP extends Net_SSH2 {
883
  }
884
 
885
  $stat = $this->_stat($filename, NET_SFTP_STAT);
 
 
 
886
 
887
  $pwd = $this->pwd;
888
  $stat['type'] = $this->chdir($filename) ?
@@ -915,6 +952,9 @@ class Net_SFTP extends Net_SSH2 {
915
 
916
  $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
917
  $stat = $this->_stat($filename, NET_SFTP_STAT);
 
 
 
918
 
919
  if ($lstat != $stat) {
920
  return array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
@@ -957,12 +997,11 @@ class Net_SFTP extends Net_SSH2 {
957
  }
958
  return $attributes;
959
  case NET_SFTP_STATUS:
960
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
961
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
962
  return false;
963
  }
964
 
965
- user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
966
  return false;
967
  }
968
 
@@ -1055,14 +1094,13 @@ class Net_SFTP extends Net_SSH2 {
1055
  */
1056
  $response = $this->_get_sftp_packet();
1057
  if ($this->packet_type != NET_SFTP_STATUS) {
1058
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1059
  return false;
1060
  }
1061
 
1062
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1063
  if ($status != NET_SFTP_STATUS_OK) {
1064
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1065
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1066
  }
1067
 
1068
  // rather than return what the permissions *should* be, we'll return what they actually are. this will also
@@ -1079,12 +1117,11 @@ class Net_SFTP extends Net_SSH2 {
1079
  $attrs = $this->_parseAttributes($response);
1080
  return $attrs['permissions'];
1081
  case NET_SFTP_STATUS:
1082
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1083
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1084
  return false;
1085
  }
1086
 
1087
- user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
1088
  return false;
1089
  }
1090
 
@@ -1110,7 +1147,11 @@ class Net_SFTP extends Net_SSH2 {
1110
  return $this->chmod($mode, $path);
1111
  }
1112
 
1113
- // presumably $entries will never be empty because it'll always have . and ..
 
 
 
 
1114
 
1115
  foreach ($entries as $filename=>$props) {
1116
  if ($filename == '.' || $filename == '..') {
@@ -1173,11 +1214,38 @@ class Net_SFTP extends Net_SSH2 {
1173
  return false;
1174
  }
1175
 
1176
- $dir = $this->_realpath(rtrim($dir, '/'));
1177
- if ($dir === false) {
1178
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1179
  }
1180
 
 
 
 
 
 
 
 
 
 
 
 
 
1181
  // by not providing any permissions, hopefully the server will use the logged in users umask - their
1182
  // default permissions.
1183
  if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*N', strlen($dir), $dir, 0))) {
@@ -1186,14 +1254,13 @@ class Net_SFTP extends Net_SSH2 {
1186
 
1187
  $response = $this->_get_sftp_packet();
1188
  if ($this->packet_type != NET_SFTP_STATUS) {
1189
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1190
  return false;
1191
  }
1192
 
1193
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1194
  if ($status != NET_SFTP_STATUS_OK) {
1195
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1196
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1197
  return false;
1198
  }
1199
 
@@ -1226,15 +1293,14 @@ class Net_SFTP extends Net_SSH2 {
1226
 
1227
  $response = $this->_get_sftp_packet();
1228
  if ($this->packet_type != NET_SFTP_STATUS) {
1229
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1230
  return false;
1231
  }
1232
 
1233
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1234
  if ($status != NET_SFTP_STATUS_OK) {
1235
  // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
1236
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1237
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1238
  return false;
1239
  }
1240
 
@@ -1301,11 +1367,10 @@ class Net_SFTP extends Net_SSH2 {
1301
  $handle = substr($response, 4);
1302
  break;
1303
  case NET_SFTP_STATUS:
1304
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1305
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1306
  return false;
1307
  default:
1308
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
1309
  return false;
1310
  }
1311
 
@@ -1314,7 +1379,7 @@ class Net_SFTP extends Net_SSH2 {
1314
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
1315
  if ($mode & NET_SFTP_LOCAL_FILE) {
1316
  if (!is_file($data)) {
1317
- user_error("$data is not a valid file", E_USER_NOTICE);
1318
  return false;
1319
  }
1320
  $fp = @fopen($data, 'rb');
@@ -1351,7 +1416,9 @@ class Net_SFTP extends Net_SSH2 {
1351
  }
1352
  }
1353
 
1354
- $this->_read_put_responses($i);
 
 
1355
 
1356
  if ($mode & NET_SFTP_LOCAL_FILE) {
1357
  fclose($fp);
@@ -1363,14 +1430,13 @@ class Net_SFTP extends Net_SSH2 {
1363
 
1364
  $response = $this->_get_sftp_packet();
1365
  if ($this->packet_type != NET_SFTP_STATUS) {
1366
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1367
  return false;
1368
  }
1369
 
1370
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1371
  if ($status != NET_SFTP_STATUS_OK) {
1372
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1373
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1374
  return false;
1375
  }
1376
 
@@ -1392,14 +1458,13 @@ class Net_SFTP extends Net_SSH2 {
1392
  while ($i--) {
1393
  $response = $this->_get_sftp_packet();
1394
  if ($this->packet_type != NET_SFTP_STATUS) {
1395
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1396
  return false;
1397
  }
1398
 
1399
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1400
  if ($status != NET_SFTP_STATUS_OK) {
1401
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1402
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1403
  break;
1404
  }
1405
  }
@@ -1419,7 +1484,7 @@ class Net_SFTP extends Net_SSH2 {
1419
  * @return Mixed
1420
  * @access public
1421
  */
1422
- function get($remote_file, $local_file = false)
1423
  {
1424
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1425
  return false;
@@ -1441,11 +1506,10 @@ class Net_SFTP extends Net_SSH2 {
1441
  $handle = substr($response, 4);
1442
  break;
1443
  case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1444
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1445
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1446
  return false;
1447
  default:
1448
- user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
1449
  return false;
1450
  }
1451
 
@@ -1458,9 +1522,10 @@ class Net_SFTP extends Net_SSH2 {
1458
  $content = '';
1459
  }
1460
 
1461
- $read = 0;
 
1462
  while (true) {
1463
- $packet = pack('Na*N3', strlen($handle), $handle, 0, $read, 1 << 20);
1464
  if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
1465
  if ($local_file !== false) {
1466
  fclose($fp);
@@ -1472,7 +1537,7 @@ class Net_SFTP extends Net_SSH2 {
1472
  switch ($this->packet_type) {
1473
  case NET_SFTP_DATA:
1474
  $temp = substr($response, 4);
1475
- $read+= strlen($temp);
1476
  if ($local_file === false) {
1477
  $content.= $temp;
1478
  } else {
@@ -1480,16 +1545,24 @@ class Net_SFTP extends Net_SSH2 {
1480
  }
1481
  break;
1482
  case NET_SFTP_STATUS:
1483
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1484
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1485
  break 2;
1486
  default:
1487
- user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS', E_USER_NOTICE);
1488
  if ($local_file !== false) {
1489
  fclose($fp);
1490
  }
1491
  return false;
1492
  }
 
 
 
 
 
 
 
 
 
1493
  }
1494
 
1495
  if ($local_file !== false) {
@@ -1502,15 +1575,13 @@ class Net_SFTP extends Net_SSH2 {
1502
 
1503
  $response = $this->_get_sftp_packet();
1504
  if ($this->packet_type != NET_SFTP_STATUS) {
1505
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1506
  return false;
1507
  }
1508
 
1509
- extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
1510
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1511
-
1512
- // check the status from the NET_SFTP_STATUS case in the above switch after the file has been closed
1513
  if ($status != NET_SFTP_STATUS_OK) {
 
1514
  return false;
1515
  }
1516
 
@@ -1547,15 +1618,14 @@ class Net_SFTP extends Net_SSH2 {
1547
 
1548
  $response = $this->_get_sftp_packet();
1549
  if ($this->packet_type != NET_SFTP_STATUS) {
1550
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1551
  return false;
1552
  }
1553
 
1554
  // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1555
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1556
  if ($status != NET_SFTP_STATUS_OK) {
1557
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1558
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1559
  if (!$recursive) {
1560
  return false;
1561
  }
@@ -1586,7 +1656,11 @@ class Net_SFTP extends Net_SSH2 {
1586
  $i = 0;
1587
  $entries = $this->_list($path, true, false);
1588
 
1589
- // presumably $entries will never be empty because it'll always have . and ..
 
 
 
 
1590
 
1591
  foreach ($entries as $filename=>$props) {
1592
  if ($filename == '.' || $filename == '..') {
@@ -1621,6 +1695,7 @@ class Net_SFTP extends Net_SSH2 {
1621
  if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
1622
  return false;
1623
  }
 
1624
 
1625
  $i++;
1626
 
@@ -1662,15 +1737,14 @@ class Net_SFTP extends Net_SSH2 {
1662
 
1663
  $response = $this->_get_sftp_packet();
1664
  if ($this->packet_type != NET_SFTP_STATUS) {
1665
- user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
1666
  return false;
1667
  }
1668
 
1669
  // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1670
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1671
  if ($status != NET_SFTP_STATUS_OK) {
1672
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
1673
- $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
1674
  return false;
1675
  }
1676
 
@@ -1721,7 +1795,7 @@ class Net_SFTP extends Net_SSH2 {
1721
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
1722
  $key = $this->_string_shift($response, $length);
1723
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
1724
- $attr[$key] = $this->_string_shift($response, $length);
1725
  }
1726
  }
1727
  }
6
  *
7
  * PHP versions 4 and 5
8
  *
9
+ * Currently only supports SFTPv2 and v3, 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
  *
57
  /**
58
  * Include Net_SSH2
59
  */
60
+ if (!class_exists('Net_SSH2')) {
61
+ require_once('Net/SSH2.php');
62
+ }
63
 
64
  /**#@+
65
  * @access public
399
 
400
  $response = $this->_get_sftp_packet();
401
  if ($this->packet_type != NET_SFTP_VERSION) {
402
+ user_error('Expected SSH_FXP_VERSION');
403
  return false;
404
  }
405
 
452
  in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
453
  channel and reopen it with a new and updated SSH_FXP_INIT packet.
454
  */
455
+ switch ($this->version) {
456
+ case 2:
457
+ case 3:
458
+ break;
459
+ default:
460
+ return false;
461
  }
462
 
463
  $this->pwd = $this->_realpath('.', false);
478
  return $this->pwd;
479
  }
480
 
481
+ /**
482
+ * Logs errors
483
+ *
484
+ * @param String $response
485
+ * @param optional Integer $status
486
+ * @access public
487
+ */
488
+ function _logError($response, $status = -1) {
489
+ if ($status == -1) {
490
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
491
+ }
492
+
493
+ $error = $this->status_codes[$status];
494
+
495
+ if ($this->version > 2) {
496
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
497
+ $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
498
+ } else {
499
+ $this->sftp_errors[] = $error;
500
+ }
501
+ }
502
+
503
  /**
504
  * Canonicalize the Server-Side Path Name
505
  *
506
  * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
507
+ * the absolute (canonicalized) path.
 
508
  *
509
  * @see Net_SFTP::chdir()
510
  * @param String $dir
 
511
  * @return Mixed
512
  * @access private
513
  */
542
  $dir = $dir[0] == '/' ? '/' . rtrim(substr($dir, 1), '/') : rtrim($dir, '/');
543
 
544
  if ($dir == '.' || $dir == $this->pwd) {
545
+ $temp = $this->pwd;
546
+ if (!empty($file)) {
547
+ $temp.= '/' . $file;
548
+ }
549
+ return $temp;
550
  }
551
 
552
  if ($dir[0] != '/') {
585
  $this->fileType = $this->_parseLongname($this->_string_shift($response, $length));
586
  break;
587
  case NET_SFTP_STATUS:
588
+ $this->_logError($response);
 
589
  return false;
590
  default:
591
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
592
  return false;
593
  }
594
 
595
  // if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to
596
  // be a bonafide directory
597
+ if (!empty($file)) {
598
+ $realpath.= '/' . $file;
599
+ }
600
+
601
+ return $realpath;
602
  }
603
 
604
  /**
642
  $handle = substr($response, 4);
643
  break;
644
  case NET_SFTP_STATUS:
645
+ $this->_logError($response);
 
646
  return false;
647
  default:
648
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
649
  return false;
650
  }
651
 
655
 
656
  $response = $this->_get_sftp_packet();
657
  if ($this->packet_type != NET_SFTP_STATUS) {
658
+ user_error('Expected SSH_FXP_STATUS');
659
  return false;
660
  }
661
 
662
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
663
  if ($status != NET_SFTP_STATUS_OK) {
664
+ $this->_logError($response, $status);
 
665
  return false;
666
  }
667
 
698
  /**
699
  * Reads a list, be it detailed or not, of files in the given directory
700
  *
701
+ * $realpath exists because, in the case of the recursive deletes and recursive chmod's $realpath has already
702
+ * been calculated.
703
+ *
704
+ * @param String $dir
705
+ * @param optional Boolean $raw
706
+ * @param optional Boolean $realpath
707
  * @return Mixed
708
  * @access private
709
  */
733
  break;
734
  case NET_SFTP_STATUS:
735
  // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
736
+ $this->_logError($response);
 
737
  return false;
738
  default:
739
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
740
  return false;
741
  }
742
 
780
  case NET_SFTP_STATUS:
781
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
782
  if ($status != NET_SFTP_STATUS_EOF) {
783
+ $this->_logError($response, $status);
 
784
  return false;
785
  }
786
  break 2;
787
  default:
788
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
789
  return false;
790
  }
791
  }
798
  // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
799
  $response = $this->_get_sftp_packet();
800
  if ($this->packet_type != NET_SFTP_STATUS) {
801
+ user_error('Expected SSH_FXP_STATUS');
802
  return false;
803
  }
804
 
805
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
806
  if ($status != NET_SFTP_STATUS_OK) {
807
+ $this->_logError($response, $status);
 
808
  return false;
809
  }
810
 
868
  foreach ($dirs as $dir) {
869
  if ($dir == end($dirs)) {
870
  unset($temp[$dir]);
871
+ return true;
872
  }
873
+ if (!isset($temp[$dir])) {
874
+ return false;
875
  }
876
+ $temp = &$temp[$dir];
877
  }
878
  }
879
 
917
  }
918
 
919
  $stat = $this->_stat($filename, NET_SFTP_STAT);
920
+ if ($stat === false) {
921
+ return false;
922
+ }
923
 
924
  $pwd = $this->pwd;
925
  $stat['type'] = $this->chdir($filename) ?
952
 
953
  $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
954
  $stat = $this->_stat($filename, NET_SFTP_STAT);
955
+ if ($stat === false) {
956
+ return false;
957
+ }
958
 
959
  if ($lstat != $stat) {
960
  return array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
997
  }
998
  return $attributes;
999
  case NET_SFTP_STATUS:
1000
+ $this->_logError($response);
 
1001
  return false;
1002
  }
1003
 
1004
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1005
  return false;
1006
  }
1007
 
1094
  */
1095
  $response = $this->_get_sftp_packet();
1096
  if ($this->packet_type != NET_SFTP_STATUS) {
1097
+ user_error('Expected SSH_FXP_STATUS');
1098
  return false;
1099
  }
1100
 
1101
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1102
  if ($status != NET_SFTP_STATUS_OK) {
1103
+ $this->_logError($response, $status);
 
1104
  }
1105
 
1106
  // rather than return what the permissions *should* be, we'll return what they actually are. this will also
1117
  $attrs = $this->_parseAttributes($response);
1118
  return $attrs['permissions'];
1119
  case NET_SFTP_STATUS:
1120
+ $this->_logError($response);
 
1121
  return false;
1122
  }
1123
 
1124
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1125
  return false;
1126
  }
1127
 
1147
  return $this->chmod($mode, $path);
1148
  }
1149
 
1150
+ // normally $entries would have at least . and .. but it might not if the directories
1151
+ // permissions didn't allow reading
1152
+ if (empty($entries)) {
1153
+ return false;
1154
+ }
1155
 
1156
  foreach ($entries as $filename=>$props) {
1157
  if ($filename == '.' || $filename == '..') {
1214
  return false;
1215
  }
1216
 
1217
+ if ($dir[0] != '/') {
1218
+ $dir = $this->_realpath(rtrim($dir, '/'));
1219
+ if ($dir === false) {
1220
+ return false;
1221
+ }
1222
+ if (!$this->_mkdir_helper($dir)) {
1223
+ return false;
1224
+ }
1225
+ } else {
1226
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
1227
+ $temp = '';
1228
+ foreach ($dirs as $dir) {
1229
+ $temp.= '/' . $dir;
1230
+ $result = $this->_mkdir_helper($temp);
1231
+ }
1232
+ if (!$result) {
1233
+ return false;
1234
+ }
1235
  }
1236
 
1237
+ return true;
1238
+ }
1239
+
1240
+ /**
1241
+ * Helper function for directory creation
1242
+ *
1243
+ * @param String $dir
1244
+ * @return Boolean
1245
+ * @access private
1246
+ */
1247
+ function _mkdir_helper($dir)
1248
+ {
1249
  // by not providing any permissions, hopefully the server will use the logged in users umask - their
1250
  // default permissions.
1251
  if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*N', strlen($dir), $dir, 0))) {
1254
 
1255
  $response = $this->_get_sftp_packet();
1256
  if ($this->packet_type != NET_SFTP_STATUS) {
1257
+ user_error('Expected SSH_FXP_STATUS');
1258
  return false;
1259
  }
1260
 
1261
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1262
  if ($status != NET_SFTP_STATUS_OK) {
1263
+ $this->_logError($response, $status);
 
1264
  return false;
1265
  }
1266
 
1293
 
1294
  $response = $this->_get_sftp_packet();
1295
  if ($this->packet_type != NET_SFTP_STATUS) {
1296
+ user_error('Expected SSH_FXP_STATUS');
1297
  return false;
1298
  }
1299
 
1300
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1301
  if ($status != NET_SFTP_STATUS_OK) {
1302
  // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
1303
+ $this->_logError($response, $status);
 
1304
  return false;
1305
  }
1306
 
1367
  $handle = substr($response, 4);
1368
  break;
1369
  case NET_SFTP_STATUS:
1370
+ $this->_logError($response);
 
1371
  return false;
1372
  default:
1373
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1374
  return false;
1375
  }
1376
 
1379
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
1380
  if ($mode & NET_SFTP_LOCAL_FILE) {
1381
  if (!is_file($data)) {
1382
+ user_error("$data is not a valid file");
1383
  return false;
1384
  }
1385
  $fp = @fopen($data, 'rb');
1416
  }
1417
  }
1418
 
1419
+ if (!$this->_read_put_responses($i)) {
1420
+ return false;
1421
+ }
1422
 
1423
  if ($mode & NET_SFTP_LOCAL_FILE) {
1424
  fclose($fp);
1430
 
1431
  $response = $this->_get_sftp_packet();
1432
  if ($this->packet_type != NET_SFTP_STATUS) {
1433
+ user_error('Expected SSH_FXP_STATUS');
1434
  return false;
1435
  }
1436
 
1437
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1438
  if ($status != NET_SFTP_STATUS_OK) {
1439
+ $this->_logError($response, $status);
 
1440
  return false;
1441
  }
1442
 
1458
  while ($i--) {
1459
  $response = $this->_get_sftp_packet();
1460
  if ($this->packet_type != NET_SFTP_STATUS) {
1461
+ user_error('Expected SSH_FXP_STATUS');
1462
  return false;
1463
  }
1464
 
1465
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1466
  if ($status != NET_SFTP_STATUS_OK) {
1467
+ $this->_logError($response, $status);
 
1468
  break;
1469
  }
1470
  }
1484
  * @return Mixed
1485
  * @access public
1486
  */
1487
+ function get($remote_file, $local_file = false, $offset = 0, $length = -1)
1488
  {
1489
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1490
  return false;
1506
  $handle = substr($response, 4);
1507
  break;
1508
  case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1509
+ $this->_logError($response);
 
1510
  return false;
1511
  default:
1512
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1513
  return false;
1514
  }
1515
 
1522
  $content = '';
1523
  }
1524
 
1525
+ $size = (1 << 20) < $length || $length < 0 ? 1 << 20 : $length;
1526
+ $start = $offset;
1527
  while (true) {
1528
+ $packet = pack('Na*N3', strlen($handle), $handle, 0, $offset, $size);
1529
  if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
1530
  if ($local_file !== false) {
1531
  fclose($fp);
1537
  switch ($this->packet_type) {
1538
  case NET_SFTP_DATA:
1539
  $temp = substr($response, 4);
1540
+ $offset+= strlen($temp);
1541
  if ($local_file === false) {
1542
  $content.= $temp;
1543
  } else {
1545
  }
1546
  break;
1547
  case NET_SFTP_STATUS:
1548
+ $this->_logError($response);
 
1549
  break 2;
1550
  default:
1551
+ user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
1552
  if ($local_file !== false) {
1553
  fclose($fp);
1554
  }
1555
  return false;
1556
  }
1557
+
1558
+ if ($length > 0 && $length <= $offset - $size) {
1559
+ if ($local_file === false) {
1560
+ $content = substr($content, 0, $length);
1561
+ } else {
1562
+ ftruncate($fp, $length);
1563
+ }
1564
+ break;
1565
+ }
1566
  }
1567
 
1568
  if ($local_file !== false) {
1575
 
1576
  $response = $this->_get_sftp_packet();
1577
  if ($this->packet_type != NET_SFTP_STATUS) {
1578
+ user_error('Expected SSH_FXP_STATUS');
1579
  return false;
1580
  }
1581
 
1582
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
 
 
 
1583
  if ($status != NET_SFTP_STATUS_OK) {
1584
+ $this->_logError($response, $status);
1585
  return false;
1586
  }
1587
 
1618
 
1619
  $response = $this->_get_sftp_packet();
1620
  if ($this->packet_type != NET_SFTP_STATUS) {
1621
+ user_error('Expected SSH_FXP_STATUS');
1622
  return false;
1623
  }
1624
 
1625
  // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1626
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1627
  if ($status != NET_SFTP_STATUS_OK) {
1628
+ $this->_logError($response, $status);
 
1629
  if (!$recursive) {
1630
  return false;
1631
  }
1656
  $i = 0;
1657
  $entries = $this->_list($path, true, false);
1658
 
1659
+ // normally $entries would have at least . and .. but it might not if the directories
1660
+ // permissions didn't allow reading
1661
+ if (empty($entries)) {
1662
+ return false;
1663
+ }
1664
 
1665
  foreach ($entries as $filename=>$props) {
1666
  if ($filename == '.' || $filename == '..') {
1695
  if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
1696
  return false;
1697
  }
1698
+ $this->_remove_dir($path);
1699
 
1700
  $i++;
1701
 
1737
 
1738
  $response = $this->_get_sftp_packet();
1739
  if ($this->packet_type != NET_SFTP_STATUS) {
1740
+ user_error('Expected SSH_FXP_STATUS');
1741
  return false;
1742
  }
1743
 
1744
  // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
1745
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1746
  if ($status != NET_SFTP_STATUS_OK) {
1747
+ $this->_logError($response, $status);
 
1748
  return false;
1749
  }
1750
 
1795
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
1796
  $key = $this->_string_shift($response, $length);
1797
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
1798
+ $attr[$key] = $this->_string_shift($response, $length);
1799
  }
1800
  }
1801
  }
phpseclib/Net/SSH2.php CHANGED
@@ -73,32 +73,48 @@
73
  *
74
  * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
75
  */
76
- require_once('Math/BigInteger.php');
 
 
77
 
78
  /**
79
  * Include Crypt_Random
80
  */
81
- require_once('Crypt/Random.php');
 
 
 
 
 
 
82
 
83
  /**
84
  * Include Crypt_Hash
85
  */
86
- require_once('Crypt/Hash.php');
 
 
87
 
88
  /**
89
  * Include Crypt_TripleDES
90
  */
91
- require_once('Crypt/TripleDES.php');
 
 
92
 
93
  /**
94
  * Include Crypt_RC4
95
  */
96
- require_once('Crypt/RC4.php');
 
 
97
 
98
  /**
99
  * Include Crypt_AES
100
  */
101
- require_once('Crypt/AES.php');
 
 
102
 
103
  /**#@+
104
  * Execution Bitmap Masks
@@ -143,6 +159,14 @@ define('NET_SSH2_LOG_SIMPLE', 1);
143
  * Returns the message content
144
  */
145
  define('NET_SSH2_LOG_COMPLEX', 2);
 
 
 
 
 
 
 
 
146
  /**#@-*/
147
 
148
  /**#@+
@@ -178,7 +202,7 @@ class Net_SSH2 {
178
  * @var String
179
  * @access private
180
  */
181
- var $identifier = 'SSH-2.0-phpseclib_0.2';
182
 
183
  /**
184
  * The Socket Object
@@ -191,7 +215,7 @@ class Net_SSH2 {
191
  /**
192
  * Execution Bitmap
193
  *
194
- * The bits that are set reprsent functions that have been called already. This is used to determine
195
  * if a requisite function has been successfully executed. If not, an error should be thrown.
196
  *
197
  * @var Integer
@@ -635,6 +659,56 @@ class Net_SSH2 {
635
  */
636
  var $curTimeout;
637
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
  /**
639
  * Default Constructor.
640
  *
@@ -648,6 +722,7 @@ class Net_SSH2 {
648
  */
649
  function Net_SSH2($host, $port = 22, $timeout = 10)
650
  {
 
651
  $this->message_numbers = array(
652
  1 => 'NET_SSH2_MSG_DISCONNECT',
653
  2 => 'NET_SSH2_MSG_IGNORE',
@@ -718,9 +793,31 @@ class Net_SSH2 {
718
  61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE')
719
  );
720
 
 
721
  $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
722
  if (!$this->fsock) {
723
- user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  return;
725
  }
726
 
@@ -742,7 +839,7 @@ class Net_SSH2 {
742
  }
743
 
744
  if (feof($this->fsock)) {
745
- user_error('Connection closed by server', E_USER_NOTICE);
746
  return false;
747
  }
748
 
@@ -761,13 +858,8 @@ class Net_SSH2 {
761
  }
762
 
763
  if (defined('NET_SSH2_LOGGING')) {
764
- $this->message_number_log[] = '<-';
765
- $this->message_number_log[] = '->';
766
-
767
- if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
768
- $this->message_log[] = $temp;
769
- $this->message_log[] = $this->identifier . "\r\n";
770
- }
771
  }
772
 
773
  $this->server_identifier = trim($temp, "\r\n");
@@ -776,7 +868,7 @@ class Net_SSH2 {
776
  }
777
 
778
  if ($matches[1] != '1.99' && $matches[1] != '2.0') {
779
- user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE);
780
  return;
781
  }
782
 
@@ -784,12 +876,12 @@ class Net_SSH2 {
784
 
785
  $response = $this->_get_binary_packet();
786
  if ($response === false) {
787
- user_error('Connection closed by server', E_USER_NOTICE);
788
  return;
789
  }
790
 
791
  if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
792
- user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE);
793
  return;
794
  }
795
 
@@ -852,6 +944,15 @@ class Net_SSH2 {
852
  //'zlib' // OPTIONAL ZLIB (LZ77) compression
853
  );
854
 
 
 
 
 
 
 
 
 
 
855
  static $str_kex_algorithms, $str_server_host_key_algorithms,
856
  $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
857
  $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
@@ -864,10 +965,7 @@ class Net_SSH2 {
864
  $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
865
  }
866
 
867
- $client_cookie = '';
868
- for ($i = 0; $i < 16; $i++) {
869
- $client_cookie.= chr(crypt_random(0, 255));
870
- }
871
 
872
  $response = $kexinit_payload_server;
873
  $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
@@ -925,7 +1023,7 @@ class Net_SSH2 {
925
  // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
926
  for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
927
  if ($i == count($encryption_algorithms)) {
928
- user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
929
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
930
  }
931
 
@@ -962,7 +1060,7 @@ class Net_SSH2 {
962
 
963
  for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
964
  if ($i == count($encryption_algorithms)) {
965
- user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
966
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
967
  }
968
 
@@ -1000,7 +1098,7 @@ class Net_SSH2 {
1000
  // through diffie-hellman key exchange a symmetric key is obtained
1001
  for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
1002
  if ($i == count($kex_algorithms)) {
1003
- user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
1004
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1005
  }
1006
 
@@ -1045,7 +1143,6 @@ class Net_SSH2 {
1045
 
1046
  $g = new Math_BigInteger(2);
1047
  $x = new Math_BigInteger();
1048
- $x->setRandomGenerator('crypt_random');
1049
  $x = $x->random(new Math_BigInteger(1), $q);
1050
  $e = $g->modPow($x, $p);
1051
 
@@ -1053,19 +1150,19 @@ class Net_SSH2 {
1053
  $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
1054
 
1055
  if (!$this->_send_binary_packet($data)) {
1056
- user_error('Connection closed by server', E_USER_NOTICE);
1057
  return false;
1058
  }
1059
 
1060
  $response = $this->_get_binary_packet();
1061
  if ($response === false) {
1062
- user_error('Connection closed by server', E_USER_NOTICE);
1063
  return false;
1064
  }
1065
  extract(unpack('Ctype', $this->_string_shift($response, 1)));
1066
 
1067
  if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
1068
- user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
1069
  return false;
1070
  }
1071
 
@@ -1103,12 +1200,12 @@ class Net_SSH2 {
1103
 
1104
  for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
1105
  if ($i == count($server_host_key_algorithms)) {
1106
- user_error('No compatible server host key algorithms found', E_USER_NOTICE);
1107
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1108
  }
1109
 
1110
  if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
1111
- user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
1112
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1113
  }
1114
 
@@ -1123,14 +1220,14 @@ class Net_SSH2 {
1123
  $response = $this->_get_binary_packet();
1124
 
1125
  if ($response === false) {
1126
- user_error('Connection closed by server', E_USER_NOTICE);
1127
  return false;
1128
  }
1129
 
1130
  extract(unpack('Ctype', $this->_string_shift($response, 1)));
1131
 
1132
  if ($type != NET_SSH2_MSG_NEWKEYS) {
1133
- user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
1134
  return false;
1135
  }
1136
 
@@ -1244,7 +1341,7 @@ class Net_SSH2 {
1244
 
1245
  for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
1246
  if ($i == count($mac_algorithms)) {
1247
- user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
1248
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1249
  }
1250
 
@@ -1269,7 +1366,7 @@ class Net_SSH2 {
1269
 
1270
  for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
1271
  if ($i == count($mac_algorithms)) {
1272
- user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
1273
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1274
  }
1275
 
@@ -1311,14 +1408,14 @@ class Net_SSH2 {
1311
 
1312
  for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
1313
  if ($i == count($compression_algorithms)) {
1314
- user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
1315
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1316
  }
1317
  $this->decompress = $compression_algorithms[$i] == 'zlib';
1318
 
1319
  for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
1320
  if ($i == count($compression_algorithms)) {
1321
- user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
1322
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1323
  }
1324
  $this->compress = $compression_algorithms[$i] == 'zlib';
@@ -1338,7 +1435,7 @@ class Net_SSH2 {
1338
  * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
1339
  * by sending dummy SSH_MSG_IGNORE messages.
1340
  */
1341
- function login($username, $password = '')
1342
  {
1343
  if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
1344
  return false;
@@ -1354,14 +1451,14 @@ class Net_SSH2 {
1354
 
1355
  $response = $this->_get_binary_packet();
1356
  if ($response === false) {
1357
- user_error('Connection closed by server', E_USER_NOTICE);
1358
  return false;
1359
  }
1360
 
1361
  extract(unpack('Ctype', $this->_string_shift($response, 1)));
1362
 
1363
  if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
1364
- user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE);
1365
  return false;
1366
  }
1367
 
@@ -1370,6 +1467,34 @@ class Net_SSH2 {
1370
  return $this->_privatekey_login($username, $password);
1371
  }
1372
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1373
  $packet = pack('CNa*Na*Na*CNa*',
1374
  NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
1375
  strlen('password'), 'password', 0, strlen($password), $password
@@ -1390,7 +1515,7 @@ class Net_SSH2 {
1390
 
1391
  $response = $this->_get_binary_packet();
1392
  if ($response === false) {
1393
- user_error('Connection closed by server', E_USER_NOTICE);
1394
  return false;
1395
  }
1396
 
@@ -1462,7 +1587,7 @@ class Net_SSH2 {
1462
 
1463
  $response = $this->_get_binary_packet();
1464
  if ($response === false) {
1465
- user_error('Connection closed by server', E_USER_NOTICE);
1466
  return false;
1467
  }
1468
 
@@ -1575,7 +1700,7 @@ class Net_SSH2 {
1575
 
1576
  $response = $this->_get_binary_packet();
1577
  if ($response === false) {
1578
- user_error('Connection closed by server', E_USER_NOTICE);
1579
  return false;
1580
  }
1581
 
@@ -1610,7 +1735,7 @@ class Net_SSH2 {
1610
 
1611
  $response = $this->_get_binary_packet();
1612
  if ($response === false) {
1613
- user_error('Connection closed by server', E_USER_NOTICE);
1614
  return false;
1615
  }
1616
 
@@ -1618,7 +1743,7 @@ class Net_SSH2 {
1618
 
1619
  switch ($type) {
1620
  case NET_SSH2_MSG_USERAUTH_FAILURE:
1621
- // either the login is bad or the server employees multi-factor authentication
1622
  return false;
1623
  case NET_SSH2_MSG_USERAUTH_SUCCESS:
1624
  $this->bitmap |= NET_SSH2_MASK_LOGIN;
@@ -1763,7 +1888,7 @@ class Net_SSH2 {
1763
 
1764
  $response = $this->_get_binary_packet();
1765
  if ($response === false) {
1766
- user_error('Connection closed by server', E_USER_NOTICE);
1767
  return false;
1768
  }
1769
 
@@ -1774,7 +1899,7 @@ class Net_SSH2 {
1774
  break;
1775
  case NET_SSH2_MSG_CHANNEL_FAILURE:
1776
  default:
1777
- user_error('Unable to request pseudo-terminal', E_USER_NOTICE);
1778
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1779
  }
1780
 
@@ -1815,12 +1940,12 @@ class Net_SSH2 {
1815
  $this->curTimeout = $this->timeout;
1816
 
1817
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1818
- user_error('Operation disallowed prior to login()', E_USER_NOTICE);
1819
  return false;
1820
  }
1821
 
1822
  if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
1823
- user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
1824
  return false;
1825
  }
1826
 
@@ -1828,7 +1953,7 @@ class Net_SSH2 {
1828
  while (true) {
1829
  if ($mode == NET_SSH2_READ_REGEX) {
1830
  preg_match($expect, $this->interactiveBuffer, $matches);
1831
- $match = $matches[0];
1832
  }
1833
  $pos = !empty($match) ? strpos($this->interactiveBuffer, $match) : false;
1834
  if ($pos !== false) {
@@ -1854,12 +1979,12 @@ class Net_SSH2 {
1854
  function write($cmd)
1855
  {
1856
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1857
- user_error('Operation disallowed prior to login()', E_USER_NOTICE);
1858
  return false;
1859
  }
1860
 
1861
  if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
1862
- user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
1863
  return false;
1864
  }
1865
 
@@ -1874,6 +1999,9 @@ class Net_SSH2 {
1874
  function disconnect()
1875
  {
1876
  $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 
 
1877
  }
1878
 
1879
  /**
@@ -1901,7 +2029,8 @@ class Net_SSH2 {
1901
  function _get_binary_packet()
1902
  {
1903
  if (!is_resource($this->fsock) || feof($this->fsock)) {
1904
- user_error('Connection closed prematurely', E_USER_NOTICE);
 
1905
  return false;
1906
  }
1907
 
@@ -1917,7 +2046,7 @@ class Net_SSH2 {
1917
  $raw = $this->decrypt->decrypt($raw);
1918
  }
1919
  if ($raw === false) {
1920
- user_error('Unable to decrypt content', E_USER_NOTICE);
1921
  return false;
1922
  }
1923
 
@@ -1941,7 +2070,7 @@ class Net_SSH2 {
1941
  if ($this->hmac_check !== false) {
1942
  $hmac = fread($this->fsock, $this->hmac_size);
1943
  if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
1944
- user_error('Invalid HMAC', E_USER_NOTICE);
1945
  return false;
1946
  }
1947
  }
@@ -1953,12 +2082,12 @@ class Net_SSH2 {
1953
  $this->get_seq_no++;
1954
 
1955
  if (defined('NET_SSH2_LOGGING')) {
1956
- $temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
1957
- $this->message_number_log[] = '<- ' . $temp .
1958
- ' (' . round($stop - $start, 4) . 's)';
1959
- if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
1960
- $this->_append_log($payload);
1961
- }
1962
  }
1963
 
1964
  return $this->_filter($payload);
@@ -2050,6 +2179,30 @@ class Net_SSH2 {
2050
  return $payload;
2051
  }
2052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2053
  /**
2054
  * Gets channel data
2055
  *
@@ -2070,24 +2223,21 @@ class Net_SSH2 {
2070
  $read = array($this->fsock);
2071
  $write = $except = NULL;
2072
 
2073
- stream_set_blocking($this->fsock, false);
2074
-
2075
  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
 
 
2076
  // on windows this returns a "Warning: Invalid CRT parameters detected" error
2077
- if (!@stream_select($read, $write, $except, $this->curTimeout)) {
2078
- stream_set_blocking($this->fsock, true);
2079
  $this->_close_channel($client_channel);
2080
  return true;
2081
  }
2082
  $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
2083
  $this->curTimeout-= $elapsed;
2084
-
2085
- stream_set_blocking($this->fsock, true);
2086
  }
2087
 
2088
  $response = $this->_get_binary_packet();
2089
  if ($response === false) {
2090
- user_error('Connection closed by server', E_USER_NOTICE);
2091
  return false;
2092
  }
2093
 
@@ -2109,7 +2259,7 @@ class Net_SSH2 {
2109
  return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
2110
  //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
2111
  default:
2112
- user_error('Unable to open channel', E_USER_NOTICE);
2113
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2114
  }
2115
  break;
@@ -2119,7 +2269,7 @@ class Net_SSH2 {
2119
  return true;
2120
  //case NET_SSH2_MSG_CHANNEL_FAILURE:
2121
  default:
2122
- user_error('Unable to request pseudo-terminal', E_USER_NOTICE);
2123
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2124
  }
2125
  case NET_SSH2_MSG_CHANNEL_CLOSE:
@@ -2148,7 +2298,7 @@ class Net_SSH2 {
2148
  $this->channel_buffers[$client_channel][] = $data;
2149
  break;
2150
  case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
2151
- if ($skip_extended) {
2152
  break;
2153
  }
2154
  /*
@@ -2183,8 +2333,10 @@ class Net_SSH2 {
2183
  case 'exit-status':
2184
  // "The channel needs to be closed with SSH_MSG_CHANNEL_CLOSE after this message."
2185
  // -- http://tools.ietf.org/html/rfc4254#section-6.10
2186
- $this->_close_channel($client_channel);
2187
- return true;
 
 
2188
  default:
2189
  // "Some systems may not implement signals, in which case they SHOULD ignore this message."
2190
  // -- http://tools.ietf.org/html/rfc4254#section-6.9
@@ -2192,12 +2344,21 @@ class Net_SSH2 {
2192
  }
2193
  break;
2194
  case NET_SSH2_MSG_CHANNEL_CLOSE:
2195
- $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
 
 
 
 
 
 
 
 
 
2196
  return true;
2197
  case NET_SSH2_MSG_CHANNEL_EOF:
2198
  break;
2199
  default:
2200
- user_error('Error reading channel data', E_USER_NOTICE);
2201
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2202
  }
2203
  }
@@ -2216,7 +2377,8 @@ class Net_SSH2 {
2216
  function _send_binary_packet($data)
2217
  {
2218
  if (!is_resource($this->fsock) || feof($this->fsock)) {
2219
- user_error('Connection closed prematurely', E_USER_NOTICE);
 
2220
  return false;
2221
  }
2222
 
@@ -2232,11 +2394,7 @@ class Net_SSH2 {
2232
  $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
2233
  // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
2234
  $padding_length = $packet_length - strlen($data) - 5;
2235
-
2236
- $padding = '';
2237
- for ($i = 0; $i < $padding_length; $i++) {
2238
- $padding.= chr(crypt_random(0, 255));
2239
- }
2240
 
2241
  // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
2242
  $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);
@@ -2255,12 +2413,12 @@ class Net_SSH2 {
2255
  $stop = strtok(microtime(), ' ') + strtok('');
2256
 
2257
  if (defined('NET_SSH2_LOGGING')) {
2258
- $temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
2259
- $this->message_number_log[] = '-> ' . $temp .
2260
- ' (' . round($stop - $start, 4) . 's)';
2261
- if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
2262
- $this->_append_log($data);
2263
- }
2264
  }
2265
 
2266
  return $result;
@@ -2274,15 +2432,60 @@ class Net_SSH2 {
2274
  * @param String $data
2275
  * @access private
2276
  */
2277
- function _append_log($data)
2278
  {
2279
- $this->_string_shift($data);
2280
- $this->log_size+= strlen($data);
2281
- $this->message_log[] = $data;
2282
- while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) {
2283
- $this->log_size-= strlen(array_shift($this->message_log));
2284
- array_shift($this->message_number_log);
2285
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2286
  }
2287
 
2288
  /**
@@ -2654,6 +2857,14 @@ class Net_SSH2 {
2654
  extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
2655
  $this->_string_shift($server_public_host_key, $length);
2656
 
 
 
 
 
 
 
 
 
2657
  switch ($this->signature_format) {
2658
  case 'ssh-dss':
2659
  $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
@@ -2673,7 +2884,7 @@ class Net_SSH2 {
2673
  padding, unsigned, and in network byte order). */
2674
  $temp = unpack('Nlength', $this->_string_shift($signature, 4));
2675
  if ($temp['length'] != 40) {
2676
- user_error('Invalid signature', E_USER_NOTICE);
2677
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2678
  }
2679
 
@@ -2681,7 +2892,7 @@ class Net_SSH2 {
2681
  $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
2682
 
2683
  if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
2684
- user_error('Invalid signature', E_USER_NOTICE);
2685
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2686
  }
2687
 
@@ -2701,7 +2912,7 @@ class Net_SSH2 {
2701
  list(, $v) = $v->divide($q);
2702
 
2703
  if (!$v->equals($r)) {
2704
- user_error('Bad server signature', E_USER_NOTICE);
2705
  return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2706
  }
2707
 
@@ -2726,7 +2937,7 @@ class Net_SSH2 {
2726
  $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2727
  $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
2728
  if (!$rsa->verify($this->exchange_hash, $signature)) {
2729
- user_error('Bad server signature', E_USER_NOTICE);
2730
  return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2731
  }
2732
  */
@@ -2741,7 +2952,7 @@ class Net_SSH2 {
2741
  // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
2742
 
2743
  if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
2744
- user_error('Invalid signature', E_USER_NOTICE);
2745
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2746
  }
2747
 
@@ -2752,11 +2963,15 @@ class Net_SSH2 {
2752
  $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h;
2753
 
2754
  if ($s != $h) {
2755
- user_error('Bad server signature', E_USER_NOTICE);
2756
  return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2757
  }
 
 
 
 
2758
  }
2759
 
2760
- return $this->server_public_host_key;
2761
  }
2762
  }
73
  *
74
  * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
75
  */
76
+ if (!class_exists('Math_BigInteger')) {
77
+ require_once('Math/BigInteger.php');
78
+ }
79
 
80
  /**
81
  * Include Crypt_Random
82
  */
83
+ // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
84
+ // will trigger a call to __autoload() if you're wanting to auto-load classes
85
+ // call function_exists() a second time to stop the require_once from being called outside
86
+ // of the auto loader
87
+ if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
88
+ require_once('Crypt/Random.php');
89
+ }
90
 
91
  /**
92
  * Include Crypt_Hash
93
  */
94
+ if (!class_exists('Crypt_Hash')) {
95
+ require_once('Crypt/Hash.php');
96
+ }
97
 
98
  /**
99
  * Include Crypt_TripleDES
100
  */
101
+ if (!class_exists('Crypt_TripleDES')) {
102
+ require_once('Crypt/TripleDES.php');
103
+ }
104
 
105
  /**
106
  * Include Crypt_RC4
107
  */
108
+ if (!class_exists('Crypt_RC4')) {
109
+ require_once('Crypt/RC4.php');
110
+ }
111
 
112
  /**
113
  * Include Crypt_AES
114
  */
115
+ if (!class_exists('Crypt_AES')) {
116
+ require_once('Crypt/AES.php');
117
+ }
118
 
119
  /**#@+
120
  * Execution Bitmap Masks
159
  * Returns the message content
160
  */
161
  define('NET_SSH2_LOG_COMPLEX', 2);
162
+ /**
163
+ * Outputs the content real-time
164
+ */
165
+ define('NET_SSH2_LOG_REALTIME', 3);
166
+ /**
167
+ * Dumps the content real-time to a file
168
+ */
169
+ define('NET_SSH2_LOG_REALTIME_FILE', 4);
170
  /**#@-*/
171
 
172
  /**#@+
202
  * @var String
203
  * @access private
204
  */
205
+ var $identifier = 'SSH-2.0-phpseclib_0.3';
206
 
207
  /**
208
  * The Socket Object
215
  /**
216
  * Execution Bitmap
217
  *
218
+ * The bits that are set represent functions that have been called already. This is used to determine
219
  * if a requisite function has been successfully executed. If not, an error should be thrown.
220
  *
221
  * @var Integer
659
  */
660
  var $curTimeout;
661
 
662
+ /**
663
+ * Real-time log file pointer
664
+ *
665
+ * @see Net_SSH2::_append_log()
666
+ * @var Resource
667
+ * @access private
668
+ */
669
+ var $realtime_log_file;
670
+
671
+ /**
672
+ * Real-time log file size
673
+ *
674
+ * @see Net_SSH2::_append_log()
675
+ * @var Integer
676
+ * @access private
677
+ */
678
+ var $realtime_log_size;
679
+
680
+ /**
681
+ * Has the signature been validated?
682
+ *
683
+ * @see Net_SSH2::getServerPublicHostKey()
684
+ * @var Boolean
685
+ * @access private
686
+ */
687
+ var $signature_validated = false;
688
+
689
+ /**
690
+ * Real-time log file wrap boolean
691
+ *
692
+ * @see Net_SSH2::_append_log()
693
+ * @access private
694
+ */
695
+ var $realtime_log_wrap;
696
+
697
+ /**
698
+ * Flag to suppress stderr from output
699
+ *
700
+ * @see Net_SSH2::enableQuietMode()
701
+ * @access private
702
+ */
703
+ var $quiet_mode = false;
704
+
705
+ /**
706
+ * Time of first network activity
707
+ *
708
+ * @access private
709
+ */
710
+ var $last_packet;
711
+
712
  /**
713
  * Default Constructor.
714
  *
722
  */
723
  function Net_SSH2($host, $port = 22, $timeout = 10)
724
  {
725
+ $this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5
726
  $this->message_numbers = array(
727
  1 => 'NET_SSH2_MSG_DISCONNECT',
728
  2 => 'NET_SSH2_MSG_IGNORE',
793
  61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE')
794
  );
795
 
796
+ $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
797
  $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
798
  if (!$this->fsock) {
799
+ user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
800
+ return;
801
+ }
802
+ $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
803
+
804
+ $timeout-= $elapsed;
805
+
806
+ if ($timeout <= 0) {
807
+ user_error(rtrim("Cannot connect to $host. Timeout error"));
808
+ return;
809
+ }
810
+
811
+ $read = array($this->fsock);
812
+ $write = $except = NULL;
813
+
814
+ $sec = floor($timeout);
815
+ $usec = 1000000 * ($timeout - $sec);
816
+
817
+ // on windows this returns a "Warning: Invalid CRT parameters detected" error
818
+ // the !count() is done as a workaround for <https://bugs.php.net/42682>
819
+ if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
820
+ user_error(rtrim("Cannot connect to $host. Banner timeout"));
821
  return;
822
  }
823
 
839
  }
840
 
841
  if (feof($this->fsock)) {
842
+ user_error('Connection closed by server');
843
  return false;
844
  }
845
 
858
  }
859
 
860
  if (defined('NET_SSH2_LOGGING')) {
861
+ $this->_append_log('<-', $extra . $temp);
862
+ $this->_append_log('->', $this->identifier . "\r\n");
 
 
 
 
 
863
  }
864
 
865
  $this->server_identifier = trim($temp, "\r\n");
868
  }
869
 
870
  if ($matches[1] != '1.99' && $matches[1] != '2.0') {
871
+ user_error("Cannot connect to SSH $matches[1] servers");
872
  return;
873
  }
874
 
876
 
877
  $response = $this->_get_binary_packet();
878
  if ($response === false) {
879
+ user_error('Connection closed by server');
880
  return;
881
  }
882
 
883
  if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
884
+ user_error('Expected SSH_MSG_KEXINIT');
885
  return;
886
  }
887
 
944
  //'zlib' // OPTIONAL ZLIB (LZ77) compression
945
  );
946
 
947
+ // some SSH servers have buggy implementations of some of the above algorithms
948
+ switch ($this->server_identifier) {
949
+ case 'SSH-2.0-SSHD':
950
+ $mac_algorithms = array_values(array_diff(
951
+ $mac_algorithms,
952
+ array('hmac-sha1-96', 'hmac-md5-96')
953
+ ));
954
+ }
955
+
956
  static $str_kex_algorithms, $str_server_host_key_algorithms,
957
  $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
958
  $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
965
  $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
966
  }
967
 
968
+ $client_cookie = crypt_random_string(16);
 
 
 
969
 
970
  $response = $kexinit_payload_server;
971
  $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
1023
  // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
1024
  for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
1025
  if ($i == count($encryption_algorithms)) {
1026
+ user_error('No compatible server to client encryption algorithms found');
1027
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1028
  }
1029
 
1060
 
1061
  for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
1062
  if ($i == count($encryption_algorithms)) {
1063
+ user_error('No compatible client to server encryption algorithms found');
1064
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1065
  }
1066
 
1098
  // through diffie-hellman key exchange a symmetric key is obtained
1099
  for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
1100
  if ($i == count($kex_algorithms)) {
1101
+ user_error('No compatible key exchange algorithms found');
1102
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1103
  }
1104
 
1143
 
1144
  $g = new Math_BigInteger(2);
1145
  $x = new Math_BigInteger();
 
1146
  $x = $x->random(new Math_BigInteger(1), $q);
1147
  $e = $g->modPow($x, $p);
1148
 
1150
  $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
1151
 
1152
  if (!$this->_send_binary_packet($data)) {
1153
+ user_error('Connection closed by server');
1154
  return false;
1155
  }
1156
 
1157
  $response = $this->_get_binary_packet();
1158
  if ($response === false) {
1159
+ user_error('Connection closed by server');
1160
  return false;
1161
  }
1162
  extract(unpack('Ctype', $this->_string_shift($response, 1)));
1163
 
1164
  if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
1165
+ user_error('Expected SSH_MSG_KEXDH_REPLY');
1166
  return false;
1167
  }
1168
 
1200
 
1201
  for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
1202
  if ($i == count($server_host_key_algorithms)) {
1203
+ user_error('No compatible server host key algorithms found');
1204
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1205
  }
1206
 
1207
  if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
1208
+ user_error('Sever Host Key Algorithm Mismatch');
1209
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1210
  }
1211
 
1220
  $response = $this->_get_binary_packet();
1221
 
1222
  if ($response === false) {
1223
+ user_error('Connection closed by server');
1224
  return false;
1225
  }
1226
 
1227
  extract(unpack('Ctype', $this->_string_shift($response, 1)));
1228
 
1229
  if ($type != NET_SSH2_MSG_NEWKEYS) {
1230
+ user_error('Expected SSH_MSG_NEWKEYS');
1231
  return false;
1232
  }
1233
 
1341
 
1342
  for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
1343
  if ($i == count($mac_algorithms)) {
1344
+ user_error('No compatible client to server message authentication algorithms found');
1345
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1346
  }
1347
 
1366
 
1367
  for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
1368
  if ($i == count($mac_algorithms)) {
1369
+ user_error('No compatible server to client message authentication algorithms found');
1370
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1371
  }
1372
 
1408
 
1409
  for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
1410
  if ($i == count($compression_algorithms)) {
1411
+ user_error('No compatible server to client compression algorithms found');
1412
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1413
  }
1414
  $this->decompress = $compression_algorithms[$i] == 'zlib';
1415
 
1416
  for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
1417
  if ($i == count($compression_algorithms)) {
1418
+ user_error('No compatible client to server compression algorithms found');
1419
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
1420
  }
1421
  $this->compress = $compression_algorithms[$i] == 'zlib';
1435
  * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
1436
  * by sending dummy SSH_MSG_IGNORE messages.
1437
  */
1438
+ function login($username, $password = null)
1439
  {
1440
  if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
1441
  return false;
1451
 
1452
  $response = $this->_get_binary_packet();
1453
  if ($response === false) {
1454
+ user_error('Connection closed by server');
1455
  return false;
1456
  }
1457
 
1458
  extract(unpack('Ctype', $this->_string_shift($response, 1)));
1459
 
1460
  if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
1461
+ user_error('Expected SSH_MSG_SERVICE_ACCEPT');
1462
  return false;
1463
  }
1464
 
1467
  return $this->_privatekey_login($username, $password);
1468
  }
1469
 
1470
+ if (!isset($password)) {
1471
+ $packet = pack('CNa*Na*Na*',
1472
+ NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
1473
+ strlen('none'), 'none'
1474
+ );
1475
+
1476
+ if (!$this->_send_binary_packet($packet)) {
1477
+ return false;
1478
+ }
1479
+
1480
+ $response = $this->_get_binary_packet();
1481
+ if ($response === false) {
1482
+ user_error('Connection closed by server');
1483
+ return false;
1484
+ }
1485
+
1486
+ extract(unpack('Ctype', $this->_string_shift($response, 1)));
1487
+
1488
+ switch ($type) {
1489
+ case NET_SSH2_MSG_USERAUTH_SUCCESS:
1490
+ $this->bitmap |= NET_SSH2_MASK_LOGIN;
1491
+ return true;
1492
+ //case NET_SSH2_MSG_USERAUTH_FAILURE:
1493
+ default:
1494
+ return false;
1495
+ }
1496
+ }
1497
+
1498
  $packet = pack('CNa*Na*Na*CNa*',
1499
  NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
1500
  strlen('password'), 'password', 0, strlen($password), $password
1515
 
1516
  $response = $this->_get_binary_packet();
1517
  if ($response === false) {
1518
+ user_error('Connection closed by server');
1519
  return false;
1520
  }
1521
 
1587
 
1588
  $response = $this->_get_binary_packet();
1589
  if ($response === false) {
1590
+ user_error('Connection closed by server');
1591
  return false;
1592
  }
1593
 
1700
 
1701
  $response = $this->_get_binary_packet();
1702
  if ($response === false) {
1703
+ user_error('Connection closed by server');
1704
  return false;
1705
  }
1706
 
1735
 
1736
  $response = $this->_get_binary_packet();
1737
  if ($response === false) {
1738
+ user_error('Connection closed by server');
1739
  return false;
1740
  }
1741
 
1743
 
1744
  switch ($type) {
1745
  case NET_SSH2_MSG_USERAUTH_FAILURE:
1746
+ // either the login is bad or the server employs multi-factor authentication
1747
  return false;
1748
  case NET_SSH2_MSG_USERAUTH_SUCCESS:
1749
  $this->bitmap |= NET_SSH2_MASK_LOGIN;
1888
 
1889
  $response = $this->_get_binary_packet();
1890
  if ($response === false) {
1891
+ user_error('Connection closed by server');
1892
  return false;
1893
  }
1894
 
1899
  break;
1900
  case NET_SSH2_MSG_CHANNEL_FAILURE:
1901
  default:
1902
+ user_error('Unable to request pseudo-terminal');
1903
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
1904
  }
1905
 
1940
  $this->curTimeout = $this->timeout;
1941
 
1942
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1943
+ user_error('Operation disallowed prior to login()');
1944
  return false;
1945
  }
1946
 
1947
  if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
1948
+ user_error('Unable to initiate an interactive shell session');
1949
  return false;
1950
  }
1951
 
1953
  while (true) {
1954
  if ($mode == NET_SSH2_READ_REGEX) {
1955
  preg_match($expect, $this->interactiveBuffer, $matches);
1956
+ $match = isset($matches[0]) ? $matches[0] : array();
1957
  }
1958
  $pos = !empty($match) ? strpos($this->interactiveBuffer, $match) : false;
1959
  if ($pos !== false) {
1979
  function write($cmd)
1980
  {
1981
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1982
+ user_error('Operation disallowed prior to login()');
1983
  return false;
1984
  }
1985
 
1986
  if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
1987
+ user_error('Unable to initiate an interactive shell session');
1988
  return false;
1989
  }
1990
 
1999
  function disconnect()
2000
  {
2001
  $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2002
+ if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
2003
+ fclose($this->realtime_log_file);
2004
+ }
2005
  }
2006
 
2007
  /**
2029
  function _get_binary_packet()
2030
  {
2031
  if (!is_resource($this->fsock) || feof($this->fsock)) {
2032
+ user_error('Connection closed prematurely');
2033
+ $this->bitmask = 0;
2034
  return false;
2035
  }
2036
 
2046
  $raw = $this->decrypt->decrypt($raw);
2047
  }
2048
  if ($raw === false) {
2049
+ user_error('Unable to decrypt content');
2050
  return false;
2051
  }
2052
 
2070
  if ($this->hmac_check !== false) {
2071
  $hmac = fread($this->fsock, $this->hmac_size);
2072
  if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
2073
+ user_error('Invalid HMAC');
2074
  return false;
2075
  }
2076
  }
2082
  $this->get_seq_no++;
2083
 
2084
  if (defined('NET_SSH2_LOGGING')) {
2085
+ $current = strtok(microtime(), ' ') + strtok('');
2086
+ $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
2087
+ $message_number = '<- ' . $message_number .
2088
+ ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
2089
+ $this->_append_log($message_number, $payload);
2090
+ $this->last_packet = $current;
2091
  }
2092
 
2093
  return $this->_filter($payload);
2179
  return $payload;
2180
  }
2181
 
2182
+ /**
2183
+ * Enable Quiet Mode
2184
+ *
2185
+ * Suppress stderr from output
2186
+ *
2187
+ * @access public
2188
+ */
2189
+ function enableQuietMode()
2190
+ {
2191
+ $this->quiet_mode = true;
2192
+ }
2193
+
2194
+ /**
2195
+ * Disable Quiet Mode
2196
+ *
2197
+ * Show stderr in output
2198
+ *
2199
+ * @access public
2200
+ */
2201
+ function disableQuietMode()
2202
+ {
2203
+ $this->quiet_mode = false;
2204
+ }
2205
+
2206
  /**
2207
  * Gets channel data
2208
  *
2223
  $read = array($this->fsock);
2224
  $write = $except = NULL;
2225
 
 
 
2226
  $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
2227
+ $sec = floor($this->curTimeout);
2228
+ $usec = 1000000 * ($this->curTimeout - $sec);
2229
  // on windows this returns a "Warning: Invalid CRT parameters detected" error
2230
+ if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
 
2231
  $this->_close_channel($client_channel);
2232
  return true;
2233
  }
2234
  $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
2235
  $this->curTimeout-= $elapsed;
 
 
2236
  }
2237
 
2238
  $response = $this->_get_binary_packet();
2239
  if ($response === false) {
2240
+ user_error('Connection closed by server');
2241
  return false;
2242
  }
2243
 
2259
  return $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
2260
  //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
2261
  default:
2262
+ user_error('Unable to open channel');
2263
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2264
  }
2265
  break;
2269
  return true;
2270
  //case NET_SSH2_MSG_CHANNEL_FAILURE:
2271
  default:
2272
+ user_error('Unable to request pseudo-terminal');
2273
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2274
  }
2275
  case NET_SSH2_MSG_CHANNEL_CLOSE:
2298
  $this->channel_buffers[$client_channel][] = $data;
2299
  break;
2300
  case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
2301
+ if ($skip_extended || $this->quiet_mode) {
2302
  break;
2303
  }
2304
  /*
2333
  case 'exit-status':
2334
  // "The channel needs to be closed with SSH_MSG_CHANNEL_CLOSE after this message."
2335
  // -- http://tools.ietf.org/html/rfc4254#section-6.10
2336
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
2337
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
2338
+
2339
+ $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
2340
  default:
2341
  // "Some systems may not implement signals, in which case they SHOULD ignore this message."
2342
  // -- http://tools.ietf.org/html/rfc4254#section-6.9
2344
  }
2345
  break;
2346
  case NET_SSH2_MSG_CHANNEL_CLOSE:
2347
+ $this->curTimeout = 0;
2348
+
2349
+ if ($this->bitmap & NET_SSH2_MASK_SHELL) {
2350
+ $this->bitmap&= ~NET_SSH2_MASK_SHELL;
2351
+ }
2352
+ if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
2353
+ $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
2354
+ }
2355
+
2356
+ $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
2357
  return true;
2358
  case NET_SSH2_MSG_CHANNEL_EOF:
2359
  break;
2360
  default:
2361
+ user_error('Error reading channel data');
2362
  return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
2363
  }
2364
  }
2377
  function _send_binary_packet($data)
2378
  {
2379
  if (!is_resource($this->fsock) || feof($this->fsock)) {
2380
+ user_error('Connection closed prematurely');
2381
+ $this->bitmask = 0;
2382
  return false;
2383
  }
2384
 
2394
  $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
2395
  // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
2396
  $padding_length = $packet_length - strlen($data) - 5;
2397
+ $padding = crypt_random_string($padding_length);
 
 
 
 
2398
 
2399
  // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
2400
  $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);
2413
  $stop = strtok(microtime(), ' ') + strtok('');
2414
 
2415
  if (defined('NET_SSH2_LOGGING')) {
2416
+ $current = strtok(microtime(), ' ') + strtok('');
2417
+ $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
2418
+ $message_number = '-> ' . $message_number .
2419
+ ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
2420
+ $this->_append_log($message_number, $data);
2421
+ $this->last_packet = $current;
2422
  }
2423
 
2424
  return $result;
2432
  * @param String $data
2433
  * @access private
2434
  */
2435
+ function _append_log($message_number, $message)
2436
  {
2437
+ switch (NET_SSH2_LOGGING) {
2438
+ // useful for benchmarks
2439
+ case NET_SSH2_LOG_SIMPLE:
2440
+ $this->message_number_log[] = $message_number;
2441
+ break;
2442
+ // the most useful log for SSH2
2443
+ case NET_SSH2_LOG_COMPLEX:
2444
+ $this->message_number_log[] = $message_number;
2445
+ $this->_string_shift($message);
2446
+ $this->log_size+= strlen($message);
2447
+ $this->message_log[] = $message;
2448
+ while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) {
2449
+ $this->log_size-= strlen(array_shift($this->message_log));
2450
+ array_shift($this->message_number_log);
2451
+ }
2452
+ break;
2453
+ // dump the output out realtime; packets may be interspersed with non packets,
2454
+ // passwords won't be filtered out and select other packets may not be correctly
2455
+ // identified
2456
+ case NET_SSH2_LOG_REALTIME:
2457
+ echo "<pre>\r\n" . $this->_format_log(array($message), array($message_number)) . "\r\n</pre>\r\n";
2458
+ @flush();
2459
+ @ob_flush();
2460
+ break;
2461
+ // basically the same thing as NET_SSH2_LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILE
2462
+ // needs to be defined and that the resultant log file will be capped out at NET_SSH2_LOG_MAX_SIZE.
2463
+ // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
2464
+ // at the beginning of the file
2465
+ case NET_SSH2_LOG_REALTIME_FILE:
2466
+ if (!isset($this->realtime_log_file)) {
2467
+ // PHP doesn't seem to like using constants in fopen()
2468
+ $filename = NET_SSH2_LOG_REALTIME_FILE;
2469
+ $fp = fopen($filename, 'w');
2470
+ $this->realtime_log_file = $fp;
2471
+ }
2472
+ if (!is_resource($this->realtime_log_file)) {
2473
+ break;
2474
+ }
2475
+ $entry = $this->_format_log(array($message), array($message_number));
2476
+ if ($this->realtime_log_wrap) {
2477
+ $temp = "<<< START >>>\r\n";
2478
+ $entry.= $temp;
2479
+ fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
2480
+ }
2481
+ $this->realtime_log_size+= strlen($entry);
2482
+ if ($this->realtime_log_size > NET_SSH2_LOG_MAX_SIZE) {
2483
+ fseek($this->realtime_log_file, 0);
2484
+ $this->realtime_log_size = strlen($entry);
2485
+ $this->realtime_log_wrap = true;
2486
+ }
2487
+ fputs($this->realtime_log_file, $entry);
2488
+ }
2489
  }
2490
 
2491
  /**
2857
  extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
2858
  $this->_string_shift($server_public_host_key, $length);
2859
 
2860
+ if ($this->signature_validated) {
2861
+ return $this->bitmap ?
2862
+ $this->signature_format . ' ' . base64_encode($this->server_public_host_key) :
2863
+ false;
2864
+ }
2865
+
2866
+ $this->signature_validated = true;
2867
+
2868
  switch ($this->signature_format) {
2869
  case 'ssh-dss':
2870
  $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
2884
  padding, unsigned, and in network byte order). */
2885
  $temp = unpack('Nlength', $this->_string_shift($signature, 4));
2886
  if ($temp['length'] != 40) {
2887
+ user_error('Invalid signature');
2888
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2889
  }
2890
 
2892
  $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
2893
 
2894
  if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
2895
+ user_error('Invalid signature');
2896
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2897
  }
2898
 
2912
  list(, $v) = $v->divide($q);
2913
 
2914
  if (!$v->equals($r)) {
2915
+ user_error('Bad server signature');
2916
  return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2917
  }
2918
 
2937
  $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
2938
  $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
2939
  if (!$rsa->verify($this->exchange_hash, $signature)) {
2940
+ user_error('Bad server signature');
2941
  return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2942
  }
2943
  */
2952
  // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
2953
 
2954
  if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
2955
+ user_error('Invalid signature');
2956
  return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
2957
  }
2958
 
2963
  $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h;
2964
 
2965
  if ($s != $h) {
2966
+ user_error('Bad server signature');
2967
  return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2968
  }
2969
+ break;
2970
+ default:
2971
+ user_error('Unsupported signature format');
2972
+ return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
2973
  }
2974
 
2975
+ return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
2976
  }
2977
  }
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: TerraFrost
3
  Donate link: http://sourceforge.net/donate/index.php?group_id=198487
4
  Tags: ssh, sftp
5
  Requires at least: 3.1
6
- Tested up to: 3.3
7
- Stable tag: 0.3
8
 
9
  "SSH SFTP Updater Support" is the easiest way to keep your Wordpress installation up-to-date with SFTP.
10
 
@@ -31,4 +31,9 @@ Keeping your Wordpress install up-to-date and installing plugins in a hassle-fre
31
 
32
  = 0.3 =
33
  * update phpseclib to latest SVN
34
- * read file when FTP_PRIKEY is defined (thanks, lkraav!)
 
 
 
 
 
3
  Donate link: http://sourceforge.net/donate/index.php?group_id=198487
4
  Tags: ssh, sftp
5
  Requires at least: 3.1
6
+ Tested up to: 3.4
7
+ Stable tag: 0.4
8
 
9
  "SSH SFTP Updater Support" is the easiest way to keep your Wordpress installation up-to-date with SFTP.
10
 
31
 
32
  = 0.3 =
33
  * update phpseclib to latest SVN
34
+ * read file when FTP_PRIKEY is defined (thanks, lkraav!)
35
+
36
+ = 0.4 =
37
+ * fix an E_NOTICE (thanks, runblip!)
38
+ * make it so keys that are copy / pasted in are saved with HTML5's localStorage (thanks, kkzk!)
39
+ * update phpseclib to latest Git
sftp.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: SSH SFTP Updater Support
4
  Plugin URI: http://phpseclib.sourceforge.net/wordpress.htm
5
  Description: Update your Wordpress blog / plugins via SFTP without libssh2
6
- Version: 0.3
7
  Author: TerraFrost
8
  Author URI: http://phpseclib.sourceforge.net/
9
  */
@@ -30,7 +30,7 @@ function phpseclib_fs_ftp_connection_types($types) {
30
  }
31
 
32
  // this has been pretty much copy / pasted from wp-admin/includes/file.php
33
- function phpseclib_request_filesystem_credentials($value, $form_post, $type, $error, $context, $extra_fields) {
34
  if ( empty($type) )
35
  $type = get_filesystem_method(array(), $context);
36
 
@@ -122,6 +122,14 @@ jQuery(function($){
122
  jQuery("#ftp, #ftps").click(function () {
123
  jQuery(".ssh_keys").hide();
124
  });
 
 
 
 
 
 
 
 
125
  jQuery('form input[value=""]:first').focus();
126
  });
127
  -->
3
  Plugin Name: SSH SFTP Updater Support
4
  Plugin URI: http://phpseclib.sourceforge.net/wordpress.htm
5
  Description: Update your Wordpress blog / plugins via SFTP without libssh2
6
+ Version: 0.4
7
  Author: TerraFrost
8
  Author URI: http://phpseclib.sourceforge.net/
9
  */
30
  }
31
 
32
  // this has been pretty much copy / pasted from wp-admin/includes/file.php
33
+ function phpseclib_request_filesystem_credentials($value, $form_post, $type = '', $error = false, $context = false, $extra_fields = null) {
34
  if ( empty($type) )
35
  $type = get_filesystem_method(array(), $context);
36
 
122
  jQuery("#ftp, #ftps").click(function () {
123
  jQuery(".ssh_keys").hide();
124
  });
125
+ jQuery('form').submit(function () {
126
+ if(typeof(Storage)!=="undefined") {
127
+ localStorage.privateKeyFile = jQuery("#private_key").val();
128
+ }
129
+ });
130
+ if(typeof(Storage)!=="undefined" && localStorage.privateKeyFile) {
131
+ jQuery('#private_key').val(localStorage.privateKeyFile);
132
+ }
133
  jQuery('form input[value=""]:first').focus();
134
  });
135
  -->