SSH2: use Strings::packSSH2() / Strings::unpackSSH2()

This commit is contained in:
terrafrost 2019-04-02 00:09:19 -05:00
parent f2226184ee
commit 0001b81950
2 changed files with 196 additions and 529 deletions

View File

@ -72,7 +72,7 @@ abstract class Strings
* N = uint32 * N = uint32
* s = string * s = string
* i = mpint * i = mpint
* l = name-list * L = name-list
* *
* uint64 is not supported. * uint64 is not supported.
* *
@ -82,21 +82,22 @@ abstract class Strings
*/ */
public static function unpackSSH2($format, &$data) public static function unpackSSH2($format, &$data)
{ {
$format = self::formatPack($format);
$result = []; $result = [];
for ($i = 0; $i < strlen($format); $i++) { for ($i = 0; $i < strlen($format); $i++) {
switch ($format[$i]) { switch ($format[$i]) {
case 'C': case 'C':
case 'b': case 'b':
if (!strlen($data)) { if (!strlen($data)) {
return false; throw new \LengthException('At least one byte needs to be present for successful C / b decodes');
} }
break; break;
case 'N': case 'N':
case 'i': case 'i':
case 's': case 's':
case 'l': case 'L':
if (strlen($data) < 4) { if (strlen($data) < 4) {
return false; throw new \LengthException('At least four byte needs to be present for successful N / i / s / L decodes');
} }
break; break;
default: default:
@ -116,7 +117,7 @@ abstract class Strings
} }
list(, $length) = unpack('N', self::shift($data, 4)); list(, $length) = unpack('N', self::shift($data, 4));
if (strlen($data) < $length) { if (strlen($data) < $length) {
return false; throw new \LengthException("$length bytes needed; " . strlen($data) . ' bytes available');
} }
$temp = self::shift($data, $length); $temp = self::shift($data, $length);
switch ($format[$i]) { switch ($format[$i]) {
@ -126,7 +127,7 @@ abstract class Strings
case 's': case 's':
$result[] = $temp; $result[] = $temp;
break; break;
case 'l': case 'L':
$result[] = explode(',', $temp); $result[] = explode(',', $temp);
} }
} }
@ -143,7 +144,7 @@ abstract class Strings
*/ */
public static function packSSH2(...$elements) public static function packSSH2(...$elements)
{ {
$format = $elements[0]; $format = self::formatPack($elements[0]);
array_shift($elements); array_shift($elements);
if (strlen($format) != count($elements)) { if (strlen($format) != count($elements)) {
throw new \InvalidArgumentException('There must be as many arguments as there are characters in the $format string'); throw new \InvalidArgumentException('There must be as many arguments as there are characters in the $format string');
@ -183,7 +184,7 @@ abstract class Strings
$element = $element->toBytes(true); $element = $element->toBytes(true);
$result.= pack('Na*', strlen($element), $element); $result.= pack('Na*', strlen($element), $element);
break; break;
case 'l': case 'L':
if (!is_array($element)) { if (!is_array($element)) {
throw new \InvalidArgumentException('An array was expected.'); throw new \InvalidArgumentException('An array was expected.');
} }
@ -197,6 +198,27 @@ abstract class Strings
return $result; return $result;
} }
/**
* Expand a pack string
*
* Converts C5 to CCCCC, for example.
*
* @access private
* @param string $format
* @return string
*/
private static function formatPack($format)
{
$parts = preg_split('#(\d+)#', $format, -1, PREG_SPLIT_DELIM_CAPTURE);
$format = '';
for ($i = 1; $i < count($parts); $i+=2) {
$format.= substr($parts[$i - 1], 0, -1) . str_repeat(substr($parts[$i - 1], -1), $parts[$i]);
}
$format.= $parts[$i - 1];
return $format;
}
/** /**
* Convert binary data into bits * Convert binary data into bits
* *

File diff suppressed because it is too large Load Diff