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 | 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 +55 -36
- phpseclib/Crypt/DES.php +12 -13
- phpseclib/Crypt/Hash.php +825 -825
- phpseclib/Crypt/RC4.php +531 -564
- phpseclib/Crypt/RSA.php +234 -108
- phpseclib/Crypt/Random.php +164 -64
- phpseclib/Crypt/Rijndael.php +1501 -1477
- phpseclib/Crypt/TripleDES.php +12 -10
- phpseclib/Math/BigInteger.php +117 -35
- phpseclib/Net/SFTP.php +159 -85
- phpseclib/Net/SSH2.php +319 -104
- readme.txt +8 -3
- sftp.php +10 -2
phpseclib/Crypt/AES.php
CHANGED
@@ -66,7 +66,9 @@
|
|
66 |
/**
|
67 |
* Include Crypt_Rijndael
|
68 |
*/
|
69 |
-
|
|
|
|
|
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 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
|
|
|
|
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 |
-
|
|
|
|
|
|
|
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 |
-
$
|
343 |
-
$ciphertext.= $
|
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 |
-
|
397 |
-
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
|
398 |
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
|
|
|
|
412 |
|
413 |
if (strlen($ciphertext) & 0xF) {
|
414 |
-
|
415 |
-
|
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 < $
|
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 = $
|
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 =
|
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, $
|
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 (
|
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->
|
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 (
|
781 |
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
782 |
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
783 |
-
if (strlen($buffer['ciphertext'])
|
|
|
|
|
|
|
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)"
|
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 |
-
*
|
147 |
-
*
|
148 |
-
*
|
149 |
-
*
|
150 |
-
* @
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
*
|
158 |
-
*
|
159 |
-
* @see Crypt_RC4::
|
160 |
-
* @var
|
161 |
-
* @access private
|
162 |
-
*/
|
163 |
-
var $
|
164 |
-
|
165 |
-
/**
|
166 |
-
*
|
167 |
-
*
|
168 |
-
*
|
169 |
-
*
|
170 |
-
* @
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
$
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
$
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
if (!isset($
|
263 |
-
$
|
264 |
-
}
|
265 |
-
|
266 |
-
if (!
|
267 |
-
|
268 |
-
}
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
$count
|
273 |
-
|
274 |
-
|
275 |
-
$
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
*
|
305 |
-
*
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
*
|
313 |
-
*
|
314 |
-
*
|
315 |
-
*
|
316 |
-
*
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
*
|
328 |
-
*
|
329 |
-
*
|
330 |
-
*
|
331 |
-
* @
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
*
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
$
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
}
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
*
|
441 |
-
*
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
*
|
450 |
-
*
|
451 |
-
*
|
452 |
-
*
|
453 |
-
*
|
454 |
-
*
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
*
|
468 |
-
*
|
469 |
-
*
|
470 |
-
*
|
471 |
-
*
|
472 |
-
*
|
473 |
-
* @
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
*
|
483 |
-
*
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
*
|
506 |
-
*
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
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 |
-
|
|
|
|
|
76 |
|
77 |
/**
|
78 |
* Include Crypt_Random
|
79 |
*/
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
/**
|
83 |
* Include Crypt_Hash
|
84 |
*/
|
85 |
-
|
|
|
|
|
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('
|
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 |
-
|
433 |
-
|
434 |
-
|
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 (
|
471 |
-
|
472 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
473 |
$publickey = openssl_pkey_get_details($rsa);
|
474 |
$publickey = $publickey['key'];
|
475 |
|
476 |
-
|
477 |
-
|
478 |
-
|
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.=
|
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 =
|
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]
|
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,
|
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),
|
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),
|
1022 |
$this->_string_shift($key);
|
1023 |
$length = $this->_decodeLength($key);
|
1024 |
-
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length),
|
1025 |
$this->_string_shift($key);
|
1026 |
$length = $this->_decodeLength($key);
|
1027 |
-
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length),
|
1028 |
$this->_string_shift($key);
|
1029 |
$length = $this->_decodeLength($key);
|
1030 |
-
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length),
|
1031 |
$this->_string_shift($key);
|
1032 |
$length = $this->_decodeLength($key);
|
1033 |
-
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length),
|
1034 |
$this->_string_shift($key);
|
1035 |
$length = $this->_decodeLength($key);
|
1036 |
-
$components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length),
|
1037 |
$this->_string_shift($key);
|
1038 |
$length = $this->_decodeLength($key);
|
1039 |
-
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length),
|
1040 |
$this->_string_shift($key);
|
1041 |
$length = $this->_decodeLength($key);
|
1042 |
-
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length),
|
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),
|
1057 |
$this->_string_shift($key);
|
1058 |
$length = $this->_decodeLength($key);
|
1059 |
-
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length),
|
1060 |
$this->_string_shift($key);
|
1061 |
$length = $this->_decodeLength($key);
|
1062 |
-
$components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length),
|
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' =>
|
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 |
-
|
|
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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 =
|
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'
|
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'
|
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'
|
1984 |
return false;
|
1985 |
}
|
1986 |
$m = ltrim($m, chr(0));
|
1987 |
if (ord($m[0]) != 1) {
|
1988 |
-
user_error('Decryption error'
|
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'
|
2014 |
return false;
|
2015 |
}
|
2016 |
|
2017 |
// EME-PKCS1-v1_5 encoding
|
2018 |
-
|
2019 |
-
$ps =
|
|
|
|
|
|
|
|
|
|
|
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.
|
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'
|
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'
|
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'
|
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'
|
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'
|
2112 |
return false;
|
2113 |
}
|
2114 |
|
2115 |
-
$salt =
|
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
|
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'
|
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'
|
2228 |
return false;
|
2229 |
}
|
2230 |
$em = $this->_i2osp($m2, $modBits >> 3);
|
2231 |
if ($em === false) {
|
2232 |
-
user_error('Invalid signature'
|
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'
|
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'
|
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'
|
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'
|
2347 |
return false;
|
2348 |
}
|
2349 |
$em = $this->_i2osp($m2, $this->k);
|
2350 |
if ($em === false) {
|
2351 |
-
user_error('Invalid signature'
|
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'
|
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
|
15 |
* ?>
|
16 |
* </code>
|
17 |
*
|
@@ -43,78 +43,146 @@
|
|
43 |
*/
|
44 |
|
45 |
/**
|
46 |
-
* Generate a random
|
47 |
*
|
48 |
-
*
|
49 |
-
*
|
|
|
50 |
*
|
51 |
-
*
|
52 |
-
*
|
53 |
-
* can.
|
54 |
-
*
|
55 |
-
* @param optional Integer $min
|
56 |
-
* @param optional Integer $max
|
57 |
-
* @return Integer
|
58 |
* @access public
|
59 |
*/
|
60 |
-
function
|
61 |
-
|
62 |
-
if (
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
//
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
74 |
}
|
|
|
75 |
|
76 |
-
//
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
-
|
92 |
-
|
|
|
|
|
93 |
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
-
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
$
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
}
|
105 |
-
}
|
106 |
-
|
107 |
-
static $crypto;
|
108 |
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
|
112 |
-
|
113 |
-
|
114 |
-
|
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 |
-
|
133 |
-
return
|
134 |
}
|
|
|
135 |
$crypto->setKey($key);
|
136 |
$crypto->setIV($iv);
|
137 |
$crypto->enableContinuousBuffer();
|
138 |
}
|
139 |
|
140 |
-
|
141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 (
|
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 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
$
|
774 |
-
$
|
775 |
-
$
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
$
|
793 |
-
}
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
}
|
816 |
-
}
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
$
|
883 |
-
}
|
884 |
-
}
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
}
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
$
|
905 |
-
|
906 |
-
|
907 |
-
$
|
908 |
-
|
909 |
-
$
|
910 |
-
}
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
$
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
$
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
$
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
$
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
$
|
1020 |
-
|
1021 |
-
|
1022 |
-
}
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
$
|
1046 |
-
|
1047 |
-
$
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
-
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
);
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
$
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
$
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
for
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
$
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
$
|
1195 |
-
|
1196 |
-
if ($
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
1302 |
-
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
|
1307 |
-
|
1308 |
-
|
1309 |
-
|
1310 |
-
|
1311 |
-
|
1312 |
-
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
1325 |
-
|
1326 |
-
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
*
|
1340 |
-
*
|
1341 |
-
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
*
|
1349 |
-
*
|
1350 |
-
*
|
1351 |
-
*
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
*
|
1380 |
-
*
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
1391 |
-
|
1392 |
-
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
|
1402 |
-
|
1403 |
-
*
|
1404 |
-
*
|
1405 |
-
*
|
1406 |
-
*
|
1407 |
-
*
|
1408 |
-
|
1409 |
-
|
1410 |
-
|
1411 |
-
|
1412 |
-
|
1413 |
-
|
1414 |
-
|
1415 |
-
|
1416 |
-
|
1417 |
-
|
1418 |
-
|
1419 |
-
|
1420 |
-
|
1421 |
-
|
1422 |
-
|
1423 |
-
|
1424 |
-
|
1425 |
-
*
|
1426 |
-
*
|
1427 |
-
*
|
1428 |
-
*
|
1429 |
-
*
|
1430 |
-
*
|
1431 |
-
*
|
1432 |
-
*
|
1433 |
-
*
|
1434 |
-
*
|
1435 |
-
*
|
1436 |
-
*
|
1437 |
-
*
|
1438 |
-
|
1439 |
-
|
1440 |
-
|
1441 |
-
|
1442 |
-
|
1443 |
-
|
1444 |
-
|
1445 |
-
*
|
1446 |
-
*
|
1447 |
-
*
|
1448 |
-
*
|
1449 |
-
*
|
1450 |
-
*
|
1451 |
-
|
1452 |
-
|
1453 |
-
|
1454 |
-
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
-
|
1461 |
-
|
1462 |
-
|
1463 |
-
|
1464 |
-
|
1465 |
-
|
1466 |
-
|
1467 |
-
*
|
1468 |
-
|
1469 |
-
|
1470 |
-
|
1471 |
-
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
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 (
|
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 (
|
826 |
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
827 |
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
828 |
-
if (strlen($buffer['ciphertext'])
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
301 |
return;
|
302 |
}
|
303 |
|
@@ -599,13 +605,19 @@ class Math_BigInteger {
|
|
599 |
{
|
600 |
$hex = $this->toHex($twos_compliment);
|
601 |
$bits = '';
|
602 |
-
for ($i =
|
603 |
-
$bits
|
604 |
}
|
605 |
-
if ($
|
606 |
-
$bits
|
|
|
|
|
|
|
|
|
|
|
607 |
}
|
608 |
-
|
|
|
609 |
}
|
610 |
|
611 |
/**
|
@@ -1589,13 +1601,54 @@ class Math_BigInteger {
|
|
1589 |
return $this->_normalize($temp->modPow($e, $n));
|
1590 |
}
|
1591 |
|
1592 |
-
|
1593 |
-
|
1594 |
-
|
1595 |
-
$temp->value = gmp_powm($this->value, $e->value, $n->value);
|
1596 |
|
1597 |
-
|
1598 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
*
|
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 |
-
* @
|
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 |
-
$
|
2998 |
-
|
2999 |
-
$random
|
3000 |
-
}
|
|
|
|
|
|
|
|
|
|
|
3001 |
|
3002 |
-
|
3003 |
-
|
3004 |
-
|
3005 |
-
|
|
|
3006 |
}
|
3007 |
|
3008 |
-
$
|
3009 |
-
|
3010 |
-
|
|
|
|
|
|
|
3011 |
} else {
|
3012 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
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 |
-
|
|
|
|
|
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'
|
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 |
-
|
454 |
-
|
|
|
|
|
|
|
|
|
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.
|
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 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
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'
|
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 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
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'
|
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'
|
627 |
return false;
|
628 |
}
|
629 |
|
630 |
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
631 |
if ($status != NET_SFTP_STATUS_OK) {
|
632 |
-
|
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 |
-
*
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
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'
|
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 |
-
|
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'
|
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'
|
768 |
return false;
|
769 |
}
|
770 |
|
771 |
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
772 |
if ($status != NET_SFTP_STATUS_OK) {
|
773 |
-
|
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 |
-
|
839 |
}
|
840 |
-
if (isset($
|
841 |
-
|
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 |
-
|
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'
|
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'
|
1059 |
return false;
|
1060 |
}
|
1061 |
|
1062 |
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1063 |
if ($status != NET_SFTP_STATUS_OK) {
|
1064 |
-
|
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 |
-
|
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'
|
1088 |
return false;
|
1089 |
}
|
1090 |
|
@@ -1110,7 +1147,11 @@ class Net_SFTP extends Net_SSH2 {
|
|
1110 |
return $this->chmod($mode, $path);
|
1111 |
}
|
1112 |
|
1113 |
-
//
|
|
|
|
|
|
|
|
|
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 |
-
|
1177 |
-
|
1178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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'
|
1190 |
return false;
|
1191 |
}
|
1192 |
|
1193 |
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1194 |
if ($status != NET_SFTP_STATUS_OK) {
|
1195 |
-
|
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'
|
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 |
-
|
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 |
-
|
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'
|
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"
|
1318 |
return false;
|
1319 |
}
|
1320 |
$fp = @fopen($data, 'rb');
|
@@ -1351,7 +1416,9 @@ class Net_SFTP extends Net_SSH2 {
|
|
1351 |
}
|
1352 |
}
|
1353 |
|
1354 |
-
|
|
|
|
|
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'
|
1367 |
return false;
|
1368 |
}
|
1369 |
|
1370 |
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1371 |
if ($status != NET_SFTP_STATUS_OK) {
|
1372 |
-
|
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'
|
1396 |
return false;
|
1397 |
}
|
1398 |
|
1399 |
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1400 |
if ($status != NET_SFTP_STATUS_OK) {
|
1401 |
-
|
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 |
-
|
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'
|
1449 |
return false;
|
1450 |
}
|
1451 |
|
@@ -1458,9 +1522,10 @@ class Net_SFTP extends Net_SSH2 {
|
|
1458 |
$content = '';
|
1459 |
}
|
1460 |
|
1461 |
-
$
|
|
|
1462 |
while (true) {
|
1463 |
-
$packet = pack('Na*N3', strlen($handle), $handle, 0, $
|
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 |
-
$
|
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 |
-
|
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'
|
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'
|
1506 |
return false;
|
1507 |
}
|
1508 |
|
1509 |
-
extract(unpack('Nstatus
|
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'
|
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 |
-
|
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 |
-
//
|
|
|
|
|
|
|
|
|
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'
|
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 |
-
|
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 |
-
|
|
|
|
|
77 |
|
78 |
/**
|
79 |
* Include Crypt_Random
|
80 |
*/
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
/**
|
84 |
* Include Crypt_Hash
|
85 |
*/
|
86 |
-
|
|
|
|
|
87 |
|
88 |
/**
|
89 |
* Include Crypt_TripleDES
|
90 |
*/
|
91 |
-
|
|
|
|
|
92 |
|
93 |
/**
|
94 |
* Include Crypt_RC4
|
95 |
*/
|
96 |
-
|
|
|
|
|
97 |
|
98 |
/**
|
99 |
* Include Crypt_AES
|
100 |
*/
|
101 |
-
|
|
|
|
|
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.
|
182 |
|
183 |
/**
|
184 |
* The Socket Object
|
@@ -191,7 +215,7 @@ class Net_SSH2 {
|
|
191 |
/**
|
192 |
* Execution Bitmap
|
193 |
*
|
194 |
-
* The bits that are set
|
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")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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'
|
746 |
return false;
|
747 |
}
|
748 |
|
@@ -761,13 +858,8 @@ class Net_SSH2 {
|
|
761 |
}
|
762 |
|
763 |
if (defined('NET_SSH2_LOGGING')) {
|
764 |
-
$this->
|
765 |
-
$this->
|
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"
|
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'
|
788 |
return;
|
789 |
}
|
790 |
|
791 |
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
|
792 |
-
user_error('Expected SSH_MSG_KEXINIT'
|
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'
|
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'
|
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'
|
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'
|
1057 |
return false;
|
1058 |
}
|
1059 |
|
1060 |
$response = $this->_get_binary_packet();
|
1061 |
if ($response === false) {
|
1062 |
-
user_error('Connection closed by server'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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
|
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'
|
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'
|
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()'
|
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'
|
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()'
|
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'
|
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'
|
|
|
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'
|
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'
|
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 |
-
$
|
1957 |
-
$this->
|
1958 |
-
|
1959 |
-
|
1960 |
-
|
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, $
|
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'
|
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'
|
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'
|
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->
|
2187 |
-
|
|
|
|
|
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->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2196 |
return true;
|
2197 |
case NET_SSH2_MSG_CHANNEL_EOF:
|
2198 |
break;
|
2199 |
default:
|
2200 |
-
user_error('Error reading channel data'
|
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'
|
|
|
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 |
-
$
|
2259 |
-
$this->
|
2260 |
-
|
2261 |
-
|
2262 |
-
|
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($
|
2278 |
{
|
2279 |
-
|
2280 |
-
|
2281 |
-
|
2282 |
-
|
2283 |
-
|
2284 |
-
|
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'
|
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'
|
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'
|
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'
|
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'
|
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'
|
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.
|
7 |
-
Stable tag: 0.
|
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.
|
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 |
-->
|